From 1d5e5247e8d32ded06f51f6fe4f66210b1acd853 Mon Sep 17 00:00:00 2001 From: Dotta Date: Thu, 12 Mar 2026 08:42:12 -0500 Subject: [PATCH 1/2] Raise default max turns to 300 Co-Authored-By: Paperclip --- doc/spec/agent-runs.md | 2 +- docs/adapters/claude-local.md | 2 +- server/src/services/company-portability.ts | 2 +- ui/src/adapters/claude-local/config-fields.tsx | 4 ++-- ui/src/components/agent-config-defaults.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/spec/agent-runs.md b/doc/spec/agent-runs.md index 4c172c7b..f0d02275 100644 --- a/doc/spec/agent-runs.md +++ b/doc/spec/agent-runs.md @@ -249,7 +249,7 @@ Runs local `claude` CLI directly. "cwd": "/absolute/or/relative/path", "promptTemplate": "You are agent {{agent.id}} ...", "model": "optional-model-id", - "maxTurnsPerRun": 80, + "maxTurnsPerRun": 300, "dangerouslySkipPermissions": true, "env": {"KEY": "VALUE"}, "extraArgs": [], diff --git a/docs/adapters/claude-local.md b/docs/adapters/claude-local.md index 3b80f288..c6029e0c 100644 --- a/docs/adapters/claude-local.md +++ b/docs/adapters/claude-local.md @@ -20,7 +20,7 @@ The `claude_local` adapter runs Anthropic's Claude Code CLI locally. It supports | `env` | object | No | Environment variables (supports secret refs) | | `timeoutSec` | number | No | Process timeout (0 = no timeout) | | `graceSec` | number | No | Grace period before force-kill | -| `maxTurnsPerRun` | number | No | Max agentic turns per heartbeat | +| `maxTurnsPerRun` | number | No | Max agentic turns per heartbeat (defaults to `300`) | | `dangerouslySkipPermissions` | boolean | No | Skip permission prompts (dev only) | ## Prompt Templates diff --git a/server/src/services/company-portability.ts b/server/src/services/company-portability.ts index 06928f08..f067e957 100644 --- a/server/src/services/company-portability.ts +++ b/server/src/services/company-portability.ts @@ -85,7 +85,7 @@ const ADAPTER_DEFAULT_RULES_BY_TYPE: Record mark("adapterConfig", "maxTurnsPerRun", v || 80)} + onCommit={(v) => mark("adapterConfig", "maxTurnsPerRun", v || 300)} immediate className={inputClass} /> diff --git a/ui/src/components/agent-config-defaults.ts b/ui/src/components/agent-config-defaults.ts index 4cf1df2f..9932f873 100644 --- a/ui/src/components/agent-config-defaults.ts +++ b/ui/src/components/agent-config-defaults.ts @@ -24,7 +24,7 @@ export const defaultCreateValues: CreateConfigValues = { workspaceBranchTemplate: "", worktreeParentDir: "", runtimeServicesJson: "", - maxTurnsPerRun: 80, + maxTurnsPerRun: 300, heartbeatEnabled: false, intervalSec: 300, }; From 8808a33fe1bd0de9ac3ee6d838c633a442ea3474 Mon Sep 17 00:00:00 2001 From: Dotta Date: Thu, 12 Mar 2026 10:52:17 -0500 Subject: [PATCH 2/2] ci: refresh pnpm lockfile before merge --- .github/workflows/pr-policy.yml | 39 ++++++-- .github/workflows/pr-verify.yml | 2 +- .github/workflows/refresh-lockfile-pr.yml | 111 ++++++++++++++++++++++ .github/workflows/refresh-lockfile.yml | 81 ---------------- doc/DEVELOPING.md | 6 +- 5 files changed, 145 insertions(+), 94 deletions(-) create mode 100644 .github/workflows/refresh-lockfile-pr.yml delete mode 100644 .github/workflows/refresh-lockfile.yml diff --git a/.github/workflows/pr-policy.yml b/.github/workflows/pr-policy.yml index 16953380..a8042120 100644 --- a/.github/workflows/pr-policy.yml +++ b/.github/workflows/pr-policy.yml @@ -13,6 +13,8 @@ jobs: policy: runs-on: ubuntu-latest timeout-minutes: 10 + permissions: + pull-requests: read steps: - name: Checkout repository @@ -31,19 +33,38 @@ jobs: with: node-version: 20 - - name: Block manual lockfile edits - if: github.head_ref != 'chore/refresh-lockfile' + - name: Enforce lockfile policy when manifests change + env: + GH_TOKEN: ${{ github.token }} run: | - changed="$(git diff --name-only "${{ github.event.pull_request.base.sha }}" "${{ github.event.pull_request.head.sha }}")" + changed="$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" --paginate --jq '.[].filename')" + manifest_pattern='(^|/)package\.json$|^pnpm-workspace\.yaml$|^\.npmrc$|^pnpmfile\.(cjs|js|mjs)$' + + manifest_changed=false + lockfile_changed=false + + if printf '%s\n' "$changed" | grep -Eq "$manifest_pattern"; then + manifest_changed=true + fi + if printf '%s\n' "$changed" | grep -qx 'pnpm-lock.yaml'; then - echo "Do not commit pnpm-lock.yaml in pull requests. CI owns lockfile updates." + lockfile_changed=true + fi + + if [ "$lockfile_changed" = true ] && [ "$manifest_changed" != true ]; then + echo "pnpm-lock.yaml changed without a dependency manifest change." >&2 exit 1 fi - - name: Validate dependency resolution when manifests change - run: | - changed="$(git diff --name-only "${{ github.event.pull_request.base.sha }}" "${{ github.event.pull_request.head.sha }}")" - manifest_pattern='(^|/)package\.json$|^pnpm-workspace\.yaml$|^\.npmrc$|^pnpmfile\.(cjs|js|mjs)$' - if printf '%s\n' "$changed" | grep -Eq "$manifest_pattern"; then + if [ "$manifest_changed" = true ]; then pnpm install --lockfile-only --ignore-scripts --no-frozen-lockfile + + if ! git diff --quiet -- pnpm-lock.yaml; then + if [ "${{ github.event.pull_request.head.repo.full_name }}" = "${{ github.repository }}" ]; then + echo "pnpm-lock.yaml is stale for this PR. Wait for the Refresh Lockfile workflow to push the bot commit, then rerun checks." >&2 + else + echo "pnpm-lock.yaml is stale for this fork PR. Run pnpm install --lockfile-only --ignore-scripts --no-frozen-lockfile and commit pnpm-lock.yaml." >&2 + fi + exit 1 + fi fi diff --git a/.github/workflows/pr-verify.yml b/.github/workflows/pr-verify.yml index e84e448a..60d2f075 100644 --- a/.github/workflows/pr-verify.yml +++ b/.github/workflows/pr-verify.yml @@ -30,7 +30,7 @@ jobs: cache: pnpm - name: Install dependencies - run: pnpm install --no-frozen-lockfile + run: pnpm install --frozen-lockfile - name: Typecheck run: pnpm -r typecheck diff --git a/.github/workflows/refresh-lockfile-pr.yml b/.github/workflows/refresh-lockfile-pr.yml new file mode 100644 index 00000000..7d69588b --- /dev/null +++ b/.github/workflows/refresh-lockfile-pr.yml @@ -0,0 +1,111 @@ +name: Refresh Lockfile + +on: + pull_request: + branches: + - master + types: + - opened + - synchronize + - reopened + - ready_for_review + +concurrency: + group: refresh-lockfile-pr-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + refresh: + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: write + pull-requests: read + + steps: + - name: Detect dependency manifest changes + id: changes + env: + GH_TOKEN: ${{ github.token }} + run: | + changed="$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" --paginate --jq '.[].filename')" + manifest_pattern='(^|/)package\.json$|^pnpm-workspace\.yaml$|^\.npmrc$|^pnpmfile\.(cjs|js|mjs)$' + + if printf '%s\n' "$changed" | grep -Eq "$manifest_pattern"; then + echo "manifest_changed=true" >> "$GITHUB_OUTPUT" + else + echo "manifest_changed=false" >> "$GITHUB_OUTPUT" + fi + + if [ "${{ github.event.pull_request.head.repo.full_name }}" = "${{ github.repository }}" ]; then + echo "same_repo=true" >> "$GITHUB_OUTPUT" + else + echo "same_repo=false" >> "$GITHUB_OUTPUT" + fi + + - name: Checkout pull request head + if: steps.changes.outputs.manifest_changed == 'true' + uses: actions/checkout@v4 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + fetch-depth: 0 + + - name: Setup pnpm + if: steps.changes.outputs.manifest_changed == 'true' + uses: pnpm/action-setup@v4 + with: + version: 9.15.4 + run_install: false + + - name: Setup Node.js + if: steps.changes.outputs.manifest_changed == 'true' + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + + - name: Refresh pnpm lockfile + if: steps.changes.outputs.manifest_changed == 'true' + run: pnpm install --lockfile-only --ignore-scripts --no-frozen-lockfile + + - name: Fail on unexpected file changes + if: steps.changes.outputs.manifest_changed == 'true' + run: | + changed="$(git status --porcelain)" + if [ -z "$changed" ]; then + echo "Lockfile is already up to date." + exit 0 + fi + if printf '%s\n' "$changed" | grep -Fvq ' pnpm-lock.yaml'; then + echo "Unexpected files changed during lockfile refresh:" + echo "$changed" + exit 1 + fi + + - name: Commit refreshed lockfile to same-repo PR branch + if: steps.changes.outputs.manifest_changed == 'true' && steps.changes.outputs.same_repo == 'true' + run: | + if git diff --quiet -- pnpm-lock.yaml; then + echo "Lockfile unchanged, nothing to do." + exit 0 + fi + + git config user.name "lockfile-bot" + git config user.email "lockfile-bot@users.noreply.github.com" + git add pnpm-lock.yaml + git commit -m "chore(lockfile): refresh pnpm-lock.yaml" + git push origin "HEAD:${{ github.event.pull_request.head.ref }}" + + - name: Fail fork PRs that need a lockfile refresh + if: steps.changes.outputs.manifest_changed == 'true' && steps.changes.outputs.same_repo != 'true' + run: | + if git diff --quiet -- pnpm-lock.yaml; then + echo "Lockfile unchanged, nothing to do." + exit 0 + fi + + echo "This fork PR changes dependency manifests and requires a refreshed pnpm-lock.yaml." >&2 + echo "Run: pnpm install --lockfile-only --ignore-scripts --no-frozen-lockfile" >&2 + echo "Then commit pnpm-lock.yaml to the PR branch." >&2 + exit 1 diff --git a/.github/workflows/refresh-lockfile.yml b/.github/workflows/refresh-lockfile.yml deleted file mode 100644 index a879e5bc..00000000 --- a/.github/workflows/refresh-lockfile.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Refresh Lockfile - -on: - push: - branches: - - master - workflow_dispatch: - -concurrency: - group: refresh-lockfile-master - cancel-in-progress: false - -jobs: - refresh: - runs-on: ubuntu-latest - timeout-minutes: 10 - permissions: - contents: write - pull-requests: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 9.15.4 - run_install: false - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: pnpm - - - name: Refresh pnpm lockfile - run: pnpm install --lockfile-only --ignore-scripts --no-frozen-lockfile - - - name: Fail on unexpected file changes - run: | - changed="$(git status --porcelain)" - if [ -z "$changed" ]; then - echo "Lockfile is already up to date." - exit 0 - fi - if printf '%s\n' "$changed" | grep -Fvq ' pnpm-lock.yaml'; then - echo "Unexpected files changed during lockfile refresh:" - echo "$changed" - exit 1 - fi - - - name: Create or update pull request - env: - GH_TOKEN: ${{ github.token }} - run: | - if git diff --quiet -- pnpm-lock.yaml; then - echo "Lockfile unchanged, nothing to do." - exit 0 - fi - - BRANCH="chore/refresh-lockfile" - git config user.name "lockfile-bot" - git config user.email "lockfile-bot@users.noreply.github.com" - - git checkout -B "$BRANCH" - git add pnpm-lock.yaml - git commit -m "chore(lockfile): refresh pnpm-lock.yaml" - git push --force origin "$BRANCH" - - # Create PR if one doesn't already exist - existing=$(gh pr list --head "$BRANCH" --json number --jq '.[0].number') - if [ -z "$existing" ]; then - gh pr create \ - --head "$BRANCH" \ - --title "chore(lockfile): refresh pnpm-lock.yaml" \ - --body "Auto-generated lockfile refresh after dependencies changed on master. This PR only updates pnpm-lock.yaml." - echo "Created new PR." - else - echo "PR #$existing already exists, branch updated via force push." - fi diff --git a/doc/DEVELOPING.md b/doc/DEVELOPING.md index 1ca1409b..b73a53f1 100644 --- a/doc/DEVELOPING.md +++ b/doc/DEVELOPING.md @@ -19,9 +19,9 @@ Current implementation status: GitHub Actions owns `pnpm-lock.yaml`. -- Do not commit `pnpm-lock.yaml` in pull requests. -- Pull request CI validates dependency resolution when manifests change. -- Pushes to `master` regenerate `pnpm-lock.yaml` with `pnpm install --lockfile-only --no-frozen-lockfile`, commit it back if needed, and then run verification with `--frozen-lockfile`. +- Same-repo pull requests that change dependency manifests are auto-refreshed by GitHub Actions before merge. +- Fork pull requests that change dependency manifests must include the refreshed `pnpm-lock.yaml`. +- Pull request CI validates lockfile freshness when manifests change and verifies with `--frozen-lockfile`. ## Start Dev