Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
877f64e
chore(strands-ts): scaffold typescript project
yonib05 Jun 12, 2026
20544cc
test(strands-ts): add vitest smoke test
yonib05 Jun 12, 2026
4506596
fix(strands-ts): use NodeNext module resolution for direct node execu…
yonib05 Jun 12, 2026
deae676
feat(strands-ts): add Finding/ReviewOutput zod schemas
yonib05 Jun 12, 2026
b169320
feat(strands-ts): add deterministic score/dedupe/cap filter
yonib05 Jun 12, 2026
7b9d536
feat(strands-ts): add deferred-write safeguard wrapper
yonib05 Jun 12, 2026
d1fe60f
fix(strands-ts): async artifact writes, schema comment, test coverage
yonib05 Jun 12, 2026
57670b1
feat(strands-ts): add github read tools and deferred addPrComment
yonib05 Jun 12, 2026
c6d22c1
feat(strands-ts): add writeExecutor finalize replay
yonib05 Jun 12, 2026
920518f
fix(strands-ts): encode contents url, pin replay repo, pagination + t…
yonib05 Jun 12, 2026
d82da69
feat(strands-ts): add model factory, lens SOPs, and SOP loader
yonib05 Jun 12, 2026
39e628b
feat(strands-ts): add specialist and orchestrator agent builders
yonib05 Jun 12, 2026
2f56b25
feat(strands-ts): add reviewer mode, registry, runner entry
yonib05 Jun 12, 2026
26fe579
fix(strands-ts): harden sop path guard, tier lookup, finding range va…
yonib05 Jun 12, 2026
b86367e
feat(strands-ts): add read-only runner action
yonib05 Jun 12, 2026
457f330
feat(strands-ts): add finalize action and example consumer workflow
yonib05 Jun 12, 2026
2435eba
fix(strands-ts): gate finalize on agent success, env-pass pr number
yonib05 Jun 12, 2026
cf5dade
fix(strands-ts): decode file contents, give orchestrator the head ref
yonib05 Jun 12, 2026
0c3505f
fix(strands-ts): reject dot-segment paths, require commit_id for inli…
yonib05 Jun 12, 2026
a5e18d9
fix(strands-ts): paginate listings, harden entry guards, cover runner…
yonib05 Jun 12, 2026
3fdbef2
refactor(strands-ts): restructure SOPs to devtools house style
yonib05 Jun 13, 2026
cfd45fe
feat(strands-ts): post inline review comments per finding
yonib05 Jun 13, 2026
a301b09
fix(strands-ts): treat inline-comment 422 as skipped, not a run failure
yonib05 Jun 14, 2026
4c83da7
fix(strands-ts): orchestrator fetches governance docs for the adheren…
yonib05 Jun 14, 2026
14eabf6
fix(strands-ts): keep masking-test findings separate, clamp inline an…
yonib05 Jun 14, 2026
1a41528
fix(strands-ts): score verified/doc-cited findings at the posting thr…
yonib05 Jun 14, 2026
5313a60
feat(strands-ts): default to opus tier and add strands-running label …
yonib05 Jun 14, 2026
f19f37d
refactor(strands-ts): remove dead scaffolding and low-value tests
yonib05 Jun 14, 2026
14a756f
refactor(strands-ts): collapse maxTokens config and share path guard
yonib05 Jun 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions strands-command/actions/strands-ts-finalize/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: 'Strands TS Finalize'
description: 'Replay deferred write operations recorded by the read-only Strands TypeScript agent'

runs:
using: 'composite'
steps:
# The TypeScript project ships inside this action's repository, which GitHub
# downloads (at the ref the consumer pinned) to run the action. Resolve its
# absolute path so consumer workflows don't need to check out devtools.
- name: Resolve TypeScript project directory
id: dirs
shell: bash
run: echo "ts_dir=$(cd "${{ github.action_path }}/../../scripts/typescript" && pwd)" >> "$GITHUB_OUTPUT"

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
shell: bash
working-directory: ${{ steps.dirs.outputs.ts_dir }}
run: npm ci

- name: Build
shell: bash
working-directory: ${{ steps.dirs.outputs.ts_dir }}
run: npx tsc

# No artifact means the agent run deferred nothing — there is nothing to post.
- name: Download artifact with write operations
uses: actions/download-artifact@v4
with:
name: strands-ts-write-operations
path: ${{ steps.dirs.outputs.ts_dir }}/.artifact
continue-on-error: true

- name: Replay deferred writes
shell: bash
working-directory: ${{ steps.dirs.outputs.ts_dir }}
env:
GITHUB_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: node dist/writeExecutor.js .artifact/write_operations.jsonl
85 changes: 85 additions & 0 deletions strands-command/actions/strands-ts-runner/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: 'Strands TS Runner'
description: 'Run the read-only Strands TypeScript agent against a pull request'

inputs:
command:
description: 'The comment body that triggered the run (e.g. "/strands-ts review")'
required: true
pr_number:
description: 'Pull request number the agent should review'
required: true
pr_head_sha:
description: 'Head SHA of the pull request'
required: true
aws_role_arn:
description: 'AWS IAM role ARN to assume via OIDC for Bedrock access'
required: true
agents_config:
description: 'Optional per-agent config: JSON map of agent key -> {model?, sop?}'
required: false
default: ''

runs:
using: 'composite'
steps:
# The TypeScript project ships inside this action's repository, which GitHub
# downloads (at the ref the consumer pinned) to run the action. Resolve its
# absolute path so consumer workflows don't need to check out devtools.
- name: Resolve TypeScript project directory
id: dirs
shell: bash
run: echo "ts_dir=$(cd "${{ github.action_path }}/../../scripts/typescript" && pwd)" >> "$GITHUB_OUTPUT"

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
shell: bash
working-directory: ${{ steps.dirs.outputs.ts_dir }}
run: npm ci

- name: Build
shell: bash
working-directory: ${{ steps.dirs.outputs.ts_dir }}
run: npx tsc

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ inputs.aws_role_arn }}
role-session-name: GitHubActions-StrandsTS-${{ github.run_id }}
aws-region: us-west-2
mask-aws-account-id: true

- name: Run agent (read-only)
shell: bash
working-directory: ${{ steps.dirs.outputs.ts_dir }}
env:
# Read-only: write tool calls are deferred to .artifact/write_operations.jsonl
GITHUB_WRITE: 'false'

# GitHub Configuration
GITHUB_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}

# Task Configuration
# inputs.command is attacker-influenced PR comment text. Pass it (and the
# other inputs) via env only — never interpolate into the run script body.
INPUT_TASK: ${{ inputs.command }}
PR_NUMBER: ${{ inputs.pr_number }}
PR_HEAD_SHA: ${{ inputs.pr_head_sha }}
STRANDS_TS_AGENTS: ${{ inputs.agents_config }}

# AWS Configuration
AWS_REGION: 'us-west-2'
run: node dist/runner.js

- name: Upload artifact for write operations
uses: actions/upload-artifact@v4
with:
name: strands-ts-write-operations
path: ${{ steps.dirs.outputs.ts_dir }}/.artifact/write_operations.jsonl
retention-days: 1
if-no-files-found: ignore
104 changes: 104 additions & 0 deletions strands-command/examples/strands-ts-command.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Example consumer workflow for the /strands-ts command.
# Copy into your repo's .github/workflows/ and adjust secrets/vars.
name: Strands-TS Command Handler

on:
issue_comment:
types: [created]

# SECURITY: no workflow-level write permissions. The read/write split is enforced
# per job — the agent-running job must NEVER hold a write-capable token, or the
# deferred-write safeguard is decorative.
permissions: {}

jobs:
authorization-check:
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/strands-ts') }}
name: Check access
permissions:
contents: read
runs-on: ubuntu-latest
outputs:
approval-env: ${{ steps.auth.outputs.approval-env }}
steps:
- name: Check Authorization
id: auth
uses: strands-agents/devtools/authorization-check@main
with:
username: ${{ github.event.comment.user.login }}
allowed-roles: 'maintain,triage,write,admin'

# Visible in-progress indicator + soft concurrency signal. Runs in its own
# write-capable job so the agent job below stays tokenless.
mark-running:
needs: [authorization-check]
runs-on: ubuntu-latest
permissions:
issues: write # PR labels are managed via the issues API
pull-requests: write
steps:
- name: Add strands-running label
env:
GH_TOKEN: ${{ github.token }}
PR_NUM: ${{ github.event.issue.number }}
run: gh pr edit "$PR_NUM" --repo "${{ github.repository }}" --add-label strands-running || true

execute-readonly-agent:
needs: [authorization-check, mark-running]
environment: ${{ needs.authorization-check.outputs.approval-env }}
runs-on: ubuntu-latest
timeout-minutes: 20 # bounded execution: cap a hung multi-agent run
permissions:
contents: read
pull-requests: read
id-token: write # AWS OIDC role assumption only
steps:
- uses: actions/checkout@v4
- name: Resolve PR head SHA
id: pr
env:
GH_TOKEN: ${{ github.token }}
# Event payload data goes through env, never into the script body.
PR_NUM: ${{ github.event.issue.number }}
run: echo "sha=$(gh pr view "$PR_NUM" --json headRefOid -q .headRefOid)" >> "$GITHUB_OUTPUT"
- name: Run Strands-TS Agent
uses: strands-agents/devtools/strands-command/actions/strands-ts-runner@main
with:
command: ${{ github.event.comment.body }}
pr_number: ${{ github.event.issue.number }}
pr_head_sha: ${{ steps.pr.outputs.sha }}
aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
# Per-repo agent config (Actions variable, optional). JSON map of
# agent key -> {model?, sop?}.
agents_config: ${{ vars.STRANDS_TS_AGENTS || '' }}

finalize:
needs: [execute-readonly-agent]
# Only replay when the agent run succeeded: a crashed run may leave a
# partial artifact, and replaying it would post incomplete reviews while
# making the failure look green.
if: ${{ needs.execute-readonly-agent.result == 'success' }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # the ONLY job that can write; replays vetted artifact ops
steps:
- uses: actions/checkout@v4
- name: Replay deferred writes
uses: strands-agents/devtools/strands-command/actions/strands-ts-finalize@main

# Always clear the label once the run is done (success, failure, or skip),
# mirroring the Python command's remove-on-finalize behavior.
clear-running:
needs: [mark-running, execute-readonly-agent, finalize]
if: ${{ always() && needs.mark-running.result == 'success' }}
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Remove strands-running label
env:
GH_TOKEN: ${{ github.token }}
PR_NUM: ${{ github.event.issue.number }}
run: gh pr edit "$PR_NUM" --repo "${{ github.repository }}" --remove-label strands-running || true
5 changes: 5 additions & 0 deletions strands-command/scripts/typescript/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
.artifact/
# Root .gitignore ignores all package-lock.json; track this one for CI npm ci.
!package-lock.json
Loading