@fitlab-ai/agent-infra 0.11.2 → 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/manual-validation.js +22 -27
- package/dist/lib/internal/sandbox-control.js +1 -43
- package/dist/lib/internal/task-lifecycle.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +6 -2
- package/dist/lib/platform/issue-comments.js +2 -31
- package/dist/lib/platform/pr-summary.js +7 -2
- package/dist/lib/sandbox/control/client.js +3 -44
- package/dist/lib/sandbox/control/executor.js +14 -79
- package/dist/lib/sandbox/control/finalization-response.js +3 -5
- 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 +1 -2
- package/dist/lib/task/control-authority.js +34 -36
- package/dist/lib/task/control-recovery.js +3 -42
- package/dist/lib/task/delegation-receipts.js +2 -2
- package/dist/lib/task/finalization-artifacts.js +1 -3
- package/dist/lib/task/finalization-state.js +1 -1
- package/dist/lib/task/finalization.js +53 -126
- package/dist/lib/task/lifecycle.js +1 -1
- package/dist/lib/task/manual-validation-receipt.js +8 -3
- package/dist/lib/task/orchestration.js +12 -6
- 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/manual-validation.ts +22 -26
- package/lib/internal/sandbox-control.ts +0 -42
- package/lib/internal/task-lifecycle.ts +2 -2
- package/lib/internal/task-operation-registry.ts +7 -4
- package/lib/platform/issue-comments.ts +1 -35
- package/lib/platform/pr-summary.ts +10 -2
- package/lib/sandbox/control/client.ts +5 -68
- package/lib/sandbox/control/executor.ts +14 -81
- package/lib/sandbox/control/finalization-response.ts +3 -5
- 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 +1 -2
- package/lib/task/control-authority.ts +38 -47
- package/lib/task/control-recovery.ts +3 -43
- package/lib/task/delegation-receipts.ts +2 -2
- package/lib/task/finalization-artifacts.ts +1 -3
- package/lib/task/finalization-state.ts +1 -1
- package/lib/task/finalization.ts +57 -121
- package/lib/task/lifecycle.ts +2 -2
- package/lib/task/manual-validation-receipt.ts +8 -2
- package/lib/task/orchestration.ts +30 -19
- package/package.json +1 -1
- package/templates/.agents/rules/lifecycle-orchestration.en.md +19 -5
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +19 -5
- 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 +6 -7
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +6 -7
- 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 +9 -8
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +9 -8
- package/dist/lib/sandbox/control/task-workflow.js +0 -74
- package/dist/lib/sandbox/control/workflow-executor.js +0 -142
- 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 -21
- package/dist/lib/task/workflow-dispatch.js +0 -213
- package/lib/sandbox/control/task-workflow.ts +0 -95
- package/lib/sandbox/control/workflow-executor.ts +0 -156
- package/lib/task/lifecycle-recovery.ts +0 -691
- package/lib/task/recovery-warning.ts +0 -21
- package/lib/task/workflow-command.ts +0 -22
- package/lib/task/workflow-dispatch.ts +0 -214
|
@@ -21,7 +21,7 @@ description: >
|
|
|
21
21
|
- 本技能用于收尾已有 PR 摘要评论中的人工校验状态,不创建并行的普通验证留言。
|
|
22
22
|
- 必须写入 `manual-validation.md` 或 `manual-validation-r{N}.md`,让后续 PR 摘要刷新可复用人工验证结果。
|
|
23
23
|
- 找不到 `sync-pr` 摘要评论时失败,不创建部分摘要兜底;receipt、通过日志和 final summary 未全部提交前,远端只允许 pending/non-pass 状态。
|
|
24
|
-
-
|
|
24
|
+
- 生成会由 task 评论和 PR 摘要引用的人工验证 artifact Markdown 前,先读取 `.agents/rules/sync-content-generation.md` 并遵循其中的生成端约束;人工验证 artifact 保留在本地,不发布为 Issue artifact 评论。
|
|
25
25
|
- 执行本技能后必须立即更新 `task.md`。
|
|
26
26
|
|
|
27
27
|
版本戳规则:创建或更新 `task.md` frontmatter 时,先读取 `.agents/rules/version-stamp.md`,并写入或刷新 `agent_infra_version`。
|
|
@@ -106,7 +106,7 @@ coordinator 负责 pending summary、receipt、通过日志、final promotion
|
|
|
106
106
|
|
|
107
107
|
transaction coordinator 成功后,核心已使用同一 transaction/receipt/head identity 原子登记 `manual-validation.completed`;不要手工补写 Activity Log。
|
|
108
108
|
|
|
109
|
-
如任务存在有效 `platform_issue_identity
|
|
109
|
+
如任务存在有效 `platform_issue_identity`,仅调用 `agent-infra-internal platform-comment sync {task-id} --kind task --agent {standard-agent-token}`。人工验证 artifact 继续作为本地证据和 PR 摘要输入,不发布为 Issue 评论。
|
|
110
110
|
|
|
111
111
|
### 8. 完成校验
|
|
112
112
|
|
|
@@ -59,7 +59,7 @@ If not found in `active/`, check `blocked/` and `completed/`:
|
|
|
59
59
|
- If in `completed/` without a matching entry: report the incomplete terminal identity and stop without hand-repairing it
|
|
60
60
|
- If in `blocked/`: Inform user the task is blocked; suggest unblocking first
|
|
61
61
|
|
|
62
|
-
Scenario A is the normal active-task path. Scenario B `finalization-retry` retries
|
|
62
|
+
Scenario A is the normal active-task path. Scenario B `finalization-retry` retries allowed artifact backfill, the terminal task comment, completion verification, and summary sealing without moving lifecycle backward.
|
|
63
63
|
|
|
64
64
|
### 2. Verify Completion Prerequisites (Failure Must Stop)
|
|
65
65
|
|
|
@@ -141,9 +141,8 @@ Check whether task.md has a valid `platform_issue_identity`. If it does not, ski
|
|
|
141
141
|
|
|
142
142
|
When a valid `platform_issue_identity` exists, execute in this exact order:
|
|
143
143
|
|
|
144
|
-
1. Run `agent-infra-internal platform-
|
|
145
|
-
2.
|
|
146
|
-
3. Write the business summary to a temporary file and run `agent-infra-internal platform-comment stage-summary {task-id} --body-file {path}`. This stores the body and SHA-256 in the task's durable staging record; it must not publish the summary comment directly.
|
|
144
|
+
1. Run `agent-infra-internal platform-issue sync {task-id} --agent {standard-agent-token} --requirements --fields`.
|
|
145
|
+
2. Write the business summary to a temporary file and run `agent-infra-internal platform-comment stage-summary {task-id} --body-file {path}`. This stores the body and SHA-256 in the task's durable staging record; it must not publish the summary comment directly.
|
|
147
146
|
|
|
148
147
|
When the ledger contains a valid `PRC-N` post-review exemption, the summary body must mirror the ruling reason, commit scope, human identity, and time from task.md, and state that this is a human override rather than an automatic verification success. If a matching workflow warning exists, also mirror its original failure code/message. If no warning exists yet, state only that the ruling is recorded and final gate verification is pending; do not claim that the exemption has passed. The same `--kind summary` intent remains the sole owner of the summary marker.
|
|
149
148
|
|
|
@@ -152,7 +151,7 @@ Do not sync the task comment here; it requires the terminal task.md written by l
|
|
|
152
151
|
If any operation fails, the task must remain active and its short id must remain valid. Record the failure with the matching structured warning intent, then continue to Step 5. Platform failures do not block the local lifecycle:
|
|
153
152
|
|
|
154
153
|
```bash
|
|
155
|
-
agent-infra-internal task-warning {task-id} add --step complete-task --severity ACTION_REQUIRED --code {
|
|
154
|
+
agent-infra-internal task-warning {task-id} add --step complete-task --severity ACTION_REQUIRED --code {REQUIREMENTS_SYNC_FAILED|SUMMARY_SYNC_FAILED|NETWORK_RETRY_EXHAUSTED} --target {issue|summary|platform} --message "{error_code}: {error_message}" --action "Fix the platform sync problem and rerun complete-task"
|
|
156
155
|
```
|
|
157
156
|
|
|
158
157
|
The core deduplicates the stable `step/code/target` tuple. Callers must not allocate warning ids or edit ledger rows.
|
|
@@ -177,11 +176,11 @@ If a summary must mirror a human-decided `post-review-commit` exemption, make a
|
|
|
177
176
|
agent-infra-internal task-finalization {task-id} complete --agent {standard-agent-token}
|
|
178
177
|
```
|
|
179
178
|
|
|
180
|
-
Finalization runs lifecycle -> terminal task comment -> core verification -> warning task-comment update -> summary
|
|
179
|
+
Finalization runs allowed artifact backfill -> lifecycle -> terminal task comment -> core verification -> warning task-comment update -> summary seal in a fixed order. Every backfill must reach a successful terminal result before lifecycle starts. Summary seal always reads the durable staging record retained in the task directory; the platform entry point validates marker, owner, and digest, performs any required delete/recreate, and reads back final remote order. Re-entry repeats this idempotent operation instead of recovering local input from a remote comment. `result=completed` means the host safely completed the task from structured results and the receipt; if peripheral warnings or pending steps remain, return `result=completed_with_warnings`, warnings, and pending steps. Use `result=failed` or `result=blocked` only for hard or receipt/capability failures, then fix the cause and retry through the same entry point; do not claim completion or hand-repair partial state. A sandbox must not run `ls completed` or a local terminal verification against its historical mount to re-decide this result.
|
|
181
180
|
|
|
182
181
|
### 7. Handle Finalization Retries and Results
|
|
183
182
|
|
|
184
|
-
Both Scenario A and Scenario B `finalization-retry` run the same `task-finalization` entry point from the host. The receipt is only a re-entry hint, not canonical truth: every re-entry revalidates the terminal task comment and completion
|
|
183
|
+
Both Scenario A and Scenario B `finalization-retry` run the same `task-finalization` entry point from the host. The receipt is only a re-entry hint, not canonical truth: every re-entry revalidates allowed artifact backfill, the terminal task comment, and completion verification, then repeats summary seal from the retained durable staging record; only an already `completed` task with its short-id registry entry released may skip the irreversible lifecycle. Do not split the operation into the former lifecycle, comment-sync, or completion-gate commands. If backfill, the task comment, summary seal, or verification is blocked by the network, preserve the receipt, durable staging record, and completed steps, fix the network, and rerun complete-task. If lifecycle has not completed, keep the task active and resume the pending steps from the receipt.
|
|
185
184
|
|
|
186
185
|
Consume the structured finalization result, receipt, and warning projection directly. Continue only for `completed` or `completed_with_warnings`; preserve the receipt and stop for `failed`, `blocked`, or `unknown`, then retry through the same finalization entry point. Do not run `ls completed` or `task-verify complete-task.completed` from a stale sandbox mount, and do not let that local result overrule the host result.
|
|
187
186
|
|
|
@@ -58,7 +58,7 @@ agent-infra-internal task-snapshot {task-id} --format text
|
|
|
58
58
|
- 如果在 `completed/` 但缺少匹配日志:告知用户任务已完成但终态身份不完整并停止,不手工修补
|
|
59
59
|
- 如果在 `blocked/`:告知用户任务被阻塞;建议先解除阻塞
|
|
60
60
|
|
|
61
|
-
场景 A 为 active 任务的正常完成路径;场景 B `finalization-retry`
|
|
61
|
+
场景 A 为 active 任务的正常完成路径;场景 B `finalization-retry` 重试允许的 artifact 回填、终态 task 评论、完成校验和摘要封口,不回迁生命周期。
|
|
62
62
|
|
|
63
63
|
### 2. 验证完成前置条件(未满足则必须停止)
|
|
64
64
|
|
|
@@ -140,9 +140,8 @@ Please satisfy the hard prerequisite first, then retry complete-task.
|
|
|
140
140
|
|
|
141
141
|
如果存在有效的 `platform_issue_identity`,严格按以下顺序执行:
|
|
142
142
|
|
|
143
|
-
1. 调用 `agent-infra-internal platform-
|
|
144
|
-
2.
|
|
145
|
-
3. 把业务摘要写入临时文件,并调用 `agent-infra-internal platform-comment stage-summary {task-id} --body-file {path}`。该命令把正文和 SHA-256 写入 task 目录的 durable staging record;本步骤不得直接发布 summary 评论。
|
|
143
|
+
1. 调用 `agent-infra-internal platform-issue sync {task-id} --agent {standard-agent-token} --requirements --fields`。
|
|
144
|
+
2. 把业务摘要写入临时文件,并调用 `agent-infra-internal platform-comment stage-summary {task-id} --body-file {path}`。该命令把正文和 SHA-256 写入 task 目录的 durable staging record;本步骤不得直接发布 summary 评论。
|
|
146
145
|
|
|
147
146
|
若账本含合法的 `PRC-N` post-review 豁免,摘要正文必须镜像 task.md 中的裁决理由、提交范围、人工身份与时间,并明确这是人工覆盖而非自动校验成功。已有匹配 workflow warning 时,同时镜像其原始 failure code/message;尚无 warning 时只写“裁决已记录、最终门禁待验证”,不得提前宣称豁免已通过。summary marker 仍由同一 `--kind summary` intent 唯一维护。
|
|
148
147
|
|
|
@@ -151,7 +150,7 @@ Please satisfy the hard prerequisite first, then retry complete-task.
|
|
|
151
150
|
任一操作失败时,任务仍必须位于 active 且短号仍有效;按失败类型调用以下结构化 warning intent,随后继续步骤 5。平台失败不会阻止本地生命周期。
|
|
152
151
|
|
|
153
152
|
```bash
|
|
154
|
-
agent-infra-internal task-warning {task-id} add --step complete-task --severity ACTION_REQUIRED --code {
|
|
153
|
+
agent-infra-internal task-warning {task-id} add --step complete-task --severity ACTION_REQUIRED --code {REQUIREMENTS_SYNC_FAILED|SUMMARY_SYNC_FAILED|NETWORK_RETRY_EXHAUSTED} --target {issue|summary|platform} --message "{error_code}: {error_message}" --action "修复平台同步问题后重跑 complete-task"
|
|
155
154
|
```
|
|
156
155
|
|
|
157
156
|
相同 `step/code/target` 组合由核心幂等去重;调用方不分配 warning id 或手写账本行。
|
|
@@ -176,11 +175,11 @@ agent-infra-internal task-verify {task-id} complete-task.preflight --format text
|
|
|
176
175
|
agent-infra-internal task-finalization {task-id} complete --agent {standard-agent-token}
|
|
177
176
|
```
|
|
178
177
|
|
|
179
|
-
finalization
|
|
178
|
+
finalization 按允许的 artifact backfill → lifecycle → task 评论 → core verification → warning task 评论更新 → summary seal 的固定顺序执行。每项 backfill 必须取得成功终态,否则不得进入 lifecycle。summary seal 始终读取任务目录中保留的 durable staging record;平台入口负责校验 marker、owner 和 digest,必要时删除并重建摘要,再复读最终远端顺序。重入直接重复该幂等操作,不从远端评论反向恢复本地正文。`result=completed` 即表示宿主已依据结构化结果和 receipt 安全完成;若还有外围 warning 或 pending step,返回 `result=completed_with_warnings`、warnings 和 pending steps。`result=failed` 或 `result=blocked` 仅用于硬失败或 receipt/capability 失败,修复原因后以同一入口重试,不得宣称完成或手工补写局部状态。沙箱不得从旧挂载执行 `ls completed` 或本地终态校验来重新裁决该结果。
|
|
180
179
|
|
|
181
180
|
### 7. 处理 finalization 重试与结果
|
|
182
181
|
|
|
183
|
-
场景 A 与场景 B `finalization-retry` 都从宿主执行同一个 `task-finalization` 入口。receipt 只是重入提示,不是 canonical truth
|
|
182
|
+
场景 A 与场景 B `finalization-retry` 都从宿主执行同一个 `task-finalization` 入口。receipt 只是重入提示,不是 canonical truth:每次重入都要重新核对允许的 artifact 回填、终态 task 评论、完成校验,并使用保留的 durable staging record 重做 summary seal;只有任务已处于 `completed` 且短号 registry 已释放时,才可跳过不可逆的 lifecycle。不得拆开调用旧的 lifecycle、评论同步或完成校验命令。若回填、task 评论、summary seal 或校验因网络问题返回 `blocked`,保留 receipt、durable staging record 和已完成状态,修复网络后重跑 complete-task;若生命周期仍未完成,任务保持 active 并从 receipt 的待处理步骤继续。
|
|
184
183
|
|
|
185
184
|
完成结果必须直接消费本次宿主 finalization 的结构化输出、receipt 和 warning projection。`completed` 或 `completed_with_warnings` 才允许继续;`failed` / `blocked` / `unknown` 必须保留 receipt 并停止,之后通过同一 finalization 入口重试。不要在沙箱旧挂载中另行运行 `ls completed` 或 `task-verify complete-task.completed`,也不要用其结果推翻宿主结果。
|
|
186
185
|
|
|
@@ -26,7 +26,7 @@ Before generating a validation report, read `.agents/rules/evidence-reporting.md
|
|
|
26
26
|
- `complete-manual-validation` remains the maintainer's final registration after coverage is judged sufficient.
|
|
27
27
|
- Never manipulate temporary worktrees, leases, or containers directly; only call `agent-infra-internal task-validate`.
|
|
28
28
|
- Never record tokens, environment variables, full argv, absolute user paths, or raw transcripts in the artifact; the core must write one current-only evidence envelope for each validation target.
|
|
29
|
-
- Before generating
|
|
29
|
+
- Before generating validation artifact Markdown referenced by the task comment, read `.agents/rules/sync-content-generation.md` and follow its generator-side constraints. Keep the validation artifact local instead of publishing it as an Issue artifact comment.
|
|
30
30
|
- The branch-only fallback writes to `.agents/workspace/validations/{branch-slug}/` and is marked `recoverable: false`: no task.md write-back, no lifecycle events, no Issue sync, no `task-verify`; the artifact must be carried back to the host that owns the task workspace for registration.
|
|
31
31
|
|
|
32
32
|
## Step 0: State Check (pre-execution hard gate)
|
|
@@ -46,7 +46,7 @@ Branch-only has no `{task-id}`: skip this step and record `not-applicable (branc
|
|
|
46
46
|
3. Take the round and artifact name from the core result. After confirming valid explicit work or a non-empty discovered list, run `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}` and classify each item as `executable|unavailable|unknown|unsafe|unresolved`.
|
|
47
47
|
4. Allocate an `{evidence-file}` for each validation target and invoke every executable item separately with `agent-infra-internal task-validate {task-ref} --scope snapshot --format json --evidence-file {evidence-file} -- {command...}`. Only make a second explicit inplace invocation for that item when evidence proves it is required, using its evidence file. If no item is executable, run no fabricated command but still produce coverage-gap evidence.
|
|
48
48
|
5. Read `reference/report-template.md`, create `validation-run.md|validation-run-r{N}.md`, and record the input mode, discovered list, per-item results, CLI JSON allowlist, and sanitized summaries.
|
|
49
|
-
6. Run `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}`. When an Issue exists, run `agent-infra-internal platform-comment sync {task-id} --kind task --agent {standard-agent-token}
|
|
49
|
+
6. Run `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}`. When an Issue exists, run only `agent-infra-internal platform-comment sync {task-id} --kind task --agent {standard-agent-token}`; do not publish the validation artifact as an Issue comment.
|
|
50
50
|
7. Run `agent-infra-internal task-verify {task-id} validation-run.completed --artifact {artifact} --format text`; fix failures and rerun it.
|
|
51
51
|
8. Report the evidence path, coverage gaps, and verification result; explicitly leave the decision to run `complete-manual-validation` to the maintainer. Read `.agents/rules/next-step-output.md` and end with `Completed at`.
|
|
52
52
|
|
|
@@ -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
|
|
|
@@ -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. Use the current host's native child spawn, wait, and result interfaces. Task-bound sandboxes
|
|
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
|
|
|
@@ -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. 使用当前宿主的原生子 Agent 启动、等待与结果接口。task-bound sandbox
|
|
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
|
|
|
@@ -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,142 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import { TASK_WORKFLOW_COMMANDS } from '../../task/workflow-command.js';
|
|
5
|
-
import { parseArtifactCommand, executeArtifactCommand } from '../../task/artifact-command.js';
|
|
6
|
-
import { parseReviewCommand } from '../../task/review-command.js';
|
|
7
|
-
import { prepareLocalArtifact, preflightLocalArtifact, commitLocalArtifactProvenance } from '../../task/local-artifact-finalization.js';
|
|
8
|
-
import { prepareReviewSummaryCandidate, preflightReviewSummary } from '../../task/review-finalization.js';
|
|
9
|
-
import { withTaskExecutionLock } from '../../task/task-execution-lock.js';
|
|
10
|
-
import { dispatchWorkflowCommand } from '../../task/workflow-dispatch.js';
|
|
11
|
-
import { assertSandboxTaskSource } from '../workspace-view.js';
|
|
12
|
-
import { appendDiagnosticAudit } from './audit.js';
|
|
13
|
-
import { readTaskArtifact } from './task-workflow.js';
|
|
14
|
-
import { applyTaskEvent } from '../../task/events.js';
|
|
15
|
-
import { parseTaskEventRequest } from '../../internal/task-event.js';
|
|
16
|
-
function executionResult(result) {
|
|
17
|
-
return { exitCode: result.status === 'failed' || result.status === 'refused' ? 1 : 0, stdout: `${JSON.stringify(result)}\n`, stderr: '' };
|
|
18
|
-
}
|
|
19
|
-
function replaceCurrentArtifactAtomically(file, content) {
|
|
20
|
-
const temporary = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${randomUUID()}.tmp`);
|
|
21
|
-
try {
|
|
22
|
-
fs.writeFileSync(temporary, content, { encoding: 'utf8', flag: 'wx' });
|
|
23
|
-
fs.renameSync(temporary, file);
|
|
24
|
-
}
|
|
25
|
-
finally {
|
|
26
|
-
try {
|
|
27
|
-
fs.unlinkSync(temporary);
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
if (error.code !== 'ENOENT')
|
|
31
|
-
throw error;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/** The broker already authorized this host executor; domain operations own validation. */
|
|
36
|
-
export async function executeTaskWorkflow(manifest, request, lifecycleRecoveryAttestation = null, options = {}) {
|
|
37
|
-
let publicationCommitted = false;
|
|
38
|
-
let faultTriggered = false;
|
|
39
|
-
const fault = (window) => {
|
|
40
|
-
if (faultTriggered || options.faultWindow !== window)
|
|
41
|
-
return;
|
|
42
|
-
faultTriggered = true;
|
|
43
|
-
throw new Error(`TASK_WORKFLOW_FAULT_INJECTED:${window}`);
|
|
44
|
-
};
|
|
45
|
-
const response = (result) => {
|
|
46
|
-
fault('before-result-return');
|
|
47
|
-
return executionResult(result);
|
|
48
|
-
};
|
|
49
|
-
try {
|
|
50
|
-
fault('before-call');
|
|
51
|
-
const taskDir = assertSandboxTaskSource(manifest.repoRoot, request.taskId);
|
|
52
|
-
const [command] = TASK_WORKFLOW_COMMANDS[request.operation];
|
|
53
|
-
if (request.operation === 'event') {
|
|
54
|
-
const eventRequest = parseTaskEventRequest(request.args);
|
|
55
|
-
const boundEventRequest = lifecycleRecoveryAttestation && eventRequest.requestId === undefined
|
|
56
|
-
? { ...eventRequest, requestId: lifecycleRecoveryAttestation.lifecycleRequestId }
|
|
57
|
-
: eventRequest;
|
|
58
|
-
fault('before-domain-write');
|
|
59
|
-
const result = applyTaskEvent(boundEventRequest, {
|
|
60
|
-
repoRoot: manifest.repoRoot,
|
|
61
|
-
lifecycleRecoveryAttestation,
|
|
62
|
-
deferLifecycleRecoveryConsumption: true
|
|
63
|
-
});
|
|
64
|
-
publicationCommitted = result.changed;
|
|
65
|
-
fault('after-atomic-rename');
|
|
66
|
-
return response(result);
|
|
67
|
-
}
|
|
68
|
-
if (command !== 'task-artifact' && command !== 'task-review') {
|
|
69
|
-
// The broker owns this short-lived executor; no global service or worker
|
|
70
|
-
// credential participates in the command's authority or recovery path.
|
|
71
|
-
fault('before-domain-write');
|
|
72
|
-
const result = dispatchWorkflowCommand(manifest.repoRoot, request.operation, request.args);
|
|
73
|
-
publicationCommitted = result.changed === true;
|
|
74
|
-
fault('after-atomic-rename');
|
|
75
|
-
return response(result);
|
|
76
|
-
}
|
|
77
|
-
const input = command === 'task-artifact' ? parseArtifactCommand(request.args) : parseReviewCommand(request.args);
|
|
78
|
-
if (command === 'task-artifact' && 'operation' in input && input.operation === 'inspect') {
|
|
79
|
-
fault('before-domain-write');
|
|
80
|
-
const result = executeArtifactCommand(input, { repoRoot: manifest.repoRoot });
|
|
81
|
-
publicationCommitted = result.changed === true;
|
|
82
|
-
fault('after-atomic-rename');
|
|
83
|
-
return response(result);
|
|
84
|
-
}
|
|
85
|
-
if ('operation' in input && input.operation === 'init') {
|
|
86
|
-
fault('before-domain-write');
|
|
87
|
-
const result = executeArtifactCommand(input, { repoRoot: manifest.repoRoot, artifactDir: taskDir });
|
|
88
|
-
publicationCommitted = result.changed === true;
|
|
89
|
-
fault('after-atomic-rename');
|
|
90
|
-
return response(result);
|
|
91
|
-
}
|
|
92
|
-
return await withTaskExecutionLock(manifest.repoRoot, request.taskId, `sandbox-control.${request.operation}`, async () => {
|
|
93
|
-
const artifact = await readTaskArtifact(taskDir, { artifact: input.artifact });
|
|
94
|
-
const content = artifact.bytes.toString('utf8');
|
|
95
|
-
fault('before-domain-write');
|
|
96
|
-
let result;
|
|
97
|
-
if ('operation' in input) {
|
|
98
|
-
const { family } = input;
|
|
99
|
-
if (family !== 'analysis' && family !== 'plan' && family !== 'code')
|
|
100
|
-
throw new Error('ARTIFACT_IDENTITY_INVALID');
|
|
101
|
-
const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot, lockAlreadyHeld: true };
|
|
102
|
-
if (input.operation === 'preflight') {
|
|
103
|
-
const result = preflightLocalArtifact(local);
|
|
104
|
-
return response(result);
|
|
105
|
-
}
|
|
106
|
-
const prepared = prepareLocalArtifact(local, content);
|
|
107
|
-
result = commitLocalArtifactProvenance(prepared);
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
if (input.overrideTicket)
|
|
111
|
-
throw new Error('TASK_WORKFLOW_OVERRIDE_UNSUPPORTED');
|
|
112
|
-
const family = `review-${input.stage}`;
|
|
113
|
-
if (request.operation === 'review-preflight') {
|
|
114
|
-
const result = preflightReviewSummary(input, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true });
|
|
115
|
-
return response(result);
|
|
116
|
-
}
|
|
117
|
-
const prepared = prepareReviewSummaryCandidate(input, content, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true });
|
|
118
|
-
if (input.dryRun || prepared.result.status === 'planned')
|
|
119
|
-
return executionResult(prepared.result);
|
|
120
|
-
if (prepared.result.status === 'failed')
|
|
121
|
-
return executionResult(prepared.result);
|
|
122
|
-
if (prepared.result.changed)
|
|
123
|
-
replaceCurrentArtifactAtomically(path.join(taskDir, input.artifact), prepared.content);
|
|
124
|
-
result = prepared.result;
|
|
125
|
-
}
|
|
126
|
-
publicationCommitted ||= result.changed === true;
|
|
127
|
-
if (result.status !== 'failed')
|
|
128
|
-
appendDiagnosticAudit(manifest, 'task-workflow-artifact-finalized', {
|
|
129
|
-
requestId: request.id, sandboxTaskId: request.taskId, workflowOperation: request.operation,
|
|
130
|
-
artifact: input.artifact, sha256: result.artifactSha256, semanticDigest: result.semanticDigest
|
|
131
|
-
});
|
|
132
|
-
fault('after-atomic-rename');
|
|
133
|
-
return response(result);
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
138
|
-
const code = error?.code ?? /^([A-Z][A-Z0-9_]+)/u.exec(message)?.[1] ?? 'TASK_WORKFLOW_REQUEST_INVALID';
|
|
139
|
-
return executionResult({ status: 'failed', changed: publicationCommitted ? null : false, error: { code, message } });
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
//# sourceMappingURL=workflow-executor.js.map
|