codex-workflow-v2 2.0.0-beta.13.9 → 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 (271) hide show
  1. package/README.md +27 -388
  2. package/dist/reviewer-runtime-build.json +89 -29
  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/literal-test-invocation.d.ts +2 -0
  19. package/dist/src/alpha6/literal-test-invocation.js +106 -0
  20. package/dist/src/alpha6/literal-test-invocation.js.map +1 -0
  21. package/dist/src/alpha6/milestone.d.ts +2 -0
  22. package/dist/src/alpha6/milestone.js +10 -1
  23. package/dist/src/alpha6/milestone.js.map +1 -1
  24. package/dist/src/alpha6/navigation-dirty-carryover.d.ts +11 -0
  25. package/dist/src/alpha6/navigation-dirty-carryover.js +130 -0
  26. package/dist/src/alpha6/navigation-dirty-carryover.js.map +1 -0
  27. package/dist/src/alpha6/plan-integrity.js +7 -5
  28. package/dist/src/alpha6/plan-integrity.js.map +1 -1
  29. package/dist/src/alpha6/remediation.d.ts +6 -21
  30. package/dist/src/alpha6/remediation.js +161 -476
  31. package/dist/src/alpha6/remediation.js.map +1 -1
  32. package/dist/src/alpha6/root-cause-replan-carryover.d.ts +4 -1
  33. package/dist/src/alpha6/root-cause-replan-carryover.js +29 -5
  34. package/dist/src/alpha6/root-cause-replan-carryover.js.map +1 -1
  35. package/dist/src/beta1/project-transaction.d.ts +3 -1
  36. package/dist/src/beta1/project-transaction.js +6 -2
  37. package/dist/src/beta1/project-transaction.js.map +1 -1
  38. package/dist/src/checks/runner.d.ts +26 -0
  39. package/dist/src/checks/runner.js +223 -0
  40. package/dist/src/checks/runner.js.map +1 -0
  41. package/dist/src/checks/task-sync.d.ts +10 -0
  42. package/dist/src/checks/task-sync.js +41 -0
  43. package/dist/src/checks/task-sync.js.map +1 -0
  44. package/dist/src/checks/worker.d.ts +1 -0
  45. package/dist/src/checks/worker.js +154 -0
  46. package/dist/src/checks/worker.js.map +1 -0
  47. package/dist/src/cli-actions.d.ts +2 -2
  48. package/dist/src/cli-actions.js +3 -15
  49. package/dist/src/cli-actions.js.map +1 -1
  50. package/dist/src/cli.js +14 -98
  51. package/dist/src/cli.js.map +1 -1
  52. package/dist/src/contracts.d.ts +35 -32
  53. package/dist/src/dependency-provenance.d.ts +2 -2
  54. package/dist/src/dependency-provenance.js +12 -69
  55. package/dist/src/dependency-provenance.js.map +1 -1
  56. package/dist/src/domain/base-sync-conflict.d.ts +13 -0
  57. package/dist/src/domain/base-sync-conflict.js +32 -0
  58. package/dist/src/domain/base-sync-conflict.js.map +1 -0
  59. package/dist/src/domain/step-start-admission.d.ts +4 -0
  60. package/dist/src/domain/step-start-admission.js +9 -0
  61. package/dist/src/domain/step-start-admission.js.map +1 -0
  62. package/dist/src/domain/virgin-registration.d.ts +3 -0
  63. package/dist/src/domain/virgin-registration.js +65 -0
  64. package/dist/src/domain/virgin-registration.js.map +1 -0
  65. package/dist/src/errors.d.ts +1 -1
  66. package/dist/src/errors.js.map +1 -1
  67. package/dist/src/gateway-handshake.js +0 -8
  68. package/dist/src/gateway-handshake.js.map +1 -1
  69. package/dist/src/git.d.ts +3 -1
  70. package/dist/src/git.js +41 -14
  71. package/dist/src/git.js.map +1 -1
  72. package/dist/src/graph.js +25 -3
  73. package/dist/src/graph.js.map +1 -1
  74. package/dist/src/index.d.ts +1 -0
  75. package/dist/src/navigation-actions.d.ts +9 -0
  76. package/dist/src/navigation-actions.js +72 -0
  77. package/dist/src/navigation-actions.js.map +1 -0
  78. package/dist/src/navigation-update-artifact.d.ts +5 -0
  79. package/dist/src/navigation-update-artifact.js +227 -0
  80. package/dist/src/navigation-update-artifact.js.map +1 -0
  81. package/dist/src/navigation-update.d.ts +39 -0
  82. package/dist/src/navigation-update.js +82 -0
  83. package/dist/src/navigation-update.js.map +1 -0
  84. package/dist/src/observation.js +52 -29
  85. package/dist/src/observation.js.map +1 -1
  86. package/dist/src/observed-routes.js +5 -6
  87. package/dist/src/observed-routes.js.map +1 -1
  88. package/dist/src/pending-review-update.d.ts +0 -13
  89. package/dist/src/pending-review-update.js +1 -6
  90. package/dist/src/pending-review-update.js.map +1 -1
  91. package/dist/src/reviewer.d.ts +1 -1
  92. package/dist/src/reviewer.js +20 -17
  93. package/dist/src/reviewer.js.map +1 -1
  94. package/dist/src/runtime.d.ts +3 -0
  95. package/dist/src/runtime.js +6 -0
  96. package/dist/src/runtime.js.map +1 -0
  97. package/dist/src/state/corrective-replan-executor.d.ts +10 -0
  98. package/dist/src/state/corrective-replan-executor.js +37 -1
  99. package/dist/src/state/corrective-replan-executor.js.map +1 -1
  100. package/dist/src/state/corrective-replan-public-schema.js +15 -2
  101. package/dist/src/state/corrective-replan-public-schema.js.map +1 -1
  102. package/dist/src/state/corrective-replan-public.js +1 -1
  103. package/dist/src/state/corrective-replan-public.js.map +1 -1
  104. package/dist/src/state/corrective-replan-transaction.d.ts +1 -0
  105. package/dist/src/state/corrective-replan-transaction.js +12 -11
  106. package/dist/src/state/corrective-replan-transaction.js.map +1 -1
  107. package/dist/src/state/corrective-yield-transaction.d.ts +1 -0
  108. package/dist/src/state/corrective-yield-transaction.js +11 -10
  109. package/dist/src/state/corrective-yield-transaction.js.map +1 -1
  110. package/dist/src/state/lock.d.ts +4 -0
  111. package/dist/src/state/lock.js +21 -0
  112. package/dist/src/state/lock.js.map +1 -1
  113. package/dist/src/version.d.ts +1 -1
  114. package/dist/src/version.js +1 -1
  115. package/dist/src/version.js.map +1 -1
  116. package/dist/src/workflow-blocker-route.d.ts +8 -0
  117. package/dist/src/workflow-blocker-route.js +106 -0
  118. package/dist/src/workflow-blocker-route.js.map +1 -0
  119. package/dist/src/workflow.d.ts +48 -63
  120. package/dist/src/workflow.js +666 -1460
  121. package/dist/src/workflow.js.map +1 -1
  122. package/docs/autonomy-guardrails.md +26 -304
  123. package/docs/decisions.md +14 -112
  124. package/docs/development-flow.md +35 -238
  125. package/docs/project-memory.md +31 -50
  126. package/docs/release-app-evidence.md +190 -0
  127. package/docs/release.md +95 -388
  128. package/docs/updating-existing-project.md +19 -717
  129. package/package.json +11 -13
  130. package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +2 -2
  131. package/plugins/codex-workflow-gateway/references/chat-dispatch.md +73 -197
  132. package/plugins/codex-workflow-gateway/references/codebase-memory-routing.md +57 -0
  133. package/plugins/codex-workflow-gateway/references/protocol.md +42 -445
  134. package/plugins/codex-workflow-gateway/scripts/chat-dispatch.mjs +7 -1
  135. package/plugins/codex-workflow-gateway/scripts/chat-model-policy.mjs +10 -8
  136. package/plugins/codex-workflow-gateway/scripts/chat-registry.mjs +23 -5
  137. package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +66 -757
  138. package/references/state-machine.md +4 -4
  139. package/roles/technical-planner.md +1 -1
  140. package/schemas/corrective-decision-event.schema.json +3 -1
  141. package/schemas/project-knowledge-map.schema.json +3 -1
  142. package/schemas/remediation-event.schema.json +10 -1
  143. package/schemas/task.schema.json +46 -2
  144. package/schemas/transition-payloads.schema.json +16 -1
  145. package/src/alpha6/adoption.ts +1123 -0
  146. package/src/alpha6/captured-check-evidence.ts +132 -0
  147. package/src/alpha6/check-support-anchor.ts +128 -0
  148. package/src/alpha6/component-owner.ts +168 -0
  149. package/src/alpha6/corrective-decision-boundary.ts +39 -0
  150. package/src/alpha6/downstream-proof.ts +520 -0
  151. package/src/alpha6/failed-step-planning-recovery.ts +88 -0
  152. package/src/alpha6/handoff.ts +1443 -0
  153. package/src/alpha6/journal.ts +473 -0
  154. package/src/alpha6/literal-test-invocation.ts +84 -0
  155. package/src/alpha6/mechanical-feasibility.ts +488 -0
  156. package/src/alpha6/milestone.ts +2192 -0
  157. package/src/alpha6/navigation-dirty-carryover.ts +154 -0
  158. package/src/alpha6/npm-check-contract.ts +47 -0
  159. package/src/alpha6/plan-integrity.ts +298 -0
  160. package/src/alpha6/plan-risk.ts +1480 -0
  161. package/src/alpha6/preexecution-replan.ts +187 -0
  162. package/src/alpha6/remediation-cause.ts +98 -0
  163. package/src/alpha6/remediation.ts +2438 -0
  164. package/src/alpha6/review.ts +1198 -0
  165. package/src/alpha6/root-cause-replan-carryover.ts +491 -0
  166. package/src/alpha6/store-sidecars.ts +335 -0
  167. package/src/alpha7/autonomy.ts +411 -0
  168. package/src/alpha7/corrective-recovery.ts +1332 -0
  169. package/src/artifacts.ts +130 -0
  170. package/src/beta1/project-transaction.ts +355 -0
  171. package/src/change-explanation.ts +153 -0
  172. package/src/checks/runner.ts +245 -0
  173. package/src/checks/task-sync.ts +41 -0
  174. package/src/checks/worker.ts +149 -0
  175. package/src/cli-actions.ts +107 -0
  176. package/src/cli.ts +1457 -0
  177. package/src/contracts.ts +1494 -0
  178. package/src/credential-output.ts +89 -0
  179. package/src/credential-transport.ts +215 -0
  180. package/src/delegation.ts +190 -0
  181. package/src/dependency-provenance.ts +472 -0
  182. package/src/diagnostics.ts +93 -0
  183. package/src/domain/base-sync-conflict.ts +35 -0
  184. package/src/domain/completed-step-carryover.ts +76 -0
  185. package/src/domain/discovery.ts +27 -0
  186. package/src/domain/plan-semantics.ts +58 -0
  187. package/src/domain/step-start-admission.ts +10 -0
  188. package/src/domain/validation.ts +177 -0
  189. package/src/domain/virgin-registration.ts +46 -0
  190. package/src/errors.ts +24 -0
  191. package/src/fs-utils.ts +61 -0
  192. package/src/gateway-handshake.ts +95 -0
  193. package/src/git.ts +183 -0
  194. package/src/graph.ts +342 -0
  195. package/src/historical-step-provenance.ts +136 -0
  196. package/src/index.ts +23 -0
  197. package/src/lifecycle/canonical-hash.ts +28 -0
  198. package/src/lifecycle/catalog.ts +202 -0
  199. package/src/lifecycle/compiler-inspection.ts +29 -0
  200. package/src/lifecycle/core-static-readiness.ts +132 -0
  201. package/src/lifecycle/corrective-replan-authority.ts +136 -0
  202. package/src/lifecycle/corrective-replan-binding-manifest.ts +51 -0
  203. package/src/lifecycle/corrective-replan-credential-core.ts +408 -0
  204. package/src/lifecycle/corrective-replan-credential-schema.ts +54 -0
  205. package/src/lifecycle/corrective-replan-credentials.ts +48 -0
  206. package/src/lifecycle/corrective-replan.ts +843 -0
  207. package/src/lifecycle/evaluator.ts +48 -0
  208. package/src/lifecycle/fingerprint.ts +488 -0
  209. package/src/lifecycle/immutable.ts +8 -0
  210. package/src/lifecycle/implementation-table.ts +118 -0
  211. package/src/lifecycle/index.ts +8 -0
  212. package/src/lifecycle/schema-artifact.ts +263 -0
  213. package/src/lifecycle/semantic-registry.ts +572 -0
  214. package/src/lifecycle/types.ts +838 -0
  215. package/src/memory.ts +273 -0
  216. package/src/migration.ts +161 -0
  217. package/src/navigation-actions.ts +70 -0
  218. package/src/navigation-update-artifact.ts +198 -0
  219. package/src/navigation-update.ts +121 -0
  220. package/src/observation.ts +225 -0
  221. package/src/observed-routes.ts +660 -0
  222. package/src/operational-contract.ts +125 -0
  223. package/src/pending-review-update.ts +175 -0
  224. package/src/repository.ts +99 -0
  225. package/src/reviewer.ts +1879 -0
  226. package/src/runtime.ts +6 -0
  227. package/src/state/corrective-replan-executor.ts +818 -0
  228. package/src/state/corrective-replan-public-schema.ts +83 -0
  229. package/src/state/corrective-replan-public.ts +908 -0
  230. package/src/state/corrective-replan-transaction.ts +949 -0
  231. package/src/state/corrective-yield-executor.ts +327 -0
  232. package/src/state/corrective-yield-transaction.ts +730 -0
  233. package/src/state/lock.ts +902 -0
  234. package/src/state/store.ts +567 -0
  235. package/src/transition-core.ts +330 -0
  236. package/src/ulid.ts +24 -0
  237. package/src/version.ts +2 -0
  238. package/src/workflow-blocker-route.ts +109 -0
  239. package/src/workflow.ts +10172 -0
  240. package/docs/alpha7.1-implementation-brief.md +0 -268
  241. package/docs/alpha7.2-corrective-context-refresh-brief.md +0 -484
  242. package/docs/alpha7.2.1-remediation-recovery-brief.md +0 -86
  243. package/docs/beta1-stabilization-brief.md +0 -165
  244. package/docs/beta11-plan-integrity-recovery-brief.md +0 -38
  245. package/docs/beta13.2-signal-review-recovery.md +0 -38
  246. package/docs/beta2-initial-assembly-navigation-brief.md +0 -616
  247. package/docs/change-model.md +0 -118
  248. package/docs/delegated-approval.md +0 -254
  249. package/docs/lifecycle/state-machine-stabilization.md +0 -641
  250. package/docs/pdf/README.md +0 -24
  251. package/docs/pdf/codex-workflow-v2-architecture-ru.pdf +0 -0
  252. package/docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf +0 -0
  253. package/docs/pdf/codex-workflow-v2-technical-reference-ru.pdf +0 -0
  254. package/docs/pdf/requirements.txt +0 -1
  255. package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +0 -478
  256. package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +0 -506
  257. package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +0 -778
  258. package/docs/pending-review-update.md +0 -15
  259. package/docs/problem-briefs/01-pre-implementation-integrity.md +0 -482
  260. package/docs/problem-briefs/02-minimal-step-integrity.md +0 -411
  261. package/docs/problem-briefs/03-minimal-agent-context-integrity.md +0 -358
  262. package/docs/problem-briefs/04-task-dependency-and-structural-replacement-integrity.md +0 -573
  263. package/docs/problem-briefs/BRIEF-TEMPLATE.md +0 -56
  264. package/docs/problem-briefs/README.md +0 -120
  265. package/docs/problem-briefs/evidence/p01-mechanical-feasibility-corpus.md +0 -90
  266. package/docs/problem-briefs/evidence/signal-v4-pre-m3-replay.md +0 -246
  267. package/docs/split-required-recovery.md +0 -47
  268. package/docs/stable-release-defect-register.md +0 -730
  269. package/docs/validation-report.md +0 -182
  270. package/scripts/generate-pdf-docs.py +0 -524
  271. 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();