@fitlab-ai/agent-infra 0.9.12 → 0.9.14
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 +11 -11
- package/README.zh-CN.md +11 -11
- package/bin/cli.ts +26 -9
- package/dist/bin/cli.js +173 -157
- package/dist/bin/internal-cli.js +66 -40
- package/dist/lib/agent-client.js +5 -0
- package/dist/lib/agent-clients/next-steps.js +6 -1
- package/dist/lib/decide.js +3 -3
- package/dist/lib/internal/agent-client.js +5 -2
- package/dist/lib/internal/cli-route-inventory.js +152 -0
- package/dist/lib/internal/codex-lifecycle.js +9 -6
- package/dist/lib/internal/codex-sandbox-controller.js +8 -2
- package/dist/lib/internal/git-workflow.js +10 -6
- package/dist/lib/internal/platform-checks.js +19 -7
- package/dist/lib/internal/platform-comment.js +25 -13
- package/dist/lib/internal/platform-context.js +6 -3
- package/dist/lib/internal/platform-issue.js +20 -13
- package/dist/lib/internal/platform-metadata.js +88 -0
- package/dist/lib/internal/platform-pr-review.js +26 -13
- package/dist/lib/internal/platform-pr.js +84 -31
- package/dist/lib/internal/platform-release-notes.js +9 -6
- package/dist/lib/internal/platform-security.js +93 -0
- package/dist/lib/internal/pr-review-grade.js +25 -12
- package/dist/lib/internal/release-workflow.js +23 -9
- package/dist/lib/internal/sandbox-control.js +50 -7
- package/dist/lib/internal/task-activity.js +16 -7
- package/dist/lib/internal/task-artifact.js +235 -24
- package/dist/lib/internal/task-context.js +4 -1
- package/dist/lib/internal/task-create.js +50 -17
- package/dist/lib/internal/task-delivery.js +4 -1
- package/dist/lib/internal/task-event.js +10 -4
- package/dist/lib/internal/task-finalization.js +6 -3
- package/dist/lib/internal/task-invalidation.js +63 -0
- package/dist/lib/internal/task-ledger.js +20 -6
- package/dist/lib/internal/task-lifecycle.js +6 -3
- package/dist/lib/internal/task-operation-registry.js +421 -0
- package/dist/lib/internal/task-orchestration.js +12 -0
- package/dist/lib/internal/task-override.js +14 -7
- package/dist/lib/internal/task-qualification.js +90 -0
- package/dist/lib/internal/task-review.js +7 -4
- 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 +7 -2
- package/dist/lib/internal/task-verify.js +11 -7
- package/dist/lib/internal/task-warning.js +11 -4
- package/dist/lib/platform/adapters.js +1 -3
- package/dist/lib/platform/change-request-git-evidence.js +27 -7
- package/dist/lib/platform/comment-safety.js +226 -0
- package/dist/lib/platform/completion-backfill.js +6 -5
- package/dist/lib/platform/context.js +70 -130
- package/dist/lib/platform/github-client.js +1 -1
- package/dist/lib/platform/github-provider.js +1130 -0
- package/dist/lib/platform/in-label-sync.js +143 -0
- package/dist/lib/platform/issue-comments.js +237 -72
- package/dist/lib/platform/issues.js +335 -189
- package/dist/lib/platform/metadata-labels.js +6 -2
- package/dist/lib/platform/none-provider.js +28 -0
- package/dist/lib/platform/pr-change-report.js +545 -0
- package/dist/lib/platform/pr-checks.js +119 -104
- package/dist/lib/platform/pr-review.js +88 -72
- package/dist/lib/platform/pr-summary.js +541 -50
- package/dist/lib/platform/provider-bridge.js +45 -0
- package/dist/lib/platform/provider-contract.d.ts +553 -0
- package/dist/lib/platform/provider-contract.js +99 -0
- package/dist/lib/platform/provider-loader.js +251 -0
- package/dist/lib/platform/provider-validation.js +577 -0
- package/dist/lib/platform/pull-request-metadata.js +8 -6
- package/dist/lib/platform/pull-requests.js +734 -543
- package/dist/lib/platform/release-notes.js +78 -55
- package/dist/lib/platform/releases.js +79 -50
- package/dist/lib/platform/repository-metadata.js +377 -0
- package/dist/lib/platform/resource-identity.d.ts +26 -0
- package/dist/lib/platform/resource-identity.js +92 -0
- package/dist/lib/platform/security-alerts.js +155 -0
- package/dist/lib/platform/task-identities.js +31 -0
- package/dist/lib/platform/verification-required.js +11 -12
- package/dist/lib/platform/verification-sync.js +129 -248
- package/dist/lib/pr-review/evidence-grading.js +19 -6
- package/dist/lib/process-data/index.js +7 -0
- package/dist/lib/run/index.js +68 -23
- package/dist/lib/sandbox/commands/control-status.js +22 -0
- package/dist/lib/sandbox/commands/create.js +32 -6
- package/dist/lib/sandbox/commands/ls.js +5 -0
- package/dist/lib/sandbox/commands/rm.js +827 -120
- package/dist/lib/sandbox/commands/show.js +16 -0
- package/dist/lib/sandbox/control/client.js +174 -19
- 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 +151 -16
- package/dist/lib/sandbox/control/lifecycle.js +621 -127
- package/dist/lib/sandbox/control/native-file-lock.js +177 -0
- package/dist/lib/sandbox/control/protocol.js +77 -0
- package/dist/lib/sandbox/control/server.js +677 -34
- package/dist/lib/sandbox/control/state.js +209 -4
- package/dist/lib/sandbox/control/task-view.js +183 -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 +5 -0
- package/dist/lib/sandbox/recovery.js +21 -1
- package/dist/lib/sandbox/workspace-view.js +2 -1
- package/dist/lib/sandbox/worktree-safety.js +4 -1
- package/dist/lib/server/index.js +8 -0
- package/dist/lib/server/protocol.js +38 -1
- package/dist/lib/task/activity-log.js +8 -1
- package/dist/lib/task/artifact-lifecycle.js +75 -18
- package/dist/lib/task/artifact-operations.js +520 -0
- package/dist/lib/task/artifact-repair-intent.js +59 -0
- package/dist/lib/task/artifact-schema.js +135 -0
- package/dist/lib/task/capabilities.js +310 -0
- package/dist/lib/task/commands/status.js +32 -0
- package/dist/lib/task/commit-operation.js +12 -1
- package/dist/lib/task/control-authority.js +12 -5
- package/dist/lib/task/create-service.js +111 -12
- package/dist/lib/task/create.js +25 -0
- package/dist/lib/task/current-contract.js +5 -1
- package/dist/lib/task/decision-details.js +1 -1
- package/dist/lib/task/events.js +416 -17
- package/dist/lib/task/finalization.js +37 -13
- package/dist/lib/task/human-override.js +58 -36
- package/dist/lib/task/index.js +11 -3
- package/dist/lib/task/invalidation-command.js +86 -0
- package/dist/lib/task/invalidation.js +260 -0
- package/dist/lib/task/ledger-intents.js +37 -0
- package/dist/lib/task/local-artifact-finalization.js +299 -0
- package/dist/lib/task/orchestration.js +240 -144
- package/dist/lib/task/pr-delivery-fact.js +102 -101
- package/dist/lib/task/qualification-audit.js +490 -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 +22 -23
- package/dist/lib/task/review-finalization.js +121 -4
- package/dist/lib/task/review-fingerprint.js +24 -2
- package/dist/lib/task/rework-intent.js +138 -0
- package/dist/lib/task/sections.js +6 -4
- package/dist/lib/task/skill-scope.js +23 -0
- package/dist/lib/task/task-execution-lock.js +27 -17
- package/dist/lib/task/verification-config.js +11 -0
- package/dist/lib/task/verification-engine.js +93 -16
- package/dist/lib/task/verification.js +3 -3
- package/dist/lib/task/workflow-warning-intents.js +1 -1
- package/dist/lib/task/write.js +11 -0
- package/dist/lib/version.js +11 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-client.ts +9 -0
- package/lib/agent-clients/next-steps.ts +6 -1
- package/lib/decide.ts +3 -3
- package/lib/init.ts +1 -1
- package/lib/internal/agent-client.ts +4 -2
- package/lib/internal/cli-route-inventory.ts +140 -0
- package/lib/internal/codex-lifecycle.ts +8 -6
- package/lib/internal/codex-sandbox-controller.ts +7 -2
- package/lib/internal/git-workflow.ts +9 -6
- package/lib/internal/platform-checks.ts +14 -6
- package/lib/internal/platform-comment.ts +20 -12
- package/lib/internal/platform-context.ts +5 -3
- package/lib/internal/platform-issue.ts +17 -11
- package/lib/internal/platform-metadata.ts +70 -0
- package/lib/internal/platform-pr-review.ts +23 -12
- package/lib/internal/platform-pr.ts +65 -27
- package/lib/internal/platform-release-notes.ts +8 -6
- package/lib/internal/platform-security.ts +83 -0
- package/lib/internal/pr-review-grade.ts +20 -11
- package/lib/internal/release-workflow.ts +21 -9
- package/lib/internal/sandbox-control.ts +44 -6
- package/lib/internal/task-activity.ts +15 -7
- package/lib/internal/task-artifact.ts +204 -22
- package/lib/internal/task-context.ts +3 -1
- package/lib/internal/task-create.ts +78 -17
- package/lib/internal/task-delivery.ts +3 -1
- package/lib/internal/task-event.ts +9 -4
- package/lib/internal/task-finalization.ts +6 -4
- package/lib/internal/task-invalidation.ts +41 -0
- package/lib/internal/task-ledger.ts +21 -8
- package/lib/internal/task-lifecycle.ts +5 -3
- package/lib/internal/task-operation-registry.ts +482 -0
- package/lib/internal/task-orchestration.ts +12 -0
- package/lib/internal/task-override.ts +15 -9
- package/lib/internal/task-qualification.ts +61 -0
- package/lib/internal/task-review.ts +6 -4
- package/lib/internal/task-short-id.ts +10 -1
- package/lib/internal/task-snapshot.ts +3 -1
- package/lib/internal/task-validate.ts +6 -2
- package/lib/internal/task-verify.ts +10 -7
- package/lib/internal/task-warning.ts +10 -4
- package/lib/platform/adapters.ts +3 -2
- package/lib/platform/change-request-git-evidence.ts +36 -9
- package/lib/platform/comment-safety.ts +250 -0
- package/lib/platform/completion-backfill.ts +9 -8
- package/lib/platform/context.ts +97 -134
- package/lib/platform/github-client.ts +2 -2
- package/lib/platform/github-provider.ts +1132 -0
- package/lib/platform/in-label-sync.ts +208 -0
- package/lib/platform/issue-comments.ts +255 -80
- package/lib/platform/issues.ts +344 -174
- package/lib/platform/metadata-labels.ts +5 -2
- package/lib/platform/none-provider.ts +35 -0
- package/lib/platform/pr-change-report.ts +639 -0
- package/lib/platform/pr-checks.ts +126 -106
- package/lib/platform/pr-review.ts +88 -85
- package/lib/platform/pr-summary.ts +581 -53
- package/lib/platform/provider-bridge.ts +82 -0
- package/lib/platform/provider-contract.ts +611 -0
- package/lib/platform/provider-loader.ts +307 -0
- package/lib/platform/provider-validation.ts +611 -0
- package/lib/platform/pull-request-metadata.ts +10 -7
- package/lib/platform/pull-requests.ts +781 -550
- package/lib/platform/release-notes.ts +76 -59
- package/lib/platform/releases.ts +77 -43
- package/lib/platform/repository-metadata.ts +453 -0
- package/lib/platform/resource-identity.ts +121 -0
- package/lib/platform/security-alerts.ts +191 -0
- package/lib/platform/task-identities.ts +40 -0
- package/lib/platform/types.ts +4 -2
- package/lib/platform/verification-required.ts +11 -13
- package/lib/platform/verification-sync.ts +128 -304
- package/lib/pr-review/evidence-grading.ts +25 -8
- package/lib/process-data/index.ts +7 -0
- package/lib/run/index.ts +62 -22
- package/lib/sandbox/commands/control-status.ts +26 -0
- package/lib/sandbox/commands/create.ts +46 -6
- package/lib/sandbox/commands/ls.ts +7 -0
- package/lib/sandbox/commands/rm.ts +1000 -87
- package/lib/sandbox/commands/show.ts +16 -0
- package/lib/sandbox/control/client.ts +203 -19
- package/lib/sandbox/control/completed-reentry.ts +98 -0
- package/lib/sandbox/control/container-identity.ts +27 -43
- package/lib/sandbox/control/executor.ts +180 -15
- package/lib/sandbox/control/lifecycle.ts +629 -17
- package/lib/sandbox/control/native-file-lock.ts +209 -0
- package/lib/sandbox/control/protocol.ts +118 -2
- package/lib/sandbox/control/server.ts +724 -34
- package/lib/sandbox/control/state.ts +257 -4
- package/lib/sandbox/control/task-view.ts +240 -0
- package/lib/sandbox/engines/authority.ts +365 -0
- package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
- package/lib/sandbox/index.ts +7 -0
- package/lib/sandbox/recovery.ts +21 -1
- package/lib/sandbox/workspace-view.ts +9 -3
- package/lib/sandbox/worktree-safety.ts +4 -1
- package/lib/server/index.ts +10 -0
- package/lib/server/protocol.ts +36 -1
- package/lib/task/activity-log.ts +8 -0
- package/lib/task/artifact-lifecycle.ts +70 -22
- package/lib/task/artifact-operations.ts +626 -0
- package/lib/task/artifact-repair-intent.ts +71 -0
- package/lib/task/artifact-schema.ts +192 -0
- package/lib/task/capabilities.ts +331 -0
- package/lib/task/commands/status.ts +38 -0
- package/lib/task/commit-operation.ts +12 -1
- package/lib/task/control-authority.ts +22 -9
- package/lib/task/create-service.ts +139 -14
- package/lib/task/create.ts +27 -0
- package/lib/task/current-contract.ts +6 -1
- package/lib/task/decision-details.ts +6 -2
- package/lib/task/events.ts +392 -16
- package/lib/task/finalization.ts +50 -14
- package/lib/task/human-override.ts +70 -46
- package/lib/task/index.ts +16 -3
- package/lib/task/invalidation-command.ts +86 -0
- package/lib/task/invalidation.ts +332 -0
- package/lib/task/ledger-intents.ts +35 -1
- package/lib/task/local-artifact-finalization.ts +432 -0
- package/lib/task/orchestration.ts +223 -133
- package/lib/task/pr-delivery-fact.ts +131 -148
- package/lib/task/qualification-audit.ts +599 -0
- package/lib/task/qualification-confirmation.ts +117 -0
- package/lib/task/qualification-intents.ts +150 -0
- package/lib/task/review-artifacts.ts +21 -22
- package/lib/task/review-finalization.ts +133 -4
- package/lib/task/review-fingerprint.ts +23 -2
- package/lib/task/rework-intent.ts +165 -0
- package/lib/task/sections.ts +6 -4
- package/lib/task/skill-scope.ts +24 -0
- package/lib/task/task-execution-lock.ts +23 -14
- package/lib/task/verification-config.ts +12 -0
- package/lib/task/verification-engine.ts +103 -17
- package/lib/task/verification.ts +4 -4
- package/lib/task/workflow-warning-intents.ts +1 -1
- package/lib/task/write.ts +19 -0
- package/lib/update.ts +1 -1
- package/lib/version.ts +15 -1
- package/package.json +12 -1
- package/templates/.agents/rules/README.en.md +3 -1
- package/templates/.agents/rules/README.zh-CN.md +3 -1
- 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/issue-pr-commands.en.md +1 -1
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.en.md +2 -0
- package/templates/.agents/rules/issue-sync.zh-CN.md +2 -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 +13 -2
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -2
- package/templates/.agents/rules/pr-sync.en.md +10 -4
- package/templates/.agents/rules/pr-sync.zh-CN.md +17 -4
- 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/task-short-id.en.md +1 -4
- package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
- package/templates/.agents/skills/analyze-task/SKILL.en.md +28 -5
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +29 -5
- 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/check-task/SKILL.en.md +16 -37
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
- 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 +41 -9
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +43 -11
- package/templates/.agents/skills/code-task/config/verify.en.json +6 -14
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +6 -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/commit/reference/issue-metadata-sync.en.md +2 -0
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +3 -3
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +3 -3
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +10 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +10 -4
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +4 -3
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +4 -3
- package/templates/.agents/skills/complete-task/SKILL.en.md +26 -21
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +25 -21
- package/templates/.agents/skills/create-pr/SKILL.en.md +7 -6
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -7
- package/templates/.agents/skills/create-pr/config/verify.json +1 -0
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
- 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 +27 -4
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +26 -4
- 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/review-analysis/SKILL.en.md +17 -4
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +17 -4
- 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 +18 -5
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +18 -5
- 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 +17 -4
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +17 -4
- 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 +9 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +9 -3
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
- package/templates/.agents/skills/test/SKILL.en.md +13 -2
- package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
- package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
- package/templates/.agents/templates/task.en.md +24 -1
- package/templates/.agents/templates/task.zh-CN.md +24 -1
- package/templates/.github/workflows/pr-label.yml +7 -26
- 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) {
|
|
@@ -3,25 +3,79 @@ import path from 'node:path';
|
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import { SANDBOX_CONTROL_ADMISSION_WINDOW_MS, SANDBOX_CONTROL_MAX_BYTES, SANDBOX_CONTROL_STATUS_STALE_MS, isSandboxControlFamily } from './protocol.js';
|
|
5
5
|
import { normalizeAgentToken } from '../../agent-clients/tokens.js';
|
|
6
|
-
import { readSandboxControlStatus } from './state.js';
|
|
6
|
+
import { readSandboxControlPayload, readSandboxControlStatus } from './state.js';
|
|
7
|
+
import { accessSandboxTaskView, taskViewFromStatus } from './task-view.js';
|
|
7
8
|
const SANDBOX_CONTROL_RESPONSE_SETTLE_MS = 250;
|
|
9
|
+
export function classifySandboxControlEnvironment(env = process.env) {
|
|
10
|
+
const controlKeys = [
|
|
11
|
+
'AGENT_INFRA_CONTROL_TOKEN',
|
|
12
|
+
'AGENT_INFRA_CONTROL_GENERATION',
|
|
13
|
+
'AGENT_INFRA_CONTROL_DIR',
|
|
14
|
+
'AGENT_INFRA_CONTROL_STATUS_DIR'
|
|
15
|
+
];
|
|
16
|
+
const hasControlMarker = controlKeys.some((key) => Boolean(env[key]));
|
|
17
|
+
const hasTaskIdentity = Boolean(env.AGENT_INFRA_TASK_ID);
|
|
18
|
+
const hasRuntime = Boolean(env.AGENT_INFRA_RUNTIME_DIR);
|
|
19
|
+
const hasExecutorMarker = Boolean(env.AGENT_INFRA_EXECUTOR_MANIFEST);
|
|
20
|
+
const hasControllerBinding = Boolean(env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING);
|
|
21
|
+
const hasAnyMarker = hasControlMarker || hasTaskIdentity || hasRuntime || hasExecutorMarker || hasControllerBinding;
|
|
22
|
+
const hasCompleteControl = controlKeys.every((key) => Boolean(env[key]));
|
|
23
|
+
if (!hasAnyMarker)
|
|
24
|
+
return { kind: 'direct' };
|
|
25
|
+
if (hasExecutorMarker) {
|
|
26
|
+
return {
|
|
27
|
+
kind: 'invalid',
|
|
28
|
+
code: 'TASK_CONTROL_TRANSPORT_INVALID',
|
|
29
|
+
message: 'executor context is only valid for sandbox-control execute'
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (hasControllerBinding) {
|
|
33
|
+
return {
|
|
34
|
+
kind: 'invalid',
|
|
35
|
+
code: 'TASK_CONTROL_TRANSPORT_INVALID',
|
|
36
|
+
message: 'sandbox client control configuration is incomplete or conflicting'
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (!hasCompleteControl) {
|
|
40
|
+
return {
|
|
41
|
+
kind: 'invalid',
|
|
42
|
+
code: 'TASK_CONTROL_TRANSPORT_INVALID',
|
|
43
|
+
message: 'sandbox client control configuration is incomplete or conflicting'
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (hasTaskIdentity !== hasRuntime) {
|
|
47
|
+
return {
|
|
48
|
+
kind: 'invalid',
|
|
49
|
+
code: 'TASK_CONTROL_TRANSPORT_INVALID',
|
|
50
|
+
message: 'sandbox task identity and runtime binding must be provided together'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return { kind: 'controlled', mode: hasTaskIdentity ? 'task-bound' : 'branch-only' };
|
|
54
|
+
}
|
|
8
55
|
export class SandboxControlClientError extends Error {
|
|
9
56
|
detail;
|
|
10
57
|
accepted;
|
|
11
|
-
|
|
58
|
+
requestId;
|
|
59
|
+
constructor(detail, accepted = false, requestId = null) {
|
|
12
60
|
super(detail.message);
|
|
13
61
|
this.name = 'SandboxControlClientError';
|
|
14
62
|
this.detail = detail;
|
|
15
63
|
this.accepted = accepted;
|
|
64
|
+
this.requestId = requestId;
|
|
16
65
|
}
|
|
17
66
|
}
|
|
18
67
|
function sleep(milliseconds) {
|
|
19
68
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
|
|
20
69
|
}
|
|
21
|
-
function clientError(code, message, retryable, accepted = false) {
|
|
22
|
-
throw new SandboxControlClientError({ code, message: `${code}: ${message}`, retryable }, accepted);
|
|
70
|
+
function clientError(code, message, retryable, accepted = false, requestId = null) {
|
|
71
|
+
throw new SandboxControlClientError({ code, message: `${code}: ${message}`, retryable }, accepted, requestId);
|
|
72
|
+
}
|
|
73
|
+
function hasTaskBoundMarker(env = process.env) {
|
|
74
|
+
return Boolean(env.AGENT_INFRA_TASK_ID)
|
|
75
|
+
&& Boolean(env.AGENT_INFRA_CONTROL_TOKEN || env.AGENT_INFRA_CONTROL_GENERATION
|
|
76
|
+
|| env.AGENT_INFRA_CONTROL_STATUS_DIR || env.AGENT_INFRA_RUNTIME_DIR || env.AGENT_INFRA_CONTROL_DIR);
|
|
23
77
|
}
|
|
24
|
-
function preflight(statusDir, generation, now = Date.now()) {
|
|
78
|
+
function preflight(statusDir, generation, taskViewEffect = null, now = Date.now(), env = process.env) {
|
|
25
79
|
let status;
|
|
26
80
|
try {
|
|
27
81
|
status = readSandboxControlStatus(statusDir);
|
|
@@ -43,16 +97,56 @@ function preflight(statusDir, generation, now = Date.now()) {
|
|
|
43
97
|
}
|
|
44
98
|
if (status.state !== 'healthy')
|
|
45
99
|
clientError('SANDBOX_CONTROL_BROKER_UNAVAILABLE', 'broker is not ready', true);
|
|
100
|
+
if (taskViewEffect && hasTaskBoundMarker(env)) {
|
|
101
|
+
const view = taskViewFromStatus(status);
|
|
102
|
+
if (view.taskId !== env.AGENT_INFRA_TASK_ID) {
|
|
103
|
+
clientError('SANDBOX_TASK_VIEW_TASK_ID_MISMATCH', 'task view task id does not match the sandbox task marker', false);
|
|
104
|
+
}
|
|
105
|
+
const access = accessSandboxTaskView(view, taskViewEffect);
|
|
106
|
+
if (!access.allowed) {
|
|
107
|
+
clientError(access.reasonCode ?? 'SANDBOX_TASK_VIEW_DENIED', access.message ?? 'task view denied', false);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function taskViewEffectForRequest(request) {
|
|
112
|
+
if (request.family === 'task-lifecycle' || request.family === 'task-finalization')
|
|
113
|
+
return 'progress';
|
|
114
|
+
if (request.family === 'task-orchestration')
|
|
115
|
+
return request.args[1] === 'status' ? 'diagnostic' : 'progress';
|
|
116
|
+
return null;
|
|
46
117
|
}
|
|
47
|
-
function parseResponse(raw, id) {
|
|
118
|
+
function parseResponse(raw, id, accepted = false) {
|
|
48
119
|
const response = JSON.parse(raw);
|
|
49
120
|
if (response.version !== 2 || response.id !== id
|
|
50
|
-
|| !['
|
|
51
|
-
|| (response.phase === 'completed' && !Number.isInteger(response.exitCode))
|
|
52
|
-
|
|
121
|
+
|| !['completed', 'rejected'].includes(response.phase)
|
|
122
|
+
|| (response.phase === 'completed' && !Number.isInteger(response.exitCode))
|
|
123
|
+
|| (response.outputState !== undefined && response.outputState !== 'available' && response.outputState !== 'unavailable')
|
|
124
|
+
|| (response.outputState === 'available' && !response.payload)
|
|
125
|
+
|| (response.outputState === 'unavailable' && response.payload !== null && response.payload !== undefined)) {
|
|
126
|
+
clientError('SANDBOX_CONTROL_RESPONSE_INVALID', 'broker response is invalid', false, accepted, id);
|
|
53
127
|
}
|
|
54
128
|
return response;
|
|
55
129
|
}
|
|
130
|
+
function readPublishedResponse(raw, id, channelDir, accepted = false) {
|
|
131
|
+
const response = parseResponse(raw, id, accepted);
|
|
132
|
+
if (response.outputState !== 'available')
|
|
133
|
+
return response;
|
|
134
|
+
const filePath = path.join(channelDir, 'responses', `${id}.payload.json`);
|
|
135
|
+
let payload;
|
|
136
|
+
try {
|
|
137
|
+
payload = readSandboxControlPayload(filePath);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
clientError('SANDBOX_CONTROL_RESPONSE_INVALID', 'broker payload is missing or invalid', false, true, id);
|
|
141
|
+
}
|
|
142
|
+
if (!response.payload || response.payload.version !== payload.version
|
|
143
|
+
|| response.payload.id !== payload.id || response.payload.generation !== payload.generation
|
|
144
|
+
|| response.payload.stdoutBytes !== payload.stdoutBytes || response.payload.stderrBytes !== payload.stderrBytes
|
|
145
|
+
|| response.payload.stdoutSha256 !== payload.stdoutSha256 || response.payload.stderrSha256 !== payload.stderrSha256) {
|
|
146
|
+
clientError('SANDBOX_CONTROL_RESPONSE_INVALID', 'broker payload reference is invalid', false, true, id);
|
|
147
|
+
}
|
|
148
|
+
return { ...response, stdout: payload.stdout, stderr: payload.stderr };
|
|
149
|
+
}
|
|
56
150
|
function cancelPendingRequest(requestPath) {
|
|
57
151
|
try {
|
|
58
152
|
fs.unlinkSync(requestPath);
|
|
@@ -67,16 +161,20 @@ function cancelPendingRequest(requestPath) {
|
|
|
67
161
|
function exchangeSandboxControl(request, params) {
|
|
68
162
|
const channelDir = params.channelDir ?? process.env.AGENT_INFRA_CONTROL_DIR ?? '/run/agent-infra/control';
|
|
69
163
|
const statusDir = params.statusDir ?? process.env.AGENT_INFRA_CONTROL_STATUS_DIR ?? '/run/agent-infra/control-status';
|
|
70
|
-
|
|
164
|
+
const taskViewEffect = taskViewEffectForRequest(request);
|
|
165
|
+
preflight(statusDir, request.generation, taskViewEffect);
|
|
71
166
|
const encoded = `${JSON.stringify(request)}\n`;
|
|
72
167
|
if (Buffer.byteLength(encoded, 'utf8') > SANDBOX_CONTROL_MAX_BYTES) {
|
|
73
|
-
clientError('SANDBOX_CONTROL_REQUEST_TOO_LARGE', 'request exceeds the control limit', false);
|
|
168
|
+
clientError('SANDBOX_CONTROL_REQUEST_TOO_LARGE', 'request exceeds the control limit', false, false, request.id);
|
|
74
169
|
}
|
|
75
170
|
const requestsDir = path.join(channelDir, 'requests');
|
|
76
171
|
const responsesDir = path.join(channelDir, 'responses');
|
|
77
172
|
const temporary = path.join(requestsDir, `.${request.id}.tmp`);
|
|
78
173
|
const requestPath = path.join(requestsDir, `${request.id}.json`);
|
|
79
174
|
const responsePath = path.join(responsesDir, `${request.id}.json`);
|
|
175
|
+
if (fs.existsSync(responsePath)) {
|
|
176
|
+
clientError('SANDBOX_CONTROL_REQUEST_REPLAYED', 'request id already has a terminal response', false, false, request.id);
|
|
177
|
+
}
|
|
80
178
|
fs.writeFileSync(temporary, encoded, { mode: 0o600, flag: 'wx' });
|
|
81
179
|
fs.renameSync(temporary, requestPath);
|
|
82
180
|
const deadline = Date.now() + (params.timeoutMs ?? 30_000);
|
|
@@ -84,6 +182,9 @@ function exchangeSandboxControl(request, params) {
|
|
|
84
182
|
let malformedResponseRaw = null;
|
|
85
183
|
let malformedResponseObservedAt = 0;
|
|
86
184
|
while (Date.now() < deadline) {
|
|
185
|
+
const acceptedPath = path.join(responsesDir, `${request.id}.accepted.json`);
|
|
186
|
+
if (fs.existsSync(acceptedPath))
|
|
187
|
+
accepted = true;
|
|
87
188
|
if (fs.existsSync(responsePath)) {
|
|
88
189
|
let raw;
|
|
89
190
|
try {
|
|
@@ -96,7 +197,9 @@ function exchangeSandboxControl(request, params) {
|
|
|
96
197
|
}
|
|
97
198
|
let response;
|
|
98
199
|
try {
|
|
99
|
-
|
|
200
|
+
// The request-specific terminal proves the broker claimed the request; preserve recovery evidence if marker cleanup won the race.
|
|
201
|
+
accepted = true;
|
|
202
|
+
response = readPublishedResponse(raw, request.id, channelDir, accepted);
|
|
100
203
|
malformedResponseRaw = null;
|
|
101
204
|
}
|
|
102
205
|
catch (error) {
|
|
@@ -108,7 +211,7 @@ function exchangeSandboxControl(request, params) {
|
|
|
108
211
|
malformedResponseObservedAt = now;
|
|
109
212
|
}
|
|
110
213
|
else if (now - malformedResponseObservedAt >= SANDBOX_CONTROL_RESPONSE_SETTLE_MS) {
|
|
111
|
-
clientError('SANDBOX_CONTROL_RESPONSE_INVALID', 'broker response remained malformed', false, accepted);
|
|
214
|
+
clientError('SANDBOX_CONTROL_RESPONSE_INVALID', 'broker response remained malformed', false, accepted, request.id);
|
|
112
215
|
}
|
|
113
216
|
sleep(25);
|
|
114
217
|
continue;
|
|
@@ -117,29 +220,81 @@ function exchangeSandboxControl(request, params) {
|
|
|
117
220
|
accepted = true;
|
|
118
221
|
}
|
|
119
222
|
else {
|
|
120
|
-
fs.rmSync(responsePath, { force: true });
|
|
121
223
|
return response;
|
|
122
224
|
}
|
|
123
225
|
}
|
|
124
226
|
if (!accepted) {
|
|
125
227
|
try {
|
|
126
|
-
preflight(statusDir, request.generation);
|
|
228
|
+
preflight(statusDir, request.generation, taskViewEffect);
|
|
127
229
|
}
|
|
128
230
|
catch (error) {
|
|
129
231
|
if (cancelPendingRequest(requestPath))
|
|
130
232
|
throw error;
|
|
131
|
-
clientError('SANDBOX_CONTROL_RESULT_UNKNOWN', 'request was claimed before broker availability was lost; inspect domain state before retrying', false, true);
|
|
233
|
+
clientError('SANDBOX_CONTROL_RESULT_UNKNOWN', 'request was claimed before broker availability was lost; inspect domain state before retrying', false, true, request.id);
|
|
132
234
|
}
|
|
133
235
|
}
|
|
134
236
|
sleep(25);
|
|
135
237
|
}
|
|
136
238
|
if (accepted) {
|
|
137
|
-
clientError('SANDBOX_CONTROL_RESULT_UNKNOWN', 'accepted request did not produce a final result; inspect domain state before retrying', false, true);
|
|
239
|
+
clientError('SANDBOX_CONTROL_RESULT_UNKNOWN', 'accepted request did not produce a final result; inspect domain state before retrying', false, true, request.id);
|
|
138
240
|
}
|
|
139
241
|
if (!cancelPendingRequest(requestPath)) {
|
|
140
|
-
clientError('SANDBOX_CONTROL_RESULT_UNKNOWN', 'request was claimed but no acceptance result was observed; inspect domain state before retrying', false, true);
|
|
242
|
+
clientError('SANDBOX_CONTROL_RESULT_UNKNOWN', 'request was claimed but no acceptance result was observed; inspect domain state before retrying', false, true, request.id);
|
|
243
|
+
}
|
|
244
|
+
clientError('SANDBOX_CONTROL_BROKER_UNAVAILABLE', `broker did not accept the request within ${params.timeoutMs ?? 30_000}ms`, true, false, request.id);
|
|
245
|
+
}
|
|
246
|
+
export function recoverSandboxControl(requestId, params = {}) {
|
|
247
|
+
if (!/^[a-f0-9-]{16,64}$/u.test(requestId)) {
|
|
248
|
+
clientError('SANDBOX_CONTROL_REQUEST_INVALID', 'request id is invalid', false, true);
|
|
249
|
+
}
|
|
250
|
+
const channelDir = params.channelDir ?? process.env.AGENT_INFRA_CONTROL_DIR ?? '/run/agent-infra/control';
|
|
251
|
+
const responsePath = path.join(channelDir, 'responses', `${requestId}.json`);
|
|
252
|
+
const deadline = Date.now() + (params.timeoutMs ?? 30_000);
|
|
253
|
+
let accepted = false;
|
|
254
|
+
let malformedResponseRaw = null;
|
|
255
|
+
let malformedResponseObservedAt = 0;
|
|
256
|
+
while (Date.now() < deadline) {
|
|
257
|
+
if (fs.existsSync(path.join(channelDir, 'responses', `${requestId}.accepted.json`)))
|
|
258
|
+
accepted = true;
|
|
259
|
+
if (fs.existsSync(responsePath)) {
|
|
260
|
+
let raw;
|
|
261
|
+
try {
|
|
262
|
+
raw = fs.readFileSync(responsePath, 'utf8');
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
if (error.code === 'ENOENT')
|
|
266
|
+
continue;
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
269
|
+
let response;
|
|
270
|
+
try {
|
|
271
|
+
// The request-specific terminal proves the broker claimed the request; preserve recovery evidence if marker cleanup won the race.
|
|
272
|
+
accepted = true;
|
|
273
|
+
response = readPublishedResponse(raw, requestId, channelDir, accepted);
|
|
274
|
+
malformedResponseRaw = null;
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
if (!(error instanceof SyntaxError))
|
|
278
|
+
throw error;
|
|
279
|
+
const now = Date.now();
|
|
280
|
+
if (malformedResponseRaw !== raw) {
|
|
281
|
+
malformedResponseRaw = raw;
|
|
282
|
+
malformedResponseObservedAt = now;
|
|
283
|
+
}
|
|
284
|
+
else if (now - malformedResponseObservedAt >= SANDBOX_CONTROL_RESPONSE_SETTLE_MS) {
|
|
285
|
+
clientError('SANDBOX_CONTROL_RESPONSE_INVALID', 'broker response remained malformed', false, accepted, requestId);
|
|
286
|
+
}
|
|
287
|
+
sleep(25);
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (response.phase === 'accepted')
|
|
291
|
+
accepted = true;
|
|
292
|
+
else
|
|
293
|
+
return response;
|
|
294
|
+
}
|
|
295
|
+
sleep(25);
|
|
141
296
|
}
|
|
142
|
-
clientError('
|
|
297
|
+
clientError('SANDBOX_CONTROL_RESULT_UNKNOWN', 'request did not produce a final result; inspect domain state before retrying', false, accepted, requestId);
|
|
143
298
|
}
|
|
144
299
|
function authority(params) {
|
|
145
300
|
const token = params.token ?? process.env.AGENT_INFRA_CONTROL_TOKEN;
|
|
@@ -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 });
|