codex-workflow-v2 2.0.0-beta.13.8 → 2.0.0-beta.14

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 (281) hide show
  1. package/README.md +27 -388
  2. package/dist/reviewer-runtime-build.json +96 -32
  3. package/dist/src/alpha6/adoption.d.ts +2 -0
  4. package/dist/src/alpha6/adoption.js +22 -0
  5. package/dist/src/alpha6/adoption.js.map +1 -1
  6. package/dist/src/alpha6/captured-check-evidence.d.ts +51 -0
  7. package/dist/src/alpha6/captured-check-evidence.js +152 -0
  8. package/dist/src/alpha6/captured-check-evidence.js.map +1 -0
  9. package/dist/src/alpha6/component-owner.d.ts +15 -1
  10. package/dist/src/alpha6/component-owner.js +44 -2
  11. package/dist/src/alpha6/component-owner.js.map +1 -1
  12. package/dist/src/alpha6/corrective-decision-boundary.d.ts +4 -0
  13. package/dist/src/alpha6/corrective-decision-boundary.js +47 -0
  14. package/dist/src/alpha6/corrective-decision-boundary.js.map +1 -0
  15. package/dist/src/alpha6/downstream-proof.d.ts +1 -25
  16. package/dist/src/alpha6/downstream-proof.js +0 -171
  17. package/dist/src/alpha6/downstream-proof.js.map +1 -1
  18. package/dist/src/alpha6/failed-step-planning-recovery.d.ts +10 -0
  19. package/dist/src/alpha6/failed-step-planning-recovery.js +93 -0
  20. package/dist/src/alpha6/failed-step-planning-recovery.js.map +1 -0
  21. package/dist/src/alpha6/literal-test-invocation.d.ts +2 -0
  22. package/dist/src/alpha6/literal-test-invocation.js +106 -0
  23. package/dist/src/alpha6/literal-test-invocation.js.map +1 -0
  24. package/dist/src/alpha6/milestone.d.ts +2 -0
  25. package/dist/src/alpha6/milestone.js +10 -1
  26. package/dist/src/alpha6/milestone.js.map +1 -1
  27. package/dist/src/alpha6/navigation-dirty-carryover.d.ts +11 -0
  28. package/dist/src/alpha6/navigation-dirty-carryover.js +130 -0
  29. package/dist/src/alpha6/navigation-dirty-carryover.js.map +1 -0
  30. package/dist/src/alpha6/plan-integrity.js +7 -5
  31. package/dist/src/alpha6/plan-integrity.js.map +1 -1
  32. package/dist/src/alpha6/plan-risk.d.ts +2 -0
  33. package/dist/src/alpha6/plan-risk.js +10 -3
  34. package/dist/src/alpha6/plan-risk.js.map +1 -1
  35. package/dist/src/alpha6/remediation.d.ts +6 -21
  36. package/dist/src/alpha6/remediation.js +161 -476
  37. package/dist/src/alpha6/remediation.js.map +1 -1
  38. package/dist/src/alpha6/root-cause-replan-carryover.d.ts +4 -1
  39. package/dist/src/alpha6/root-cause-replan-carryover.js +29 -5
  40. package/dist/src/alpha6/root-cause-replan-carryover.js.map +1 -1
  41. package/dist/src/beta1/project-transaction.d.ts +3 -1
  42. package/dist/src/beta1/project-transaction.js +6 -2
  43. package/dist/src/beta1/project-transaction.js.map +1 -1
  44. package/dist/src/checks/runner.d.ts +26 -0
  45. package/dist/src/checks/runner.js +223 -0
  46. package/dist/src/checks/runner.js.map +1 -0
  47. package/dist/src/checks/task-sync.d.ts +10 -0
  48. package/dist/src/checks/task-sync.js +41 -0
  49. package/dist/src/checks/task-sync.js.map +1 -0
  50. package/dist/src/checks/worker.d.ts +1 -0
  51. package/dist/src/checks/worker.js +154 -0
  52. package/dist/src/checks/worker.js.map +1 -0
  53. package/dist/src/cli-actions.d.ts +2 -2
  54. package/dist/src/cli-actions.js +3 -15
  55. package/dist/src/cli-actions.js.map +1 -1
  56. package/dist/src/cli.js +14 -98
  57. package/dist/src/cli.js.map +1 -1
  58. package/dist/src/contracts.d.ts +35 -32
  59. package/dist/src/dependency-provenance.d.ts +2 -2
  60. package/dist/src/dependency-provenance.js +12 -69
  61. package/dist/src/dependency-provenance.js.map +1 -1
  62. package/dist/src/domain/base-sync-conflict.d.ts +13 -0
  63. package/dist/src/domain/base-sync-conflict.js +32 -0
  64. package/dist/src/domain/base-sync-conflict.js.map +1 -0
  65. package/dist/src/domain/step-start-admission.d.ts +4 -0
  66. package/dist/src/domain/step-start-admission.js +9 -0
  67. package/dist/src/domain/step-start-admission.js.map +1 -0
  68. package/dist/src/domain/virgin-registration.d.ts +3 -0
  69. package/dist/src/domain/virgin-registration.js +65 -0
  70. package/dist/src/domain/virgin-registration.js.map +1 -0
  71. package/dist/src/errors.d.ts +1 -1
  72. package/dist/src/errors.js.map +1 -1
  73. package/dist/src/gateway-handshake.js +0 -8
  74. package/dist/src/gateway-handshake.js.map +1 -1
  75. package/dist/src/git.d.ts +3 -1
  76. package/dist/src/git.js +41 -14
  77. package/dist/src/git.js.map +1 -1
  78. package/dist/src/graph.js +25 -3
  79. package/dist/src/graph.js.map +1 -1
  80. package/dist/src/index.d.ts +1 -0
  81. package/dist/src/lifecycle/corrective-replan.js +3 -3
  82. package/dist/src/lifecycle/corrective-replan.js.map +1 -1
  83. package/dist/src/navigation-actions.d.ts +9 -0
  84. package/dist/src/navigation-actions.js +72 -0
  85. package/dist/src/navigation-actions.js.map +1 -0
  86. package/dist/src/navigation-update-artifact.d.ts +5 -0
  87. package/dist/src/navigation-update-artifact.js +227 -0
  88. package/dist/src/navigation-update-artifact.js.map +1 -0
  89. package/dist/src/navigation-update.d.ts +39 -0
  90. package/dist/src/navigation-update.js +82 -0
  91. package/dist/src/navigation-update.js.map +1 -0
  92. package/dist/src/observation.js +52 -29
  93. package/dist/src/observation.js.map +1 -1
  94. package/dist/src/observed-routes.js +5 -6
  95. package/dist/src/observed-routes.js.map +1 -1
  96. package/dist/src/pending-review-update.d.ts +0 -13
  97. package/dist/src/pending-review-update.js +1 -6
  98. package/dist/src/pending-review-update.js.map +1 -1
  99. package/dist/src/reviewer.d.ts +1 -1
  100. package/dist/src/reviewer.js +20 -17
  101. package/dist/src/reviewer.js.map +1 -1
  102. package/dist/src/runtime.d.ts +3 -0
  103. package/dist/src/runtime.js +6 -0
  104. package/dist/src/runtime.js.map +1 -0
  105. package/dist/src/state/corrective-replan-executor.d.ts +10 -0
  106. package/dist/src/state/corrective-replan-executor.js +37 -1
  107. package/dist/src/state/corrective-replan-executor.js.map +1 -1
  108. package/dist/src/state/corrective-replan-public-schema.js +15 -2
  109. package/dist/src/state/corrective-replan-public-schema.js.map +1 -1
  110. package/dist/src/state/corrective-replan-public.js +6 -5
  111. package/dist/src/state/corrective-replan-public.js.map +1 -1
  112. package/dist/src/state/corrective-replan-transaction.d.ts +1 -0
  113. package/dist/src/state/corrective-replan-transaction.js +12 -11
  114. package/dist/src/state/corrective-replan-transaction.js.map +1 -1
  115. package/dist/src/state/corrective-yield-executor.js +2 -2
  116. package/dist/src/state/corrective-yield-executor.js.map +1 -1
  117. package/dist/src/state/corrective-yield-transaction.d.ts +1 -0
  118. package/dist/src/state/corrective-yield-transaction.js +11 -10
  119. package/dist/src/state/corrective-yield-transaction.js.map +1 -1
  120. package/dist/src/state/lock.d.ts +4 -0
  121. package/dist/src/state/lock.js +21 -0
  122. package/dist/src/state/lock.js.map +1 -1
  123. package/dist/src/version.d.ts +1 -1
  124. package/dist/src/version.js +1 -1
  125. package/dist/src/version.js.map +1 -1
  126. package/dist/src/workflow-blocker-route.d.ts +8 -0
  127. package/dist/src/workflow-blocker-route.js +106 -0
  128. package/dist/src/workflow-blocker-route.js.map +1 -0
  129. package/dist/src/workflow.d.ts +48 -63
  130. package/dist/src/workflow.js +698 -1470
  131. package/dist/src/workflow.js.map +1 -1
  132. package/docs/autonomy-guardrails.md +26 -304
  133. package/docs/decisions.md +14 -112
  134. package/docs/development-flow.md +35 -238
  135. package/docs/project-memory.md +31 -50
  136. package/docs/release-app-evidence.md +190 -0
  137. package/docs/release.md +95 -363
  138. package/docs/updating-existing-project.md +19 -717
  139. package/package.json +11 -13
  140. package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +2 -2
  141. package/plugins/codex-workflow-gateway/references/chat-dispatch.md +73 -197
  142. package/plugins/codex-workflow-gateway/references/codebase-memory-routing.md +57 -0
  143. package/plugins/codex-workflow-gateway/references/protocol.md +42 -445
  144. package/plugins/codex-workflow-gateway/scripts/chat-dispatch.mjs +7 -1
  145. package/plugins/codex-workflow-gateway/scripts/chat-model-policy.mjs +10 -8
  146. package/plugins/codex-workflow-gateway/scripts/chat-registry.mjs +23 -5
  147. package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +66 -740
  148. package/references/state-machine.md +4 -4
  149. package/roles/technical-planner.md +1 -1
  150. package/schemas/corrective-decision-event.schema.json +3 -1
  151. package/schemas/project-knowledge-map.schema.json +3 -1
  152. package/schemas/remediation-event.schema.json +10 -1
  153. package/schemas/task.schema.json +46 -2
  154. package/schemas/transition-payloads.schema.json +16 -1
  155. package/src/alpha6/adoption.ts +1123 -0
  156. package/src/alpha6/captured-check-evidence.ts +132 -0
  157. package/src/alpha6/check-support-anchor.ts +128 -0
  158. package/src/alpha6/component-owner.ts +168 -0
  159. package/src/alpha6/corrective-decision-boundary.ts +39 -0
  160. package/src/alpha6/downstream-proof.ts +520 -0
  161. package/src/alpha6/failed-step-planning-recovery.ts +88 -0
  162. package/src/alpha6/handoff.ts +1443 -0
  163. package/src/alpha6/journal.ts +473 -0
  164. package/src/alpha6/literal-test-invocation.ts +84 -0
  165. package/src/alpha6/mechanical-feasibility.ts +488 -0
  166. package/src/alpha6/milestone.ts +2192 -0
  167. package/src/alpha6/navigation-dirty-carryover.ts +154 -0
  168. package/src/alpha6/npm-check-contract.ts +47 -0
  169. package/src/alpha6/plan-integrity.ts +298 -0
  170. package/src/alpha6/plan-risk.ts +1480 -0
  171. package/src/alpha6/preexecution-replan.ts +187 -0
  172. package/src/alpha6/remediation-cause.ts +98 -0
  173. package/src/alpha6/remediation.ts +2438 -0
  174. package/src/alpha6/review.ts +1198 -0
  175. package/src/alpha6/root-cause-replan-carryover.ts +491 -0
  176. package/src/alpha6/store-sidecars.ts +335 -0
  177. package/src/alpha7/autonomy.ts +411 -0
  178. package/src/alpha7/corrective-recovery.ts +1332 -0
  179. package/src/artifacts.ts +130 -0
  180. package/src/beta1/project-transaction.ts +355 -0
  181. package/src/change-explanation.ts +153 -0
  182. package/src/checks/runner.ts +245 -0
  183. package/src/checks/task-sync.ts +41 -0
  184. package/src/checks/worker.ts +149 -0
  185. package/src/cli-actions.ts +107 -0
  186. package/src/cli.ts +1457 -0
  187. package/src/contracts.ts +1494 -0
  188. package/src/credential-output.ts +89 -0
  189. package/src/credential-transport.ts +215 -0
  190. package/src/delegation.ts +190 -0
  191. package/src/dependency-provenance.ts +472 -0
  192. package/src/diagnostics.ts +93 -0
  193. package/src/domain/base-sync-conflict.ts +35 -0
  194. package/src/domain/completed-step-carryover.ts +76 -0
  195. package/src/domain/discovery.ts +27 -0
  196. package/src/domain/plan-semantics.ts +58 -0
  197. package/src/domain/step-start-admission.ts +10 -0
  198. package/src/domain/validation.ts +177 -0
  199. package/src/domain/virgin-registration.ts +46 -0
  200. package/src/errors.ts +24 -0
  201. package/src/fs-utils.ts +61 -0
  202. package/src/gateway-handshake.ts +95 -0
  203. package/src/git.ts +183 -0
  204. package/src/graph.ts +342 -0
  205. package/src/historical-step-provenance.ts +136 -0
  206. package/src/index.ts +23 -0
  207. package/src/lifecycle/canonical-hash.ts +28 -0
  208. package/src/lifecycle/catalog.ts +202 -0
  209. package/src/lifecycle/compiler-inspection.ts +29 -0
  210. package/src/lifecycle/core-static-readiness.ts +132 -0
  211. package/src/lifecycle/corrective-replan-authority.ts +136 -0
  212. package/src/lifecycle/corrective-replan-binding-manifest.ts +51 -0
  213. package/src/lifecycle/corrective-replan-credential-core.ts +408 -0
  214. package/src/lifecycle/corrective-replan-credential-schema.ts +54 -0
  215. package/src/lifecycle/corrective-replan-credentials.ts +48 -0
  216. package/src/lifecycle/corrective-replan.ts +843 -0
  217. package/src/lifecycle/evaluator.ts +48 -0
  218. package/src/lifecycle/fingerprint.ts +488 -0
  219. package/src/lifecycle/immutable.ts +8 -0
  220. package/src/lifecycle/implementation-table.ts +118 -0
  221. package/src/lifecycle/index.ts +8 -0
  222. package/src/lifecycle/schema-artifact.ts +263 -0
  223. package/src/lifecycle/semantic-registry.ts +572 -0
  224. package/src/lifecycle/types.ts +838 -0
  225. package/src/memory.ts +273 -0
  226. package/src/migration.ts +161 -0
  227. package/src/navigation-actions.ts +70 -0
  228. package/src/navigation-update-artifact.ts +198 -0
  229. package/src/navigation-update.ts +121 -0
  230. package/src/observation.ts +225 -0
  231. package/src/observed-routes.ts +660 -0
  232. package/src/operational-contract.ts +125 -0
  233. package/src/pending-review-update.ts +175 -0
  234. package/src/repository.ts +99 -0
  235. package/src/reviewer.ts +1879 -0
  236. package/src/runtime.ts +6 -0
  237. package/src/state/corrective-replan-executor.ts +818 -0
  238. package/src/state/corrective-replan-public-schema.ts +83 -0
  239. package/src/state/corrective-replan-public.ts +908 -0
  240. package/src/state/corrective-replan-transaction.ts +949 -0
  241. package/src/state/corrective-yield-executor.ts +327 -0
  242. package/src/state/corrective-yield-transaction.ts +730 -0
  243. package/src/state/lock.ts +902 -0
  244. package/src/state/store.ts +567 -0
  245. package/src/transition-core.ts +330 -0
  246. package/src/ulid.ts +24 -0
  247. package/src/version.ts +2 -0
  248. package/src/workflow-blocker-route.ts +109 -0
  249. package/src/workflow.ts +10172 -0
  250. package/docs/alpha7.1-implementation-brief.md +0 -268
  251. package/docs/alpha7.2-corrective-context-refresh-brief.md +0 -484
  252. package/docs/alpha7.2.1-remediation-recovery-brief.md +0 -86
  253. package/docs/beta1-stabilization-brief.md +0 -165
  254. package/docs/beta11-plan-integrity-recovery-brief.md +0 -38
  255. package/docs/beta13.2-signal-review-recovery.md +0 -38
  256. package/docs/beta2-initial-assembly-navigation-brief.md +0 -616
  257. package/docs/change-model.md +0 -118
  258. package/docs/delegated-approval.md +0 -254
  259. package/docs/lifecycle/state-machine-stabilization.md +0 -641
  260. package/docs/pdf/README.md +0 -24
  261. package/docs/pdf/codex-workflow-v2-architecture-ru.pdf +0 -0
  262. package/docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf +0 -0
  263. package/docs/pdf/codex-workflow-v2-technical-reference-ru.pdf +0 -0
  264. package/docs/pdf/requirements.txt +0 -1
  265. package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +0 -478
  266. package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +0 -508
  267. package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +0 -778
  268. package/docs/pending-review-update.md +0 -15
  269. package/docs/problem-briefs/01-pre-implementation-integrity.md +0 -482
  270. package/docs/problem-briefs/02-minimal-step-integrity.md +0 -411
  271. package/docs/problem-briefs/03-minimal-agent-context-integrity.md +0 -358
  272. package/docs/problem-briefs/04-task-dependency-and-structural-replacement-integrity.md +0 -573
  273. package/docs/problem-briefs/BRIEF-TEMPLATE.md +0 -56
  274. package/docs/problem-briefs/README.md +0 -120
  275. package/docs/problem-briefs/evidence/p01-mechanical-feasibility-corpus.md +0 -90
  276. package/docs/problem-briefs/evidence/signal-v4-pre-m3-replay.md +0 -246
  277. package/docs/split-required-recovery.md +0 -47
  278. package/docs/stable-release-defect-register.md +0 -730
  279. package/docs/validation-report.md +0 -182
  280. package/scripts/generate-pdf-docs.py +0 -524
  281. package/scripts/run-pdf-docs.mjs +0 -62
package/src/cli.ts ADDED
@@ -0,0 +1,1457 @@
1
+ #!/usr/bin/env node
2
+ import { SUPPORTED_NODE_VERSION, isSupportedNodeVersion } from './runtime.js';
3
+ import { readFileSync } from 'node:fs';
4
+ import path from 'node:path';
5
+ import process from 'node:process';
6
+ import type {
7
+ CorrectivePlanAuditInput,
8
+ DelegationPolicyInput,
9
+ GraphKind,
10
+ GraphMode,
11
+ GraphRefreshEvidence,
12
+ GraphRefreshRequest,
13
+ KnowledgeSelection,
14
+ MilestonePlanInput,
15
+ ReviewInput,
16
+ TaskPlanInput,
17
+ WorkspaceOwner,
18
+ } from './contracts.js';
19
+ import type { RecordPlanRiskAuditInput } from './alpha6/plan-risk.js';
20
+ import { defaultTaskWorkerActor } from './alpha6/handoff.js';
21
+ import {
22
+ assertCliSuccessCredentialSafety,
23
+ projectCliErrorMessage,
24
+ projectCliErrorValue,
25
+ UnsafeCredentialOutputError,
26
+ } from './credential-output.js';
27
+ import {
28
+ assertNoLegacyCredentialArguments,
29
+ consumeCredentialReference,
30
+ issueCredentialReference,
31
+ resolveCredentialReference,
32
+ } from './credential-transport.js';
33
+ import { integrationDiagnostics } from './diagnostics.js';
34
+ import { WorkflowError } from './errors.js';
35
+ import { prepareGraphView } from './graph.js';
36
+ import { migrateState } from './migration.js';
37
+ import { changedFiles, currentBranch, isClean, resolveRepositoryIdentity } from './repository.js';
38
+ import { launchStrictReviewer } from './reviewer.js';
39
+ import type { ExternalStrictStepReviewInput, ExternalStrictTaskReviewInput, ReviewMode } from './reviewer.js';
40
+ import {
41
+ WorkflowService,
42
+ type AuditedRemediationMaterializationInput,
43
+ type DiscoveryInput,
44
+ type DiscoveryPatch,
45
+ } from './workflow.js';
46
+ import { gatewayHandshake } from './gateway-handshake.js';
47
+ import type {
48
+ CorrectiveReplanHumanGate,
49
+ CorrectiveReplanPublicCandidate,
50
+ CorrectiveReplanPublicCredential,
51
+ } from './state/corrective-replan-public.js';
52
+ import { CLI_ACTIONS } from './cli-actions.js';
53
+
54
+ interface ParsedArguments {
55
+ positionals: string[];
56
+ options: Map<string, string[]>;
57
+ }
58
+
59
+ interface CliHelpSpec {
60
+ requiredOptions: string[];
61
+ optionalOptions: string[];
62
+ fileInput?: {
63
+ description: string;
64
+ requiredTopLevelFields: string[];
65
+ reviewMode: "ordinary | security";
66
+ nestedReviewRequiredFields: string[];
67
+ example: Record<string, unknown>;
68
+ };
69
+ }
70
+
71
+ const CLI_HELP_SPECS: Record<string, CliHelpSpec> = {
72
+ 'update navigation-source-preflight': { requiredOptions: ['--id', '--tarball'], optionalOptions: ['--repo', '--json'] },
73
+ 'update navigation-transport-preflight': { requiredOptions: ['--id', '--tarball', '--file'], optionalOptions: ['--repo', '--json'] },
74
+ 'update navigation-recover': { requiredOptions: ['--id', '--tarball', '--file', '--expected-revision', '--actor', '--reason'], optionalOptions: ['--repo', '--json'] },
75
+ 'change explain': { requiredOptions: ['--task', '--file'], optionalOptions: ['--repo', '--json'] },
76
+ 'milestone remediation-materialize': {
77
+ requiredOptions: ['--id', '--expected-revision', '--task', '--expected-task-revision', '--file'],
78
+ optionalOptions: ['--repo', '--json'],
79
+ },
80
+ 'update dependency-provenance-preflight': {
81
+ requiredOptions: ['--id'],
82
+ optionalOptions: ['--repo', '--json'],
83
+ },
84
+ 'task historical-step-provenance-preflight': {
85
+ requiredOptions: ['--id'],
86
+ optionalOptions: ['--repo', '--json'],
87
+ },
88
+ 'task historical-step-provenance-recover': {
89
+ requiredOptions: ['--id', '--expected-revision', '--commit', '--actor', '--reason'],
90
+ optionalOptions: ['--repo', '--json'],
91
+ },
92
+ 'update dependency-provenance-recover': {
93
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--reason'],
94
+ optionalOptions: ['--repo', '--json'],
95
+ },
96
+ 'update historical-step-dependency-preflight': {
97
+ requiredOptions: ['--id'],
98
+ optionalOptions: ['--repo', '--json'],
99
+ },
100
+ 'update historical-step-dependency-recover': {
101
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--reason'],
102
+ optionalOptions: ['--repo', '--json'],
103
+ },
104
+ 'update downstream-proof-dependency-preflight': {
105
+ requiredOptions: ['--id'],
106
+ optionalOptions: ['--repo', '--json'],
107
+ },
108
+ 'update downstream-proof-dependency-recover': {
109
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--reason'],
110
+ optionalOptions: ['--repo', '--json'],
111
+ },
112
+ 'milestone progress': {
113
+ requiredOptions: ['--id'],
114
+ optionalOptions: ['--repo', '--json'],
115
+ },
116
+ 'milestone authorize': {
117
+ requiredOptions: ['--id', '--expected-revision'],
118
+ optionalOptions: ['--actor', '--reason', '--delegation-grant', '--repo', '--json'],
119
+ },
120
+ 'milestone validate': {
121
+ requiredOptions: ['--id', '--expected-revision'],
122
+ optionalOptions: ['--repo', '--json'],
123
+ },
124
+ 'milestone accept': {
125
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--confirmation-code'],
126
+ optionalOptions: ['--delegation-grant', '--repo', '--json'],
127
+ },
128
+ 'task plan-set': {
129
+ requiredOptions: ['--id', '--expected-revision', '--file', '--risk-audit-file'],
130
+ optionalOptions: ['--corrective-audit-file', '--repo', '--json'],
131
+ },
132
+ 'task preexecution-replan': {
133
+ requiredOptions: [
134
+ '--id', '--expected-revision', '--actor', '--reason', '--file', '--expected-brief-hash',
135
+ '--expected-plan-hash', '--expected-plan-risk-audit-event-hash', '--expected-head-commit',
136
+ ],
137
+ optionalOptions: ['--repo', '--json'],
138
+ },
139
+ 'task handoff-replace': {
140
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--target-actor', '--reason'],
141
+ optionalOptions: ['--writer-credential-ref', '--delegation-grant', '--expires-at', '--repo', '--json'],
142
+ },
143
+ 'task handoff': {
144
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--reason'],
145
+ optionalOptions: ['--target-actor', '--writer-credential-ref', '--delegation-grant', '--expires-at', '--repo', '--json'],
146
+ },
147
+ 'task handoff-prepare': {
148
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--reason'],
149
+ optionalOptions: ['--target-actor', '--writer-credential-ref', '--delegation-grant', '--expires-at', '--repo', '--json'],
150
+ },
151
+ 'task claim': {
152
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--claim-credential-ref'],
153
+ optionalOptions: ['--writer-credential-ref', '--repo', '--json'],
154
+ },
155
+ 'task writer-credential-replace': {
156
+ requiredOptions: ['--id', '--expected-revision', '--actor'],
157
+ optionalOptions: ['--repo', '--json'],
158
+ },
159
+ 'task corrective-yield': {
160
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--writer-credential-ref', '--reason'],
161
+ optionalOptions: ['--repo', '--json'],
162
+ },
163
+ 'task plan-integrity-recover': {
164
+ requiredOptions: ['--id', '--step', '--expected-revision', '--actor'],
165
+ optionalOptions: ['--writer-credential-ref', '--repo', '--json'],
166
+ },
167
+ 'task downstream-proof-recover': {
168
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--writer-credential-ref', '--reason'],
169
+ optionalOptions: ['--repo', '--json'],
170
+ },
171
+ 'task corrective-yield-recover': {
172
+ requiredOptions: ['--id', '--transaction-id'],
173
+ optionalOptions: ['--repo', '--json'],
174
+ },
175
+ 'task corrective-replan-prepare': {
176
+ requiredOptions: ['--id', '--file'],
177
+ optionalOptions: ['--repo', '--json'],
178
+ },
179
+ 'task corrective-replan-confirm': {
180
+ requiredOptions: ['--id', '--file', '--gate-file', '--confirmation-code'],
181
+ optionalOptions: ['--repo', '--json'],
182
+ },
183
+ 'task corrective-replan-execute': {
184
+ requiredOptions: ['--id', '--file', '--credential-file'],
185
+ optionalOptions: ['--repo', '--json'],
186
+ },
187
+ 'task corrective-replan-recover': {
188
+ requiredOptions: ['--id', '--transaction-id'],
189
+ optionalOptions: ['--repo', '--json'],
190
+ },
191
+ 'task authorize': {
192
+ requiredOptions: ['--id', '--expected-revision'],
193
+ optionalOptions: ['--actor', '--reason', '--delegation-grant', '--repo', '--json'],
194
+ },
195
+ 'task start': {
196
+ requiredOptions: ['--id', '--expected-revision', '--workspace-owner'],
197
+ optionalOptions: ['--repo', '--json'],
198
+ },
199
+ 'task run': {
200
+ requiredOptions: ['--id', '--step', '--expected-revision'],
201
+ optionalOptions: ['--owner', '--writer-credential-ref', '--repo', '--json'],
202
+ },
203
+ 'task step-complete': {
204
+ requiredOptions: ['--id', '--step', '--expected-revision', '--writer-credential-ref'],
205
+ optionalOptions: ['--note', '--actor', '--repo', '--json'],
206
+ },
207
+ 'task submit': {
208
+ requiredOptions: ['--id', '--expected-revision', '--writer-credential-ref'],
209
+ optionalOptions: ['--actor', '--repo', '--json'],
210
+ },
211
+ 'task review-launch': {
212
+ requiredOptions: ['--id', '--expected-revision'],
213
+ optionalOptions: ['--actor', '--writer-credential-ref', '--repo', '--json'],
214
+ },
215
+ 'task review-packet': {
216
+ requiredOptions: ['--id', '--expected-revision', '--review-mode'],
217
+ optionalOptions: ['--repo', '--json'],
218
+ },
219
+ 'task review-sealed-record': {
220
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--file'],
221
+ optionalOptions: ['--writer-credential-ref', '--repo', '--json'],
222
+ fileInput: {
223
+ description: 'Full ExternalStrictTaskReviewInput envelope; reviewMode is a top-level JSON field.',
224
+ requiredTopLevelFields: ['protocol', 'packetHash', 'repositorySealHash', 'reviewerThreadId', 'reviewMode', 'review'],
225
+ reviewMode: 'ordinary | security',
226
+ nestedReviewRequiredFields: ['status', 'reviewer', 'summary', 'findings'],
227
+ example: {
228
+ protocol: 'codex-workflow-external-strict-task-review-v1',
229
+ packetHash: '<packet.packetHash>',
230
+ repositorySealHash: '<packet.repositorySealHash>',
231
+ reviewerThreadId: '<separate-reviewer-thread-id>',
232
+ reviewMode: 'ordinary',
233
+ review: { status: 'passed', reviewer: '<reviewer>', summary: '<summary>', findings: [] },
234
+ },
235
+ },
236
+ },
237
+ 'task step-review-packet': {
238
+ requiredOptions: ['--id', '--step', '--expected-revision', '--review-mode'],
239
+ optionalOptions: ['--repo', '--json'],
240
+ },
241
+ 'task step-review-record': {
242
+ requiredOptions: ['--id', '--step', '--expected-revision', '--actor', '--file'],
243
+ optionalOptions: ['--writer-credential-ref', '--repo', '--json'],
244
+ fileInput: {
245
+ description: 'Full ExternalStrictStepReviewInput envelope; reviewMode is a top-level JSON field.',
246
+ requiredTopLevelFields: ['protocol', 'packetHash', 'repositorySealHash', 'reviewerThreadId', 'reviewMode', 'review'],
247
+ reviewMode: 'ordinary | security',
248
+ nestedReviewRequiredFields: ['status', 'reviewer', 'summary', 'findings'],
249
+ example: {
250
+ protocol: 'codex-workflow-external-strict-step-review-v1',
251
+ packetHash: '<packet.packetHash>',
252
+ repositorySealHash: '<packet.repositorySealHash>',
253
+ reviewerThreadId: '<separate-reviewer-thread-id>',
254
+ reviewMode: 'ordinary',
255
+ review: { status: 'passed', reviewer: '<reviewer>', summary: '<summary>', findings: [] },
256
+ },
257
+ },
258
+ },
259
+ 'task result-set': {
260
+ requiredOptions: ['--id', '--expected-revision', '--summary', '--writer-credential-ref'],
261
+ optionalOptions: ['--actor', '--limitation', '--repo', '--json'],
262
+ },
263
+ 'task accept': {
264
+ requiredOptions: ['--id', '--expected-revision'],
265
+ optionalOptions: ['--actor', '--delegation-grant', '--repo', '--json'],
266
+ },
267
+ 'task merge': {
268
+ requiredOptions: ['--id', '--expected-revision', '--writer-credential-ref'],
269
+ optionalOptions: ['--actor', '--repo', '--json'],
270
+ },
271
+ 'task merge-confirm': {
272
+ requiredOptions: ['--id', '--expected-revision', '--writer-credential-ref'],
273
+ optionalOptions: ['--actor', '--repo', '--json'],
274
+ },
275
+ };
276
+
277
+ function parseArguments(argv: string[]): ParsedArguments {
278
+ const positionals: string[] = [];
279
+ const options = new Map<string, string[]>();
280
+ for (let index = 0; index < argv.length; index += 1) {
281
+ const argument = argv[index];
282
+ if (!argument) continue;
283
+ if (!argument.startsWith('--')) {
284
+ positionals.push(argument);
285
+ continue;
286
+ }
287
+ const equals = argument.indexOf('=');
288
+ const name = argument.slice(2, equals === -1 ? undefined : equals);
289
+ const inlineValue = equals === -1 ? null : argument.slice(equals + 1);
290
+ const next = argv[index + 1];
291
+ const value = inlineValue ?? (next && !next.startsWith('--') ? next : 'true');
292
+ if (inlineValue === null && next && !next.startsWith('--')) index += 1;
293
+ options.set(name, [...(options.get(name) ?? []), value]);
294
+ }
295
+ return { positionals, options };
296
+ }
297
+
298
+ function option(args: ParsedArguments, name: string): string | undefined {
299
+ return args.options.get(name)?.at(-1);
300
+ }
301
+
302
+ function reviewMode(args: ParsedArguments): ReviewMode {
303
+ const value = required(args, 'review-mode');
304
+ if (value !== 'ordinary' && value !== 'security') {
305
+ throw new WorkflowError('INVALID_ARGUMENT', '--review-mode must be ordinary or security.');
306
+ }
307
+ return value;
308
+ }
309
+
310
+ function cliHelp(args: ParsedArguments): Record<string, unknown> {
311
+ const [noun, action] = args.positionals;
312
+ if (!noun) {
313
+ return {
314
+ kind: 'cli-help',
315
+ readOnly: true,
316
+ scope: 'top-level',
317
+ usage: 'codex-workflow <command> [action] [options]',
318
+ commands: ['doctor', 'status', 'next', ...Object.keys(CLI_ACTIONS)],
319
+ };
320
+ }
321
+ if (!action) {
322
+ if (['doctor', 'status', 'next'].includes(noun)) {
323
+ const taskSelector = noun === 'next' ? ['--task'] : [];
324
+ return {
325
+ kind: 'cli-help',
326
+ readOnly: true,
327
+ scope: 'command',
328
+ command: noun,
329
+ usage: noun === 'next'
330
+ ? 'codex-workflow next [--task <task-id>] [--repo <path>] [--json]'
331
+ : noun === 'status'
332
+ ? 'codex-workflow status [--full] [--repo <path>] [--json]'
333
+ : `codex-workflow ${noun} [--repo <path>] [--json]`,
334
+ requiredOptions: [],
335
+ optionalOptions: [...taskSelector, ...(noun === 'status' ? ['--full'] : []), '--repo', '--json'],
336
+ exactOptionContractAvailable: true,
337
+ };
338
+ }
339
+ return {
340
+ kind: 'cli-help',
341
+ readOnly: true,
342
+ scope: 'command',
343
+ command: noun,
344
+ usage: `codex-workflow ${noun} <action> [options]`,
345
+ actions: CLI_ACTIONS[noun] ?? [],
346
+ };
347
+ }
348
+ const command = `${noun} ${action}`;
349
+ const spec = CLI_HELP_SPECS[command];
350
+ return {
351
+ kind: 'cli-help',
352
+ readOnly: true,
353
+ scope: 'action',
354
+ command,
355
+ usage: spec
356
+ ? ['codex-workflow', noun, action, ...spec.requiredOptions.map((name) => `${name} <value>`), '[options]'].join(' ')
357
+ : `codex-workflow ${noun} ${action} [options]`,
358
+ requiredOptions: spec?.requiredOptions ?? null,
359
+ optionalOptions: spec?.optionalOptions ?? null,
360
+ exactOptionContractAvailable: Boolean(spec),
361
+ ...(spec?.fileInput ? { fileInput: spec.fileInput } : {}),
362
+ ...(spec ? {} : { note: 'Consult the packaged protocol for this action option contract.' }),
363
+ };
364
+ }
365
+
366
+ function required(args: ParsedArguments, name: string): string {
367
+ const value = option(args, name)?.trim();
368
+ if (!value) throw new WorkflowError('INVALID_ARGUMENT', `Missing required option --${name}.`);
369
+ return value;
370
+ }
371
+
372
+ function repeated(args: ParsedArguments, name: string): string[] {
373
+ return (args.options.get(name) ?? []).map((value) => value.trim()).filter(Boolean);
374
+ }
375
+
376
+ function revision(args: ParsedArguments): number {
377
+ const value = Number(required(args, 'expected-revision'));
378
+ if (!Number.isInteger(value) || value < 1) {
379
+ throw new WorkflowError('INVALID_ARGUMENT', '--expected-revision must be a positive integer.');
380
+ }
381
+ return value;
382
+ }
383
+
384
+ function positiveIntegerOption(args: ParsedArguments, name: string): number {
385
+ const value = Number(required(args, name));
386
+ if (!Number.isInteger(value) || value < 1) {
387
+ throw new WorkflowError('INVALID_ARGUMENT', `--${name} must be a positive integer.`);
388
+ }
389
+ return value;
390
+ }
391
+
392
+ function optionalRevision(args: ParsedArguments): number | null {
393
+ const raw = option(args, 'expected-revision');
394
+ if (raw === undefined) return null;
395
+ const value = Number(raw);
396
+ if (!Number.isInteger(value) || value < 1) {
397
+ throw new WorkflowError('INVALID_ARGUMENT', '--expected-revision must be a positive integer.');
398
+ }
399
+ return value;
400
+ }
401
+
402
+ function graphKind(args: ParsedArguments): GraphKind {
403
+ const value = required(args, 'kind');
404
+ if (value !== 'product' && value !== 'workflow') {
405
+ throw new WorkflowError('INVALID_ARGUMENT', '--kind must be product or workflow.');
406
+ }
407
+ return value;
408
+ }
409
+
410
+ function graphMode(args: ParsedArguments): GraphMode {
411
+ const value = option(args, 'mode') ?? 'moderate';
412
+ if (value !== 'moderate' && value !== 'full') {
413
+ throw new WorkflowError('INVALID_ARGUMENT', '--mode must be moderate or full.');
414
+ }
415
+ return value;
416
+ }
417
+
418
+ function jsonFile<T>(args: ParsedArguments, optionName = 'file'): T {
419
+ const file = path.resolve(required(args, optionName));
420
+ try {
421
+ return JSON.parse(readFileSync(file, 'utf8')) as T;
422
+ } catch (error) {
423
+ throw new WorkflowError('INVALID_ARGUMENT', `Cannot read JSON from ${file}.`, {
424
+ cause: error instanceof Error ? error.message : String(error),
425
+ });
426
+ }
427
+ }
428
+
429
+ function stdinJson<T>(): T {
430
+ try {
431
+ return JSON.parse(readFileSync(0, 'utf8')) as T;
432
+ } catch (error) {
433
+ throw new WorkflowError('INVALID_ARGUMENT', 'Cannot read JSON from stdin.', {
434
+ cause: error instanceof Error ? error.message : String(error),
435
+ });
436
+ }
437
+ }
438
+
439
+ function repository(args: ParsedArguments): string {
440
+ return path.resolve(option(args, 'repo') ?? '.');
441
+ }
442
+
443
+ const WRITER_CREDENTIAL_ACTIONS = [
444
+ 'task run',
445
+ 'task step-complete',
446
+ 'task submit',
447
+ 'task review-record',
448
+ 'task review-launch',
449
+ 'task review-sealed-record',
450
+ 'task step-review',
451
+ 'task step-review-record',
452
+ 'task corrective-decision-recover',
453
+ 'task plan-integrity-recover',
454
+ 'task downstream-proof-recover',
455
+ 'task corrective-decision',
456
+ 'task corrective-yield',
457
+ 'task handoff',
458
+ 'task handoff-prepare',
459
+ 'task handoff-replace',
460
+ 'task claim',
461
+ 'task handback',
462
+ 'task handback-create',
463
+ 'task result-set',
464
+ 'task merge',
465
+ 'task merge-confirm',
466
+ ] as const;
467
+
468
+ function credentialToken(
469
+ workflow: WorkflowService,
470
+ repo: string,
471
+ args: ParsedArguments,
472
+ kind: 'writer-lease' | 'claim-token',
473
+ action: string,
474
+ entityId: string,
475
+ actor: string | null,
476
+ requiredReference: boolean,
477
+ ): string | null {
478
+ const optionName = kind === 'writer-lease' ? 'writer-credential-ref' : 'claim-credential-ref';
479
+ const reference = option(args, optionName);
480
+ if (!reference) {
481
+ if (requiredReference) {
482
+ throw new WorkflowError('INVALID_ARGUMENT', `Missing required option --${optionName}.`);
483
+ }
484
+ return null;
485
+ }
486
+ const identity = resolveRepositoryIdentity(repo);
487
+ return resolveCredentialReference({
488
+ stateRoot: workflow.store.root,
489
+ projectId: identity.projectId,
490
+ reference,
491
+ kind,
492
+ entityId,
493
+ actor,
494
+ action,
495
+ }).token;
496
+ }
497
+
498
+ function writerCredentialReceipt(
499
+ workflow: WorkflowService,
500
+ repo: string,
501
+ taskId: string,
502
+ actor: string,
503
+ token: string,
504
+ expiresAt: string,
505
+ ) {
506
+ const identity = resolveRepositoryIdentity(repo);
507
+ return issueCredentialReference({
508
+ stateRoot: workflow.store.root,
509
+ projectId: identity.projectId,
510
+ entityId: taskId,
511
+ actor,
512
+ kind: 'writer-lease',
513
+ token,
514
+ allowedActions: WRITER_CREDENTIAL_ACTIONS,
515
+ expiresAt,
516
+ oneTime: false,
517
+ });
518
+ }
519
+
520
+ function consumeCredentialOption(
521
+ workflow: WorkflowService,
522
+ repo: string,
523
+ args: ParsedArguments,
524
+ optionName: 'writer-credential-ref' | 'claim-credential-ref',
525
+ ): void {
526
+ const reference = option(args, optionName);
527
+ if (!reference) return;
528
+ consumeCredentialReference(workflow.store.root, resolveRepositoryIdentity(repo).projectId, reference);
529
+ }
530
+
531
+ async function dispatch(args: ParsedArguments): Promise<unknown> {
532
+ const [noun, action] = args.positionals;
533
+ if (args.options.has('help')) return cliHelp(args);
534
+ const repo = repository(args);
535
+
536
+ if (noun === 'gateway' && action === 'handshake') {
537
+ return gatewayHandshake();
538
+ }
539
+
540
+ const workflow = new WorkflowService();
541
+
542
+ if (noun === 'doctor') {
543
+ const identity = resolveRepositoryIdentity(repo);
544
+ const integration = integrationDiagnostics(identity.repositoryRoot);
545
+ const nodeSupported = isSupportedNodeVersion(process.versions.node);
546
+ return {
547
+ ok: nodeSupported && integration.localDependency.current,
548
+ node: process.versions.node,
549
+ requiredNode: SUPPORTED_NODE_VERSION,
550
+ repositoryRoot: identity.repositoryRoot,
551
+ projectId: identity.projectId,
552
+ stateRoot: workflow.store.root,
553
+ branch: currentBranch(identity.repositoryRoot),
554
+ clean: isClean(identity.repositoryRoot),
555
+ changedFiles: changedFiles(identity.repositoryRoot),
556
+ integration,
557
+ limitations: [
558
+ 'CLI diagnostics cannot prove that Codex enforced a role, model, sandbox, or read-only reviewer.',
559
+ 'MCP refresh execution is performed by the personal gateway; the core verifies returned binding evidence.',
560
+ ],
561
+ };
562
+ }
563
+ if (noun === 'status') return args.options.has('full') ? workflow.status(repo) : workflow.compactStatus(repo);
564
+ if (noun === 'next') return workflow.next(repo, option(args, 'task') ?? null);
565
+ if (noun === 'change' && action === 'explain') return workflow.explainChange(repo, required(args, 'task'), jsonFile(args));
566
+ if (noun === 'update' && action === 'preflight') return workflow.updatePreflight(repo);
567
+ if (noun === 'update' && action === 'navigation-source-preflight') {
568
+ return workflow.navigationUpdateSourcePreflight(repo, required(args, 'id'), required(args, 'tarball'));
569
+ }
570
+ if (noun === 'update' && action === 'navigation-transport-preflight') {
571
+ return workflow.navigationUpdateTransportPreflight(repo, required(args, 'id'), required(args, 'tarball'), jsonFile(args));
572
+ }
573
+ if (noun === 'update' && action === 'navigation-recover') {
574
+ return workflow.recoverNavigationUpdate(repo, required(args, 'id'), revision(args), required(args, 'tarball'),
575
+ jsonFile(args), required(args, 'actor'), required(args, 'reason'));
576
+ }
577
+ if (noun === 'update' && action === 'dependency-provenance-preflight') {
578
+ return workflow.dependencyProvenanceRecoveryPreflight(repo, required(args, 'id'));
579
+ }
580
+ if (noun === 'task' && action === 'historical-step-provenance-preflight') {
581
+ return workflow.historicalStepProvenanceRecoveryPreflight(repo, required(args, 'id'));
582
+ }
583
+ if (noun === 'task' && action === 'historical-step-provenance-recover') {
584
+ return workflow.recoverHistoricalStepProvenance(
585
+ repo,
586
+ required(args, 'id'),
587
+ revision(args),
588
+ required(args, 'commit'),
589
+ required(args, 'actor'),
590
+ required(args, 'reason'),
591
+ );
592
+ }
593
+ if (noun === 'update' && action === 'dependency-provenance-recover') {
594
+ return workflow.recoverDependencyProvenance(
595
+ repo,
596
+ required(args, 'id'),
597
+ revision(args),
598
+ required(args, 'actor'),
599
+ required(args, 'reason'),
600
+ );
601
+ }
602
+ if (noun === 'update' && action === 'historical-step-dependency-preflight') {
603
+ return workflow.historicalStepDependencyRecoveryPreflight(repo, required(args, 'id'));
604
+ }
605
+ if (noun === 'update' && action === 'historical-step-dependency-recover') {
606
+ return workflow.recoverHistoricalStepDependencyProvenance(
607
+ repo,
608
+ required(args, 'id'),
609
+ revision(args),
610
+ required(args, 'actor'),
611
+ required(args, 'reason'),
612
+ );
613
+ }
614
+ if (noun === 'update' && action === 'downstream-proof-dependency-preflight') {
615
+ return workflow.activeDownstreamProofDependencyRecoveryPreflight(repo, required(args, 'id'));
616
+ }
617
+ if (noun === 'update' && action === 'downstream-proof-dependency-recover') {
618
+ return workflow.recoverActiveDownstreamProofDependencyProvenance(
619
+ repo,
620
+ required(args, 'id'),
621
+ revision(args),
622
+ required(args, 'actor'),
623
+ required(args, 'reason'),
624
+ );
625
+ }
626
+ if (noun === 'delegation' && action === 'prepare') {
627
+ return workflow.prepareDelegation(repo, jsonFile<DelegationPolicyInput>(args));
628
+ }
629
+ if (noun === 'delegation' && action === 'grant') {
630
+ return workflow.grantDelegation(
631
+ repo,
632
+ jsonFile<DelegationPolicyInput>(args),
633
+ required(args, 'confirmation-code'),
634
+ );
635
+ }
636
+ if (noun === 'delegation' && action === 'list') {
637
+ const identity = resolveRepositoryIdentity(repo);
638
+ return workflow.listDelegations(identity.projectId);
639
+ }
640
+ if (noun === 'delegation' && action === 'show') {
641
+ const identity = resolveRepositoryIdentity(repo);
642
+ return workflow.store.readDelegation(identity.projectId, required(args, 'id'));
643
+ }
644
+ if (noun === 'delegation' && action === 'revoke') {
645
+ return workflow.revokeDelegation(
646
+ repo,
647
+ required(args, 'id'),
648
+ revision(args),
649
+ required(args, 'actor'),
650
+ required(args, 'reason'),
651
+ );
652
+ }
653
+ if (noun === 'project-memory' && action === 'scan') return workflow.scanKnowledgeMap(repo);
654
+ if (noun === 'project-memory' && action === 'show') return workflow.showKnowledgeMap(repo);
655
+ if (noun === 'project-memory' && action === 'status') return workflow.knowledgeMapStatus(repo);
656
+ if (noun === 'project-memory' && action === 'approve') {
657
+ const input = jsonFile<{ selections: KnowledgeSelection[] }>(args);
658
+ if (!Array.isArray(input.selections)) {
659
+ throw new WorkflowError('INVALID_ARGUMENT', 'Knowledge approval file requires a selections array.');
660
+ }
661
+ return workflow.approveKnowledgeMap(
662
+ repo,
663
+ revision(args),
664
+ input.selections,
665
+ option(args, 'actor') ?? 'user',
666
+ option(args, 'delegation-grant') ?? null,
667
+ );
668
+ }
669
+ if (noun === 'project-memory' && action === 'reconcile') {
670
+ return workflow.reconcileKnowledgeMap(repo, revision(args));
671
+ }
672
+ if (noun === 'state' && action === 'migrate') {
673
+ const dryRun = option(args, 'dry-run') === 'true';
674
+ const snapshot = option(args, 'snapshot') === 'true';
675
+ if (dryRun === snapshot) {
676
+ throw new WorkflowError('INVALID_ARGUMENT', 'state migrate requires exactly one of --dry-run or --snapshot.');
677
+ }
678
+ return migrateState(repo, workflow.store, dryRun, snapshot);
679
+ }
680
+ if (noun === 'state' && action === 'adoption-prepare') {
681
+ return workflow.prepareAdoption(repo);
682
+ }
683
+ if (noun === 'state' && action === 'adoption-apply') {
684
+ return workflow.applyAdoption(
685
+ repo,
686
+ required(args, 'actor'),
687
+ required(args, 'confirmation-code'),
688
+ );
689
+ }
690
+ if (noun === 'milestone' && action === 'recover') {
691
+ return workflow.recoverMilestoneTransactions(repo);
692
+ }
693
+ if (noun === 'graph' && action === 'prepare') {
694
+ return prepareGraphView(option(args, 'target') ? path.resolve(required(args, 'target')) : undefined);
695
+ }
696
+ if (noun === 'graph' && action === 'status') {
697
+ return workflow.graphStatus(repo, graphKind(args), graphMode(args));
698
+ }
699
+ if (noun === 'graph' && action === 'refresh-request') {
700
+ return workflow.graphRefreshRequest(repo, graphKind(args), graphMode(args));
701
+ }
702
+ if (noun === 'graph' && action === 'bind') {
703
+ const input = stdinJson<{ request: GraphRefreshRequest; evidence: GraphRefreshEvidence }>();
704
+ return workflow.bindGraph(repo, optionalRevision(args), input.request, input.evidence);
705
+ }
706
+ if (noun === 'graph' && action === 'fallback') {
707
+ return workflow.recordGraphFallback(
708
+ repo,
709
+ graphKind(args),
710
+ graphMode(args),
711
+ optionalRevision(args),
712
+ required(args, 'reason'),
713
+ );
714
+ }
715
+ if (noun === 'context') {
716
+ const role = required(args, 'role');
717
+ if (role === 'worker' || role === 'scope-lead') {
718
+ throw new WorkflowError(
719
+ 'INVALID_ARGUMENT',
720
+ role === 'worker'
721
+ ? 'Worker context is issued by task run together with a writer lease.'
722
+ : 'Scope Lead works on Discovery before Task materialization.',
723
+ );
724
+ }
725
+ if (!['technical-planner', 'delivery-coordinator', 'independent-reviewer'].includes(role)) {
726
+ throw new WorkflowError('INVALID_ARGUMENT', 'Unknown context role.');
727
+ }
728
+ return workflow.taskContext(
729
+ repo,
730
+ required(args, 'task'),
731
+ role as 'technical-planner' | 'delivery-coordinator' | 'independent-reviewer',
732
+ );
733
+ }
734
+
735
+ if (noun === 'discovery' && action === 'start') {
736
+ const outcome = option(args, 'outcome')?.trim();
737
+ const input: DiscoveryInput = {
738
+ goal: required(args, 'goal'),
739
+ ...(outcome ? { outcome } : {}),
740
+ facts: repeated(args, 'fact'),
741
+ decisions: repeated(args, 'decision'),
742
+ assumptions: repeated(args, 'assumption'),
743
+ unknowns: repeated(args, 'unknown'),
744
+ blockingUnknowns: repeated(args, 'blocking-unknown'),
745
+ scope: repeated(args, 'scope'),
746
+ outOfScope: repeated(args, 'out-of-scope'),
747
+ constraints: repeated(args, 'constraint'),
748
+ acceptance: repeated(args, 'acceptance'),
749
+ };
750
+ return workflow.startDiscovery(repo, input);
751
+ }
752
+ if (noun === 'discovery' && action === 'update') {
753
+ const goal = option(args, 'goal')?.trim();
754
+ const outcome = option(args, 'outcome')?.trim();
755
+ const patch: DiscoveryPatch = {
756
+ ...(goal ? { goal } : {}),
757
+ ...(outcome ? { outcome } : {}),
758
+ facts: repeated(args, 'fact'),
759
+ decisions: repeated(args, 'decision'),
760
+ assumptions: repeated(args, 'assumption'),
761
+ unknowns: repeated(args, 'unknown'),
762
+ blockingUnknowns: repeated(args, 'blocking-unknown'),
763
+ resolveUnknowns: repeated(args, 'resolve-unknown'),
764
+ scope: repeated(args, 'scope'),
765
+ outOfScope: repeated(args, 'out-of-scope'),
766
+ constraints: repeated(args, 'constraint'),
767
+ acceptance: repeated(args, 'acceptance'),
768
+ };
769
+ return workflow.updateDiscovery(repo, required(args, 'id'), revision(args), patch);
770
+ }
771
+ if (noun === 'discovery' && action === 'show') {
772
+ const identity = resolveRepositoryIdentity(repo);
773
+ return workflow.store.readDiscovery(identity.projectId, required(args, 'id'));
774
+ }
775
+ if (noun === 'discovery' && action === 'materialize') {
776
+ const kind = option(args, 'kind') ?? 'task';
777
+ if (kind === 'task') {
778
+ return workflow.materializeTask(
779
+ repo,
780
+ required(args, 'id'),
781
+ revision(args),
782
+ required(args, 'title'),
783
+ option(args, 'base') ?? 'main',
784
+ option(args, 'milestone') ?? null,
785
+ );
786
+ }
787
+ if (kind === 'milestone') {
788
+ return workflow.materializeMilestone(
789
+ repo,
790
+ required(args, 'id'),
791
+ revision(args),
792
+ required(args, 'title'),
793
+ option(args, 'base') ?? 'main',
794
+ );
795
+ }
796
+ throw new WorkflowError('INVALID_ARGUMENT', '--kind must be task or milestone.');
797
+ }
798
+
799
+ if (noun === 'task' && action === 'show') {
800
+ const identity = resolveRepositoryIdentity(repo);
801
+ return workflow.store.readTask(identity.projectId, required(args, 'id'));
802
+ }
803
+ if (noun === 'task' && action === 'replacement-materialize') {
804
+ return workflow.replaceSplitRequiredTask(
805
+ repo,
806
+ required(args, 'id'),
807
+ revision(args),
808
+ required(args, 'discovery'),
809
+ positiveIntegerOption(args, 'expected-discovery-revision'),
810
+ positiveIntegerOption(args, 'expected-milestone-revision'),
811
+ required(args, 'title'),
812
+ option(args, 'actor') ?? 'user',
813
+ );
814
+ }
815
+ if (noun === 'task' && action === 'preexecution-replan') {
816
+ return workflow.recordPreExecutionReplan(
817
+ repo,
818
+ required(args, 'id'),
819
+ revision(args),
820
+ required(args, 'actor'),
821
+ required(args, 'reason'),
822
+ {
823
+ expectedBriefHash: required(args, 'expected-brief-hash'),
824
+ expectedPlanHash: required(args, 'expected-plan-hash'),
825
+ expectedPlanRiskAuditEventHash: required(args, 'expected-plan-risk-audit-event-hash'),
826
+ expectedHeadCommit: required(args, 'expected-head-commit'),
827
+ },
828
+ jsonFile<RecordPlanRiskAuditInput>(args),
829
+ );
830
+ }
831
+ if (noun === 'task' && action === 'plan-set') {
832
+ return workflow.setTaskPlan(
833
+ repo,
834
+ required(args, 'id'),
835
+ revision(args),
836
+ jsonFile<TaskPlanInput>(args),
837
+ option(args, 'corrective-audit-file')
838
+ ? jsonFile<CorrectivePlanAuditInput>(args, 'corrective-audit-file')
839
+ : null,
840
+ jsonFile<RecordPlanRiskAuditInput>(args, 'risk-audit-file'),
841
+ );
842
+ }
843
+ if (noun === 'task' && action === 'knowledge-rebind') {
844
+ return workflow.rebindTaskKnowledge(repo, required(args, 'id'), revision(args));
845
+ }
846
+ if (noun === 'task' && action === 'context-refresh') {
847
+ return workflow.refreshTaskContext(
848
+ repo,
849
+ required(args, 'id'),
850
+ positiveIntegerOption(args, 'expected-task-revision'),
851
+ positiveIntegerOption(args, 'expected-map-revision'),
852
+ required(args, 'actor'),
853
+ required(args, 'delegation-grant'),
854
+ );
855
+ }
856
+ if (noun === 'task' && action === 'authorize') {
857
+ return workflow.authorizeTask(
858
+ repo,
859
+ required(args, 'id'),
860
+ revision(args),
861
+ option(args, 'actor') ?? 'user',
862
+ option(args, 'reason') ?? '',
863
+ option(args, 'delegation-grant') ?? null,
864
+ );
865
+ }
866
+ if (noun === 'task' && action === 'plan-risk-audit') {
867
+ return workflow.recordPlanRiskAudit(
868
+ repo,
869
+ required(args, 'id'),
870
+ revision(args),
871
+ jsonFile<RecordPlanRiskAuditInput>(args),
872
+ );
873
+ }
874
+ if (noun === 'task' && action === 'start') {
875
+ const owner = required(args, 'workspace-owner');
876
+ if (owner !== 'local' && owner !== 'external') {
877
+ throw new WorkflowError('INVALID_ARGUMENT', '--workspace-owner must be local or external.');
878
+ }
879
+ return workflow.startTask(repo, required(args, 'id'), revision(args), owner as WorkspaceOwner);
880
+ }
881
+ if (noun === 'task' && action === 'run') {
882
+ const taskId = required(args, 'id');
883
+ const owner = option(args, 'owner') ?? 'worker';
884
+ const outcome = workflow.runStep(
885
+ repo,
886
+ taskId,
887
+ required(args, 'step'),
888
+ revision(args),
889
+ owner,
890
+ credentialToken(workflow, repo, args, 'writer-lease', 'task run', taskId, owner, false),
891
+ );
892
+ const { writerToken, ...envelope } = outcome.envelope;
893
+ if (outcome.writerCredential.disposition === 'issued' && !writerToken) {
894
+ throw new WorkflowError('STATE_CORRUPT', 'Fresh task run credential issuance did not return its protocol-v1 writer token.');
895
+ }
896
+ if (outcome.writerCredential.disposition === 'renewed' && writerToken !== null) {
897
+ throw new WorkflowError('STATE_CORRUPT', 'Renewed task run credential unexpectedly returned a writer token.');
898
+ }
899
+ return {
900
+ writerCredential: { disposition: outcome.writerCredential.disposition },
901
+ ...(writerToken ? {
902
+ writerCredentialReference: writerCredentialReceipt(
903
+ workflow, repo, taskId, outcome.lease.owner, writerToken, outcome.lease.expiresAt,
904
+ ),
905
+ } : {}),
906
+ task: outcome.task,
907
+ lease: outcome.lease,
908
+ envelope,
909
+ };
910
+ }
911
+ if (noun === 'task' && action === 'step-complete') {
912
+ const taskId = required(args, 'id');
913
+ return workflow.completeStep(
914
+ repo,
915
+ taskId,
916
+ required(args, 'step'),
917
+ revision(args),
918
+ credentialToken(workflow, repo, args, 'writer-lease', 'task step-complete', taskId, option(args, 'actor') ?? null, true)!,
919
+ repeated(args, 'note'),
920
+ option(args, 'actor'),
921
+ );
922
+ }
923
+ if (noun === 'task' && action === 'submit') {
924
+ const taskId = required(args, 'id');
925
+ return workflow.submitTask(
926
+ repo,
927
+ taskId,
928
+ revision(args),
929
+ credentialToken(workflow, repo, args, 'writer-lease', 'task submit', taskId, option(args, 'actor') ?? null, true)!,
930
+ option(args, 'actor'),
931
+ );
932
+ }
933
+ if (noun === 'task' && action === 'review-record') {
934
+ const review = jsonFile<ReviewInput>(args);
935
+ return workflow.recordReview(
936
+ repo,
937
+ required(args, 'id'),
938
+ revision(args),
939
+ review,
940
+ option(args, 'actor'),
941
+ credentialToken(workflow, repo, args, 'writer-lease', 'task review-record', required(args, 'id'), option(args, 'actor') ?? null, false),
942
+ );
943
+ }
944
+ if (noun === 'task' && action === 'review-launch') {
945
+ const identity = resolveRepositoryIdentity(repo);
946
+ const id = required(args, 'id');
947
+ const expectedRevision = revision(args);
948
+ const task = workflow.store.readTask(identity.projectId, id);
949
+ if (task.revision !== expectedRevision) {
950
+ throw new WorkflowError('STATE_CONFLICT', `State revision conflict for ${id}`, {
951
+ expectedRevision,
952
+ actualRevision: task.revision,
953
+ });
954
+ }
955
+ const envelope = workflow.taskContext(repo, id, 'independent-reviewer');
956
+ const launch = launchStrictReviewer(
957
+ identity.repositoryRoot,
958
+ task,
959
+ workflow.store.taskRoot(task.projectId, task.id),
960
+ envelope,
961
+ );
962
+ // The independent reviewer identity belongs to the strict reviewer payload. CLI --actor
963
+ // remains the lifecycle mutation actor, such as the current C1 claimant.
964
+ const saved = workflow.recordReview(
965
+ repo,
966
+ id,
967
+ expectedRevision,
968
+ launch.review,
969
+ option(args, 'actor'),
970
+ credentialToken(workflow, repo, args, 'writer-lease', 'task review-launch', id, option(args, 'actor') ?? null, false),
971
+ );
972
+ return { launch, task: saved };
973
+ }
974
+ if (noun === 'task' && action === 'review-packet') {
975
+ return workflow.prepareExternalTaskReview(
976
+ repo,
977
+ required(args, 'id'),
978
+ revision(args),
979
+ reviewMode(args),
980
+ );
981
+ }
982
+ if (noun === 'task' && action === 'review-sealed-record') {
983
+ return workflow.recordExternalTaskReview(
984
+ repo,
985
+ required(args, 'id'),
986
+ revision(args),
987
+ jsonFile<ExternalStrictTaskReviewInput>(args),
988
+ required(args, 'actor'),
989
+ credentialToken(workflow, repo, args, 'writer-lease', 'task review-sealed-record', required(args, 'id'), required(args, 'actor'), false),
990
+ );
991
+ }
992
+ if (noun === 'task' && action === 'step-review') {
993
+ // Strict Step Review launches and records the isolated reviewer inside Core. CLI --actor
994
+ // remains the lifecycle actor from next, typically the active C1 claimant.
995
+ return workflow.reviewStep(
996
+ repo,
997
+ required(args, 'id'),
998
+ required(args, 'step'),
999
+ revision(args),
1000
+ undefined,
1001
+ option(args, 'actor'),
1002
+ credentialToken(workflow, repo, args, 'writer-lease', 'task step-review', required(args, 'id'), option(args, 'actor') ?? null, false),
1003
+ );
1004
+ }
1005
+ if (noun === 'task' && action === 'step-review-packet') {
1006
+ return workflow.prepareExternalStepReview(
1007
+ repo,
1008
+ required(args, 'id'),
1009
+ required(args, 'step'),
1010
+ revision(args),
1011
+ reviewMode(args),
1012
+ );
1013
+ }
1014
+ if (noun === 'task' && action === 'step-review-record') {
1015
+ return workflow.recordExternalStepReview(
1016
+ repo,
1017
+ required(args, 'id'),
1018
+ required(args, 'step'),
1019
+ revision(args),
1020
+ jsonFile<ExternalStrictStepReviewInput>(args),
1021
+ required(args, 'actor'),
1022
+ credentialToken(workflow, repo, args, 'writer-lease', 'task step-review-record', required(args, 'id'), required(args, 'actor'), false),
1023
+ );
1024
+ }
1025
+ if (noun === 'task' && action === 'corrective-decision-recover') {
1026
+ const taskId = required(args, 'id');
1027
+ const actor = required(args, 'actor');
1028
+ return workflow.recoverStepCorrectiveDecision(
1029
+ repo,
1030
+ taskId,
1031
+ required(args, 'step'),
1032
+ revision(args),
1033
+ actor,
1034
+ credentialToken(workflow, repo, args, 'writer-lease', 'task corrective-decision-recover', taskId, actor, false),
1035
+ );
1036
+ }
1037
+ if (noun === 'task' && action === 'plan-integrity-recover') {
1038
+ const taskId = required(args, 'id');
1039
+ const actor = required(args, 'actor');
1040
+ return workflow.recoverPlanIntegrity(
1041
+ repo,
1042
+ taskId,
1043
+ required(args, 'step'),
1044
+ revision(args),
1045
+ actor,
1046
+ credentialToken(workflow, repo, args, 'writer-lease', 'task plan-integrity-recover', taskId, actor, false),
1047
+ );
1048
+ }
1049
+ if (noun === 'task' && action === 'downstream-proof-recover') {
1050
+ const taskId = required(args, 'id');
1051
+ const actor = required(args, 'actor');
1052
+ return workflow.recoverDownstreamProof(
1053
+ repo,
1054
+ taskId,
1055
+ revision(args),
1056
+ actor,
1057
+ credentialToken(workflow, repo, args, 'writer-lease', 'task downstream-proof-recover', taskId, actor, true)!,
1058
+ required(args, 'reason'),
1059
+ );
1060
+ }
1061
+ if (noun === 'task' && action === 'corrective-decision') {
1062
+ const taskId = required(args, 'id');
1063
+ return workflow.recordStepCorrectiveDecision(
1064
+ repo,
1065
+ taskId,
1066
+ required(args, 'step'),
1067
+ revision(args),
1068
+ jsonFile<CorrectivePlanAuditInput>(args),
1069
+ option(args, 'actor'),
1070
+ credentialToken(workflow, repo, args, 'writer-lease', 'task corrective-decision', taskId, option(args, 'actor') ?? null, false),
1071
+ );
1072
+ }
1073
+ if (noun === 'task' && action === 'corrective-yield') {
1074
+ const taskId = required(args, 'id');
1075
+ const actor = required(args, 'actor');
1076
+ const outcome = workflow.executeCorrectiveYield(
1077
+ repo,
1078
+ taskId,
1079
+ revision(args),
1080
+ actor,
1081
+ credentialToken(workflow, repo, args, 'writer-lease', 'task corrective-yield', taskId, actor, true)!,
1082
+ required(args, 'reason'),
1083
+ );
1084
+ consumeCredentialOption(workflow, repo, args, 'writer-credential-ref');
1085
+ return outcome;
1086
+ }
1087
+ if (noun === 'task' && action === 'corrective-yield-recover') {
1088
+ return workflow.recoverCorrectiveYield(repo, required(args, 'id'), required(args, 'transaction-id'));
1089
+ }
1090
+ if (noun === 'task' && action === 'corrective-replan-prepare') {
1091
+ return workflow.prepareCorrectiveReplan(
1092
+ repo,
1093
+ required(args, 'id'),
1094
+ jsonFile<CorrectiveReplanPublicCandidate>(args),
1095
+ );
1096
+ }
1097
+ if (noun === 'task' && action === 'corrective-replan-confirm') {
1098
+ return workflow.confirmCorrectiveReplan(
1099
+ repo,
1100
+ required(args, 'id'),
1101
+ jsonFile<CorrectiveReplanPublicCandidate>(args),
1102
+ jsonFile<CorrectiveReplanHumanGate>(args, 'gate-file'),
1103
+ required(args, 'confirmation-code'),
1104
+ );
1105
+ }
1106
+ if (noun === 'task' && action === 'corrective-replan-execute') {
1107
+ return workflow.executeCorrectiveReplan(
1108
+ repo,
1109
+ required(args, 'id'),
1110
+ jsonFile<CorrectiveReplanPublicCandidate>(args),
1111
+ jsonFile<CorrectiveReplanPublicCredential>(args, 'credential-file'),
1112
+ );
1113
+ }
1114
+ if (noun === 'task' && action === 'corrective-replan-recover') {
1115
+ return workflow.recoverCorrectiveReplan(repo, required(args, 'id'), required(args, 'transaction-id'));
1116
+ }
1117
+ if (noun === 'task' && (action === 'handoff' || action === 'handoff-prepare' || action === 'handoff-replace')) {
1118
+ const replacePending = action === 'handoff-replace';
1119
+ const taskId = required(args, 'id');
1120
+ const actor = required(args, 'actor');
1121
+ const targetActor = replacePending
1122
+ ? required(args, 'target-actor')
1123
+ : option(args, 'target-actor') ?? defaultTaskWorkerActor(taskId);
1124
+ const outcome = workflow.handoffTask(
1125
+ repo,
1126
+ taskId,
1127
+ revision(args),
1128
+ actor,
1129
+ targetActor,
1130
+ required(args, 'reason'),
1131
+ credentialToken(workflow, repo, args, 'writer-lease', `task ${action}`, taskId, actor, false),
1132
+ option(args, 'delegation-grant') ?? null,
1133
+ option(args, 'expires-at') ?? null,
1134
+ replacePending,
1135
+ );
1136
+ consumeCredentialOption(workflow, repo, args, 'writer-credential-ref');
1137
+ const { claimToken, ...bundle } = outcome.bundle;
1138
+ const identity = resolveRepositoryIdentity(repo);
1139
+ return {
1140
+ claimCredentialReference: issueCredentialReference({
1141
+ stateRoot: workflow.store.root,
1142
+ projectId: identity.projectId,
1143
+ entityId: taskId,
1144
+ actor: outcome.bundle.delegate,
1145
+ kind: 'claim-token',
1146
+ token: claimToken,
1147
+ allowedActions: ['task claim'],
1148
+ expiresAt: outcome.bundle.expiresAt,
1149
+ oneTime: true,
1150
+ }),
1151
+ task: outcome.task,
1152
+ event: outcome.event,
1153
+ bundle,
1154
+ };
1155
+ }
1156
+ if (noun === 'task' && action === 'handoff-show') {
1157
+ return workflow.showTaskHandoff(repo, required(args, 'id'));
1158
+ }
1159
+ if (noun === 'task' && action === 'claim') {
1160
+ const taskId = required(args, 'id');
1161
+ const actor = required(args, 'actor');
1162
+ const claimToken = credentialToken(
1163
+ workflow, repo, args, 'claim-token', 'task claim', taskId, actor, true,
1164
+ )!;
1165
+ const outcome = workflow.claimTask(
1166
+ repo,
1167
+ taskId,
1168
+ revision(args),
1169
+ actor,
1170
+ claimToken,
1171
+ credentialToken(workflow, repo, args, 'writer-lease', 'task claim', taskId, actor, false),
1172
+ );
1173
+ consumeCredentialOption(workflow, repo, args, 'claim-credential-ref');
1174
+ return {
1175
+ writerCredential: { disposition: outcome.writerCredential.disposition },
1176
+ ...(outcome.writerCredential.disposition === 'issued' ? {
1177
+ writerCredentialReference: writerCredentialReceipt(
1178
+ workflow, repo, taskId, outcome.lease.owner, outcome.writerCredential.token, outcome.lease.expiresAt,
1179
+ ),
1180
+ } : {}),
1181
+ task: outcome.task,
1182
+ event: outcome.event,
1183
+ lease: outcome.lease,
1184
+ };
1185
+ }
1186
+ if (noun === 'task' && action === 'writer-credential-replace') {
1187
+ const taskId = required(args, 'id');
1188
+ const actor = required(args, 'actor');
1189
+ const outcome = workflow.replaceClaimedWriterCredential(
1190
+ repo,
1191
+ taskId,
1192
+ revision(args),
1193
+ actor,
1194
+ );
1195
+ return {
1196
+ writerCredential: { disposition: outcome.writerCredential.disposition },
1197
+ writerCredentialReference: writerCredentialReceipt(
1198
+ workflow, repo, taskId, outcome.lease.owner, outcome.writerCredential.token, outcome.lease.expiresAt,
1199
+ ),
1200
+ task: outcome.task,
1201
+ lease: outcome.lease,
1202
+ };
1203
+ }
1204
+ if (noun === 'task' && (action === 'handback' || action === 'handback-create')) {
1205
+ const taskId = required(args, 'id');
1206
+ const actor = required(args, 'actor');
1207
+ const outcome = workflow.handbackTask(
1208
+ repo,
1209
+ taskId,
1210
+ revision(args),
1211
+ actor,
1212
+ required(args, 'reason'),
1213
+ credentialToken(workflow, repo, args, 'writer-lease', `task ${action}`, taskId, actor, false),
1214
+ repeated(args, 'limitation'),
1215
+ action === 'handback-create'
1216
+ ? required(args, 'recommended-next')
1217
+ : option(args, 'recommended-next') ?? 'Coordinator reviews the terminal Task result and recorded evidence.',
1218
+ );
1219
+ consumeCredentialOption(workflow, repo, args, 'writer-credential-ref');
1220
+ return outcome;
1221
+ }
1222
+ if (noun === 'task' && action === 'result-set') {
1223
+ const taskId = required(args, 'id');
1224
+ const outcome = workflow.setTaskResult(
1225
+ repo,
1226
+ taskId,
1227
+ revision(args),
1228
+ required(args, 'summary'),
1229
+ repeated(args, 'limitation'),
1230
+ credentialToken(workflow, repo, args, 'writer-lease', 'task result-set', taskId, option(args, 'actor') ?? null, true)!,
1231
+ option(args, 'actor'),
1232
+ );
1233
+ consumeCredentialOption(workflow, repo, args, 'writer-credential-ref');
1234
+ return outcome;
1235
+ }
1236
+ if (noun === 'task' && action === 'accept') {
1237
+ return workflow.acceptTask(
1238
+ repo,
1239
+ required(args, 'id'),
1240
+ revision(args),
1241
+ option(args, 'actor') ?? 'user',
1242
+ option(args, 'delegation-grant') ?? null,
1243
+ );
1244
+ }
1245
+ if (noun === 'task' && action === 'sync-base') {
1246
+ return workflow.syncTaskBase(repo, required(args, 'id'), revision(args));
1247
+ }
1248
+ if (noun === 'task' && action === 'merge') {
1249
+ const taskId = required(args, 'id');
1250
+ const outcome = workflow.mergeTask(
1251
+ repo,
1252
+ taskId,
1253
+ revision(args),
1254
+ credentialToken(workflow, repo, args, 'writer-lease', 'task merge', taskId, option(args, 'actor') ?? null, true)!,
1255
+ option(args, 'actor'),
1256
+ );
1257
+ consumeCredentialOption(workflow, repo, args, 'writer-credential-ref');
1258
+ return outcome;
1259
+ }
1260
+ if (noun === 'task' && action === 'merge-confirm') {
1261
+ const taskId = required(args, 'id');
1262
+ const outcome = workflow.confirmExternalMerge(
1263
+ repo,
1264
+ taskId,
1265
+ revision(args),
1266
+ credentialToken(workflow, repo, args, 'writer-lease', 'task merge-confirm', taskId, option(args, 'actor') ?? null, true)!,
1267
+ option(args, 'actor'),
1268
+ );
1269
+ consumeCredentialOption(workflow, repo, args, 'writer-credential-ref');
1270
+ return outcome;
1271
+ }
1272
+
1273
+ if (noun === 'milestone' && action === 'show') {
1274
+ const identity = resolveRepositoryIdentity(repo);
1275
+ return workflow.store.readMilestone(identity.projectId, required(args, 'id'));
1276
+ }
1277
+ if (noun === 'milestone' && action === 'progress') {
1278
+ return workflow.milestoneProgress(repo, required(args, 'id'));
1279
+ }
1280
+ if (noun === 'milestone' && action === 'plan-set') {
1281
+ return workflow.setMilestonePlan(repo, required(args, 'id'), revision(args), jsonFile<MilestonePlanInput>(args));
1282
+ }
1283
+ if (noun === 'milestone' && action === 'remediation-materialize') {
1284
+ return workflow.materializeAuditedRemediationTask(
1285
+ repo,
1286
+ required(args, 'id'),
1287
+ revision(args),
1288
+ required(args, 'task'),
1289
+ positiveIntegerOption(args, 'expected-task-revision'),
1290
+ jsonFile<AuditedRemediationMaterializationInput>(args),
1291
+ );
1292
+ }
1293
+ if (noun === 'milestone' && action === 'scope-change-prepare') {
1294
+ return workflow.prepareMilestoneScopeChange(
1295
+ repo,
1296
+ required(args, 'id'),
1297
+ revision(args),
1298
+ jsonFile<MilestonePlanInput>(args),
1299
+ required(args, 'actor'),
1300
+ );
1301
+ }
1302
+ if (noun === 'milestone' && action === 'scope-change-apply') {
1303
+ return workflow.applyMilestoneScopeChange(
1304
+ repo,
1305
+ required(args, 'id'),
1306
+ revision(args),
1307
+ jsonFile<MilestonePlanInput>(args),
1308
+ required(args, 'actor'),
1309
+ required(args, 'confirmation-code'),
1310
+ );
1311
+ }
1312
+ if (noun === 'milestone' && action === 'autonomy-prepare') {
1313
+ return workflow.prepareMilestoneAutonomy(
1314
+ repo,
1315
+ required(args, 'id'),
1316
+ revision(args),
1317
+ required(args, 'principal'),
1318
+ required(args, 'delegate'),
1319
+ required(args, 'expires-at'),
1320
+ );
1321
+ }
1322
+ if (noun === 'milestone' && action === 'autonomy-grant') {
1323
+ return workflow.grantMilestoneAutonomy(
1324
+ repo,
1325
+ required(args, 'id'),
1326
+ revision(args),
1327
+ required(args, 'principal'),
1328
+ required(args, 'delegate'),
1329
+ required(args, 'expires-at'),
1330
+ required(args, 'confirmation-code'),
1331
+ );
1332
+ }
1333
+ if (noun === 'milestone' && action === 'autonomy-evolve') {
1334
+ return workflow.evolveMilestonePlanAutonomously(
1335
+ repo,
1336
+ required(args, 'id'),
1337
+ revision(args),
1338
+ jsonFile<MilestonePlanInput>(args),
1339
+ required(args, 'actor'),
1340
+ );
1341
+ }
1342
+ if (noun === 'milestone' && action === 'authorize') {
1343
+ return workflow.authorizeMilestone(
1344
+ repo,
1345
+ required(args, 'id'),
1346
+ revision(args),
1347
+ option(args, 'actor') ?? 'user',
1348
+ option(args, 'reason') ?? '',
1349
+ option(args, 'delegation-grant') ?? null,
1350
+ );
1351
+ }
1352
+ if (noun === 'milestone' && action === 'validate') {
1353
+ return workflow.validateMilestone(repo, required(args, 'id'), revision(args));
1354
+ }
1355
+ if (noun === 'milestone' && action === 'accept') {
1356
+ return workflow.acceptMilestone(
1357
+ repo,
1358
+ required(args, 'id'),
1359
+ revision(args),
1360
+ required(args, 'actor'),
1361
+ required(args, 'confirmation-code'),
1362
+ option(args, 'delegation-grant') ?? null,
1363
+ );
1364
+ }
1365
+ if (noun === 'milestone' && action === 'cancel') {
1366
+ return workflow.cancelMilestone(repo, required(args, 'id'), revision(args), required(args, 'reason'));
1367
+ }
1368
+
1369
+ if (noun === 'locks' && (action === 'inspect' || action === 'repair')) {
1370
+ const id = required(args, 'id');
1371
+ if (action === 'repair') return workflow.repairStaleWriterLease(repo, id);
1372
+ const inspection = workflow.inspectWriterLease(repo, id);
1373
+ return inspection ? { ...inspection, repaired: false } : null;
1374
+ }
1375
+
1376
+ throw new WorkflowError('INVALID_ARGUMENT', 'Unknown command.', {
1377
+ command: args.positionals.join(' '),
1378
+ hint: 'Use doctor, status, next, update preflight, state <action>, delegation <action>, project-memory <action>, discovery <action>, task <action>, milestone <action>, or locks <action>.',
1379
+ });
1380
+ }
1381
+
1382
+ function credentialAllowancesForResult(
1383
+ _args: ParsedArguments,
1384
+ _value: unknown,
1385
+ ): [] {
1386
+ // Beta 13 has no CLI issuance allowance: the host receives reference metadata only.
1387
+ return [];
1388
+ }
1389
+
1390
+ function rawCredentialInputs(argv: readonly string[]): string[] {
1391
+ const values: string[] = [];
1392
+ for (let index = 0; index < argv.length; index += 1) {
1393
+ const argument = argv[index]!;
1394
+ for (const optionName of ['--writer-token', '--claim-token', '--confirmation-code']) {
1395
+ if (argument === optionName && argv[index + 1]) values.push(argv[index + 1]!);
1396
+ if (argument.startsWith(`${optionName}=`)) values.push(argument.slice(optionName.length + 1));
1397
+ }
1398
+ }
1399
+ return [...new Set(values.filter(Boolean))];
1400
+ }
1401
+
1402
+ function isRecord(value: unknown): value is Record<string, unknown> {
1403
+ return typeof value === 'object' && value !== null;
1404
+ }
1405
+
1406
+ async function main(): Promise<void> {
1407
+ const argv = process.argv.slice(2);
1408
+ const sensitiveInputs = rawCredentialInputs(argv);
1409
+ try {
1410
+ const args = parseArguments(argv);
1411
+ assertNoLegacyCredentialArguments(new Set(args.options.keys()));
1412
+ const value = await dispatch(args);
1413
+ assertCliSuccessCredentialSafety(value, credentialAllowancesForResult(args, value), sensitiveInputs);
1414
+ process.stdout.write(`${JSON.stringify({ ok: true, value }, null, 2)}\n`);
1415
+ } catch (error) {
1416
+ if (error instanceof UnsafeCredentialOutputError) {
1417
+ process.stderr.write(
1418
+ `${JSON.stringify({
1419
+ ok: false,
1420
+ error: {
1421
+ code: 'STATE_CORRUPT',
1422
+ message: error.message,
1423
+ details: { credentialPaths: error.paths },
1424
+ },
1425
+ }, null, 2)}\n`,
1426
+ );
1427
+ process.exitCode = 2;
1428
+ return;
1429
+ }
1430
+ if (error instanceof WorkflowError) {
1431
+ process.stderr.write(
1432
+ `${JSON.stringify({
1433
+ ok: false,
1434
+ error: {
1435
+ code: error.code,
1436
+ message: projectCliErrorMessage(error.message, sensitiveInputs),
1437
+ details: projectCliErrorValue(error.details, sensitiveInputs),
1438
+ },
1439
+ }, null, 2)}\n`,
1440
+ );
1441
+ process.exitCode = 2;
1442
+ return;
1443
+ }
1444
+ process.stderr.write(
1445
+ `${JSON.stringify({
1446
+ ok: false,
1447
+ error: {
1448
+ code: 'UNEXPECTED',
1449
+ message: projectCliErrorMessage(error instanceof Error ? error.message : String(error), sensitiveInputs),
1450
+ },
1451
+ }, null, 2)}\n`,
1452
+ );
1453
+ process.exitCode = 1;
1454
+ }
1455
+ }
1456
+
1457
+ await main();