@fitlab-ai/agent-infra 0.11.10 → 0.11.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/dist/bin/internal-cli.js +2 -2
  2. package/dist/lib/agent-clients/adapter.js +27 -1
  3. package/dist/lib/agent-clients/adapters/claude-code.js +5 -1
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +78 -63
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +114 -0
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +447 -0
  7. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-client.js +130 -0
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-operation.js +131 -0
  9. package/dist/lib/{sandbox/control → agent-clients/adapters/codex-lifecycle}/controller-registration.js +2 -2
  10. package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +48 -1
  11. package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +124 -62
  12. package/dist/lib/{internal/codex-sandbox-controller.js → agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.js} +3 -3
  13. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -5
  14. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +222 -210
  15. package/dist/lib/agent-clients/adapters/codex-orchestration.js +468 -0
  16. package/dist/lib/agent-clients/adapters/codex-sandbox.js +13 -0
  17. package/dist/lib/agent-clients/adapters/codex.js +44 -1
  18. package/dist/lib/agent-clients/adapters/index.js +2 -10
  19. package/dist/lib/agent-clients/tokens.js +3 -2
  20. package/dist/lib/internal/agent-client.js +132 -72
  21. package/dist/lib/internal/cli-route-inventory.js +2 -2
  22. package/dist/lib/internal/manual-validation.js +2 -2
  23. package/dist/lib/internal/platform-pr.js +4 -5
  24. package/dist/lib/internal/task-artifact.js +1 -1
  25. package/dist/lib/internal/task-create.js +15 -1
  26. package/dist/lib/internal/task-finalization.js +1 -3
  27. package/dist/lib/internal/task-operation-registry.js +5 -139
  28. package/dist/lib/internal/task-validate.js +1 -1
  29. package/dist/lib/platform/issues.js +18 -6
  30. package/dist/lib/platform/pr-summary.js +45 -8
  31. package/dist/lib/platform/pull-requests.js +79 -14
  32. package/dist/lib/platform/verification-sync.js +17 -14
  33. package/dist/lib/runtime/agent-runtime.js +6 -29
  34. package/dist/lib/sandbox/commands/control-status.js +1 -0
  35. package/dist/lib/sandbox/commands/create.js +19 -2
  36. package/dist/lib/sandbox/commands/enter.js +47 -33
  37. package/dist/lib/sandbox/control/agent-operation.js +34 -0
  38. package/dist/lib/sandbox/control/client.js +68 -161
  39. package/dist/lib/sandbox/control/executor.js +13 -87
  40. package/dist/lib/sandbox/control/host-recovery.js +218 -0
  41. package/dist/lib/sandbox/control/protocol.js +15 -44
  42. package/dist/lib/sandbox/control/server.js +57 -51
  43. package/dist/lib/sandbox/environment.js +150 -0
  44. package/dist/lib/sandbox/mounts.js +2 -1
  45. package/dist/lib/sandbox/recovery.js +11 -1
  46. package/dist/lib/sandbox/removal.js +9 -5
  47. package/dist/lib/sandbox/workspace-identity.js +0 -14
  48. package/dist/lib/sandbox/workspace-view.js +41 -23
  49. package/dist/lib/task/artifact-command.js +7 -2
  50. package/dist/lib/task/artifact-lifecycle.js +2 -1
  51. package/dist/lib/task/capabilities.js +4 -1
  52. package/dist/lib/task/control-authority.js +54 -266
  53. package/dist/lib/task/control-recovery.js +1 -1
  54. package/dist/lib/task/create.js +2 -2
  55. package/dist/lib/task/delegation-receipts.js +74 -161
  56. package/dist/lib/task/events.js +89 -45
  57. package/dist/lib/task/finalization.js +58 -60
  58. package/dist/lib/task/frontmatter.js +24 -1
  59. package/dist/lib/task/ledger-intents.js +2 -1
  60. package/dist/lib/task/lifecycle.js +84 -97
  61. package/dist/lib/task/orchestration.js +182 -129
  62. package/dist/lib/task/platform-operation-journal.js +12 -0
  63. package/dist/lib/task/platform-operation-recovery.js +14 -7
  64. package/dist/lib/task/resolve-ref.js +8 -3
  65. package/dist/lib/task/runtime-paths.js +10 -0
  66. package/dist/lib/task/verification-engine.js +28 -15
  67. package/dist/lib/task/workspace-snapshot.js +1 -1
  68. package/dist/lifecycle-build-manifest.json +3 -3
  69. package/lib/agent-clients/adapter.ts +61 -0
  70. package/lib/agent-clients/adapters/claude-code.ts +5 -1
  71. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +105 -80
  72. package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +147 -0
  73. package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +510 -0
  74. package/lib/agent-clients/adapters/codex-lifecycle/controller-client.ts +158 -0
  75. package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +1 -1
  76. package/lib/agent-clients/adapters/codex-lifecycle/controller-operation.ts +151 -0
  77. package/lib/{sandbox/control → agent-clients/adapters/codex-lifecycle}/controller-registration.ts +4 -4
  78. package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +43 -0
  79. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +8 -5
  80. package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +190 -65
  81. package/lib/{internal/codex-sandbox-controller.ts → agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.ts} +2 -2
  82. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -5
  83. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +272 -223
  84. package/lib/agent-clients/adapters/codex-orchestration.ts +632 -0
  85. package/lib/agent-clients/adapters/codex-sandbox.ts +13 -0
  86. package/lib/agent-clients/adapters/codex.ts +48 -1
  87. package/lib/agent-clients/adapters/index.ts +7 -20
  88. package/lib/agent-clients/tokens.ts +4 -3
  89. package/lib/internal/agent-client.ts +142 -73
  90. package/lib/internal/cli-route-inventory.ts +2 -2
  91. package/lib/internal/manual-validation.ts +2 -2
  92. package/lib/internal/platform-pr.ts +3 -4
  93. package/lib/internal/task-artifact.ts +1 -1
  94. package/lib/internal/task-create.ts +15 -2
  95. package/lib/internal/task-finalization.ts +1 -3
  96. package/lib/internal/task-operation-registry.ts +5 -151
  97. package/lib/internal/task-validate.ts +1 -1
  98. package/lib/platform/issues.ts +18 -6
  99. package/lib/platform/pr-summary.ts +43 -7
  100. package/lib/platform/pull-requests.ts +74 -13
  101. package/lib/platform/verification-sync.ts +18 -14
  102. package/lib/runtime/agent-runtime.ts +6 -41
  103. package/lib/sandbox/commands/control-status.ts +1 -0
  104. package/lib/sandbox/commands/create.ts +25 -2
  105. package/lib/sandbox/commands/enter.ts +42 -39
  106. package/lib/sandbox/control/agent-operation.ts +49 -0
  107. package/lib/sandbox/control/client.ts +86 -210
  108. package/lib/sandbox/control/executor.ts +17 -96
  109. package/lib/sandbox/control/host-recovery.ts +195 -0
  110. package/lib/sandbox/control/protocol.ts +24 -55
  111. package/lib/sandbox/control/server.ts +54 -52
  112. package/lib/sandbox/environment.ts +162 -0
  113. package/lib/sandbox/mounts.ts +2 -1
  114. package/lib/sandbox/recovery.ts +13 -1
  115. package/lib/sandbox/removal.ts +12 -5
  116. package/lib/sandbox/tool-types.ts +1 -0
  117. package/lib/sandbox/workspace-identity.ts +0 -26
  118. package/lib/sandbox/workspace-view.ts +42 -24
  119. package/lib/task/artifact-command.ts +9 -2
  120. package/lib/task/artifact-lifecycle.ts +2 -1
  121. package/lib/task/capabilities.ts +5 -2
  122. package/lib/task/control-authority.ts +65 -382
  123. package/lib/task/control-recovery.ts +2 -2
  124. package/lib/task/create.ts +3 -3
  125. package/lib/task/delegation-receipts.ts +87 -231
  126. package/lib/task/events.ts +101 -43
  127. package/lib/task/finalization.ts +57 -58
  128. package/lib/task/frontmatter.ts +25 -1
  129. package/lib/task/ledger-intents.ts +2 -1
  130. package/lib/task/lifecycle.ts +82 -87
  131. package/lib/task/orchestration.ts +237 -176
  132. package/lib/task/platform-operation-journal.ts +29 -2
  133. package/lib/task/platform-operation-recovery.ts +12 -6
  134. package/lib/task/resolve-ref.ts +8 -3
  135. package/lib/task/runtime-paths.ts +12 -0
  136. package/lib/task/verification-engine.ts +27 -16
  137. package/lib/task/workspace-snapshot.ts +1 -1
  138. package/package.json +1 -1
  139. package/templates/.agents/hooks/lifecycle-delegation.js +1 -25
  140. package/templates/.agents/rules/README.en.md +2 -2
  141. package/templates/.agents/rules/README.zh-CN.md +2 -2
  142. package/templates/.agents/rules/issue-sync.en.md +1 -1
  143. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  144. package/templates/.agents/rules/next-step-output.en.md +6 -19
  145. package/templates/.agents/rules/next-step-output.zh-CN.md +6 -19
  146. package/templates/.agents/rules/no-mid-flow-questions.en.md +19 -0
  147. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +19 -0
  148. package/templates/.agents/rules/review-handshake.en.md +3 -0
  149. package/templates/.agents/rules/review-handshake.zh-CN.md +3 -0
  150. package/templates/.agents/rules/task-management.en.md +1 -1
  151. package/templates/.agents/rules/task-management.zh-CN.md +1 -1
  152. package/templates/.agents/skills/analyze-task/SKILL.en.md +2 -2
  153. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +2 -2
  154. package/templates/.agents/skills/block-task/SKILL.en.md +1 -1
  155. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +1 -1
  156. package/templates/.agents/skills/cancel-task/SKILL.en.md +1 -1
  157. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +1 -1
  158. package/templates/.agents/skills/check-task/SKILL.en.md +1 -1
  159. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +1 -1
  160. package/templates/.agents/skills/close-codescan/SKILL.en.md +3 -0
  161. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -0
  162. package/templates/.agents/skills/close-dependabot/SKILL.en.md +3 -0
  163. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +3 -0
  164. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  165. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
  166. package/templates/.agents/skills/code-task/reference/branch-management.en.md +1 -1
  167. package/templates/.agents/skills/code-task/reference/branch-management.zh-CN.md +1 -1
  168. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +2 -0
  169. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +2 -0
  170. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
  171. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
  172. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +1 -2
  173. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +1 -2
  174. package/templates/.agents/skills/complete-task/SKILL.en.md +0 -3
  175. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +0 -3
  176. package/templates/.agents/skills/create-pr/SKILL.en.md +1 -1
  177. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +1 -1
  178. package/templates/.agents/skills/create-pr/reference/branch-strategy.en.md +2 -2
  179. package/templates/.agents/skills/create-pr/reference/branch-strategy.zh-CN.md +2 -2
  180. package/templates/.agents/skills/create-task/SKILL.en.md +3 -5
  181. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +3 -4
  182. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  183. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  184. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  185. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  186. package/templates/.agents/skills/import-issue/SKILL.en.md +1 -1
  187. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +1 -1
  188. package/templates/.agents/skills/plan-task/SKILL.en.md +1 -1
  189. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +1 -1
  190. package/templates/.agents/skills/review-analysis/SKILL.en.md +1 -1
  191. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +1 -1
  192. package/templates/.agents/skills/review-code/SKILL.en.md +5 -5
  193. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -5
  194. package/templates/.agents/skills/review-plan/SKILL.en.md +1 -1
  195. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +1 -1
  196. package/templates/.agents/skills/review-pr/SKILL.en.md +1 -1
  197. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +1 -1
  198. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
  199. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
  200. package/templates/.agents/skills/test/SKILL.en.md +4 -1
  201. package/templates/.agents/skills/test/SKILL.zh-CN.md +4 -1
  202. package/templates/.agents/skills/test-integration/SKILL.en.md +5 -2
  203. package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +5 -2
  204. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +4 -1
  205. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +4 -1
  206. package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +5 -2
  207. package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +5 -2
  208. package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
  209. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
  210. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +1 -1
  211. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +1 -1
  212. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +0 -546
  213. package/dist/lib/internal/codex-lifecycle.js +0 -385
  214. package/dist/lib/task/codex-orchestration.js +0 -206
  215. package/dist/lib/task/finalization-handoff.js +0 -93
  216. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +0 -776
  217. package/lib/internal/codex-lifecycle.ts +0 -390
  218. package/lib/task/codex-orchestration.ts +0 -276
  219. package/lib/task/finalization-handoff.ts +0 -105
@@ -111,12 +111,12 @@ if (!controlRouted && !taskViewGuardFailed && internalRouteRegistered)
111
111
  break;
112
112
  }
113
113
  case 'codex-lifecycle': {
114
- const { codexLifecycle } = await import('../lib/internal/codex-lifecycle.js');
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/internal/codex-sandbox-controller.js');
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
  }
@@ -1,3 +1,4 @@
1
+ import path from 'node:path';
1
2
  import { AGENT_CLIENT_CAPABILITY_IDS, AGENT_CLIENT_SUPPORT_LEVELS, isAgentClientId } from './types.js';
2
3
  import { SANDBOX_HOOK_PHASES } from '../sandbox/tool-types.js';
3
4
  const PROJECT_ASSET_CATEGORIES = ['managed', 'merged', 'ejected'];
@@ -65,6 +66,24 @@ function freezeTool(tool) {
65
66
  if (!tool.containerMount.startsWith('/')) {
66
67
  throw new Error(`Sandbox tool '${tool.id}' containerMount must be absolute`);
67
68
  }
69
+ if (tool.hostStateMounts !== undefined && !Array.isArray(tool.hostStateMounts)) {
70
+ throw new Error(`Agent Client '${tool.id}' hostStateMounts must be an array`);
71
+ }
72
+ const hostStateMounts = tool.hostStateMounts?.map((entry) => {
73
+ if (!entry || typeof entry.hostSubdir !== 'string' || typeof entry.containerSubpath !== 'string') {
74
+ throw new Error(`Agent Client '${tool.id}' hostStateMounts must contain relative path pairs`);
75
+ }
76
+ for (const value of [entry.hostSubdir, entry.containerSubpath]) {
77
+ const normalized = path.posix.normalize(value);
78
+ if (value === ''
79
+ || path.posix.isAbsolute(value)
80
+ || normalized === '..'
81
+ || normalized.startsWith('../')) {
82
+ throw new Error(`Agent Client '${tool.id}' hostStateMounts must stay within the tool directories`);
83
+ }
84
+ }
85
+ return Object.freeze({ ...entry });
86
+ });
68
87
  if (!tool.versionCmd) {
69
88
  throw new Error(`Sandbox tool '${tool.id}' requires versionCmd`);
70
89
  }
@@ -82,6 +101,7 @@ function freezeTool(tool) {
82
101
  ...(tool.hostLiveMounts ? {
83
102
  hostLiveMounts: Object.freeze(tool.hostLiveMounts.map((entry) => Object.freeze({ ...entry })))
84
103
  } : {}),
104
+ ...(hostStateMounts ? { hostStateMounts: Object.freeze(hostStateMounts) } : {}),
85
105
  ...(tool.postSetupCmds ? { postSetupCmds: Object.freeze([...tool.postSetupCmds]) } : {}),
86
106
  ...(tool.tmpfs ? {
87
107
  tmpfs: Object.freeze({
@@ -191,7 +211,10 @@ function defineAgentClientAdapter(candidate) {
191
211
  const evidence = candidate.delegationEvidence;
192
212
  if (!evidence
193
213
  || !['host-event', 'app-server', 'unavailable'].includes(evidence.actualModel)
194
- || !['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')) {
195
218
  throw new Error(`Agent Client '${candidate.id}' has invalid delegation evidence`);
196
219
  }
197
220
  if (typeof candidate.project !== 'object'
@@ -411,6 +434,9 @@ function defineAgentClientAdapter(candidate) {
411
434
  ...(candidate.orchestrationAdapter === undefined
412
435
  ? {}
413
436
  : { orchestrationAdapter: Object.freeze({ ...candidate.orchestrationAdapter }) }),
437
+ ...(candidate.sandboxControlOperation === undefined
438
+ ? {}
439
+ : { sandboxControlOperation: Object.freeze({ ...candidate.sandboxControlOperation }) }),
414
440
  project: Object.freeze({
415
441
  ownedPathPrefixes: Object.freeze(paths),
416
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 { resolveAgentRuntimeStoreRoot } from '../../../runtime/agent-runtime.js';
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 resolveCodexSpawnedChild(transcriptPath, expected) {
30
+ function readRolloutRecords(transcriptPath, sessionId) {
29
31
  const name = path.basename(transcriptPath);
30
- if (!transcriptPath || (!name.endsWith(`-${expected.sessionId}.jsonl`) && name !== `${expected.sessionId}.jsonl`)) {
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 maxBytes = 8 * 1024 * 1024;
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
- const records = text.split(/\r?\n/).filter(Boolean).map((line) => object(JSON.parse(line))).filter(Boolean);
50
- const calls = records.filter((record) => {
51
- const payload = object(record?.payload);
52
- return record?.type === 'response_item'
53
- && payload?.type === 'function_call'
54
- && payload.call_id === expected.toolUseId
55
- && payload.namespace === 'collaboration'
56
- && payload.name === 'spawn_agent';
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?.agent_type !== expected.nativeAgent
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
- const hookDefinitionHash = crypto.createHash('sha256').update(hooksRaw).digest('hex');
523
- const runtimeRoot = resolveAgentRuntimeStoreRoot({ repoRoot, store: 'lifecycle' });
524
- const runtimeLiveness = hasCodexRuntimeLiveness(runtimeRoot, hookDefinitionHash, runtimeIdentity);
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 Object.freeze({
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, hasCodexRuntimeLiveness, parseCodexModelReroute, parseCodexHooksList, parseCodexThreadResolution, parseCodexTurnCompleted, resolveCodexSpawnedChild, preflightCodexLifecycleEvidence, resolveCodexTerminal, resolveCodexThread, validateCodexLifecycleHookConfig };
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