@fitlab-ai/agent-infra 0.11.1 → 0.11.3
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/dist/bin/internal-cli.js +7 -2
- package/dist/lib/agent-clients/adapter.js +3 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +234 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +8 -35
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +1 -34
- package/dist/lib/agent-clients/adapters/codex.js +10 -0
- package/dist/lib/internal/cli-route-inventory.js +1 -1
- package/dist/lib/internal/manual-validation.js +22 -27
- package/dist/lib/internal/platform-comment.js +59 -0
- package/dist/lib/internal/sandbox-control.js +2 -171
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-lifecycle.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +7 -2
- package/dist/lib/internal/task-review.js +5 -5
- package/dist/lib/internal/task-validate.js +0 -6
- package/dist/lib/platform/comment-safety.js +7 -1
- package/dist/lib/platform/github-provider.js +13 -3
- package/dist/lib/platform/issue-comments.js +93 -15
- package/dist/lib/platform/pr-summary.js +7 -2
- package/dist/lib/platform/provider-contract.d.ts +2 -0
- package/dist/lib/platform/provider-validation.js +7 -2
- package/dist/lib/platform/verification-sync.js +19 -2
- package/dist/lib/sandbox/control/client.js +3 -44
- package/dist/lib/sandbox/control/executor.js +14 -117
- package/dist/lib/sandbox/control/finalization-response.js +8 -2
- package/dist/lib/sandbox/control/protocol.js +5 -64
- package/dist/lib/sandbox/control/server.js +29 -206
- package/dist/lib/sandbox/control/state.js +1 -7
- package/dist/lib/sandbox/control/task-view.js +2 -1
- package/dist/lib/task/artifact-command.js +6 -6
- package/dist/lib/task/codex-orchestration.js +10 -208
- package/dist/lib/task/commit-operation.js +3 -18
- package/dist/lib/task/control-authority.js +35 -44
- package/dist/lib/task/control-recovery.js +3 -42
- package/dist/lib/task/delegation-receipts.js +16 -78
- package/dist/lib/task/events.js +89 -237
- package/dist/lib/task/finalization-artifacts.js +1 -3
- package/dist/lib/task/finalization-state.js +2 -1
- package/dist/lib/task/finalization.js +208 -57
- package/dist/lib/task/lifecycle-execution.js +2 -11
- package/dist/lib/task/lifecycle.js +1 -1
- package/dist/lib/task/local-artifact-finalization.js +25 -242
- package/dist/lib/task/manual-validation-receipt.js +8 -3
- package/dist/lib/task/orchestration.js +12 -24
- package/dist/lib/task/review-command.js +0 -1
- package/dist/lib/task/review-finalization.js +46 -211
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapter.ts +46 -0
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +297 -0
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +13 -33
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +1 -44
- package/lib/agent-clients/adapters/codex.ts +10 -0
- package/lib/internal/cli-route-inventory.ts +1 -1
- package/lib/internal/manual-validation.ts +22 -26
- package/lib/internal/platform-comment.ts +38 -0
- package/lib/internal/sandbox-control.ts +1 -185
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-lifecycle.ts +2 -2
- package/lib/internal/task-operation-registry.ts +8 -4
- package/lib/internal/task-review.ts +5 -5
- package/lib/internal/task-validate.ts +0 -5
- package/lib/platform/comment-safety.ts +8 -0
- package/lib/platform/github-provider.ts +11 -2
- package/lib/platform/issue-comments.ts +102 -17
- package/lib/platform/pr-summary.ts +10 -2
- package/lib/platform/provider-contract.ts +2 -0
- package/lib/platform/provider-validation.ts +6 -2
- package/lib/platform/verification-sync.ts +19 -2
- package/lib/sandbox/control/client.ts +5 -68
- package/lib/sandbox/control/executor.ts +14 -125
- package/lib/sandbox/control/finalization-response.ts +8 -2
- package/lib/sandbox/control/protocol.ts +7 -83
- package/lib/sandbox/control/server.ts +30 -220
- package/lib/sandbox/control/state.ts +1 -9
- package/lib/sandbox/control/task-view.ts +2 -1
- package/lib/task/artifact-command.ts +6 -7
- package/lib/task/codex-orchestration.ts +8 -241
- package/lib/task/commit-operation.ts +3 -23
- package/lib/task/control-authority.ts +39 -55
- package/lib/task/control-recovery.ts +3 -43
- package/lib/task/delegation-receipts.ts +14 -81
- package/lib/task/events.ts +106 -255
- package/lib/task/finalization-artifacts.ts +1 -3
- package/lib/task/finalization-state.ts +2 -1
- package/lib/task/finalization.ts +221 -65
- package/lib/task/lifecycle-execution.ts +10 -21
- package/lib/task/lifecycle.ts +2 -2
- package/lib/task/local-artifact-finalization.ts +23 -281
- package/lib/task/manual-validation-receipt.ts +8 -2
- package/lib/task/orchestration.ts +30 -53
- package/lib/task/review-command.ts +0 -1
- package/lib/task/review-finalization.ts +45 -193
- package/package.json +2 -2
- package/templates/.agents/rules/lifecycle-orchestration.en.md +23 -9
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +23 -9
- package/templates/.agents/rules/local-artifact-repair.en.md +14 -60
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -60
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/code-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
- 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-task/SKILL.en.md +7 -8
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +7 -8
- package/templates/.agents/skills/plan-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-code/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-plan/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +2 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/run-task/SKILL.en.md +10 -9
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +10 -9
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +2 -2
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +2 -2
- package/dist/lib/sandbox/control/task-workflow.js +0 -74
- package/dist/lib/sandbox/control/workflow-executor.js +0 -157
- package/dist/lib/task/lifecycle-recovery.js +0 -549
- package/dist/lib/task/recovery-warning.js +0 -19
- package/dist/lib/task/workflow-command.js +0 -18
- package/dist/lib/task/workflow-dispatch.js +0 -161
- package/lib/sandbox/control/task-workflow.ts +0 -95
- package/lib/sandbox/control/workflow-executor.ts +0 -183
- package/lib/task/lifecycle-recovery.ts +0 -691
- package/lib/task/recovery-warning.ts +0 -21
- package/lib/task/workflow-command.ts +0 -19
- package/lib/task/workflow-dispatch.ts +0 -171
|
@@ -26,7 +26,7 @@ description: >
|
|
|
26
26
|
- `complete-manual-validation` 仍是维护者确认覆盖充分后的最终登记入口。
|
|
27
27
|
- 禁止直接操作临时 worktree、lease 或 container;只调用 `agent-infra-internal task-validate`。
|
|
28
28
|
- 产物不得记录 token、环境变量、完整 argv、绝对用户路径或原始 transcript;每个验证目标必须由核心写入同一 current-only evidence envelope。
|
|
29
|
-
-
|
|
29
|
+
- 生成会由 task 评论引用的验证 artifact Markdown 前,先读取 `.agents/rules/sync-content-generation.md` 并遵循其中的生成端约束;验证 artifact 保留在本地,不发布为 Issue artifact 评论。
|
|
30
30
|
- branch-only 降级路径走 `.agents/workspace/validations/{branch-slug}/`,标记 `recoverable: false`:不写 task.md、不发 lifecycle 事件、不同步 Issue、不跑 `task-verify`;产物须带回宿主机,由维护者登记。
|
|
31
31
|
|
|
32
32
|
## 第 0 步:状态核对(执行前硬约束)
|
|
@@ -46,7 +46,7 @@ branch-only 无 `{task-id}`,跳过本步,并在产物 `## 状态核对` 记
|
|
|
46
46
|
3. 从核心结果取得轮次和产物名;确认存在有效显式工作或非空发现清单后,运行 `agent-infra-internal task-event {task-id} validation-run.started --agent {standard-agent-token} --initiator {trigger-initiator} --request-id {request-id} --reason-code {reason-code}`,并逐项分类为 `executable|unavailable|unknown|unsafe|unresolved`。
|
|
47
47
|
4. 为每个验证目标分配 `{evidence-file}`,分别调用 `agent-infra-internal task-validate {task-ref} --scope snapshot --format json --evidence-file {evidence-file} -- {command...}`;只有证据表明必须原位时才对该项进行第二次显式 inplace 调用并写入对应 evidence 文件。零项可执行时不运行伪造命令,但仍继续产出覆盖缺口证据。
|
|
48
48
|
5. 读取 `reference/report-template.md`,创建 `validation-run.md|validation-run-r{N}.md`;记录输入模式、发现清单、逐项结果、CLI JSON allowlist 与去敏摘要。
|
|
49
|
-
6. 运行 `agent-infra-internal task-event {task-id} validation-run.completed --agent {standard-agent-token} --initiator {trigger-initiator} --request-id {request-id} --reason-code {reason-code} --artifact {artifact}`。存在 Issue
|
|
49
|
+
6. 运行 `agent-infra-internal task-event {task-id} validation-run.completed --agent {standard-agent-token} --initiator {trigger-initiator} --request-id {request-id} --reason-code {reason-code} --artifact {artifact}`。存在 Issue 时仅运行 `agent-infra-internal platform-comment sync {task-id} --kind task --agent {standard-agent-token}`;验证 artifact 不发布为 Issue 评论。
|
|
50
50
|
7. 运行 `agent-infra-internal task-verify {task-id} validation-run.completed --artifact {artifact} --format text`;未通过则修复后重跑。
|
|
51
51
|
8. 告知用户证据路径、覆盖缺口和验证结果;明确仍需维护者判断是否执行 `complete-manual-validation`。读取 `.agents/rules/next-step-output.md`,最后一行输出 `Completed at`。
|
|
52
52
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: run-task
|
|
3
3
|
description: >
|
|
4
|
-
Orchestrate lifecycle stages from the task's current state with fresh executors/reviewers and
|
|
4
|
+
Orchestrate lifecycle stages from the task's current state with fresh executors/reviewers and recorded execution results.
|
|
5
5
|
Use when one entry should advance an existing task until a safe commit or stable pause.
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -14,14 +14,15 @@ The entry point may omit the task ref; explicit task scope accepts only `--task
|
|
|
14
14
|
The orchestrator delegates only and never executes a stage skill itself. First read `.agents/rules/no-mid-flow-questions.md`, `.agents/rules/lifecycle-orchestration.md`, and `reference/host-validation.md`.
|
|
15
15
|
|
|
16
16
|
1. Resolve the canonical task ID, current Agent Client, and optional atomic policy flags, then run `task-snapshot`. If one explicit role field is present, all four are required.
|
|
17
|
-
2.
|
|
18
|
-
3.
|
|
19
|
-
4. Run `
|
|
20
|
-
5.
|
|
21
|
-
6.
|
|
22
|
-
7.
|
|
23
|
-
8.
|
|
24
|
-
9.
|
|
17
|
+
2. Use the current host's native child spawn, wait, and result interfaces. Task-bound sandboxes execute ordinary task orchestration locally in the current worktree; Codex controller `open`, `verify`, and `close` remain restricted broker operations. Retain task binding and checks for real external process operations.
|
|
18
|
+
3. Before each loop, run `agent-infra-internal task-lifecycle {task-id} recover-started --agent {client} --auto`. The client adapter owns recovery capability and stop-evidence validation; an unsupported adapter or a run that needs no recovery returns `no-op`. Continue only after `no-op` or `applied`. Stop on every other result; a later operator invocation retries from persisted state without routing or dispatching a child.
|
|
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
|
+
5. Run `route`. On `completed`, run `agent-infra-internal task-verify {task-id} run-task.completed --format text` and stop. Only a `running` result with non-null `next` supplies action, role, round, artifact, requested model, and requested effort.
|
|
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, run `task-orchestration <task-ref> dispatch` before spawning a fresh native child with route's model/effort. Pass the short task ref, skill, `--orchestrated`, and stage identity. 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. Retain existing write locks without introducing a new lock protocol around native spawn.
|
|
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
|
+
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
|
+
10. On pause or completion, run the matching typed verification and report the structured endpoint.
|
|
25
26
|
|
|
26
27
|
## Stop
|
|
27
28
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: run-task
|
|
3
3
|
description: >
|
|
4
|
-
|
|
4
|
+
从任务当前状态持续编排生命周期阶段,使用 fresh executor/reviewer 并记录实际执行结果。
|
|
5
5
|
当用户希望通过单一入口推进已有任务直到安全提交或稳定暂停时使用。
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -14,14 +14,15 @@ description: >
|
|
|
14
14
|
总控只编排,不直接执行任何阶段技能。执行前先读取 `.agents/rules/no-mid-flow-questions.md`、`.agents/rules/lifecycle-orchestration.md` 与 `reference/host-validation.md`。
|
|
15
15
|
|
|
16
16
|
1. 解析规范任务 ID、当前 Agent Client,以及可选的原子策略 `--executor-model`、`--executor-reasoning-effort`、`--reviewer-model`、`--reviewer-reasoning-effort`,并执行 `agent-infra-internal task-snapshot {task-id} --format text`。任一显式策略字段出现时四个 role 字段必须完整,不得与配置拼接;两个角色可以使用同一模型。
|
|
17
|
-
2.
|
|
18
|
-
3.
|
|
19
|
-
4. 调用 `
|
|
20
|
-
5.
|
|
21
|
-
6.
|
|
22
|
-
7.
|
|
23
|
-
8.
|
|
24
|
-
9.
|
|
17
|
+
2. 使用当前宿主的原生子 Agent 启动、等待与结果接口。task-bound sandbox 在当前 worktree 本地执行普通任务编排;Codex controller 的 `open`、`verify`、`close` 继续通过受限 broker 执行。保留任务绑定与真实外部进程操作检查。
|
|
18
|
+
3. 每次进入循环时先调用 `agent-infra-internal task-lifecycle {task-id} recover-started --agent {client} --auto`。客户端适配器负责恢复能力和停止证据校验;没有该能力或无需恢复时返回 `no-op`。仅在结构化结果为 `no-op` 或 `applied` 时继续,其他结果安全停止;下一次人为调用按持久化状态幂等重试,不 route、不派发 child。
|
|
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
|
+
5. 调用 `route` 并读取结构化结果。若返回 `completed`,立即运行 `agent-infra-internal task-verify {task-id} run-task.completed --format text` 并停止;仅当返回 `running` 且 `next` 非空时读取唯一 action、role、round、artifact、`requestedModel` 和 `requestedReasoningEffort`,不得自行推断。
|
|
21
|
+
6. 调用 `prepare --client {client} --requested-model {requestedModel} --requested-reasoning-effort {requestedReasoningEffort}`,使用 route 返回的精确策略。客户端适配器执行宿主 preflight;任务身份、策略或宿主检查失败时记录实际诊断。
|
|
22
|
+
7. prepare 成功后,在调用 fresh 原生子 Agent 前执行 `task-orchestration <task-ref> dispatch`,显式指定 route 返回的 model/effort;传递短任务引用、skill 名、`--orchestrated` 与 stage/round/artifact/role。child 调用 `await-activation --stage ... --round ... --artifact ... --role ...`,确认当前阶段与实际 child 关联后执行。代码阶段通过 code-task 创建本地 checkpoint;禁止单独委派 commit 阶段或推送。保留已有写锁,不把实际 spawn 纳入新建锁协议。
|
|
23
|
+
8. 通过当前宿主的原生生命周期事件和结果接口记录实际启动及终态。timed-out wait 不推断成功;身份、传输或异常终态失败如实暂停。阶段结果和 child 完成后调用 `advance`;只有 `running` 才重复步骤 3。
|
|
24
|
+
9. 每轮创建新 child;禁止 follow-up 复用 reviewer。如实记录 actual model/effort 及宿主降级理由。检查当前身份、产物、账本与实际执行结果;用户裁决优先于历史方案派生要求。不得新增 child discovery、孤立 child 恢复或专用恢复协议。
|
|
25
|
+
10. 完成或暂停后运行对应 typed verification,并把结构化 run 摘要、暂停原因、commit 终点或 clean completion evidence 告知用户。
|
|
25
26
|
|
|
26
27
|
## 停止
|
|
27
28
|
|
|
@@ -10,7 +10,7 @@ Before publishing support for a client, prove the lifecycle evidence chain with
|
|
|
10
10
|
- Explicit requested model/effort reaches each executor/reviewer. A fallback of either field reports the corresponding actual value and its own non-empty reason.
|
|
11
11
|
> claude-code exception: requested reasoning effort does not yet support per-role dispatch to executor/reviewer — `.claude/agents/{executor,reviewer}.md` is a repository-level shared singleton, and writing it per role would race across concurrent tasks. This client only needs to honestly record the actual model/actual reasoning effort observed in native Start/Stop host events (`delegationEvidence.actualReasoningEffort` is declared `spawn-ack`); when not observed it is recorded as missing, which is not treated as a fallback requiring its own reason and does not fail closed. This exception does not apply to any other client.
|
|
12
12
|
- Candidate-checkout and packed-install behavior match, with model policy, receipts, and verification results auditable in `orchestration.json`.
|
|
13
|
-
-
|
|
13
|
+
- Use the hooks/profiles actually loaded by the current host and verify observed parent/child identity and terminal results. Prepare does not depend on historical capability or controller attestation.
|
|
14
14
|
|
|
15
15
|
## Validation Sequence
|
|
16
16
|
|
|
@@ -21,4 +21,4 @@ Before publishing support for a client, prove the lifecycle evidence chain with
|
|
|
21
21
|
5. Commit only redacted summaries and non-sensitive fixtures. Remove or replace tokens, user-specific absolute paths, transcript content, and credentials.
|
|
22
22
|
6. For sandbox, run at least ten cold executor starts and ten cold reviewer starts. Record monotonic prepared, spawn-dispatch, SubagentStart, and activation-completed timestamps plus p50/p95/max. Enable only when max plus 20% fits the deadline and symlink/config/plugin/lease/context/build failure injection and terminal cleanup audits pass.
|
|
23
23
|
|
|
24
|
-
If any required field cannot be observed reliably from the real host, keep that client's orchestration capability `unsupported` and record the gap as manual validation. Codex may advertise `experimental`, but every `prepare` must still pass static preflight and either native start/stop or the parent spawn/completed-wait fallback must
|
|
24
|
+
If any required field cannot be observed reliably from the real host, keep that client's orchestration capability `unsupported` and record the gap as manual validation. Codex may advertise `experimental`, but every `prepare` must still pass static preflight and either native start/stop or the parent spawn/completed-wait fallback must record verifiable execution results. The fallback may wait only for empty turns or protocol `inProgress`; malformed, identity/transport errors, or abnormal terminals pause deterministically. The claude-code exception above is already scoped in the second bullet and does not change this rule's fail-closed requirement for any other field or client.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
- 显式 requested model/effort 能传给 executor/reviewer;宿主对任一字段回退时,事件能给出对应 actual 值与独立的非空 fallback reason。
|
|
11
11
|
> claude-code 例外:requested reasoning effort 暂不支持按角色下发给 executor/reviewer——`.claude/agents/{executor,reviewer}.md` 是仓库级共享单例,动态写入存在跨任务竞态,解决该竞态超出本任务范围。该客户端只要求如实记录宿主原生 Start/Stop 事件中能观察到的 actual model/actual reasoning effort(`delegationEvidence.actualReasoningEffort` 声明为 `spawn-ack`);观察不到时记录为缺失,不视为需要独立 fallback reason 的回退场景,也不构成 fail-closed 阻断。此例外不适用于其他客户端。
|
|
12
12
|
- candidate checkout 与打包安装后的行为一致,且模型策略、receipt 与验证结果可从 `orchestration.json` 复核。
|
|
13
|
-
-
|
|
13
|
+
- 使用当前宿主实际加载的 hook/profile,并核对实际 parent/child 身份与终态;prepare 不依赖历史 capability 或 controller attestation。
|
|
14
14
|
|
|
15
15
|
## 验证顺序
|
|
16
16
|
|
|
@@ -21,4 +21,4 @@
|
|
|
21
21
|
5. 仅把去敏摘要与非敏感 fixture 纳入版本库;token、绝对用户路径、transcript 内容和凭证必须删除或替换。
|
|
22
22
|
6. sandbox backend 另做至少 10 次 executor 与 10 次 reviewer 冷启动,记录 prepared、spawn dispatch、SubagentStart、activation completed 的单调时钟及 p50/p95/max;仅当 max 加 20% 余量不超过 deadline,并通过 symlink/config/plugin/lease/context/build 失败注入和终态清理审计时启用。
|
|
23
23
|
|
|
24
|
-
任一字段无法从真实宿主稳定观察时,该客户端的 orchestration capability 保持 `unsupported`,并把缺口记录为人工验证项。Codex 可声明为 `experimental`,但每次 `prepare` 仍必须通过静态 preflight,且原生 start/stop 或 parent spawn/completed-wait fallback
|
|
24
|
+
任一字段无法从真实宿主稳定观察时,该客户端的 orchestration capability 保持 `unsupported`,并把缺口记录为人工验证项。Codex 可声明为 `experimental`,但每次 `prepare` 仍必须通过静态 preflight,且原生 start/stop 或 parent spawn/completed-wait fallback 必须记录可核对的实际执行结果。fallback 只允许 empty turns/协议 `inProgress` 等待;malformed、身份/传输错误或异常 terminal 都稳定暂停。上述关于 claude-code 的例外已在第 2 条单独说明,不改变本条对其余字段/客户端的 fail-closed 要求。
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import { readStableFile, SecureFileError, writeAtomicFile } from '../../task/secure-fs.js';
|
|
5
|
-
import { TASK_WORKFLOW_COMMANDS, TASK_WORKFLOW_OPERATIONS } from '../../task/workflow-command.js';
|
|
6
|
-
export function validateTaskWorkflowRequest(value) {
|
|
7
|
-
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
8
|
-
throw new Error('TASK_WORKFLOW_REQUEST_INVALID');
|
|
9
|
-
const request = value;
|
|
10
|
-
if (Object.keys(request).sort().join(',') !== 'args,generation,id,operation,taskId,version'
|
|
11
|
-
|| request.version !== 1 || typeof request.id !== 'string' || !/^[a-f0-9-]{16,64}$/u.test(request.id)
|
|
12
|
-
|| typeof request.taskId !== 'string' || !/^TASK-\d{8}-\d{6}$/u.test(request.taskId)
|
|
13
|
-
|| typeof request.generation !== 'string' || !request.generation
|
|
14
|
-
|| !Object.hasOwn(TASK_WORKFLOW_COMMANDS, request.operation)
|
|
15
|
-
|| !Array.isArray(request.args) || request.args.length < 2 || request.args.length > 128
|
|
16
|
-
|| !request.args.every((arg) => typeof arg === 'string' && !/[\r\n]/u.test(arg))
|
|
17
|
-
|| request.args[0] !== request.taskId)
|
|
18
|
-
throw new Error('TASK_WORKFLOW_REQUEST_INVALID');
|
|
19
|
-
const [, selector] = TASK_WORKFLOW_COMMANDS[request.operation];
|
|
20
|
-
if (selector !== null && request.args[1] !== selector)
|
|
21
|
-
throw new Error('TASK_WORKFLOW_REQUEST_INVALID');
|
|
22
|
-
return request;
|
|
23
|
-
}
|
|
24
|
-
/** Preserve argv verbatim; the domain command owns option parsing and validation. */
|
|
25
|
-
export function createTaskWorkflowRequest(command, args, taskId, generation) {
|
|
26
|
-
const operation = TASK_WORKFLOW_OPERATIONS.find((key) => {
|
|
27
|
-
const [name, selector] = TASK_WORKFLOW_COMMANDS[key];
|
|
28
|
-
return name === command && (selector === null || selector === args[1]);
|
|
29
|
-
});
|
|
30
|
-
if (!operation)
|
|
31
|
-
throw new Error('TASK_WORKFLOW_OPERATION_UNSUPPORTED');
|
|
32
|
-
return validateTaskWorkflowRequest({ version: 1, id: randomUUID(), taskId, generation, operation, args: [...args] });
|
|
33
|
-
}
|
|
34
|
-
export function canonicalArtifactName(value) {
|
|
35
|
-
return /^(?:analysis|plan|code|review-analysis|review-plan|review-code)(?:-r[1-9]\d*)?\.md$/u.test(value)
|
|
36
|
-
&& path.basename(value) === value;
|
|
37
|
-
}
|
|
38
|
-
function assertTaskArtifactDirectory(directory) {
|
|
39
|
-
const resolved = path.resolve(directory);
|
|
40
|
-
let stat;
|
|
41
|
-
try {
|
|
42
|
-
stat = fs.lstatSync(resolved);
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'task directory is unavailable');
|
|
46
|
-
}
|
|
47
|
-
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
48
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'task directory must be a real directory');
|
|
49
|
-
}
|
|
50
|
-
return resolved;
|
|
51
|
-
}
|
|
52
|
-
export async function readTaskArtifact(taskDir, input) {
|
|
53
|
-
if (!canonicalArtifactName(input.artifact))
|
|
54
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'artifact must be a canonical top-level basename');
|
|
55
|
-
const root = assertTaskArtifactDirectory(taskDir);
|
|
56
|
-
const candidate = path.join(root, input.artifact);
|
|
57
|
-
if (path.dirname(candidate) !== root)
|
|
58
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'artifact escapes task directory');
|
|
59
|
-
const stable = await readStableFile(candidate, {
|
|
60
|
-
maxBytes: 1024 * 1024,
|
|
61
|
-
...(input.expectedSha256 ? { expectedSha256: input.expectedSha256 } : {})
|
|
62
|
-
});
|
|
63
|
-
return { artifact: input.artifact, bytes: stable.bytes, sha256: stable.sha256 };
|
|
64
|
-
}
|
|
65
|
-
export async function writeTaskArtifact(taskDir, artifact) {
|
|
66
|
-
if (!canonicalArtifactName(artifact.artifact))
|
|
67
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'artifact must be a canonical top-level basename');
|
|
68
|
-
const root = assertTaskArtifactDirectory(taskDir);
|
|
69
|
-
const target = path.join(root, artifact.artifact);
|
|
70
|
-
if (path.dirname(target) !== root)
|
|
71
|
-
throw new SecureFileError('TASK_ARTIFACT_WRITE_DENIED', 'artifact escapes task directory');
|
|
72
|
-
await writeAtomicFile(target, artifact.bytes, 0o600, artifact.expectedSha256);
|
|
73
|
-
}
|
|
74
|
-
//# sourceMappingURL=task-workflow.js.map
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { TASK_WORKFLOW_COMMANDS } from '../../task/workflow-command.js';
|
|
2
|
-
import { parseArtifactCommand, executeArtifactCommand } from '../../task/artifact-command.js';
|
|
3
|
-
import { parseReviewCommand } from '../../task/review-command.js';
|
|
4
|
-
import { prepareLocalArtifact, preflightLocalArtifact, commitLocalArtifactProvenance } from '../../task/local-artifact-finalization.js';
|
|
5
|
-
import { prepareReviewSummaryCandidate, commitReviewSummaryProvenance, preflightReviewSummary } from '../../task/review-finalization.js';
|
|
6
|
-
import { readArtifactRecoveryIntent } from '../../task/artifact-repair-intent.js';
|
|
7
|
-
import { withTaskExecutionLock } from '../../task/task-execution-lock.js';
|
|
8
|
-
import { dispatchWorkflowCommand } from '../../task/workflow-dispatch.js';
|
|
9
|
-
import { assertSandboxTaskSource } from '../workspace-view.js';
|
|
10
|
-
import { appendDiagnosticAudit } from './audit.js';
|
|
11
|
-
import { readTaskArtifact } from './task-workflow.js';
|
|
12
|
-
import { applyTaskEvent } from '../../task/events.js';
|
|
13
|
-
import { parseTaskEventRequest } from '../../internal/task-event.js';
|
|
14
|
-
function executionResult(result) {
|
|
15
|
-
return { exitCode: result.status === 'failed' || result.status === 'refused' ? 1 : 0, stdout: `${JSON.stringify(result)}\n`, stderr: '' };
|
|
16
|
-
}
|
|
17
|
-
/** The broker already authorized this host executor; domain operations own validation. */
|
|
18
|
-
export async function executeTaskWorkflow(manifest, request, lifecycleRecoveryAttestation = null, options = {}) {
|
|
19
|
-
let publicationCommitted = false;
|
|
20
|
-
let recoveryObservation = null;
|
|
21
|
-
const observeRecoveryPublication = () => {
|
|
22
|
-
if (!recoveryObservation || recoveryObservation.wasPassed)
|
|
23
|
-
return;
|
|
24
|
-
const intent = readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, recoveryObservation.family, recoveryObservation.artifact);
|
|
25
|
-
publicationCommitted ||= intent?.state === 'preflight-ready'
|
|
26
|
-
|| intent?.state === 'preflight-commit-started'
|
|
27
|
-
|| intent?.state === 'preflight-passed'
|
|
28
|
-
|| intent?.state === 'passed'
|
|
29
|
-
|| intent?.state === 'commit-started';
|
|
30
|
-
};
|
|
31
|
-
let faultTriggered = false;
|
|
32
|
-
const fault = (window) => {
|
|
33
|
-
if (faultTriggered || options.faultWindow !== window)
|
|
34
|
-
return;
|
|
35
|
-
faultTriggered = true;
|
|
36
|
-
throw new Error(`TASK_WORKFLOW_FAULT_INJECTED:${window}`);
|
|
37
|
-
};
|
|
38
|
-
const response = (result) => {
|
|
39
|
-
fault('before-result-return');
|
|
40
|
-
return executionResult(result);
|
|
41
|
-
};
|
|
42
|
-
try {
|
|
43
|
-
fault('before-call');
|
|
44
|
-
const taskDir = assertSandboxTaskSource(manifest.repoRoot, request.taskId);
|
|
45
|
-
const [command] = TASK_WORKFLOW_COMMANDS[request.operation];
|
|
46
|
-
if (request.operation === 'event') {
|
|
47
|
-
const eventRequest = parseTaskEventRequest(request.args);
|
|
48
|
-
const boundEventRequest = lifecycleRecoveryAttestation && eventRequest.requestId === undefined
|
|
49
|
-
? { ...eventRequest, requestId: lifecycleRecoveryAttestation.lifecycleRequestId }
|
|
50
|
-
: eventRequest;
|
|
51
|
-
fault('before-domain-write');
|
|
52
|
-
const result = applyTaskEvent(boundEventRequest, {
|
|
53
|
-
repoRoot: manifest.repoRoot,
|
|
54
|
-
lifecycleRecoveryAttestation,
|
|
55
|
-
deferLifecycleRecoveryConsumption: true
|
|
56
|
-
});
|
|
57
|
-
publicationCommitted = result.changed;
|
|
58
|
-
fault('after-atomic-rename');
|
|
59
|
-
return response(result);
|
|
60
|
-
}
|
|
61
|
-
if (command !== 'task-artifact' && command !== 'task-review') {
|
|
62
|
-
// The broker owns this short-lived executor; no global service or worker
|
|
63
|
-
// credential participates in the command's authority or recovery path.
|
|
64
|
-
fault('before-domain-write');
|
|
65
|
-
const result = dispatchWorkflowCommand(manifest.repoRoot, request.operation, request.args);
|
|
66
|
-
publicationCommitted = result.changed === true;
|
|
67
|
-
fault('after-atomic-rename');
|
|
68
|
-
return response(result);
|
|
69
|
-
}
|
|
70
|
-
const input = command === 'task-artifact' ? parseArtifactCommand(request.args) : parseReviewCommand(request.args);
|
|
71
|
-
if (command === 'task-artifact' && 'operation' in input && input.operation === 'inspect') {
|
|
72
|
-
fault('before-domain-write');
|
|
73
|
-
const result = executeArtifactCommand(input, { repoRoot: manifest.repoRoot });
|
|
74
|
-
publicationCommitted = result.changed === true;
|
|
75
|
-
fault('after-atomic-rename');
|
|
76
|
-
return response(result);
|
|
77
|
-
}
|
|
78
|
-
if ('operation' in input && input.operation === 'init') {
|
|
79
|
-
fault('before-domain-write');
|
|
80
|
-
const result = executeArtifactCommand(input, { repoRoot: manifest.repoRoot, artifactDir: taskDir });
|
|
81
|
-
publicationCommitted = result.changed === true;
|
|
82
|
-
fault('after-atomic-rename');
|
|
83
|
-
return response(result);
|
|
84
|
-
}
|
|
85
|
-
return await withTaskExecutionLock(manifest.repoRoot, request.taskId, `sandbox-control.${request.operation}`, async () => {
|
|
86
|
-
const artifact = await readTaskArtifact(taskDir, { artifact: input.artifact });
|
|
87
|
-
const content = artifact.bytes.toString('utf8');
|
|
88
|
-
fault('before-domain-write');
|
|
89
|
-
let result;
|
|
90
|
-
if ('operation' in input) {
|
|
91
|
-
const { family } = input;
|
|
92
|
-
if (family !== 'analysis' && family !== 'plan' && family !== 'code')
|
|
93
|
-
throw new Error('ARTIFACT_IDENTITY_INVALID');
|
|
94
|
-
const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot, recoveryId: input.recoveryId, lockAlreadyHeld: true };
|
|
95
|
-
if (input.operation === 'preflight') {
|
|
96
|
-
// Preflight only seals a verified generation. It must not publish the
|
|
97
|
-
// formal artifact, set publicationStarted, or append finalizer audit.
|
|
98
|
-
const result = preflightLocalArtifact(local);
|
|
99
|
-
recoveryObservation = { family, artifact: input.artifact, wasPassed: false };
|
|
100
|
-
observeRecoveryPublication();
|
|
101
|
-
return response(result);
|
|
102
|
-
}
|
|
103
|
-
recoveryObservation = {
|
|
104
|
-
family,
|
|
105
|
-
artifact: input.artifact,
|
|
106
|
-
wasPassed: readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, family, input.artifact)?.state === 'passed'
|
|
107
|
-
};
|
|
108
|
-
const prepared = prepareLocalArtifact(local, content, lifecycleRecoveryAttestation ?? undefined);
|
|
109
|
-
observeRecoveryPublication();
|
|
110
|
-
const commitOptions = { afterPublish: () => fault('after-atomic-rename') };
|
|
111
|
-
if (prepared.result.status === 'failed')
|
|
112
|
-
return executionResult(commitLocalArtifactProvenance(prepared, commitOptions));
|
|
113
|
-
result = commitLocalArtifactProvenance(prepared, commitOptions);
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
if (input.overrideTicket)
|
|
117
|
-
throw new Error('TASK_WORKFLOW_OVERRIDE_UNSUPPORTED');
|
|
118
|
-
const family = `review-${input.stage}`;
|
|
119
|
-
if (request.operation === 'review-preflight') {
|
|
120
|
-
const result = preflightReviewSummary(input, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true });
|
|
121
|
-
recoveryObservation = { family, artifact: input.artifact, wasPassed: false };
|
|
122
|
-
observeRecoveryPublication();
|
|
123
|
-
return response(result);
|
|
124
|
-
}
|
|
125
|
-
recoveryObservation = {
|
|
126
|
-
family,
|
|
127
|
-
artifact: input.artifact,
|
|
128
|
-
wasPassed: readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, family, input.artifact)?.state === 'passed'
|
|
129
|
-
};
|
|
130
|
-
const prepared = prepareReviewSummaryCandidate(input, content, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true, startRecovery: true });
|
|
131
|
-
observeRecoveryPublication();
|
|
132
|
-
if (input.dryRun || prepared.result.status === 'planned')
|
|
133
|
-
return executionResult(prepared.result);
|
|
134
|
-
const commitOptions = { afterPublish: () => fault('after-atomic-rename') };
|
|
135
|
-
if (prepared.result.status === 'failed')
|
|
136
|
-
return executionResult(commitReviewSummaryProvenance(prepared, manifest.repoRoot, commitOptions));
|
|
137
|
-
result = commitReviewSummaryProvenance(prepared, manifest.repoRoot, commitOptions);
|
|
138
|
-
}
|
|
139
|
-
observeRecoveryPublication();
|
|
140
|
-
publicationCommitted ||= result.changed === true;
|
|
141
|
-
if (result.status !== 'failed')
|
|
142
|
-
appendDiagnosticAudit(manifest, 'task-workflow-artifact-finalized', {
|
|
143
|
-
requestId: request.id, sandboxTaskId: request.taskId, workflowOperation: request.operation,
|
|
144
|
-
artifact: input.artifact, sha256: result.artifactSha256, semanticDigest: result.semanticDigest
|
|
145
|
-
});
|
|
146
|
-
fault('after-atomic-rename');
|
|
147
|
-
return response(result);
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
catch (error) {
|
|
151
|
-
observeRecoveryPublication();
|
|
152
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
153
|
-
const code = error?.code ?? /^([A-Z][A-Z0-9_]+)/u.exec(message)?.[1] ?? 'TASK_WORKFLOW_REQUEST_INVALID';
|
|
154
|
-
return executionResult({ status: 'failed', changed: publicationCommitted ? null : false, error: { code, message } });
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
//# sourceMappingURL=workflow-executor.js.map
|