@fitlab-ai/agent-infra 0.11.15 → 0.12.1
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/bin/cli.ts +1 -1
- package/dist/bin/cli.js +1 -1
- package/dist/bin/internal-cli.js +6 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +6 -6
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +8 -18
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +1 -1
- package/dist/lib/decide.js +2 -7
- package/dist/lib/internal/cli-route-inventory.js +3 -0
- package/dist/lib/internal/manual-validation.js +19 -33
- package/dist/lib/internal/platform-comment.js +59 -9
- package/dist/lib/internal/task-activity.js +1 -12
- package/dist/lib/internal/task-event.js +1 -12
- package/dist/lib/internal/task-ledger.js +1 -12
- package/dist/lib/internal/task-operation-registry.js +2 -1
- package/dist/lib/internal/task-qualification.js +6 -15
- package/dist/lib/internal/task-review.js +3 -16
- package/dist/lib/internal/task-short-id.js +2 -1
- package/dist/lib/internal/task-verify.js +1 -11
- package/dist/lib/internal/task-warning.js +1 -12
- package/dist/lib/internal/task-workspace.js +43 -0
- package/dist/lib/merge.js +4 -3
- package/dist/lib/platform/issue-comments.js +373 -267
- package/dist/lib/platform/issue-summary-content.js +112 -0
- package/dist/lib/platform/pr-change-report.js +175 -26
- package/dist/lib/platform/pr-summary-content.js +54 -0
- package/dist/lib/platform/pr-summary.js +321 -296
- package/dist/lib/platform/pull-requests.js +3 -15
- package/dist/lib/platform/summary-content-pipeline.js +18 -0
- package/dist/lib/pr-review/evidence-grading.js +3 -2
- package/dist/lib/process-data/index.js +5 -4
- package/dist/lib/process-data/sources.js +6 -0
- package/dist/lib/run/index.js +3 -2
- package/dist/lib/sandbox/commands/create.js +5 -1
- package/dist/lib/sandbox/commands/enter.js +1 -1
- package/dist/lib/sandbox/commands/list-running.js +2 -1
- package/dist/lib/sandbox/control/client.js +8 -13
- package/dist/lib/sandbox/control/completed-reentry.js +2 -1
- package/dist/lib/sandbox/control/task-view.js +4 -2
- package/dist/lib/sandbox/mounts.js +4 -4
- package/dist/lib/sandbox/recovery.js +26 -16
- package/dist/lib/sandbox/removal.js +62 -12
- package/dist/lib/sandbox/task-resolver.js +9 -6
- package/dist/lib/sandbox/workspace-identity.js +6 -5
- package/dist/lib/sandbox/workspace-view.js +29 -22
- package/dist/lib/task/activity-intent.js +2 -12
- package/dist/lib/task/artifact-lifecycle.js +17 -11
- package/dist/lib/task/artifact-operations.js +41 -49
- package/dist/lib/task/capabilities.js +2 -2
- package/dist/lib/task/commands/ls.js +4 -3
- package/dist/lib/task/commands/status.js +1 -1
- package/dist/lib/task/commit-operation.js +6 -6
- package/dist/lib/task/control-authority.js +32 -32
- package/dist/lib/task/create-service.js +2 -4
- package/dist/lib/task/create.js +12 -65
- package/dist/lib/task/delegation-receipts.js +1 -1
- package/dist/lib/task/delivery.js +2 -8
- package/dist/lib/task/events.js +5 -31
- package/dist/lib/task/finalization.js +33 -29
- package/dist/lib/task/lifecycle.js +9 -48
- package/dist/lib/task/local-artifact-finalization.js +1 -2
- package/dist/lib/task/orchestration.js +24 -57
- package/dist/lib/task/platform-operation-recovery.js +87 -88
- package/dist/lib/task/resolve-ref.js +17 -12
- package/dist/lib/task/review-finalization.js +2 -35
- package/dist/lib/task/review-identity.js +3 -1
- package/dist/lib/task/short-id.js +10 -8
- package/dist/lib/task/verification-engine.js +19 -58
- package/dist/lib/task/workspace-root.js +59 -0
- package/dist/lib/task/workspace-snapshot.js +4 -3
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +6 -6
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +8 -34
- package/lib/agent-clients/adapters/codex-orchestration.ts +1 -1
- package/lib/decide.ts +2 -7
- package/lib/internal/cli-route-inventory.ts +2 -0
- package/lib/internal/manual-validation.ts +20 -37
- package/lib/internal/platform-comment.ts +49 -6
- package/lib/internal/task-activity.ts +1 -10
- package/lib/internal/task-event.ts +1 -10
- package/lib/internal/task-ledger.ts +1 -10
- package/lib/internal/task-operation-registry.ts +2 -1
- package/lib/internal/task-qualification.ts +5 -11
- package/lib/internal/task-review.ts +3 -14
- package/lib/internal/task-short-id.ts +2 -1
- package/lib/internal/task-verify.ts +1 -9
- package/lib/internal/task-warning.ts +1 -10
- package/lib/internal/task-workspace.ts +39 -0
- package/lib/merge.ts +4 -3
- package/lib/platform/issue-comments.ts +478 -280
- package/lib/platform/issue-summary-content.ts +132 -0
- package/lib/platform/pr-change-report.ts +165 -20
- package/lib/platform/pr-summary-content.ts +60 -0
- package/lib/platform/pr-summary.ts +367 -269
- package/lib/platform/pull-requests.ts +3 -24
- package/lib/platform/summary-content-pipeline.ts +23 -0
- package/lib/pr-review/evidence-grading.ts +3 -2
- package/lib/process-data/index.ts +4 -3
- package/lib/process-data/sources.ts +6 -0
- package/lib/run/index.ts +3 -2
- package/lib/sandbox/commands/create.ts +5 -1
- package/lib/sandbox/commands/enter.ts +1 -1
- package/lib/sandbox/commands/list-running.ts +2 -1
- package/lib/sandbox/control/client.ts +7 -12
- package/lib/sandbox/control/completed-reentry.ts +2 -1
- package/lib/sandbox/control/task-view.ts +4 -2
- package/lib/sandbox/mounts.ts +4 -4
- package/lib/sandbox/recovery.ts +26 -18
- package/lib/sandbox/removal.ts +60 -27
- package/lib/sandbox/task-resolver.ts +9 -6
- package/lib/sandbox/workspace-identity.ts +6 -5
- package/lib/sandbox/workspace-view.ts +28 -20
- package/lib/task/activity-intent.ts +3 -17
- package/lib/task/artifact-lifecycle.ts +39 -11
- package/lib/task/artifact-operations.ts +28 -35
- package/lib/task/capabilities.ts +2 -2
- package/lib/task/commands/ls.ts +4 -3
- package/lib/task/commands/status.ts +1 -1
- package/lib/task/commit-operation.ts +5 -6
- package/lib/task/control-authority.ts +29 -35
- package/lib/task/create-service.ts +2 -4
- package/lib/task/create.ts +10 -51
- package/lib/task/delegation-receipts.ts +1 -1
- package/lib/task/delivery.ts +2 -10
- package/lib/task/events.ts +5 -32
- package/lib/task/finalization.ts +27 -30
- package/lib/task/lifecycle.ts +9 -50
- package/lib/task/local-artifact-finalization.ts +1 -4
- package/lib/task/orchestration.ts +31 -80
- package/lib/task/platform-operation-recovery.ts +70 -82
- package/lib/task/resolve-ref.ts +18 -12
- package/lib/task/review-finalization.ts +2 -52
- package/lib/task/review-identity.ts +3 -1
- package/lib/task/short-id.ts +10 -8
- package/lib/task/verification-engine.ts +20 -62
- package/lib/task/workspace-root.ts +78 -0
- package/lib/task/workspace-snapshot.ts +4 -3
- package/package.json +1 -1
- package/templates/.agents/QUICKSTART.en.md +19 -8
- package/templates/.agents/QUICKSTART.zh-CN.md +19 -8
- package/templates/.agents/README.en.md +10 -15
- package/templates/.agents/README.zh-CN.md +9 -13
- package/templates/.agents/rules/issue-sync.en.md +1 -1
- package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
- package/templates/.agents/rules/lifecycle-orchestration.en.md +1 -1
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +1 -1
- package/templates/.agents/rules/next-step-output.en.md +2 -2
- package/templates/.agents/rules/next-step-output.zh-CN.md +2 -2
- package/templates/.agents/rules/pr-sync.en.md +5 -3
- package/templates/.agents/rules/pr-sync.zh-CN.md +7 -10
- package/templates/.agents/rules/release-commands.en.md +3 -0
- package/templates/.agents/rules/release-commands.zh-CN.md +3 -0
- package/templates/.agents/rules/task-management.en.md +0 -2
- package/templates/.agents/rules/task-management.zh-CN.md +0 -2
- package/templates/.agents/rules/task-short-id.en.md +2 -2
- package/templates/.agents/rules/task-short-id.zh-CN.md +2 -2
- package/templates/.agents/scripts/task-short-id.js +2 -8
- package/templates/.agents/skills/analyze-task/SKILL.en.md +6 -6
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/analyze-task/config/verify.en.json +0 -1
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/archive-tasks/SKILL.en.md +5 -5
- package/templates/.agents/skills/archive-tasks/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/archive-tasks/scripts/archive-tasks.sh +10 -2
- package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/block-task/config/verify.json +0 -1
- package/templates/.agents/skills/cancel-task/SKILL.en.md +7 -7
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +7 -7
- package/templates/.agents/skills/cancel-task/config/verify.json +0 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/code-task/config/verify.en.json +0 -1
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/code-task/reference/output-template.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/SKILL.en.md +1 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/config/verify.json +0 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +2 -2
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +2 -2
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +2 -2
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +0 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +3 -3
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +3 -3
- package/templates/.agents/skills/complete-task/SKILL.en.md +15 -30
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +17 -32
- package/templates/.agents/skills/complete-task/config/verify.en.json +0 -1
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/create-pr/SKILL.en.md +3 -3
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/create-pr/config/verify.json +0 -1
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +10 -3
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +10 -3
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +3 -3
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +3 -3
- package/templates/.agents/skills/create-release-note/SKILL.en.md +2 -2
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/create-task/SKILL.en.md +4 -22
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +4 -22
- package/templates/.agents/skills/create-task/config/verify.json +0 -1
- 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-codescan/config/verify.json +0 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +3 -3
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/import-dependabot/config/verify.json +0 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/import-issue/config/verify.json +0 -1
- package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/plan-task/config/verify.en.json +0 -1
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/restore-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/restore-task/config/verify.json +0 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-analysis/config/verify.en.json +0 -1
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +5 -5
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +5 -5
- package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +4 -4
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +4 -4
- package/templates/.agents/skills/review-plan/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-plan/config/verify.en.json +0 -1
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +5 -5
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +5 -5
- package/templates/.agents/skills/review-pr/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-pr/config/verify.en.json +0 -1
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +1 -1
- package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +1 -1
- package/templates/.agents/skills/run-manual-validation/config/verify.en.json +0 -1
- package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +0 -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 +0 -3
- package/templates/.agents/skills/test/SKILL.zh-CN.md +0 -3
- package/templates/.agents/skills/test-integration/SKILL.en.md +0 -3
- package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +0 -3
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +13 -6
- package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +0 -3
- package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +0 -3
- package/templates/.agents/skills/watch-pr/SKILL.en.md +4 -4
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/watch-pr/config/verify.json +0 -1
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +3 -3
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +3 -3
- package/templates/.agents/templates/handoff.en.md +1 -1
- package/templates/.agents/templates/handoff.zh-CN.md +1 -1
- package/templates/.agents/workflows/bug-fix.en.yaml +1 -1
- package/templates/.agents/workflows/feature-development.en.yaml +1 -1
- package/templates/.agents/workflows/refactoring.en.yaml +1 -1
- package/dist/lib/task/task-execution-lock.js +0 -250
- package/lib/task/task-execution-lock.ts +0 -320
|
@@ -8,7 +8,7 @@ Read this file and `.agents/rules/next-step-output.md` before presenting the fin
|
|
|
8
8
|
|------|---------|---------|
|
|
9
9
|
| A Local review complete | the local review round closed and verification passed; formal publication succeeded or has a durable pending record | conclusion, mode, reviewed head SHA, actual publication status, Review URL or recovery action, receipt, next step |
|
|
10
10
|
| B Blocked, requires linking | `resolve-host` returned none or ambiguous | linking guidance (create/link an Issue and task); do not auto-create an Issue; or explicitly choose the one-shot review |
|
|
11
|
-
| C One-shot review | the user explicitly chose a "one-shot review" | non-recoverable notice, artifact directory
|
|
11
|
+
| C One-shot review | the user explicitly chose a "one-shot review" | non-recoverable notice, artifact directory `<task-workspace>/reviews/{pr-number}/`, Review URL or publication failure |
|
|
12
12
|
|
|
13
13
|
## Presentation Requirements
|
|
14
14
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|------|----------|----------|
|
|
9
9
|
| A 本地审查完成 | 本地审查轮次闭合且校验通过;正式 Review 已发布或有持久化待恢复记录 | 结论、模式、被审 head SHA、实际发布状态、Review URL 或恢复动作、receipt、下一步 |
|
|
10
10
|
| B 阻塞要求关联 | `resolve-host` 返回 none 或 ambiguous | 关联指引(创建/关联 Issue 与 task),不自动创建 Issue;或显式选择一次性检视 |
|
|
11
|
-
| C 一次性检视 | 用户显式选择「仅一次性检视」 | 不可恢复提示、产物目录
|
|
11
|
+
| C 一次性检视 | 用户显式选择「仅一次性检视」 | 不可恢复提示、产物目录 `<task-workspace>/reviews/{pr-number}/`、Review URL 或发布失败 |
|
|
12
12
|
|
|
13
13
|
## 呈现要求
|
|
14
14
|
|
|
@@ -19,7 +19,7 @@ The orchestrator delegates only and never executes a stage skill itself. First r
|
|
|
19
19
|
4. Run `task-orchestration {task-id} begin-or-resume --client {client}` with the complete explicit policy. With no explicit policy, core reads that client's configured policy; existing runs use persisted policy. Disk state outside the complete current structure fails closed without rewriting; finish or clear active runs before upgrading. Stop on paused/completed results.
|
|
20
20
|
5. Run `route`. On `completed`, run `agent-infra-internal task-verify {task-id} run-task.completed --format text`, present its summary per `.agents/rules/validation-output.md` while retaining necessary diagnostics, and stop. Only a `running` result with non-null `next` supplies action, role, round, artifact, requested model, and requested effort.
|
|
21
21
|
6. Call `prepare --client {client} --requested-model {requestedModel} --requested-reasoning-effort {requestedReasoningEffort}` with route's exact policy. The client adapter runs host preflight. Report actual task, policy, or host failures.
|
|
22
|
-
7. After prepare, forward the optional `adapterContext` unchanged to `agent-infra-internal agent-client launch-carrier --client {client} --adapter-context {adapterContext} --stage {stage} --round {round} --role {role} --format json`. The shared skill must not parse, rewrite, or validate this opaque value. The controlled entry point calls the current Agent Client adapter's `createLaunchCarrier` and returns a carrier for native spawn. Stop dispatch with the structured error if carrier support is unavailable or conversion fails. Then run `task-orchestration <task-ref> dispatch` with route's exact model/effort, passing the short task ref, skill, `--orchestrated`, stage/round/artifact/role, and the returned carrier unchanged to native spawn. The child calls `await-activation --stage ... --round ... --artifact ... --role ...` to associate its actual identity before executing. Code-task creates the local checkpoint; do not delegate a separate commit stage or push.
|
|
22
|
+
7. After prepare, forward the optional `adapterContext` unchanged to `agent-infra-internal agent-client launch-carrier --client {client} --adapter-context {adapterContext} --stage {stage} --round {round} --role {role} --format json`. The shared skill must not parse, rewrite, or validate this opaque value. The controlled entry point calls the current Agent Client adapter's `createLaunchCarrier` and returns a carrier for native spawn. Stop dispatch with the structured error if carrier support is unavailable or conversion fails. Then run `task-orchestration <task-ref> dispatch` with route's exact model/effort, passing the short task ref, skill, `--orchestrated`, stage/round/artifact/role, and the returned carrier unchanged to native spawn. The child calls `await-activation --stage ... --round ... --artifact ... --role ...` to associate its actual identity before executing. Code-task creates the local checkpoint; do not delegate a separate commit stage or push. Execute task stages sequentially; state updates retain atomic writes and identity/state validation.
|
|
23
23
|
8. Record actual start and terminal results through the current host's native lifecycle events and result interfaces. A timed-out wait does not imply success. Pause on actual identity, transport, or terminal failures. After the stage and child finish, call `advance`; repeat step 3 only while running.
|
|
24
24
|
9. Create a fresh child each round and never reuse a reviewer. Record actual model/effort and host fallback reasons. Validate current identity, artifacts, ledger, and execution results. User rulings override derived historical plan requirements. Do not introduce child discovery, orphan recovery, or a dedicated recovery protocol.
|
|
25
25
|
10. On pause or completion, run the matching typed verification and report the structured endpoint.
|
|
@@ -19,7 +19,7 @@ description: >
|
|
|
19
19
|
4. 调用 `agent-infra-internal task-orchestration {task-id} begin-or-resume --client {client}` 并转发完整显式策略。完全没有显式策略时由核心读取当前 client 的 `agentClients[].orchestration`;existing run 使用持久化策略。磁盘状态不符合当前完整结构时核心失败关闭且不改写;升级前必须完成或清空 active run。仅当核心返回 `ORCHESTRATION_MODEL_POLICY_REQUIRED` 时,先用 `agent-client model-selection` 展示 complete/partial/interactive-only 来源,再一次收集完整策略;未回答则不创建 run。若为 paused/completed,按结构化结果停止。
|
|
20
20
|
5. 调用 `route` 并读取结构化结果。若返回 `completed`,立即运行 `agent-infra-internal task-verify {task-id} run-task.completed --format text` 并停止;按 `.agents/rules/validation-output.md` 展示摘要并保留必要诊断。仅当返回 `running` 且 `next` 非空时读取唯一 action、role、round、artifact、`requestedModel` 和 `requestedReasoningEffort`,不得自行推断。
|
|
21
21
|
6. 调用 `prepare --client {client} --requested-model {requestedModel} --requested-reasoning-effort {requestedReasoningEffort}`,使用 route 返回的精确策略。客户端适配器执行宿主 preflight;任务身份、策略或宿主检查失败时记录实际诊断。
|
|
22
|
-
7. prepare 成功后,原样转发返回的可选 `adapterContext`,调用 `agent-infra-internal agent-client launch-carrier --client {client} --adapter-context {adapterContext} --stage {stage} --round {round} --role {role} --format json`。共享技能不解析、重写或验证该不透明值;受控入口调用当前 Agent Client adapter 的 `createLaunchCarrier`,并返回可直接交给 native spawn 的 carrier。缺少 carrier 能力或转换失败时按结构化错误停止派发。随后执行 `task-orchestration <task-ref> dispatch`,显式指定 route 返回的 model/effort;传递短任务引用、skill 名、`--orchestrated` 与 stage/round/artifact/role,并把返回的 carrier 原样交给 native spawn。child 调用 `await-activation --stage ... --round ... --artifact ... --role ...`,确认当前阶段与实际 child 关联后执行。代码阶段通过 code-task 创建本地 checkpoint;禁止单独委派 commit
|
|
22
|
+
7. prepare 成功后,原样转发返回的可选 `adapterContext`,调用 `agent-infra-internal agent-client launch-carrier --client {client} --adapter-context {adapterContext} --stage {stage} --round {round} --role {role} --format json`。共享技能不解析、重写或验证该不透明值;受控入口调用当前 Agent Client adapter 的 `createLaunchCarrier`,并返回可直接交给 native spawn 的 carrier。缺少 carrier 能力或转换失败时按结构化错误停止派发。随后执行 `task-orchestration <task-ref> dispatch`,显式指定 route 返回的 model/effort;传递短任务引用、skill 名、`--orchestrated` 与 stage/round/artifact/role,并把返回的 carrier 原样交给 native spawn。child 调用 `await-activation --stage ... --round ... --artifact ... --role ...`,确认当前阶段与实际 child 关联后执行。代码阶段通过 code-task 创建本地 checkpoint;禁止单独委派 commit 阶段或推送。任务阶段按序执行,状态更新保留原子写入与身份、状态校验。
|
|
23
23
|
8. 通过当前宿主的原生生命周期事件和结果接口记录实际启动及终态。timed-out wait 不推断成功;身份、传输或异常终态失败如实暂停。阶段结果和 child 完成后调用 `advance`;只有 `running` 才重复步骤 3。
|
|
24
24
|
9. 每轮创建新 child;禁止 follow-up 复用 reviewer。如实记录 actual model/effort 及宿主降级理由。检查当前身份、产物、账本与实际执行结果;用户裁决优先于历史方案派生要求。不得新增 child discovery、孤立 child 恢复或专用恢复协议。
|
|
25
25
|
10. 完成或暂停后运行对应 typed verification,并把结构化 run 摘要、暂停原因、commit 终点或 clean completion evidence 告知用户。
|
|
@@ -120,6 +120,3 @@ Populate `{next-step-commands}` for this scenario by running `agent-infra-intern
|
|
|
120
120
|
Next step - commit changes:
|
|
121
121
|
{next-step-commands}
|
|
122
122
|
```
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
For an in-scope, diagnosable failure, inspect the error evidence, identify the cause, fix it, and retry with the same verifier; do not stop or ask merely because an ordinary attempt failed. Preserve a blocked state for user data/template conflicts, design choices beyond approved scope, required human validation/authorization, or unsafe recovery, and continue independent work.
|
|
@@ -67,6 +67,3 @@ Next step - commit changes:
|
|
|
67
67
|
2. **Environment**: Integration tests may require external services (databases, APIs, etc.)
|
|
68
68
|
3. **Timeouts**: Integration tests typically take longer; be patient
|
|
69
69
|
4. **Cleanup**: Ensure test environment is cleaned up after tests complete
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
For an in-scope, diagnosable failure, inspect the error evidence, identify the cause, fix it, and retry with the same verifier; do not stop or ask merely because an ordinary attempt failed. Preserve a blocked state for user data/template conflicts, design choices beyond approved scope, required human validation/authorization, or unsafe recovery, and continue independent work.
|
|
@@ -994,19 +994,26 @@ function entryVariantRels(entry, allSet, platform) {
|
|
|
994
994
|
return rels;
|
|
995
995
|
}
|
|
996
996
|
|
|
997
|
-
function ensureRuntimeWorkspace(projectRoot) {
|
|
997
|
+
function ensureRuntimeWorkspace(projectRoot, project) {
|
|
998
|
+
if (typeof project !== 'string' || !project || project === '.' || project === '..' || /[\\/\u0000-\u001f\u007f]/u.test(project)) {
|
|
999
|
+
throw new Error('Runtime task workspace requires a valid project key in .agents/.airc.json');
|
|
1000
|
+
}
|
|
1001
|
+
const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
|
|
1002
|
+
if (!path.isAbsolute(home)) throw new Error('Runtime task workspace requires an absolute HOME');
|
|
1003
|
+
const workspaceRoot = path.join(home, '.agent-infra', 'task-workspaces', project);
|
|
998
1004
|
const directories = [
|
|
999
|
-
path.join(
|
|
1000
|
-
path.join(
|
|
1005
|
+
path.join(home, '.agent-infra'),
|
|
1006
|
+
path.join(home, '.agent-infra', 'task-workspaces'),
|
|
1007
|
+
workspaceRoot,
|
|
1001
1008
|
...['active', 'blocked', 'completed', 'archive'].map((state) =>
|
|
1002
|
-
path.join(
|
|
1009
|
+
path.join(workspaceRoot, state)
|
|
1003
1010
|
)
|
|
1004
1011
|
];
|
|
1005
1012
|
for (const directory of directories) {
|
|
1006
1013
|
if (fs.existsSync(directory)) {
|
|
1007
1014
|
const stat = fs.lstatSync(directory);
|
|
1008
1015
|
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
1009
|
-
throw new Error(`Runtime workspace path must be a real directory: ${directory}`);
|
|
1016
|
+
throw new Error(`Runtime task workspace path must be a real directory: ${directory}`);
|
|
1010
1017
|
}
|
|
1011
1018
|
continue;
|
|
1012
1019
|
}
|
|
@@ -1024,7 +1031,7 @@ function syncTemplates(projectRoot, templateRootOverride) {
|
|
|
1024
1031
|
|
|
1025
1032
|
const originalConfigText = fs.readFileSync(cfgPath, 'utf8');
|
|
1026
1033
|
const cfg = JSON.parse(originalConfigText);
|
|
1027
|
-
ensureRuntimeWorkspace(projectRoot);
|
|
1034
|
+
ensureRuntimeWorkspace(projectRoot, cfg.project);
|
|
1028
1035
|
const configPathRel = norm(path.relative(projectRoot, cfgPath));
|
|
1029
1036
|
let templateRoot = templateRootOverride;
|
|
1030
1037
|
if (!templateRoot) {
|
|
@@ -85,6 +85,3 @@ Next step - commit changes:
|
|
|
85
85
|
- Package not found: Prompt "Package {name} not found in dependency files"
|
|
86
86
|
- Build failure: Output errors and suggest checking for breaking changes
|
|
87
87
|
- Test failure: Diagnose and fix recoverable in-scope issues, then rerun the same verifier; report migration-guide risks when relevant
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
For an in-scope, diagnosable failure, inspect the error evidence, identify the cause, fix it, and retry with the same verifier; do not stop or ask merely because an ordinary attempt failed. Preserve a blocked state for user data/template conflicts, design choices beyond approved scope, required human validation/authorization, or unsafe recovery, and continue independent work.
|
|
@@ -85,6 +85,3 @@ description: >
|
|
|
85
85
|
- 包未找到:提示 "Package {name} not found in dependency files"
|
|
86
86
|
- 构建失败:输出错误并建议检查破坏性变更
|
|
87
87
|
- 测试失败:先诊断并修复任务范围内可恢复的问题,再按同一验证器复测;必要时记录迁移指南相关风险
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
遇到任务范围内且可诊断的失败,先读取错误证据、定位根因、修复并按同一验证器重试;不要仅因一次普通失败就停止或提问。若涉及用户数据/模板冲突、超出批准范围的设计选择、必要人工验证/授权或无法安全恢复,则保留阻塞事实并继续独立工作。
|
|
@@ -40,7 +40,7 @@ After prerequisites pass and before this round's first artifact action, append a
|
|
|
40
40
|
Resolve the target PR number `{pr#}` and an optional `{task-id}` via these deterministic branches:
|
|
41
41
|
|
|
42
42
|
- Scenario A (argument omitted): reverse-lookup the active task from the current branch, then read its verified `pr_delivery_fact.identity.number`.
|
|
43
|
-
- Scenario B (omitted task ref or `--task/-t`, **task-anchored primary path**): resolve the full `{task-id}` via "Task Context Resolution" and read
|
|
43
|
+
- Scenario B (omitted task ref or `--task/-t`, **task-anchored primary path**): resolve the full `{task-id}` via "Task Context Resolution" and read `<task-workspace>/active/{task-id}/task.md` for verified `pr_delivery_fact.identity.number` as `{pr#}`; if the fact is unbound, follow "Error Handling" to prompt running `create-pr` first, then stop.
|
|
44
44
|
- Scenario C (`--pr <number>` or a PR URL): use that PR number directly as `{pr#}`; then determine `{task-id}` via "Reverse-lookup task".
|
|
45
45
|
- Reverse-lookup task (scenarios A / C): use task context/query capabilities to find the unique active task bound to `{pr#}`. If none exists, stop and request binding first; the typed checks intent does not create a second taskless state machine.
|
|
46
46
|
|
|
@@ -53,7 +53,7 @@ Initialize `repairCommits=[]` and `rebaseAttempts=0`. Before overwriting the cur
|
|
|
53
53
|
```bash
|
|
54
54
|
node --experimental-strip-types --input-type=module -e '
|
|
55
55
|
import { readPrChangeReport } from "./lib/platform/pr-change-report.ts";
|
|
56
|
-
const report = readPrChangeReport(
|
|
56
|
+
const report = readPrChangeReport(`<task-workspace>/active/${process.argv[1]}/pr-change-report.json`);
|
|
57
57
|
const previous = report.ok
|
|
58
58
|
? { repository: report.value.identity.repository, resource: report.value.identity.resource, head: report.value.identity.head.sha }
|
|
59
59
|
: { status: "unavailable" };
|
|
@@ -61,7 +61,7 @@ process.stdout.write(`${JSON.stringify(previous)}\n`);
|
|
|
61
61
|
' {task-id}
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
Then run `platform-pr summary-context` and compare the retained repository/resource identity with the authoritative snapshot; discard a mismatch and mark the increment unconfirmed. Rebuild the task-bound `pr-change-report.json` for the authoritative PR head using the shared PR change-report contract, and refresh the single summary with
|
|
64
|
+
Then run `platform-pr summary-context` and compare the retained repository/resource identity with the authoritative snapshot; discard a mismatch and mark the increment unconfirmed. Rebuild the task-bound `pr-change-report.json` for the authoritative PR head using the shared PR change-report contract, and refresh the single summary with structured summary JSON via `summary-sync --change-report-file ... --result no_op --strict`. Preserve the actual test, review, and manual validation states; do not depend on later events or final verification. Complete-PR statistics keep the current base/head/merge-base/patch and existing totals. Only when the prior report is valid, the PR identity matches, and the heads differ, describe the separate head-to-head tree diff using `git diff --find-renames --numstat {previous-head} {current-head}`, `--name-status`, and `--summary`. Do not substitute a merge-base diff for this range or add increment totals to the full PR. If no valid prior head exists, state that it is unconfirmed; do not infer from complete-PR statistics or fill in zeroes. Matching heads mean there was no new head transition.
|
|
65
65
|
|
|
66
66
|
`--strict` preserves report or summary refresh failures as `failed/blocked` instead of treating warnings as success. A report or summary refresh failure must not enter the ready/complete exit; use step 4. After a successful refresh, consume `nextAction` from the structured `summary-sync` result: `review-code` exits readiness/self-heal and follows the code-review branch in step 7; only `watch-pr` continues to `agent-infra-internal platform-checks watch {task-id} --interval-seconds 30 --deadline-seconds 1800`. Missing or invalid `nextAction` follows the refresh-failure exit; do not infer `watch-pr`. Route readiness only by `readiness.state`: `ready` to step 7, `conflicting|checks-failed` to step 3, and `pending|timed-out|cancelled` to step 4.
|
|
67
67
|
|
|
@@ -85,7 +85,7 @@ Get the current time:
|
|
|
85
85
|
date "+%Y-%m-%d %H:%M:%S%z" | sed 's/\([+-][0-9][0-9]\)\([0-9][0-9]\)$/\1:\2/'
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
Update
|
|
88
|
+
Update `<task-workspace>/active/{task-id}/task.md`:
|
|
89
89
|
- `assigned_to`: {current agent}
|
|
90
90
|
- `updated_at`: {current time}
|
|
91
91
|
- `agent_infra_version`: per `.agents/rules/version-stamp.md`
|
|
@@ -40,7 +40,7 @@ description: >
|
|
|
40
40
|
按以下确定性分支解析出目标 PR 号 `{pr#}` 与可选 `{task-id}`:
|
|
41
41
|
|
|
42
42
|
- 场景 A(省略入参):从当前分支反查 active task;定位后读取其 verified `pr_delivery_fact.identity.number`。
|
|
43
|
-
- 场景 B(省略 task ref 或 `--task/-t`,**任务锚定主路径**):按「任务上下文解析」取得完整 `{task-id}`。读
|
|
43
|
+
- 场景 B(省略 task ref 或 `--task/-t`,**任务锚定主路径**):按「任务上下文解析」取得完整 `{task-id}`。读 `<task-workspace>/active/{task-id}/task.md` 取 verified `pr_delivery_fact.identity.number` 作为 `{pr#}`;fact 未绑定时按「错误处理」提示先 `create-pr`,停止。
|
|
44
44
|
- 场景 C(`--pr <number>` 或 PR URL):直接取该 PR 号为 `{pr#}`;随后按「反查任务」确定 `{task-id}`。
|
|
45
45
|
- 反查任务(场景 A / C):通过任务上下文/任务查询取得与 `{pr#}` 唯一绑定的 active task。未命中时停止并提示先绑定 PR;typed checks intent 不建立第二套无任务状态机。
|
|
46
46
|
|
|
@@ -53,7 +53,7 @@ description: >
|
|
|
53
53
|
```bash
|
|
54
54
|
node --experimental-strip-types --input-type=module -e '
|
|
55
55
|
import { readPrChangeReport } from "./lib/platform/pr-change-report.ts";
|
|
56
|
-
const report = readPrChangeReport(
|
|
56
|
+
const report = readPrChangeReport(`<task-workspace>/active/${process.argv[1]}/pr-change-report.json`);
|
|
57
57
|
const previous = report.ok
|
|
58
58
|
? { repository: report.value.identity.repository, resource: report.value.identity.resource, head: report.value.identity.head.sha }
|
|
59
59
|
: { status: "unavailable" };
|
|
@@ -61,7 +61,7 @@ process.stdout.write(`${JSON.stringify(previous)}\n`);
|
|
|
61
61
|
' {task-id}
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
随后调用 `platform-pr summary-context`,比较暂存的 repository/resource identity 与当前权威 snapshot;不匹配时丢弃旧 head 并标记增量未确认。按共享 PR change-report contract 用当前权威 PR head 重建任务绑定的 `pr-change-report.json
|
|
64
|
+
随后调用 `platform-pr summary-context`,比较暂存的 repository/resource identity 与当前权威 snapshot;不匹配时丢弃旧 head 并标记增量未确认。按共享 PR change-report contract 用当前权威 PR head 重建任务绑定的 `pr-change-report.json`,用结构化摘要 JSON 调用 `summary-sync --change-report-file ... --result no_op --strict` 刷新同一条摘要;保留测试、Review 和人工校验的真实状态,不能依赖后续事件或最终验证。完整 PR 仍使用当前 base/head/merge-base/patch 与现有 totals。只有在上一报告有效、PR identity 相同且两个 head 不同的情况下,才用 `git diff --find-renames --numstat {previous-head} {current-head}`、`--name-status`、`--summary` 描述独立的 head→head 树差异;不使用 merge-base 替代该范围,不把增量 totals 加入完整 PR。无有效上一 head 时写明未确认,不从完整 PR 推算或填零;head 相同只说明没有新的 head 转换。
|
|
65
65
|
|
|
66
66
|
`--strict` 将报告或摘要刷新失败保留为 `failed/blocked`,不得把 warning 当作成功;刷新失败时不得进入 ready/complete 出口,按步骤 4 记录阻塞。刷新成功后,消费 `summary-sync` 结构化结果的 `nextAction`:`review-code` 立即结束 readiness/self-heal 路径,按步骤 7 的代码审查分支退出;`watch-pr` 才继续调用 `agent-infra-internal platform-checks watch {task-id} --interval-seconds 30 --deadline-seconds 1800`。缺失或 invalid `nextAction` 按刷新失败处理,不推断为 `watch-pr`。readiness 只按结构化 `readiness.state` 分流:`ready` 进入步骤 7,`conflicting` 或 `checks-failed` 进入步骤 3,`pending|timed-out|cancelled` 进入步骤 4。
|
|
67
67
|
|
|
@@ -85,7 +85,7 @@ process.stdout.write(`${JSON.stringify(previous)}\n`);
|
|
|
85
85
|
date "+%Y-%m-%d %H:%M:%S%z" | sed 's/\([+-][0-9][0-9]\)\([0-9][0-9]\)$/\1:\2/'
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
更新
|
|
88
|
+
更新 `<task-workspace>/active/{task-id}/task.md`:
|
|
89
89
|
- `assigned_to`:{当前代理}
|
|
90
90
|
- `updated_at`:{当前时间}
|
|
91
91
|
- `agent_infra_version`:按 `.agents/rules/version-stamp.md` 取值
|
|
@@ -13,11 +13,11 @@ After the watch command, route by structured `readiness.state`:
|
|
|
13
13
|
|
|
14
14
|
## Summary Refresh Boundary
|
|
15
15
|
|
|
16
|
-
Before readiness in every round, and after an external push, self-heal commit, or successful rebase changes the PR head, rerun `summary-context` → mechanical report and six-check precheck → `platform-pr change-report` → `summary-sync --change-report-file ... --result no_op --strict
|
|
16
|
+
Before readiness in every round, and after an external push, self-heal commit, or successful rebase changes the PR head, rerun `summary-context` → mechanical report and six-check precheck → `platform-pr change-report` → update the full PR summary JSON per `.agents/rules/pr-sync.md` → `summary-sync --change-report-file ... --result no_op --strict`. `--strict` preserves report or summary refresh failures as `failed/blocked`. The core revalidates the sidecar and reads back the remote body; missing, stale, invalid, incomplete, or raced publication must not continue to a ready/complete route.
|
|
17
17
|
|
|
18
|
-
When rebuilding the precheck, each of the six `rationale` fields must state
|
|
18
|
+
When rebuilding the precheck, each of the six `rationale` fields must state its actual finding and include at least one item of evidence with a path, line range, and concise `detail`; state compatibility, legacy-path, redundancy, and scope findings separately without generic boilerplate. Use the deployed skill's language for rationales and evidence; Chinese deployments must use Chinese.
|
|
19
19
|
|
|
20
|
-
Use the
|
|
20
|
+
Use the candidate content contract in `.agents/skills/create-pr/reference/change-report.md` for functional grouping, per-group fields, unique line attribution, and `needs-review` criteria. Rebuild groups from the current task goal and patch on every refresh; do not reuse prior-head explanations as evidence for the current increment. Reconcile complete-PR statistics separately from the previous valid head → current head increment; explicitly mark the increment unconfirmed when no previous head can be verified. If any group lacks goal alignment, behavior added/removed, necessity, line-count reconciliation, test coverage/cost, or locatable evidence, mark `target-alignment` or `change-composition` as `needs-review` and identify the gap. Reuse the existing `nextAction=review-code` route; structural completeness or green CI must not continue to `watch-pr`.
|
|
21
21
|
|
|
22
22
|
Keep complete-PR scope bound to the current authoritative base/head/merge-base/patch and its full statistics. Report the increment separately as previous valid report head → current head. Before overwriting the prior sidecar, validate it with `readPrChangeReport`; use its `identity.head.sha` only when its repository/resource identity matches the current PR. Compare the two head trees directly and state both SHAs. Do not substitute a merge-base diff for these endpoints or add increment totals to complete-PR totals. If no prior report exists, it is invalid, or its identity differs, mark the previous head unconfirmed; do not infer values from the full PR or fill in zeroes. Identical SHAs mean the head did not change. After a rebase, compare the old and new head trees. An invalid sidecar makes only the increment unconfirmed; the existing full-PR report flow continues.
|
|
23
23
|
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
|
|
14
14
|
## 摘要刷新边界
|
|
15
15
|
|
|
16
|
-
每轮 readiness 之前,以及外部 push、自愈 commit 或 rebase 成功改变 PR head 之后,必须重新执行 `summary-context` → 机械报告与六项 precheck → `platform-pr change-report` →
|
|
16
|
+
每轮 readiness 之前,以及外部 push、自愈 commit 或 rebase 成功改变 PR head 之后,必须重新执行 `summary-context` → 机械报告与六项 precheck → `platform-pr change-report` → 按 `.agents/rules/pr-sync.md` 更新完整 PR 摘要 JSON 并调用 `summary-sync --change-report-file ... --result no_op --strict`。`--strict` 将报告或摘要刷新失败保留为 `failed/blocked`,不允许 warning 穿透到 ready/complete 路由。core 以权威 PR snapshot、任务意图 digest 和完整 patch 重新校验 sidecar,并回读远端正文;报告缺失、stale、invalid、结构不完整或发布竞态时,不得继续 ready/complete 路由,转入求助出口并登记 warning。
|
|
17
17
|
|
|
18
|
-
每轮重建 precheck
|
|
18
|
+
每轮重建 precheck 时,除执行下方功能级报告门槛外,六项 `rationale` 都必须陈述对应检查的实际结论,并至少带一条含路径、行号和简短 `detail` 的证据;兼容、旧路径、冗余和范围检查分别说明,不复用泛化套话。理由和证据遵循当前部署语言,中文技能必须使用中文。
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
功能分组、逐组字段、行数唯一归属及 `needs-review` 条件统一遵循 `.agents/skills/create-pr/reference/change-report.md` 的 candidate 内容契约。每次刷新都重新按当前任务目标和 patch 建立功能组,不沿用上一 head 的说明代替本轮证据。完整 PR 统计与上一有效 head → 当前 head 的增量分开核算;没有可验证的上一 head 时明确标为未确认。任何功能组缺少目标对应、行为增减、必要性、行数对账、测试覆盖/成本或定位证据时,将 `target-alignment` 或 `change-composition` 标为 `needs-review` 并指出缺口。沿用现有 `nextAction=review-code` 路由;不得以结构完整或 CI 全绿继续 `watch-pr`。
|
|
21
21
|
|
|
22
22
|
完整 PR 的范围继续绑定当前权威 base/head/merge-base/patch 与完整统计。增量单独绑定上一有效报告 head → 当前 head:在覆盖旧 sidecar 前,用 `readPrChangeReport` 校验旧报告,只在 repository/resource identity 匹配当前 PR 时采用旧 `identity.head.sha`。对两个 head 做 tree-to-tree diff 并明确列出 SHA,不用 merge-base 替代端点差异,不把增量 totals 加到完整 PR totals。没有旧报告、报告无效或身份不符时标注上一 head 未确认,不从全量推算或填零。两个 SHA 相同只报告 head 未变化;rebase 后仍比较原 head 和新 head 的树差异。sidecar 无效只使增量不可确认,不改变现有 full-PR 报告流程。
|
|
23
23
|
|
|
@@ -200,4 +200,4 @@ steps:
|
|
|
200
200
|
- Task workspace
|
|
201
201
|
outputs:
|
|
202
202
|
- Pull request (only on the PR path)
|
|
203
|
-
- Completed task
|
|
203
|
+
- Completed task under `completed/{task-id}` in the host root returned by `task-workspace resolve`
|
|
@@ -200,4 +200,4 @@ steps:
|
|
|
200
200
|
- Task workspace
|
|
201
201
|
outputs:
|
|
202
202
|
- Pull request (only on the PR path)
|
|
203
|
-
- Completed task
|
|
203
|
+
- Completed task under `completed/{task-id}` in the host root returned by `task-workspace resolve`
|
|
@@ -204,4 +204,4 @@ steps:
|
|
|
204
204
|
- Task workspace
|
|
205
205
|
outputs:
|
|
206
206
|
- Pull request (only on the PR path)
|
|
207
|
-
- Completed task
|
|
207
|
+
- Completed task under `completed/{task-id}` in the host root returned by `task-workspace resolve`
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import os from 'node:os';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { createHash, randomUUID } from 'node:crypto';
|
|
5
|
-
import { getProcessStartTime, processIdentityMatches } from '../server/process-state.js';
|
|
6
|
-
class TaskExecutionLockError extends Error {
|
|
7
|
-
code;
|
|
8
|
-
detail;
|
|
9
|
-
constructor(code, message, detail) {
|
|
10
|
-
super(message);
|
|
11
|
-
this.name = 'TaskExecutionLockError';
|
|
12
|
-
this.code = code;
|
|
13
|
-
this.detail = detail;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
function errno(error) {
|
|
17
|
-
const value = error?.code;
|
|
18
|
-
return typeof value === 'string' ? value : null;
|
|
19
|
-
}
|
|
20
|
-
function mapLinkError(operation, error, key) {
|
|
21
|
-
const code = errno(error);
|
|
22
|
-
if (code === 'EEXIST')
|
|
23
|
-
return 'exists';
|
|
24
|
-
if (operation === 'quarantine' && code === 'ENOENT')
|
|
25
|
-
return 'missing';
|
|
26
|
-
const detail = { operation, errno: code, key };
|
|
27
|
-
if (['EPERM', 'EACCES', 'ENOSYS', 'ENOTSUP', 'EOPNOTSUPP', 'EXDEV'].includes(code ?? '')) {
|
|
28
|
-
return new TaskExecutionLockError('ORCHESTRATION_LOCK_UNSUPPORTED', `lifecycle lock hard-link operation '${operation}' is unsupported`, detail);
|
|
29
|
-
}
|
|
30
|
-
return new TaskExecutionLockError('ORCHESTRATION_LOCK_FAILED', `lifecycle lock hard-link operation '${operation}' failed`, detail);
|
|
31
|
-
}
|
|
32
|
-
function lockKey(repoRoot, taskId, identityScope) {
|
|
33
|
-
const canonicalRepoRoot = fs.realpathSync.native(repoRoot);
|
|
34
|
-
const identity = identityScope === undefined
|
|
35
|
-
? `${canonicalRepoRoot}\0${taskId}`
|
|
36
|
-
: `${identityScope}\0${taskId}`;
|
|
37
|
-
const key = createHash('sha256').update(identity).digest('hex');
|
|
38
|
-
return { canonicalRepoRoot, key };
|
|
39
|
-
}
|
|
40
|
-
function parseOwner(raw, key) {
|
|
41
|
-
try {
|
|
42
|
-
const value = JSON.parse(raw);
|
|
43
|
-
if (value !== null
|
|
44
|
-
&& value.version === 2
|
|
45
|
-
&& Number.isSafeInteger(value.pid)
|
|
46
|
-
&& (value.pid ?? 0) > 0
|
|
47
|
-
&& typeof value.startTime === 'number'
|
|
48
|
-
&& Number.isSafeInteger(value.startTime)
|
|
49
|
-
&& value.startTime >= 0
|
|
50
|
-
&& typeof value.token === 'string'
|
|
51
|
-
&& value.token.length > 0
|
|
52
|
-
&& typeof value.owner === 'string'
|
|
53
|
-
&& typeof value.canonicalRepoRoot === 'string'
|
|
54
|
-
&& typeof value.taskId === 'string'
|
|
55
|
-
&& typeof value.acquiredAt === 'string') {
|
|
56
|
-
return value;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
// Fall through to the stable lock failure below.
|
|
61
|
-
}
|
|
62
|
-
throw new TaskExecutionLockError('ORCHESTRATION_LOCK_FAILED', 'lifecycle lock owner record is invalid', { operation: 'read', errno: null, key });
|
|
63
|
-
}
|
|
64
|
-
function unlinkIfPresent(file) {
|
|
65
|
-
try {
|
|
66
|
-
fs.unlinkSync(file);
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
if (errno(error) !== 'ENOENT')
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
function sameInode(left, right) {
|
|
74
|
-
return left.dev === right.dev && left.ino === right.ino;
|
|
75
|
-
}
|
|
76
|
-
function reclaimStaleLock(fixed, quarantine, snapshot, key, link) {
|
|
77
|
-
let linked = false;
|
|
78
|
-
try {
|
|
79
|
-
link(fixed, quarantine);
|
|
80
|
-
linked = true;
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
const disposition = mapLinkError('quarantine', error, key);
|
|
84
|
-
if (disposition === 'missing')
|
|
85
|
-
return;
|
|
86
|
-
if (disposition === 'exists') {
|
|
87
|
-
try {
|
|
88
|
-
const quarantineSnapshot = fs.readFileSync(quarantine, 'utf8');
|
|
89
|
-
const fixedStat = fs.statSync(fixed);
|
|
90
|
-
const quarantineStat = fs.statSync(quarantine);
|
|
91
|
-
if (quarantineSnapshot === snapshot && sameInode(fixedStat, quarantineStat)) {
|
|
92
|
-
unlinkIfPresent(quarantine);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
catch (readError) {
|
|
96
|
-
if (errno(readError) !== 'ENOENT')
|
|
97
|
-
throw readError;
|
|
98
|
-
}
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
if (disposition instanceof TaskExecutionLockError)
|
|
102
|
-
throw disposition;
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
const fixedSnapshot = fs.readFileSync(fixed, 'utf8');
|
|
106
|
-
const fixedStat = fs.statSync(fixed);
|
|
107
|
-
const quarantineStat = fs.statSync(quarantine);
|
|
108
|
-
if (fixedSnapshot === snapshot && sameInode(fixedStat, quarantineStat))
|
|
109
|
-
unlinkIfPresent(fixed);
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
if (errno(error) !== 'ENOENT')
|
|
113
|
-
throw error;
|
|
114
|
-
}
|
|
115
|
-
finally {
|
|
116
|
-
if (linked)
|
|
117
|
-
unlinkIfPresent(quarantine);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
function cleanStaleCandidates(lockRoot, key, identityMatches) {
|
|
121
|
-
const prefix = `${key}.candidate.`;
|
|
122
|
-
for (const name of fs.readdirSync(lockRoot)) {
|
|
123
|
-
if (!name.startsWith(prefix))
|
|
124
|
-
continue;
|
|
125
|
-
const candidate = path.join(lockRoot, name);
|
|
126
|
-
try {
|
|
127
|
-
const owner = parseOwner(fs.readFileSync(candidate, 'utf8'), key);
|
|
128
|
-
if (!identityMatches(owner))
|
|
129
|
-
unlinkIfPresent(candidate);
|
|
130
|
-
}
|
|
131
|
-
catch {
|
|
132
|
-
// A malformed candidate never owns the fixed lock and is left for manual diagnosis.
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
function withTaskExecutionLock(repoRoot, taskId, ownerName, callback, options = {}) {
|
|
137
|
-
let identity;
|
|
138
|
-
try {
|
|
139
|
-
identity = lockKey(repoRoot, taskId, options.identityScope);
|
|
140
|
-
}
|
|
141
|
-
catch (error) {
|
|
142
|
-
throw new TaskExecutionLockError('ORCHESTRATION_LOCK_FAILED', 'failed to canonicalize the repository for lifecycle locking', { operation: 'canonicalize', errno: errno(error), key: 'unresolved' });
|
|
143
|
-
}
|
|
144
|
-
const { canonicalRepoRoot, key } = identity;
|
|
145
|
-
const lockRoot = options.lockRoot ?? path.join(os.tmpdir(), 'agent-infra-lifecycle-locks');
|
|
146
|
-
const token = (options.token ?? randomUUID)();
|
|
147
|
-
const candidate = path.join(lockRoot, `${key}.candidate.${process.pid}.${token}`);
|
|
148
|
-
const fixed = path.join(lockRoot, `${key}.lock`);
|
|
149
|
-
const link = options.linkSync ?? fs.linkSync;
|
|
150
|
-
const startTime = (options.getStartTime ?? getProcessStartTime)(process.pid);
|
|
151
|
-
if (startTime === null) {
|
|
152
|
-
throw new TaskExecutionLockError('ORCHESTRATION_LOCK_FAILED', 'current process start time is unavailable', { operation: 'identity', errno: null, key });
|
|
153
|
-
}
|
|
154
|
-
const owner = {
|
|
155
|
-
version: 2,
|
|
156
|
-
pid: process.pid,
|
|
157
|
-
startTime,
|
|
158
|
-
token,
|
|
159
|
-
owner: ownerName,
|
|
160
|
-
canonicalRepoRoot,
|
|
161
|
-
taskId,
|
|
162
|
-
acquiredAt: (options.now ?? (() => new Date().toISOString()))()
|
|
163
|
-
};
|
|
164
|
-
const serialized = `${JSON.stringify(owner)}\n`;
|
|
165
|
-
let ownsFixed = false;
|
|
166
|
-
let deferRelease = false;
|
|
167
|
-
const release = () => {
|
|
168
|
-
try {
|
|
169
|
-
unlinkIfPresent(candidate);
|
|
170
|
-
}
|
|
171
|
-
catch {
|
|
172
|
-
// Candidate cleanup is best-effort and must not replace the primary result.
|
|
173
|
-
}
|
|
174
|
-
if (ownsFixed) {
|
|
175
|
-
try {
|
|
176
|
-
const current = parseOwner(fs.readFileSync(fixed, 'utf8'), key);
|
|
177
|
-
if (current.token === token)
|
|
178
|
-
unlinkIfPresent(fixed);
|
|
179
|
-
}
|
|
180
|
-
catch {
|
|
181
|
-
// A missing or replaced fixed lock is not owned by this invocation.
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
try {
|
|
186
|
-
fs.mkdirSync(lockRoot, { recursive: true });
|
|
187
|
-
cleanStaleCandidates(lockRoot, key, options.identityMatches ?? processIdentityMatches);
|
|
188
|
-
const descriptor = fs.openSync(candidate, 'wx', 0o600);
|
|
189
|
-
try {
|
|
190
|
-
fs.writeFileSync(descriptor, serialized);
|
|
191
|
-
fs.fsyncSync(descriptor);
|
|
192
|
-
}
|
|
193
|
-
finally {
|
|
194
|
-
fs.closeSync(descriptor);
|
|
195
|
-
}
|
|
196
|
-
for (let attempt = 0; attempt < 16; attempt += 1) {
|
|
197
|
-
try {
|
|
198
|
-
link(candidate, fixed);
|
|
199
|
-
ownsFixed = true;
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
catch (error) {
|
|
203
|
-
const disposition = mapLinkError('acquire', error, key);
|
|
204
|
-
if (disposition instanceof TaskExecutionLockError)
|
|
205
|
-
throw disposition;
|
|
206
|
-
let snapshot;
|
|
207
|
-
let current;
|
|
208
|
-
try {
|
|
209
|
-
snapshot = fs.readFileSync(fixed, 'utf8');
|
|
210
|
-
current = parseOwner(snapshot, key);
|
|
211
|
-
}
|
|
212
|
-
catch (readError) {
|
|
213
|
-
if (errno(readError) === 'ENOENT')
|
|
214
|
-
continue;
|
|
215
|
-
throw readError;
|
|
216
|
-
}
|
|
217
|
-
if ((options.identityMatches ?? processIdentityMatches)(current)) {
|
|
218
|
-
throw new TaskExecutionLockError('ORCHESTRATION_LOCK_BUSY', 'another lifecycle operation holds the task lock', { operation: 'acquire', errno: 'EEXIST', key });
|
|
219
|
-
}
|
|
220
|
-
reclaimStaleLock(fixed, `${fixed}.quarantine.${current.token}`, snapshot, key, link);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
if (!ownsFixed) {
|
|
224
|
-
throw new TaskExecutionLockError('ORCHESTRATION_LOCK_BUSY', 'lifecycle task lock could not be acquired after stale recovery', { operation: 'acquire', errno: 'EEXIST', key });
|
|
225
|
-
}
|
|
226
|
-
unlinkIfPresent(candidate);
|
|
227
|
-
const value = callback();
|
|
228
|
-
if (value && typeof value.then === 'function') {
|
|
229
|
-
deferRelease = true;
|
|
230
|
-
return value.finally(release);
|
|
231
|
-
}
|
|
232
|
-
return value;
|
|
233
|
-
}
|
|
234
|
-
catch (error) {
|
|
235
|
-
if (error instanceof TaskExecutionLockError)
|
|
236
|
-
throw error;
|
|
237
|
-
if (error instanceof Error && ['OrchestrationStateError', 'ArtifactRecoveryError'].includes(error.name))
|
|
238
|
-
throw error;
|
|
239
|
-
throw new TaskExecutionLockError('ORCHESTRATION_LOCK_FAILED', 'lifecycle task lock operation failed', { operation: ownsFixed ? 'callback' : 'acquire', errno: errno(error), key });
|
|
240
|
-
}
|
|
241
|
-
finally {
|
|
242
|
-
if (!deferRelease)
|
|
243
|
-
release();
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
function withRepositoryMutationLock(repoRoot, callback, options = {}) {
|
|
247
|
-
return withTaskExecutionLock(repoRoot, '__repository_mutation__', 'repository-mutation', callback, options);
|
|
248
|
-
}
|
|
249
|
-
export { TaskExecutionLockError, lockKey, mapLinkError, withRepositoryMutationLock, withTaskExecutionLock };
|
|
250
|
-
//# sourceMappingURL=task-execution-lock.js.map
|