@fitlab-ai/agent-infra 0.9.2 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -9
- package/README.zh-CN.md +12 -9
- package/bin/cli.ts +12 -0
- package/dist/bin/cli.js +14 -0
- package/dist/bin/internal-cli.js +134 -108
- package/dist/lib/agent-clients/adapter.js +137 -4
- package/dist/lib/agent-clients/adapters/antigravity-cli.js +64 -0
- package/dist/lib/{sandbox/credentials.js → agent-clients/adapters/claude-code-credentials.js} +4 -14
- package/dist/lib/agent-clients/adapters/claude-code-refresh.js +85 -0
- package/dist/lib/agent-clients/adapters/claude-code-sandbox.js +247 -0
- package/dist/lib/agent-clients/adapters/claude-code.js +27 -4
- package/dist/lib/agent-clients/adapters/codex.js +9 -0
- package/dist/lib/agent-clients/adapters/index.js +2 -2
- package/dist/lib/agent-clients/adapters/opencode-sandbox.js +108 -0
- package/dist/lib/agent-clients/adapters/opencode.js +24 -3
- package/dist/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
- package/dist/lib/agent-clients/config.js +42 -4
- package/dist/lib/agent-clients/next-steps.js +11 -2
- package/dist/lib/agent-clients/reconcile.js +2 -1
- package/dist/lib/agent-clients/registry.js +16 -2
- package/dist/lib/agent-clients/schema.js +18 -0
- package/dist/lib/agent-clients/tokens.js +49 -0
- package/dist/lib/agent-clients/types.js +1 -1
- package/dist/lib/defaults.json +1 -1
- package/dist/lib/git/workflow.js +54 -1
- package/dist/lib/internal/agent-client.js +61 -4
- package/dist/lib/internal/git-workflow.js +6 -1
- package/dist/lib/internal/platform-checks.js +3 -3
- package/dist/lib/internal/platform-comment.js +29 -2
- package/dist/lib/internal/platform-issue.js +7 -0
- package/dist/lib/internal/platform-pr-review.js +132 -0
- package/dist/lib/internal/platform-pr.js +20 -2
- package/dist/lib/internal/platform-release-notes.js +52 -16
- package/dist/lib/internal/pr-review-grade.js +140 -0
- package/dist/lib/internal/release-workflow.js +13 -6
- package/dist/lib/internal/sandbox-control.js +24 -0
- package/dist/lib/internal/task-activity.js +105 -0
- package/dist/lib/internal/task-event.js +17 -1
- package/dist/lib/internal/task-ledger.js +12 -3
- package/dist/lib/internal/task-lifecycle.js +26 -1
- package/dist/lib/internal/task-orchestration.js +167 -18
- package/dist/lib/internal/task-review.js +8 -3
- package/dist/lib/platform/adapters.js +8 -1
- package/dist/lib/platform/completion-backfill.js +122 -0
- package/dist/lib/platform/github-client.js +19 -2
- package/dist/lib/platform/issue-comments.js +3 -2
- package/dist/lib/platform/merged-pr-equivalence.js +115 -5
- package/dist/lib/platform/pr-checks.js +65 -42
- package/dist/lib/platform/pr-review.js +166 -0
- package/dist/lib/platform/pull-requests.js +371 -4
- package/dist/lib/platform/release-notes.js +85 -3
- package/dist/lib/platform/releases.js +13 -5
- package/dist/lib/pr-review/evidence-grading.js +229 -0
- package/dist/lib/process-data/index.js +239 -0
- package/dist/lib/process-data/normalize.js +198 -0
- package/dist/lib/process-data/privacy.js +33 -0
- package/dist/lib/process-data/reconcile.js +95 -0
- package/dist/lib/process-data/repair.js +58 -0
- package/dist/lib/process-data/sources.js +345 -0
- package/dist/lib/process-data/store.js +282 -0
- package/dist/lib/process-data/types.js +2 -0
- package/dist/lib/run/index.js +4 -3
- package/dist/lib/run/tui.js +10 -13
- package/dist/lib/sandbox/agent-client-reconciler.js +26 -2
- package/dist/lib/sandbox/capture.js +7 -2
- package/dist/lib/sandbox/commands/create.js +109 -248
- package/dist/lib/sandbox/commands/enter.js +15 -47
- package/dist/lib/sandbox/commands/list-running.js +16 -6
- package/dist/lib/sandbox/commands/ls.js +10 -6
- package/dist/lib/sandbox/commands/rebuild.js +4 -3
- package/dist/lib/sandbox/commands/refresh.js +4 -84
- package/dist/lib/sandbox/commands/rm.js +24 -3
- package/dist/lib/sandbox/commands/show.js +13 -4
- package/dist/lib/sandbox/commands/start.js +7 -4
- package/dist/lib/sandbox/config.js +2 -0
- package/dist/lib/sandbox/constants.js +6 -0
- package/dist/lib/sandbox/control/client.js +44 -0
- package/dist/lib/sandbox/control/protocol.js +35 -0
- package/dist/lib/sandbox/control/server.js +109 -0
- package/dist/lib/sandbox/dockerfile.js +36 -13
- package/dist/lib/sandbox/mounts.js +17 -4
- package/dist/lib/sandbox/recovery.js +128 -5
- package/dist/lib/sandbox/redaction.js +12 -0
- package/dist/lib/sandbox/runtimes/base.dockerfile +24 -74
- package/dist/lib/sandbox/workspace-identity.js +95 -0
- package/dist/lib/sandbox/workspace-view.js +103 -0
- package/dist/lib/task/activity-intent.js +307 -0
- package/dist/lib/task/artifact-lifecycle.js +2 -1
- package/dist/lib/task/commands/log.js +15 -14
- package/dist/lib/task/commit-finalization.js +267 -0
- package/dist/lib/task/commit-intent.js +165 -0
- package/dist/lib/task/decision-intents.js +31 -17
- package/dist/lib/task/delegation-receipts.js +25 -4
- package/dist/lib/task/events.js +67 -28
- package/dist/lib/task/finalization-artifacts.js +35 -0
- package/dist/lib/task/implementation-inputs.js +54 -7
- package/dist/lib/task/ledger-intents.js +35 -1
- package/dist/lib/task/lifecycle-execution.js +46 -0
- package/dist/lib/task/orchestration.js +753 -54
- package/dist/lib/task/resolve-ref.js +41 -1
- package/dist/lib/task/review-finalization.js +29 -9
- package/dist/lib/task/task-execution-lock.js +231 -0
- package/dist/lib/task/verification-checks.js +1 -1
- package/dist/lib/task/verification-engine.js +218 -2
- package/dist/lib/task/verification.js +4 -3
- package/dist/lib/task/workspace-snapshot.js +17 -5
- package/lib/agent-clients/adapter.ts +201 -4
- package/lib/agent-clients/adapters/antigravity-cli.ts +65 -0
- package/lib/{sandbox/credentials.ts → agent-clients/adapters/claude-code-credentials.ts} +3 -18
- package/lib/agent-clients/adapters/claude-code-refresh.ts +128 -0
- package/lib/agent-clients/adapters/claude-code-sandbox.ts +295 -0
- package/lib/agent-clients/adapters/claude-code.ts +31 -4
- package/lib/agent-clients/adapters/codex.ts +9 -0
- package/lib/agent-clients/adapters/index.ts +2 -2
- package/lib/agent-clients/adapters/opencode-sandbox.ts +136 -0
- package/lib/agent-clients/adapters/opencode.ts +27 -3
- package/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
- package/lib/agent-clients/config.ts +49 -4
- package/lib/agent-clients/next-steps.ts +15 -2
- package/lib/agent-clients/reconcile.ts +2 -1
- package/lib/agent-clients/registry.ts +19 -1
- package/lib/agent-clients/schema.ts +18 -0
- package/lib/agent-clients/tokens.ts +53 -0
- package/lib/agent-clients/types.ts +15 -1
- package/lib/defaults.json +1 -1
- package/lib/git/workflow.ts +66 -2
- package/lib/internal/agent-client.ts +59 -4
- package/lib/internal/git-workflow.ts +5 -1
- package/lib/internal/platform-checks.ts +4 -4
- package/lib/internal/platform-comment.ts +17 -2
- package/lib/internal/platform-issue.ts +4 -0
- package/lib/internal/platform-pr-review.ts +104 -0
- package/lib/internal/platform-pr.ts +14 -1
- package/lib/internal/platform-release-notes.ts +59 -16
- package/lib/internal/pr-review-grade.ts +130 -0
- package/lib/internal/release-workflow.ts +13 -6
- package/lib/internal/sandbox-control.ts +24 -0
- package/lib/internal/task-activity.ts +91 -0
- package/lib/internal/task-event.ts +9 -1
- package/lib/internal/task-ledger.ts +12 -3
- package/lib/internal/task-lifecycle.ts +26 -1
- package/lib/internal/task-orchestration.ts +123 -14
- package/lib/internal/task-review.ts +8 -3
- package/lib/platform/adapters.ts +29 -2
- package/lib/platform/completion-backfill.ts +134 -0
- package/lib/platform/github-client.ts +20 -2
- package/lib/platform/issue-comments.ts +3 -2
- package/lib/platform/merged-pr-equivalence.ts +127 -5
- package/lib/platform/pr-checks.ts +73 -46
- package/lib/platform/pr-review.ts +201 -0
- package/lib/platform/pull-requests.ts +444 -3
- package/lib/platform/release-notes.ts +100 -4
- package/lib/platform/releases.ts +16 -4
- package/lib/pr-review/evidence-grading.ts +318 -0
- package/lib/process-data/index.ts +224 -0
- package/lib/process-data/normalize.ts +202 -0
- package/lib/process-data/privacy.ts +41 -0
- package/lib/process-data/reconcile.ts +110 -0
- package/lib/process-data/repair.ts +64 -0
- package/lib/process-data/sources.ts +354 -0
- package/lib/process-data/store.ts +315 -0
- package/lib/process-data/types.ts +135 -0
- package/lib/run/index.ts +5 -3
- package/lib/run/tui.ts +14 -12
- package/lib/sandbox/agent-client-reconciler.ts +44 -2
- package/lib/sandbox/capture.ts +9 -2
- package/lib/sandbox/commands/create.ts +126 -280
- package/lib/sandbox/commands/enter.ts +13 -59
- package/lib/sandbox/commands/list-running.ts +23 -6
- package/lib/sandbox/commands/ls.ts +22 -6
- package/lib/sandbox/commands/rebuild.ts +4 -3
- package/lib/sandbox/commands/refresh.ts +4 -126
- package/lib/sandbox/commands/rm.ts +24 -3
- package/lib/sandbox/commands/show.ts +30 -4
- package/lib/sandbox/commands/start.ts +6 -4
- package/lib/sandbox/config.ts +4 -0
- package/lib/sandbox/constants.ts +8 -0
- package/lib/sandbox/control/client.ts +55 -0
- package/lib/sandbox/control/protocol.ts +75 -0
- package/lib/sandbox/control/server.ts +117 -0
- package/lib/sandbox/dockerfile.ts +66 -13
- package/lib/sandbox/mounts.ts +24 -4
- package/lib/sandbox/recovery.ts +163 -6
- package/lib/sandbox/redaction.ts +14 -0
- package/lib/sandbox/runtimes/base.dockerfile +24 -74
- package/lib/sandbox/tool-types.ts +16 -0
- package/lib/sandbox/workspace-identity.ts +123 -0
- package/lib/sandbox/workspace-view.ts +143 -0
- package/lib/server/server.schema.json +2 -2
- package/lib/task/activity-intent.ts +417 -0
- package/lib/task/artifact-lifecycle.ts +2 -1
- package/lib/task/commands/log.ts +15 -14
- package/lib/task/commit-finalization.ts +356 -0
- package/lib/task/commit-intent.ts +230 -0
- package/lib/task/decision-intents.ts +32 -12
- package/lib/task/delegation-receipts.ts +34 -5
- package/lib/task/events.ts +75 -30
- package/lib/task/finalization-artifacts.ts +58 -0
- package/lib/task/implementation-inputs.ts +62 -8
- package/lib/task/ledger-intents.ts +43 -3
- package/lib/task/lifecycle-execution.ts +106 -0
- package/lib/task/orchestration.ts +1019 -72
- package/lib/task/resolve-ref.ts +46 -1
- package/lib/task/review-finalization.ts +40 -9
- package/lib/task/task-execution-lock.ts +296 -0
- package/lib/task/verification-checks.ts +1 -1
- package/lib/task/verification-engine.ts +249 -2
- package/lib/task/verification.ts +5 -3
- package/lib/task/workspace-snapshot.ts +26 -5
- package/package.json +3 -3
- package/templates/.agents/QUICKSTART.en.md +25 -8
- package/templates/.agents/QUICKSTART.zh-CN.md +25 -8
- package/templates/.agents/README.en.md +10 -7
- package/templates/.agents/README.zh-CN.md +10 -7
- package/templates/.agents/hooks/lifecycle-delegation.js +15 -4
- package/templates/.agents/rules/README.en.md +1 -1
- package/templates/.agents/rules/README.zh-CN.md +1 -1
- package/templates/.agents/rules/create-issue.github.en.md +4 -2
- package/templates/.agents/rules/create-issue.github.zh-CN.md +4 -2
- package/templates/.agents/rules/human-decision-context.en.md +11 -2
- package/templates/.agents/rules/human-decision-context.zh-CN.md +11 -2
- package/templates/.agents/rules/issue-fields.github.en.md +3 -1
- package/templates/.agents/rules/issue-fields.github.zh-CN.md +3 -1
- package/templates/.agents/rules/issue-pr-commands.en.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.github.en.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +5 -3
- package/templates/.agents/rules/issue-sync.github.en.md +7 -3
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +8 -4
- package/templates/.agents/rules/lifecycle-orchestration.en.md +5 -2
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +5 -2
- package/templates/.agents/rules/milestone-inference.github.en.md +4 -2
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -2
- package/templates/.agents/rules/next-step-output.en.md +3 -1
- package/templates/.agents/rules/next-step-output.zh-CN.md +3 -1
- package/templates/.agents/rules/no-mid-flow-questions.en.md +17 -0
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +17 -0
- package/templates/.agents/rules/pr-checks-commands.en.md +3 -3
- package/templates/.agents/rules/pr-checks-commands.github.en.md +2 -2
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +3 -3
- package/templates/.agents/rules/pr-checks-commands.zh-CN.md +3 -3
- package/templates/.agents/rules/pr-sync.en.md +3 -1
- package/templates/.agents/rules/pr-sync.github.en.md +11 -1
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +11 -1
- package/templates/.agents/rules/pr-sync.zh-CN.md +3 -1
- package/templates/.agents/rules/release-commands.en.md +1 -1
- package/templates/.agents/rules/release-commands.github.en.md +12 -2
- package/templates/.agents/rules/release-commands.github.zh-CN.md +12 -2
- package/templates/.agents/rules/release-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
- package/templates/.agents/rules/task-management.en.md +13 -0
- package/templates/.agents/rules/task-management.zh-CN.md +13 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +10 -7
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +10 -7
- package/templates/.agents/skills/block-task/SKILL.en.md +7 -5
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +7 -5
- package/templates/.agents/skills/cancel-task/SKILL.en.md +6 -4
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +6 -4
- package/templates/.agents/skills/close-codescan/SKILL.en.md +3 -1
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +3 -1
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +10 -7
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +12 -9
- package/templates/.agents/skills/commit/SKILL.en.md +23 -11
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +29 -11
- package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +49 -0
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +55 -0
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +4 -4
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +4 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +6 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +6 -4
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +22 -7
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +22 -7
- package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +17 -0
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +17 -0
- package/templates/.agents/skills/create-pr/SKILL.en.md +7 -5
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -5
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
- package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -16
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +17 -16
- package/templates/.agents/skills/create-task/SKILL.en.md +5 -3
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/create-task/reference/context-capture.en.md +34 -0
- package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +34 -0
- package/templates/.agents/skills/import-issue/SKILL.en.md +5 -3
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/plan-task/SKILL.en.md +8 -5
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +8 -5
- package/templates/.agents/skills/post-release/SKILL.en.md +2 -0
- package/templates/.agents/skills/post-release/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/release/SKILL.en.md +16 -10
- package/templates/.agents/skills/release/SKILL.zh-CN.md +16 -10
- package/templates/.agents/skills/restore-task/SKILL.en.md +4 -1
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +7 -4
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/review-code/SKILL.en.md +11 -8
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +11 -8
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +1 -1
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +1 -1
- package/templates/.agents/skills/review-plan/SKILL.en.md +7 -4
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/review-pr/SKILL.en.md +186 -0
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +186 -0
- package/templates/.agents/skills/review-pr/config/verify.en.json +37 -0
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +37 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +65 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +65 -0
- package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +18 -0
- package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +18 -0
- package/templates/.agents/skills/review-pr/reference/report-template.en.md +85 -0
- package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +85 -0
- package/templates/.agents/skills/run-task/SKILL.en.md +8 -8
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/run-task/config/verify.en.json +2 -1
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +2 -1
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +20 -0
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +20 -0
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +98 -107
- package/templates/.agents/skills/watch-pr/SKILL.en.md +13 -13
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +13 -13
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +27 -6
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +26 -5
- package/templates/.agents/templates/task.en.md +2 -2
- package/templates/.agents/templates/task.zh-CN.md +2 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +3 -3
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +3 -3
- package/templates/.agents/workflows/code-review.en.yaml +1 -1
- package/templates/.agents/workflows/code-review.zh-CN.yaml +1 -1
- package/templates/.agents/workflows/feature-development.en.yaml +4 -4
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +4 -4
- package/templates/.agents/workflows/refactoring.en.yaml +3 -3
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +3 -3
- package/templates/.claude/commands/post-release.en.md +1 -0
- package/templates/.claude/commands/post-release.zh-CN.md +1 -0
- package/templates/.claude/commands/review-pr.en.md +8 -0
- package/templates/.claude/commands/review-pr.zh-CN.md +8 -0
- package/templates/.claude/commands/watch-pr.en.md +1 -1
- package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
- package/templates/.claude/rules/tool-preferences.en.md +20 -0
- package/templates/.claude/rules/tool-preferences.zh-CN.md +20 -0
- package/templates/.opencode/commands/post-release.en.md +2 -0
- package/templates/.opencode/commands/post-release.zh-CN.md +2 -0
- package/templates/.opencode/commands/review-pr.en.md +11 -0
- package/templates/.opencode/commands/review-pr.zh-CN.md +11 -0
- package/templates/.opencode/commands/watch-pr.en.md +1 -1
- package/templates/.opencode/commands/watch-pr.zh-CN.md +1 -1
- package/dist/lib/agent-clients/adapters/gemini-cli.js +0 -64
- package/lib/agent-clients/adapters/gemini-cli.ts +0 -65
- package/templates/.gemini/commands/_project_/analyze-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/archive-tasks.en.toml +0 -10
- package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/block-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/cancel-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/check-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/close-codescan.en.toml +0 -8
- package/templates/.gemini/commands/_project_/close-codescan.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/close-dependabot.en.toml +0 -8
- package/templates/.gemini/commands/_project_/close-dependabot.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/code-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/commit.en.toml +0 -10
- package/templates/.gemini/commands/_project_/commit.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/create-pr.en.toml +0 -10
- package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/create-release-note.en.toml +0 -8
- package/templates/.gemini/commands/_project_/create-release-note.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/create-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/create-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-codescan.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-codescan.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-dependabot.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-dependabot.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-issue.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-issue.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/init-labels.en.toml +0 -8
- package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/init-milestones.en.toml +0 -10
- package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/plan-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/post-release.en.toml +0 -6
- package/templates/.gemini/commands/_project_/post-release.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/refine-title.en.toml +0 -8
- package/templates/.gemini/commands/_project_/refine-title.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/release.en.toml +0 -8
- package/templates/.gemini/commands/_project_/release.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/restore-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/review-analysis.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/review-code.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/review-plan.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/run-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/test-integration.en.toml +0 -6
- package/templates/.gemini/commands/_project_/test-integration.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/test.en.toml +0 -6
- package/templates/.gemini/commands/_project_/test.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/update-agent-infra.en.toml +0 -6
- package/templates/.gemini/commands/_project_/update-agent-infra.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/upgrade-dependency.en.toml +0 -8
- package/templates/.gemini/commands/_project_/upgrade-dependency.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/watch-pr.en.toml +0 -10
- package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +0 -10
- package/templates/.gemini/settings.json +0 -3
|
@@ -1,13 +1,53 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { containerNameCandidates, sandboxBranchLabel, sandboxLabel, sandboxRuntimeCapabilityLabel, sandboxTaskIdLabel, sandboxWorkspaceModeLabel } from './constants.js';
|
|
4
6
|
import { isAgentClientId } from '../agent-clients/types.js';
|
|
5
7
|
import { createSandboxCapabilityPlan } from './agent-client-reconciler.js';
|
|
6
8
|
import { toEnginePath } from './engines/wsl2-paths.js';
|
|
7
9
|
import { sandboxCoreBindMounts } from './mounts.js';
|
|
10
|
+
import { assertSandboxTaskSource, sandboxControlPaths, sandboxWorkspaceViewPaths } from './workspace-view.js';
|
|
11
|
+
import { parseSandboxWorkspaceIdentity, sameSandboxWorkspaceIdentity } from './workspace-identity.js';
|
|
8
12
|
import { runEngine, runOkEngine, runVerboseEngine } from './shell.js';
|
|
9
13
|
import { declaredTmpfsSeedEntries, resolveTools, toolConfigDirCandidates } from './tools.js';
|
|
10
14
|
import { fetchSandboxRows, selectSandboxContainer, startSandboxContainer } from './commands/list-running.js';
|
|
15
|
+
import { processIdentityMatches } from '../server/process-state.js';
|
|
16
|
+
function ensureSandboxControlBroker(params) {
|
|
17
|
+
const control = sandboxControlPaths({
|
|
18
|
+
base: params.config.controlBase ?? path.join(params.config.home, '.agent-infra', 'sandbox-control'),
|
|
19
|
+
project: params.config.project,
|
|
20
|
+
container: params.container,
|
|
21
|
+
identity: params.workspace
|
|
22
|
+
});
|
|
23
|
+
if (!fs.existsSync(control.manifestPath))
|
|
24
|
+
return;
|
|
25
|
+
const manifest = JSON.parse(fs.readFileSync(control.manifestPath, 'utf8'));
|
|
26
|
+
const brokerPath = path.join(control.root, 'broker.json');
|
|
27
|
+
try {
|
|
28
|
+
const broker = JSON.parse(fs.readFileSync(brokerPath, 'utf8'));
|
|
29
|
+
if (broker.version === 1
|
|
30
|
+
&& typeof broker.pid === 'number'
|
|
31
|
+
&& typeof broker.startTime === 'string'
|
|
32
|
+
&& broker.token === manifest.token
|
|
33
|
+
&& processIdentityMatches({ version: 1, pid: broker.pid, startTime: broker.startTime }))
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// A missing, stale, or malformed broker record is replaced below.
|
|
38
|
+
}
|
|
39
|
+
fs.rmSync(brokerPath, { force: true });
|
|
40
|
+
const directory = path.dirname(fileURLToPath(import.meta.url));
|
|
41
|
+
const extension = path.extname(fileURLToPath(import.meta.url));
|
|
42
|
+
const internalCli = path.resolve(directory, '..', '..', 'bin', `internal-cli${extension}`);
|
|
43
|
+
const child = spawn(process.execPath, [internalCli, 'sandbox-control', 'serve', '--manifest', control.manifestPath], { cwd: params.config.repoRoot, detached: true, stdio: 'ignore' });
|
|
44
|
+
child.once('error', () => {
|
|
45
|
+
// Readiness remains fail-closed; a later control request reports the
|
|
46
|
+
// unavailable broker without turning this detached spawn into an
|
|
47
|
+
// unhandled process error.
|
|
48
|
+
});
|
|
49
|
+
child.unref();
|
|
50
|
+
}
|
|
11
51
|
function findingKey(finding) {
|
|
12
52
|
return `${finding.repairKind}:${finding.path ?? finding.seed?.targetPath ?? finding.message}`;
|
|
13
53
|
}
|
|
@@ -156,7 +196,28 @@ function hostSourceAccessible(hostPath, writable) {
|
|
|
156
196
|
}
|
|
157
197
|
function expectedMounts(params) {
|
|
158
198
|
const { config, branch, tools, actualMounts } = params;
|
|
159
|
-
const
|
|
199
|
+
const view = sandboxWorkspaceViewPaths({
|
|
200
|
+
base: config.workspaceViewBase ?? path.join(config.home, '.agent-infra', 'workspace-views'),
|
|
201
|
+
project: config.project,
|
|
202
|
+
container: params.container,
|
|
203
|
+
identity: params.workspace
|
|
204
|
+
});
|
|
205
|
+
const control = sandboxControlPaths({
|
|
206
|
+
base: config.controlBase ?? path.join(config.home, '.agent-infra', 'sandbox-control'),
|
|
207
|
+
project: config.project,
|
|
208
|
+
container: params.container,
|
|
209
|
+
identity: params.workspace
|
|
210
|
+
});
|
|
211
|
+
const core = sandboxCoreBindMounts(config, branch, {
|
|
212
|
+
workspaceViewRoot: view.root,
|
|
213
|
+
controlDir: control.channelDir,
|
|
214
|
+
...(params.workspace.mode === 'task-bound'
|
|
215
|
+
? {
|
|
216
|
+
taskSource: assertSandboxTaskSource(config.repoRoot, params.workspace.taskId),
|
|
217
|
+
taskId: params.workspace.taskId
|
|
218
|
+
}
|
|
219
|
+
: {})
|
|
220
|
+
}).map((mount) => ({
|
|
160
221
|
path: mount.containerPath,
|
|
161
222
|
expectedType: 'bind',
|
|
162
223
|
hostPaths: mount.hostPaths,
|
|
@@ -248,6 +309,7 @@ export function collectSandboxRecoverySnapshot(params) {
|
|
|
248
309
|
}
|
|
249
310
|
}
|
|
250
311
|
const capabilityPlan = createSandboxCapabilityPlan(params.config);
|
|
312
|
+
const workspace = params.workspace ?? { mode: 'branch-only' };
|
|
251
313
|
const tools = [...capabilityPlan.tools];
|
|
252
314
|
const seeds = declaredTmpfsSeedEntries(tools).map((seed) => {
|
|
253
315
|
const mounted = mountsByDestination.get(seed.stagingPath)?.Type === 'bind';
|
|
@@ -269,6 +331,10 @@ export function collectSandboxRecoverySnapshot(params) {
|
|
|
269
331
|
}));
|
|
270
332
|
const labels = inspection.Config?.Labels ?? {};
|
|
271
333
|
const branchLabel = labels[sandboxBranchLabel(params.config)];
|
|
334
|
+
const containerWorkspace = parseSandboxWorkspaceIdentity(labels, {
|
|
335
|
+
mode: sandboxWorkspaceModeLabel(params.config),
|
|
336
|
+
taskId: sandboxTaskIdLabel(params.config)
|
|
337
|
+
});
|
|
272
338
|
const selectedToolIds = new Set(tools.map((tool) => tool.id));
|
|
273
339
|
const enforceCanonicalPlan = params.config.agentClientSource === 'canonical';
|
|
274
340
|
const unexpectedCapabilityMounts = enforceCanonicalPlan
|
|
@@ -280,6 +346,8 @@ export function collectSandboxRecoverySnapshot(params) {
|
|
|
280
346
|
const mountSnapshots = expectedMounts({
|
|
281
347
|
config: params.config,
|
|
282
348
|
branch: params.branch,
|
|
349
|
+
container: params.container,
|
|
350
|
+
workspace,
|
|
283
351
|
tools,
|
|
284
352
|
actualMounts: mountsByDestination
|
|
285
353
|
}).map((expected) => {
|
|
@@ -313,7 +381,8 @@ export function collectSandboxRecoverySnapshot(params) {
|
|
|
313
381
|
return {
|
|
314
382
|
identityOk: typeof inspection.Id === 'string'
|
|
315
383
|
&& inspection.Id.length > 0
|
|
316
|
-
&& branchLabel === params.branch
|
|
384
|
+
&& branchLabel === params.branch
|
|
385
|
+
&& sameSandboxWorkspaceIdentity(containerWorkspace, workspace),
|
|
317
386
|
runtimeCapabilityOk: enforceCanonicalPlan
|
|
318
387
|
? labels[sandboxRuntimeCapabilityLabel(params.config)] === capabilityPlan.runtimeSignature
|
|
319
388
|
: undefined,
|
|
@@ -424,14 +493,51 @@ function assess(params) {
|
|
|
424
493
|
const snapshot = collectSandboxRecoverySnapshot(params);
|
|
425
494
|
return { snapshot, findings: classifySandboxRecovery(snapshot) };
|
|
426
495
|
}
|
|
427
|
-
|
|
496
|
+
function canRetryFreshReadiness(findings) {
|
|
497
|
+
return findings.length > 0 && findings.every((finding) => finding.repairKind === 'hard-failure'
|
|
498
|
+
&& finding.path !== undefined
|
|
499
|
+
&& (finding.path.startsWith('/workspace/.agents/workspace')
|
|
500
|
+
|| finding.path === '/home/devuser/.host-shell-config'
|
|
501
|
+
|| finding.path === '/home/devuser/.bash_aliases'));
|
|
502
|
+
}
|
|
503
|
+
export async function assertFreshSandboxReady(params) {
|
|
428
504
|
validateTmpfsSeedEntries({
|
|
429
505
|
engine: params.engine,
|
|
430
506
|
container: params.container,
|
|
431
507
|
entries: params.copiedEntries,
|
|
432
508
|
deps: params.deps
|
|
433
509
|
});
|
|
434
|
-
|
|
510
|
+
let { findings } = assess(params);
|
|
511
|
+
if (canRetryFreshReadiness(findings)) {
|
|
512
|
+
const runVerboseFn = params.deps?.runVerbose ?? runVerboseEngine;
|
|
513
|
+
runVerboseFn(params.engine, 'docker', ['restart', params.container]);
|
|
514
|
+
prepareTmpfsMounts({
|
|
515
|
+
engine: params.engine,
|
|
516
|
+
container: params.container,
|
|
517
|
+
mountPaths: resolveTools(params.config)
|
|
518
|
+
.filter((tool) => tool.tmpfs)
|
|
519
|
+
.map((tool) => tool.containerMount),
|
|
520
|
+
deps: params.deps
|
|
521
|
+
});
|
|
522
|
+
hydrateTmpfsSeedEntries({
|
|
523
|
+
engine: params.engine,
|
|
524
|
+
container: params.container,
|
|
525
|
+
entries: params.copiedEntries,
|
|
526
|
+
replace: true,
|
|
527
|
+
deps: params.deps
|
|
528
|
+
});
|
|
529
|
+
let retried = assess(params);
|
|
530
|
+
if (!retried.findings.some((finding) => finding.repairKind === 'hard-failure')) {
|
|
531
|
+
repairFindings({
|
|
532
|
+
engine: params.engine,
|
|
533
|
+
container: params.container,
|
|
534
|
+
findings: retried.findings,
|
|
535
|
+
deps: params.deps
|
|
536
|
+
});
|
|
537
|
+
retried = assess(params);
|
|
538
|
+
}
|
|
539
|
+
findings = retried.findings;
|
|
540
|
+
}
|
|
435
541
|
if (findings.length > 0) {
|
|
436
542
|
throw new Error(`Fresh sandbox readiness check failed: ${describeFindings(findings)}`);
|
|
437
543
|
}
|
|
@@ -441,6 +547,11 @@ export async function ensureSandboxReady(params) {
|
|
|
441
547
|
const startFn = deps?.start ?? startSandboxContainer;
|
|
442
548
|
const warnings = [];
|
|
443
549
|
let failure = null;
|
|
550
|
+
ensureSandboxControlBroker({
|
|
551
|
+
config: params.config,
|
|
552
|
+
container: params.row.name,
|
|
553
|
+
workspace: params.workspace ?? { mode: 'branch-only' }
|
|
554
|
+
});
|
|
444
555
|
try {
|
|
445
556
|
if (!params.row.running) {
|
|
446
557
|
startFn(params.engine, params.row.name);
|
|
@@ -448,6 +559,7 @@ export async function ensureSandboxReady(params) {
|
|
|
448
559
|
config: params.config,
|
|
449
560
|
engine: params.engine,
|
|
450
561
|
branch: params.branch,
|
|
562
|
+
workspace: params.workspace,
|
|
451
563
|
container: params.row.name,
|
|
452
564
|
deps
|
|
453
565
|
});
|
|
@@ -472,6 +584,7 @@ export async function ensureSandboxReady(params) {
|
|
|
472
584
|
config: params.config,
|
|
473
585
|
engine: params.engine,
|
|
474
586
|
branch: params.branch,
|
|
587
|
+
workspace: params.workspace,
|
|
475
588
|
container: params.row.name,
|
|
476
589
|
deps
|
|
477
590
|
});
|
|
@@ -486,6 +599,7 @@ export async function ensureSandboxReady(params) {
|
|
|
486
599
|
config: params.config,
|
|
487
600
|
engine: params.engine,
|
|
488
601
|
branch: params.branch,
|
|
602
|
+
workspace: params.workspace,
|
|
489
603
|
container: params.row.name,
|
|
490
604
|
deps
|
|
491
605
|
});
|
|
@@ -499,6 +613,7 @@ export async function ensureSandboxReady(params) {
|
|
|
499
613
|
config: params.config,
|
|
500
614
|
engine: params.engine,
|
|
501
615
|
branch: params.branch,
|
|
616
|
+
workspace: params.workspace,
|
|
502
617
|
container: params.row.name,
|
|
503
618
|
deps
|
|
504
619
|
});
|
|
@@ -521,6 +636,7 @@ export async function ensureSandboxReady(params) {
|
|
|
521
636
|
config: params.config,
|
|
522
637
|
engine: params.engine,
|
|
523
638
|
branch: params.branch,
|
|
639
|
+
workspace: params.workspace,
|
|
524
640
|
container: params.row.name,
|
|
525
641
|
deps
|
|
526
642
|
});
|
|
@@ -539,6 +655,7 @@ export async function ensureSandboxReady(params) {
|
|
|
539
655
|
config: params.config,
|
|
540
656
|
engine: params.engine,
|
|
541
657
|
branch: params.branch,
|
|
658
|
+
workspace: params.workspace,
|
|
542
659
|
container: params.row.name,
|
|
543
660
|
deps
|
|
544
661
|
});
|
|
@@ -557,6 +674,11 @@ export async function ensureSandboxReady(params) {
|
|
|
557
674
|
const warning = `Sandbox recovery failed in place. Replacing only the container. ${dataBoundary}`;
|
|
558
675
|
warnings.push(warning);
|
|
559
676
|
(params.writeWarning ?? ((message) => process.stderr.write(`${message}\n`)))(warning);
|
|
677
|
+
const runVerboseFn = deps?.runVerbose ?? runVerboseEngine;
|
|
678
|
+
if (params.row.running) {
|
|
679
|
+
runVerboseFn(params.engine, 'docker', ['stop', params.row.name]);
|
|
680
|
+
}
|
|
681
|
+
runVerboseFn(params.engine, 'docker', ['rm', params.row.name]);
|
|
560
682
|
await params.recreate(params.branch);
|
|
561
683
|
const rows = (deps?.fetchRows ?? fetchSandboxRows)(params.engine, sandboxLabel(params.config), sandboxBranchLabel(params.config));
|
|
562
684
|
const replacement = selectSandboxContainer([...rows.running, ...rows.nonRunning], containerNameCandidates(params.config, params.branch));
|
|
@@ -567,6 +689,7 @@ export async function ensureSandboxReady(params) {
|
|
|
567
689
|
config: params.config,
|
|
568
690
|
engine: params.engine,
|
|
569
691
|
branch: params.branch,
|
|
692
|
+
workspace: params.workspace,
|
|
570
693
|
container: replacement.name,
|
|
571
694
|
deps
|
|
572
695
|
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const SENSITIVE_OUTPUT_PATTERNS = [
|
|
2
|
+
{ pattern: /\{[^{}]*"claudeAiOauth"[\s\S]*?\}\s*\}/g, replacement: '[REDACTED credentials blob]' },
|
|
3
|
+
{ pattern: /sk-ant-[A-Za-z0-9_-]{20,}/g, replacement: '[REDACTED claude token]' },
|
|
4
|
+
{ pattern: /gh[psoru]_[A-Za-z0-9]{30,}/g, replacement: '[REDACTED github token]' },
|
|
5
|
+
{ pattern: /Bearer\s+[A-Za-z0-9._~+/=-]{20,}/gi, replacement: 'Bearer [REDACTED]' }
|
|
6
|
+
];
|
|
7
|
+
export function redactCommandError(text) {
|
|
8
|
+
if (!text || typeof text !== 'string')
|
|
9
|
+
return '';
|
|
10
|
+
return SENSITIVE_OUTPUT_PATTERNS.reduce((result, { pattern, replacement }) => result.replace(pattern, replacement), text);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=redaction.js.map
|
|
@@ -64,69 +64,9 @@ RUN printf '%s\n' \
|
|
|
64
64
|
'set -g mouse on' \
|
|
65
65
|
'set -g status-interval 1' \
|
|
66
66
|
'set -g status-right-length 80' \
|
|
67
|
-
"set -g status-right '
|
|
67
|
+
"set -g status-right '%H:%M'" \
|
|
68
68
|
> /etc/tmux.conf
|
|
69
69
|
|
|
70
|
-
RUN cat > /usr/local/bin/cc-token-status <<'SCRIPT' && chmod +x /usr/local/bin/cc-token-status
|
|
71
|
-
#!/bin/sh
|
|
72
|
-
set -eu
|
|
73
|
-
|
|
74
|
-
SETTINGS_FILE="/home/devuser/.claude/settings.json"
|
|
75
|
-
if [ -r "$SETTINGS_FILE" ] && jq -e '
|
|
76
|
-
def has_nonempty($v):
|
|
77
|
-
if ($v | type) == "string" then ($v | gsub("^\\s+|\\s+$"; "") | length) > 0 else false end;
|
|
78
|
-
(if type == "object" then . else {} end) as $settings
|
|
79
|
-
| (if ($settings.env | type) == "object" then $settings.env else {} end) as $env
|
|
80
|
-
| has_nonempty($env.ANTHROPIC_AUTH_TOKEN)
|
|
81
|
-
or has_nonempty($env.ANTHROPIC_API_KEY)
|
|
82
|
-
or has_nonempty($settings.apiKeyHelper)
|
|
83
|
-
' "$SETTINGS_FILE" >/dev/null 2>&1; then
|
|
84
|
-
exit 0
|
|
85
|
-
fi
|
|
86
|
-
|
|
87
|
-
CRED_FILE="/home/devuser/.claude/.credentials.json"
|
|
88
|
-
[ -r "$CRED_FILE" ] || exit 0
|
|
89
|
-
|
|
90
|
-
EXPIRES_MS=$(jq -r '(.claudeAiOauth.expiresAt // .expiresAt) // empty' "$CRED_FILE" 2>/dev/null || true)
|
|
91
|
-
case "$EXPIRES_MS" in
|
|
92
|
-
''|*[!0-9]*) exit 0 ;;
|
|
93
|
-
esac
|
|
94
|
-
|
|
95
|
-
NOW_MS=$(($(date +%s) * 1000))
|
|
96
|
-
DIFF_MS=$((EXPIRES_MS - NOW_MS))
|
|
97
|
-
DIFF_S=$((DIFF_MS / 1000))
|
|
98
|
-
|
|
99
|
-
DIM='#[fg=colour245]'
|
|
100
|
-
YELLOW='#[fg=yellow]'
|
|
101
|
-
YELLOW_BOLD='#[fg=yellow,bold]'
|
|
102
|
-
RED_BOLD='#[fg=red,bold]'
|
|
103
|
-
RED_REV='#[fg=red,reverse]'
|
|
104
|
-
RESET='#[default]'
|
|
105
|
-
|
|
106
|
-
if [ "$DIFF_S" -le 0 ]; then
|
|
107
|
-
ELAPSED=$(( -DIFF_S ))
|
|
108
|
-
M=$((ELAPSED / 60))
|
|
109
|
-
printf '%sClaude Code auth EXPIRED %dm ago%s' "$RED_REV" "$M" "$RESET"
|
|
110
|
-
elif [ "$DIFF_S" -lt 60 ]; then
|
|
111
|
-
printf '%sClaude Code auth expires in %ds%s' "$RED_BOLD" "$DIFF_S" "$RESET"
|
|
112
|
-
elif [ "$DIFF_S" -lt 300 ]; then
|
|
113
|
-
M=$((DIFF_S / 60))
|
|
114
|
-
S=$((DIFF_S % 60))
|
|
115
|
-
printf '%sClaude Code auth expires in %dm %ds%s' "$RED_BOLD" "$M" "$S" "$RESET"
|
|
116
|
-
elif [ "$DIFF_S" -lt 1800 ]; then
|
|
117
|
-
M=$((DIFF_S / 60))
|
|
118
|
-
printf '%sClaude Code auth expires in %dm%s' "$YELLOW_BOLD" "$M" "$RESET"
|
|
119
|
-
elif [ "$DIFF_S" -lt 3600 ]; then
|
|
120
|
-
M=$((DIFF_S / 60))
|
|
121
|
-
printf '%sClaude Code auth expires in %dm%s' "$YELLOW" "$M" "$RESET"
|
|
122
|
-
else
|
|
123
|
-
TOTAL_M=$((DIFF_S / 60))
|
|
124
|
-
H=$((TOTAL_M / 60))
|
|
125
|
-
M=$((TOTAL_M % 60))
|
|
126
|
-
printf '%sClaude Code auth expires in %dh %dm%s' "$DIM" "$H" "$M" "$RESET"
|
|
127
|
-
fi
|
|
128
|
-
SCRIPT
|
|
129
|
-
|
|
130
70
|
RUN cat > /usr/local/bin/sandbox-dotfiles-link <<'SCRIPT' && chmod +x /usr/local/bin/sandbox-dotfiles-link
|
|
131
71
|
#!/bin/sh
|
|
132
72
|
# Mirror /dotfiles/ tree as symlinks under $HOME/, overwriting any image-baked
|
|
@@ -136,23 +76,34 @@ set -eu
|
|
|
136
76
|
DOTFILES_SRC=/dotfiles
|
|
137
77
|
[ -d "$DOTFILES_SRC" ] || exit 0
|
|
138
78
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
target="$HOME/$rel"
|
|
143
|
-
case "$rel" in
|
|
79
|
+
is_dotfiles_excluded() {
|
|
80
|
+
candidate=$1
|
|
81
|
+
case "$candidate" in
|
|
144
82
|
.ssh|.ssh/*|\
|
|
145
83
|
.gnupg|.gnupg/*|\
|
|
146
|
-
.claude|.claude/*|\
|
|
147
|
-
.codex|.codex/*|\
|
|
148
|
-
.gemini|.gemini/*|\
|
|
149
|
-
.config/opencode|.config/opencode/*|\
|
|
150
|
-
.local/share/opencode|.local/share/opencode/*|\
|
|
151
84
|
.host-shell-config|.host-shell-config/*|\
|
|
152
85
|
.gitconfig|.gitignore_global|.stCommitMsg|.bash_aliases|README.md)
|
|
153
|
-
|
|
86
|
+
return 0 ;;
|
|
154
87
|
esac
|
|
155
88
|
|
|
89
|
+
[ -r /etc/agent-infra/dotfiles-exclusions ] || return 1
|
|
90
|
+
while IFS= read -r prefix; do
|
|
91
|
+
[ -n "$prefix" ] || continue
|
|
92
|
+
case "$candidate" in
|
|
93
|
+
"$prefix"|"$prefix"/*) return 0 ;;
|
|
94
|
+
esac
|
|
95
|
+
done < /etc/agent-infra/dotfiles-exclusions
|
|
96
|
+
return 1
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
cd "$DOTFILES_SRC"
|
|
100
|
+
find . -type f -print | while IFS= read -r rel; do
|
|
101
|
+
rel=${rel#./}
|
|
102
|
+
target="$HOME/$rel"
|
|
103
|
+
if is_dotfiles_excluded "$rel"; then
|
|
104
|
+
continue
|
|
105
|
+
fi
|
|
106
|
+
|
|
156
107
|
mkdir -p "$(dirname "$target")"
|
|
157
108
|
if [ -d "$target" ] && [ ! -L "$target" ]; then
|
|
158
109
|
printf 'sandbox-dotfiles-link: skipping %s (existing directory; use nested path like %s/<file> instead)\n' "$target" "$rel" >&2
|
|
@@ -198,8 +149,7 @@ fi
|
|
|
198
149
|
exec tmux new-session -s "$SESSION"
|
|
199
150
|
SCRIPT
|
|
200
151
|
|
|
201
|
-
RUN test -s /usr/local/bin/
|
|
202
|
-
test -s /usr/local/bin/sandbox-dotfiles-link && test -x /usr/local/bin/sandbox-dotfiles-link && \
|
|
152
|
+
RUN test -s /usr/local/bin/sandbox-dotfiles-link && test -x /usr/local/bin/sandbox-dotfiles-link && \
|
|
203
153
|
test -s /usr/local/bin/sandbox-tmux-entry && test -x /usr/local/bin/sandbox-tmux-entry
|
|
204
154
|
|
|
205
155
|
ENV LANG=en_US.UTF-8
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isRemovedHashShortIdInput } from '../task/short-id.js';
|
|
4
|
+
const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
|
|
5
|
+
const SHORT_ID_RE = /^\d+$/;
|
|
6
|
+
function stripQuotes(value) {
|
|
7
|
+
return value.replace(/^(?:"([^"]*)"|'([^']*)')$/, '$1$2');
|
|
8
|
+
}
|
|
9
|
+
function taskBranch(taskMd, taskId) {
|
|
10
|
+
const content = fs.readFileSync(taskMd, 'utf8');
|
|
11
|
+
const value = content.match(/^branch:\s*(.+)$/m)?.[1]?.trim()
|
|
12
|
+
?? content.match(/^- \*\*(?:分支|Branch)\*\*:[ \t]*`?([^`\n]+)`?$/m)?.[1]?.trim();
|
|
13
|
+
if (!value)
|
|
14
|
+
throw new Error(`Task ${taskId} has no branch field in task.md`);
|
|
15
|
+
return stripQuotes(value);
|
|
16
|
+
}
|
|
17
|
+
function activeRegistry(repoRoot) {
|
|
18
|
+
const registryPath = path.join(repoRoot, '.agents', 'workspace', 'active', '.short-ids.json');
|
|
19
|
+
if (!fs.existsSync(registryPath))
|
|
20
|
+
return {};
|
|
21
|
+
const value = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
|
|
22
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
23
|
+
throw new Error('Active task short-id registry is invalid');
|
|
24
|
+
}
|
|
25
|
+
const ids = 'ids' in value && value.ids && typeof value.ids === 'object' && !Array.isArray(value.ids)
|
|
26
|
+
? value.ids
|
|
27
|
+
: value;
|
|
28
|
+
return Object.fromEntries(Object.entries(ids).filter((entry) => SHORT_ID_RE.test(entry[0]) && typeof entry[1] === 'string' && TASK_ID_RE.test(entry[1])));
|
|
29
|
+
}
|
|
30
|
+
function taskIdentity(repoRoot, taskId, registry) {
|
|
31
|
+
const taskMd = path.join(repoRoot, '.agents', 'workspace', 'active', taskId, 'task.md');
|
|
32
|
+
if (!fs.existsSync(taskMd))
|
|
33
|
+
throw new Error(`Active task not found: ${taskId}`);
|
|
34
|
+
const shortIds = Object.entries(registry).filter(([, id]) => id === taskId).map(([shortId]) => shortId);
|
|
35
|
+
if (shortIds.length !== 1) {
|
|
36
|
+
throw new Error(`Task ${taskId} must have exactly one active short id`);
|
|
37
|
+
}
|
|
38
|
+
return { mode: 'task-bound', taskId, shortId: shortIds[0] };
|
|
39
|
+
}
|
|
40
|
+
export function resolveSandboxTarget(requestedRef, repoRoot) {
|
|
41
|
+
if (isRemovedHashShortIdInput(requestedRef)) {
|
|
42
|
+
throw new Error(`Invalid task short id '${requestedRef}': task short ids must use bare digits`);
|
|
43
|
+
}
|
|
44
|
+
const registry = activeRegistry(repoRoot);
|
|
45
|
+
if (SHORT_ID_RE.test(requestedRef)) {
|
|
46
|
+
const matchingShortIds = Object.keys(registry).filter((shortId) => shortId === requestedRef || Number(shortId) === Number(requestedRef));
|
|
47
|
+
if (matchingShortIds.length > 1) {
|
|
48
|
+
throw new Error(`Short id '${requestedRef}' is ambiguous in active task registry`);
|
|
49
|
+
}
|
|
50
|
+
const canonicalShortId = matchingShortIds[0];
|
|
51
|
+
const taskId = canonicalShortId ? registry[canonicalShortId] : undefined;
|
|
52
|
+
if (!taskId)
|
|
53
|
+
throw new Error(`Short id '${requestedRef}' not found in active task registry`);
|
|
54
|
+
const workspace = taskIdentity(repoRoot, taskId, registry);
|
|
55
|
+
return { requestedRef, branch: taskBranch(path.join(repoRoot, '.agents', 'workspace', 'active', taskId, 'task.md'), taskId), workspace };
|
|
56
|
+
}
|
|
57
|
+
if (TASK_ID_RE.test(requestedRef)) {
|
|
58
|
+
const workspace = taskIdentity(repoRoot, requestedRef, registry);
|
|
59
|
+
return { requestedRef, branch: taskBranch(path.join(repoRoot, '.agents', 'workspace', 'active', requestedRef, 'task.md'), requestedRef), workspace };
|
|
60
|
+
}
|
|
61
|
+
const activeRoot = path.join(repoRoot, '.agents', 'workspace', 'active');
|
|
62
|
+
const matches = fs.existsSync(activeRoot)
|
|
63
|
+
? fs.readdirSync(activeRoot, { withFileTypes: true }).flatMap((entry) => {
|
|
64
|
+
if (!entry.isDirectory() || !TASK_ID_RE.test(entry.name))
|
|
65
|
+
return [];
|
|
66
|
+
const taskMd = path.join(activeRoot, entry.name, 'task.md');
|
|
67
|
+
if (!fs.existsSync(taskMd))
|
|
68
|
+
return [];
|
|
69
|
+
return taskBranch(taskMd, entry.name) === requestedRef ? [entry.name] : [];
|
|
70
|
+
})
|
|
71
|
+
: [];
|
|
72
|
+
if (matches.length > 1) {
|
|
73
|
+
throw new Error(`SANDBOX_TASK_IDENTITY_AMBIGUOUS: branch '${requestedRef}' is bound to multiple active tasks`);
|
|
74
|
+
}
|
|
75
|
+
if (matches.length === 1) {
|
|
76
|
+
const taskId = matches[0];
|
|
77
|
+
return { requestedRef, branch: requestedRef, workspace: taskIdentity(repoRoot, taskId, registry) };
|
|
78
|
+
}
|
|
79
|
+
return { requestedRef, branch: requestedRef, workspace: { mode: 'branch-only' } };
|
|
80
|
+
}
|
|
81
|
+
export function parseSandboxWorkspaceIdentity(labels, keys) {
|
|
82
|
+
const mode = labels[keys.mode];
|
|
83
|
+
const taskId = labels[keys.taskId];
|
|
84
|
+
if (mode === 'branch-only' && taskId === undefined)
|
|
85
|
+
return { mode: 'branch-only' };
|
|
86
|
+
if (mode === 'task-bound' && typeof taskId === 'string' && TASK_ID_RE.test(taskId)) {
|
|
87
|
+
return { mode: 'task-bound', taskId };
|
|
88
|
+
}
|
|
89
|
+
return { mode: 'legacy-invalid' };
|
|
90
|
+
}
|
|
91
|
+
export function sameSandboxWorkspaceIdentity(left, right) {
|
|
92
|
+
return left.mode === right.mode
|
|
93
|
+
&& (left.mode !== 'task-bound' || (right.mode === 'task-bound' && left.taskId === right.taskId));
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=workspace-identity.js.map
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export function sandboxWorkspaceViewPaths(params) {
|
|
5
|
+
const identityKey = params.identity.mode === 'task-bound'
|
|
6
|
+
? `task-bound:${params.identity.taskId}`
|
|
7
|
+
: 'branch-only';
|
|
8
|
+
const digest = createHash('sha256').update(identityKey).digest('hex').slice(0, 16);
|
|
9
|
+
const projectRoot = path.resolve(params.base, params.project);
|
|
10
|
+
const root = path.resolve(projectRoot, params.container, digest);
|
|
11
|
+
return {
|
|
12
|
+
root,
|
|
13
|
+
taskMountPath: params.identity.mode === 'task-bound'
|
|
14
|
+
? path.join(root, 'active', params.identity.taskId)
|
|
15
|
+
: null
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function sandboxControlPaths(params) {
|
|
19
|
+
const identityKey = params.identity.mode === 'task-bound'
|
|
20
|
+
? `task-bound:${params.identity.taskId}`
|
|
21
|
+
: 'branch-only';
|
|
22
|
+
const digest = createHash('sha256').update(identityKey).digest('hex').slice(0, 16);
|
|
23
|
+
const root = path.resolve(params.base, params.project, params.container, digest);
|
|
24
|
+
return { root, channelDir: path.join(root, 'channel'), manifestPath: path.join(root, 'manifest.json') };
|
|
25
|
+
}
|
|
26
|
+
function assertSafeDirectory(directory, expectedBase) {
|
|
27
|
+
const relative = path.relative(expectedBase, directory);
|
|
28
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
29
|
+
throw new Error(`Sandbox workspace view escapes its configured root: ${directory}`);
|
|
30
|
+
}
|
|
31
|
+
if (fs.existsSync(directory) && fs.lstatSync(directory).isSymbolicLink()) {
|
|
32
|
+
throw new Error(`Sandbox workspace view must not be a symbolic link: ${directory}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function assertSandboxTaskSource(repoRoot, taskId) {
|
|
36
|
+
if (!/^TASK-\d{8}-\d{6}$/.test(taskId))
|
|
37
|
+
throw new Error('SANDBOX_TASK_SOURCE_INVALID');
|
|
38
|
+
const activeRoot = fs.realpathSync.native(path.join(repoRoot, '.agents', 'workspace', 'active'));
|
|
39
|
+
const source = path.join(activeRoot, taskId);
|
|
40
|
+
const stat = fs.lstatSync(source);
|
|
41
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
42
|
+
throw new Error(`SANDBOX_TASK_SOURCE_INVALID: ${source} must be a real directory`);
|
|
43
|
+
}
|
|
44
|
+
const canonical = fs.realpathSync.native(source);
|
|
45
|
+
if (path.dirname(canonical) !== activeRoot) {
|
|
46
|
+
throw new Error(`SANDBOX_TASK_SOURCE_INVALID: ${source} escapes the active workspace`);
|
|
47
|
+
}
|
|
48
|
+
return canonical;
|
|
49
|
+
}
|
|
50
|
+
export function materializeSandboxWorkspaceView(params) {
|
|
51
|
+
const projectRoot = path.resolve(params.base, params.project);
|
|
52
|
+
const { root, taskMountPath } = sandboxWorkspaceViewPaths(params);
|
|
53
|
+
assertSafeDirectory(projectRoot, path.resolve(params.base));
|
|
54
|
+
assertSafeDirectory(root, projectRoot);
|
|
55
|
+
fs.mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
56
|
+
for (const state of ['active', 'completed', 'blocked', 'archive']) {
|
|
57
|
+
const stateDir = path.join(root, state);
|
|
58
|
+
assertSafeDirectory(stateDir, root);
|
|
59
|
+
fs.rmSync(stateDir, { recursive: true, force: true });
|
|
60
|
+
fs.mkdirSync(stateDir, { recursive: true, mode: 0o700 });
|
|
61
|
+
}
|
|
62
|
+
const active = path.join(root, 'active');
|
|
63
|
+
const registry = {
|
|
64
|
+
version: 1,
|
|
65
|
+
ids: params.identity.mode === 'task-bound'
|
|
66
|
+
? { [params.identity.shortId]: params.identity.taskId }
|
|
67
|
+
: {}
|
|
68
|
+
};
|
|
69
|
+
fs.writeFileSync(path.join(active, '.short-ids.json'), `${JSON.stringify(registry)}\n`, {
|
|
70
|
+
encoding: 'utf8',
|
|
71
|
+
mode: 0o600
|
|
72
|
+
});
|
|
73
|
+
if (taskMountPath) {
|
|
74
|
+
assertSafeDirectory(taskMountPath, active);
|
|
75
|
+
fs.mkdirSync(taskMountPath, { recursive: true, mode: 0o700 });
|
|
76
|
+
}
|
|
77
|
+
return { root, taskMountPath };
|
|
78
|
+
}
|
|
79
|
+
export function materializeSandboxControl(params) {
|
|
80
|
+
const { root, channelDir, manifestPath } = sandboxControlPaths(params);
|
|
81
|
+
assertSafeDirectory(root, path.resolve(params.base));
|
|
82
|
+
for (const queue of ['requests', 'responses']) {
|
|
83
|
+
const directory = path.join(channelDir, queue);
|
|
84
|
+
assertSafeDirectory(directory, root);
|
|
85
|
+
fs.rmSync(directory, { recursive: true, force: true });
|
|
86
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
87
|
+
}
|
|
88
|
+
const token = randomBytes(32).toString('hex');
|
|
89
|
+
const manifest = {
|
|
90
|
+
version: 1,
|
|
91
|
+
repoRoot: fs.realpathSync.native(params.repoRoot),
|
|
92
|
+
project: params.project,
|
|
93
|
+
container: params.container,
|
|
94
|
+
branch: params.branch,
|
|
95
|
+
mode: params.identity.mode,
|
|
96
|
+
taskId: params.identity.mode === 'task-bound' ? params.identity.taskId : null,
|
|
97
|
+
token,
|
|
98
|
+
channelDir
|
|
99
|
+
};
|
|
100
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest)}\n`, { mode: 0o600 });
|
|
101
|
+
return { channelDir, manifestPath, token };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=workspace-view.js.map
|