codex-workflow-v2 2.0.0-beta.1 → 2.0.0-beta.4

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 (139) hide show
  1. package/README.md +47 -3
  2. package/dist/src/alpha6/adoption.js +13 -3
  3. package/dist/src/alpha6/adoption.js.map +1 -1
  4. package/dist/src/alpha6/handoff.d.ts +21 -0
  5. package/dist/src/alpha6/handoff.js +100 -19
  6. package/dist/src/alpha6/handoff.js.map +1 -1
  7. package/dist/src/alpha6/milestone.d.ts +12 -0
  8. package/dist/src/alpha6/milestone.js +113 -1
  9. package/dist/src/alpha6/milestone.js.map +1 -1
  10. package/dist/src/alpha6/plan-risk.d.ts +1 -0
  11. package/dist/src/alpha6/plan-risk.js +6 -0
  12. package/dist/src/alpha6/plan-risk.js.map +1 -1
  13. package/dist/src/cli.js +383 -43
  14. package/dist/src/cli.js.map +1 -1
  15. package/dist/src/contracts.d.ts +111 -5
  16. package/dist/src/contracts.js +1 -1
  17. package/dist/src/credential-output.d.ts +10 -0
  18. package/dist/src/credential-output.js +73 -0
  19. package/dist/src/credential-output.js.map +1 -0
  20. package/dist/src/errors.d.ts +1 -1
  21. package/dist/src/errors.js.map +1 -1
  22. package/dist/src/index.d.ts +1 -1
  23. package/dist/src/index.js +1 -1
  24. package/dist/src/index.js.map +1 -1
  25. package/dist/src/lifecycle/canonical-hash.d.ts +6 -0
  26. package/dist/src/lifecycle/canonical-hash.js +24 -0
  27. package/dist/src/lifecycle/canonical-hash.js.map +1 -0
  28. package/dist/src/lifecycle/catalog.d.ts +26 -0
  29. package/dist/src/lifecycle/catalog.js +208 -0
  30. package/dist/src/lifecycle/catalog.js.map +1 -0
  31. package/dist/src/lifecycle/compiler-inspection.d.ts +48 -0
  32. package/dist/src/lifecycle/compiler-inspection.js +29 -0
  33. package/dist/src/lifecycle/compiler-inspection.js.map +1 -0
  34. package/dist/src/lifecycle/core-static-readiness.d.ts +6 -0
  35. package/dist/src/lifecycle/core-static-readiness.js +130 -0
  36. package/dist/src/lifecycle/core-static-readiness.js.map +1 -0
  37. package/dist/src/lifecycle/corrective-replan-authority.d.ts +53 -0
  38. package/dist/src/lifecycle/corrective-replan-authority.js +139 -0
  39. package/dist/src/lifecycle/corrective-replan-authority.js.map +1 -0
  40. package/dist/src/lifecycle/corrective-replan-binding-manifest.d.ts +21 -0
  41. package/dist/src/lifecycle/corrective-replan-binding-manifest.js +35 -0
  42. package/dist/src/lifecycle/corrective-replan-binding-manifest.js.map +1 -0
  43. package/dist/src/lifecycle/corrective-replan-credential-core.d.ts +86 -0
  44. package/dist/src/lifecycle/corrective-replan-credential-core.js +534 -0
  45. package/dist/src/lifecycle/corrective-replan-credential-core.js.map +1 -0
  46. package/dist/src/lifecycle/corrective-replan-credential-schema.d.ts +17 -0
  47. package/dist/src/lifecycle/corrective-replan-credential-schema.js +44 -0
  48. package/dist/src/lifecycle/corrective-replan-credential-schema.js.map +1 -0
  49. package/dist/src/lifecycle/corrective-replan-credentials.d.ts +47 -0
  50. package/dist/src/lifecycle/corrective-replan-credentials.js +103 -0
  51. package/dist/src/lifecycle/corrective-replan-credentials.js.map +1 -0
  52. package/dist/src/lifecycle/corrective-replan.d.ts +64 -0
  53. package/dist/src/lifecycle/corrective-replan.js +548 -0
  54. package/dist/src/lifecycle/corrective-replan.js.map +1 -0
  55. package/dist/src/lifecycle/evaluator.d.ts +2 -0
  56. package/dist/src/lifecycle/evaluator.js +35 -0
  57. package/dist/src/lifecycle/evaluator.js.map +1 -0
  58. package/dist/src/lifecycle/fingerprint.d.ts +31 -0
  59. package/dist/src/lifecycle/fingerprint.js +388 -0
  60. package/dist/src/lifecycle/fingerprint.js.map +1 -0
  61. package/dist/src/lifecycle/immutable.d.ts +1 -0
  62. package/dist/src/lifecycle/immutable.js +10 -0
  63. package/dist/src/lifecycle/immutable.js.map +1 -0
  64. package/dist/src/lifecycle/implementation-table.d.ts +29 -0
  65. package/dist/src/lifecycle/implementation-table.js +87 -0
  66. package/dist/src/lifecycle/implementation-table.js.map +1 -0
  67. package/dist/src/lifecycle/index.d.ts +4 -0
  68. package/dist/src/lifecycle/index.js +5 -0
  69. package/dist/src/lifecycle/index.js.map +1 -0
  70. package/dist/src/lifecycle/schema-artifact.d.ts +12 -0
  71. package/dist/src/lifecycle/schema-artifact.js +214 -0
  72. package/dist/src/lifecycle/schema-artifact.js.map +1 -0
  73. package/dist/src/lifecycle/semantic-registry.d.ts +6 -0
  74. package/dist/src/lifecycle/semantic-registry.js +489 -0
  75. package/dist/src/lifecycle/semantic-registry.js.map +1 -0
  76. package/dist/src/lifecycle/types.d.ts +718 -0
  77. package/dist/src/lifecycle/types.js +4 -0
  78. package/dist/src/lifecycle/types.js.map +1 -0
  79. package/dist/src/observation.d.ts +20 -0
  80. package/dist/src/observation.js +171 -0
  81. package/dist/src/observation.js.map +1 -0
  82. package/dist/src/reviewer.d.ts +4 -0
  83. package/dist/src/reviewer.js +24 -7
  84. package/dist/src/reviewer.js.map +1 -1
  85. package/dist/src/state/corrective-replan-executor.d.ts +64 -0
  86. package/dist/src/state/corrective-replan-executor.js +598 -0
  87. package/dist/src/state/corrective-replan-executor.js.map +1 -0
  88. package/dist/src/state/corrective-replan-public-schema.d.ts +3 -0
  89. package/dist/src/state/corrective-replan-public-schema.js +43 -0
  90. package/dist/src/state/corrective-replan-public-schema.js.map +1 -0
  91. package/dist/src/state/corrective-replan-public.d.ts +95 -0
  92. package/dist/src/state/corrective-replan-public.js +618 -0
  93. package/dist/src/state/corrective-replan-public.js.map +1 -0
  94. package/dist/src/state/corrective-replan-transaction.d.ts +158 -0
  95. package/dist/src/state/corrective-replan-transaction.js +723 -0
  96. package/dist/src/state/corrective-replan-transaction.js.map +1 -0
  97. package/dist/src/state/corrective-yield-executor.d.ts +31 -0
  98. package/dist/src/state/corrective-yield-executor.js +236 -0
  99. package/dist/src/state/corrective-yield-executor.js.map +1 -0
  100. package/dist/src/state/corrective-yield-transaction.d.ts +97 -0
  101. package/dist/src/state/corrective-yield-transaction.js +591 -0
  102. package/dist/src/state/corrective-yield-transaction.js.map +1 -0
  103. package/dist/src/state/lock.d.ts +75 -3
  104. package/dist/src/state/lock.js +582 -30
  105. package/dist/src/state/lock.js.map +1 -1
  106. package/dist/src/state/store.d.ts +3 -0
  107. package/dist/src/state/store.js +65 -12
  108. package/dist/src/state/store.js.map +1 -1
  109. package/dist/src/transition-core.d.ts +67 -0
  110. package/dist/src/transition-core.js +318 -0
  111. package/dist/src/transition-core.js.map +1 -0
  112. package/dist/src/version.d.ts +1 -1
  113. package/dist/src/version.js +1 -1
  114. package/dist/src/workflow.d.ts +51 -21
  115. package/dist/src/workflow.js +667 -144
  116. package/dist/src/workflow.js.map +1 -1
  117. package/docs/autonomy-guardrails.md +8 -1
  118. package/docs/beta2-initial-assembly-navigation-brief.md +616 -0
  119. package/docs/development-flow.md +17 -2
  120. package/docs/lifecycle/state-machine-stabilization.md +641 -0
  121. package/docs/release.md +11 -2
  122. package/docs/split-required-recovery.md +5 -4
  123. package/docs/stable-release-defect-register.md +330 -1
  124. package/docs/updating-existing-project.md +11 -0
  125. package/package.json +4 -1
  126. package/plugins/codex-workflow-gateway/references/protocol.md +56 -1
  127. package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +44 -0
  128. package/references/state-machine.md +4 -1
  129. package/schemas/adoption-posture-event.schema.json +1 -1
  130. package/schemas/context-envelope.schema.json +1 -1
  131. package/schemas/corrective-replan-credentials.private.schema.json +98 -0
  132. package/schemas/corrective-replan-execution-event.private.schema.json +53 -0
  133. package/schemas/corrective-replan-public.schema.json +142 -0
  134. package/schemas/corrective-replan-task-transaction.private.schema.json +151 -0
  135. package/schemas/corrective-yield-task-transaction.private.schema.json +98 -0
  136. package/schemas/remediation-event.schema.json +11 -1
  137. package/schemas/task-handoff-event.schema.json +1 -1
  138. package/schemas/transition-definition.schema.json +2609 -0
  139. package/schemas/transition-payloads.schema.json +140 -0
package/dist/src/cli.js CHANGED
@@ -1,18 +1,160 @@
1
1
  #!/usr/bin/env node
2
- import { createHash } from 'node:crypto';
3
2
  import { readFileSync } from 'node:fs';
4
3
  import path from 'node:path';
5
4
  import process from 'node:process';
6
5
  import { defaultTaskWorkerActor } from './alpha6/handoff.js';
6
+ import { assertCliSuccessCredentialSafety, projectCliErrorMessage, projectCliErrorValue, UnsafeCredentialOutputError, } from './credential-output.js';
7
7
  import { integrationDiagnostics } from './diagnostics.js';
8
8
  import { WorkflowError } from './errors.js';
9
9
  import { prepareGraphView } from './graph.js';
10
10
  import { migrateState } from './migration.js';
11
- import { changedFiles, currentBranch, isClean } from './repository.js';
11
+ import { changedFiles, currentBranch, isClean, resolveRepositoryIdentity } from './repository.js';
12
12
  import { launchStrictReviewer } from './reviewer.js';
13
13
  import { WorkflowService } from './workflow.js';
14
14
  import { PACKAGE_NAME, PACKAGE_VERSION } from './version.js';
15
15
  import { PROTOCOL_VERSION, STATE_SCHEMA_VERSION } from './contracts.js';
16
+ const CLI_ACTIONS = {
17
+ gateway: ['handshake'],
18
+ update: ['preflight', 'rescue-preflight'],
19
+ delegation: ['prepare', 'grant', 'list', 'show', 'revoke'],
20
+ 'project-memory': ['scan', 'show', 'status', 'approve', 'reconcile'],
21
+ state: ['migrate', 'adoption-prepare', 'adoption-apply'],
22
+ graph: ['prepare', 'status', 'refresh-request', 'bind', 'fallback'],
23
+ discovery: ['start', 'update', 'show', 'materialize'],
24
+ task: [
25
+ 'show',
26
+ 'replacement-materialize',
27
+ 'plan-set',
28
+ 'knowledge-rebind',
29
+ 'context-refresh',
30
+ 'authorize',
31
+ 'plan-risk-audit',
32
+ 'start',
33
+ 'run',
34
+ 'step-complete',
35
+ 'submit',
36
+ 'review-record',
37
+ 'review-launch',
38
+ 'step-review',
39
+ 'corrective-decision-recover',
40
+ 'remediation-mode-recover',
41
+ 'corrective-decision',
42
+ 'corrective-yield',
43
+ 'corrective-yield-recover',
44
+ 'corrective-replan-prepare',
45
+ 'corrective-replan-confirm',
46
+ 'corrective-replan-execute',
47
+ 'corrective-replan-recover',
48
+ 'handoff',
49
+ 'handoff-prepare',
50
+ 'handoff-show',
51
+ 'claim',
52
+ 'handback',
53
+ 'handback-create',
54
+ 'result-set',
55
+ 'accept',
56
+ 'sync-base',
57
+ 'merge',
58
+ 'merge-confirm',
59
+ ],
60
+ milestone: [
61
+ 'recover',
62
+ 'show',
63
+ 'plan-set',
64
+ 'scope-change-prepare',
65
+ 'scope-change-apply',
66
+ 'autonomy-prepare',
67
+ 'autonomy-grant',
68
+ 'autonomy-evolve',
69
+ 'authorize',
70
+ 'validate',
71
+ 'accept',
72
+ 'cancel',
73
+ ],
74
+ locks: ['inspect', 'repair'],
75
+ };
76
+ const CLI_HELP_SPECS = {
77
+ 'milestone authorize': {
78
+ requiredOptions: ['--id', '--expected-revision'],
79
+ optionalOptions: ['--actor', '--reason', '--delegation-grant', '--repo', '--json'],
80
+ },
81
+ 'milestone validate': {
82
+ requiredOptions: ['--id', '--expected-revision'],
83
+ optionalOptions: ['--repo', '--json'],
84
+ },
85
+ 'milestone accept': {
86
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--confirmation-code'],
87
+ optionalOptions: ['--delegation-grant', '--repo', '--json'],
88
+ },
89
+ 'task plan-set': {
90
+ requiredOptions: ['--id', '--expected-revision', '--file', '--risk-audit-file'],
91
+ optionalOptions: ['--corrective-audit-file', '--repo', '--json'],
92
+ },
93
+ 'task corrective-yield': {
94
+ requiredOptions: ['--id', '--expected-revision', '--actor', '--writer-token', '--reason'],
95
+ optionalOptions: ['--repo', '--json'],
96
+ },
97
+ 'task corrective-yield-recover': {
98
+ requiredOptions: ['--id', '--transaction-id'],
99
+ optionalOptions: ['--repo', '--json'],
100
+ },
101
+ 'task corrective-replan-prepare': {
102
+ requiredOptions: ['--id', '--file'],
103
+ optionalOptions: ['--repo', '--json'],
104
+ },
105
+ 'task corrective-replan-confirm': {
106
+ requiredOptions: ['--id', '--file', '--gate-file', '--confirmation-code'],
107
+ optionalOptions: ['--repo', '--json'],
108
+ },
109
+ 'task corrective-replan-execute': {
110
+ requiredOptions: ['--id', '--file', '--credential-file'],
111
+ optionalOptions: ['--repo', '--json'],
112
+ },
113
+ 'task corrective-replan-recover': {
114
+ requiredOptions: ['--id', '--transaction-id'],
115
+ optionalOptions: ['--repo', '--json'],
116
+ },
117
+ 'task authorize': {
118
+ requiredOptions: ['--id', '--expected-revision'],
119
+ optionalOptions: ['--actor', '--reason', '--delegation-grant', '--repo', '--json'],
120
+ },
121
+ 'task start': {
122
+ requiredOptions: ['--id', '--expected-revision', '--workspace-owner'],
123
+ optionalOptions: ['--repo', '--json'],
124
+ },
125
+ 'task run': {
126
+ requiredOptions: ['--id', '--step', '--expected-revision'],
127
+ optionalOptions: ['--owner', '--writer-token', '--repo', '--json'],
128
+ },
129
+ 'task step-complete': {
130
+ requiredOptions: ['--id', '--step', '--expected-revision', '--writer-token'],
131
+ optionalOptions: ['--note', '--actor', '--repo', '--json'],
132
+ },
133
+ 'task submit': {
134
+ requiredOptions: ['--id', '--expected-revision', '--writer-token'],
135
+ optionalOptions: ['--actor', '--repo', '--json'],
136
+ },
137
+ 'task review-launch': {
138
+ requiredOptions: ['--id', '--expected-revision'],
139
+ optionalOptions: ['--actor', '--writer-token', '--repo', '--json'],
140
+ },
141
+ 'task result-set': {
142
+ requiredOptions: ['--id', '--expected-revision', '--summary'],
143
+ optionalOptions: ['--limitation', '--repo', '--json'],
144
+ },
145
+ 'task accept': {
146
+ requiredOptions: ['--id', '--expected-revision'],
147
+ optionalOptions: ['--actor', '--delegation-grant', '--repo', '--json'],
148
+ },
149
+ 'task merge': {
150
+ requiredOptions: ['--id', '--expected-revision', '--writer-token'],
151
+ optionalOptions: ['--actor', '--repo', '--json'],
152
+ },
153
+ 'task merge-confirm': {
154
+ requiredOptions: ['--id', '--expected-revision', '--writer-token'],
155
+ optionalOptions: ['--actor', '--repo', '--json'],
156
+ },
157
+ };
16
158
  function parseArguments(argv) {
17
159
  const positionals = [];
18
160
  const options = new Map();
@@ -38,6 +180,55 @@ function parseArguments(argv) {
38
180
  function option(args, name) {
39
181
  return args.options.get(name)?.at(-1);
40
182
  }
183
+ function cliHelp(args) {
184
+ const [noun, action] = args.positionals;
185
+ if (!noun) {
186
+ return {
187
+ kind: 'cli-help',
188
+ readOnly: true,
189
+ scope: 'top-level',
190
+ usage: 'codex-workflow <command> [action] [options]',
191
+ commands: ['doctor', 'status', 'next', ...Object.keys(CLI_ACTIONS)],
192
+ };
193
+ }
194
+ if (!action) {
195
+ if (['doctor', 'status', 'next'].includes(noun)) {
196
+ return {
197
+ kind: 'cli-help',
198
+ readOnly: true,
199
+ scope: 'command',
200
+ command: noun,
201
+ usage: `codex-workflow ${noun} [--repo <path>] [--json]`,
202
+ requiredOptions: [],
203
+ optionalOptions: ['--repo', '--json'],
204
+ exactOptionContractAvailable: true,
205
+ };
206
+ }
207
+ return {
208
+ kind: 'cli-help',
209
+ readOnly: true,
210
+ scope: 'command',
211
+ command: noun,
212
+ usage: `codex-workflow ${noun} <action> [options]`,
213
+ actions: CLI_ACTIONS[noun] ?? [],
214
+ };
215
+ }
216
+ const command = `${noun} ${action}`;
217
+ const spec = CLI_HELP_SPECS[command];
218
+ return {
219
+ kind: 'cli-help',
220
+ readOnly: true,
221
+ scope: 'action',
222
+ command,
223
+ usage: spec
224
+ ? ['codex-workflow', noun, action, ...spec.requiredOptions.map((name) => `${name} <value>`), '[options]'].join(' ')
225
+ : `codex-workflow ${noun} ${action} [options]`,
226
+ requiredOptions: spec?.requiredOptions ?? null,
227
+ optionalOptions: spec?.optionalOptions ?? null,
228
+ exactOptionContractAvailable: Boolean(spec),
229
+ ...(spec ? {} : { note: 'Consult the packaged protocol for this action option contract.' }),
230
+ };
231
+ }
41
232
  function required(args, name) {
42
233
  const value = option(args, name)?.trim();
43
234
  if (!value)
@@ -136,6 +327,7 @@ function workflowCapabilities() {
136
327
  'alpha6-adoption-posture-v1',
137
328
  'alpha6-strict-review-rescue-v1',
138
329
  'milestone-initial-assembly-v1',
330
+ 'milestone-initial-assembly-navigation-v2',
139
331
  'milestone-autonomy-contract-v1',
140
332
  'milestone-autonomy-content-refresh-v1',
141
333
  'milestone-autonomous-membership-evolution-v1',
@@ -146,10 +338,16 @@ function workflowCapabilities() {
146
338
  'plan-proof-obligations-v1',
147
339
  'terminal-task-replacement-transaction-v1',
148
340
  'project-composite-transaction-journal-v1',
341
+ 'corrective-yield-journal-v1',
342
+ 'corrective-replan-journal-v1',
343
+ 'corrective-replan-human-gate-v1',
344
+ 'corrective-replan-protocol-v2',
149
345
  ];
150
346
  }
151
347
  async function dispatch(args) {
152
348
  const [noun, action] = args.positionals;
349
+ if (args.options.has('help'))
350
+ return cliHelp(args);
153
351
  const repo = repository(args);
154
352
  if (noun === 'gateway' && action === 'handshake') {
155
353
  return {
@@ -162,19 +360,19 @@ async function dispatch(args) {
162
360
  }
163
361
  const workflow = new WorkflowService();
164
362
  if (noun === 'doctor') {
165
- const context = workflow.context(repo);
166
- const integration = integrationDiagnostics(context.identity.repositoryRoot);
363
+ const identity = resolveRepositoryIdentity(repo);
364
+ const integration = integrationDiagnostics(identity.repositoryRoot);
167
365
  const nodeSupported = Number(process.versions.node.split('.')[0]) >= 22;
168
366
  return {
169
367
  ok: nodeSupported && integration.localDependency.current,
170
368
  node: process.versions.node,
171
369
  requiredNode: '>=22',
172
- repositoryRoot: context.identity.repositoryRoot,
173
- projectId: context.identity.projectId,
174
- stateRoot: context.store.root,
175
- branch: currentBranch(context.identity.repositoryRoot),
176
- clean: isClean(context.identity.repositoryRoot),
177
- changedFiles: changedFiles(context.identity.repositoryRoot),
370
+ repositoryRoot: identity.repositoryRoot,
371
+ projectId: identity.projectId,
372
+ stateRoot: workflow.store.root,
373
+ branch: currentBranch(identity.repositoryRoot),
374
+ clean: isClean(identity.repositoryRoot),
375
+ changedFiles: changedFiles(identity.repositoryRoot),
178
376
  integration,
179
377
  limitations: [
180
378
  'CLI diagnostics cannot prove that Codex enforced a role, model, sandbox, or read-only reviewer.',
@@ -198,12 +396,12 @@ async function dispatch(args) {
198
396
  return workflow.grantDelegation(repo, jsonFile(args), required(args, 'confirmation-code'));
199
397
  }
200
398
  if (noun === 'delegation' && action === 'list') {
201
- const context = workflow.context(repo);
202
- return context.store.listDelegations(context.identity.projectId);
399
+ const identity = resolveRepositoryIdentity(repo);
400
+ return workflow.store.listDelegations(identity.projectId);
203
401
  }
204
402
  if (noun === 'delegation' && action === 'show') {
205
- const context = workflow.context(repo);
206
- return context.store.readDelegation(context.identity.projectId, required(args, 'id'));
403
+ const identity = resolveRepositoryIdentity(repo);
404
+ return workflow.store.readDelegation(identity.projectId, required(args, 'id'));
207
405
  }
208
406
  if (noun === 'delegation' && action === 'revoke') {
209
407
  return workflow.revokeDelegation(repo, required(args, 'id'), revision(args), required(args, 'actor'), required(args, 'reason'));
@@ -306,8 +504,8 @@ async function dispatch(args) {
306
504
  return workflow.updateDiscovery(repo, required(args, 'id'), revision(args), patch);
307
505
  }
308
506
  if (noun === 'discovery' && action === 'show') {
309
- const context = workflow.context(repo);
310
- return context.store.readDiscovery(context.identity.projectId, required(args, 'id'));
507
+ const identity = resolveRepositoryIdentity(repo);
508
+ return workflow.store.readDiscovery(identity.projectId, required(args, 'id'));
311
509
  }
312
510
  if (noun === 'discovery' && action === 'materialize') {
313
511
  const kind = option(args, 'kind') ?? 'task';
@@ -320,8 +518,8 @@ async function dispatch(args) {
320
518
  throw new WorkflowError('INVALID_ARGUMENT', '--kind must be task or milestone.');
321
519
  }
322
520
  if (noun === 'task' && action === 'show') {
323
- const context = workflow.context(repo);
324
- return context.store.readTask(context.identity.projectId, required(args, 'id'));
521
+ const identity = resolveRepositoryIdentity(repo);
522
+ return workflow.store.readTask(identity.projectId, required(args, 'id'));
325
523
  }
326
524
  if (noun === 'task' && action === 'replacement-materialize') {
327
525
  return workflow.replaceSplitRequiredTask(repo, required(args, 'id'), revision(args), required(args, 'discovery'), positiveIntegerOption(args, 'expected-discovery-revision'), positiveIntegerOption(args, 'expected-milestone-revision'), required(args, 'title'), option(args, 'actor') ?? 'user');
@@ -351,7 +549,32 @@ async function dispatch(args) {
351
549
  return workflow.startTask(repo, required(args, 'id'), revision(args), owner);
352
550
  }
353
551
  if (noun === 'task' && action === 'run') {
354
- return workflow.runStep(repo, required(args, 'id'), required(args, 'step'), revision(args), option(args, 'owner') ?? 'worker', option(args, 'writer-token') ?? null);
552
+ const outcome = workflow.runStep(repo, required(args, 'id'), required(args, 'step'), revision(args), option(args, 'owner') ?? 'worker', option(args, 'writer-token') ?? null);
553
+ const { writerToken, ...envelope } = outcome.envelope;
554
+ if (outcome.writerCredential.disposition === 'issued' && !writerToken) {
555
+ throw new WorkflowError('STATE_CORRUPT', 'Fresh task run credential issuance did not return its protocol-v1 writer token.');
556
+ }
557
+ if (outcome.writerCredential.disposition === 'renewed' && writerToken !== null) {
558
+ throw new WorkflowError('STATE_CORRUPT', 'Renewed task run credential unexpectedly returned a writer token.');
559
+ }
560
+ return {
561
+ writerCredential: { disposition: outcome.writerCredential.disposition },
562
+ ...(writerToken ? {
563
+ writerLeaseReceipt: {
564
+ token: writerToken,
565
+ kind: 'writer-lease',
566
+ owner: outcome.lease.owner,
567
+ action: 'task step-complete',
568
+ option: '--writer-token',
569
+ source: 'task run',
570
+ sensitive: true,
571
+ oneTime: false,
572
+ },
573
+ } : {}),
574
+ task: outcome.task,
575
+ lease: outcome.lease,
576
+ envelope,
577
+ };
355
578
  }
356
579
  if (noun === 'task' && action === 'step-complete') {
357
580
  return workflow.completeStep(repo, required(args, 'id'), required(args, 'step'), revision(args), required(args, 'writer-token'), repeated(args, 'note'), option(args, 'actor'));
@@ -364,10 +587,10 @@ async function dispatch(args) {
364
587
  return workflow.recordReview(repo, required(args, 'id'), revision(args), review, option(args, 'actor'), option(args, 'writer-token') ?? null);
365
588
  }
366
589
  if (noun === 'task' && action === 'review-launch') {
367
- const context = workflow.context(repo);
590
+ const identity = resolveRepositoryIdentity(repo);
368
591
  const id = required(args, 'id');
369
592
  const expectedRevision = revision(args);
370
- const task = context.store.readTask(context.identity.projectId, id);
593
+ const task = workflow.store.readTask(identity.projectId, id);
371
594
  if (task.revision !== expectedRevision) {
372
595
  throw new WorkflowError('STATE_CONFLICT', `State revision conflict for ${id}`, {
373
596
  expectedRevision,
@@ -375,11 +598,15 @@ async function dispatch(args) {
375
598
  });
376
599
  }
377
600
  const envelope = workflow.taskContext(repo, id, 'independent-reviewer');
378
- const launch = launchStrictReviewer(context.identity.repositoryRoot, task, context.store.taskRoot(task.projectId, task.id), envelope);
601
+ const launch = launchStrictReviewer(identity.repositoryRoot, task, workflow.store.taskRoot(task.projectId, task.id), envelope);
602
+ // The independent reviewer identity belongs to the strict reviewer payload. CLI --actor
603
+ // remains the lifecycle mutation actor, such as the current C1 claimant.
379
604
  const saved = workflow.recordReview(repo, id, expectedRevision, launch.review, option(args, 'actor'), option(args, 'writer-token') ?? null);
380
605
  return { launch, task: saved };
381
606
  }
382
607
  if (noun === 'task' && action === 'step-review') {
608
+ // Strict Step Review launches and records the isolated reviewer inside Core. CLI --actor
609
+ // remains the lifecycle actor from next, typically the active C1 claimant.
383
610
  return workflow.reviewStep(repo, required(args, 'id'), required(args, 'step'), revision(args), undefined, option(args, 'actor'), option(args, 'writer-token') ?? null);
384
611
  }
385
612
  if (noun === 'task' && action === 'corrective-decision-recover') {
@@ -391,14 +618,66 @@ async function dispatch(args) {
391
618
  if (noun === 'task' && action === 'corrective-decision') {
392
619
  return workflow.recordStepCorrectiveDecision(repo, required(args, 'id'), required(args, 'step'), revision(args), jsonFile(args), option(args, 'actor'), option(args, 'writer-token') ?? null);
393
620
  }
621
+ if (noun === 'task' && action === 'corrective-yield') {
622
+ return workflow.executeCorrectiveYield(repo, required(args, 'id'), revision(args), required(args, 'actor'), required(args, 'writer-token'), required(args, 'reason'));
623
+ }
624
+ if (noun === 'task' && action === 'corrective-yield-recover') {
625
+ return workflow.recoverCorrectiveYield(repo, required(args, 'id'), required(args, 'transaction-id'));
626
+ }
627
+ if (noun === 'task' && action === 'corrective-replan-prepare') {
628
+ return workflow.prepareCorrectiveReplan(repo, required(args, 'id'), jsonFile(args));
629
+ }
630
+ if (noun === 'task' && action === 'corrective-replan-confirm') {
631
+ return workflow.confirmCorrectiveReplan(repo, required(args, 'id'), jsonFile(args), jsonFile(args, 'gate-file'), required(args, 'confirmation-code'));
632
+ }
633
+ if (noun === 'task' && action === 'corrective-replan-execute') {
634
+ return workflow.executeCorrectiveReplan(repo, required(args, 'id'), jsonFile(args), jsonFile(args, 'credential-file'));
635
+ }
636
+ if (noun === 'task' && action === 'corrective-replan-recover') {
637
+ return workflow.recoverCorrectiveReplan(repo, required(args, 'id'), required(args, 'transaction-id'));
638
+ }
394
639
  if (noun === 'task' && (action === 'handoff' || action === 'handoff-prepare')) {
395
- return workflow.handoffTask(repo, required(args, 'id'), revision(args), required(args, 'actor'), option(args, 'target-actor') ?? defaultTaskWorkerActor(required(args, 'id')), required(args, 'reason'), option(args, 'writer-token') ?? null, option(args, 'delegation-grant') ?? null, option(args, 'expires-at') ?? null);
640
+ const outcome = workflow.handoffTask(repo, required(args, 'id'), revision(args), required(args, 'actor'), option(args, 'target-actor') ?? defaultTaskWorkerActor(required(args, 'id')), required(args, 'reason'), option(args, 'writer-token') ?? null, option(args, 'delegation-grant') ?? null, option(args, 'expires-at') ?? null);
641
+ const { claimToken, ...bundle } = outcome.bundle;
642
+ return {
643
+ credentialHandoff: {
644
+ token: claimToken,
645
+ kind: 'claim-token',
646
+ targetActor: outcome.bundle.delegate,
647
+ action: 'task claim',
648
+ option: '--claim-token',
649
+ source: 'task handoff-prepare',
650
+ sensitive: true,
651
+ oneTime: true,
652
+ },
653
+ task: outcome.task,
654
+ event: outcome.event,
655
+ bundle,
656
+ };
396
657
  }
397
658
  if (noun === 'task' && action === 'handoff-show') {
398
659
  return workflow.showTaskHandoff(repo, required(args, 'id'));
399
660
  }
400
661
  if (noun === 'task' && action === 'claim') {
401
- return workflow.claimTask(repo, required(args, 'id'), revision(args), required(args, 'actor'), required(args, 'claim-token'), option(args, 'writer-token') ?? null);
662
+ const outcome = workflow.claimTask(repo, required(args, 'id'), revision(args), required(args, 'actor'), required(args, 'claim-token'), option(args, 'writer-token') ?? null);
663
+ return {
664
+ writerCredential: { disposition: outcome.writerCredential.disposition },
665
+ ...(outcome.writerCredential.disposition === 'issued' ? {
666
+ writerLeaseReceipt: {
667
+ token: outcome.writerCredential.token,
668
+ kind: 'writer-lease',
669
+ owner: outcome.lease.owner,
670
+ action: 'task run',
671
+ option: '--writer-token',
672
+ source: 'task claim',
673
+ sensitive: true,
674
+ oneTime: false,
675
+ },
676
+ } : {}),
677
+ task: outcome.task,
678
+ event: outcome.event,
679
+ lease: outcome.lease,
680
+ };
402
681
  }
403
682
  if (noun === 'task' && (action === 'handback' || action === 'handback-create')) {
404
683
  return workflow.handbackTask(repo, required(args, 'id'), revision(args), required(args, 'actor'), required(args, 'reason'), option(args, 'writer-token') ?? null, repeated(args, 'limitation'), action === 'handback-create'
@@ -421,8 +700,8 @@ async function dispatch(args) {
421
700
  return workflow.confirmExternalMerge(repo, required(args, 'id'), revision(args), required(args, 'writer-token'), option(args, 'actor'));
422
701
  }
423
702
  if (noun === 'milestone' && action === 'show') {
424
- const context = workflow.context(repo);
425
- return context.store.readMilestone(context.identity.projectId, required(args, 'id'));
703
+ const identity = resolveRepositoryIdentity(repo);
704
+ return workflow.store.readMilestone(identity.projectId, required(args, 'id'));
426
705
  }
427
706
  if (noun === 'milestone' && action === 'plan-set') {
428
707
  return workflow.setMilestonePlan(repo, required(args, 'id'), revision(args), jsonFile(args));
@@ -455,39 +734,100 @@ async function dispatch(args) {
455
734
  return workflow.cancelMilestone(repo, required(args, 'id'), revision(args), required(args, 'reason'));
456
735
  }
457
736
  if (noun === 'locks' && (action === 'inspect' || action === 'repair')) {
458
- const context = workflow.context(repo);
459
737
  const id = required(args, 'id');
460
- const lease = action === 'inspect' ? context.locks.inspect(id) : context.locks.repairStale(id);
461
- return lease ? {
462
- schemaVersion: lease.schemaVersion,
463
- entityId: lease.entityId,
464
- tokenFingerprint: createHash('sha256').update(lease.token).digest('hex').slice(0, 16),
465
- owner: lease.owner,
466
- pid: lease.pid,
467
- hostname: lease.hostname,
468
- acquiredAt: lease.acquiredAt,
469
- heartbeatAt: lease.heartbeatAt,
470
- expiresAt: lease.expiresAt,
471
- repaired: action === 'repair',
472
- } : null;
738
+ if (action === 'repair')
739
+ return workflow.repairStaleWriterLease(repo, id);
740
+ const inspection = workflow.inspectWriterLease(repo, id);
741
+ return inspection ? { ...inspection, repaired: false } : null;
473
742
  }
474
743
  throw new WorkflowError('INVALID_ARGUMENT', 'Unknown command.', {
475
744
  command: args.positionals.join(' '),
476
745
  hint: 'Use doctor, status, next, update preflight, state <action>, delegation <action>, project-memory <action>, discovery <action>, task <action>, milestone <action>, or locks <action>.',
477
746
  });
478
747
  }
748
+ function credentialAllowancesForResult(args, value) {
749
+ const [noun, action] = args.positionals;
750
+ if (!isRecord(value))
751
+ return [];
752
+ if (noun === 'task' && (action === 'run' || action === 'claim')) {
753
+ const disposition = isRecord(value.writerCredential) ? value.writerCredential.disposition : null;
754
+ const receipt = isRecord(value.writerLeaseReceipt) ? value.writerLeaseReceipt : null;
755
+ if (disposition === 'issued'
756
+ && receipt?.kind === 'writer-lease'
757
+ && receipt.source === `task ${action}`
758
+ && receipt.sensitive === true) {
759
+ return [{ path: '$.writerLeaseReceipt.token' }];
760
+ }
761
+ return [];
762
+ }
763
+ if (noun === 'task' && (action === 'handoff' || action === 'handoff-prepare')) {
764
+ const receipt = isRecord(value.credentialHandoff) ? value.credentialHandoff : null;
765
+ if (receipt?.kind === 'claim-token'
766
+ && receipt.source === 'task handoff-prepare'
767
+ && receipt.sensitive === true
768
+ && receipt.oneTime === true) {
769
+ return [{ path: '$.credentialHandoff.token' }];
770
+ }
771
+ }
772
+ return [];
773
+ }
774
+ function rawCredentialInputs(argv) {
775
+ const values = [];
776
+ for (let index = 0; index < argv.length; index += 1) {
777
+ const argument = argv[index];
778
+ for (const optionName of ['--writer-token', '--claim-token', '--confirmation-code']) {
779
+ if (argument === optionName && argv[index + 1])
780
+ values.push(argv[index + 1]);
781
+ if (argument.startsWith(`${optionName}=`))
782
+ values.push(argument.slice(optionName.length + 1));
783
+ }
784
+ }
785
+ return [...new Set(values.filter(Boolean))];
786
+ }
787
+ function isRecord(value) {
788
+ return typeof value === 'object' && value !== null;
789
+ }
479
790
  async function main() {
791
+ const argv = process.argv.slice(2);
792
+ const sensitiveInputs = rawCredentialInputs(argv);
480
793
  try {
481
- const value = await dispatch(parseArguments(process.argv.slice(2)));
794
+ const args = parseArguments(argv);
795
+ const value = await dispatch(args);
796
+ assertCliSuccessCredentialSafety(value, credentialAllowancesForResult(args, value), sensitiveInputs);
482
797
  process.stdout.write(`${JSON.stringify({ ok: true, value }, null, 2)}\n`);
483
798
  }
484
799
  catch (error) {
800
+ if (error instanceof UnsafeCredentialOutputError) {
801
+ process.stderr.write(`${JSON.stringify({
802
+ ok: false,
803
+ error: {
804
+ code: 'STATE_CORRUPT',
805
+ message: error.message,
806
+ details: { credentialPaths: error.paths },
807
+ },
808
+ }, null, 2)}\n`);
809
+ process.exitCode = 2;
810
+ return;
811
+ }
485
812
  if (error instanceof WorkflowError) {
486
- process.stderr.write(`${JSON.stringify({ ok: false, error: { code: error.code, message: error.message, details: error.details } }, null, 2)}\n`);
813
+ process.stderr.write(`${JSON.stringify({
814
+ ok: false,
815
+ error: {
816
+ code: error.code,
817
+ message: projectCliErrorMessage(error.message, sensitiveInputs),
818
+ details: projectCliErrorValue(error.details, sensitiveInputs),
819
+ },
820
+ }, null, 2)}\n`);
487
821
  process.exitCode = 2;
488
822
  return;
489
823
  }
490
- process.stderr.write(`${JSON.stringify({ ok: false, error: { code: 'UNEXPECTED', message: error instanceof Error ? error.message : String(error) } }, null, 2)}\n`);
824
+ process.stderr.write(`${JSON.stringify({
825
+ ok: false,
826
+ error: {
827
+ code: 'UNEXPECTED',
828
+ message: projectCliErrorMessage(error instanceof Error ? error.message : String(error), sensitiveInputs),
829
+ },
830
+ }, null, 2)}\n`);
491
831
  process.exitCode = 1;
492
832
  }
493
833
  }