@fitlab-ai/agent-infra 0.9.14 → 0.9.15

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 (250) hide show
  1. package/README.md +10 -0
  2. package/README.zh-CN.md +10 -0
  3. package/bin/internal-cli.sh +45 -0
  4. package/dist/bin/internal-cli.js +93 -30
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
  7. package/dist/lib/defaults.json +103 -103
  8. package/dist/lib/fs/durable-write.js +37 -0
  9. package/dist/lib/fs/file-lock.js +111 -0
  10. package/dist/lib/host-control/audit.js +19 -0
  11. package/dist/lib/host-control/client.js +142 -0
  12. package/dist/lib/host-control/command.js +49 -0
  13. package/dist/lib/host-control/path.js +160 -0
  14. package/dist/lib/host-control/secure-fs.js +140 -0
  15. package/dist/lib/host-control/server.js +159 -0
  16. package/dist/lib/host-control/service.js +112 -0
  17. package/dist/lib/init.js +11 -2
  18. package/dist/lib/internal/cli-route-inventory.js +3 -1
  19. package/dist/lib/internal/codex-lifecycle.js +6 -6
  20. package/dist/lib/internal/demo-promotion.js +322 -0
  21. package/dist/lib/internal/demo-transcript.js +454 -0
  22. package/dist/lib/internal/host-control.js +28 -0
  23. package/dist/lib/internal/manual-validation.js +322 -0
  24. package/dist/lib/internal/platform-pr.js +18 -4
  25. package/dist/lib/internal/release-workflow.js +63 -84
  26. package/dist/lib/internal/sandbox-control.js +149 -2
  27. package/dist/lib/internal/task-artifact.js +15 -262
  28. package/dist/lib/internal/task-create.js +6 -5
  29. package/dist/lib/internal/task-event.js +37 -37
  30. package/dist/lib/internal/task-operation-registry.js +101 -3
  31. package/dist/lib/internal/task-review.js +8 -53
  32. package/dist/lib/internal/task-validate.js +30 -10
  33. package/dist/lib/owned-path.js +33 -0
  34. package/dist/lib/platform/check-status.js +11 -0
  35. package/dist/lib/platform/comment-safety.js +4 -1
  36. package/dist/lib/platform/completion-backfill.js +1 -1
  37. package/dist/lib/platform/github-data.js +241 -0
  38. package/dist/lib/platform/github-provider.js +15 -20
  39. package/dist/lib/platform/issue-comments.js +2 -2
  40. package/dist/lib/platform/issues.js +1 -179
  41. package/dist/lib/platform/pr-checks.js +12 -65
  42. package/dist/lib/platform/pr-summary.js +55 -3
  43. package/dist/lib/platform/pull-requests.js +2 -105
  44. package/dist/lib/platform/snapshots.js +2 -0
  45. package/dist/lib/platform/verification-sync.js +127 -142
  46. package/dist/lib/release/workflow.js +1 -1
  47. package/dist/lib/sandbox/commands/create.js +7 -2
  48. package/dist/lib/sandbox/commands/rm.js +3 -1514
  49. package/dist/lib/sandbox/control/audit.js +203 -0
  50. package/dist/lib/sandbox/control/client.js +93 -54
  51. package/dist/lib/sandbox/control/executor.js +129 -65
  52. package/dist/lib/sandbox/control/finalization-response.js +27 -0
  53. package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
  54. package/dist/lib/sandbox/control/lifecycle.js +36 -2
  55. package/dist/lib/sandbox/control/native-file-lock.js +6 -98
  56. package/dist/lib/sandbox/control/protocol.js +55 -4
  57. package/dist/lib/sandbox/control/server.js +491 -120
  58. package/dist/lib/sandbox/control/state.js +58 -0
  59. package/dist/lib/sandbox/control/task-workflow.js +74 -0
  60. package/dist/lib/sandbox/control/workflow-executor.js +99 -0
  61. package/dist/lib/sandbox/index.js +2 -2
  62. package/dist/lib/sandbox/recovery.js +28 -4
  63. package/dist/lib/sandbox/removal.js +1717 -0
  64. package/dist/lib/sandbox/task-cleanup.js +217 -0
  65. package/dist/lib/sandbox/workspace-view.js +13 -14
  66. package/dist/lib/task/activity-intent.js +2 -1
  67. package/dist/lib/task/activity-log.js +30 -24
  68. package/dist/lib/task/artifact-command.js +101 -0
  69. package/dist/lib/task/artifact-lifecycle.js +30 -28
  70. package/dist/lib/task/artifact-name.js +36 -0
  71. package/dist/lib/task/artifact-operations.js +23 -69
  72. package/dist/lib/task/artifact-receipts.js +3 -15
  73. package/dist/lib/task/artifact-repair-intent.js +87 -16
  74. package/dist/lib/task/artifact-schema.js +6 -14
  75. package/dist/lib/task/capabilities.js +12 -19
  76. package/dist/lib/task/codex-orchestration.js +71 -25
  77. package/dist/lib/task/commit-identity.js +28 -0
  78. package/dist/lib/task/commit-operation.js +2 -16
  79. package/dist/lib/task/control-authority.js +371 -5
  80. package/dist/lib/task/control-recovery.js +128 -0
  81. package/dist/lib/task/create.js +62 -9
  82. package/dist/lib/task/decision-details.js +2 -46
  83. package/dist/lib/task/events.js +120 -9
  84. package/dist/lib/task/finalization-state.js +9 -0
  85. package/dist/lib/task/human-override.js +3 -6
  86. package/dist/lib/task/implementation-inputs.js +3 -3
  87. package/dist/lib/task/intermediate-cleanup.js +383 -0
  88. package/dist/lib/task/invalidation.js +18 -65
  89. package/dist/lib/task/ledger-intents.js +7 -22
  90. package/dist/lib/task/ledger.js +1 -3
  91. package/dist/lib/task/lifecycle.js +19 -1
  92. package/dist/lib/task/local-artifact-finalization.js +132 -157
  93. package/dist/lib/task/manual-validation-completion.js +26 -0
  94. package/dist/lib/task/manual-validation-evidence.js +130 -0
  95. package/dist/lib/task/manual-validation-receipt.js +101 -0
  96. package/dist/lib/task/manual-validation-shared.js +40 -0
  97. package/dist/lib/task/manual-validation-transaction.js +243 -0
  98. package/dist/lib/task/markdown.js +47 -0
  99. package/dist/lib/task/orchestration.js +14 -17
  100. package/dist/lib/task/qualification-audit.js +20 -34
  101. package/dist/lib/task/review-artifacts.js +2 -18
  102. package/dist/lib/task/review-command.js +25 -0
  103. package/dist/lib/task/review-finalization.js +125 -193
  104. package/dist/lib/task/review-fingerprint.js +2 -2
  105. package/dist/lib/task/sections.js +34 -56
  106. package/dist/lib/task/verification-engine.js +116 -323
  107. package/dist/lib/task/verification.js +1 -1
  108. package/dist/lib/task/workflow-command.js +17 -0
  109. package/dist/lib/task/workflow-warning-intents.js +0 -16
  110. package/dist/lib/task/workflow-warnings.js +28 -2
  111. package/dist/lib/update.js +2 -0
  112. package/dist/lifecycle-build-manifest.json +3 -3
  113. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
  114. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
  115. package/lib/fs/durable-write.ts +29 -0
  116. package/lib/fs/file-lock.ts +113 -0
  117. package/lib/host-control/audit.ts +22 -0
  118. package/lib/host-control/client.ts +172 -0
  119. package/lib/host-control/command.ts +60 -0
  120. package/lib/host-control/path.ts +167 -0
  121. package/lib/host-control/secure-fs.ts +135 -0
  122. package/lib/host-control/server.ts +180 -0
  123. package/lib/host-control/service.ts +133 -0
  124. package/lib/init.ts +15 -2
  125. package/lib/internal/cli-route-inventory.ts +3 -1
  126. package/lib/internal/codex-lifecycle.ts +6 -6
  127. package/lib/internal/demo-promotion.ts +354 -0
  128. package/lib/internal/demo-transcript.ts +419 -0
  129. package/lib/internal/host-control.ts +28 -0
  130. package/lib/internal/manual-validation.ts +306 -0
  131. package/lib/internal/platform-pr.ts +15 -4
  132. package/lib/internal/release-workflow.ts +74 -82
  133. package/lib/internal/sandbox-control.ts +162 -1
  134. package/lib/internal/task-artifact.ts +13 -216
  135. package/lib/internal/task-create.ts +5 -5
  136. package/lib/internal/task-event.ts +20 -11
  137. package/lib/internal/task-operation-registry.ts +111 -3
  138. package/lib/internal/task-review.ts +6 -51
  139. package/lib/internal/task-validate.ts +26 -10
  140. package/lib/owned-path.ts +26 -0
  141. package/lib/platform/check-status.ts +9 -0
  142. package/lib/platform/comment-safety.ts +5 -0
  143. package/lib/platform/completion-backfill.ts +1 -1
  144. package/lib/platform/github-data.ts +322 -0
  145. package/lib/platform/github-provider.ts +15 -20
  146. package/lib/platform/issue-comments.ts +3 -4
  147. package/lib/platform/issues.ts +4 -245
  148. package/lib/platform/pr-checks.ts +13 -77
  149. package/lib/platform/pr-summary.ts +61 -5
  150. package/lib/platform/pull-requests.ts +3 -170
  151. package/lib/platform/snapshots.ts +53 -0
  152. package/lib/platform/verification-sync.ts +145 -155
  153. package/lib/release/workflow.ts +3 -3
  154. package/lib/sandbox/commands/create.ts +7 -6
  155. package/lib/sandbox/commands/rm.ts +3 -1909
  156. package/lib/sandbox/control/audit.ts +253 -0
  157. package/lib/sandbox/control/client.ts +109 -66
  158. package/lib/sandbox/control/executor.ts +134 -74
  159. package/lib/sandbox/control/finalization-response.ts +29 -0
  160. package/lib/sandbox/control/identity-sentinel.ts +137 -0
  161. package/lib/sandbox/control/lifecycle.ts +45 -3
  162. package/lib/sandbox/control/native-file-lock.ts +6 -107
  163. package/lib/sandbox/control/protocol.ts +75 -6
  164. package/lib/sandbox/control/server.ts +538 -123
  165. package/lib/sandbox/control/state.ts +78 -0
  166. package/lib/sandbox/control/task-workflow.ts +95 -0
  167. package/lib/sandbox/control/workflow-executor.ts +102 -0
  168. package/lib/sandbox/index.ts +2 -2
  169. package/lib/sandbox/recovery.ts +28 -5
  170. package/lib/sandbox/removal.ts +2144 -0
  171. package/lib/sandbox/task-cleanup.ts +209 -0
  172. package/lib/sandbox/workspace-view.ts +17 -15
  173. package/lib/task/activity-intent.ts +2 -2
  174. package/lib/task/activity-log.ts +27 -19
  175. package/lib/task/artifact-command.ts +104 -0
  176. package/lib/task/artifact-lifecycle.ts +31 -26
  177. package/lib/task/artifact-name.ts +55 -0
  178. package/lib/task/artifact-operations.ts +22 -68
  179. package/lib/task/artifact-receipts.ts +3 -14
  180. package/lib/task/artifact-repair-intent.ts +99 -18
  181. package/lib/task/artifact-schema.ts +5 -34
  182. package/lib/task/capabilities.ts +13 -22
  183. package/lib/task/codex-orchestration.ts +85 -24
  184. package/lib/task/commit-identity.ts +31 -0
  185. package/lib/task/commit-operation.ts +2 -16
  186. package/lib/task/control-authority.ts +502 -5
  187. package/lib/task/control-recovery.ts +174 -0
  188. package/lib/task/create.ts +63 -8
  189. package/lib/task/decision-details.ts +3 -71
  190. package/lib/task/events.ts +131 -10
  191. package/lib/task/finalization-state.ts +11 -0
  192. package/lib/task/human-override.ts +3 -8
  193. package/lib/task/implementation-inputs.ts +3 -3
  194. package/lib/task/intermediate-cleanup.ts +455 -0
  195. package/lib/task/invalidation.ts +18 -62
  196. package/lib/task/ledger-intents.ts +7 -24
  197. package/lib/task/ledger.ts +1 -3
  198. package/lib/task/lifecycle.ts +17 -1
  199. package/lib/task/local-artifact-finalization.ts +148 -182
  200. package/lib/task/manual-validation-completion.ts +40 -0
  201. package/lib/task/manual-validation-evidence.ts +209 -0
  202. package/lib/task/manual-validation-receipt.ts +152 -0
  203. package/lib/task/manual-validation-shared.ts +50 -0
  204. package/lib/task/manual-validation-transaction.ts +304 -0
  205. package/lib/task/markdown.ts +70 -0
  206. package/lib/task/orchestration.ts +19 -19
  207. package/lib/task/qualification-audit.ts +22 -33
  208. package/lib/task/review-artifacts.ts +1 -20
  209. package/lib/task/review-command.ts +23 -0
  210. package/lib/task/review-finalization.ts +131 -259
  211. package/lib/task/review-fingerprint.ts +2 -2
  212. package/lib/task/sections.ts +33 -54
  213. package/lib/task/verification-engine.ts +110 -366
  214. package/lib/task/verification-types.ts +17 -0
  215. package/lib/task/verification.ts +1 -1
  216. package/lib/task/workflow-command.ts +18 -0
  217. package/lib/task/workflow-warning-intents.ts +0 -13
  218. package/lib/task/workflow-warnings.ts +21 -2
  219. package/lib/update.ts +6 -0
  220. package/package.json +6 -6
  221. package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
  222. package/templates/.agents/rules/testing-discipline.en.md +2 -0
  223. package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
  224. package/templates/.agents/scripts/package.json +3 -0
  225. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +32 -20
  226. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +32 -20
  227. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  228. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  229. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  230. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  231. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
  232. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
  233. package/templates/.agents/skills/complete-task/SKILL.en.md +1 -1
  234. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +1 -1
  235. package/templates/.agents/skills/release/SKILL.en.md +7 -3
  236. package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
  237. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +20 -3
  238. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +20 -3
  239. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
  240. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
  241. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -0
  242. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -0
  243. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  244. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  245. package/templates/.agents/skills/test/SKILL.en.md +17 -6
  246. package/templates/.agents/skills/test/SKILL.zh-CN.md +17 -6
  247. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  248. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  249. package/dist/lib/platform/adapters.js +0 -56
  250. package/lib/platform/adapters.ts +0 -197
@@ -1,10 +1,106 @@
1
- import { recoverSandboxControl, requestSandboxControl, requestSandboxTaskFinalization, requestSandboxTaskControl, SandboxControlClientError } from '../sandbox/control/client.js';
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { readFileSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { recoverSandboxControl, requestSandboxControl, requestSandboxTaskFinalization, requestSandboxTaskControl, requestSandboxTaskWorkflow, resolveVisibleActiveShortId, SandboxControlClientError } from '../sandbox/control/client.js';
2
5
  import { normalizeAgentToken, AGENT_USAGE_HINT } from '../agent-clients/tokens.js';
3
6
  import { serveSandboxControl } from '../sandbox/control/server.js';
4
7
  import { runSandboxControlExecutor } from '../sandbox/control/executor.js';
5
8
  import { controllerProofFromContext, verifyCodexSandboxControllerContextWithWarnings } from '../agent-clients/adapters/codex-lifecycle/sandbox-controller.js';
6
9
  import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.js';
7
10
  import { parseTaskCreateResult, taskCreateExitCode } from '../task/create-service.js';
11
+ import { createTaskWorkflowRequest } from '../sandbox/control/task-workflow.js';
12
+ import { computeLifecycleBuildIdentity } from '../agent-clients/adapters/codex-lifecycle/build-identity.js';
13
+ import { routeOrchestration } from '../task/orchestration.js';
14
+ import { parseArtifactName } from '../task/artifact-name.js';
15
+ function valueAfter(args, flag) {
16
+ for (let index = 0; index < args.length; index += 1) {
17
+ if (args[index] === flag)
18
+ return args[index + 1];
19
+ if (args[index]?.startsWith(`${flag}=`))
20
+ return args[index].slice(flag.length + 1);
21
+ }
22
+ return undefined;
23
+ }
24
+ function withoutValue(args, flag) {
25
+ const result = [];
26
+ for (let index = 0; index < args.length; index += 1) {
27
+ if (args[index] === flag) {
28
+ index += 1;
29
+ continue;
30
+ }
31
+ if (args[index]?.startsWith(`${flag}=`))
32
+ continue;
33
+ result.push(args[index]);
34
+ }
35
+ return result;
36
+ }
37
+ function lifecycleIds(authorityRef, taskId) {
38
+ const digest = (label) => createHash('sha256')
39
+ .update(`${label}\0${taskId}\0${authorityRef}`, 'utf8')
40
+ .digest('hex');
41
+ return { operationId: digest('operation'), lifecycleRequestId: digest('lifecycle-request') };
42
+ }
43
+ function lifecycleAuthorityIdentity(authorityRef, taskId, requestId, phase, family, artifact, round) {
44
+ const contextPath = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
45
+ if (!authorityRef || !contextPath)
46
+ return undefined;
47
+ const routed = verifyCodexSandboxControllerContextWithWarnings(contextPath, { repoRoot: process.cwd() });
48
+ const buildIdentity = computeLifecycleBuildIdentity(process.cwd());
49
+ const hookDefinitionHash = createHash('sha256')
50
+ .update(readFileSync(path.join(process.cwd(), '.codex', 'hooks.json')))
51
+ .digest('hex');
52
+ const ids = lifecycleIds(authorityRef, taskId);
53
+ return {
54
+ version: 1,
55
+ requestId,
56
+ operationId: ids.operationId,
57
+ phase,
58
+ taskId,
59
+ family,
60
+ artifact,
61
+ round,
62
+ lifecycleRequestId: ids.lifecycleRequestId,
63
+ authorityRef,
64
+ expectedControlGeneration: routed.context.controlGeneration,
65
+ expectedControllerInstanceDigest: routed.context.controllerInstanceDigest,
66
+ expectedBuildIdentityDigest: createHash('sha256').update(JSON.stringify(buildIdentity)).digest('hex'),
67
+ expectedHookDefinitionHash: hookDefinitionHash
68
+ };
69
+ }
70
+ function lifecycleAuthoritySelector(args) {
71
+ if (!isCanonicalCodexPrepare(args))
72
+ return undefined;
73
+ const authorityRef = valueAfter(args, '--capability-ref');
74
+ const taskId = args[0];
75
+ if (!authorityRef || !taskId)
76
+ return undefined;
77
+ const routed = routeOrchestration(taskId);
78
+ if (!routed.next || !['analysis', 'plan', 'code'].includes(routed.next.stage))
79
+ return undefined;
80
+ return lifecycleAuthorityIdentity(authorityRef, taskId, randomUUID(), 'orchestration.prepare', routed.next.stage === 'analysis' ? 'analysis' : routed.next.stage === 'plan' ? 'plan' : 'code', routed.next.artifact, routed.next.round);
81
+ }
82
+ function lifecycleWorkflowAuthoritySelector(originalArgs, workflow) {
83
+ const authorityRef = valueAfter(originalArgs, '--capability-ref');
84
+ if (!authorityRef)
85
+ return undefined;
86
+ if (workflow.operation === 'artifact-finalize-local') {
87
+ const family = valueAfter(workflow.args, '--family');
88
+ const artifact = valueAfter(workflow.args, '--artifact');
89
+ const parsed = artifact ? parseArtifactName(artifact) : null;
90
+ if ((family !== 'analysis' && family !== 'plan' && family !== 'code')
91
+ || !parsed || parsed.family !== family)
92
+ return undefined;
93
+ return lifecycleAuthorityIdentity(authorityRef, workflow.taskId, workflow.id, 'artifact.finalize-local', family, artifact, parsed.round);
94
+ }
95
+ if (workflow.operation !== 'event')
96
+ return undefined;
97
+ const completed = /^(analysis|plan|code)\.completed$/u.exec(workflow.args[1] ?? '');
98
+ const artifact = valueAfter(workflow.args, '--artifact');
99
+ const parsed = artifact ? parseArtifactName(artifact) : null;
100
+ if (!completed || !parsed || parsed.family !== completed[1])
101
+ return undefined;
102
+ return lifecycleAuthorityIdentity(authorityRef, workflow.taskId, workflow.id, 'task-event.completed', completed[1], artifact, parsed.round);
103
+ }
8
104
  function isCanonicalCodexPrepare(args) {
9
105
  if (args[1] !== 'prepare')
10
106
  return false;
@@ -144,6 +240,51 @@ async function sandboxControl(args) {
144
240
  sandboxFinalizationClient(commandArgs);
145
241
  return;
146
242
  }
243
+ if (family === 'task-workflow') {
244
+ const command = commandArgs[0];
245
+ const taskId = process.env.AGENT_INFRA_TASK_ID;
246
+ const generation = process.env.AGENT_INFRA_CONTROL_GENERATION;
247
+ if (!command || !taskId || !generation) {
248
+ process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'SANDBOX_CONTROL_REQUEST_INVALID', message: 'task-workflow requires a bound task and generation' } })}\n`);
249
+ process.exitCode = 1;
250
+ return;
251
+ }
252
+ let workflow;
253
+ try {
254
+ const args = withoutValue(commandArgs.slice(1), '--capability-ref');
255
+ if (/^\d+$/.test(args[0] ?? '')) {
256
+ const resolved = resolveVisibleActiveShortId(args[0]);
257
+ if (resolved !== taskId)
258
+ throw new Error('SANDBOX_TASK_REF_MISMATCH');
259
+ args[0] = resolved;
260
+ }
261
+ workflow = createTaskWorkflowRequest(command, args, taskId, generation);
262
+ }
263
+ catch (error) {
264
+ process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'SANDBOX_CONTROL_REQUEST_INVALID', message: error instanceof Error ? error.message : String(error) } })}\n`);
265
+ process.exitCode = 1;
266
+ return;
267
+ }
268
+ let response;
269
+ try {
270
+ const authority = lifecycleWorkflowAuthoritySelector(commandArgs, workflow);
271
+ response = requestSandboxTaskWorkflow({
272
+ workflow,
273
+ ...(authority ? { authority } : {})
274
+ });
275
+ }
276
+ catch (error) {
277
+ if (!(error instanceof SandboxControlClientError))
278
+ throw error;
279
+ writeClientError(error);
280
+ process.exitCode = error.detail.retryable ? 75 : 1;
281
+ return;
282
+ }
283
+ process.stdout.write(response.stdout);
284
+ process.stderr.write(response.stderr);
285
+ process.exitCode = response.phase === 'rejected' ? response.error?.retryable ? 75 : 1 : response.exitCode ?? 1;
286
+ return;
287
+ }
147
288
  let response;
148
289
  try {
149
290
  if (family === 'task-orchestration' && isCanonicalCodexPrepare(commandArgs)) {
@@ -151,7 +292,13 @@ async function sandboxControl(args) {
151
292
  const proof = contextPath
152
293
  ? controllerProofFromContext(verifyCodexSandboxControllerContextWithWarnings(contextPath).context)
153
294
  : null;
154
- response = requestSandboxTaskControl({ family, args: commandArgs, controllerProof: proof });
295
+ const authority = lifecycleAuthoritySelector(commandArgs);
296
+ response = requestSandboxTaskControl({
297
+ family,
298
+ args: commandArgs,
299
+ controllerProof: authority ? null : proof,
300
+ ...(authority ? { authority } : {})
301
+ });
155
302
  }
156
303
  else {
157
304
  response = requestSandboxControl({ family, args: commandArgs });
@@ -1,45 +1,6 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { resolveArtifactContext } from '../task/artifact-lifecycle.js';
4
- import { parseArtifactName } from '../task/artifact-lifecycle.js';
5
- import { locateActivityLog, pairEntries, startedBackedRows } from '../task/activity-log.js';
6
- import { finalizeLocalArtifact } from '../task/local-artifact-finalization.js';
7
- import { resolveTaskRef } from '../task/resolve-ref.js';
8
- import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.js';
9
- import { getArtifactSchema } from '../task/artifact-schema.js';
10
- import { applyArtifactRepair, initializeArtifactSkeleton, inspectArtifactStructure } from '../task/artifact-operations.js';
1
+ import { parseArtifactCommand, executeArtifactCommand } from '../task/artifact-command.js';
2
+ import { ensureInternalHandlerRoute } from './cli-route-inventory.js';
11
3
  const USAGE = `Usage: agent-infra-internal task-artifact <N | TASK-id> inspect --family <family>\n agent-infra-internal task-artifact <N | TASK-id> init --family <family> --artifact <artifact> [--locale <zh-CN|en>]\n agent-infra-internal task-artifact <N | TASK-id> repair --family <family> --artifact <artifact> --expected-sha256 <sha256> --expected-semantic-digest <digest>\n agent-infra-internal task-artifact <N | TASK-id> finalize-local --family <analysis|plan|code> --artifact <artifact>\n\nInspect, initialize, repair, or finalize a workflow artifact without changing task state.\n`;
12
- function failUsage(message) {
13
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'ARTIFACT_PAYLOAD_INVALID', message } })}\n`);
14
- process.stderr.write(USAGE);
15
- process.exitCode = 2;
16
- }
17
- function hasOpenLocalArtifactRound(taskDir, family, round) {
18
- try {
19
- const activity = locateActivityLog(fs.readFileSync(path.join(taskDir, 'task.md'), 'utf8'));
20
- if (!activity)
21
- return false;
22
- const label = family === 'analysis'
23
- ? 'Analyze Task'
24
- : family === 'review-analysis'
25
- ? 'Review Analysis'
26
- : family === 'plan'
27
- ? 'Plan Task'
28
- : family === 'review-plan'
29
- ? 'Review Plan'
30
- : family === 'code'
31
- ? 'Code Task'
32
- : 'Review Code';
33
- const qualifier = family === 'code'
34
- ? '(?:, (?:fix for review-code(?:-r\\d+)?\\.md|decision II-[1-9]\\d*))?'
35
- : '';
36
- const expected = new RegExp(`^${label} \\(Round ${round}${qualifier}\\)$`);
37
- return startedBackedRows(pairEntries(activity.entries)).some((row) => expected.test(row.step) && !row.done);
38
- }
39
- catch {
40
- return false;
41
- }
42
- }
43
4
  function taskArtifact(args = []) {
44
5
  if (!ensureInternalHandlerRoute('task-artifact', args))
45
6
  return;
@@ -47,232 +8,24 @@ function taskArtifact(args = []) {
47
8
  process.stdout.write(USAGE);
48
9
  return;
49
10
  }
50
- if (args.length < 2) {
51
- failUsage('task ref and operation are required');
52
- return;
53
- }
54
- const operation = args[1];
55
- if (!internalHandlerRoute('task-artifact', 'inspect', operation ?? '')
56
- && !internalHandlerRoute('task-artifact', 'init', operation ?? '')
57
- && !internalHandlerRoute('task-artifact', 'repair', operation ?? '')
58
- && !internalHandlerRoute('task-artifact', 'finalize-local', operation ?? '')) {
59
- failUsage(`unknown operation '${operation}'`);
60
- return;
61
- }
62
- let family = '';
63
- let artifact = '';
64
- let locale;
65
- let expectedSha256 = '';
66
- let expectedSemanticDigest = '';
67
- const seen = new Set();
68
- for (let index = 2; index < args.length; index += 1) {
69
- const flag = args[index];
70
- if (flag !== '--family' && flag !== '--artifact' && flag !== '--locale' && flag !== '--expected-sha256' && flag !== '--expected-semantic-digest') {
71
- failUsage(`unknown option '${flag}'`);
72
- return;
73
- }
74
- if (seen.has(flag)) {
75
- failUsage(`duplicate option '${flag}'`);
76
- return;
77
- }
78
- const value = args[++index];
79
- if (!value || value.startsWith('--')) {
80
- failUsage(`option '${flag}' requires a value`);
81
- return;
82
- }
83
- seen.add(flag);
84
- if (flag === '--family')
85
- family = value;
86
- else if (flag === '--artifact')
87
- artifact = value;
88
- else if (flag === '--locale') {
89
- if (value !== 'zh-CN' && value !== 'en') {
90
- failUsage("option '--locale' must be 'zh-CN' or 'en'");
91
- return;
92
- }
93
- locale = value;
94
- }
95
- else if (flag === '--expected-sha256')
96
- expectedSha256 = value;
97
- else
98
- expectedSemanticDigest = value;
99
- }
100
- if (!family) {
101
- failUsage("option '--family' is required");
102
- return;
103
- }
104
- if ((operation === 'init' || operation === 'repair' || operation === 'finalize-local') && !artifact) {
105
- failUsage("option '--artifact' is required");
106
- return;
107
- }
108
- if (internalHandlerRoute('task-artifact', 'inspect', operation ?? '')) {
109
- if (artifact || locale || expectedSha256 || expectedSemanticDigest) {
110
- failUsage("artifact options are only valid for init, repair, or finalize-local");
111
- return;
112
- }
113
- const result = resolveArtifactContext(args[0], family);
114
- const output = family === 'code' && result.codeMode ? {
115
- ...result,
116
- mode: result.codeMode.mode,
117
- code_max: result.codeMode.codeMax,
118
- rev_max: result.codeMode.reviewMax,
119
- verdict: result.codeMode.verdict,
120
- next_round: result.next?.round ?? null,
121
- next_artifact: result.next?.name ?? null,
122
- review_artifact: result.codeMode.reviewArtifact,
123
- implementation_input: result.codeMode.implementationInput,
124
- decision_id: result.codeMode.decisionId,
125
- decision_evidence: result.codeMode.decisionEvidence,
126
- message: result.codeMode.message
127
- } : result;
128
- process.stdout.write(`${JSON.stringify(output)}\n`);
129
- if (result.status === 'refused')
130
- process.exitCode = 1;
131
- else if (result.status === 'failed')
132
- process.exitCode = 2;
133
- return;
134
- }
135
- if (internalHandlerRoute('task-artifact', 'init', operation ?? '')) {
136
- if (expectedSha256 || expectedSemanticDigest) {
137
- failUsage("repair baseline options are only valid for repair");
138
- return;
139
- }
140
- const schema = getArtifactSchema(family);
141
- const resolved = resolveTaskRef(args[0]);
142
- if (!schema) {
143
- failUsage(`init does not support artifact family '${family}'`);
144
- return;
145
- }
146
- if (!resolved.ok) {
147
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: resolved.code, message: resolved.message } })}\n`);
148
- process.exitCode = 1;
149
- return;
150
- }
151
- const parsed = parseArtifactName(artifact);
152
- if (!parsed || parsed.family !== family) {
153
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'ARTIFACT_INIT_CONTEXT_INVALID', message: `artifact '${artifact}' does not match ${family}` } })}\n`);
154
- process.exitCode = 1;
155
- return;
156
- }
157
- const context = resolveArtifactContext(args[0], family);
158
- const isNextArtifact = context.status === 'ready' && context.next?.name === artifact;
159
- const isCurrentOpenArtifact = context.status === 'ready'
160
- && context.taskDir !== null
161
- && hasOpenLocalArtifactRound(context.taskDir, family, parsed.round);
162
- if (!isNextArtifact && !isCurrentOpenArtifact) {
163
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'ARTIFACT_INIT_CONTEXT_INVALID', message: context.error?.message ?? `artifact '${artifact}' is not the next ${family} artifact` } })}\n`);
164
- process.exitCode = 1;
165
- return;
166
- }
167
- if (!context.taskId || !context.taskDir) {
168
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'ARTIFACT_INIT_CONTEXT_INVALID', message: `artifact '${artifact}' does not match ${family}` } })}\n`);
169
- process.exitCode = 1;
170
- return;
171
- }
172
- try {
173
- const existing = fs.lstatSync(path.join(resolved.taskDir, artifact));
174
- if (existing.isSymbolicLink() || !existing.isFile()) {
175
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'ARTIFACT_INIT_TARGET_INVALID', message: 'artifact target is not a regular file' } })}\n`);
176
- process.exitCode = 1;
177
- return;
178
- }
179
- const result = initializeArtifactSkeleton({ repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskDir: resolved.taskDir, family: schema.family, artifact, ...(locale ? { locale } : {}) });
180
- process.stdout.write(`${JSON.stringify({ ...result, taskId: resolved.taskId, taskDir: resolved.taskDir, family, artifact })}\n`);
181
- if (result.status === 'failed')
182
- process.exitCode = 1;
183
- return;
184
- }
185
- catch (error) {
186
- if (error.code !== 'ENOENT') {
187
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'ARTIFACT_INIT_TARGET_INVALID', message: String(error) } })}\n`);
188
- process.exitCode = 1;
189
- return;
190
- }
191
- }
192
- const result = initializeArtifactSkeleton({
193
- repoRoot: resolved.repoRoot,
194
- taskId: context.taskId,
195
- taskDir: context.taskDir,
196
- family: schema.family,
197
- artifact,
198
- ...(locale ? { locale } : {})
199
- });
200
- process.stdout.write(`${JSON.stringify({ ...result, taskId: context.taskId, taskDir: context.taskDir, family, artifact })}\n`);
201
- if (result.status === 'failed')
202
- process.exitCode = 1;
203
- return;
204
- }
205
- if (internalHandlerRoute('task-artifact', 'repair', operation ?? '')) {
206
- if (locale) {
207
- failUsage("option '--locale' is only valid for init");
208
- return;
209
- }
210
- if (!/^[a-f0-9]{64}$/.test(expectedSha256) || !/^[a-f0-9]{64}$/.test(expectedSemanticDigest)) {
211
- failUsage("repair requires lowercase 64-character '--expected-sha256' and '--expected-semantic-digest'");
212
- return;
213
- }
214
- const schema = getArtifactSchema(family);
215
- const resolved = resolveTaskRef(args[0]);
216
- const parsed = parseArtifactName(artifact);
217
- if (!schema || !parsed || parsed.family !== family) {
218
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'ARTIFACT_REPAIR_TARGET_INVALID', message: `artifact '${artifact}' does not match ${family}` } })}\n`);
219
- process.exitCode = 1;
220
- return;
221
- }
222
- if (!resolved.ok) {
223
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: resolved.code, message: resolved.message } })}\n`);
224
- process.exitCode = 1;
225
- return;
226
- }
227
- let content;
228
- try {
229
- content = fs.readFileSync(path.join(resolved.taskDir, artifact), 'utf8');
230
- }
231
- catch (error) {
232
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'ARTIFACT_REPAIR_TARGET_INVALID', message: String(error) } })}\n`);
233
- process.exitCode = 1;
234
- return;
235
- }
236
- const inspection = inspectArtifactStructure(content, schema);
237
- if (!inspection.repair) {
238
- process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, artifact, family, diagnostics: inspection.diagnostics, error: { code: 'ARTIFACT_REPAIR_UNSAFE', message: inspection.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ') || 'no deterministic structural repair is available' } })}\n`);
239
- process.exitCode = 1;
240
- return;
241
- }
242
- const result = applyArtifactRepair({
243
- repoRoot: resolved.repoRoot,
244
- taskId: resolved.taskId,
245
- taskDir: resolved.taskDir,
246
- family: schema.family,
247
- artifact,
248
- expectedSha256,
249
- expectedSemanticDigest,
250
- operation: inspection.repair
251
- });
252
- process.stdout.write(`${JSON.stringify({ ...result, taskId: resolved.taskId, taskDir: resolved.taskDir, family, artifact })}\n`);
253
- if (result.status === 'failed')
254
- process.exitCode = 1;
255
- return;
256
- }
257
- const resolved = resolveTaskRef(args[0]);
258
- const repositoryRoot = resolved.ok ? resolved.repoRoot : process.cwd();
259
- if (!artifact) {
260
- failUsage("option '--artifact' is required");
261
- return;
11
+ let command;
12
+ try {
13
+ command = parseArtifactCommand(args);
262
14
  }
263
- if (family !== 'analysis' && family !== 'plan' && family !== 'code') {
264
- failUsage("finalize-local only supports 'analysis', 'plan', and 'code'");
15
+ catch (error) {
16
+ process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: {
17
+ code: 'ARTIFACT_PAYLOAD_INVALID', message: error instanceof Error ? error.message : String(error)
18
+ } })}\n`);
19
+ process.stderr.write(USAGE);
20
+ process.exitCode = 2;
265
21
  return;
266
22
  }
267
- const result = finalizeLocalArtifact({
268
- taskRef: args[0],
269
- family: family,
270
- artifact,
271
- repoRoot: repositoryRoot
272
- });
23
+ const result = executeArtifactCommand(command);
273
24
  process.stdout.write(`${JSON.stringify(result)}\n`);
274
- if (result.status === 'failed')
25
+ if (result.status === 'refused')
275
26
  process.exitCode = 1;
27
+ else if (result.status === 'failed')
28
+ process.exitCode = command.operation === 'inspect' ? 2 : 1;
276
29
  }
277
30
  export { taskArtifact };
278
31
  //# sourceMappingURL=task-artifact.js.map
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
+ import { resolveSandboxControlTransport } from './task-operation-registry.js';
2
3
  import path from 'node:path';
3
- import { classifySandboxControlEnvironment, requestSandboxTaskCreate, SandboxControlClientError } from '../sandbox/control/client.js';
4
+ import { requestSandboxTaskCreate, SandboxControlClientError } from '../sandbox/control/client.js';
4
5
  import { SANDBOX_CONTROL_MAX_BYTES } from '../sandbox/control/protocol.js';
5
6
  import { validateTaskCreateCandidate } from '../task/create.js';
6
7
  import { createTask, parseTaskCreateResult, projectTaskCreateResult, taskCreateExitCode, taskCreateFailure } from '../task/create-service.js';
@@ -54,12 +55,12 @@ async function taskCreate(args) {
54
55
  if (stat.size > SANDBOX_CONTROL_MAX_BYTES)
55
56
  throw new Error('TASK_CREATE_INPUT_TOO_LARGE: input exceeds the control limit');
56
57
  const candidate = validateTaskCreateCandidate(JSON.parse(fs.readFileSync(inputPath, 'utf8')));
57
- const environment = classifySandboxControlEnvironment();
58
- if (environment.kind === 'invalid') {
59
- output(failed(environment.code ?? 'TASK_CONTROL_TRANSPORT_INVALID', environment.message ?? 'sandbox client control configuration is invalid'));
58
+ const environment = resolveSandboxControlTransport();
59
+ if (environment.kind === 'fail-closed') {
60
+ output(failed(environment.reasonCode ?? 'TASK_CONTROL_TRANSPORT_INVALID', 'sandbox client control configuration is invalid'));
60
61
  return;
61
62
  }
62
- if (environment.kind === 'controlled') {
63
+ if (environment.kind === 'broker-client') {
63
64
  const response = requestSandboxTaskCreate({ candidate });
64
65
  if (response.phase === 'rejected') {
65
66
  const accepted = response.error?.code === 'SANDBOX_CONTROL_RESULT_UNKNOWN';
@@ -18,6 +18,7 @@ const FLAGS = {
18
18
  '--verdict': 'verdict', '--blockers': 'blockers', '--major': 'major',
19
19
  '--minor': 'minor', '--manual-validation': 'manualValidation', '--files-modified': 'filesModified',
20
20
  '--tests-passed': 'testsPassed', '--summary-result': 'summaryResult',
21
+ '--transaction-id': 'transactionId', '--receipt-digest': 'receiptDigest', '--pr-head-sha': 'prHeadSha',
21
22
  '--override-ticket': 'overrideTicket', '--override-target': 'overrideTarget', '--override-scope': 'overrideScope'
22
23
  };
23
24
  const NUMERIC = new Set(['round', 'question', 'blockers', 'major', 'minor', 'manualValidation', 'filesModified', 'testsPassed']);
@@ -26,53 +27,35 @@ function usageFailure(message) {
26
27
  process.stderr.write(USAGE);
27
28
  process.exitCode = 1;
28
29
  }
29
- async function taskEvent(args = []) {
30
- if (!ensureInternalHandlerRoute('task-event', args))
31
- return;
32
- if (args[0] === '--help' || args[0] === '-h') {
33
- process.stdout.write(USAGE);
34
- return;
35
- }
36
- if (args.length < 2 || !internalHandlerRoute('task-event', 'event', args[1] ? 'event' : '')) {
37
- usageFailure('task ref and event are required');
38
- return;
39
- }
30
+ export function parseTaskEventRequest(args) {
31
+ if (args.length < 2)
32
+ throw new Error('task ref and event are required');
40
33
  const request = { taskRef: args[0], event: args[1], agent: '' };
41
34
  const seen = new Set();
42
35
  for (let index = 2; index < args.length; index += 1) {
43
36
  const flag = args[index];
44
37
  if (flag === '--orchestrated') {
45
- if (seen.has(flag)) {
46
- usageFailure(`duplicate option '${flag}'`);
47
- return;
48
- }
38
+ if (seen.has(flag))
39
+ throw new Error(`duplicate option '${flag}'`);
49
40
  seen.add(flag);
50
41
  request.orchestrated = true;
51
42
  continue;
52
43
  }
53
44
  if (flag === '--dry-run') {
54
- if (seen.has(flag)) {
55
- usageFailure(`duplicate option '${flag}'`);
56
- return;
57
- }
45
+ if (seen.has(flag))
46
+ throw new Error(`duplicate option '${flag}'`);
58
47
  seen.add(flag);
59
48
  request.dryRun = true;
60
49
  continue;
61
50
  }
62
51
  const key = FLAGS[flag];
63
- if (!key) {
64
- usageFailure(`unknown option '${flag}'`);
65
- return;
66
- }
67
- if (seen.has(flag)) {
68
- usageFailure(`duplicate option '${flag}'`);
69
- return;
70
- }
52
+ if (!key)
53
+ throw new Error(`unknown option '${flag}'`);
54
+ if (seen.has(flag))
55
+ throw new Error(`duplicate option '${flag}'`);
71
56
  const value = args[++index];
72
- if (value === undefined || value.startsWith('--')) {
73
- usageFailure(`option '${flag}' requires a value`);
74
- return;
75
- }
57
+ if (value === undefined || value.startsWith('--'))
58
+ throw new Error(`option '${flag}' requires a value`);
76
59
  seen.add(flag);
77
60
  if (NUMERIC.has(key))
78
61
  request[key] = Number(value);
@@ -82,14 +65,31 @@ async function taskEvent(args = []) {
82
65
  request[key] = value;
83
66
  }
84
67
  const agent = normalizeAgentToken(String(request.agent ?? ''));
85
- if (!agent) {
86
- usageFailure(`invalid --agent '${request.agent}': ${AGENT_USAGE_HINT}`);
87
- return;
88
- }
68
+ if (!agent)
69
+ throw new Error(`invalid --agent '${request.agent}': ${AGENT_USAGE_HINT}`);
89
70
  request.agent = agent;
90
71
  const dryRunConflict = overrideDryRunConflict(request);
91
- if (dryRunConflict) {
92
- usageFailure(dryRunConflict.message);
72
+ if (dryRunConflict)
73
+ throw new Error(dryRunConflict.message);
74
+ return request;
75
+ }
76
+ async function taskEvent(args = []) {
77
+ if (!ensureInternalHandlerRoute('task-event', args))
78
+ return;
79
+ if (args[0] === '--help' || args[0] === '-h') {
80
+ process.stdout.write(USAGE);
81
+ return;
82
+ }
83
+ if (!internalHandlerRoute('task-event', 'event', args[1] ? 'event' : '')) {
84
+ usageFailure('task ref and event are required');
85
+ return;
86
+ }
87
+ let request;
88
+ try {
89
+ request = parseTaskEventRequest(args);
90
+ }
91
+ catch (error) {
92
+ usageFailure(error instanceof Error ? error.message : String(error));
93
93
  return;
94
94
  }
95
95
  const resolved = resolveTaskRef(request.taskRef);