@fitlab-ai/agent-infra 0.9.13 → 0.9.15
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 +10 -0
- package/README.zh-CN.md +10 -0
- package/bin/cli.ts +26 -9
- package/bin/internal-cli.sh +45 -0
- package/dist/bin/cli.js +173 -157
- package/dist/bin/internal-cli.js +126 -42
- package/dist/lib/agent-client.js +5 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
- package/dist/lib/defaults.json +103 -103
- package/dist/lib/fs/durable-write.js +37 -0
- package/dist/lib/fs/file-lock.js +111 -0
- package/dist/lib/host-control/audit.js +19 -0
- package/dist/lib/host-control/client.js +142 -0
- package/dist/lib/host-control/command.js +49 -0
- package/dist/lib/host-control/path.js +160 -0
- package/dist/lib/host-control/secure-fs.js +140 -0
- package/dist/lib/host-control/server.js +159 -0
- package/dist/lib/host-control/service.js +112 -0
- package/dist/lib/init.js +11 -2
- package/dist/lib/internal/agent-client.js +5 -2
- package/dist/lib/internal/cli-route-inventory.js +154 -0
- package/dist/lib/internal/codex-lifecycle.js +15 -12
- package/dist/lib/internal/codex-sandbox-controller.js +8 -2
- package/dist/lib/internal/demo-promotion.js +322 -0
- package/dist/lib/internal/demo-transcript.js +454 -0
- package/dist/lib/internal/git-workflow.js +10 -6
- package/dist/lib/internal/host-control.js +28 -0
- package/dist/lib/internal/manual-validation.js +322 -0
- package/dist/lib/internal/platform-checks.js +16 -4
- package/dist/lib/internal/platform-comment.js +16 -4
- package/dist/lib/internal/platform-context.js +4 -1
- package/dist/lib/internal/platform-issue.js +12 -4
- package/dist/lib/internal/platform-metadata.js +88 -0
- package/dist/lib/internal/platform-pr-review.js +16 -3
- package/dist/lib/internal/platform-pr.js +42 -14
- package/dist/lib/internal/platform-release-notes.js +6 -3
- package/dist/lib/internal/platform-security.js +93 -0
- package/dist/lib/internal/pr-review-grade.js +14 -3
- package/dist/lib/internal/release-workflow.js +82 -89
- package/dist/lib/internal/sandbox-control.js +171 -7
- package/dist/lib/internal/task-activity.js +13 -4
- package/dist/lib/internal/task-artifact.js +19 -107
- package/dist/lib/internal/task-context.js +4 -1
- package/dist/lib/internal/task-create.js +48 -14
- package/dist/lib/internal/task-delivery.js +4 -1
- package/dist/lib/internal/task-event.js +38 -35
- package/dist/lib/internal/task-finalization.js +4 -1
- package/dist/lib/internal/task-invalidation.js +4 -1
- package/dist/lib/internal/task-ledger.js +12 -1
- package/dist/lib/internal/task-lifecycle.js +4 -1
- package/dist/lib/internal/task-operation-registry.js +519 -0
- package/dist/lib/internal/task-orchestration.js +12 -0
- package/dist/lib/internal/task-override.js +10 -3
- package/dist/lib/internal/task-qualification.js +90 -0
- package/dist/lib/internal/task-review.js +10 -52
- package/dist/lib/internal/task-short-id.js +11 -1
- package/dist/lib/internal/task-snapshot.js +4 -1
- package/dist/lib/internal/task-validate.js +37 -12
- package/dist/lib/internal/task-verify.js +5 -1
- package/dist/lib/internal/task-warning.js +8 -1
- package/dist/lib/owned-path.js +33 -0
- package/dist/lib/platform/check-status.js +11 -0
- package/dist/lib/platform/comment-safety.js +229 -0
- package/dist/lib/platform/completion-backfill.js +1 -1
- package/dist/lib/platform/github-data.js +241 -0
- package/dist/lib/platform/github-provider.js +248 -26
- package/dist/lib/platform/issue-comments.js +146 -34
- package/dist/lib/platform/issues.js +1 -179
- package/dist/lib/platform/pr-change-report.js +6 -12
- package/dist/lib/platform/pr-checks.js +12 -65
- package/dist/lib/platform/pr-summary.js +83 -10
- package/dist/lib/platform/provider-contract.d.ts +67 -1
- package/dist/lib/platform/provider-contract.js +6 -2
- package/dist/lib/platform/provider-validation.js +76 -3
- package/dist/lib/platform/pull-requests.js +117 -275
- package/dist/lib/platform/repository-metadata.js +377 -0
- package/dist/lib/platform/security-alerts.js +155 -0
- package/dist/lib/platform/snapshots.js +2 -0
- package/dist/lib/platform/verification-sync.js +154 -162
- package/dist/lib/process-data/index.js +7 -0
- package/dist/lib/release/workflow.js +1 -1
- package/dist/lib/run/index.js +5 -0
- package/dist/lib/sandbox/commands/control-status.js +22 -0
- package/dist/lib/sandbox/commands/create.js +39 -8
- package/dist/lib/sandbox/commands/ls.js +5 -0
- package/dist/lib/sandbox/commands/rm.js +3 -807
- package/dist/lib/sandbox/commands/show.js +16 -0
- package/dist/lib/sandbox/control/audit.js +203 -0
- package/dist/lib/sandbox/control/client.js +125 -12
- package/dist/lib/sandbox/control/completed-reentry.js +85 -0
- package/dist/lib/sandbox/control/container-identity.js +28 -31
- package/dist/lib/sandbox/control/executor.js +233 -34
- package/dist/lib/sandbox/control/finalization-response.js +27 -0
- package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
- package/dist/lib/sandbox/control/lifecycle.js +656 -128
- package/dist/lib/sandbox/control/native-file-lock.js +85 -0
- package/dist/lib/sandbox/control/protocol.js +55 -4
- package/dist/lib/sandbox/control/server.js +720 -79
- package/dist/lib/sandbox/control/state.js +63 -3
- package/dist/lib/sandbox/control/task-view.js +183 -0
- package/dist/lib/sandbox/control/task-workflow.js +74 -0
- package/dist/lib/sandbox/control/workflow-executor.js +99 -0
- package/dist/lib/sandbox/engines/authority.js +289 -0
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
- package/dist/lib/sandbox/index.js +7 -2
- package/dist/lib/sandbox/recovery.js +49 -5
- package/dist/lib/sandbox/removal.js +1717 -0
- package/dist/lib/sandbox/task-cleanup.js +217 -0
- package/dist/lib/sandbox/workspace-view.js +15 -15
- package/dist/lib/sandbox/worktree-safety.js +4 -1
- package/dist/lib/server/index.js +8 -0
- package/dist/lib/task/activity-intent.js +2 -1
- package/dist/lib/task/activity-log.js +30 -24
- package/dist/lib/task/artifact-command.js +101 -0
- package/dist/lib/task/artifact-lifecycle.js +71 -40
- package/dist/lib/task/artifact-name.js +36 -0
- package/dist/lib/task/artifact-operations.js +474 -0
- package/dist/lib/task/artifact-receipts.js +3 -15
- package/dist/lib/task/artifact-repair-intent.js +130 -0
- package/dist/lib/task/artifact-schema.js +127 -0
- package/dist/lib/task/capabilities.js +83 -19
- package/dist/lib/task/codex-orchestration.js +71 -25
- package/dist/lib/task/commit-identity.js +28 -0
- package/dist/lib/task/commit-operation.js +2 -16
- package/dist/lib/task/control-authority.js +375 -5
- package/dist/lib/task/control-recovery.js +128 -0
- package/dist/lib/task/create-service.js +103 -4
- package/dist/lib/task/create.js +80 -2
- package/dist/lib/task/decision-details.js +2 -46
- package/dist/lib/task/events.js +306 -76
- package/dist/lib/task/finalization-state.js +9 -0
- package/dist/lib/task/human-override.js +3 -6
- package/dist/lib/task/implementation-inputs.js +3 -3
- package/dist/lib/task/index.js +11 -3
- package/dist/lib/task/intermediate-cleanup.js +383 -0
- package/dist/lib/task/invalidation.js +18 -65
- package/dist/lib/task/ledger-intents.js +7 -22
- package/dist/lib/task/ledger.js +1 -3
- package/dist/lib/task/lifecycle.js +19 -1
- package/dist/lib/task/local-artifact-finalization.js +190 -290
- package/dist/lib/task/manual-validation-completion.js +26 -0
- package/dist/lib/task/manual-validation-evidence.js +130 -0
- package/dist/lib/task/manual-validation-receipt.js +101 -0
- package/dist/lib/task/manual-validation-shared.js +40 -0
- package/dist/lib/task/manual-validation-transaction.js +243 -0
- package/dist/lib/task/markdown.js +47 -0
- package/dist/lib/task/orchestration.js +206 -69
- package/dist/lib/task/qualification-audit.js +476 -0
- package/dist/lib/task/qualification-confirmation.js +109 -0
- package/dist/lib/task/qualification-intents.js +148 -0
- package/dist/lib/task/review-artifacts.js +23 -40
- package/dist/lib/task/review-command.js +25 -0
- package/dist/lib/task/review-finalization.js +146 -97
- package/dist/lib/task/review-fingerprint.js +2 -2
- package/dist/lib/task/sections.js +34 -54
- package/dist/lib/task/verification-config.js +11 -0
- package/dist/lib/task/verification-engine.js +170 -327
- package/dist/lib/task/verification.js +1 -1
- package/dist/lib/task/workflow-command.js +17 -0
- package/dist/lib/task/workflow-warning-intents.js +0 -16
- package/dist/lib/task/workflow-warnings.js +28 -2
- package/dist/lib/update.js +2 -0
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-client.ts +9 -0
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
- package/lib/fs/durable-write.ts +29 -0
- package/lib/fs/file-lock.ts +113 -0
- package/lib/host-control/audit.ts +22 -0
- package/lib/host-control/client.ts +172 -0
- package/lib/host-control/command.ts +60 -0
- package/lib/host-control/path.ts +167 -0
- package/lib/host-control/secure-fs.ts +135 -0
- package/lib/host-control/server.ts +180 -0
- package/lib/host-control/service.ts +133 -0
- package/lib/init.ts +15 -2
- package/lib/internal/agent-client.ts +4 -2
- package/lib/internal/cli-route-inventory.ts +142 -0
- package/lib/internal/codex-lifecycle.ts +14 -12
- package/lib/internal/codex-sandbox-controller.ts +7 -2
- package/lib/internal/demo-promotion.ts +354 -0
- package/lib/internal/demo-transcript.ts +419 -0
- package/lib/internal/git-workflow.ts +9 -6
- package/lib/internal/host-control.ts +28 -0
- package/lib/internal/manual-validation.ts +306 -0
- package/lib/internal/platform-checks.ts +12 -4
- package/lib/internal/platform-comment.ts +12 -4
- package/lib/internal/platform-context.ts +3 -1
- package/lib/internal/platform-issue.ts +11 -4
- package/lib/internal/platform-metadata.ts +70 -0
- package/lib/internal/platform-pr-review.ts +14 -3
- package/lib/internal/platform-pr.ts +38 -14
- package/lib/internal/platform-release-notes.ts +5 -3
- package/lib/internal/platform-security.ts +83 -0
- package/lib/internal/pr-review-grade.ts +10 -3
- package/lib/internal/release-workflow.ts +91 -87
- package/lib/internal/sandbox-control.ts +181 -6
- package/lib/internal/task-activity.ts +12 -4
- package/lib/internal/task-artifact.ts +15 -79
- package/lib/internal/task-context.ts +3 -1
- package/lib/internal/task-create.ts +76 -15
- package/lib/internal/task-delivery.ts +3 -1
- package/lib/internal/task-event.ts +21 -10
- package/lib/internal/task-finalization.ts +3 -1
- package/lib/internal/task-invalidation.ts +3 -1
- package/lib/internal/task-ledger.ts +11 -1
- package/lib/internal/task-lifecycle.ts +3 -1
- package/lib/internal/task-operation-registry.ts +590 -0
- package/lib/internal/task-orchestration.ts +12 -0
- package/lib/internal/task-override.ts +9 -3
- package/lib/internal/task-qualification.ts +61 -0
- package/lib/internal/task-review.ts +7 -50
- package/lib/internal/task-short-id.ts +10 -1
- package/lib/internal/task-snapshot.ts +3 -1
- package/lib/internal/task-validate.ts +32 -12
- package/lib/internal/task-verify.ts +4 -1
- package/lib/internal/task-warning.ts +7 -1
- package/lib/owned-path.ts +26 -0
- package/lib/platform/check-status.ts +9 -0
- package/lib/platform/comment-safety.ts +255 -0
- package/lib/platform/completion-backfill.ts +1 -1
- package/lib/platform/github-data.ts +322 -0
- package/lib/platform/github-provider.ts +244 -27
- package/lib/platform/issue-comments.ts +159 -35
- package/lib/platform/issues.ts +4 -245
- package/lib/platform/pr-change-report.ts +6 -12
- package/lib/platform/pr-checks.ts +13 -77
- package/lib/platform/pr-summary.ts +88 -11
- package/lib/platform/provider-contract.ts +78 -3
- package/lib/platform/provider-validation.ts +85 -3
- package/lib/platform/pull-requests.ts +129 -348
- package/lib/platform/repository-metadata.ts +453 -0
- package/lib/platform/security-alerts.ts +191 -0
- package/lib/platform/snapshots.ts +53 -0
- package/lib/platform/verification-sync.ts +171 -177
- package/lib/process-data/index.ts +7 -0
- package/lib/release/workflow.ts +3 -3
- package/lib/run/index.ts +5 -0
- package/lib/sandbox/commands/control-status.ts +26 -0
- package/lib/sandbox/commands/create.ts +53 -12
- package/lib/sandbox/commands/ls.ts +7 -0
- package/lib/sandbox/commands/rm.ts +3 -996
- package/lib/sandbox/commands/show.ts +16 -0
- package/lib/sandbox/control/audit.ts +253 -0
- package/lib/sandbox/control/client.ts +150 -13
- package/lib/sandbox/control/completed-reentry.ts +98 -0
- package/lib/sandbox/control/container-identity.ts +27 -43
- package/lib/sandbox/control/executor.ts +262 -37
- package/lib/sandbox/control/finalization-response.ts +29 -0
- package/lib/sandbox/control/identity-sentinel.ts +137 -0
- package/lib/sandbox/control/lifecycle.ts +672 -18
- package/lib/sandbox/control/native-file-lock.ts +108 -0
- package/lib/sandbox/control/protocol.ts +80 -8
- package/lib/sandbox/control/server.ts +779 -82
- package/lib/sandbox/control/state.ts +84 -3
- package/lib/sandbox/control/task-view.ts +240 -0
- package/lib/sandbox/control/task-workflow.ts +95 -0
- package/lib/sandbox/control/workflow-executor.ts +102 -0
- package/lib/sandbox/engines/authority.ts +365 -0
- package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
- package/lib/sandbox/index.ts +9 -2
- package/lib/sandbox/recovery.ts +49 -6
- package/lib/sandbox/removal.ts +2144 -0
- package/lib/sandbox/task-cleanup.ts +209 -0
- package/lib/sandbox/workspace-view.ts +26 -18
- package/lib/sandbox/worktree-safety.ts +4 -1
- package/lib/server/index.ts +10 -0
- package/lib/task/activity-intent.ts +2 -2
- package/lib/task/activity-log.ts +27 -19
- package/lib/task/artifact-command.ts +104 -0
- package/lib/task/artifact-lifecycle.ts +66 -39
- package/lib/task/artifact-name.ts +55 -0
- package/lib/task/artifact-operations.ts +580 -0
- package/lib/task/artifact-receipts.ts +3 -14
- package/lib/task/artifact-repair-intent.ts +152 -0
- package/lib/task/artifact-schema.ts +163 -0
- package/lib/task/capabilities.ts +82 -22
- package/lib/task/codex-orchestration.ts +85 -24
- package/lib/task/commit-identity.ts +31 -0
- package/lib/task/commit-operation.ts +2 -16
- package/lib/task/control-authority.ts +513 -6
- package/lib/task/control-recovery.ts +174 -0
- package/lib/task/create-service.ts +131 -6
- package/lib/task/create.ts +83 -1
- package/lib/task/decision-details.ts +3 -71
- package/lib/task/events.ts +292 -75
- package/lib/task/finalization-state.ts +11 -0
- package/lib/task/human-override.ts +3 -8
- package/lib/task/implementation-inputs.ts +3 -3
- package/lib/task/index.ts +16 -3
- package/lib/task/intermediate-cleanup.ts +455 -0
- package/lib/task/invalidation.ts +18 -62
- package/lib/task/ledger-intents.ts +7 -24
- package/lib/task/ledger.ts +1 -3
- package/lib/task/lifecycle.ts +17 -1
- package/lib/task/local-artifact-finalization.ts +223 -388
- package/lib/task/manual-validation-completion.ts +40 -0
- package/lib/task/manual-validation-evidence.ts +209 -0
- package/lib/task/manual-validation-receipt.ts +152 -0
- package/lib/task/manual-validation-shared.ts +50 -0
- package/lib/task/manual-validation-transaction.ts +304 -0
- package/lib/task/markdown.ts +70 -0
- package/lib/task/orchestration.ts +191 -68
- package/lib/task/qualification-audit.ts +588 -0
- package/lib/task/qualification-confirmation.ts +117 -0
- package/lib/task/qualification-intents.ts +150 -0
- package/lib/task/review-artifacts.ts +21 -41
- package/lib/task/review-command.ts +23 -0
- package/lib/task/review-finalization.ts +154 -153
- package/lib/task/review-fingerprint.ts +2 -2
- package/lib/task/sections.ts +33 -52
- package/lib/task/verification-config.ts +12 -0
- package/lib/task/verification-engine.ts +165 -370
- package/lib/task/verification-types.ts +17 -0
- package/lib/task/verification.ts +1 -1
- package/lib/task/workflow-command.ts +18 -0
- package/lib/task/workflow-warning-intents.ts +0 -13
- package/lib/task/workflow-warnings.ts +21 -2
- package/lib/update.ts +6 -0
- package/package.json +7 -2
- package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
- package/templates/.agents/rules/README.en.md +2 -0
- package/templates/.agents/rules/README.zh-CN.md +2 -0
- package/templates/.agents/rules/decision-qualification.en.md +22 -0
- package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
- package/templates/.agents/rules/evidence-reporting.en.md +28 -0
- package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
- package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
- package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
- package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
- package/templates/.agents/rules/security-alerts.en.md +8 -8
- package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
- package/templates/.agents/rules/testing-discipline.en.md +2 -0
- package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
- package/templates/.agents/scripts/package.json +3 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
- package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
- package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +37 -21
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +37 -21
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +4 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +4 -0
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
- package/templates/.agents/skills/complete-task/SKILL.en.md +10 -23
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -23
- package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
- package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
- package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
- package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
- package/templates/.agents/skills/release/SKILL.en.md +7 -3
- package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
- package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
- package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +25 -4
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +25 -4
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +5 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +5 -1
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/test/SKILL.en.md +29 -7
- package/templates/.agents/skills/test/SKILL.zh-CN.md +29 -7
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
- package/templates/.agents/templates/task.en.md +6 -0
- package/templates/.agents/templates/task.zh-CN.md +6 -0
- package/templates/.claude/commands/run-manual-validation.en.md +1 -1
- package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
- package/dist/lib/platform/adapters.js +0 -56
- package/lib/platform/adapters.ts +0 -197
- package/templates/.agents/scripts/security-alerts.github.sh +0 -151
- package/templates/.agents/scripts/security-alerts.sh +0 -31
- package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
- package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
|
@@ -7,6 +7,7 @@ import { fetchSandboxRows, selectSandboxContainer } from './list-running.js';
|
|
|
7
7
|
import { resolveTools, toolConfigDirCandidates } from '../tools.js';
|
|
8
8
|
import { detectEngine } from '../engine.js';
|
|
9
9
|
import { resolveSandboxTarget } from '../workspace-identity.js';
|
|
10
|
+
import { readSandboxControlStatusForRow } from './control-status.js';
|
|
10
11
|
const USAGE = `Usage: ai sandbox show <branch | TASK-id | N>
|
|
11
12
|
|
|
12
13
|
Shows one sandbox's worktree path and per-tool state paths (Claude Code,
|
|
@@ -62,6 +63,21 @@ export function show(args = []) {
|
|
|
62
63
|
p.log.step('Workspace identity');
|
|
63
64
|
process.stdout.write(` Mode: ${container?.workspaceMode ?? 'legacy-invalid'}\n`);
|
|
64
65
|
process.stdout.write(` Task: ${container?.taskId ?? '-'}\n`);
|
|
66
|
+
p.log.step('Control status');
|
|
67
|
+
const controlStatus = container
|
|
68
|
+
? readSandboxControlStatusForRow(config, container)
|
|
69
|
+
: null;
|
|
70
|
+
if (!controlStatus) {
|
|
71
|
+
p.log.warn(' Control status unavailable');
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
process.stdout.write(` Health: ${controlStatus.state}\n`);
|
|
75
|
+
process.stdout.write(` Task view: ${controlStatus.taskView.state}\n`);
|
|
76
|
+
process.stdout.write(` Task source: ${controlStatus.taskView.observedSource ?? '-'}\n`);
|
|
77
|
+
if (controlStatus.taskView.reasonCode) {
|
|
78
|
+
process.stdout.write(` Task view reason: ${controlStatus.taskView.reasonCode}\n`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
65
81
|
for (const tool of detail.toolStates) {
|
|
66
82
|
p.log.step(`${tool.name} state`);
|
|
67
83
|
if (tool.entries.length === 0) {
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { identityDigest as digestIdentity } from './identity-sentinel.js';
|
|
5
|
+
import { acquireSandboxResourceLock } from './native-file-lock.js';
|
|
6
|
+
import { fsyncDirectory, writeDurableFile } from '../../fs/durable-write.js';
|
|
7
|
+
export const SANDBOX_CONTROL_AUDIT_PHASES = Object.freeze([
|
|
8
|
+
'validated', 'gated', 'reserved', 'prepared', 'accepted-authorized', 'accepted-committed',
|
|
9
|
+
'start-authorized', 'started-committed', 'completed', 'evidence-written',
|
|
10
|
+
'publish-authorized', 'published-committed', 'rejected', 'recovered'
|
|
11
|
+
]);
|
|
12
|
+
const REQUEST_ID = /^[a-f0-9-]{16,64}$/u;
|
|
13
|
+
const SAFE_OPERATION = /^[a-z][a-z0-9.-]{0,96}$/u;
|
|
14
|
+
const AUDIT_MAX_BYTES = 1024 * 1024;
|
|
15
|
+
export function requestAuditFields(manifest, request) {
|
|
16
|
+
return {
|
|
17
|
+
requestId: request.id, requestFamily: request.family, sandboxTaskId: manifest.taskId,
|
|
18
|
+
requestGeneration: request.generation, requestIssuedAt: request.issuedAt, requestExpiresAt: request.expiresAt
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function resultAuditFields(result) {
|
|
22
|
+
return {
|
|
23
|
+
exitCode: result.exitCode,
|
|
24
|
+
outputBytes: Buffer.byteLength(result.stdout, 'utf8'), errorBytes: Buffer.byteLength(result.stderr, 'utf8'),
|
|
25
|
+
outputDigest: createHash('sha256').update(result.stdout, 'utf8').digest('hex'),
|
|
26
|
+
errorDigest: createHash('sha256').update(result.stderr, 'utf8').digest('hex')
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function auditRoot(manifest) {
|
|
30
|
+
return path.dirname(path.resolve(manifest.publicStatusDir));
|
|
31
|
+
}
|
|
32
|
+
function auditPath(manifest) {
|
|
33
|
+
return path.join(auditRoot(manifest), 'audit.ndjson');
|
|
34
|
+
}
|
|
35
|
+
function manifestIdentityDigest(manifest) {
|
|
36
|
+
return digestIdentity({
|
|
37
|
+
version: 1,
|
|
38
|
+
mode: manifest.mode,
|
|
39
|
+
taskId: manifest.taskId,
|
|
40
|
+
generation: manifest.generation,
|
|
41
|
+
controlRootId: manifest.controlRootId
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export function createSandboxControlAuditContext(manifest, params) {
|
|
45
|
+
if (!REQUEST_ID.test(params.requestId))
|
|
46
|
+
throw new Error('SANDBOX_CONTROL_AUDIT_REQUEST_INVALID');
|
|
47
|
+
if (params.operation !== null && params.operation !== undefined && !SAFE_OPERATION.test(params.operation)) {
|
|
48
|
+
throw new Error('SANDBOX_CONTROL_AUDIT_OPERATION_INVALID');
|
|
49
|
+
}
|
|
50
|
+
if (!SANDBOX_CONTROL_AUDIT_PHASES.includes(params.phase))
|
|
51
|
+
throw new Error('SANDBOX_CONTROL_AUDIT_PHASE_INVALID');
|
|
52
|
+
return {
|
|
53
|
+
requestId: params.requestId,
|
|
54
|
+
taskId: manifest.taskId,
|
|
55
|
+
family: params.family,
|
|
56
|
+
operation: params.operation ?? null,
|
|
57
|
+
phase: params.phase,
|
|
58
|
+
outcome: params.outcome,
|
|
59
|
+
generation: manifest.generation,
|
|
60
|
+
identityDigest: manifestIdentityDigest(manifest)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function safeFields(fields) {
|
|
64
|
+
const result = {};
|
|
65
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
66
|
+
if (!/^[a-z][a-zA-Z0-9]{0,63}$/u.test(key))
|
|
67
|
+
continue;
|
|
68
|
+
if (/(token|secret|credential|proof|password|path|root|cwd|stdout|stderr|args|command|taskref)/iu.test(key))
|
|
69
|
+
continue;
|
|
70
|
+
if (typeof value === 'string' && value.length > 256)
|
|
71
|
+
continue;
|
|
72
|
+
result[key] = value;
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
function requestHasTerminalTransition(directory) {
|
|
77
|
+
const transitions = path.join(directory, 'transitions');
|
|
78
|
+
if (!fs.existsSync(transitions))
|
|
79
|
+
return false;
|
|
80
|
+
return ['published-committed', 'recovered'].some((phase) => fs.existsSync(path.join(transitions, `${phase}.json`)));
|
|
81
|
+
}
|
|
82
|
+
function hasActiveRequest(manifest) {
|
|
83
|
+
if (!fs.existsSync(manifest.processingDir))
|
|
84
|
+
return false;
|
|
85
|
+
return fs.readdirSync(manifest.processingDir, { withFileTypes: true })
|
|
86
|
+
.some((entry) => entry.isDirectory() && REQUEST_ID.test(entry.name)
|
|
87
|
+
&& !requestHasTerminalTransition(path.join(manifest.processingDir, entry.name)));
|
|
88
|
+
}
|
|
89
|
+
function rotateAuditUnderLock(manifest, filePath) {
|
|
90
|
+
if (!fs.existsSync(filePath) || fs.statSync(filePath).size < AUDIT_MAX_BYTES)
|
|
91
|
+
return;
|
|
92
|
+
if (hasActiveRequest(manifest))
|
|
93
|
+
return;
|
|
94
|
+
fs.rmSync(`${filePath}.1`, { force: true });
|
|
95
|
+
fs.renameSync(filePath, `${filePath}.1`);
|
|
96
|
+
fsyncDirectory(auditRoot(manifest));
|
|
97
|
+
const descriptor = fs.openSync(filePath, 'a', 0o600);
|
|
98
|
+
try {
|
|
99
|
+
fs.fsyncSync(descriptor);
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
fs.closeSync(descriptor);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function appendAuditRecord(manifest, record, critical) {
|
|
106
|
+
const root = auditRoot(manifest);
|
|
107
|
+
fs.mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
108
|
+
const lock = acquireSandboxResourceLock(`sandbox-control-audit:${root}`);
|
|
109
|
+
try {
|
|
110
|
+
const filePath = auditPath(manifest);
|
|
111
|
+
rotateAuditUnderLock(manifest, filePath);
|
|
112
|
+
const descriptor = fs.openSync(filePath, 'a', 0o600);
|
|
113
|
+
try {
|
|
114
|
+
fs.writeSync(descriptor, `${JSON.stringify(record)}\n`, undefined, 'utf8');
|
|
115
|
+
if (critical)
|
|
116
|
+
fs.fsyncSync(descriptor);
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
fs.closeSync(descriptor);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (critical)
|
|
124
|
+
throw new Error(`SANDBOX_CONTROL_AUDIT_UNAVAILABLE: ${error instanceof Error ? error.message : String(error)}`);
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
lock.release();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export function appendCriticalAudit(manifest, context, fields = {}, now = Date.now()) {
|
|
131
|
+
appendAuditRecord(manifest, {
|
|
132
|
+
version: 2,
|
|
133
|
+
at: now,
|
|
134
|
+
event: context.phase,
|
|
135
|
+
...context,
|
|
136
|
+
...safeFields(fields)
|
|
137
|
+
}, true);
|
|
138
|
+
}
|
|
139
|
+
export function appendDiagnosticAudit(manifest, event, fields = {}, now = Date.now()) {
|
|
140
|
+
try {
|
|
141
|
+
appendAuditRecord(manifest, {
|
|
142
|
+
version: 2,
|
|
143
|
+
at: now,
|
|
144
|
+
event,
|
|
145
|
+
generation: manifest.generation,
|
|
146
|
+
identityDigest: manifestIdentityDigest(manifest),
|
|
147
|
+
...safeFields(fields)
|
|
148
|
+
}, false);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Diagnostics are deliberately best effort.
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function transitionPath(manifest, requestId, phase) {
|
|
155
|
+
if (!REQUEST_ID.test(requestId))
|
|
156
|
+
throw new Error('SANDBOX_CONTROL_TRANSITION_REQUEST_INVALID');
|
|
157
|
+
return path.join(manifest.processingDir, requestId, 'transitions', `${phase}.json`);
|
|
158
|
+
}
|
|
159
|
+
export function writeSandboxControlTransition(manifest, params) {
|
|
160
|
+
const transition = {
|
|
161
|
+
version: 1,
|
|
162
|
+
requestId: params.requestId,
|
|
163
|
+
generation: manifest.generation,
|
|
164
|
+
phase: params.phase,
|
|
165
|
+
at: params.now ?? Date.now(),
|
|
166
|
+
identityDigest: manifestIdentityDigest(manifest),
|
|
167
|
+
reference: params.reference ?? null
|
|
168
|
+
};
|
|
169
|
+
const target = transitionPath(manifest, params.requestId, params.phase);
|
|
170
|
+
fs.mkdirSync(path.dirname(target), { recursive: true, mode: 0o700 });
|
|
171
|
+
try {
|
|
172
|
+
writeDurableFile(target, `${JSON.stringify(transition)}\n`, { mode: 0o600, replace: false });
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
if (error.code !== 'EEXIST')
|
|
176
|
+
throw error;
|
|
177
|
+
const existing = readSandboxControlTransition(manifest, params.requestId, params.phase);
|
|
178
|
+
if (JSON.stringify(existing) !== JSON.stringify(transition))
|
|
179
|
+
throw new Error('SANDBOX_CONTROL_TRANSITION_CONFLICT');
|
|
180
|
+
}
|
|
181
|
+
return transition;
|
|
182
|
+
}
|
|
183
|
+
export function readSandboxControlTransition(manifest, requestId, phase) {
|
|
184
|
+
const filePath = transitionPath(manifest, requestId, phase);
|
|
185
|
+
if (!fs.existsSync(filePath))
|
|
186
|
+
throw new Error('SANDBOX_CONTROL_TRANSITION_MISSING');
|
|
187
|
+
let value;
|
|
188
|
+
try {
|
|
189
|
+
value = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
throw new Error('SANDBOX_CONTROL_TRANSITION_INVALID');
|
|
193
|
+
}
|
|
194
|
+
const candidate = value;
|
|
195
|
+
if (!candidate || candidate.version !== 1 || candidate.requestId !== requestId
|
|
196
|
+
|| candidate.generation !== manifest.generation || candidate.phase !== phase
|
|
197
|
+
|| !Number.isSafeInteger(candidate.at) || typeof candidate.identityDigest !== 'string'
|
|
198
|
+
|| (candidate.reference !== null && typeof candidate.reference !== 'string')) {
|
|
199
|
+
throw new Error('SANDBOX_CONTROL_TRANSITION_INVALID');
|
|
200
|
+
}
|
|
201
|
+
return candidate;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import { hasTaskBoundMarker } from '../../internal/task-operation-registry.js';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { randomUUID } from 'node:crypto';
|
|
4
5
|
import { SANDBOX_CONTROL_ADMISSION_WINDOW_MS, SANDBOX_CONTROL_MAX_BYTES, SANDBOX_CONTROL_STATUS_STALE_MS, isSandboxControlFamily } from './protocol.js';
|
|
5
6
|
import { normalizeAgentToken } from '../../agent-clients/tokens.js';
|
|
6
7
|
import { readSandboxControlPayload, readSandboxControlStatus } from './state.js';
|
|
8
|
+
import { accessSandboxTaskView, taskViewFromStatus } from './task-view.js';
|
|
9
|
+
import { readSandboxControlIdentitySentinel } from './identity-sentinel.js';
|
|
10
|
+
import { configuredShortIdLength, resolveShortIdReadOnly } from '../../task/short-id.js';
|
|
7
11
|
const SANDBOX_CONTROL_RESPONSE_SETTLE_MS = 250;
|
|
8
12
|
export class SandboxControlClientError extends Error {
|
|
9
13
|
detail;
|
|
@@ -23,7 +27,25 @@ function sleep(milliseconds) {
|
|
|
23
27
|
function clientError(code, message, retryable, accepted = false, requestId = null) {
|
|
24
28
|
throw new SandboxControlClientError({ code, message: `${code}: ${message}`, retryable }, accepted, requestId);
|
|
25
29
|
}
|
|
26
|
-
function preflight(statusDir, generation, now = Date.now()) {
|
|
30
|
+
function preflight(statusDir, generation, taskViewEffect = null, now = Date.now(), env = process.env) {
|
|
31
|
+
if (fs.existsSync(statusDir)) {
|
|
32
|
+
let identity;
|
|
33
|
+
try {
|
|
34
|
+
identity = readSandboxControlIdentitySentinel(statusDir);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const code = error instanceof Error && error.message.endsWith('MISSING')
|
|
38
|
+
? 'SANDBOX_CONTROL_IDENTITY_MISSING'
|
|
39
|
+
: 'SANDBOX_CONTROL_IDENTITY_MALFORMED';
|
|
40
|
+
clientError(code, 'sandbox control identity is missing or invalid', false);
|
|
41
|
+
}
|
|
42
|
+
if (identity.generation !== generation) {
|
|
43
|
+
clientError('SANDBOX_CONTROL_IDENTITY_GENERATION_MISMATCH', 'sandbox control identity generation does not match the request', false);
|
|
44
|
+
}
|
|
45
|
+
if (env.AGENT_INFRA_CONTROL_ROOT_ID && identity.controlRootId !== env.AGENT_INFRA_CONTROL_ROOT_ID) {
|
|
46
|
+
clientError('SANDBOX_CONTROL_IDENTITY_ROOT_ID_MISMATCH', 'sandbox control identity root does not match the client configuration', false);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
27
49
|
let status;
|
|
28
50
|
try {
|
|
29
51
|
status = readSandboxControlStatus(statusDir);
|
|
@@ -45,8 +67,27 @@ function preflight(statusDir, generation, now = Date.now()) {
|
|
|
45
67
|
}
|
|
46
68
|
if (status.state !== 'healthy')
|
|
47
69
|
clientError('SANDBOX_CONTROL_BROKER_UNAVAILABLE', 'broker is not ready', true);
|
|
70
|
+
if (taskViewEffect && hasTaskBoundMarker(env)) {
|
|
71
|
+
const view = taskViewFromStatus(status);
|
|
72
|
+
if (view.taskId !== env.AGENT_INFRA_TASK_ID) {
|
|
73
|
+
clientError('SANDBOX_TASK_VIEW_TASK_ID_MISMATCH', 'task view task id does not match the sandbox task marker', false);
|
|
74
|
+
}
|
|
75
|
+
const access = accessSandboxTaskView(view, taskViewEffect);
|
|
76
|
+
if (!access.allowed) {
|
|
77
|
+
clientError(access.reasonCode ?? 'SANDBOX_TASK_VIEW_DENIED', access.message ?? 'task view denied', false);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
48
80
|
}
|
|
49
|
-
function
|
|
81
|
+
function taskViewEffectForRequest(request) {
|
|
82
|
+
if (request.family === 'task-lifecycle' || request.family === 'task-finalization')
|
|
83
|
+
return 'progress';
|
|
84
|
+
if (request.family === 'task-orchestration')
|
|
85
|
+
return request.args[1] === 'status' ? 'diagnostic' : 'progress';
|
|
86
|
+
if (request.family === 'task-workflow')
|
|
87
|
+
return request.workflow.operation === 'artifact-inspect' || request.workflow.operation === 'decision-next-id' ? 'diagnostic' : 'progress';
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
function parseResponse(raw, id, accepted = false) {
|
|
50
91
|
const response = JSON.parse(raw);
|
|
51
92
|
if (response.version !== 2 || response.id !== id
|
|
52
93
|
|| !['completed', 'rejected'].includes(response.phase)
|
|
@@ -54,12 +95,12 @@ function parseResponse(raw, id) {
|
|
|
54
95
|
|| (response.outputState !== undefined && response.outputState !== 'available' && response.outputState !== 'unavailable')
|
|
55
96
|
|| (response.outputState === 'available' && !response.payload)
|
|
56
97
|
|| (response.outputState === 'unavailable' && response.payload !== null && response.payload !== undefined)) {
|
|
57
|
-
clientError('SANDBOX_CONTROL_RESPONSE_INVALID', 'broker response is invalid', false,
|
|
98
|
+
clientError('SANDBOX_CONTROL_RESPONSE_INVALID', 'broker response is invalid', false, accepted, id);
|
|
58
99
|
}
|
|
59
100
|
return response;
|
|
60
101
|
}
|
|
61
|
-
function readPublishedResponse(raw, id, channelDir) {
|
|
62
|
-
const response = parseResponse(raw, id);
|
|
102
|
+
function readPublishedResponse(raw, id, channelDir, accepted = false) {
|
|
103
|
+
const response = parseResponse(raw, id, accepted);
|
|
63
104
|
if (response.outputState !== 'available')
|
|
64
105
|
return response;
|
|
65
106
|
const filePath = path.join(channelDir, 'responses', `${id}.payload.json`);
|
|
@@ -89,10 +130,59 @@ function cancelPendingRequest(requestPath) {
|
|
|
89
130
|
throw error;
|
|
90
131
|
}
|
|
91
132
|
}
|
|
133
|
+
const CONTROL_TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
|
|
134
|
+
const CONTROL_SHORT_ID_RE = /^\d+$/;
|
|
135
|
+
// Use the current short-id contract for the first visible active registry.
|
|
136
|
+
export function resolveVisibleActiveShortId(ref) {
|
|
137
|
+
let dir = process.cwd();
|
|
138
|
+
for (let depth = 0; depth < 64; depth += 1) {
|
|
139
|
+
const registryPath = path.join(dir, '.agents', 'workspace', 'active', '.short-ids.json');
|
|
140
|
+
if (fs.existsSync(registryPath)) {
|
|
141
|
+
const resolved = resolveShortIdReadOnly(ref, dir, { shortIdLength: configuredShortIdLength(dir) });
|
|
142
|
+
return resolved.ok ? resolved.taskId : null;
|
|
143
|
+
}
|
|
144
|
+
const parent = path.dirname(dir);
|
|
145
|
+
if (parent === dir)
|
|
146
|
+
break;
|
|
147
|
+
dir = parent;
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
// A request's leading argument is only a task reference for some families and
|
|
152
|
+
// may be a documented short id. Compare canonical ids so a bound sandbox keeps
|
|
153
|
+
// refusing other tasks without rejecting its own task's short id.
|
|
154
|
+
function canonicalRequestTask(request) {
|
|
155
|
+
const ref = request.family === 'task-workflow'
|
|
156
|
+
? request.workflow.taskId
|
|
157
|
+
: 'args' in request ? request.args[0] ?? null : null;
|
|
158
|
+
if (!ref)
|
|
159
|
+
return { kind: 'none' };
|
|
160
|
+
if (CONTROL_TASK_ID_RE.test(ref))
|
|
161
|
+
return { kind: 'task', taskId: ref };
|
|
162
|
+
if (!CONTROL_SHORT_ID_RE.test(ref))
|
|
163
|
+
return { kind: 'none' };
|
|
164
|
+
const resolved = resolveVisibleActiveShortId(ref);
|
|
165
|
+
return resolved ? { kind: 'task', taskId: resolved } : { kind: 'unresolved' };
|
|
166
|
+
}
|
|
92
167
|
function exchangeSandboxControl(request, params) {
|
|
93
168
|
const channelDir = params.channelDir ?? process.env.AGENT_INFRA_CONTROL_DIR ?? '/run/agent-infra/control';
|
|
94
169
|
const statusDir = params.statusDir ?? process.env.AGENT_INFRA_CONTROL_STATUS_DIR ?? '/run/agent-infra/control-status';
|
|
95
|
-
|
|
170
|
+
const taskViewEffect = taskViewEffectForRequest(request);
|
|
171
|
+
preflight(statusDir, request.generation, taskViewEffect);
|
|
172
|
+
const identityPath = path.join(statusDir, 'identity.json');
|
|
173
|
+
if (fs.existsSync(statusDir)) {
|
|
174
|
+
const identity = readSandboxControlIdentitySentinel(statusDir);
|
|
175
|
+
const requestTask = canonicalRequestTask(request);
|
|
176
|
+
if (identity.mode === 'task-bound'
|
|
177
|
+
&& ((process.env.AGENT_INFRA_TASK_ID && process.env.AGENT_INFRA_TASK_ID !== identity.taskId)
|
|
178
|
+
|| requestTask.kind === 'unresolved'
|
|
179
|
+
|| (requestTask.kind === 'task' && requestTask.taskId !== identity.taskId))) {
|
|
180
|
+
clientError('SANDBOX_CONTROL_IDENTITY_TOPOLOGY_MISMATCH', 'request task does not match the sandbox identity', false);
|
|
181
|
+
}
|
|
182
|
+
if (identity.mode === 'branch-only' && (request.family === 'task-finalization' || request.family === 'task-workflow')) {
|
|
183
|
+
clientError('SANDBOX_CONTROL_BRANCH_ONLY', 'branch-only sandboxes cannot finalize tasks', false);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
96
186
|
const encoded = `${JSON.stringify(request)}\n`;
|
|
97
187
|
if (Buffer.byteLength(encoded, 'utf8') > SANDBOX_CONTROL_MAX_BYTES) {
|
|
98
188
|
clientError('SANDBOX_CONTROL_REQUEST_TOO_LARGE', 'request exceeds the control limit', false, false, request.id);
|
|
@@ -127,7 +217,9 @@ function exchangeSandboxControl(request, params) {
|
|
|
127
217
|
}
|
|
128
218
|
let response;
|
|
129
219
|
try {
|
|
130
|
-
|
|
220
|
+
// The request-specific terminal proves the broker claimed the request; preserve recovery evidence if marker cleanup won the race.
|
|
221
|
+
accepted = true;
|
|
222
|
+
response = readPublishedResponse(raw, request.id, channelDir, accepted);
|
|
131
223
|
malformedResponseRaw = null;
|
|
132
224
|
}
|
|
133
225
|
catch (error) {
|
|
@@ -153,7 +245,7 @@ function exchangeSandboxControl(request, params) {
|
|
|
153
245
|
}
|
|
154
246
|
if (!accepted) {
|
|
155
247
|
try {
|
|
156
|
-
preflight(statusDir, request.generation);
|
|
248
|
+
preflight(statusDir, request.generation, taskViewEffect);
|
|
157
249
|
}
|
|
158
250
|
catch (error) {
|
|
159
251
|
if (cancelPendingRequest(requestPath))
|
|
@@ -196,7 +288,9 @@ export function recoverSandboxControl(requestId, params = {}) {
|
|
|
196
288
|
}
|
|
197
289
|
let response;
|
|
198
290
|
try {
|
|
199
|
-
|
|
291
|
+
// The request-specific terminal proves the broker claimed the request; preserve recovery evidence if marker cleanup won the race.
|
|
292
|
+
accepted = true;
|
|
293
|
+
response = readPublishedResponse(raw, requestId, channelDir, accepted);
|
|
200
294
|
malformedResponseRaw = null;
|
|
201
295
|
}
|
|
202
296
|
catch (error) {
|
|
@@ -232,7 +326,7 @@ function authority(params) {
|
|
|
232
326
|
export function requestSandboxControl(params) {
|
|
233
327
|
if (!isSandboxControlFamily(params.family))
|
|
234
328
|
clientError('SANDBOX_CONTROL_COMMAND_DENIED', `'${params.family}' is not allowed`, false);
|
|
235
|
-
if (params.family === 'task-create' || params.family === 'codex-controller' || params.family === 'task-finalization') {
|
|
329
|
+
if (params.family === 'task-create' || params.family === 'codex-controller' || params.family === 'task-finalization' || params.family === 'task-workflow') {
|
|
236
330
|
clientError('SANDBOX_CONTROL_COMMAND_DENIED', `'${params.family}' requires a typed request`, false);
|
|
237
331
|
}
|
|
238
332
|
const auth = authority(params);
|
|
@@ -251,14 +345,15 @@ export function requestSandboxTaskControl(params) {
|
|
|
251
345
|
const issuedAt = Date.now();
|
|
252
346
|
const request = {
|
|
253
347
|
version: 3,
|
|
254
|
-
id: randomUUID(),
|
|
348
|
+
id: params.authority?.requestId ?? randomUUID(),
|
|
255
349
|
...auth,
|
|
256
350
|
issuedAt,
|
|
257
351
|
expiresAt: issuedAt + SANDBOX_CONTROL_ADMISSION_WINDOW_MS,
|
|
258
352
|
family: params.family,
|
|
259
353
|
args: params.args,
|
|
260
354
|
controllerProcess: null,
|
|
261
|
-
controllerProof: params.controllerProof
|
|
355
|
+
controllerProof: params.authority ? null : params.controllerProof,
|
|
356
|
+
...(params.authority ? { authority: params.authority } : {})
|
|
262
357
|
};
|
|
263
358
|
return exchangeSandboxControl(request, params);
|
|
264
359
|
}
|
|
@@ -283,6 +378,24 @@ export function requestSandboxTaskFinalization(params) {
|
|
|
283
378
|
};
|
|
284
379
|
return exchangeSandboxControl(request, params);
|
|
285
380
|
}
|
|
381
|
+
export function requestSandboxTaskWorkflow(params) {
|
|
382
|
+
const auth = authority(params);
|
|
383
|
+
const issuedAt = Date.now();
|
|
384
|
+
const request = {
|
|
385
|
+
version: 3,
|
|
386
|
+
id: params.workflow.id,
|
|
387
|
+
...auth,
|
|
388
|
+
issuedAt,
|
|
389
|
+
expiresAt: issuedAt + SANDBOX_CONTROL_ADMISSION_WINDOW_MS,
|
|
390
|
+
family: 'task-workflow',
|
|
391
|
+
args: [],
|
|
392
|
+
controllerProcess: null,
|
|
393
|
+
controllerProof: null,
|
|
394
|
+
workflow: params.workflow,
|
|
395
|
+
...(params.authority ? { authority: params.authority } : {})
|
|
396
|
+
};
|
|
397
|
+
return exchangeSandboxControl(request, params);
|
|
398
|
+
}
|
|
286
399
|
function exactKeys(value, keys) {
|
|
287
400
|
return Object.keys(value).sort().join(',') === [...keys].sort().join(',');
|
|
288
401
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { resolveTaskWorkspace } from '../task-resolver.js';
|
|
4
|
+
import { assertGitWorktreeBinding } from '../../git/worktree-identity.js';
|
|
5
|
+
import { parseTypedTaskFrontmatter } from '../../task/frontmatter.js';
|
|
6
|
+
import { readTaskFinalizationReceipt } from '../../task/finalization.js';
|
|
7
|
+
import { inspectSandboxControlContainer } from './container-identity.js';
|
|
8
|
+
import { atomicWriteJson, readSandboxControlStatus } from './state.js';
|
|
9
|
+
import { taskViewForManifest } from './task-view.js';
|
|
10
|
+
function evidencePath(manifest) {
|
|
11
|
+
return path.join(path.dirname(manifest.processingDir), 'completed-reentry.json');
|
|
12
|
+
}
|
|
13
|
+
function invalid() {
|
|
14
|
+
return new Error('SANDBOX_COMPLETED_REENTRY_EVIDENCE_INVALID');
|
|
15
|
+
}
|
|
16
|
+
export async function prepareCompletedReentry(manifest, inspect = inspectSandboxControlContainer) {
|
|
17
|
+
if (manifest.mode !== 'task-bound' || !manifest.taskId)
|
|
18
|
+
throw invalid();
|
|
19
|
+
assertGitWorktreeBinding(manifest.repoRoot, manifest.worktreeRoot, manifest.branch);
|
|
20
|
+
const container = await inspect(manifest);
|
|
21
|
+
if (container.state !== 'found' || container.id !== manifest.containerIdentity.id)
|
|
22
|
+
throw invalid();
|
|
23
|
+
const task = resolveTaskWorkspace(manifest.taskId, manifest.repoRoot);
|
|
24
|
+
const metadata = parseTypedTaskFrontmatter(fs.readFileSync(task.taskMd, 'utf8'));
|
|
25
|
+
if (task.state !== 'completed' || task.branch !== manifest.branch
|
|
26
|
+
|| metadata.id !== manifest.taskId || metadata.status !== 'completed')
|
|
27
|
+
throw invalid();
|
|
28
|
+
const receipt = readTaskFinalizationReceipt(manifest.repoRoot, manifest.taskId);
|
|
29
|
+
if (!receipt || receipt.taskId !== manifest.taskId)
|
|
30
|
+
throw invalid();
|
|
31
|
+
const view = taskViewForManifest({ ...manifest, receipt });
|
|
32
|
+
if (view.state !== 'current' || view.observedSource !== 'completed' || !view.receipt)
|
|
33
|
+
throw invalid();
|
|
34
|
+
const status = readSandboxControlStatus(manifest.publicStatusDir);
|
|
35
|
+
const previous = status.taskView;
|
|
36
|
+
if (status.generation !== manifest.generation || status.activeRequestId !== null
|
|
37
|
+
|| previous.taskId !== manifest.taskId || !previous.receipt
|
|
38
|
+
|| previous.receipt.receiptId !== view.receipt.receiptId
|
|
39
|
+
|| previous.receipt.generation !== view.receipt.generation
|
|
40
|
+
|| previous.receipt.requestId !== view.receipt.requestId
|
|
41
|
+
|| previous.receipt.revision > view.receipt.revision)
|
|
42
|
+
throw invalid();
|
|
43
|
+
const completedRoot = fs.realpathSync.native(path.join(manifest.repoRoot, '.agents', 'workspace', 'completed'));
|
|
44
|
+
const source = fs.realpathSync.native(path.join(completedRoot, manifest.taskId));
|
|
45
|
+
if (source !== path.join(completedRoot, manifest.taskId))
|
|
46
|
+
throw invalid();
|
|
47
|
+
const stat = fs.statSync(source, { bigint: true });
|
|
48
|
+
return {
|
|
49
|
+
taskId: manifest.taskId, generation: manifest.generation,
|
|
50
|
+
containerId: container.id, branch: manifest.branch,
|
|
51
|
+
worktreeRoot: fs.realpathSync.native(manifest.worktreeRoot),
|
|
52
|
+
source, sourceDevice: String(stat.dev), sourceInode: String(stat.ino), receipt: view.receipt
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function publishCompletedReentry(manifest, evidence) {
|
|
56
|
+
atomicWriteJson(evidencePath(manifest), evidence);
|
|
57
|
+
}
|
|
58
|
+
export async function completedReentryView(manifest, inspect = inspectSandboxControlContainer) {
|
|
59
|
+
const file = evidencePath(manifest);
|
|
60
|
+
if (!fs.existsSync(file))
|
|
61
|
+
return null;
|
|
62
|
+
const evidence = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
63
|
+
const current = await prepareCompletedReentry(manifest, inspect);
|
|
64
|
+
if (JSON.stringify(evidence) !== JSON.stringify(current))
|
|
65
|
+
throw invalid();
|
|
66
|
+
return {
|
|
67
|
+
state: 'current', taskId: current.taskId, observedSource: 'completed',
|
|
68
|
+
receipt: current.receipt, reasonCode: null
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export async function waitForCompletedReentry(manifest, evidence) {
|
|
72
|
+
const deadline = Date.now() + 10_000;
|
|
73
|
+
while (Date.now() < deadline) {
|
|
74
|
+
const status = readSandboxControlStatus(manifest.publicStatusDir);
|
|
75
|
+
if (status.generation !== evidence.generation)
|
|
76
|
+
throw invalid();
|
|
77
|
+
if (status.taskView.state === 'current' && status.taskView.observedSource === 'completed'
|
|
78
|
+
&& status.taskView.taskId === evidence.taskId
|
|
79
|
+
&& JSON.stringify(status.taskView.receipt) === JSON.stringify(evidence.receipt))
|
|
80
|
+
return;
|
|
81
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
82
|
+
}
|
|
83
|
+
throw new Error('SANDBOX_COMPLETED_REENTRY_STATUS_TIMEOUT');
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=completed-reentry.js.map
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
return /(?:no such (?:container|object)|container .* not found|cannot find container)/i.test(message);
|
|
5
|
-
}
|
|
1
|
+
import { runProbe } from '../shell.js';
|
|
2
|
+
import { captureSandboxAuthority, isSandboxAuthorityEvidence, verifySandboxAuthority } from '../engines/authority.js';
|
|
3
|
+
import { discoverExactContainer } from '../engines/docker-exact-discovery.js';
|
|
6
4
|
export function classifySandboxContainerInspection(expected, inspection) {
|
|
7
5
|
if ('notFound' in inspection)
|
|
8
6
|
return { state: 'absent', id: expected.id };
|
|
9
7
|
if ('error' in inspection) {
|
|
10
|
-
return
|
|
11
|
-
? { state: 'absent', id: expected.id }
|
|
12
|
-
: { state: 'unknown', reason: `container inspection failed: ${inspection.error instanceof Error ? inspection.error.message : String(inspection.error)}` };
|
|
8
|
+
return { state: 'unknown', reason: `container inspection failed: ${inspection.error instanceof Error ? inspection.error.message : String(inspection.error)}` };
|
|
13
9
|
}
|
|
14
10
|
const response = inspection;
|
|
15
11
|
if (typeof response.id !== 'string' || response.id !== expected.id
|
|
@@ -30,32 +26,33 @@ export function classifySandboxContainerInspection(expected, inspection) {
|
|
|
30
26
|
};
|
|
31
27
|
}
|
|
32
28
|
export async function inspectSandboxControlContainer(manifest, options = {}) {
|
|
29
|
+
if (!isSandboxAuthorityEvidence(manifest.authorityEvidence)) {
|
|
30
|
+
return { state: 'unknown', reason: 'SANDBOX_AUTHORITY_EVIDENCE_MISSING' };
|
|
31
|
+
}
|
|
33
32
|
try {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const stderr = typeof result.stderr === 'string' ? result.stderr : result.stderr?.toString('utf8') ?? '';
|
|
44
|
-
return classifySandboxContainerInspection(manifest.containerIdentity, {
|
|
45
|
-
error: new Error(stderr || `container inspection exited with ${result.status ?? 'unknown'}`)
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
raw = typeof result.stdout === 'string' ? result.stdout : result.stdout?.toString('utf8') ?? '';
|
|
33
|
+
const authority = captureSandboxAuthority(manifest.engine, {
|
|
34
|
+
probe: options.probe,
|
|
35
|
+
timeoutMs: options.timeoutMs,
|
|
36
|
+
lockDomain: manifest.authorityEvidence.lockDomain,
|
|
37
|
+
route: manifest.authorityEvidence
|
|
38
|
+
});
|
|
39
|
+
const authorityState = verifySandboxAuthority(manifest.authorityEvidence, authority);
|
|
40
|
+
if (authorityState.state !== 'verified') {
|
|
41
|
+
return { state: 'unknown', reason: authorityState.reason ?? 'SANDBOX_AUTHORITY_UNAVAILABLE' };
|
|
49
42
|
}
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return classifySandboxContainerInspection(manifest.containerIdentity, {
|
|
55
|
-
id: value.Id,
|
|
56
|
-
running: value.State?.Running,
|
|
57
|
-
labels: value.Config?.Labels
|
|
43
|
+
const discovered = discoverExactContainer(manifest.engine, manifest.containerIdentity.id, {
|
|
44
|
+
probe: options.probe,
|
|
45
|
+
timeoutMs: options.timeoutMs,
|
|
46
|
+
authority: manifest.authorityEvidence
|
|
58
47
|
});
|
|
48
|
+
if (discovered.state === 'absent')
|
|
49
|
+
return { state: 'absent', id: discovered.id };
|
|
50
|
+
if (discovered.state === 'conflict') {
|
|
51
|
+
return { state: 'unknown', reason: `SANDBOX_CONTROL_CONTAINER_CONFLICT: ${discovered.reason}` };
|
|
52
|
+
}
|
|
53
|
+
if (discovered.state === 'unknown')
|
|
54
|
+
return discovered;
|
|
55
|
+
return classifySandboxContainerInspection(manifest.containerIdentity, discovered);
|
|
59
56
|
}
|
|
60
57
|
catch (error) {
|
|
61
58
|
return classifySandboxContainerInspection(manifest.containerIdentity, { error });
|