@fitlab-ai/agent-infra 0.11.11 → 0.11.13
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 +2 -2
- package/dist/lib/agent-clients/adapter.js +7 -1
- package/dist/lib/agent-clients/adapters/claude-code.js +5 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +78 -63
- package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +114 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +447 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-client.js +130 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-operation.js +131 -0
- package/dist/lib/{sandbox/control → agent-clients/adapters/codex-lifecycle}/controller-registration.js +2 -2
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +48 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +124 -62
- package/dist/lib/{internal/codex-sandbox-controller.js → agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.js} +3 -3
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -5
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +211 -213
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +468 -0
- package/dist/lib/agent-clients/adapters/codex.js +40 -1
- package/dist/lib/agent-clients/adapters/index.js +2 -10
- package/dist/lib/agent-clients/tokens.js +3 -2
- package/dist/lib/internal/agent-client.js +132 -72
- package/dist/lib/internal/cli-route-inventory.js +2 -2
- package/dist/lib/internal/sandbox-control.js +1 -81
- package/dist/lib/internal/task-finalization.js +26 -19
- package/dist/lib/internal/task-lifecycle.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +1 -1
- package/dist/lib/internal/task-validate.js +1 -1
- package/dist/lib/platform/github-client.js +33 -3
- package/dist/lib/platform/issues.js +18 -6
- package/dist/lib/runtime/agent-runtime.js +6 -29
- package/dist/lib/sandbox/commands/control-status.js +1 -0
- package/dist/lib/sandbox/commands/create.js +7 -2
- package/dist/lib/sandbox/commands/ls.js +4 -5
- package/dist/lib/sandbox/commands/rm.js +1 -1
- package/dist/lib/sandbox/control/agent-operation.js +34 -0
- package/dist/lib/sandbox/control/client.js +14 -201
- package/dist/lib/sandbox/control/executor.js +12 -125
- package/dist/lib/sandbox/control/lifecycle.js +66 -4
- package/dist/lib/sandbox/control/protocol.js +15 -54
- package/dist/lib/sandbox/control/server.js +216 -281
- package/dist/lib/sandbox/control/task-view.js +0 -13
- package/dist/lib/sandbox/mounts.js +9 -1
- package/dist/lib/sandbox/recovery.js +31 -10
- package/dist/lib/sandbox/removal.js +28 -5
- package/dist/lib/sandbox/workspace-identity.js +18 -6
- package/dist/lib/sandbox/workspace-view.js +56 -19
- package/dist/lib/task/commands/ls.js +3 -3
- package/dist/lib/task/control-authority.js +56 -264
- package/dist/lib/task/control-recovery.js +2 -3
- package/dist/lib/task/create.js +2 -2
- package/dist/lib/task/delegation-receipts.js +74 -161
- package/dist/lib/task/events.js +88 -44
- package/dist/lib/task/finalization.js +35 -6
- package/dist/lib/task/lifecycle.js +274 -115
- package/dist/lib/task/orchestration.js +201 -194
- package/dist/lib/task/runtime-paths.js +10 -0
- package/dist/lib/task/short-id.js +37 -27
- package/dist/lib/task/verification-engine.js +32 -26
- package/dist/lib/task/workspace-snapshot.js +1 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapter.ts +39 -0
- package/lib/agent-clients/adapters/claude-code.ts +5 -1
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +105 -80
- package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +147 -0
- package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +510 -0
- package/lib/agent-clients/adapters/codex-lifecycle/controller-client.ts +158 -0
- package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +1 -1
- package/lib/agent-clients/adapters/codex-lifecycle/controller-operation.ts +151 -0
- package/lib/{sandbox/control → agent-clients/adapters/codex-lifecycle}/controller-registration.ts +4 -4
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +43 -0
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +8 -5
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +190 -65
- package/lib/{internal/codex-sandbox-controller.ts → agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.ts} +2 -2
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -5
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +270 -224
- package/lib/agent-clients/adapters/codex-orchestration.ts +632 -0
- package/lib/agent-clients/adapters/codex.ts +44 -1
- package/lib/agent-clients/adapters/index.ts +7 -20
- package/lib/agent-clients/tokens.ts +4 -3
- package/lib/internal/agent-client.ts +142 -73
- package/lib/internal/cli-route-inventory.ts +2 -2
- package/lib/internal/sandbox-control.ts +0 -97
- package/lib/internal/task-finalization.ts +30 -18
- package/lib/internal/task-lifecycle.ts +1 -1
- package/lib/internal/task-operation-registry.ts +1 -1
- package/lib/internal/task-validate.ts +1 -1
- package/lib/platform/github-client.ts +34 -3
- package/lib/platform/issues.ts +18 -6
- package/lib/runtime/agent-runtime.ts +6 -41
- package/lib/sandbox/commands/control-status.ts +1 -0
- package/lib/sandbox/commands/create.ts +7 -1
- package/lib/sandbox/commands/ls.ts +4 -5
- package/lib/sandbox/commands/rm.ts +1 -1
- package/lib/sandbox/control/agent-operation.ts +49 -0
- package/lib/sandbox/control/client.ts +20 -254
- package/lib/sandbox/control/executor.ts +13 -136
- package/lib/sandbox/control/lifecycle.ts +67 -4
- package/lib/sandbox/control/protocol.ts +22 -66
- package/lib/sandbox/control/server.ts +21 -95
- package/lib/sandbox/control/task-view.ts +0 -19
- package/lib/sandbox/mounts.ts +10 -1
- package/lib/sandbox/recovery.ts +38 -17
- package/lib/sandbox/removal.ts +33 -7
- package/lib/sandbox/workspace-identity.ts +16 -6
- package/lib/sandbox/workspace-view.ts +50 -18
- package/lib/task/commands/ls.ts +3 -3
- package/lib/task/control-authority.ts +66 -378
- package/lib/task/control-recovery.ts +3 -4
- package/lib/task/create.ts +3 -3
- package/lib/task/delegation-receipts.ts +87 -231
- package/lib/task/events.ts +100 -42
- package/lib/task/finalization.ts +37 -7
- package/lib/task/lifecycle.ts +257 -109
- package/lib/task/orchestration.ts +260 -237
- package/lib/task/runtime-paths.ts +12 -0
- package/lib/task/short-id.ts +33 -40
- package/lib/task/verification-engine.ts +30 -25
- package/lib/task/workspace-snapshot.ts +1 -1
- package/package.json +1 -1
- package/templates/.agents/hooks/lifecycle-delegation.js +1 -25
- package/templates/.agents/rules/README.en.md +2 -1
- package/templates/.agents/rules/README.zh-CN.md +2 -1
- package/templates/.agents/rules/next-step-output.en.md +6 -19
- package/templates/.agents/rules/next-step-output.zh-CN.md +6 -19
- package/templates/.agents/rules/strategy-pattern.en.md +25 -0
- package/templates/.agents/rules/strategy-pattern.zh-CN.md +25 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/check-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +4 -0
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +4 -0
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +0 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +0 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +5 -29
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +5 -26
- package/templates/.agents/skills/plan-task/SKILL.en.md +7 -4
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/review-analysis/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/review-code/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/review-plan/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +1 -1
- 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/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +0 -546
- package/dist/lib/internal/codex-lifecycle.js +0 -385
- package/dist/lib/task/codex-orchestration.js +0 -206
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +0 -776
- package/lib/internal/codex-lifecycle.ts +0 -390
- package/lib/task/codex-orchestration.ts +0 -276
package/dist/bin/internal-cli.js
CHANGED
|
@@ -111,12 +111,12 @@ if (!controlRouted && !taskViewGuardFailed && internalRouteRegistered)
|
|
|
111
111
|
break;
|
|
112
112
|
}
|
|
113
113
|
case 'codex-lifecycle': {
|
|
114
|
-
const { codexLifecycle } = await import('../lib/
|
|
114
|
+
const { codexLifecycle } = await import('../lib/agent-clients/adapters/codex-lifecycle/cli.js');
|
|
115
115
|
await codexLifecycle(process.argv.slice(3));
|
|
116
116
|
break;
|
|
117
117
|
}
|
|
118
118
|
case 'codex-sandbox-controller': {
|
|
119
|
-
const { codexSandboxController } = await import('../lib/
|
|
119
|
+
const { codexSandboxController } = await import('../lib/agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.js');
|
|
120
120
|
await codexSandboxController(process.argv.slice(3));
|
|
121
121
|
break;
|
|
122
122
|
}
|
|
@@ -211,7 +211,10 @@ function defineAgentClientAdapter(candidate) {
|
|
|
211
211
|
const evidence = candidate.delegationEvidence;
|
|
212
212
|
if (!evidence
|
|
213
213
|
|| !['host-event', 'app-server', 'unavailable'].includes(evidence.actualModel)
|
|
214
|
-
|| !['host-event', 'app-server', 'spawn-ack', 'unavailable'].includes(evidence.actualReasoningEffort)
|
|
214
|
+
|| !['host-event', 'app-server', 'spawn-ack', 'unavailable'].includes(evidence.actualReasoningEffort)
|
|
215
|
+
|| ['spawnModeRequired', 'actualModelRequired', 'actualReasoningEffortRequired', 'fallbackReasonRequired']
|
|
216
|
+
.some((key) => evidence[key] !== undefined
|
|
217
|
+
&& typeof evidence[key] !== 'boolean')) {
|
|
215
218
|
throw new Error(`Agent Client '${candidate.id}' has invalid delegation evidence`);
|
|
216
219
|
}
|
|
217
220
|
if (typeof candidate.project !== 'object'
|
|
@@ -431,6 +434,9 @@ function defineAgentClientAdapter(candidate) {
|
|
|
431
434
|
...(candidate.orchestrationAdapter === undefined
|
|
432
435
|
? {}
|
|
433
436
|
: { orchestrationAdapter: Object.freeze({ ...candidate.orchestrationAdapter }) }),
|
|
437
|
+
...(candidate.sandboxControlOperation === undefined
|
|
438
|
+
? {}
|
|
439
|
+
: { sandboxControlOperation: Object.freeze({ ...candidate.sandboxControlOperation }) }),
|
|
434
440
|
project: Object.freeze({
|
|
435
441
|
ownedPathPrefixes: Object.freeze(paths),
|
|
436
442
|
...projectAssets,
|
|
@@ -22,7 +22,11 @@ const claudeCodeAdapter = defineAgentClientAdapter({
|
|
|
22
22
|
},
|
|
23
23
|
delegationEvidence: {
|
|
24
24
|
actualModel: 'host-event',
|
|
25
|
-
actualReasoningEffort: 'spawn-ack'
|
|
25
|
+
actualReasoningEffort: 'spawn-ack',
|
|
26
|
+
spawnModeRequired: false,
|
|
27
|
+
actualModelRequired: false,
|
|
28
|
+
actualReasoningEffortRequired: false,
|
|
29
|
+
fallbackReasonRequired: false
|
|
26
30
|
},
|
|
27
31
|
project: {
|
|
28
32
|
ownedPathPrefixes: ['.claude/'],
|
|
@@ -4,7 +4,9 @@ import fs from 'node:fs';
|
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import semver from 'semver';
|
|
7
|
-
import {
|
|
7
|
+
import { parseCodexLifecycleBinding } from './binding.js';
|
|
8
|
+
import { hasActiveCodexLifecycleEvidence } from './store.js';
|
|
9
|
+
import { resolveTaskContext, resolveTaskRef } from '../../../task/resolve-ref.js';
|
|
8
10
|
const LIFECYCLE_HOOKS = Object.freeze([
|
|
9
11
|
Object.freeze({ event: 'PreToolUse', matcher: '^collaborationspawn_agent$', phase: 'pre-tool' }),
|
|
10
12
|
Object.freeze({ event: 'PostToolUse', matcher: '', phase: 'post-tool' }),
|
|
@@ -25,16 +27,15 @@ function object(value) {
|
|
|
25
27
|
function nonEmpty(value) {
|
|
26
28
|
return typeof value === 'string' && value.trim() ? value : null;
|
|
27
29
|
}
|
|
28
|
-
function
|
|
30
|
+
function readRolloutRecords(transcriptPath, sessionId) {
|
|
29
31
|
const name = path.basename(transcriptPath);
|
|
30
|
-
if (!transcriptPath || (!name.endsWith(`-${
|
|
32
|
+
if (!transcriptPath || (!name.endsWith(`-${sessionId}.jsonl`) && name !== `${sessionId}.jsonl`)) {
|
|
31
33
|
throw new Error('Codex parent rollout path is invalid');
|
|
32
34
|
}
|
|
33
35
|
const stat = fs.lstatSync(transcriptPath);
|
|
34
36
|
if (!stat.isFile() || stat.isSymbolicLink())
|
|
35
37
|
throw new Error('Codex parent rollout is not a regular file');
|
|
36
|
-
const
|
|
37
|
-
const offset = Math.max(0, stat.size - maxBytes);
|
|
38
|
+
const offset = Math.max(0, stat.size - 8 * 1024 * 1024);
|
|
38
39
|
const buffer = Buffer.alloc(stat.size - offset);
|
|
39
40
|
const descriptor = fs.openSync(transcriptPath, 'r');
|
|
40
41
|
try {
|
|
@@ -46,37 +47,48 @@ function resolveCodexSpawnedChild(transcriptPath, expected) {
|
|
|
46
47
|
let text = buffer.toString('utf8');
|
|
47
48
|
if (offset)
|
|
48
49
|
text = text.slice(text.indexOf('\n') + 1);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
return text.split(/\r?\n/u).filter(Boolean).map((line) => object(JSON.parse(line))).filter((record) => Boolean(record));
|
|
51
|
+
}
|
|
52
|
+
function isExpectedSpawnCall(record, expected) {
|
|
53
|
+
const payload = object(record.payload);
|
|
54
|
+
return record.type === 'response_item'
|
|
55
|
+
&& payload?.type === 'function_call'
|
|
56
|
+
&& payload.call_id === expected.toolUseId
|
|
57
|
+
&& payload.namespace === 'collaboration'
|
|
58
|
+
&& payload.name === 'spawn_agent';
|
|
59
|
+
}
|
|
60
|
+
function spawnArgsMatch(args, expected) {
|
|
61
|
+
return args?.agent_type === expected.nativeAgent
|
|
62
|
+
&& args.task_name === expected.taskName
|
|
63
|
+
&& (!expected.requestedModel || args.model === expected.requestedModel)
|
|
64
|
+
&& (!expected.requestedReasoningEffort || args.reasoning_effort === expected.requestedReasoningEffort);
|
|
65
|
+
}
|
|
66
|
+
function isExpectedChildActivity(record, expected) {
|
|
67
|
+
const payload = object(record.payload);
|
|
68
|
+
const item = object(payload?.item);
|
|
69
|
+
return record.type === 'event_msg'
|
|
70
|
+
&& payload?.type === 'item_completed'
|
|
71
|
+
&& payload.thread_id === expected.sessionId
|
|
72
|
+
&& payload.turn_id === expected.turnId
|
|
73
|
+
&& item?.type === 'SubAgentActivity'
|
|
74
|
+
&& item.id === expected.toolUseId
|
|
75
|
+
&& item.kind === 'started'
|
|
76
|
+
&& item.agent_path === `/root/${expected.taskName}`
|
|
77
|
+
&& Boolean(nonEmpty(item.agent_thread_id));
|
|
78
|
+
}
|
|
79
|
+
function resolveCodexSpawnedChild(transcriptPath, expected) {
|
|
80
|
+
if (!parseCodexLifecycleBinding(expected.taskName)) {
|
|
81
|
+
throw new Error('Codex spawn task_name does not carry a valid lifecycle binding');
|
|
82
|
+
}
|
|
83
|
+
const records = readRolloutRecords(transcriptPath, expected.sessionId);
|
|
84
|
+
const calls = records.filter((record) => isExpectedSpawnCall(record, expected));
|
|
58
85
|
if (calls.length !== 1)
|
|
59
86
|
throw new Error('Codex parent rollout spawn call was not found uniquely');
|
|
60
87
|
const call = object(calls[0]?.payload);
|
|
61
88
|
const args = object(JSON.parse(nonEmpty(call?.arguments) ?? '{}'));
|
|
62
|
-
if (args
|
|
63
|
-
|| args.task_name !== expected.taskName
|
|
64
|
-
|| (expected.requestedModel && args.model !== expected.requestedModel)
|
|
65
|
-
|| (expected.requestedReasoningEffort && args.reasoning_effort !== expected.requestedReasoningEffort))
|
|
89
|
+
if (!spawnArgsMatch(args, expected))
|
|
66
90
|
throw new Error('Codex parent rollout spawn identity does not match the hook event');
|
|
67
|
-
const activities = records.filter((record) =>
|
|
68
|
-
const payload = object(record?.payload);
|
|
69
|
-
const item = object(payload?.item);
|
|
70
|
-
return record?.type === 'event_msg'
|
|
71
|
-
&& payload?.type === 'item_completed'
|
|
72
|
-
&& payload.thread_id === expected.sessionId
|
|
73
|
-
&& payload.turn_id === expected.turnId
|
|
74
|
-
&& item?.type === 'SubAgentActivity'
|
|
75
|
-
&& item.id === expected.toolUseId
|
|
76
|
-
&& item.kind === 'started'
|
|
77
|
-
&& item.agent_path === `/root/${expected.taskName}`
|
|
78
|
-
&& nonEmpty(item.agent_thread_id);
|
|
79
|
-
});
|
|
91
|
+
const activities = records.filter((record) => isExpectedChildActivity(record, expected));
|
|
80
92
|
if (activities.length !== 1)
|
|
81
93
|
throw new Error('Codex parent rollout child activity was not found uniquely');
|
|
82
94
|
return nonEmpty(object(object(activities[0]?.payload)?.item)?.agent_thread_id);
|
|
@@ -141,27 +153,6 @@ function parseCodexHooksList(value, repoRoot, expectedSource = 'direct-host') {
|
|
|
141
153
|
throw new Error('CODEX_PREFLIGHT_HOOKS_NOT_LOADED: lifecycle hooks are not loaded for this workspace');
|
|
142
154
|
return Object.freeze(hooks);
|
|
143
155
|
}
|
|
144
|
-
function hasCodexRuntimeLiveness(runtimeRoot, hookDefinitionHash, identity) {
|
|
145
|
-
if (!identity || !fs.existsSync(runtimeRoot))
|
|
146
|
-
return false;
|
|
147
|
-
return fs.readdirSync(runtimeRoot)
|
|
148
|
-
.filter((name) => /^[a-f0-9]{64}\.json$/.test(name))
|
|
149
|
-
.some((name) => {
|
|
150
|
-
try {
|
|
151
|
-
const record = object(JSON.parse(fs.readFileSync(path.join(runtimeRoot, name), 'utf8')));
|
|
152
|
-
const state = object(record?.state);
|
|
153
|
-
const spawnEvent = object(state?.spawn);
|
|
154
|
-
return !['invalid', 'expired'].includes(String(state?.status))
|
|
155
|
-
&& spawnEvent?.hookDefinitionHash === hookDefinitionHash
|
|
156
|
-
&& spawnEvent.sessionId === identity.sessionId
|
|
157
|
-
&& spawnEvent.turnId === identity.turnId
|
|
158
|
-
&& spawnEvent.toolUseId === identity.toolUseId;
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
156
|
function parseCodexThreadResolution(readValue, rolloutRecords) {
|
|
166
157
|
const readRoot = object(readValue);
|
|
167
158
|
const thread = object(readRoot?.thread);
|
|
@@ -215,6 +206,17 @@ function parseCodexThreadResolution(readValue, rolloutRecords) {
|
|
|
215
206
|
})
|
|
216
207
|
});
|
|
217
208
|
}
|
|
209
|
+
function resolvePreflightTaskDir(repoRoot, taskId) {
|
|
210
|
+
try {
|
|
211
|
+
const context = taskId
|
|
212
|
+
? resolveTaskRef(taskId, { repoRoot })
|
|
213
|
+
: resolveTaskContext(undefined, { repoRoot });
|
|
214
|
+
return context.ok ? context.taskDir : undefined;
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
218
220
|
function readCodexRolloutRecords(readValue, childThreadId) {
|
|
219
221
|
const thread = object(object(readValue)?.thread);
|
|
220
222
|
const rolloutPath = nonEmpty(thread?.path);
|
|
@@ -491,7 +493,24 @@ async function resolveCodexTerminal(childThreadId, expectedTurnIdOrOptions = {},
|
|
|
491
493
|
transport.close();
|
|
492
494
|
}
|
|
493
495
|
}
|
|
494
|
-
async function preflightCodexLifecycleEvidence(repoRoot = process.cwd(), runtimeIdentity) {
|
|
496
|
+
async function preflightCodexLifecycleEvidence(repoRoot = process.cwd(), runtimeIdentity, taskId) {
|
|
497
|
+
const { cliVersion, hooksRaw } = validateStaticCodexPreflight(repoRoot);
|
|
498
|
+
const hookDefinitionHash = crypto.createHash('sha256').update(hooksRaw).digest('hex');
|
|
499
|
+
const taskDir = resolvePreflightTaskDir(repoRoot, taskId);
|
|
500
|
+
const runtimeLiveness = Boolean(taskDir && runtimeIdentity
|
|
501
|
+
&& hasActiveCodexLifecycleEvidence(taskDir, { hookDefinitionHash, identity: runtimeIdentity }));
|
|
502
|
+
const host = await discoverLifecycleHooks(repoRoot);
|
|
503
|
+
return Object.freeze({
|
|
504
|
+
cliVersion,
|
|
505
|
+
hookDefinitionHash,
|
|
506
|
+
staticReady: true,
|
|
507
|
+
discoveredHooks: host.discoveredHooks,
|
|
508
|
+
hookProvenance: host.hookProvenance,
|
|
509
|
+
runtimeLiveness,
|
|
510
|
+
diagnostics: host.diagnostics
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
function validateStaticCodexPreflight(repoRoot) {
|
|
495
514
|
const versionRun = spawnSync('codex', ['--version'], { encoding: 'utf8' });
|
|
496
515
|
const match = /codex-cli\s+(\d+\.\d+\.\d+)/.exec(versionRun.stdout ?? '');
|
|
497
516
|
if (versionRun.status !== 0 || !match?.[1] || !semver.gte(match[1], '0.147.0')) {
|
|
@@ -519,9 +538,9 @@ async function preflightCodexLifecycleEvidence(repoRoot = process.cwd(), runtime
|
|
|
519
538
|
finally {
|
|
520
539
|
fs.rmSync(schemaDir, { recursive: true, force: true });
|
|
521
540
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
541
|
+
return { cliVersion: match[1], hooksRaw };
|
|
542
|
+
}
|
|
543
|
+
async function discoverLifecycleHooks(repoRoot) {
|
|
525
544
|
const transport = new CodexAppServerTransport();
|
|
526
545
|
transport.start();
|
|
527
546
|
let discoveredHooks;
|
|
@@ -548,10 +567,7 @@ async function preflightCodexLifecycleEvidence(repoRoot = process.cwd(), runtime
|
|
|
548
567
|
const hookSource = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT
|
|
549
568
|
? 'isolated-user'
|
|
550
569
|
: source === 'managed' ? 'managed' : 'project';
|
|
551
|
-
return
|
|
552
|
-
cliVersion: match[1],
|
|
553
|
-
hookDefinitionHash,
|
|
554
|
-
staticReady: true,
|
|
570
|
+
return {
|
|
555
571
|
discoveredHooks,
|
|
556
572
|
hookProvenance: Object.freeze({
|
|
557
573
|
hookSource,
|
|
@@ -563,9 +579,8 @@ async function preflightCodexLifecycleEvidence(repoRoot = process.cwd(), runtime
|
|
|
563
579
|
currentHash: hook.currentHash
|
|
564
580
|
})))).digest('hex')
|
|
565
581
|
}),
|
|
566
|
-
runtimeLiveness,
|
|
567
582
|
diagnostics: transport.diagnostics
|
|
568
|
-
}
|
|
583
|
+
};
|
|
569
584
|
}
|
|
570
|
-
export { CodexAppServerTransport,
|
|
585
|
+
export { CodexAppServerTransport, parseCodexModelReroute, parseCodexHooksList, parseCodexThreadResolution, parseCodexTurnCompleted, resolveCodexSpawnedChild, preflightCodexLifecycleEvidence, resolveCodexTerminal, resolveCodexThread, validateCodexLifecycleHookConfig };
|
|
571
586
|
//# sourceMappingURL=app-server.js.map
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { managedDelegationRole } from '../../../task/delegation-receipts.js';
|
|
2
|
+
const MARKER_PREFIX = '__agent_infra_binding_';
|
|
3
|
+
const BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
|
|
4
|
+
const TASK_ID_PATTERN = /^TASK-[0-9]{8}-[0-9]{6}$/u;
|
|
5
|
+
const SAFE_LABEL_PATTERN = /^[a-z0-9_]{1,80}$/u;
|
|
6
|
+
const SAFE_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/u;
|
|
7
|
+
function assertSafeTaskName(taskName) {
|
|
8
|
+
if (Buffer.byteLength(taskName, 'utf8') > 255 || !/^[a-z0-9_]+$/u.test(taskName)) {
|
|
9
|
+
throw new Error('Codex task_name must use lowercase letters, digits, and underscores within 255 bytes');
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function encodeTaskNamePayload(value) {
|
|
13
|
+
let buffer = 0;
|
|
14
|
+
let bits = 0;
|
|
15
|
+
let encoded = '';
|
|
16
|
+
for (const byte of Buffer.from(value, 'utf8')) {
|
|
17
|
+
buffer = (buffer << 8) | byte;
|
|
18
|
+
bits += 8;
|
|
19
|
+
while (bits >= 5) {
|
|
20
|
+
encoded += BASE32_ALPHABET[(buffer >>> (bits - 5)) & 31];
|
|
21
|
+
bits -= 5;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (bits)
|
|
25
|
+
encoded += BASE32_ALPHABET[(buffer << (5 - bits)) & 31];
|
|
26
|
+
return encoded;
|
|
27
|
+
}
|
|
28
|
+
function decodeTaskNamePayload(encoded) {
|
|
29
|
+
let buffer = 0;
|
|
30
|
+
let bits = 0;
|
|
31
|
+
const bytes = [];
|
|
32
|
+
for (const character of encoded) {
|
|
33
|
+
const value = BASE32_ALPHABET.indexOf(character);
|
|
34
|
+
if (value < 0)
|
|
35
|
+
return null;
|
|
36
|
+
buffer = (buffer << 5) | value;
|
|
37
|
+
bits += 5;
|
|
38
|
+
if (bits >= 8) {
|
|
39
|
+
bytes.push((buffer >>> (bits - 8)) & 255);
|
|
40
|
+
bits -= 8;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (bits && (buffer & ((1 << bits) - 1)) !== 0)
|
|
44
|
+
return null;
|
|
45
|
+
const decoded = Buffer.from(bytes).toString('utf8');
|
|
46
|
+
return encodeTaskNamePayload(decoded) === encoded ? decoded : null;
|
|
47
|
+
}
|
|
48
|
+
function encodeCodexLifecycleBinding(binding) {
|
|
49
|
+
if (!TASK_ID_PATTERN.test(binding.taskId)
|
|
50
|
+
|| !SAFE_ID_PATTERN.test(binding.runId)
|
|
51
|
+
|| !SAFE_ID_PATTERN.test(binding.receiptId)) {
|
|
52
|
+
throw new Error('Codex lifecycle task binding is invalid');
|
|
53
|
+
}
|
|
54
|
+
return `${MARKER_PREFIX}${encodeTaskNamePayload(JSON.stringify(binding))}`;
|
|
55
|
+
}
|
|
56
|
+
function appendCodexLifecycleBinding(label, binding) {
|
|
57
|
+
if (!SAFE_LABEL_PATTERN.test(label))
|
|
58
|
+
throw new Error('Codex task_name label is invalid');
|
|
59
|
+
const taskName = `${label}${encodeCodexLifecycleBinding(binding)}`;
|
|
60
|
+
assertSafeTaskName(taskName);
|
|
61
|
+
return taskName;
|
|
62
|
+
}
|
|
63
|
+
function parseCodexLifecycleBinding(taskName) {
|
|
64
|
+
assertSafeTaskName(taskName);
|
|
65
|
+
const markerIndex = taskName.lastIndexOf(MARKER_PREFIX);
|
|
66
|
+
if (markerIndex < 1)
|
|
67
|
+
return null;
|
|
68
|
+
const label = taskName.slice(0, markerIndex);
|
|
69
|
+
const encoded = taskName.slice(markerIndex + MARKER_PREFIX.length);
|
|
70
|
+
if (!SAFE_LABEL_PATTERN.test(label) || !/^[a-z2-7]+$/u.test(encoded))
|
|
71
|
+
return null;
|
|
72
|
+
try {
|
|
73
|
+
const decoded = decodeTaskNamePayload(encoded);
|
|
74
|
+
if (!decoded)
|
|
75
|
+
return null;
|
|
76
|
+
const value = JSON.parse(decoded);
|
|
77
|
+
if (Object.keys(value).sort().join(',') !== 'receiptId,runId,taskId'
|
|
78
|
+
|| typeof value.taskId !== 'string' || !TASK_ID_PATTERN.test(value.taskId)
|
|
79
|
+
|| typeof value.runId !== 'string' || !SAFE_ID_PATTERN.test(value.runId)
|
|
80
|
+
|| typeof value.receiptId !== 'string' || !SAFE_ID_PATTERN.test(value.receiptId))
|
|
81
|
+
return null;
|
|
82
|
+
return Object.freeze({
|
|
83
|
+
taskName,
|
|
84
|
+
label,
|
|
85
|
+
binding: Object.freeze({ taskId: value.taskId, runId: value.runId, receiptId: value.receiptId })
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function verifyCodexLifecycleTaskBinding(binding, run, nativeAgent, expected = {}) {
|
|
93
|
+
if (!codexReceiptMatchesBinding(binding, run, nativeAgent, expected)) {
|
|
94
|
+
throw new Error('Codex lifecycle task binding does not match the current pending receipt');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function codexReceiptMatchesBinding(binding, run, nativeAgent, expected) {
|
|
98
|
+
const receipt = run.pendingDelegation;
|
|
99
|
+
return Boolean(receipt)
|
|
100
|
+
&& run.status === 'running'
|
|
101
|
+
&& run.runId === binding.runId
|
|
102
|
+
&& receipt.runId === binding.runId
|
|
103
|
+
&& receipt.id === binding.receiptId
|
|
104
|
+
&& receipt.client === 'codex'
|
|
105
|
+
&& receipt.status === 'prepared'
|
|
106
|
+
&& managedDelegationRole(nativeAgent) === receipt.role
|
|
107
|
+
&& requestedBindingMatches(receipt, expected);
|
|
108
|
+
}
|
|
109
|
+
function requestedBindingMatches(receipt, expected) {
|
|
110
|
+
return (!expected.requestedModel || receipt.requestedModel === expected.requestedModel)
|
|
111
|
+
&& (!expected.requestedReasoningEffort || receipt.requestedReasoningEffort === expected.requestedReasoningEffort);
|
|
112
|
+
}
|
|
113
|
+
export { appendCodexLifecycleBinding, encodeCodexLifecycleBinding, parseCodexLifecycleBinding, verifyCodexLifecycleTaskBinding };
|
|
114
|
+
//# sourceMappingURL=binding.js.map
|