@fitlab-ai/agent-infra 0.12.1 → 0.12.2
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 +0 -2
- package/README.zh-CN.md +0 -2
- package/dist/bin/internal-cli.js +2 -17
- package/dist/lib/agent-clients/adapter.js +0 -13
- package/dist/lib/agent-clients/adapters/antigravity-cli.js +0 -5
- package/dist/lib/agent-clients/adapters/claude-code-credentials.js +0 -17
- package/dist/lib/agent-clients/adapters/claude-code.js +0 -9
- package/dist/lib/agent-clients/adapters/codex.js +0 -52
- package/dist/lib/agent-clients/adapters/opencode.js +0 -5
- package/dist/lib/agent-clients/adapters/traecli.js +0 -5
- package/dist/lib/agent-clients/config.js +19 -54
- package/dist/lib/agent-clients/registry.js +1 -12
- package/dist/lib/agent-clients/schema.js +0 -18
- package/dist/lib/agent-clients/tokens.js +1 -2
- package/dist/lib/agent-clients/types.js +0 -1
- package/dist/lib/decide.js +2 -0
- package/dist/lib/git/worktree-identity.js +1 -9
- package/dist/lib/internal/agent-client.js +2 -62
- package/dist/lib/internal/cli-route-inventory.js +1 -5
- package/dist/lib/internal/manual-validation.js +18 -10
- package/dist/lib/internal/task-create.js +1 -1
- package/dist/lib/internal/task-event.js +1 -8
- package/dist/lib/internal/task-finalization.js +0 -1
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-operation-registry.js +4 -20
- package/dist/lib/internal/task-review.js +4 -4
- package/dist/lib/platform/comment-safety.js +1 -7
- package/dist/lib/platform/in-label-sync.js +1 -14
- package/dist/lib/platform/issue-comments.js +1 -16
- package/dist/lib/platform/issues.js +1 -1
- package/dist/lib/platform/operation-coordinator.js +4 -2
- package/dist/lib/platform/pr-change-report.js +1 -4
- package/dist/lib/platform/pr-checks.js +2 -8
- package/dist/lib/platform/provider-validation.js +0 -20
- package/dist/lib/platform/pull-requests.js +73 -84
- package/dist/lib/platform/releases.js +1 -43
- package/dist/lib/platform/verification-required.js +0 -2
- package/dist/lib/platform/verification-sync.js +1 -79
- package/dist/lib/process-data/normalize.js +1 -185
- package/dist/lib/process-data/privacy.js +1 -16
- package/dist/lib/process-data/sources.js +2 -279
- package/dist/lib/render.js +0 -12
- package/dist/lib/run/index.js +15 -10
- package/dist/lib/run/skills.js +0 -3
- package/dist/lib/sandbox/commands/create.js +40 -53
- package/dist/lib/sandbox/commands/list-running.js +0 -18
- package/dist/lib/sandbox/commands/start.js +7 -8
- package/dist/lib/sandbox/constants.js +0 -6
- package/dist/lib/sandbox/control/client.js +0 -1
- package/dist/lib/sandbox/control/container-identity.js +1 -16
- package/dist/lib/sandbox/control/executor.js +0 -4
- package/dist/lib/sandbox/control/identity-sentinel.js +0 -7
- package/dist/lib/sandbox/control/lifecycle.js +21 -37
- package/dist/lib/sandbox/control/native-file-lock.js +0 -3
- package/dist/lib/sandbox/control/server.js +18 -38
- package/dist/lib/sandbox/control/state.js +1 -9
- package/dist/lib/sandbox/dockerfile.js +0 -6
- package/dist/lib/sandbox/engine.js +0 -14
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +1 -4
- package/dist/lib/sandbox/engines/wsl2-paths.js +0 -3
- package/dist/lib/sandbox/recovery.js +24 -26
- package/dist/lib/sandbox/removal.js +11 -519
- package/dist/lib/sandbox/task-resolver.js +0 -41
- package/dist/lib/sandbox/tools.js +1 -4
- package/dist/lib/sandbox/workspace-view.js +1 -2
- package/dist/lib/server/display.js +0 -6
- package/dist/lib/task/activity-intent.js +45 -40
- package/dist/lib/task/activity-log.js +9 -16
- package/dist/lib/task/artifact-command.js +1 -1
- package/dist/lib/task/artifact-lifecycle.js +61 -63
- package/dist/lib/task/artifact-name.js +0 -6
- package/dist/lib/task/artifact-operations.js +3 -3
- package/dist/lib/task/capabilities.js +4 -5
- package/dist/lib/task/commands/log.js +0 -6
- package/dist/lib/task/commands/status.js +17 -60
- package/dist/lib/task/commit-operation.js +28 -39
- package/dist/lib/task/completion-facts.js +56 -43
- package/dist/lib/task/control-authority.js +23 -256
- package/dist/lib/task/control-recovery.js +3 -5
- package/dist/lib/task/create.js +2 -4
- package/dist/lib/task/decision-intents.js +8 -9
- package/dist/lib/task/delivery-target.js +1 -40
- package/dist/lib/task/events.js +84 -107
- package/dist/lib/task/finalization.js +44 -8
- package/dist/lib/task/ledger-intents.js +1 -1
- package/dist/lib/task/lifecycle-execution.js +38 -33
- package/dist/lib/task/lifecycle.js +49 -41
- package/dist/lib/task/local-artifact-finalization.js +1 -4
- package/dist/lib/task/manual-validation-evidence.js +1 -37
- package/dist/lib/task/platform-operation-recovery.js +67 -24
- package/dist/lib/task/pr-delivery-fact.js +2 -5
- package/dist/lib/task/qualification-confirmation.js +5 -7
- package/dist/lib/task/resolve-ref.js +1 -25
- package/dist/lib/task/review-command.js +2 -2
- package/dist/lib/task/review-finalization.js +1 -21
- package/dist/lib/task/review-fingerprint.js +0 -4
- package/dist/lib/task/secure-fs.js +0 -56
- package/dist/lib/task/short-id.js +1 -39
- package/dist/lib/task/skill-scope.js +0 -1
- package/dist/lib/task/verification-engine.js +58 -282
- package/dist/lib/task/verification.js +6 -3
- package/dist/lib/task/write.js +11 -1
- package/lib/agent-clients/adapter.ts +0 -76
- package/lib/agent-clients/adapters/antigravity-cli.ts +0 -5
- package/lib/agent-clients/adapters/claude-code-credentials.ts +0 -19
- package/lib/agent-clients/adapters/claude-code.ts +0 -9
- package/lib/agent-clients/adapters/codex.ts +0 -56
- package/lib/agent-clients/adapters/opencode.ts +0 -5
- package/lib/agent-clients/adapters/traecli.ts +0 -5
- package/lib/agent-clients/config.ts +20 -61
- package/lib/agent-clients/registry.ts +1 -34
- package/lib/agent-clients/schema.ts +0 -18
- package/lib/agent-clients/tokens.ts +1 -2
- package/lib/agent-clients/types.ts +0 -15
- package/lib/decide.ts +1 -0
- package/lib/git/worktree-identity.ts +0 -10
- package/lib/internal/agent-client.ts +2 -70
- package/lib/internal/cli-route-inventory.ts +1 -4
- package/lib/internal/manual-validation.ts +16 -9
- package/lib/internal/task-create.ts +0 -1
- package/lib/internal/task-event.ts +1 -5
- package/lib/internal/task-finalization.ts +0 -1
- package/lib/internal/task-lifecycle.ts +3 -5
- package/lib/internal/task-operation-registry.ts +3 -19
- package/lib/internal/task-review.ts +4 -4
- package/lib/platform/comment-safety.ts +0 -10
- package/lib/platform/github-provider.ts +0 -2
- package/lib/platform/in-label-sync.ts +0 -16
- package/lib/platform/issue-comments.ts +0 -21
- package/lib/platform/issues.ts +0 -2
- package/lib/platform/operation-coordinator.ts +4 -2
- package/lib/platform/pr-change-report.ts +0 -5
- package/lib/platform/pr-checks.ts +1 -10
- package/lib/platform/pr-review.ts +1 -1
- package/lib/platform/provider-bridge.ts +0 -1
- package/lib/platform/provider-loader.ts +1 -5
- package/lib/platform/provider-validation.ts +1 -49
- package/lib/platform/pull-requests.ts +64 -99
- package/lib/platform/releases.ts +1 -40
- package/lib/platform/verification-required.ts +0 -2
- package/lib/platform/verification-sync.ts +0 -94
- package/lib/process-data/normalize.ts +1 -186
- package/lib/process-data/privacy.ts +2 -19
- package/lib/process-data/sources.ts +3 -283
- package/lib/render.ts +0 -15
- package/lib/run/index.ts +13 -7
- package/lib/run/skills.ts +0 -4
- package/lib/sandbox/commands/create.ts +37 -74
- package/lib/sandbox/commands/list-running.ts +0 -19
- package/lib/sandbox/commands/start.ts +7 -10
- package/lib/sandbox/constants.ts +0 -8
- package/lib/sandbox/control/client.ts +0 -1
- package/lib/sandbox/control/container-identity.ts +1 -16
- package/lib/sandbox/control/executor.ts +1 -5
- package/lib/sandbox/control/identity-sentinel.ts +0 -8
- package/lib/sandbox/control/lifecycle.ts +18 -51
- package/lib/sandbox/control/native-file-lock.ts +0 -8
- package/lib/sandbox/control/protocol.ts +0 -2
- package/lib/sandbox/control/server.ts +13 -39
- package/lib/sandbox/control/state.ts +1 -10
- package/lib/sandbox/dockerfile.ts +0 -11
- package/lib/sandbox/engine.ts +0 -17
- package/lib/sandbox/engines/docker-exact-discovery.ts +1 -5
- package/lib/sandbox/engines/wsl2-paths.ts +0 -4
- package/lib/sandbox/recovery.ts +24 -26
- package/lib/sandbox/removal.ts +11 -696
- package/lib/sandbox/shell.ts +1 -1
- package/lib/sandbox/task-resolver.ts +0 -48
- package/lib/sandbox/tools.ts +1 -5
- package/lib/sandbox/workspace-view.ts +2 -4
- package/lib/server/display.ts +0 -14
- package/lib/server/process-control.ts +1 -1
- package/lib/task/activity-intent.ts +36 -44
- package/lib/task/activity-log.ts +9 -22
- package/lib/task/artifact-command.ts +1 -1
- package/lib/task/artifact-lifecycle.ts +58 -67
- package/lib/task/artifact-name.ts +0 -7
- package/lib/task/artifact-operations.ts +3 -3
- package/lib/task/capabilities.ts +5 -6
- package/lib/task/commands/log.ts +0 -7
- package/lib/task/commands/status.ts +14 -79
- package/lib/task/commit-operation.ts +29 -51
- package/lib/task/completion-facts.ts +45 -42
- package/lib/task/control-authority.ts +27 -317
- package/lib/task/control-recovery.ts +2 -5
- package/lib/task/create.ts +2 -5
- package/lib/task/decision-intents.ts +5 -5
- package/lib/task/delivery-target.ts +0 -40
- package/lib/task/events.ts +89 -123
- package/lib/task/finalization.ts +41 -9
- package/lib/task/ledger-intents.ts +1 -1
- package/lib/task/lifecycle-execution.ts +37 -89
- package/lib/task/lifecycle.ts +48 -44
- package/lib/task/local-artifact-finalization.ts +0 -7
- package/lib/task/manual-validation-evidence.ts +1 -47
- package/lib/task/platform-operation-recovery.ts +50 -26
- package/lib/task/pr-delivery-fact.ts +2 -11
- package/lib/task/qualification-confirmation.ts +6 -6
- package/lib/task/resolve-ref.ts +0 -23
- package/lib/task/review-command.ts +2 -2
- package/lib/task/review-finalization.ts +1 -27
- package/lib/task/review-fingerprint.ts +0 -8
- package/lib/task/secure-fs.ts +0 -42
- package/lib/task/short-id.ts +0 -43
- package/lib/task/skill-scope.ts +0 -1
- package/lib/task/verification-engine.ts +56 -287
- package/lib/task/verification.ts +5 -5
- package/lib/task/write.ts +12 -1
- package/package.json +2 -2
- package/templates/.agents/README.en.md +1 -3
- package/templates/.agents/README.zh-CN.md +0 -2
- package/templates/.agents/rules/README.en.md +0 -1
- package/templates/.agents/rules/README.zh-CN.md +0 -1
- package/templates/.agents/rules/commit-and-pr.en.md +1 -1
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -1
- package/templates/.agents/rules/no-mid-flow-questions.en.md +0 -10
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +0 -10
- package/templates/.agents/rules/pr-sync.en.md +1 -1
- package/templates/.agents/rules/pr-sync.zh-CN.md +1 -1
- package/templates/.agents/rules/task-management.en.md +3 -3
- package/templates/.agents/rules/task-management.zh-CN.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/commit/SKILL.en.md +2 -2
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +6 -6
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +6 -6
- package/templates/.agents/skills/plan-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -5
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/review-plan/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-pr/SKILL.en.md +4 -4
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -75
- package/templates/.agents/templates/task.en.md +1 -0
- package/templates/.agents/templates/task.zh-CN.md +1 -0
- package/templates/.claude/settings.json +0 -24
- package/templates/.codex/hooks.json +0 -50
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +0 -582
- package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +0 -114
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +0 -237
- package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +0 -443
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +0 -236
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +0 -292
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +0 -267
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +0 -466
- package/dist/lib/internal/task-orchestration.js +0 -71
- package/dist/lib/platform/verification.js +0 -6
- package/dist/lib/run/prompt.js +0 -2
- package/dist/lib/sandbox/engines/authority.js +0 -289
- package/dist/lib/task/delegation-receipts.js +0 -410
- package/dist/lib/task/orchestration.js +0 -1233
- package/dist/lib/task/verification-checks.js +0 -9
- package/dist/lib/task/workspace-snapshot.js +0 -121
- package/dist/lifecycle-build-manifest.json +0 -6
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +0 -688
- package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +0 -147
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +0 -349
- package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +0 -506
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +0 -385
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -41
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +0 -418
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +0 -354
- package/lib/agent-clients/adapters/codex-orchestration.ts +0 -630
- package/lib/internal/task-orchestration.ts +0 -74
- package/lib/platform/verification.ts +0 -11
- package/lib/run/prompt.ts +0 -1
- package/lib/sandbox/engines/authority.ts +0 -365
- package/lib/task/delegation-receipts.ts +0 -547
- package/lib/task/orchestration.ts +0 -1651
- package/lib/task/verification-checks.ts +0 -10
- package/lib/task/workspace-snapshot.ts +0 -144
- package/templates/.agents/hooks/lifecycle-delegation.js +0 -140
- package/templates/.agents/rules/lifecycle-orchestration.en.md +0 -44
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +0 -44
- package/templates/.agents/skills/run-task/SKILL.en.md +0 -29
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +0 -29
- package/templates/.agents/skills/run-task/config/verify.en.json +0 -10
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +0 -10
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +0 -24
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +0 -24
- package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +0 -6
- package/templates/.claude/commands/run-task.en.md +0 -8
- package/templates/.claude/commands/run-task.zh-CN.md +0 -8
- package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +0 -3
- package/templates/.opencode/commands/run-task.en.md +0 -11
- package/templates/.opencode/commands/run-task.zh-CN.md +0 -11
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import { createCodexLifecycleStore, readCodexLifecycleActivationEvidence } 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 { recoverActivatedOrchestrationDelegation, readRun } from '../../../task/orchestration.js';
|
|
10
|
-
const ACTIONS = {
|
|
11
|
-
analysis: 'Analyze Task',
|
|
12
|
-
'review-analysis': 'Review Analysis',
|
|
13
|
-
plan: 'Plan Task',
|
|
14
|
-
'review-plan': 'Review Plan',
|
|
15
|
-
code: 'Code Task',
|
|
16
|
-
'review-code': 'Review Code'
|
|
17
|
-
};
|
|
18
|
-
function result(request, status, extra = {}) {
|
|
19
|
-
return {
|
|
20
|
-
status,
|
|
21
|
-
changed: status === 'applied',
|
|
22
|
-
targetState: 'active',
|
|
23
|
-
requestRef: request.taskRef,
|
|
24
|
-
intent: 'recover-started',
|
|
25
|
-
taskId: null,
|
|
26
|
-
receiptId: null,
|
|
27
|
-
childId: null,
|
|
28
|
-
error: null,
|
|
29
|
-
...extra
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
function failure(request, status, code, message, extra = {}) {
|
|
33
|
-
return result(request, status, { error: { code, message }, ...extra });
|
|
34
|
-
}
|
|
35
|
-
function actionPattern(receipt) {
|
|
36
|
-
const action = ACTIONS[receipt.stage];
|
|
37
|
-
if (!action)
|
|
38
|
-
return null;
|
|
39
|
-
const escaped = action.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
40
|
-
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');
|
|
41
|
-
}
|
|
42
|
-
function openRows(section) {
|
|
43
|
-
return pairEntries([...section.entries]).filter((row) => row.started !== '' && row.done === '');
|
|
44
|
-
}
|
|
45
|
-
function rowForReceipt(rows, receipt) {
|
|
46
|
-
const pattern = actionPattern(receipt);
|
|
47
|
-
return pattern ? rows.filter((row) => pattern.test(row.step)) : [];
|
|
48
|
-
}
|
|
49
|
-
function readLifecycleStore(options, repoRoot, taskId) {
|
|
50
|
-
return options.lifecycleStore ?? createCodexLifecycleStore({
|
|
51
|
-
repoRoot,
|
|
52
|
-
taskId,
|
|
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
|
-
if (!stopRecordMatchesReceipt(record, receipt)) {
|
|
70
|
-
return { ok: false, code: 'RECOVERY_TASK_BINDING_MISMATCH', message: 'lifecycle evidence belongs to a different task receipt' };
|
|
71
|
-
}
|
|
72
|
-
if (!stopEvidenceMatchesReceipt(record, receipt)) {
|
|
73
|
-
return { ok: false, code: 'RECOVERY_STOP_EVIDENCE_INVALID', message: 'Codex stop evidence does not match the activated receipt' };
|
|
74
|
-
}
|
|
75
|
-
if (record.consumer !== null && record.consumer !== receipt.id) {
|
|
76
|
-
return { ok: false, code: 'RECOVERY_CONSUMER_CONFLICT', message: `Codex lifecycle evidence was consumed by '${record.consumer}'` };
|
|
77
|
-
}
|
|
78
|
-
return { ok: true };
|
|
79
|
-
}
|
|
80
|
-
function stopRecordMatchesReceipt(record, receipt) {
|
|
81
|
-
return record.taskBinding?.runId === receipt.runId
|
|
82
|
-
&& record.taskBinding.receiptId === receipt.id;
|
|
83
|
-
}
|
|
84
|
-
function stopEvidenceMatchesReceipt(record, receipt) {
|
|
85
|
-
const start = record.state.startEvidence;
|
|
86
|
-
const stop = record.state.stopEvidence;
|
|
87
|
-
const host = readCodexLifecycleActivationEvidence(receipt);
|
|
88
|
-
if (!stopRecordHasRequiredEvidence(record, receipt, start, stop, host))
|
|
89
|
-
return false;
|
|
90
|
-
return spawnMatchesReceipt(record, receipt, host, start)
|
|
91
|
-
&& childMatchesReceipt(record, receipt, start, stop)
|
|
92
|
-
&& hostEvidenceMatches(record, receipt, host, start);
|
|
93
|
-
}
|
|
94
|
-
function stopRecordHasRequiredEvidence(record, receipt, start, stop, host) {
|
|
95
|
-
return receipt.client === 'codex'
|
|
96
|
-
&& host?.kind === 'codex-lifecycle-v2'
|
|
97
|
-
&& Boolean(start && stop && record.state.spawn && record.state.child && record.state.stop)
|
|
98
|
-
&& record.state.status === 'stop-ready'
|
|
99
|
-
&& stop?.terminalStatus === 'completed'
|
|
100
|
-
&& stop.hookStopObserved === true;
|
|
101
|
-
}
|
|
102
|
-
function spawnMatchesReceipt(record, receipt, host, start) {
|
|
103
|
-
const spawn = record.state.spawn;
|
|
104
|
-
return Boolean(spawn)
|
|
105
|
-
&& spawn.sessionId === start.parentThreadId
|
|
106
|
-
&& spawn.turnId === host.capabilityTurnId
|
|
107
|
-
&& spawn.toolUseId === host.spawnToolUseId
|
|
108
|
-
&& spawn.nativeAgent === start.nativeAgent
|
|
109
|
-
&& spawn.hookDefinitionHash === host.hookDefinitionHash
|
|
110
|
-
&& spawn.requestedModel === receipt.requestedModel
|
|
111
|
-
&& spawn.requestedReasoningEffort === receipt.requestedReasoningEffort
|
|
112
|
-
&& spawn.taskBinding?.runId === receipt.runId
|
|
113
|
-
&& spawn.taskBinding.receiptId === receipt.id;
|
|
114
|
-
}
|
|
115
|
-
function childMatchesReceipt(record, receipt, start, stop) {
|
|
116
|
-
const child = record.state.child;
|
|
117
|
-
const stopState = record.state.stop;
|
|
118
|
-
return Boolean(child && stopState)
|
|
119
|
-
&& child.sessionId === start.parentThreadId
|
|
120
|
-
&& stopState.turnId === child.turnId
|
|
121
|
-
&& (stopState.source === 'parent-rollout'
|
|
122
|
-
? stop.turnId === record.state.terminal?.turnId
|
|
123
|
-
: child.turnId === stop.turnId)
|
|
124
|
-
&& child.childThreadId === receipt.childId
|
|
125
|
-
&& child.nativeAgent === start.nativeAgent
|
|
126
|
-
&& stopState.childThreadId === receipt.childId
|
|
127
|
-
&& stopState.nativeAgent === start.nativeAgent
|
|
128
|
-
&& start.childThreadId === receipt.childId
|
|
129
|
-
&& start.parentThreadId === receipt.parentId
|
|
130
|
-
&& managedDelegationRole(start.nativeAgent) === receipt.role;
|
|
131
|
-
}
|
|
132
|
-
function hostEvidenceMatches(record, receipt, host, start) {
|
|
133
|
-
return start.hookDefinitionHash === host.hookDefinitionHash
|
|
134
|
-
&& host.capabilitySessionId === start.parentThreadId
|
|
135
|
-
&& host.capabilityTurnId === record.state.spawn?.turnId
|
|
136
|
-
&& host.spawnToolUseId === start.spawnToolUseId
|
|
137
|
-
&& Boolean(host.spawnObservedAt)
|
|
138
|
-
&& host.spawnObservedAt === record.spawnObservedAt
|
|
139
|
-
&& hostRevisionMatches(record, receipt, host);
|
|
140
|
-
}
|
|
141
|
-
function hostRevisionMatches(record, receipt, host) {
|
|
142
|
-
return host.startRevision >= 1
|
|
143
|
-
&& record.revision > host.startRevision
|
|
144
|
-
&& record.state.child?.childThreadId === receipt.childId
|
|
145
|
-
&& record.state.stop?.childThreadId === receipt.childId;
|
|
146
|
-
}
|
|
147
|
-
function abortedCandidates(run, rows) {
|
|
148
|
-
const candidates = run.receipts.flatMap((receipt) => {
|
|
149
|
-
if (receipt.status !== 'aborted' || receipt.activatedAt === null || receipt.client !== 'codex')
|
|
150
|
-
return [];
|
|
151
|
-
const matches = rowForReceipt(rows, receipt);
|
|
152
|
-
return matches.length === 1 ? [{ receipt, row: matches[0] }] : [];
|
|
153
|
-
});
|
|
154
|
-
return candidates;
|
|
155
|
-
}
|
|
156
|
-
function appendRecoveryLog(request, taskId, section, candidate, repoRoot, writer) {
|
|
157
|
-
const metadata = captureTaskWriteMetadata();
|
|
158
|
-
const body = appendActivityEntry(section, {
|
|
159
|
-
time: metadata.timestamp,
|
|
160
|
-
step: `${candidate.row.step} [aborted]`,
|
|
161
|
-
agent: request.agent,
|
|
162
|
-
note: `terminated Codex delegation; receipt=${candidate.receipt.id}; child=${candidate.receipt.childId}`
|
|
163
|
-
});
|
|
164
|
-
const written = writer({
|
|
165
|
-
taskRef: taskId,
|
|
166
|
-
expectedState: 'active',
|
|
167
|
-
mutations: [{ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body }]
|
|
168
|
-
}, { repoRoot, metadataProvider: () => metadata });
|
|
169
|
-
if (written.status === 'failed') {
|
|
170
|
-
return failure(request, 'owner-unknown', 'RECOVERY_LOG_WRITE_FAILED', written.error.message, {
|
|
171
|
-
taskId, receiptId: candidate.receipt.id, childId: candidate.receipt.childId
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
return result(request, 'applied', {
|
|
175
|
-
taskId, receiptId: candidate.receipt.id, childId: candidate.receipt.childId
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
function recoverStartedLifecycle(request, options = {}) {
|
|
179
|
-
if (!request || request.intent !== 'recover-started' || request.auto !== true || normalizeAgentToken(request.agent) !== 'codex') {
|
|
180
|
-
return failure(request, 'conflict', 'RECOVERY_PAYLOAD_INVALID', 'automatic recovery requires a task and the Codex agent');
|
|
181
|
-
}
|
|
182
|
-
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
183
|
-
if (!resolved.ok)
|
|
184
|
-
return failure(request, 'conflict', resolved.code, resolved.message);
|
|
185
|
-
const taskId = resolved.taskId;
|
|
186
|
-
let content;
|
|
187
|
-
try {
|
|
188
|
-
content = fs.readFileSync(resolved.taskMdPath, 'utf8');
|
|
189
|
-
parseTypedTaskFrontmatter(content);
|
|
190
|
-
}
|
|
191
|
-
catch (error) {
|
|
192
|
-
return failure(request, 'conflict', 'RECOVERY_TASK_INVALID', error instanceof Error ? error.message : String(error), { taskId });
|
|
193
|
-
}
|
|
194
|
-
const section = locateActivityLog(content);
|
|
195
|
-
if (!section)
|
|
196
|
-
return failure(request, 'conflict', 'RECOVERY_LOG_INVALID', 'task has no unique Activity Log section', { taskId });
|
|
197
|
-
let run;
|
|
198
|
-
try {
|
|
199
|
-
run = readRun(resolved.taskDir, options.orchestration);
|
|
200
|
-
}
|
|
201
|
-
catch (error) {
|
|
202
|
-
return failure(request, 'owner-unknown', 'RECOVERY_ORCHESTRATION_UNKNOWN', error instanceof Error ? error.message : String(error), { taskId });
|
|
203
|
-
}
|
|
204
|
-
if (!run)
|
|
205
|
-
return result(request, 'no-op', { taskId });
|
|
206
|
-
const rows = openRows(section);
|
|
207
|
-
const pending = run.pendingDelegation;
|
|
208
|
-
if (!pending)
|
|
209
|
-
return recoverAbortedLifecycle(request, taskId, section, resolved.repoRoot, run, rows, options);
|
|
210
|
-
return recoverActiveLifecycle(request, taskId, section, resolved.repoRoot, run, rows, pending, options);
|
|
211
|
-
}
|
|
212
|
-
function recoverAbortedLifecycle(request, taskId, section, repoRoot, run, rows, options) {
|
|
213
|
-
const candidates = abortedCandidates(run, rows);
|
|
214
|
-
if (candidates.length === 0)
|
|
215
|
-
return result(request, 'no-op', { taskId });
|
|
216
|
-
if (candidates.length > 1) {
|
|
217
|
-
return failure(request, 'conflict', 'RECOVERY_CANDIDATE_AMBIGUOUS', 'more than one aborted delegation has an open lifecycle row', { taskId });
|
|
218
|
-
}
|
|
219
|
-
return appendRecoveryLog(request, taskId, section, candidates[0], repoRoot, options.writeTask ?? writeTask);
|
|
220
|
-
}
|
|
221
|
-
function recoverActiveLifecycle(request, taskId, section, repoRoot, run, rows, pending, options) {
|
|
222
|
-
if (pending.status !== 'activated')
|
|
223
|
-
return result(request, 'no-op', { taskId });
|
|
224
|
-
if (pending.client !== 'codex' || run.status !== 'running' || run.pause !== null) {
|
|
225
|
-
return failure(request, 'conflict', 'RECOVERY_ORCHESTRATION_INVALID', 'activated recovery requires one running Codex delegation', {
|
|
226
|
-
taskId, receiptId: pending.id, childId: pending.childId
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
const rowResult = matchingActiveRecoveryRow(request, taskId, rows, pending);
|
|
230
|
-
if ('result' in rowResult)
|
|
231
|
-
return rowResult.result;
|
|
232
|
-
const evidenceResult = consumeRecoveryEvidence(request, taskId, repoRoot, pending, options);
|
|
233
|
-
if ('result' in evidenceResult)
|
|
234
|
-
return evidenceResult.result;
|
|
235
|
-
return finishActiveRecovery(request, taskId, section, repoRoot, pending, rowResult.row, options);
|
|
236
|
-
}
|
|
237
|
-
function matchingActiveRecoveryRow(request, taskId, rows, pending) {
|
|
238
|
-
const matchingRows = rowForReceipt(rows, pending);
|
|
239
|
-
if (matchingRows.length !== 1 || normalizeAgentToken(matchingRows[0].agent) !== 'codex' || matchingRows[0].note !== 'started') {
|
|
240
|
-
return { result: failure(request, 'conflict', 'RECOVERY_LOG_CONFLICT', 'activated delegation does not have one matching open lifecycle row', {
|
|
241
|
-
taskId, receiptId: pending.id, childId: pending.childId
|
|
242
|
-
}) };
|
|
243
|
-
}
|
|
244
|
-
if (!pending.childId) {
|
|
245
|
-
return { result: failure(request, 'conflict', 'RECOVERY_DELEGATION_INVALID', 'activated delegation has no child identity', { taskId, receiptId: pending.id }) };
|
|
246
|
-
}
|
|
247
|
-
return { row: matchingRows[0] };
|
|
248
|
-
}
|
|
249
|
-
function consumeRecoveryEvidence(request, taskId, repoRoot, pending, options) {
|
|
250
|
-
const store = readLifecycleStore(options, repoRoot, taskId);
|
|
251
|
-
const stored = readStoredEvidence(store, pending.childId);
|
|
252
|
-
if ('error' in stored)
|
|
253
|
-
return { result: failure(request, 'owner-unknown', 'RECOVERY_STORE_UNKNOWN', stored.error.message, { taskId, receiptId: pending.id, childId: pending.childId }) };
|
|
254
|
-
if ('missing' in stored)
|
|
255
|
-
return { result: failure(request, 'owner-unknown', 'RECOVERY_STOP_EVIDENCE_MISSING', 'matching Codex lifecycle stop evidence is missing', { taskId, receiptId: pending.id, childId: pending.childId }) };
|
|
256
|
-
const evidence = validateStopRecord(stored, pending);
|
|
257
|
-
if (!evidence.ok)
|
|
258
|
-
return { result: failure(request, evidence.code === 'RECOVERY_CONSUMER_CONFLICT' ? 'conflict' : 'owner-unknown', evidence.code, evidence.message, { taskId, receiptId: pending.id, childId: pending.childId }) };
|
|
259
|
-
let consumed = stored;
|
|
260
|
-
if (stored.consumer === null) {
|
|
261
|
-
try {
|
|
262
|
-
consumed = store.consume(pending.childId, pending.id, stored.state.startEvidence?.hookDefinitionHash, {
|
|
263
|
-
taskId: pending.taskId, runId: pending.runId, receiptId: pending.id
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
catch (error) {
|
|
267
|
-
return { result: failure(request, 'owner-unknown', 'RECOVERY_EVIDENCE_CONSUME_FAILED', error instanceof Error ? error.message : String(error), { taskId, receiptId: pending.id, childId: pending.childId }) };
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return consumed.consumedAt
|
|
271
|
-
? { consumed }
|
|
272
|
-
: { result: failure(request, 'owner-unknown', 'RECOVERY_EVIDENCE_INVALID', 'consumed stop evidence has no timestamp', { taskId, receiptId: pending.id, childId: pending.childId }) };
|
|
273
|
-
}
|
|
274
|
-
function finishActiveRecovery(request, taskId, section, repoRoot, pending, row, options) {
|
|
275
|
-
const recovered = recoverActivatedOrchestrationDelegation(taskId, {
|
|
276
|
-
receiptId: pending.id,
|
|
277
|
-
stage: pending.stage,
|
|
278
|
-
round: pending.round,
|
|
279
|
-
artifact: pending.artifact,
|
|
280
|
-
startedAgent: request.agent,
|
|
281
|
-
childId: pending.childId
|
|
282
|
-
}, { ...options.orchestration, repoRoot, now: options.now });
|
|
283
|
-
if (recovered.status === 'failed' || !recovered.run) {
|
|
284
|
-
return failure(request, 'owner-unknown', recovered.error?.code ?? 'RECOVERY_ORCHESTRATION_FAILED', recovered.error?.message ?? 'orchestration recovery failed', { taskId, receiptId: pending.id, childId: pending.childId });
|
|
285
|
-
}
|
|
286
|
-
return appendRecoveryLog(request, taskId, section, { receipt: recovered.run.receipts.at(-1), row }, repoRoot, options.writeTask ?? writeTask);
|
|
287
|
-
}
|
|
288
|
-
function recoverStartedLifecycleFromAdapter(request, options = {}) {
|
|
289
|
-
return recoverStartedLifecycle(request, options);
|
|
290
|
-
}
|
|
291
|
-
export { recoverStartedLifecycle, recoverStartedLifecycleFromAdapter };
|
|
292
|
-
//# sourceMappingURL=recovery.js.map
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
import crypto from 'node:crypto';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { mutateDelegationAdapterEvidence, readRun } from '../../../task/orchestration.js';
|
|
4
|
-
import { resolveTaskRef } from '../../../task/resolve-ref.js';
|
|
5
|
-
import { createCodexLifecycleState, expireCodexLifecycleState, reduceCodexLifecycleEvent } from './evidence.js';
|
|
6
|
-
function readCodexLifecycleActivationEvidence(receipt) {
|
|
7
|
-
const state = storedEvidence(receipt.adapterEvidence?.codex);
|
|
8
|
-
return state.activationEvidence && typeof state.activationEvidence === 'object'
|
|
9
|
-
? state.activationEvidence
|
|
10
|
-
: null;
|
|
11
|
-
}
|
|
12
|
-
const NON_PERSISTENT_FAILURES = new Set([
|
|
13
|
-
'CODEX_EVIDENCE_IDENTITY_MISMATCH',
|
|
14
|
-
'CODEX_EVIDENCE_PARENT_MISMATCH',
|
|
15
|
-
'CODEX_EVIDENCE_REPLAY_CONFLICT'
|
|
16
|
-
]);
|
|
17
|
-
function recordKey(sessionId, turnId, toolUseId) {
|
|
18
|
-
return crypto.createHash('sha256').update(`${sessionId}\0${turnId}\0${toolUseId}`).digest('hex');
|
|
19
|
-
}
|
|
20
|
-
function isRecord(value) {
|
|
21
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
22
|
-
}
|
|
23
|
-
function storedEvidence(value) {
|
|
24
|
-
if (!isRecord(value) || !isRecord(value.records))
|
|
25
|
-
return Object.freeze({ records: Object.freeze({}) });
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
28
|
-
function receipts(taskDir) {
|
|
29
|
-
const run = readRun(taskDir);
|
|
30
|
-
return run ? Object.freeze([...run.receipts, ...(run.pendingDelegation ? [run.pendingDelegation] : [])]) : [];
|
|
31
|
-
}
|
|
32
|
-
function allRecords(taskDir) {
|
|
33
|
-
return Object.freeze(receipts(taskDir).flatMap((receipt) => {
|
|
34
|
-
const state = storedEvidence(receipt.adapterEvidence?.codex);
|
|
35
|
-
return Object.values(state.records);
|
|
36
|
-
}));
|
|
37
|
-
}
|
|
38
|
-
function lifecyclePath(taskDir) {
|
|
39
|
-
return path.join(taskDir, '.runtime', 'orchestration.json');
|
|
40
|
-
}
|
|
41
|
-
function assertCurrentCanApply(current, binding) {
|
|
42
|
-
if (current.revision > 0 && binding && JSON.stringify(current.taskBinding) !== JSON.stringify(binding)) {
|
|
43
|
-
throw new Error('Codex lifecycle task binding does not match the stored spawn');
|
|
44
|
-
}
|
|
45
|
-
if (current.consumer)
|
|
46
|
-
throw new Error(`Codex lifecycle evidence was already consumed by '${current.consumer}'`);
|
|
47
|
-
}
|
|
48
|
-
function hasActiveCodexLifecycleEvidence(taskDir, query) {
|
|
49
|
-
return allRecords(taskDir).some((record) => {
|
|
50
|
-
return record.consumer === null
|
|
51
|
-
&& !['invalid', 'expired'].includes(record.state.status)
|
|
52
|
-
&& record.state.spawn?.hookDefinitionHash === query.hookDefinitionHash
|
|
53
|
-
&& (!query.identity || record.state.spawn?.sessionId === query.identity.sessionId
|
|
54
|
-
&& record.state.spawn.turnId === query.identity.turnId
|
|
55
|
-
&& record.state.spawn.toolUseId === query.identity.toolUseId);
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
function createCodexLifecycleStore(options) {
|
|
59
|
-
if (!/^TASK-[0-9]{8}-[0-9]{6}$/u.test(options.taskId)) {
|
|
60
|
-
throw new Error('Codex lifecycle store task id is invalid');
|
|
61
|
-
}
|
|
62
|
-
const repoRoot = options.repoRoot ?? process.cwd();
|
|
63
|
-
const resolved = resolveTaskRef(options.taskId, { repoRoot });
|
|
64
|
-
if (!resolved.ok)
|
|
65
|
-
throw new Error(`${resolved.code}: ${resolved.message}`);
|
|
66
|
-
const taskDir = resolved.taskDir;
|
|
67
|
-
const now = options.now ?? (() => new Date().toISOString());
|
|
68
|
-
function currentBinding() {
|
|
69
|
-
const run = readRun(taskDir);
|
|
70
|
-
const receipt = run?.pendingDelegation;
|
|
71
|
-
if (!run || !receipt || receipt.client !== 'codex') {
|
|
72
|
-
throw new Error('Codex lifecycle evidence has no current task delegation');
|
|
73
|
-
}
|
|
74
|
-
return Object.freeze({ taskId: receipt.taskId, runId: receipt.runId, receiptId: receipt.id });
|
|
75
|
-
}
|
|
76
|
-
function findByChild(childThreadId) {
|
|
77
|
-
return allRecords(taskDir).filter((record) => record.state.child?.childThreadId === childThreadId);
|
|
78
|
-
}
|
|
79
|
-
function locate(event) {
|
|
80
|
-
if (event.type === 'hook-spawn') {
|
|
81
|
-
const key = recordKey(event.sessionId, event.turnId, event.toolUseId);
|
|
82
|
-
const existing = allRecords(taskDir).find((record) => record.spawnObservedAt && record.state.spawn
|
|
83
|
-
&& recordKey(record.state.spawn.sessionId, record.state.spawn.turnId, record.state.spawn.toolUseId) === key);
|
|
84
|
-
return existing ?? Object.freeze({
|
|
85
|
-
schemaVersion: 2,
|
|
86
|
-
revision: 0,
|
|
87
|
-
taskBinding: event.taskBinding ?? null,
|
|
88
|
-
state: createCodexLifecycleState(options.cliVersion),
|
|
89
|
-
consumer: null,
|
|
90
|
-
consumedAt: null,
|
|
91
|
-
spawnObservedAt: null,
|
|
92
|
-
updatedAt: now()
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
if (event.type === 'hook-child') {
|
|
96
|
-
const matches = allRecords(taskDir).filter((record) => record.state.spawn?.sessionId === event.parentThreadId
|
|
97
|
-
&& record.state.spawn.nativeAgent === event.nativeAgent
|
|
98
|
-
&& (!record.state.child || record.state.child.childThreadId === event.childThreadId));
|
|
99
|
-
if (matches.length !== 1) {
|
|
100
|
-
throw new Error(matches.length === 0
|
|
101
|
-
? 'Codex lifecycle parent session and agent correlation was not found'
|
|
102
|
-
: 'Codex lifecycle parent session and agent correlation is ambiguous');
|
|
103
|
-
}
|
|
104
|
-
return matches[0];
|
|
105
|
-
}
|
|
106
|
-
const matches = findByChild(event.childThreadId);
|
|
107
|
-
if (matches.length !== 1) {
|
|
108
|
-
throw new Error(matches.length === 0
|
|
109
|
-
? `Codex lifecycle child '${event.childThreadId}' was not found`
|
|
110
|
-
: `Codex lifecycle child '${event.childThreadId}' is ambiguous`);
|
|
111
|
-
}
|
|
112
|
-
return matches[0];
|
|
113
|
-
}
|
|
114
|
-
function update(binding, key, mutate) {
|
|
115
|
-
let result = null;
|
|
116
|
-
mutateDelegationAdapterEvidence(options.taskId, binding.receiptId, 'codex', (value) => {
|
|
117
|
-
const currentState = storedEvidence(value);
|
|
118
|
-
const current = currentState.records[key] ?? null;
|
|
119
|
-
result = mutate(current);
|
|
120
|
-
return Object.freeze({
|
|
121
|
-
...currentState,
|
|
122
|
-
records: Object.freeze({ ...currentState.records, [key]: result })
|
|
123
|
-
});
|
|
124
|
-
}, { repoRoot, now });
|
|
125
|
-
if (!result)
|
|
126
|
-
throw new Error('Codex lifecycle record was not updated');
|
|
127
|
-
return result;
|
|
128
|
-
}
|
|
129
|
-
function apply(event) {
|
|
130
|
-
const existing = event.type === 'hook-spawn' ? null : locate(event);
|
|
131
|
-
const binding = event.type === 'hook-spawn' ? event.taskBinding ?? currentBinding() : existing?.taskBinding;
|
|
132
|
-
if (!binding)
|
|
133
|
-
throw new Error('Codex lifecycle event has no task receipt binding');
|
|
134
|
-
const key = event.type === 'hook-spawn'
|
|
135
|
-
? recordKey(event.sessionId, event.turnId, event.toolUseId)
|
|
136
|
-
: existing?.state.spawn
|
|
137
|
-
? recordKey(existing.state.spawn.sessionId, existing.state.spawn.turnId, existing.state.spawn.toolUseId)
|
|
138
|
-
: '';
|
|
139
|
-
const observedAt = now();
|
|
140
|
-
const next = update(binding, key, (current) => {
|
|
141
|
-
const base = current ?? Object.freeze({
|
|
142
|
-
schemaVersion: 2,
|
|
143
|
-
revision: 0,
|
|
144
|
-
taskBinding: binding,
|
|
145
|
-
state: createCodexLifecycleState(options.cliVersion),
|
|
146
|
-
consumer: null,
|
|
147
|
-
consumedAt: null,
|
|
148
|
-
spawnObservedAt: null,
|
|
149
|
-
updatedAt: observedAt
|
|
150
|
-
});
|
|
151
|
-
assertCurrentCanApply(base, binding);
|
|
152
|
-
const state = reduceCodexLifecycleEvent(base.state, event);
|
|
153
|
-
if (state === base.state)
|
|
154
|
-
return base;
|
|
155
|
-
if (state.status === 'invalid' && state.error && NON_PERSISTENT_FAILURES.has(state.error.code)) {
|
|
156
|
-
throw new Error(`${state.error.code}: ${state.error.message}`);
|
|
157
|
-
}
|
|
158
|
-
return Object.freeze({
|
|
159
|
-
...base,
|
|
160
|
-
revision: base.revision + 1,
|
|
161
|
-
state,
|
|
162
|
-
spawnObservedAt: event.type === 'hook-spawn' && base.revision === 0 ? observedAt : base.spawnObservedAt,
|
|
163
|
-
updatedAt: observedAt
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
return Object.freeze({ path: lifecyclePath(taskDir), revision: next.revision, state: next.state });
|
|
167
|
-
}
|
|
168
|
-
function applyToSpawn(identity, event, expectedRevision) {
|
|
169
|
-
const key = recordKey(identity.sessionId, identity.turnId, identity.toolUseId);
|
|
170
|
-
const current = allRecords(taskDir).find((record) => record.state.spawn
|
|
171
|
-
&& recordKey(record.state.spawn.sessionId, record.state.spawn.turnId, record.state.spawn.toolUseId) === key);
|
|
172
|
-
if (!current)
|
|
173
|
-
throw new Error('Codex lifecycle spawn identity was not found');
|
|
174
|
-
const next = update(identity.taskBinding, key, (latest) => {
|
|
175
|
-
if (!latest || JSON.stringify(latest.taskBinding) !== JSON.stringify(identity.taskBinding)) {
|
|
176
|
-
throw new Error('Codex lifecycle task binding does not match the stored spawn');
|
|
177
|
-
}
|
|
178
|
-
if (latest.revision !== expectedRevision) {
|
|
179
|
-
throw new Error(`Codex lifecycle revision changed from ${expectedRevision} to ${latest.revision}`);
|
|
180
|
-
}
|
|
181
|
-
if (latest.consumer)
|
|
182
|
-
throw new Error(`Codex lifecycle evidence was already consumed by '${latest.consumer}'`);
|
|
183
|
-
if (latest.state.spawn?.sessionId !== identity.sessionId
|
|
184
|
-
|| latest.state.spawn.turnId !== identity.turnId
|
|
185
|
-
|| latest.state.spawn.toolUseId !== identity.toolUseId
|
|
186
|
-
|| latest.state.spawn.nativeAgent !== event.nativeAgent
|
|
187
|
-
|| event.sessionId !== identity.sessionId
|
|
188
|
-
|| event.parentThreadId !== identity.sessionId) {
|
|
189
|
-
throw new Error('Codex lifecycle spawn identity does not match the stored event');
|
|
190
|
-
}
|
|
191
|
-
const state = reduceCodexLifecycleEvent(latest.state, event);
|
|
192
|
-
if (state.status === 'invalid' && state.error && NON_PERSISTENT_FAILURES.has(state.error.code)) {
|
|
193
|
-
throw new Error(`${state.error.code}: ${state.error.message}`);
|
|
194
|
-
}
|
|
195
|
-
return state === latest.state ? latest : Object.freeze({ ...latest, revision: latest.revision + 1, state, updatedAt: now() });
|
|
196
|
-
});
|
|
197
|
-
return Object.freeze({ path: lifecyclePath(taskDir), revision: next.revision, state: next.state });
|
|
198
|
-
}
|
|
199
|
-
function findByParent(parentThreadId) {
|
|
200
|
-
const matches = allRecords(taskDir).filter((record) => record.state.startEvidence?.parentThreadId === parentThreadId
|
|
201
|
-
&& ['start-ready', 'observed-terminal', 'stop-ready'].includes(record.state.status));
|
|
202
|
-
const unconsumed = matches.filter((record) => !record.consumer);
|
|
203
|
-
if (unconsumed.length > 1)
|
|
204
|
-
throw new Error(`Codex lifecycle parent '${parentThreadId}' has ambiguous active children`);
|
|
205
|
-
return Object.freeze(unconsumed.length === 1 ? unconsumed : matches.filter((record) => record.consumer));
|
|
206
|
-
}
|
|
207
|
-
function findByTaskBinding(binding) {
|
|
208
|
-
return Object.freeze(allRecords(taskDir).filter((record) => record.taskBinding?.runId === binding.runId
|
|
209
|
-
&& record.taskBinding.receiptId === binding.receiptId));
|
|
210
|
-
}
|
|
211
|
-
function read(childThreadId) {
|
|
212
|
-
const matches = findByChild(childThreadId);
|
|
213
|
-
if (matches.length !== 1)
|
|
214
|
-
throw new Error(`Codex lifecycle child '${childThreadId}' was not found uniquely`);
|
|
215
|
-
return matches[0];
|
|
216
|
-
}
|
|
217
|
-
function consume(childThreadId, consumer, expectedHookDefinitionHash, expectedTaskBinding) {
|
|
218
|
-
if (!consumer.trim())
|
|
219
|
-
throw new Error('Codex lifecycle consumer is required');
|
|
220
|
-
const current = read(childThreadId);
|
|
221
|
-
const binding = expectedTaskBinding ?? current.taskBinding;
|
|
222
|
-
if (!binding)
|
|
223
|
-
throw new Error('Codex lifecycle task receipt binding is missing');
|
|
224
|
-
const spawn = current.state.spawn;
|
|
225
|
-
if (!spawn)
|
|
226
|
-
throw new Error('Codex lifecycle spawn evidence is missing');
|
|
227
|
-
const key = recordKey(spawn.sessionId, spawn.turnId, spawn.toolUseId);
|
|
228
|
-
return update(binding, key, (latest) => {
|
|
229
|
-
if (!latest || expectedTaskBinding && JSON.stringify(latest.taskBinding) !== JSON.stringify(expectedTaskBinding)) {
|
|
230
|
-
throw new Error('Codex lifecycle task binding does not match the expected receipt');
|
|
231
|
-
}
|
|
232
|
-
if (latest.consumer && latest.consumer !== consumer) {
|
|
233
|
-
throw new Error(`Codex lifecycle evidence was already consumed by '${latest.consumer}'`);
|
|
234
|
-
}
|
|
235
|
-
if (latest.state.status !== 'stop-ready')
|
|
236
|
-
throw new Error('Codex lifecycle evidence is not stop-ready');
|
|
237
|
-
if (expectedHookDefinitionHash && latest.state.startEvidence?.hookDefinitionHash !== expectedHookDefinitionHash) {
|
|
238
|
-
throw new Error('Codex lifecycle hook definition hash is stale');
|
|
239
|
-
}
|
|
240
|
-
if (latest.consumer)
|
|
241
|
-
return latest;
|
|
242
|
-
return Object.freeze({ ...latest, revision: latest.revision + 1, consumer, consumedAt: now(), updatedAt: now() });
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
function expireBefore(cutoff) {
|
|
246
|
-
let changed = 0;
|
|
247
|
-
for (const record of allRecords(taskDir)) {
|
|
248
|
-
if (record.updatedAt >= cutoff || !record.taskBinding?.receiptId || !record.state.spawn)
|
|
249
|
-
continue;
|
|
250
|
-
const key = recordKey(record.state.spawn.sessionId, record.state.spawn.turnId, record.state.spawn.toolUseId);
|
|
251
|
-
update(record.taskBinding, key, (latest) => {
|
|
252
|
-
if (!latest || latest.updatedAt >= cutoff || latest.consumer
|
|
253
|
-
|| ['invalid', 'expired', 'stop-ready'].includes(latest.state.status))
|
|
254
|
-
return latest ?? record;
|
|
255
|
-
const state = expireCodexLifecycleState(latest.state);
|
|
256
|
-
if (state === latest.state)
|
|
257
|
-
return latest;
|
|
258
|
-
changed += 1;
|
|
259
|
-
return Object.freeze({ ...latest, revision: latest.revision + 1, state, updatedAt: now() });
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
return changed;
|
|
263
|
-
}
|
|
264
|
-
return Object.freeze({ taskId: options.taskId, root: path.join(taskDir, '.runtime'), apply, applyToSpawn, consume, expireBefore, findByParent, findByTaskBinding, read });
|
|
265
|
-
}
|
|
266
|
-
export { createCodexLifecycleStore, hasActiveCodexLifecycleEvidence, readCodexLifecycleActivationEvidence };
|
|
267
|
-
//# sourceMappingURL=store.js.map
|