@fitlab-ai/agent-infra 0.10.0 → 0.11.0

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.
Files changed (95) hide show
  1. package/README.md +2 -6
  2. package/README.zh-CN.md +2 -6
  3. package/bin/internal-cli.sh +0 -13
  4. package/dist/bin/internal-cli.js +11 -49
  5. package/dist/lib/internal/cli-route-inventory.js +3 -4
  6. package/dist/lib/internal/platform-comment.js +60 -2
  7. package/dist/lib/internal/task-artifact.js +1 -1
  8. package/dist/lib/internal/task-finalization.js +2 -2
  9. package/dist/lib/internal/task-lifecycle.js +2 -2
  10. package/dist/lib/internal/task-operation-registry.js +22 -12
  11. package/dist/lib/internal/task-orchestration.js +2 -2
  12. package/dist/lib/internal/task-review.js +10 -5
  13. package/dist/lib/platform/activity-recovery.js +159 -0
  14. package/dist/lib/platform/issue-comments.js +84 -32
  15. package/dist/lib/platform/task-comment-projection.js +70 -0
  16. package/dist/lib/platform/task-recovery.js +55 -0
  17. package/dist/lib/platform/verification-sync.js +43 -9
  18. package/dist/lib/sandbox/control/executor.js +4 -2
  19. package/dist/lib/sandbox/control/task-workflow.js +1 -1
  20. package/dist/lib/sandbox/control/workflow-executor.js +83 -21
  21. package/dist/lib/server/process-state.js +17 -5
  22. package/dist/lib/task/artifact-command.js +6 -3
  23. package/dist/lib/task/artifact-operations.js +1 -1
  24. package/dist/lib/task/artifact-recovery.js +114 -68
  25. package/dist/lib/task/artifact-repair-intent.js +25 -8
  26. package/dist/lib/task/control-authority.js +1 -1
  27. package/dist/lib/task/events.js +6 -6
  28. package/dist/lib/task/intermediate-cleanup.js +28 -3
  29. package/dist/lib/task/local-artifact-finalization.js +78 -14
  30. package/dist/lib/task/review-command.js +2 -2
  31. package/dist/lib/task/review-finalization.js +203 -10
  32. package/dist/lib/{host-control → task}/secure-fs.js +8 -19
  33. package/dist/lib/task/workflow-command.js +2 -0
  34. package/dist/lib/task/workflow-dispatch.js +161 -0
  35. package/dist/lifecycle-build-manifest.json +3 -3
  36. package/lib/internal/cli-route-inventory.ts +3 -4
  37. package/lib/internal/platform-comment.ts +53 -2
  38. package/lib/internal/task-artifact.ts +1 -1
  39. package/lib/internal/task-finalization.ts +1 -1
  40. package/lib/internal/task-lifecycle.ts +1 -1
  41. package/lib/internal/task-operation-registry.ts +22 -12
  42. package/lib/internal/task-orchestration.ts +1 -1
  43. package/lib/internal/task-review.ts +9 -5
  44. package/lib/platform/activity-recovery.ts +179 -0
  45. package/lib/platform/issue-comments.ts +98 -31
  46. package/lib/platform/task-comment-projection.ts +79 -0
  47. package/lib/platform/task-recovery.ts +54 -0
  48. package/lib/platform/verification-sync.ts +46 -13
  49. package/lib/sandbox/control/executor.ts +4 -2
  50. package/lib/sandbox/control/protocol.ts +1 -1
  51. package/lib/sandbox/control/task-workflow.ts +1 -1
  52. package/lib/sandbox/control/workflow-executor.ts +102 -21
  53. package/lib/server/process-state.ts +26 -5
  54. package/lib/task/artifact-command.ts +6 -4
  55. package/lib/task/artifact-operations.ts +1 -1
  56. package/lib/task/artifact-recovery.ts +120 -67
  57. package/lib/task/artifact-repair-intent.ts +38 -11
  58. package/lib/task/control-authority.ts +1 -1
  59. package/lib/task/events.ts +6 -6
  60. package/lib/task/intermediate-cleanup.ts +18 -2
  61. package/lib/task/local-artifact-finalization.ts +85 -11
  62. package/lib/task/review-command.ts +1 -1
  63. package/lib/task/review-finalization.ts +203 -8
  64. package/lib/{host-control → task}/secure-fs.ts +10 -32
  65. package/lib/task/workflow-command.ts +2 -0
  66. package/lib/task/workflow-dispatch.ts +171 -0
  67. package/package.json +1 -1
  68. package/templates/.agents/rules/issue-sync.en.md +9 -1
  69. package/templates/.agents/rules/issue-sync.zh-CN.md +10 -3
  70. package/templates/.agents/rules/local-artifact-repair.en.md +7 -6
  71. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +10 -8
  72. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  73. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
  74. package/templates/.agents/skills/restore-task/SKILL.en.md +9 -4
  75. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +9 -4
  76. package/templates/.agents/skills/review-analysis/SKILL.en.md +1 -1
  77. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +1 -1
  78. package/templates/.agents/skills/review-code/SKILL.en.md +3 -2
  79. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +3 -2
  80. package/templates/.agents/skills/review-plan/SKILL.en.md +1 -1
  81. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +1 -1
  82. package/dist/lib/host-control/audit.js +0 -19
  83. package/dist/lib/host-control/client.js +0 -142
  84. package/dist/lib/host-control/command.js +0 -49
  85. package/dist/lib/host-control/path.js +0 -160
  86. package/dist/lib/host-control/server.js +0 -159
  87. package/dist/lib/host-control/service.js +0 -112
  88. package/dist/lib/internal/host-control.js +0 -28
  89. package/lib/host-control/audit.ts +0 -22
  90. package/lib/host-control/client.ts +0 -172
  91. package/lib/host-control/command.ts +0 -60
  92. package/lib/host-control/path.ts +0 -167
  93. package/lib/host-control/server.ts +0 -180
  94. package/lib/host-control/service.ts +0 -133
  95. package/lib/internal/host-control.ts +0 -28
@@ -13,6 +13,9 @@
13
13
  | `artifactChunk` | `<!-- sync-issue:{task-id}:{artifact-stem}:{part}/{total} -->` |
14
14
  | `summary` | `<!-- sync-issue:{task-id}:summary -->` |
15
15
  | `cancel` | `<!-- sync-issue:{task-id}:cancel -->` |
16
+ | `recoveryAction` | `<!-- sync-issue:{task-id}:recovery-action:{action-id} -->` |
17
+ | `recoveryPrepare` | `<!-- sync-issue:{task-id}:recovery-prepare:{commit-id} -->` |
18
+ | `recoveryCommit` | `<!-- sync-issue:{task-id}:recovery-commit:{commit-id} -->` |
16
19
 
17
20
  `prSummary` 属于 `.agents/rules/pr-sync.md`,本规则不实现 PR 聚合。
18
21
 
@@ -25,15 +28,19 @@
25
28
  ```bash
26
29
  agent-infra-internal platform-context resolve [--cwd <path>]
27
30
  agent-infra-internal platform-comment list --issue <issue-token> [--cwd <path>]
31
+ agent-infra-internal platform-comment recover --issue <issue-token> --task-id <TASK-id> \
32
+ --output <.agents/workspace/.restore-staging-*/task.md> [--cwd <path>]
28
33
  agent-infra-internal platform-comment owner <task-ref>
29
34
  agent-infra-internal platform-comment sync <task-ref> \
30
- --kind task|artifact|summary|cancel --agent {standard-agent-token} \
35
+ --kind task|artifact|summary|cancel|recovery-action|recovery-prepare|recovery-commit --agent {standard-agent-token} \
31
36
  [--artifact <canonical.md>] [--body-file <path|->] [--backfill]
32
37
  ```
33
38
 
34
39
  - `applied|no-op|degraded` → exit 0;`failed` → exit 1;`blocked` → exit 2。
35
- - task 评论保持 `<details>` frontmatter 可逆格式;artifact 原文内联并在超过 profile 上限时使用 `artifactChunk`。
36
- - task 内容超过平台评论字节上限时不上传,返回 `COMMENT_PAYLOAD_TOO_LARGE` 的 skipped 操作;本地 task 文件保持不变,platform verification 同样跳过 task marker/content 检查。
40
+ - task 评论保持 `<details>` frontmatter 可逆格式,只同步确定性的当前任务投影;活动日志、产物生命周期收据、失效记录等过程章节由 recovery 事务保存。artifact 原文内联并在超过 profile 上限时使用 `artifactChunk`。
41
+ - 长度预检与 platform verification 使用同一最终渲染正文的 UTF-8 字节数。正文超限时失败关闭;本地 task 文件不会被截断。
42
+
43
+ 恢复评论使用 `recovery-action`、`recovery-prepare` 和 `recovery-commit` marker,并携带稳定 recovery id 和 body file。task 同步按 prepare、action、task snapshot 写入并复读、commit 的顺序发布。相同内容重放返回 `no-op`;已有恢复 marker 的正文不同返回 `RECOVERY_IMMUTABLE_CONFLICT`。restore 只接受作者一致、分片完整、phase/摘要/marker 匹配且绑定当前 task 评论正文 SHA-256 的完整事务。
37
44
  - 相同 intent 重放必须收敛为 `no-op`;重复 marker 返回 `COMMENT_MARKER_CONFLICT` 且不写入。
38
45
  - 外部贡献者锁定统一使用 `platform-comment owner`;不同作者且无 triage 时返回 `COMMENT_OWNER_CONFLICT`。
39
46
 
@@ -7,8 +7,8 @@ This rule covers the pre-completion gate for `analyze-task`, `plan-task`, and `c
7
7
  - Run the applicable finalizer before a completed event; pass only that invocation's `artifactSha256` and `semanticDigest` to the event.
8
8
  - When artifact content is invalid, the finalizer returns a controlled `recovery` with a `recoveryId`, `candidatePath`, and baseline digests. The formal artifact remains unchanged until recovery commit.
9
9
  - After the mechanical safety gates pass, the model may edit only the returned `candidatePath`. After each byte-changing edit, rerun the complete finalizer with the same task, stage/family, artifact, and `--recovery-id`. Never edit the formal artifact directly and call it a candidate.
10
- - A successful finalizer commits through `finalize-ready → commit-started → passed`; completed events accept only matching `passed` final digests and consume the intent under the task lock.
11
- - Before `finalize-ready`, the recovery core seals the validated final bytes in the controlled `final.md`; later commit ignores the editable `candidate.md` and validates/publishes only that sealed snapshot, so a post-prepare candidate replacement cannot be published.
10
+ - Preflight stable-reads and validates candidate `S`, then seals immutable digest-addressed generation `R`; candidate SHA is an observation rather than an edit guard.
11
+ - Preflight publishes active `R` through `preflight-ready → preflight-commit-started → preflight-passed`; the business finalizer publishes `F` through `full-finalizer-ready → commit-started → passed` and reuses `R` when `F=R`.
12
12
  - Candidate-only is a protocol authorization boundary, not OS isolation: a same-UID process with arbitrary host filesystem write access may tamper with recovery internals. Identity, fingerprint, and state checks detect such anomalies and fail closed, but the protocol does not claim an independent security principal or cross-platform isolation.
13
13
 
14
14
  ## Authorization boundary
@@ -32,14 +32,15 @@ If any condition fails, stop without editing or publishing a completed event.
32
32
 
33
33
  | State | Formal artifact | Allowed action |
34
34
  | --- | --- | --- |
35
- | `awaiting-recovery` | baseline `B` | Edit only controlled candidate `S`; rerun the same finalizer |
36
- | `finalize-ready` | `B` | Recovery core starts the commit under the task lock |
37
- | `commit-started` | `B` or final `F` | Reconcile only; retry, confirm, or restore from verified `B/F` fingerprints |
35
+ | `awaiting-preflight-recovery` | baseline `B` | Edit `S`; stable-read, validate, and create `R` |
36
+ | `preflight-ready` / `preflight-commit-started` | `B` or `R` | Reconcile/publish only active immutable `R` |
37
+ | `preflight-passed` | `R` | Run the business finalizer for `F` |
38
+ | `full-finalizer-ready` / `commit-started` | `R` or `F` | Reconcile/publish only pending immutable `F` |
38
39
  | `passed` | `F` | Completed event validates the final digest and consumes the intent |
39
40
  | `consumed` | `F` | Cleanup may reclaim the controlled staging and backup |
40
41
  | `aborted` | verified restored `B` | Preserve diagnostics; never fabricate success |
41
42
 
42
- The intent is current-only schema version 3. Legacy schemas fail closed; do not add migration, adapters, or dual writes. Candidate, baseline, and intent files live in controlled repo-local directories and use canonical recovery IDs, regular-file checks, stable reads, the task lock, and expected-value CAS. No cross-file atomicity is claimed; unknown combinations remain indeterminate and retain their evidence.
43
+ The intent is current-only schema version 4. Legacy schemas fail closed; do not add migration, adapters, or dual writes. Candidate, baseline, generation, and intent files live in controlled repo-local directories and use canonical recovery IDs, regular-file checks, stable reads, the task lock, and expected-value CAS. No cross-file atomicity is claimed; unknown combinations remain indeterminate and retain their evidence.
43
44
 
44
45
  ## Dynamic convergence loop
45
46
 
@@ -5,10 +5,11 @@
5
5
  ## 完成前门禁
6
6
 
7
7
  - 完成事件前必须运行对应 finalizer;只有同一次返回的 `artifactSha256` 和 `semanticDigest` 才能传给 completed event。
8
- - finalizer 发现 artifact 内容错误时,返回受控 `recovery`(`recoveryId`、`candidatePath`、baseline 指纹)。正式 artifact 在 recovery commit 前必须保持不变。
8
+ - preflight 先对当前 stable-read candidate 完整验证,并将验证的 `R` 写入 digest-addressed、只读的 generation;在 journal CAS 前正式 artifact 必须保持 baseline `B`。
9
+ - candidate SHA 是 awaiting 状态的最后一次 stable-read 观测值,不是下一次编辑的 guard。合法 `S` 编辑必须重新验证并在成功后 CAS 为 `R`。
9
10
  - 只有在机械安全门通过后,模型才可编辑返回的 `candidatePath`;每次实际字节变化后,用同一 task、stage/family、artifact 和 `--recovery-id` 完整重跑 finalizer。不得直接编辑正式 artifact 后假设它属于候选。
10
- - finalizer 通过后,recovery core 按 `finalize-ready → commit-started → passed` 提交候选;completed event 只接受匹配的 `passed`/final digest,并在任务锁内消费 intent。
11
- - `finalize-ready` 前 recovery core 会把已校验的最终字节封存为受控 `final.md`;后续 commit 忽略可编辑的 `candidate.md`,只校验并发布该封存快照,避免候选在准备后被替换。
11
+ - preflight 按 `preflight-ready → preflight-commit-started → preflight-passed` 发布 immutable `R`;业务 finalizer 再按 `full-finalizer-ready → commit-started → passed` 将 `F` 发布。`F=R` 复用 active generation。
12
+ - preflight-ready 后 publish 只读取 active/pending generation,绝不再读取可编辑 candidate。
12
13
  - candidate-only 是协议授权边界,不是操作系统隔离:拥有同一 UID 且可任意写入宿主文件系统的进程可能篡改 recovery 内部文件;协议会通过身份、指纹和状态校验发现异常并失败关闭,但不承诺独立权限主体或跨平台隔离。
13
14
 
14
15
  ## 授权边界
@@ -32,14 +33,15 @@
32
33
 
33
34
  | 状态 | formal artifact | 允许动作 |
34
35
  | --- | --- | --- |
35
- | `awaiting-recovery` | baseline `B` | 只编辑受控 candidate `S`,重跑同一 finalizer |
36
- | `finalize-ready` | `B` | recovery core 在锁内开始提交 |
37
- | `commit-started` | `B` 或 final `F` | 只允许 reconcile;按 `B/F` 指纹重试、确认或回滚 |
36
+ | `awaiting-preflight-recovery` | baseline `B` | 只编辑 candidate `S`,稳定读取、验证并生成 `R` |
37
+ | `preflight-ready` / `preflight-commit-started` | `B` 或 `R` | 只可从 active immutable `R` reconcile/publish |
38
+ | `preflight-passed` | `R` | 执行业务 finalizer,生成或复用 `F` |
39
+ | `full-finalizer-ready` / `commit-started` | `R` 或 `F` | 只可从 pending immutable `F` reconcile/publish |
38
40
  | `passed` | `F` | completed event 校验 final digest 后消费 |
39
41
  | `consumed` | `F` | 可由中间产物清理流程回收受控 staging/backup |
40
42
  | `aborted` | 已确认恢复的 `B` | 只保留诊断,不得伪造成功 |
41
43
 
42
- intent 使用 current-only schema version 3。旧 schema 直接失败关闭;不添加迁移、adapter 或双写。candidate、baseline 和 intent 位于 repo-local 受控目录,使用 canonical recovery ID、普通文件检查、stable read、task lock 和 expected-value CAS。跨文件不宣称原子性;未知组合返回 indeterminate 并保留现场。
44
+ intent 使用 current-only schema version 4。旧 schema 直接失败关闭;不添加迁移、adapter 或双写。candidate、baseline、generation 和 intent 位于 repo-local 受控目录,使用 canonical recovery ID、普通文件检查、stable read、task lock 和 expected-value CAS。跨文件不宣称原子性;未知组合返回 indeterminate 并保留现场。
43
45
 
44
46
  ## 动态收敛循环
45
47
 
@@ -50,7 +52,7 @@ intent 使用 current-only schema version 3。旧 schema 直接失败关闭;
50
52
 
51
53
  ## 共享入口
52
54
 
53
- `task-artifact ... inspect|init|finalize-local` 和 `task-review ... finalize-summary` 是当前入口。恢复重试使用 finalizer 返回的 `recoveryId`,例如:
55
+ `task-artifact ... inspect|init|preflight|finalize-local` 和 `task-review ... finalize-summary` 是当前入口。preflight 不发布 task metadata、ledger、formal provenance、completed event 或平台状态;恢复重试使用 finalizer 返回的 `recoveryId`,例如:
54
56
 
55
57
  ```text
56
58
  agent-infra-internal task-artifact {task-id} finalize-local --family code --artifact {code-artifact} --recovery-id {recovery-id}
@@ -24,7 +24,7 @@ Before generating the implementation report, read `.agents/rules/evidence-report
24
24
  - Before generating task or lifecycle Markdown that will be synchronized to an Issue, read `.agents/rules/sync-content-generation.md` and apply its producer-side constraints; the sync path does not parse or rewrite the body
25
25
  - Read `.agents/rules/compatibility-policy.md` before implementation. Implement only the compatibility budget explicitly approved by the plan; never retain old branches, result contracts, or migration shims merely to be “safe”
26
26
  - Fix mode verifies each finding of the latest `review-code` one by one: fix it if it holds, or rebut it and record it under unresolved if it is unfounded/hallucinated; do not expand to issues the review did not list; manual-validation items are out of scope
27
- - Before `code.completed`, the implementation report must pass `task-artifact ... finalize-local --family code`; follow `.agents/rules/local-artifact-repair.md` for controlled recovery candidates in that same report, and pass only that successful call's digests to the completion event
27
+ - Before a checkpoint, ledger write, or `code.completed`, the implementation report must pass `task-artifact ... preflight --family code`. Preflight only validates and seals a generation; `finalize-local` publishes the matching final digest later.
28
28
  - If implementation encounters a key design decision not covered by the plan, run `agent-infra-internal task-ledger {task-id} decision-next-id`, write the returned `HD-N` detail block per `.agents/rules/human-decision-context.md` and determine whether implementation is required, then run `decision-upsert --id {HD-N} --stage code --artifact {code-artifact} --needs-implementation {true|false}`. Do not scan ids, assemble ledger rows, ask mid-flow, or silently expand scope
29
29
  - Do not invoke the `commit` skill or push to a remote; after tests pass, call the shared commit core with `delivery: { mode: 'local' }` to create the local checkpoint. The durable intent must close only after the checkpoint and task state sync succeed; only then emit `code.completed`
30
30
  - Create a new code artifact for each round and never overwrite an older one
@@ -24,7 +24,7 @@ description: >
24
24
  - 生成会同步到 Issue 的任务或生命周期 Markdown 前,先读取 `.agents/rules/sync-content-generation.md` 并遵循其中的生成端约束;同步端不解析或改写正文
25
25
  - 实现前读取 `.agents/rules/compatibility-policy.md`;只实现方案明确批准的兼容预算,不以“稳妥”为由保留旧分支、旧结果契约或迁移 shim
26
26
  - 修复模式逐条核实最新 `review-code` 的发现:成立则修复,判定为不成立/幻觉则在报告中反驳并记入 unresolved;不擅自扩大到审查未列出的问题;manual-validation 项不在修复范围
27
- - 实现报告在 `code.completed` 前必须通过 `task-artifact ... finalize-local --family code`;按 `.agents/rules/local-artifact-repair.md` 使用受控 recovery candidate 处理同一报告内可证明安全的结构修复,并只把同一次通过结果的摘要传给完成事件
27
+ - 实现报告在 checkpoint、账本和 `code.completed` 前必须先通过 `task-artifact ... preflight --family code`;preflight 只验证并封存 generation,不发布 formal/task/ledger/platform 状态。随后 `finalize-local` 才发布同一次通过的 digest。
28
28
  - 实现中遇到方案未覆盖的关键设计决策时,先调用 `agent-infra-internal task-ledger {task-id} decision-next-id` 取得 `HD-N`,按 `.agents/rules/human-decision-context.md` 写入实现报告的 `## 人工裁决待办` 详情块并判断是否需要实现,再调用 `decision-upsert --id {HD-N} --stage code --artifact {code-artifact} --needs-implementation {true|false}`;不得扫描编号、手写账本行、中途提问或擅自扩范围
29
29
  - 不调用 `commit` 技能,也不推送远端;测试通过后直接调用共享 commit core 的 `delivery: { mode: 'local' }` 创建本地 checkpoint。checkpoint 使用 durable intent,只有 checkpoint 与 task 状态同步成功后才发送 `code.completed`
30
30
  - 每轮实现都创建新的实现产物,不覆盖旧文件
@@ -148,7 +148,7 @@ echo "$result"
148
148
 
149
149
  如果测试失败,先尝试修复并重新运行测试。只有在确认存在外部阻塞、环境缺失或需求不明确且超出任务范围时,才可以停止。
150
150
 
151
- 测试通过后,通过 `agent-infra-internal git-workflow commit --input {checkpoint-input}` 调用共享 commit core,输入 `delivery: { "mode": "local" }`、明确 paths、expected HEAD/tree、task ref、agent 和 code round。该调用只创建本地 checkpoint,不访问远端;core 会在 commit 前写入 durable intent,并在 task writer 成功后清理 intent。checkpoint 失败或 task 状态未闭合时,不得发送 `code.completed`。
151
+ 测试通过后,先创建报告并运行 `task-artifact {task-id} preflight --family code --artifact {code-artifact}`;preflight 失败只允许在同一受控 candidate 中修复并完整重跑,且不得产生 checkpoint、ledger、completed 或平台副作用。preflight 通过后,才通过 `agent-infra-internal git-workflow commit --input {checkpoint-input}` 调用共享 commit core,输入 `delivery: { "mode": "local" }`、明确 paths、expected HEAD/tree、task ref、agent 和 code round。该调用只创建本地 checkpoint,不访问远端;core 会在 commit 前写入 durable intent,并在 task writer 成功后清理 intent。checkpoint 失败或 task 状态未闭合时,不得发送 `code.completed`。
152
152
 
153
153
  checkpoint 成功后,若任务存在 `platform_issue_identity`,调用 `agent-infra-internal platform-issue sync {task-id} --agent {standard-agent-token} --in-labels from-diff --base {delivery-base-ref}`,由 task-bound `delivery_base_ref` 产生 Issue 的 `in:` target;该同步失败时记录 warning 并停止本轮,不发送 `code.completed`。
154
154
 
@@ -45,13 +45,14 @@ Run `agent-infra-internal platform-comment list --issue {issue-token}` to read a
45
45
 
46
46
  ### 3. Determine the task-id and Files to Restore
47
47
 
48
- Filter comments by the task, artifact, and chunked artifact markers defined in `.agents/rules/issue-sync.md`.
48
+ Filter comments by the task, artifact, chunked artifact, and recovery markers defined in `.agents/rules/issue-sync.md`.
49
49
 
50
50
  Rules:
51
51
  - when `{task-id}` was provided, match only that task
52
52
  - when `{task-id}` was omitted, infer it from the task comment marker first
53
53
  - if you cannot determine a unique task-id, stop and tell the user
54
54
  - ignore `summary` marker comments because they are complete-task aggregate output rather than restorable local task files
55
+ - use the `task` comment only for the current projection and snapshot identity; the controlled recovery core validates `recovery-action`, `recovery-prepare`, and `recovery-commit` comments and reconstructs the complete `task.md`
55
56
  - map `{file-stem}` back to filenames:
56
57
  - `task` -> `task.md`
57
58
  - `analysis` / `analysis-r{N}` -> matching `.md`
@@ -68,7 +69,7 @@ Read `.agents/rules/issue-sync.md` before executing this step.
68
69
 
69
70
  For each file:
70
71
  - collect its single comment or chunked comments
71
- - for `task.md` comments, reverse the `<details>` frontmatter wrapper described in issue-sync.md before reassembling the file body
72
+ - do not reverse the projected task comment directly into `task.md`; the complete task content must come from a recovery commit matching the current projection
72
73
  - when a chunk marker includes part and total indexes, sort by part and verify the set is complete
73
74
  - extract the file body by removing the hidden marker, heading, and footer
74
75
  - concatenate chunk bodies into the final file content
@@ -83,10 +84,14 @@ If the directory already exists, stop immediately and tell the user to handle it
83
84
 
84
85
  Create the controlled staging directory and write files back in this order:
85
86
 
86
- 1. `task.md`
87
+ 1. call the recovery core to write `task.md`:
88
+ ```bash
89
+ agent-infra-internal platform-comment recover --issue {issue-token} --task-id {task-id} \
90
+ --output "{staging-dir}/task.md"
91
+ ```
87
92
  2. every other restored artifact file in filename order
88
93
 
89
- Write only files that were actually recovered from Issue comments. Do not invent missing files.
94
+ Write only files that were actually recovered from Issue comments. Do not invent missing files. Stop without calling the lifecycle intent if the recovery core fails.
90
95
 
91
96
  ### 6. Apply the Restore Lifecycle Intent
92
97
 
@@ -44,13 +44,14 @@ description: >
44
44
 
45
45
  ### 3. 确定 task-id 与待恢复文件
46
46
 
47
- 按 `.agents/rules/issue-sync.md` 中定义的 task、artifact 和分片 artifact 标记筛选评论。
47
+ 按 `.agents/rules/issue-sync.md` 中定义的 task、artifact、分片 artifact 和 recovery 标记筛选评论。
48
48
 
49
49
  处理规则:
50
50
  - 用户提供了 `{task-id}` 时,仅匹配该任务
51
51
  - 未提供时,优先从 task 评论标记推断
52
52
  - 若找不到唯一 task-id,立即停止并告知用户
53
53
  - 忽略 `summary` 标记评论;它是 complete-task 的聚合产物,不对应本地任务文件
54
+ - `task` 评论仅用于确定当前投影和 snapshot 身份;`recovery-action`、`recovery-prepare`、`recovery-commit` 由受控 recovery core 验证并重建完整 `task.md`
54
55
  - 将 `{file-stem}` 映射回文件名:
55
56
  - `task` -> `task.md`
56
57
  - `analysis` / `analysis-r{N}` -> 对应 `.md`
@@ -67,7 +68,7 @@ description: >
67
68
 
68
69
  对每个文件执行:
69
70
  - 收集单条评论或分片评论
70
- - 对 `task.md` 评论按 issue-sync.md 中的 `<details>` frontmatter 格式反向拆解,提取 frontmatter 后再与正文拼合
71
+ - 不直接把投影 task 评论反向拆成 `task.md`;完整 task 内容必须来自匹配当前投影的 recovery commit
71
72
  - 如分片标记中存在 part 和 total 序号,按 part 升序排序并校验分片完整
72
73
  - 从评论正文中提取文件内容,去掉隐藏标记、标题和页脚
73
74
  - 拼接得到最终文件内容
@@ -82,10 +83,14 @@ description: >
82
83
 
83
84
  创建受控 staging 目录,按以下顺序写回:
84
85
 
85
- 1. `task.md`
86
+ 1. 调用 recovery core 写入 `task.md`:
87
+ ```bash
88
+ agent-infra-internal platform-comment recover --issue {issue-token} --task-id {task-id} \
89
+ --output "{staging-dir}/task.md"
90
+ ```
86
91
  2. 其余产物文件(按文件名排序)
87
92
 
88
- 仅写回从 Issue 评论中实际恢复出的文件,不补造缺失文件。
93
+ 仅写回从 Issue 评论中实际恢复出的文件,不补造缺失文件。recovery core 返回失败时停止,不调用 lifecycle intent。
89
94
 
90
95
  ### 6. 执行 restore 生命周期意图
91
96
 
@@ -83,7 +83,7 @@ Create `.agents/workspace/active/{task-id}/{review-artifact}`.
83
83
 
84
84
  ### 6. Update Task Status
85
85
 
86
- After the report, submit each new finding with `agent-infra-internal task-ledger {task-id} finding-upsert --stage analysis --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`; submit prior-response dispositions with `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {evidence}`. Do not scan ids or edit ledger rows. After all ledger writes, make the initial call to `agent-infra-internal task-review {task-id} finalize-summary --stage analysis --artifact {review-artifact} {execution-flag}`; after a failure, follow `.agents/rules/local-artifact-repair.md` to decide whether to edit and rerun, and never treat an error type or `changed=false` as automatic authorization.
86
+ After the report, call `agent-infra-internal task-review {task-id} preflight --stage analysis --artifact {review-artifact} {execution-flag}` before any ledger write. On failure, follow `.agents/rules/local-artifact-repair.md`; on success, bind `{recovery-id}` from the response. Only after preflight passes, submit each new finding with `agent-infra-internal task-ledger {task-id} finding-upsert --stage analysis --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}` or prior-response dispositions with `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {evidence}`. Do not scan ids or edit ledger rows. After all ledger writes, call `agent-infra-internal task-review {task-id} finalize-summary --stage analysis --artifact {review-artifact} --recovery-id {recovery-id} {execution-flag}`; never treat an error type or `changed=false` as automatic authorization.
87
87
 
88
88
  Bind and reuse this structured mapping from that one response:
89
89
 
@@ -86,7 +86,7 @@ agent-infra-internal task-artifact {task-id} init --family review-analysis --art
86
86
 
87
87
  ### 6. 更新任务状态
88
88
 
89
- 报告完成后,新 finding 逐条调用 `agent-infra-internal task-ledger {task-id} finding-upsert --stage analysis --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`;复核上一轮响应时调用 `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {相称证据}`。不得扫描编号或手写账本行。全部账本写入完成后首次调用 `agent-infra-internal task-review {task-id} finalize-summary --stage analysis --artifact {review-artifact} {execution-flag}`;失败后是否继续编辑并重跑,必须遵循 `.agents/rules/local-artifact-repair.md`,不能把失败类型或 `changed=false` 当作自动授权。
89
+ 报告完成后,先调用 `agent-infra-internal task-review {task-id} preflight --stage analysis --artifact {review-artifact} {execution-flag}`,不得先写入账本。失败后是否继续编辑并重跑,必须遵循 `.agents/rules/local-artifact-repair.md`;通过时从返回值绑定 `{recovery-id}`。只有 preflight 通过后,才逐条调用 `agent-infra-internal task-ledger {task-id} finding-upsert --stage analysis --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`,或复核上一轮响应时调用 `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {相称证据}`。不得扫描编号或手写账本行。全部账本写入完成后调用 `agent-infra-internal task-review {task-id} finalize-summary --stage analysis --artifact {review-artifact} --recovery-id {recovery-id} {execution-flag}`;不能把失败类型或 `changed=false` 当作自动授权。
90
90
 
91
91
  从该次返回值绑定并复用以下结构化映射:
92
92
 
@@ -111,8 +111,9 @@ Create `.agents/workspace/active/{task-id}/{review-artifact}`.
111
111
  ### 6. Update Task Status
112
112
 
113
113
  Update task.md:
114
- - After the report, submit each new finding with `agent-infra-internal task-ledger {task-id} finding-upsert --stage code --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`; submit prior-response dispositions with `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {evidence}`. When escalating to `needs-human-decision`, append `--needs-implementation true|false` using the judgment recorded in the detail block. Do not scan ids or edit ledger rows
115
- - After all ledger writes, make the initial call to `agent-infra-internal task-review {task-id} finalize-summary --stage code --artifact {review-artifact} {execution-flag}`; after a failure, follow `.agents/rules/local-artifact-repair.md` to decide whether to edit and rerun, and never treat an error type or `changed=false` as automatic authorization
114
+ - After the report, call `agent-infra-internal task-review {task-id} preflight --stage code --artifact {review-artifact} {execution-flag}` before any ledger write. On failure, follow `.agents/rules/local-artifact-repair.md`; on success, bind `{recovery-id}` from the response.
115
+ - Only after preflight passes, submit each new finding with `agent-infra-internal task-ledger {task-id} finding-upsert --stage code --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`; submit prior-response dispositions with `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {evidence}`. When escalating to `needs-human-decision`, append `--needs-implementation true|false` using the judgment recorded in the detail block. Do not scan ids or edit ledger rows
116
+ - After all ledger writes, call `agent-infra-internal task-review {task-id} finalize-summary --stage code --artifact {review-artifact} --recovery-id {recovery-id} {execution-flag}`; never treat an error type or `changed=false` as automatic authorization
116
117
 
117
118
  Bind and reuse this structured mapping from that one response:
118
119
 
@@ -109,8 +109,9 @@ agent-infra-internal task-artifact {task-id} init --family review-code --artifac
109
109
 
110
110
  ### 6. 更新任务状态
111
111
 
112
- - 报告完成后,新 finding 逐条调用 `agent-infra-internal task-ledger {task-id} finding-upsert --stage code --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`;复核上一轮响应时调用 `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {相称证据}`。升级为 `needs-human-decision` 时,按详情块中的判断追加 `--needs-implementation true|false`。不得扫描编号或手写账本行
113
- - 全部账本写入完成后首次调用 `agent-infra-internal task-review {task-id} finalize-summary --stage code --artifact {review-artifact} {execution-flag}`;失败后是否继续编辑并重跑,必须遵循 `.agents/rules/local-artifact-repair.md`,不能把失败类型或 `changed=false` 当作自动授权
112
+ - 报告完成后,先调用 `agent-infra-internal task-review {task-id} preflight --stage code --artifact {review-artifact} {execution-flag}`,不得先写入账本。失败后是否继续编辑并重跑,必须遵循 `.agents/rules/local-artifact-repair.md`;通过时从返回值绑定 `{recovery-id}`。
113
+ - 只有 preflight 通过后,新 finding 才逐条调用 `agent-infra-internal task-ledger {task-id} finding-upsert --stage code --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`;复核上一轮响应时调用 `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {相称证据}`。升级为 `needs-human-decision` 时,按详情块中的判断追加 `--needs-implementation true|false`。不得扫描编号或手写账本行
114
+ - 全部账本写入完成后调用 `agent-infra-internal task-review {task-id} finalize-summary --stage code --artifact {review-artifact} --recovery-id {recovery-id} {execution-flag}`;不能把失败类型或 `changed=false` 当作自动授权
114
115
 
115
116
  从该次返回值绑定并复用以下结构化映射:
116
117
 
@@ -83,7 +83,7 @@ Create `.agents/workspace/active/{task-id}/{review-artifact}`.
83
83
 
84
84
  ### 6. Update Task Status
85
85
 
86
- After the report, submit each new finding with `agent-infra-internal task-ledger {task-id} finding-upsert --stage plan --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`; submit prior-response dispositions with `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {evidence}`. Do not scan ids or edit ledger rows. After all ledger writes, make the initial call to `agent-infra-internal task-review {task-id} finalize-summary --stage plan --artifact {review-artifact} {execution-flag}`; after a failure, follow `.agents/rules/local-artifact-repair.md` to decide whether to edit and rerun, and never treat an error type or `changed=false` as automatic authorization.
86
+ After the report, call `agent-infra-internal task-review {task-id} preflight --stage plan --artifact {review-artifact} {execution-flag}` before any ledger write. On failure, follow `.agents/rules/local-artifact-repair.md`; on success, bind `{recovery-id}` from the response. Only after preflight passes, submit each new finding with `agent-infra-internal task-ledger {task-id} finding-upsert --stage plan --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}` or prior-response dispositions with `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {evidence}`. Do not scan ids or edit ledger rows. After all ledger writes, call `agent-infra-internal task-review {task-id} finalize-summary --stage plan --artifact {review-artifact} --recovery-id {recovery-id} {execution-flag}`; never treat an error type or `changed=false` as automatic authorization.
87
87
 
88
88
  Bind and reuse this structured mapping from that one response:
89
89
 
@@ -86,7 +86,7 @@ agent-infra-internal task-artifact {task-id} init --family review-plan --artifac
86
86
 
87
87
  ### 6. 更新任务状态
88
88
 
89
- 报告完成后,新 finding 逐条调用 `agent-infra-internal task-ledger {task-id} finding-upsert --stage plan --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`;复核上一轮响应时调用 `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {相称证据}`。不得扫描编号或手写账本行。全部账本写入完成后首次调用 `agent-infra-internal task-review {task-id} finalize-summary --stage plan --artifact {review-artifact} {execution-flag}`;失败后是否继续编辑并重跑,必须遵循 `.agents/rules/local-artifact-repair.md`,不能把失败类型或 `changed=false` 当作自动授权。
89
+ 报告完成后,先调用 `agent-infra-internal task-review {task-id} preflight --stage plan --artifact {review-artifact} {execution-flag}`,不得先写入账本。失败后是否继续编辑并重跑,必须遵循 `.agents/rules/local-artifact-repair.md`;通过时从返回值绑定 `{recovery-id}`。只有 preflight 通过后,才逐条调用 `agent-infra-internal task-ledger {task-id} finding-upsert --stage plan --review-artifact {review-artifact} --ordinal {n} --severity {blocker|major|minor} --evidence {review-artifact}#{anchor}`,或复核上一轮响应时调用 `finding-review --id {ledger-id} --status {confirmed|closed|open|needs-human-decision} --evidence {相称证据}`。不得扫描编号或手写账本行。全部账本写入完成后调用 `agent-infra-internal task-review {task-id} finalize-summary --stage plan --artifact {review-artifact} --recovery-id {recovery-id} {execution-flag}`;不能把失败类型或 `changed=false` 当作自动授权。
90
90
 
91
91
  从该次返回值绑定并复用以下结构化映射:
92
92
 
@@ -1,19 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- export const HOST_CONTROL_AUDIT_FILE = 'audit.ndjson';
4
- export function hostControlAuditPath(endpoint) {
5
- return path.join(path.dirname(endpoint), HOST_CONTROL_AUDIT_FILE);
6
- }
7
- export function appendHostControlAudit(endpoint, entry, at = Date.now()) {
8
- const filePath = hostControlAuditPath(endpoint);
9
- const descriptor = fs.openSync(filePath, 'a', 0o600);
10
- try {
11
- fs.fchmodSync(descriptor, 0o600);
12
- fs.writeFileSync(descriptor, `${JSON.stringify({ version: 1, at, ...entry })}\n`, 'utf8');
13
- fs.fsyncSync(descriptor);
14
- }
15
- finally {
16
- fs.closeSync(descriptor);
17
- }
18
- }
19
- //# sourceMappingURL=audit.js.map
@@ -1,142 +0,0 @@
1
- import net from 'node:net';
2
- import { randomUUID } from 'node:crypto';
3
- import { inspectHostControlEndpoint, resolveHostControlEndpoint } from './path.js';
4
- export const HOST_CONTROL_MAX_REQUEST_BYTES = 64 * 1024;
5
- export const HOST_CONTROL_COMMANDS = Object.freeze([
6
- 'task-lifecycle', 'task-orchestration', 'task-finalization',
7
- 'task-artifact', 'task-review', 'task-event', 'task-ledger',
8
- 'task-invalidation', 'task-warning'
9
- ]);
10
- export const HOST_CONTROL_TEST_ENVIRONMENT_KEYS = Object.freeze([
11
- 'TZ', 'AGENT_INFRA_GH_BIN', 'AGENT_INFRA_GH_ARGS_JSON', 'GH_FAKE_PR_PATH', 'GH_FAKE_ARGS_PATH'
12
- ]);
13
- export class HostControlClientError extends Error {
14
- code;
15
- retryable;
16
- changed;
17
- constructor(code, message, retryable = false, submitted = false) {
18
- super(`${code}: ${message}`);
19
- this.name = 'HostControlClientError';
20
- this.code = code;
21
- this.retryable = retryable && !submitted;
22
- this.changed = submitted ? null : false;
23
- }
24
- }
25
- function reject(message) {
26
- throw new HostControlClientError('HOST_CONTROL_REQUEST_INVALID', message);
27
- }
28
- export function validateHostControlRequest(value) {
29
- if (!value || typeof value !== 'object' || Array.isArray(value))
30
- reject('request must be an object');
31
- const request = value;
32
- if (Object.keys(request).sort().join(',') !== 'generation,id,operation,payload,scope,taskId,version'
33
- || request.version !== 1 || typeof request.id !== 'string' || !/^[a-f0-9-]{16,64}$/u.test(request.id)
34
- || (request.taskId !== null && (typeof request.taskId !== 'string' || !/^TASK-\d{8}-\d{6}$/u.test(request.taskId)))
35
- || (request.generation !== null && (typeof request.generation !== 'string' || !request.generation))
36
- || request.scope !== 'host-command' || !HOST_CONTROL_COMMANDS.includes(request.operation))
37
- reject('request schema is invalid');
38
- const payload = request.payload;
39
- if (!payload || typeof payload !== 'object' || Array.isArray(payload)
40
- || !['args,environment,workingDirectory', 'args,workingDirectory'].includes(Object.keys(payload).sort().join(','))
41
- || !Array.isArray(payload.args) || payload.args.length > 128
42
- || !payload.args.every((arg) => typeof arg === 'string' && !/[\r\n]/u.test(arg))
43
- || typeof payload.workingDirectory !== 'string' || !payload.workingDirectory.startsWith('/'))
44
- reject('host-command payload is invalid');
45
- if (payload.environment !== undefined) {
46
- if (!payload.environment || typeof payload.environment !== 'object' || Array.isArray(payload.environment))
47
- reject('host-command environment is invalid');
48
- for (const [key, value] of Object.entries(payload.environment)) {
49
- if (!HOST_CONTROL_TEST_ENVIRONMENT_KEYS.includes(key)
50
- || typeof value !== 'string' || /[\r\n]/u.test(value))
51
- reject('host-command environment is invalid');
52
- }
53
- }
54
- return request;
55
- }
56
- export function hostControlRequestForCommand(command, args, workingDirectory, environment = {}) {
57
- if (!HOST_CONTROL_COMMANDS.includes(command))
58
- reject('host-command is unsupported');
59
- const taskArg = args[0];
60
- const taskId = taskArg && /^TASK-\d{8}-\d{6}$/u.test(taskArg) ? taskArg : null;
61
- return validateHostControlRequest({
62
- version: 1,
63
- id: randomUUID(),
64
- taskId,
65
- generation: null,
66
- operation: command,
67
- scope: 'host-command',
68
- payload: {
69
- workingDirectory,
70
- args: [...args],
71
- ...(Object.keys(environment).length > 0 ? { environment } : {})
72
- }
73
- });
74
- }
75
- function parseResponse(value, id) {
76
- if (!value || typeof value !== 'object' || Array.isArray(value))
77
- throw new HostControlClientError('HOST_CONTROL_RESPONSE_INVALID', 'response must be an object');
78
- const response = value;
79
- if (Object.keys(response).sort().join(',') !== 'error,exitCode,id,status,stderr,stdout,version'
80
- || response.version !== 1 || response.id !== id
81
- || !['completed', 'rejected', 'unknown'].includes(response.status)
82
- || !Number.isSafeInteger(response.exitCode)
83
- || typeof response.stdout !== 'string' || typeof response.stderr !== 'string'
84
- || (response.error !== null && (!response.error || typeof response.error !== 'object'))) {
85
- throw new HostControlClientError('HOST_CONTROL_RESPONSE_INVALID', 'response schema is invalid');
86
- }
87
- return response;
88
- }
89
- export async function requestHostControl(params) {
90
- const request = validateHostControlRequest(params.request);
91
- const endpoint = params.endpoint ?? resolveHostControlEndpoint();
92
- const inspection = inspectHostControlEndpoint(endpoint, { uid: process.getuid?.() });
93
- if (!inspection.ok)
94
- throw new HostControlClientError(inspection.code ?? 'HOST_CONTROL_UNAVAILABLE', 'fixed host-control endpoint is unavailable', true);
95
- const encoded = `${JSON.stringify(request)}\n`;
96
- if (Buffer.byteLength(encoded, 'utf8') > HOST_CONTROL_MAX_REQUEST_BYTES)
97
- throw new HostControlClientError('HOST_CONTROL_REQUEST_TOO_LARGE', 'request exceeds the control limit');
98
- const timeoutMs = params.timeoutMs ?? 30_000;
99
- return await new Promise((resolve, rejectPromise) => {
100
- const socket = net.createConnection(endpoint);
101
- let output = '';
102
- let settled = false;
103
- let submitted = false;
104
- const failure = (code, message, retryable = false) => new HostControlClientError(code, message, retryable, submitted);
105
- const finish = (error, response) => {
106
- if (settled)
107
- return;
108
- settled = true;
109
- clearTimeout(timer);
110
- socket.destroy();
111
- if (error)
112
- rejectPromise(error);
113
- else
114
- resolve(response);
115
- };
116
- const timer = setTimeout(() => finish(failure('HOST_CONTROL_TIMEOUT', 'host-control did not respond; inspect task state before retrying', true)), timeoutMs);
117
- socket.setEncoding('utf8');
118
- socket.on('connect', () => { submitted = true; socket.end(encoded); });
119
- socket.on('data', (chunk) => {
120
- output += chunk;
121
- if (Buffer.byteLength(output, 'utf8') > HOST_CONTROL_MAX_REQUEST_BYTES) {
122
- finish(failure('HOST_CONTROL_RESPONSE_TOO_LARGE', 'host-control response exceeds the control limit'));
123
- return;
124
- }
125
- const newline = output.indexOf('\n');
126
- if (newline < 0)
127
- return;
128
- try {
129
- finish(undefined, parseResponse(JSON.parse(output.slice(0, newline)), request.id));
130
- }
131
- catch (error) {
132
- finish(failure('HOST_CONTROL_RESPONSE_INVALID', String(error)));
133
- }
134
- });
135
- socket.on('error', (error) => finish(failure('HOST_CONTROL_UNAVAILABLE', error.message, true)));
136
- socket.on('close', () => {
137
- if (!settled)
138
- finish(failure('HOST_CONTROL_RESPONSE_INVALID', 'host-control closed without a response'));
139
- });
140
- });
141
- }
142
- //# sourceMappingURL=client.js.map
@@ -1,49 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import fs from 'node:fs';
3
- import { fileURLToPath } from 'node:url';
4
- import { readHostControlWorkerToken, resolveHostControlEndpoint } from './path.js';
5
- export async function dispatchHostControlCommand(request) {
6
- const { payload } = request;
7
- const compiledEntry = fileURLToPath(new URL('../../bin/internal-cli.js', import.meta.url));
8
- const sourceEntry = fileURLToPath(new URL('../../bin/internal-cli.ts', import.meta.url));
9
- const entry = fs.existsSync(compiledEntry) ? compiledEntry : sourceEntry;
10
- const payloadEnvironment = payload.environment ?? {};
11
- const env = { ...process.env, ...payloadEnvironment };
12
- for (const key of Object.keys(env)) {
13
- if (key.startsWith('AGENT_INFRA_CONTROL_')
14
- || key === 'AGENT_INFRA_TASK_ID'
15
- || key === 'AGENT_INFRA_RUNTIME_DIR'
16
- || key === 'AGENT_INFRA_EXECUTOR_MANIFEST'
17
- || key === 'AGENT_INFRA_HOST_CONTROL_SOCKET') {
18
- delete env[key];
19
- }
20
- }
21
- delete env.NODE_OPTIONS;
22
- delete env.NODE_PATH;
23
- delete env.AGENT_INFRA_HOST_CONTROL_WORKER;
24
- delete env.AGENT_INFRA_HOST_CONTROL_WORKER_TOKEN;
25
- env.AGENT_INFRA_HOST_CONTROL_WORKER = '1';
26
- env.AGENT_INFRA_HOST_CONTROL_WORKER_TOKEN = readHostControlWorkerToken(process.env.AGENT_INFRA_TEST_HOST_CONTROL_ENDPOINT ?? resolveHostControlEndpoint());
27
- return await new Promise((resolve, reject) => {
28
- const runtimeArgs = entry.endsWith('.ts') ? ['--experimental-strip-types', '--no-warnings', entry] : [entry];
29
- const child = spawn(process.execPath, [...runtimeArgs, request.operation, ...payload.args], {
30
- cwd: payload.workingDirectory,
31
- env,
32
- stdio: ['ignore', 'pipe', 'pipe']
33
- });
34
- let stdout = '';
35
- let stderr = '';
36
- child.stdout.setEncoding('utf8');
37
- child.stderr.setEncoding('utf8');
38
- child.stdout.on('data', (chunk) => { stdout += chunk; });
39
- child.stderr.on('data', (chunk) => { stderr += chunk; });
40
- child.once('error', reject);
41
- child.once('close', (code, signal) => {
42
- if (signal)
43
- reject(new Error(`HOST_CONTROL_WORKER_TERMINATED: ${signal}`));
44
- else
45
- resolve({ stdout, stderr, exitCode: code ?? 1 });
46
- });
47
- });
48
- }
49
- //# sourceMappingURL=command.js.map