@fitlab-ai/agent-infra 0.11.2 → 0.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -8
- package/README.zh-CN.md +17 -8
- 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/sandbox-control.js +1 -43
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-finalization.js +41 -1
- package/dist/lib/internal/task-ledger.js +13 -5
- package/dist/lib/internal/task-lifecycle.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +7 -2
- package/dist/lib/platform/completion-backfill.js +63 -17
- 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/protocol.js +5 -64
- package/dist/lib/sandbox/control/server.js +49 -343
- package/dist/lib/sandbox/control/state.js +1 -7
- package/dist/lib/sandbox/control/task-view.js +1 -2
- package/dist/lib/sandbox/task-cleanup.js +13 -20
- package/dist/lib/task/artifact-command.js +11 -4
- package/dist/lib/task/artifact-lifecycle.js +217 -85
- package/dist/lib/task/artifact-operations.js +1 -26
- package/dist/lib/task/artifact-receipts.js +4 -1
- package/dist/lib/task/artifact-schema.js +1 -0
- package/dist/lib/task/artifact-selection.js +25 -0
- package/dist/lib/task/capabilities.js +158 -39
- package/dist/lib/task/commands/status.js +9 -2
- package/dist/lib/task/control-authority.js +37 -38
- package/dist/lib/task/control-recovery.js +3 -42
- package/dist/lib/task/decision-intents.js +12 -0
- package/dist/lib/task/delegation-receipts.js +2 -2
- package/dist/lib/task/delivery.js +1 -43
- package/dist/lib/task/events.js +80 -64
- package/dist/lib/task/finalization-artifacts.js +1 -3
- package/dist/lib/task/finalization-state.js +1 -1
- package/dist/lib/task/finalization.js +319 -234
- package/dist/lib/task/ledger-intents.js +157 -15
- package/dist/lib/task/lifecycle-path.js +75 -0
- package/dist/lib/task/lifecycle.js +11 -1
- package/dist/lib/task/local-artifact-finalization.js +1 -20
- package/dist/lib/task/manual-validation-receipt.js +8 -3
- package/dist/lib/task/orchestration.js +29 -13
- package/dist/lib/task/review-finalization.js +3 -16
- package/dist/lib/task/rework-intent.js +70 -4
- package/dist/lib/task/verification-engine.js +20 -30
- package/dist/lib/task/verification.js +1 -0
- package/dist/lib/task/workflow-warning-intents.js +21 -6
- package/dist/lib/task/workspace-snapshot.js +7 -2
- 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/sandbox-control.ts +0 -42
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-finalization.ts +40 -1
- package/lib/internal/task-ledger.ts +12 -5
- package/lib/internal/task-lifecycle.ts +2 -2
- package/lib/internal/task-operation-registry.ts +8 -4
- package/lib/platform/completion-backfill.ts +78 -16
- 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/protocol.ts +7 -83
- package/lib/sandbox/control/server.ts +47 -362
- package/lib/sandbox/control/state.ts +1 -9
- package/lib/sandbox/control/task-view.ts +1 -2
- package/lib/sandbox/task-cleanup.ts +12 -20
- package/lib/task/artifact-command.ts +14 -4
- package/lib/task/artifact-lifecycle.ts +236 -85
- package/lib/task/artifact-operations.ts +1 -26
- package/lib/task/artifact-receipts.ts +4 -1
- package/lib/task/artifact-schema.ts +1 -0
- package/lib/task/artifact-selection.ts +53 -0
- package/lib/task/capabilities.ts +154 -40
- package/lib/task/commands/status.ts +11 -2
- package/lib/task/control-authority.ts +41 -48
- package/lib/task/control-recovery.ts +3 -43
- package/lib/task/decision-intents.ts +9 -0
- package/lib/task/delegation-receipts.ts +2 -2
- package/lib/task/delivery.ts +1 -40
- package/lib/task/events.ts +82 -64
- package/lib/task/finalization-artifacts.ts +1 -3
- package/lib/task/finalization-state.ts +1 -1
- package/lib/task/finalization.ts +310 -216
- package/lib/task/ledger-intents.ts +155 -15
- package/lib/task/lifecycle-path.ts +98 -0
- package/lib/task/lifecycle.ts +15 -2
- package/lib/task/local-artifact-finalization.ts +2 -25
- package/lib/task/manual-validation-receipt.ts +8 -2
- package/lib/task/orchestration.ts +56 -27
- package/lib/task/review-finalization.ts +3 -16
- package/lib/task/rework-intent.ts +75 -5
- package/lib/task/verification-engine.ts +19 -30
- package/lib/task/verification.ts +2 -1
- package/lib/task/workflow-warning-intents.ts +18 -6
- package/lib/task/workspace-snapshot.ts +3 -2
- 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/rules/review-handshake.en.md +4 -4
- package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
- package/templates/.agents/skills/analyze-task/SKILL.en.md +11 -4
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +11 -4
- package/templates/.agents/skills/code-task/SKILL.en.md +14 -8
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +18 -13
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +2 -2
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +4 -4
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +4 -4
- package/templates/.agents/skills/code-task/reference/report-template.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +1 -1
- 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 +13 -10
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +13 -10
- package/templates/.agents/skills/review-analysis/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-plan/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +5 -1
- 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/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +18 -2
- package/templates/.agents/templates/task.en.md +2 -2
- package/templates/.agents/templates/task.zh-CN.md +2 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +11 -6
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +11 -6
- package/templates/.agents/workflows/feature-development.en.yaml +11 -6
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +11 -6
- package/templates/.agents/workflows/refactoring.en.yaml +11 -6
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +11 -6
- package/dist/lib/sandbox/control/finalization-response.js +0 -35
- 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/finalization-response.ts +0 -37
- 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
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<strong>From issue to merged PR
|
|
12
|
+
<strong>From issue to merged PR through a risk-selected lifecycle.</strong> Every task starts with analysis, and every implementation receives an independent code review.
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
<p align="center">
|
|
@@ -51,14 +51,22 @@ Once initialized, open the project in your AI TUI and install the latest skills:
|
|
|
51
51
|
|
|
52
52
|
> AI reads `.agents/.airc.json`, auto-locates the installed template root, and syncs the latest skill manifests, managed files, and registry deterministically via `sync-templates.js`.
|
|
53
53
|
|
|
54
|
-
**Scenario**: Issue #42 reports *"Login API returns 500 when email contains a plus sign"*.
|
|
54
|
+
**Scenario**: Issue #42 reports *"Login API returns 500 when email contains a plus sign"*. Every task starts with analysis, which records one canonical path from observable facts:
|
|
55
|
+
|
|
56
|
+
| Path | Stages | Use when |
|
|
57
|
+
|------|--------|----------|
|
|
58
|
+
| Streamlined | `analyze → code → review-code` | Scope and acceptance are clear, with no separate design or document-audit decision |
|
|
59
|
+
| Standard | `analyze → plan → code → review-code` | The implementation needs an explicit cross-module contract, data flow, or test strategy |
|
|
60
|
+
| Full | `analyze → review-analysis → plan → review-plan → code → review-code` | Concrete acceptance disputes, costly interface/schema/migration choices, or real external/security boundaries require independent review |
|
|
61
|
+
|
|
62
|
+
File count, module count, or a merely possible risk does not select the full path. A later finding can return work to analysis, planning, or code when new evidence justifies it; independent `review-code` remains part of every path.
|
|
63
|
+
|
|
64
|
+
Suppose the analysis selects the **standard path** because the application-layer boundary needs an explicit plan:
|
|
55
65
|
|
|
56
66
|
```bash
|
|
57
67
|
/import-issue 42 # AI reads the issue, creates a task, extracts requirements
|
|
58
|
-
/analyze-task --task <task-id> # AI scans the codebase,
|
|
59
|
-
/review-analysis --task <task-id> # An isolated reviewer checks the analysis
|
|
68
|
+
/analyze-task --task <task-id> # AI scans the codebase, records the selected path, writes analysis.md
|
|
60
69
|
/plan-task --task <task-id> # AI proposes a fix plan
|
|
61
|
-
/review-plan --task <task-id> # A fresh isolated reviewer checks the plan
|
|
62
70
|
```
|
|
63
71
|
|
|
64
72
|
> **You review the plan and reply in natural language:**
|
|
@@ -79,7 +87,7 @@ Just fix it at the application layer in LoginService.
|
|
|
79
87
|
/complete-task --task <task-id> # task archived
|
|
80
88
|
```
|
|
81
89
|
|
|
82
|
-
**
|
|
90
|
+
**One analysis-selected path, one natural-language correction, and an independent code review.** The lifecycle keeps the evidence and review depth proportional to the task.
|
|
83
91
|
|
|
84
92
|
Every command above works the same way in Claude Code, Codex, Antigravity CLI, and OpenCode. Switch tools mid-task — the workflow state follows. For what each skill does under the hood, see [Built-in AI Skills](./docs/en/skills.md).
|
|
85
93
|
|
|
@@ -193,8 +201,9 @@ The most-used lifecycle commands, in delivery order. The command prefix varies b
|
|
|
193
201
|
|---------|---------|
|
|
194
202
|
| `create-task` / `import-issue` | Start a task from a description or a GitHub Issue |
|
|
195
203
|
| `run-task` | Resume the lifecycle with fresh isolated executors/reviewers when the selected client exposes verified actual model/effort evidence; Codex now has an experimental Hooks + App Server evidence channel, but orchestration remains disabled until that channel is connected to delegation receipts |
|
|
196
|
-
| `analyze-task`
|
|
197
|
-
| `
|
|
204
|
+
| `analyze-task` | Capture scope and risks, then select the streamlined, standard, or full path |
|
|
205
|
+
| `review-analysis` | Review the analysis when the selected full path requires an independent requirement checkpoint |
|
|
206
|
+
| `plan-task` / `review-plan` | Design the approach on standard/full paths; independently review it only on the full path |
|
|
198
207
|
| `code-task` → `review-code` | Implement and test; `code-task` creates a local checkpoint, then a structured review checks that checkpoint |
|
|
199
208
|
| `create-pr` → `complete-task` | Publish the approved checkpoint to the task-bound target branch, then archive after merge and final gates |
|
|
200
209
|
|
package/README.zh-CN.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<strong>从 Issue 到合并 PR
|
|
12
|
+
<strong>从 Issue 到合并 PR,由风险选择相称的生命周期。</strong> 每个任务都先分析,每份实现都接受独立代码审查。
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
<p align="center">
|
|
@@ -50,14 +50,22 @@ agent-infra 的目标就是把这层共享基础设施标准化。它为所有
|
|
|
50
50
|
|
|
51
51
|
> AI 读取 `.agents/.airc.json`,自动定位已安装的模板根目录,并通过 `sync-templates.js` 确定性地同步最新的 skill 清单、managed 文件和注册表。
|
|
52
52
|
|
|
53
|
-
**场景**:Issue #42 报告 *"登录接口在邮箱包含加号时返回 500"
|
|
53
|
+
**场景**:Issue #42 报告 *"登录接口在邮箱包含加号时返回 500"*。每个任务都从分析开始,并由分析根据可观察事实记录一条规范路径:
|
|
54
|
+
|
|
55
|
+
| 路径 | 阶段 | 适用条件 |
|
|
56
|
+
|------|------|----------|
|
|
57
|
+
| 精简路径 | `analyze → code → review-code` | 范围和验收明确,不需要独立设计或文档审计决策 |
|
|
58
|
+
| 标准路径 | `analyze → plan → code → review-code` | 实现需要明确跨模块契约、数据流或测试策略 |
|
|
59
|
+
| 完整路径 | `analyze → review-analysis → plan → review-plan → code → review-code` | 存在具体的验收争议、高代价接口/schema/迁移选择,或真实外部/安全边界,需要独立审查 |
|
|
60
|
+
|
|
61
|
+
文件数量、模块数量或可能存在的风险不能单独触发完整路径。后续 finding 只有在新证据成立时才会把工作返回分析、方案或实现阶段;每条路径都保留独立 `review-code`。
|
|
62
|
+
|
|
63
|
+
假设分析认为应用层边界需要明确方案,因此选择**标准路径**:
|
|
54
64
|
|
|
55
65
|
```bash
|
|
56
66
|
/import-issue 42 # AI 读取 Issue,创建任务,提取需求
|
|
57
|
-
/analyze-task --task <task-id> # AI
|
|
58
|
-
/review-analysis --task <task-id> # 隔离 reviewer 审查分析产物
|
|
67
|
+
/analyze-task --task <task-id> # AI 扫描代码库、记录所选路径,输出 analysis.md
|
|
59
68
|
/plan-task --task <task-id> # AI 提出修复方案
|
|
60
|
-
/review-plan --task <task-id> # fresh 隔离 reviewer 审查方案
|
|
61
69
|
```
|
|
62
70
|
|
|
63
71
|
> **你审查方案后用自然语言回复:**
|
|
@@ -78,7 +86,7 @@ agent-infra 的目标就是把这层共享基础设施标准化。它为所有
|
|
|
78
86
|
/complete-task --task <task-id> # 任务归档
|
|
79
87
|
```
|
|
80
88
|
|
|
81
|
-
|
|
89
|
+
**一条由分析选择的路径、一次自然语言纠正和一次独立代码审查。** 生命周期会让证据与审查深度和任务风险相称。
|
|
82
90
|
|
|
83
91
|
以上每条命令在 Claude Code、Codex、Antigravity CLI、OpenCode 中完全通用。任务进行到一半切换工具,工作流状态照常延续。每个 skill 背后做了什么,见 [内置 AI Skills](./docs/zh-CN/skills.md)。
|
|
84
92
|
|
|
@@ -192,8 +200,9 @@ ai agent-client configure
|
|
|
192
200
|
|------|------|
|
|
193
201
|
| `create-task` / `import-issue` | 从描述或 GitHub Issue 创建任务 |
|
|
194
202
|
| `run-task` | 当所选客户端能提供已验证的 actual model/effort 证据时,用 fresh 隔离 executor/reviewer 续跑生命周期;Codex 现已具备实验性的 Hooks + App Server 证据通道,但在该通道接入 delegation receipt 前仍不会启用 orchestration |
|
|
195
|
-
| `analyze-task`
|
|
196
|
-
| `
|
|
203
|
+
| `analyze-task` | 明确范围与风险,再选择精简、标准或完整路径 |
|
|
204
|
+
| `review-analysis` | 仅在完整路径需要独立需求检查点时审查分析 |
|
|
205
|
+
| `plan-task` / `review-plan` | 标准和完整路径需要设计方案;只有完整路径独立审查方案 |
|
|
197
206
|
| `code-task` → `review-code` | 实现并测试;`code-task` 创建本地 checkpoint,再由结构化审查检视该 checkpoint |
|
|
198
207
|
| `create-pr` → `complete-task` | 将已通过审查的 checkpoint 发布到任务绑定目标分支,并在合并和最终门禁通过后归档 |
|
|
199
208
|
|
package/dist/bin/internal-cli.js
CHANGED
|
@@ -49,7 +49,9 @@ function taskControlTransportFailure(message, code = 'TASK_CONTROL_TRANSPORT_INV
|
|
|
49
49
|
}
|
|
50
50
|
let controlRouted = false;
|
|
51
51
|
if (!taskViewGuardFailed && !markerlessHelp && (taskControlCommand || taskWorkflowCommand || manualValidationWorkflowCommand)) {
|
|
52
|
-
const transport = resolveSandboxControlTransport(process.env
|
|
52
|
+
const transport = resolveSandboxControlTransport(process.env, {
|
|
53
|
+
localWorkflow: command === 'task-orchestration' || command === 'task-finalization' || taskWorkflowCommand || manualValidationWorkflowCommand
|
|
54
|
+
});
|
|
53
55
|
switch (transport.kind) {
|
|
54
56
|
case 'fail-closed': {
|
|
55
57
|
const reason = transport.reasonCode ?? 'TASK_CONTROL_TRANSPORT_INVALID';
|
|
@@ -60,9 +62,12 @@ if (!taskViewGuardFailed && !markerlessHelp && (taskControlCommand || taskWorkfl
|
|
|
60
62
|
// The host CLI is the direct-host authority. Domain handlers retain their
|
|
61
63
|
// task locks, atomic writes, and operation-specific recovery facts.
|
|
62
64
|
break;
|
|
65
|
+
case 'sandbox-local': {
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
63
68
|
case 'broker-client': {
|
|
64
69
|
const { sandboxControl } = await import('../lib/internal/sandbox-control.js');
|
|
65
|
-
await sandboxControl(['client',
|
|
70
|
+
await sandboxControl(['client', command, ...process.argv.slice(3)]);
|
|
66
71
|
break;
|
|
67
72
|
}
|
|
68
73
|
}
|
|
@@ -408,6 +408,9 @@ function defineAgentClientAdapter(candidate) {
|
|
|
408
408
|
capabilities: Object.freeze(capabilities),
|
|
409
409
|
modelSelection: frozenModelSelection,
|
|
410
410
|
delegationEvidence: Object.freeze({ ...evidence }),
|
|
411
|
+
...(candidate.orchestrationAdapter === undefined
|
|
412
|
+
? {}
|
|
413
|
+
: { orchestrationAdapter: Object.freeze({ ...candidate.orchestrationAdapter }) }),
|
|
411
414
|
project: Object.freeze({
|
|
412
415
|
ownedPathPrefixes: Object.freeze(paths),
|
|
413
416
|
...projectAssets,
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { createCodexLifecycleStore } from './store.js';
|
|
3
|
+
import { managedDelegationRole } from '../../../task/delegation-receipts.js';
|
|
4
|
+
import { normalizeAgentToken } from '../../tokens.js';
|
|
5
|
+
import { locateActivityLog, pairEntries, appendActivityEntry } from '../../../task/activity-log.js';
|
|
6
|
+
import { captureTaskWriteMetadata, writeTask } from '../../../task/write.js';
|
|
7
|
+
import { parseTypedTaskFrontmatter } from '../../../task/frontmatter.js';
|
|
8
|
+
import { resolveTaskRef } from '../../../task/resolve-ref.js';
|
|
9
|
+
import { resolveAgentRuntimeStoreRoot } from '../../../runtime/agent-runtime.js';
|
|
10
|
+
import { recoverActivatedOrchestrationDelegationUnderLock, readRun } from '../../../task/orchestration.js';
|
|
11
|
+
const ACTIONS = {
|
|
12
|
+
analysis: 'Analyze Task',
|
|
13
|
+
'review-analysis': 'Review Analysis',
|
|
14
|
+
plan: 'Plan Task',
|
|
15
|
+
'review-plan': 'Review Plan',
|
|
16
|
+
code: 'Code Task',
|
|
17
|
+
'review-code': 'Review Code'
|
|
18
|
+
};
|
|
19
|
+
function result(request, status, extra = {}) {
|
|
20
|
+
return {
|
|
21
|
+
status,
|
|
22
|
+
changed: status === 'applied',
|
|
23
|
+
targetState: 'active',
|
|
24
|
+
requestRef: request.taskRef,
|
|
25
|
+
intent: 'recover-started',
|
|
26
|
+
taskId: null,
|
|
27
|
+
receiptId: null,
|
|
28
|
+
childId: null,
|
|
29
|
+
error: null,
|
|
30
|
+
...extra
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function failure(request, status, code, message, extra = {}) {
|
|
34
|
+
return result(request, status, { error: { code, message }, ...extra });
|
|
35
|
+
}
|
|
36
|
+
function actionPattern(receipt) {
|
|
37
|
+
const action = ACTIONS[receipt.stage];
|
|
38
|
+
if (!action)
|
|
39
|
+
return null;
|
|
40
|
+
const escaped = action.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
41
|
+
return new RegExp(`^${escaped} \\(Round ${receipt.round}(?:, (?:fix for review-code(?:-r[2-9]|-r[1-9]\\d+)?.md|decision II-[1-9]\\d*))?\\)$`, 'u');
|
|
42
|
+
}
|
|
43
|
+
function openRows(section) {
|
|
44
|
+
return pairEntries([...section.entries]).filter((row) => row.started !== '' && row.done === '');
|
|
45
|
+
}
|
|
46
|
+
function rowForReceipt(rows, receipt) {
|
|
47
|
+
const pattern = actionPattern(receipt);
|
|
48
|
+
return pattern ? rows.filter((row) => pattern.test(row.step)) : [];
|
|
49
|
+
}
|
|
50
|
+
function readLifecycleStore(options, repoRoot) {
|
|
51
|
+
return options.lifecycleStore ?? createCodexLifecycleStore({
|
|
52
|
+
root: resolveAgentRuntimeStoreRoot({ repoRoot, store: 'lifecycle' }),
|
|
53
|
+
cliVersion: 'recovery',
|
|
54
|
+
now: options.now
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function readStoredEvidence(store, childId) {
|
|
58
|
+
try {
|
|
59
|
+
return store.read(childId);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
63
|
+
if (message.includes('was not found uniquely'))
|
|
64
|
+
return { missing: true };
|
|
65
|
+
return { error: error instanceof Error ? error : new Error(message) };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function validateStopRecord(record, receipt) {
|
|
69
|
+
const start = record.state.startEvidence;
|
|
70
|
+
const stop = record.state.stopEvidence;
|
|
71
|
+
const provenance = receipt.lifecycleProvenance;
|
|
72
|
+
const host = receipt.hostEvidence;
|
|
73
|
+
if (receipt.client !== 'codex'
|
|
74
|
+
|| !provenance
|
|
75
|
+
|| host?.kind !== 'codex-lifecycle-v2'
|
|
76
|
+
|| !start
|
|
77
|
+
|| !stop
|
|
78
|
+
|| record.state.status !== 'stop-ready'
|
|
79
|
+
|| stop.terminalStatus !== 'completed'
|
|
80
|
+
|| stop.hookStopObserved !== true
|
|
81
|
+
|| start.childThreadId !== receipt.childId
|
|
82
|
+
|| start.parentThreadId !== receipt.parentId
|
|
83
|
+
|| managedDelegationRole(start.nativeAgent) !== receipt.role
|
|
84
|
+
|| start.hookDefinitionHash !== provenance.hookDefinitionHash
|
|
85
|
+
|| host.hookDefinitionHash !== provenance.hookDefinitionHash
|
|
86
|
+
|| host.capabilitySessionId !== provenance.capabilitySessionId
|
|
87
|
+
|| host.capabilityTurnId !== provenance.capabilityTurnId
|
|
88
|
+
|| host.capabilityToolUseId !== provenance.capabilityToolUseId
|
|
89
|
+
|| host.spawnToolUseId !== start.spawnToolUseId
|
|
90
|
+
|| !host.spawnObservedAt
|
|
91
|
+
|| host.spawnObservedAt !== record.spawnObservedAt
|
|
92
|
+
|| host.controllerInstanceDigest !== provenance.controllerInstanceDigest
|
|
93
|
+
|| host.controlGeneration !== provenance.controlGeneration
|
|
94
|
+
|| typeof host.controllerInstanceDigest !== 'string'
|
|
95
|
+
|| typeof host.controlGeneration !== 'string'
|
|
96
|
+
|| host.startRevision < 1
|
|
97
|
+
|| record.revision <= host.startRevision
|
|
98
|
+
|| record.state.child?.childThreadId !== receipt.childId
|
|
99
|
+
|| record.state.stop?.childThreadId !== receipt.childId) {
|
|
100
|
+
return { ok: false, code: 'RECOVERY_STOP_EVIDENCE_INVALID', message: 'Codex stop evidence does not match the activated receipt' };
|
|
101
|
+
}
|
|
102
|
+
if (record.consumer !== null && record.consumer !== receipt.id) {
|
|
103
|
+
return { ok: false, code: 'RECOVERY_CONSUMER_CONFLICT', message: `Codex lifecycle evidence was consumed by '${record.consumer}'` };
|
|
104
|
+
}
|
|
105
|
+
return { ok: true };
|
|
106
|
+
}
|
|
107
|
+
function abortedCandidates(run, rows) {
|
|
108
|
+
const candidates = run.receipts.flatMap((receipt) => {
|
|
109
|
+
if (receipt.status !== 'aborted' || receipt.activatedAt === null || receipt.client !== 'codex')
|
|
110
|
+
return [];
|
|
111
|
+
const matches = rowForReceipt(rows, receipt);
|
|
112
|
+
return matches.length === 1 ? [{ receipt, row: matches[0] }] : [];
|
|
113
|
+
});
|
|
114
|
+
return candidates;
|
|
115
|
+
}
|
|
116
|
+
function appendRecoveryLog(request, taskId, section, candidate, repoRoot, writer) {
|
|
117
|
+
const metadata = captureTaskWriteMetadata();
|
|
118
|
+
const body = appendActivityEntry(section, {
|
|
119
|
+
time: metadata.timestamp,
|
|
120
|
+
step: `${candidate.row.step} [aborted]`,
|
|
121
|
+
agent: request.agent,
|
|
122
|
+
note: `terminated Codex delegation; receipt=${candidate.receipt.id}; child=${candidate.receipt.childId}`
|
|
123
|
+
});
|
|
124
|
+
const written = writer({
|
|
125
|
+
taskRef: taskId,
|
|
126
|
+
expectedState: 'active',
|
|
127
|
+
mutations: [{ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body }]
|
|
128
|
+
}, { repoRoot, metadataProvider: () => metadata });
|
|
129
|
+
if (written.status === 'failed') {
|
|
130
|
+
return failure(request, 'owner-unknown', 'RECOVERY_LOG_WRITE_FAILED', written.error.message, {
|
|
131
|
+
taskId, receiptId: candidate.receipt.id, childId: candidate.receipt.childId
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return result(request, 'applied', {
|
|
135
|
+
taskId, receiptId: candidate.receipt.id, childId: candidate.receipt.childId
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
function recoverStartedLifecycleUnderLock(request, options = {}) {
|
|
139
|
+
if (!request || request.intent !== 'recover-started' || request.auto !== true || normalizeAgentToken(request.agent) !== 'codex') {
|
|
140
|
+
return failure(request, 'conflict', 'RECOVERY_PAYLOAD_INVALID', 'automatic recovery requires a task and the Codex agent');
|
|
141
|
+
}
|
|
142
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
143
|
+
if (!resolved.ok)
|
|
144
|
+
return failure(request, 'conflict', resolved.code, resolved.message);
|
|
145
|
+
const taskId = resolved.taskId;
|
|
146
|
+
let content;
|
|
147
|
+
try {
|
|
148
|
+
content = fs.readFileSync(resolved.taskMdPath, 'utf8');
|
|
149
|
+
parseTypedTaskFrontmatter(content);
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
return failure(request, 'conflict', 'RECOVERY_TASK_INVALID', error instanceof Error ? error.message : String(error), { taskId });
|
|
153
|
+
}
|
|
154
|
+
const section = locateActivityLog(content);
|
|
155
|
+
if (!section)
|
|
156
|
+
return failure(request, 'conflict', 'RECOVERY_LOG_INVALID', 'task has no unique Activity Log section', { taskId });
|
|
157
|
+
let run;
|
|
158
|
+
try {
|
|
159
|
+
run = readRun(resolved.taskDir, options.orchestration);
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
return failure(request, 'owner-unknown', 'RECOVERY_ORCHESTRATION_UNKNOWN', error instanceof Error ? error.message : String(error), { taskId });
|
|
163
|
+
}
|
|
164
|
+
if (!run)
|
|
165
|
+
return result(request, 'no-op', { taskId });
|
|
166
|
+
const rows = openRows(section);
|
|
167
|
+
const pending = run.pendingDelegation;
|
|
168
|
+
if (!pending) {
|
|
169
|
+
const candidates = abortedCandidates(run, rows);
|
|
170
|
+
if (candidates.length === 0)
|
|
171
|
+
return result(request, 'no-op', { taskId });
|
|
172
|
+
if (candidates.length > 1) {
|
|
173
|
+
return failure(request, 'conflict', 'RECOVERY_CANDIDATE_AMBIGUOUS', 'more than one aborted delegation has an open lifecycle row', { taskId });
|
|
174
|
+
}
|
|
175
|
+
return appendRecoveryLog(request, taskId, section, candidates[0], resolved.repoRoot, options.writeTask ?? writeTask);
|
|
176
|
+
}
|
|
177
|
+
if (pending.status !== 'activated')
|
|
178
|
+
return result(request, 'no-op', { taskId });
|
|
179
|
+
if (pending.client !== 'codex' || run.status !== 'running' || run.pause !== null) {
|
|
180
|
+
return failure(request, 'conflict', 'RECOVERY_ORCHESTRATION_INVALID', 'activated recovery requires one running Codex delegation', {
|
|
181
|
+
taskId, receiptId: pending.id, childId: pending.childId
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
const matchingRows = rowForReceipt(rows, pending);
|
|
185
|
+
if (matchingRows.length !== 1 || normalizeAgentToken(matchingRows[0].agent) !== 'codex' || matchingRows[0].note !== 'started') {
|
|
186
|
+
return failure(request, 'conflict', 'RECOVERY_LOG_CONFLICT', 'activated delegation does not have one matching open lifecycle row', {
|
|
187
|
+
taskId, receiptId: pending.id, childId: pending.childId
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (!pending.childId) {
|
|
191
|
+
return failure(request, 'conflict', 'RECOVERY_DELEGATION_INVALID', 'activated delegation has no child identity', { taskId, receiptId: pending.id });
|
|
192
|
+
}
|
|
193
|
+
const store = readLifecycleStore(options, resolved.repoRoot);
|
|
194
|
+
const stored = readStoredEvidence(store, pending.childId);
|
|
195
|
+
if ('error' in stored)
|
|
196
|
+
return failure(request, 'owner-unknown', 'RECOVERY_STORE_UNKNOWN', stored.error.message, { taskId, receiptId: pending.id, childId: pending.childId });
|
|
197
|
+
if ('missing' in stored)
|
|
198
|
+
return failure(request, 'owner-unknown', 'RECOVERY_STOP_EVIDENCE_MISSING', 'matching Codex lifecycle stop evidence is missing', { taskId, receiptId: pending.id, childId: pending.childId });
|
|
199
|
+
const evidence = validateStopRecord(stored, pending);
|
|
200
|
+
if (!evidence.ok)
|
|
201
|
+
return failure(request, evidence.code === 'RECOVERY_CONSUMER_CONFLICT' ? 'conflict' : 'owner-unknown', evidence.code, evidence.message, { taskId, receiptId: pending.id, childId: pending.childId });
|
|
202
|
+
let consumed = stored;
|
|
203
|
+
if (stored.consumer === null) {
|
|
204
|
+
try {
|
|
205
|
+
consumed = store.consume(pending.childId, pending.id, pending.hostEvidence?.hookDefinitionHash);
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
return failure(request, 'owner-unknown', 'RECOVERY_EVIDENCE_CONSUME_FAILED', error instanceof Error ? error.message : String(error), { taskId, receiptId: pending.id, childId: pending.childId });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (!consumed.consumedAt) {
|
|
212
|
+
return failure(request, 'owner-unknown', 'RECOVERY_EVIDENCE_INVALID', 'consumed stop evidence has no timestamp', { taskId, receiptId: pending.id, childId: pending.childId });
|
|
213
|
+
}
|
|
214
|
+
const recovered = recoverActivatedOrchestrationDelegationUnderLock(taskId, {
|
|
215
|
+
receiptId: pending.id,
|
|
216
|
+
stage: pending.stage,
|
|
217
|
+
round: pending.round,
|
|
218
|
+
artifact: pending.artifact,
|
|
219
|
+
startedAgent: request.agent,
|
|
220
|
+
childId: pending.childId,
|
|
221
|
+
stopRevision: consumed.revision,
|
|
222
|
+
consumer: pending.id,
|
|
223
|
+
consumedAt: consumed.consumedAt
|
|
224
|
+
}, { ...options.orchestration, repoRoot: resolved.repoRoot, now: options.now });
|
|
225
|
+
if (recovered.status === 'failed' || !recovered.run) {
|
|
226
|
+
return failure(request, 'owner-unknown', recovered.error?.code ?? 'RECOVERY_ORCHESTRATION_FAILED', recovered.error?.message ?? 'orchestration recovery failed', { taskId, receiptId: pending.id, childId: pending.childId });
|
|
227
|
+
}
|
|
228
|
+
return appendRecoveryLog(request, taskId, section, { receipt: recovered.run.receipts.at(-1), row: matchingRows[0] }, resolved.repoRoot, options.writeTask ?? writeTask);
|
|
229
|
+
}
|
|
230
|
+
function recoverStartedLifecycleFromAdapter(request, options = {}) {
|
|
231
|
+
return recoverStartedLifecycleUnderLock(request, options);
|
|
232
|
+
}
|
|
233
|
+
export { recoverStartedLifecycleFromAdapter, recoverStartedLifecycleUnderLock };
|
|
234
|
+
//# sourceMappingURL=recovery.js.map
|
|
@@ -5,8 +5,7 @@ import os from 'node:os';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import semver from 'semver';
|
|
7
7
|
import * as toml from 'smol-toml';
|
|
8
|
-
import { requestCodexControllerClose, requestCodexControllerOpen, requestCodexControllerVerify
|
|
9
|
-
import { readSandboxControlStatus } from '../../../sandbox/control/state.js';
|
|
8
|
+
import { requestCodexControllerClose, requestCodexControllerOpen, requestCodexControllerVerify } from '../../../sandbox/control/client.js';
|
|
10
9
|
import { getProcessStartTime } from '../../../server/process-state.js';
|
|
11
10
|
import { LIFECYCLE_PROTOCOL_VERSION } from './build-identity.js';
|
|
12
11
|
import { contextFromControllerLease, controllerProofFromContext, verifyCodexSandboxControllerContextWithWarnings as verifyContextFileWithWarnings, writeCodexSandboxControllerContext } from './controller-context.js';
|
|
@@ -56,44 +55,18 @@ function verifyRuntime(runtimeDir) {
|
|
|
56
55
|
fs.rmSync(probe, { force: true });
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
|
-
function
|
|
58
|
+
function verifyControllerBinding(context, control, requestControllerVerify) {
|
|
60
59
|
verifyRuntime(control.runtimeDir);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
64
|
-
try {
|
|
65
|
-
status = readSandboxControlStatus(control.statusDir);
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
lastError = error;
|
|
70
|
-
if (attempt < 4)
|
|
71
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 25);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (!status) {
|
|
75
|
-
throw new Error(`CODEX_SANDBOX_CONTROLLER_CONTROL_UNAVAILABLE: ${String(lastError)}`);
|
|
76
|
-
}
|
|
77
|
-
if (status.generation !== control.generation
|
|
78
|
-
|| status.state !== 'healthy'
|
|
79
|
-
|| Date.now() - status.updatedAt > 1_500) {
|
|
80
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_CONTROL_UNAVAILABLE');
|
|
81
|
-
}
|
|
82
|
-
const response = requestSandboxControl({
|
|
83
|
-
family: 'task-orchestration',
|
|
84
|
-
args: [taskId, 'status'],
|
|
60
|
+
const verified = requestControllerVerify({
|
|
61
|
+
controllerProof: controllerProofFromContext(context),
|
|
85
62
|
...control,
|
|
86
63
|
timeoutMs: 30_000
|
|
87
64
|
});
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
catch {
|
|
65
|
+
if (verified.binding.taskId !== context.taskId
|
|
66
|
+
|| verified.binding.controlGeneration !== context.controlGeneration
|
|
67
|
+
|| verified.binding.controllerInstanceDigest !== context.controllerInstanceDigest) {
|
|
93
68
|
throw new Error('CODEX_SANDBOX_CONTROLLER_TASK_BINDING_INVALID');
|
|
94
69
|
}
|
|
95
|
-
if (payload.taskId !== taskId)
|
|
96
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_TASK_BINDING_INVALID');
|
|
97
70
|
}
|
|
98
71
|
function verifyCodexSandboxControllerContextWithWarnings(contextPath, options = {}) {
|
|
99
72
|
const control = options.control ?? controlFromEnvironment();
|
|
@@ -272,7 +245,7 @@ function prepareCodexSandboxController(input, options = {}) {
|
|
|
272
245
|
|| opened.lease.controllerProcess.startTime !== parentStartTime) {
|
|
273
246
|
throw new Error('SANDBOX_CONTROL_RESULT_INVALID');
|
|
274
247
|
}
|
|
275
|
-
(options.
|
|
248
|
+
verifyControllerBinding(context, control, options.verifyController ?? requestCodexControllerVerify);
|
|
276
249
|
const contextPath = path.join(home, 'controller-context.json');
|
|
277
250
|
writeCodexSandboxControllerContext(contextPath, context);
|
|
278
251
|
const shimDir = path.join(home, 'bin');
|
|
@@ -6,19 +6,9 @@ import { resolveAgentRuntimeStoreRoot } from '../../../runtime/agent-runtime.js'
|
|
|
6
6
|
const LOCK_RETRY_MS = 10;
|
|
7
7
|
const LOCK_TIMEOUT_MS = 1_000;
|
|
8
8
|
const LOCK_STALE_MS = 30_000;
|
|
9
|
-
const RECOVERY_CONSUMER_RE = /^lifecycle-recovery:([^:\r\n]+):([^:\r\n]+)$/u;
|
|
10
9
|
function digest(value) {
|
|
11
10
|
return crypto.createHash('sha256').update(value).digest('hex');
|
|
12
11
|
}
|
|
13
|
-
function isRecoveryConsumer(value) {
|
|
14
|
-
return RECOVERY_CONSUMER_RE.test(value);
|
|
15
|
-
}
|
|
16
|
-
function recoveryConsumer(taskId, receiptId) {
|
|
17
|
-
if (!/^[^:\r\n]+$/u.test(taskId) || !/^[^:\r\n]+$/u.test(receiptId)) {
|
|
18
|
-
throw new Error('Codex lifecycle recovery claim identity is invalid');
|
|
19
|
-
}
|
|
20
|
-
return `lifecycle-recovery:${taskId}:${receiptId}`;
|
|
21
|
-
}
|
|
22
12
|
function readRecord(file) {
|
|
23
13
|
const value = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
24
14
|
if (value.schemaVersion !== 1
|
|
@@ -255,29 +245,8 @@ function createCodexLifecycleStore(options) {
|
|
|
255
245
|
function consume(childThreadId, consumer, expectedHookDefinitionHash) {
|
|
256
246
|
if (!consumer.trim())
|
|
257
247
|
throw new Error('Codex lifecycle consumer is required');
|
|
258
|
-
if (consumer.startsWith('lifecycle-recovery:')) {
|
|
259
|
-
throw new Error('Codex lifecycle recovery claims require claimRecovery');
|
|
260
|
-
}
|
|
261
248
|
return consumeInternal(childThreadId, consumer, expectedHookDefinitionHash);
|
|
262
249
|
}
|
|
263
|
-
function claimRecovery(childThreadId, taskId, receiptId, expectedHookDefinitionHash) {
|
|
264
|
-
return consumeInternal(childThreadId, recoveryConsumer(taskId, receiptId), expectedHookDefinitionHash);
|
|
265
|
-
}
|
|
266
|
-
function releaseRecovery(childThreadId, consumer) {
|
|
267
|
-
if (!/^lifecycle-recovery:[^:\r\n]+:[^:\r\n]+$/.test(consumer))
|
|
268
|
-
return false;
|
|
269
|
-
return withWriteLock(() => {
|
|
270
|
-
const matches = findByChild(childThreadId);
|
|
271
|
-
if (matches.length !== 1)
|
|
272
|
-
return false;
|
|
273
|
-
const file = matches[0];
|
|
274
|
-
const current = readRecord(file);
|
|
275
|
-
if (current.state.status !== 'stop-ready' || current.consumer !== consumer || !current.consumedAt)
|
|
276
|
-
return false;
|
|
277
|
-
fs.unlinkSync(file);
|
|
278
|
-
return true;
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
250
|
function expireBefore(cutoff) {
|
|
282
251
|
return withWriteLock(() => {
|
|
283
252
|
let changed = 0;
|
|
@@ -285,8 +254,6 @@ function createCodexLifecycleStore(options) {
|
|
|
285
254
|
const current = readRecord(file);
|
|
286
255
|
if (current.updatedAt >= cutoff)
|
|
287
256
|
continue;
|
|
288
|
-
if (current.consumer && isRecoveryConsumer(current.consumer))
|
|
289
|
-
continue;
|
|
290
257
|
if (current.consumer || ['invalid', 'expired', 'stop-ready'].includes(current.state.status)) {
|
|
291
258
|
fs.unlinkSync(file);
|
|
292
259
|
changed += 1;
|
|
@@ -306,7 +273,7 @@ function createCodexLifecycleStore(options) {
|
|
|
306
273
|
return changed;
|
|
307
274
|
});
|
|
308
275
|
}
|
|
309
|
-
return Object.freeze({ root, apply, applyToSpawn, consume,
|
|
276
|
+
return Object.freeze({ root, apply, applyToSpawn, consume, expireBefore, findByParent, read });
|
|
310
277
|
}
|
|
311
278
|
export { createCodexLifecycleStore, hasActiveCodexLifecycleEvidence };
|
|
312
279
|
//# sourceMappingURL=store.js.map
|
|
@@ -24,6 +24,16 @@ const codexAdapter = defineAgentClientAdapter({
|
|
|
24
24
|
actualModel: 'app-server',
|
|
25
25
|
actualReasoningEffort: 'app-server'
|
|
26
26
|
},
|
|
27
|
+
orchestrationAdapter: {
|
|
28
|
+
prepareDelegation: async (...args) => {
|
|
29
|
+
const { prepareCodexOrchestrationDelegation } = await import('../../task/codex-orchestration.js');
|
|
30
|
+
return prepareCodexOrchestrationDelegation(...args);
|
|
31
|
+
},
|
|
32
|
+
recoverStarted: async (...args) => {
|
|
33
|
+
const { recoverStartedLifecycleFromAdapter } = await import('./codex-lifecycle/recovery.js');
|
|
34
|
+
return recoverStartedLifecycleFromAdapter(...args);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
27
37
|
project: {
|
|
28
38
|
ownedPathPrefixes: ['.codex/'],
|
|
29
39
|
managed: ['.codex/hooks.json', '.codex/agents/'],
|
|
@@ -50,7 +50,7 @@ export const INTERNAL_HANDLER_ROUTE_SELECTORS = Object.freeze({
|
|
|
50
50
|
'pr-review-grade': ['decide', 'resolve-host', 'verify-artifact'],
|
|
51
51
|
'platform-checks': ['inspect', 'watch', 'resolve-run', 'logs'],
|
|
52
52
|
'task-context': ['resolve'],
|
|
53
|
-
'task-ledger': ['decision-next-id', 'stage-status', 'finding-upsert', 'finding-respond', 'finding-review', 'decision-upsert', 'rework-intent-upsert'],
|
|
53
|
+
'task-ledger': ['decision-next-id', 'stage-status', 'finding-upsert', 'finding-respond', 'finding-review', 'decision-upsert', 'rework-intent-upsert', 'rework-intent-rebuild'],
|
|
54
54
|
'task-warning': ['list', 'add', 'set-status'],
|
|
55
55
|
'task-activity': ['pr-review-inspect', 'pr-review-start', 'pr-review-complete', 'pr-review-terminate'],
|
|
56
56
|
'task-artifact': ['inspect', 'init', 'preflight', 'finalize-local'],
|