@cassiomc1/forgeloop 1.3.0 → 1.6.0

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 (163) hide show
  1. package/.github/copilot-instructions.md +1 -0
  2. package/AGENTS.md +1 -0
  3. package/CLAUDE.md +1 -0
  4. package/DOCS_INDEX.md +20 -8
  5. package/EXECUTION_STATE.md +60 -0
  6. package/LOOP_ENGINEERING.md +135 -5
  7. package/LOOP_SYSTEM_DESIGN.md +54 -1
  8. package/PROTOCOL_INTEGRATION.md +87 -0
  9. package/QUALITY_SCORECARD.md +2 -0
  10. package/README.md +69 -9
  11. package/TERMINOLOGY.md +15 -0
  12. package/THIRD_PARTY_NOTICES.md +30 -0
  13. package/THREAT_MODEL.md +59 -1
  14. package/docs/ARTIFACT_REFERENCE.md +183 -0
  15. package/docs/CLI_REFERENCE.md +391 -6
  16. package/docs/CROSS_HARNESS_CONTINUITY.md +23 -0
  17. package/docs/DIAGNOSTIC_MODEL.md +181 -0
  18. package/docs/DOCUMENTATION_GUIDE.md +36 -13
  19. package/docs/EXECUTION_TRACE.md +76 -0
  20. package/docs/GETTING_STARTED.md +1 -0
  21. package/docs/MCP.md +159 -0
  22. package/docs/RECIPES.md +149 -0
  23. package/docs/RELEASE_CHECKLIST_1_4.md +38 -0
  24. package/docs/RELEASE_CHECKLIST_1_5_MCP.md +78 -0
  25. package/docs/TROUBLESHOOTING.md +217 -3
  26. package/docs/UNIVERSAL_INTEGRATION.md +48 -0
  27. package/docs/assets/diagrams/forgeloop-engineering-flow.html +13797 -0
  28. package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +37 -0
  29. package/docs/assets/diagrams/forgeloop-engineering-flow.svg +5002 -0
  30. package/docs/diagrams/README.md +55 -0
  31. package/docs/diagrams/forgeloop-engineering-flow.workflow.json +122 -0
  32. package/docs/diagrams/manifest.json +42 -0
  33. package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +20 -0
  34. package/package.json +21 -8
  35. package/schemas/action.schema.json +100 -0
  36. package/schemas/approval.schema.json +51 -0
  37. package/schemas/capability-policy.schema.json +41 -0
  38. package/schemas/diagnostic-case.schema.json +85 -0
  39. package/schemas/execution-receipt.schema.json +16 -0
  40. package/schemas/hypothesis-disposition.schema.json +16 -0
  41. package/schemas/intervention.schema.json +27 -0
  42. package/schemas/policy-lock.schema.json +1 -0
  43. package/schemas/policy-snapshot.schema.json +2 -0
  44. package/schemas/task-recovery.schema.json +61 -0
  45. package/schemas/trajectory-evaluation.schema.json +64 -0
  46. package/schemas/trajectory-scenario.schema.json +42 -0
  47. package/src/cli.js +267 -347
  48. package/src/commands/action-authorize.js +41 -0
  49. package/src/commands/action-propose.js +10 -0
  50. package/src/commands/action-reconcile.js +10 -0
  51. package/src/commands/action-record.js +47 -0
  52. package/src/commands/action-show.js +10 -0
  53. package/src/commands/action-verify.js +10 -0
  54. package/src/commands/advance.js +7 -2
  55. package/src/commands/approval-request.js +64 -0
  56. package/src/commands/approval-resolve.js +10 -0
  57. package/src/commands/audit.js +5 -0
  58. package/src/commands/baseline.js +3 -3
  59. package/src/commands/eval.js +6 -0
  60. package/src/commands/history.js +18 -0
  61. package/src/commands/init.js +2 -2
  62. package/src/commands/inspect.js +55 -0
  63. package/src/commands/metrics.js +7 -0
  64. package/src/commands/next.js +8 -2
  65. package/src/commands/policy-discover.js +2 -2
  66. package/src/commands/progress.js +6 -2
  67. package/src/commands/record-diagnosis.js +37 -1
  68. package/src/commands/record-hypothesis-disposition.js +45 -0
  69. package/src/commands/record-intervention.js +35 -0
  70. package/src/commands/reflect.js +38 -0
  71. package/src/commands/report.js +9 -1
  72. package/src/commands/run-action.js +18 -0
  73. package/src/commands/status.js +17 -0
  74. package/src/commands/task-create.js +39 -1
  75. package/src/commands/task-list.js +14 -1
  76. package/src/commands/task-lock-status.js +2 -2
  77. package/src/commands/task-recover.js +202 -0
  78. package/src/commands/task-repair-legacy-recovery.js +417 -0
  79. package/src/commands/task-resume.js +172 -0
  80. package/src/commands/task-scope.js +23 -4
  81. package/src/commands/task-show.js +18 -4
  82. package/src/commands/trace.js +34 -0
  83. package/src/commands/validate-protocol.js +40 -15
  84. package/src/core/action-authorization.js +106 -0
  85. package/src/core/action-constants.js +86 -0
  86. package/src/core/action-execution.js +105 -0
  87. package/src/core/action-ledger-projection.js +302 -0
  88. package/src/core/action-model.js +581 -0
  89. package/src/core/action-readiness.js +141 -0
  90. package/src/core/action-reconciliation-policy.js +49 -0
  91. package/src/core/action-reconciliation.js +66 -0
  92. package/src/core/action-verification.js +111 -0
  93. package/src/core/actions.js +462 -0
  94. package/src/core/approvals.js +405 -0
  95. package/src/core/artifact-registry.js +60 -0
  96. package/src/core/audit.js +45 -4
  97. package/src/core/bundles.js +30 -0
  98. package/src/core/capability-policy.js +226 -0
  99. package/src/core/cli-command-definitions.js +260 -5
  100. package/src/core/command-executors.js +543 -0
  101. package/src/core/command-input.js +107 -0
  102. package/src/core/command-runtime.js +117 -0
  103. package/src/core/completion-artifacts.js +39 -15
  104. package/src/core/completion-ownership.js +88 -0
  105. package/src/core/completion-recovery-rebind.js +194 -0
  106. package/src/core/completion.js +70 -0
  107. package/src/core/continuity-reconciliation.js +24 -5
  108. package/src/core/diagnostic-model.js +396 -0
  109. package/src/core/diagnostic-projection.js +51 -0
  110. package/src/core/diagnostic-record.js +360 -0
  111. package/src/core/error-codes.js +461 -1
  112. package/src/core/events.js +171 -2
  113. package/src/core/execution-prerequisites.js +4 -1
  114. package/src/core/execution.js +26 -188
  115. package/src/core/failure-signature.js +70 -0
  116. package/src/core/failure-surface.js +57 -0
  117. package/src/core/filesystem.js +55 -6
  118. package/src/core/history.js +110 -0
  119. package/src/core/hypothesis-projection.js +85 -0
  120. package/src/core/information-gain-projection.js +283 -0
  121. package/src/core/information-gain.js +138 -0
  122. package/src/core/inspect.js +132 -7
  123. package/src/core/integration-invocation-policy.js +217 -0
  124. package/src/core/integration-limits.js +20 -0
  125. package/src/core/integration-resources.js +178 -0
  126. package/src/core/next-action-model.js +94 -0
  127. package/src/core/next-action.js +490 -3
  128. package/src/core/phase.js +42 -22
  129. package/src/core/policy-engine.js +113 -6
  130. package/src/core/preflight-consistency.js +31 -5
  131. package/src/core/preflight.js +19 -2
  132. package/src/core/prepared-execution.js +227 -0
  133. package/src/core/progress.js +41 -4
  134. package/src/core/project-root.js +21 -0
  135. package/src/core/protocol-info.js +61 -0
  136. package/src/core/protocol.js +14 -0
  137. package/src/core/receipt.js +1 -0
  138. package/src/core/reconcile-closure.js +35 -10
  139. package/src/core/recovery-history.js +116 -0
  140. package/src/core/reflection.js +305 -0
  141. package/src/core/resumability.js +57 -3
  142. package/src/core/schema-validation.js +9 -0
  143. package/src/core/strategy-analysis.js +97 -0
  144. package/src/core/task-claim-state.js +272 -0
  145. package/src/core/task-command.js +5 -1
  146. package/src/core/task-conflict-inspection.js +321 -0
  147. package/src/core/task-context.js +32 -29
  148. package/src/core/task-discovery.js +14 -1
  149. package/src/core/task-lock.js +216 -22
  150. package/src/core/task-paths.js +31 -2
  151. package/src/core/task-recovery-migration.js +192 -0
  152. package/src/core/task-recovery.js +205 -0
  153. package/src/core/task-scope.js +33 -1
  154. package/src/core/task-snapshot.js +53 -0
  155. package/src/core/templates.js +9 -0
  156. package/src/core/trace.js +548 -0
  157. package/src/core/trajectory-evaluation.js +71 -0
  158. package/src/core/trajectory-metrics.js +80 -0
  159. package/src/core/transaction.js +36 -2
  160. package/src/core/work-state.js +10 -5
  161. package/src/integration.js +47 -0
  162. package/docs/assets/forgeloop-flow.svg +0 -1
  163. package/docs/forgeloop-flow.mmd +0 -51
@@ -0,0 +1,543 @@
1
+ import { runDoctor } from "../commands/doctor.js";
2
+ import { runStatus } from "../commands/status.js";
3
+ import { runValidateState } from "../commands/validate-state.js";
4
+ import { runClearState } from "../commands/clear-state.js";
5
+ import { inspectTarget } from "../commands/inspect.js";
6
+ import { runInit } from "../commands/init.js";
7
+ import { runRoute } from "../commands/route.js";
8
+ import { runValidateReceipt } from "../commands/validate-receipt.js";
9
+ import { runValidateProtocol } from "../commands/validate-protocol.js";
10
+ import { runUpdate } from "../commands/update.js";
11
+ import { runActivate } from "../commands/activate.js";
12
+ import { runAdvance } from "../commands/advance.js";
13
+ import { runPreflight } from "../commands/preflight.js";
14
+ import { runComplete } from "../commands/complete.js";
15
+ import { runAudit } from "../commands/audit.js";
16
+ import { runReport } from "../commands/report.js";
17
+ import { runPolicy } from "../commands/policy.js";
18
+ import { runPolicyDiscover } from "../commands/policy-discover.js";
19
+ import { runPolicyStatus } from "../commands/policy-status.js";
20
+ import { runPolicyDiff } from "../commands/policy-diff.js";
21
+ import { runRuleVerify } from "../commands/rule-verify.js";
22
+ import { runBaseline } from "../commands/baseline.js";
23
+ import { runProfileInterview } from "../commands/profile-interview.js";
24
+ import { runBundle } from "../commands/bundle.js";
25
+ import { runPrepareCompletion } from "../commands/prepare-completion.js";
26
+ import { runRecordCheck } from "../commands/record-check.js";
27
+ import { runCheck } from "../commands/run-check.js";
28
+ import { runAction } from "../commands/run-action.js";
29
+ import { runActionPropose } from "../commands/action-propose.js";
30
+ import { runActionRecord } from "../commands/action-record.js";
31
+ import { runActionShow } from "../commands/action-show.js";
32
+ import { runActionAuthorize } from "../commands/action-authorize.js";
33
+ import { runActionVerify } from "../commands/action-verify.js";
34
+ import { runActionReconcile } from "../commands/action-reconcile.js";
35
+ import { runMetrics } from "../commands/metrics.js";
36
+ import { runEval } from "../commands/eval.js";
37
+ import { runApprovalRequest } from "../commands/approval-request.js";
38
+ import { runApprovalResolve } from "../commands/approval-resolve.js";
39
+ import { reconcileClosure } from "../commands/reconcile-closure.js";
40
+ import { runRecordTerminalResult } from "../commands/record-terminal-result.js";
41
+ import { runRecordDiagnosis } from "../commands/record-diagnosis.js";
42
+ import { runRecordIntervention } from "../commands/record-intervention.js";
43
+ import { runRecordHypothesisDisposition } from "../commands/record-hypothesis-disposition.js";
44
+ import { runHistory } from "../commands/history.js";
45
+ import { runTrace } from "../commands/trace.js";
46
+ import { runReflect } from "../commands/reflect.js";
47
+ import { runProgress } from "../commands/progress.js";
48
+ import { runRecordDecisionCriterion } from "../commands/record-decision-criterion.js";
49
+ import { runNext } from "../commands/next.js";
50
+ import { runContinuity } from "../commands/continuity.js";
51
+ import { runRecordContinuity } from "../commands/record-continuity.js";
52
+ import { runReconcileContinuity } from "../commands/reconcile-continuity.js";
53
+ import { runClearContinuity } from "../commands/clear-continuity.js";
54
+ import { runTaskCreate } from "../commands/task-create.js";
55
+ import { runTaskList } from "../commands/task-list.js";
56
+ import { runTaskShow } from "../commands/task-show.js";
57
+ import { runTaskScope } from "../commands/task-scope.js";
58
+ import { runTaskMigrate } from "../commands/task-migrate.js";
59
+ import { runMigrateProtocol } from "../commands/migrate-protocol.js";
60
+ import { runTaskUnlock } from "../commands/task-unlock.js";
61
+ import { runTaskRecover } from "../commands/task-recover.js";
62
+ import { runTaskResume } from "../commands/task-resume.js";
63
+ import { runTaskRepairLegacyRecovery } from "../commands/task-repair-legacy-recovery.js";
64
+ import { runTaskLockStatus } from "../commands/task-lock-status.js";
65
+ import { runProtocolInfo } from "../commands/protocol-info.js";
66
+
67
+ /**
68
+ * Canonical transport-neutral command executors.
69
+ *
70
+ * Every entry executes exactly one ForgeLoop command and returns a
71
+ * structured `{ result, exitCode }` envelope without any terminal output.
72
+ * Exit codes preserve CLI-equivalent semantics: a non-zero exit code is a
73
+ * deterministic protocol/domain outcome, not an invocation failure.
74
+ *
75
+ * The CLI renders these results; MCP and other integrations consume them
76
+ * directly. No ownership, recovery, or lifecycle logic may live here.
77
+ */
78
+ export const COMMAND_EXECUTORS = {
79
+ "protocol-info": async ({ packageVersion }) => ({
80
+ result: await runProtocolInfo({ packageVersion }),
81
+ exitCode: 0,
82
+ }),
83
+ init: async ({ target, packageRoot, packageVersion, options }) => ({
84
+ result: await runInit({ target, dryRun: options.dryRun, packageRoot, packageVersion }),
85
+ exitCode: 0,
86
+ }),
87
+ doctor: async ({ target, packageRoot, options }) => {
88
+ const result = await runDoctor({
89
+ target,
90
+ packageRoot,
91
+ adoptPaths: options.adopt,
92
+ strict: options.strict,
93
+ fix: options.fix,
94
+ });
95
+ return { result, exitCode: result.ok ? 0 : 1 };
96
+ },
97
+ route: async ({ target, packageRoot, options }) => ({
98
+ result: await runRoute({
99
+ target,
100
+ packageRoot,
101
+ workType: options.workType,
102
+ surfaces: options.surfaces,
103
+ risks: options.risks,
104
+ platforms: options.platforms,
105
+ behaviorChange: options.behaviorChange,
106
+ executableChange: options.executableChange,
107
+ taskId: options.taskId,
108
+ }),
109
+ exitCode: 0,
110
+ }),
111
+ activate: async ({ target, packageRoot }) => ({
112
+ result: await runActivate({ target, packageRoot }),
113
+ exitCode: 0,
114
+ }),
115
+ preflight: async ({ target, packageRoot, options }) => {
116
+ const result = await runPreflight({ target, packageRoot, strict: options.strict, taskId: options.taskId });
117
+ return { result, exitCode: result.status === "READY" ? 0 : 1 };
118
+ },
119
+ advance: async ({ target, packageRoot, options, authorityContext, runtimeContext }) => ({
120
+ result: await runAdvance({
121
+ target,
122
+ packageRoot,
123
+ to: options.to,
124
+ taskId: options.taskId,
125
+ authorityContext,
126
+ runtimeContext,
127
+ }),
128
+ exitCode: 0,
129
+ }),
130
+ next: async ({ target, packageRoot, options, authorityContext, runtimeContext }) => ({
131
+ result: await runNext({ target, packageRoot, taskId: options.taskId, authorityContext, runtimeContext }),
132
+ exitCode: 0,
133
+ }),
134
+ continuity: async ({ target, packageRoot, options }) => ({
135
+ result: await runContinuity({ target, packageRoot, taskId: options.taskId }),
136
+ exitCode: 0,
137
+ }),
138
+ "record-continuity": async ({ target, packageRoot, options }) => ({
139
+ result: await runRecordContinuity({
140
+ target,
141
+ packageRoot,
142
+ focusId: options.continuityFocusId,
143
+ focusSummary: options.continuityFocusSummary,
144
+ remaining: options.continuityRemaining,
145
+ knownIssues: options.continuityKnownIssues,
146
+ changedAreas: options.continuityChangedAreas,
147
+ inspectFirst: options.continuityInspectFirst,
148
+ resumeNote: options.continuityResumeNote,
149
+ taskId: options.taskId,
150
+ }),
151
+ exitCode: 0,
152
+ }),
153
+ "reconcile-continuity": async ({ target, packageRoot, options }) => ({
154
+ result: await runReconcileContinuity({ target, packageRoot, taskId: options.taskId }),
155
+ exitCode: 0,
156
+ }),
157
+ "clear-continuity": async ({ target, options }) => ({
158
+ result: await runClearContinuity({ target, taskId: options.taskId }),
159
+ exitCode: 0,
160
+ }),
161
+ "prepare-completion": async ({ target, packageRoot, options, authorityContext, runtimeContext }) => ({
162
+ result: await runPrepareCompletion({ target, packageRoot, taskId: options.taskId, authorityContext, runtimeContext }),
163
+ exitCode: 0,
164
+ }),
165
+ "run-check": async ({ target, packageRoot, options, authorityContext, runtimeContext }) => {
166
+ const result = await runCheck({
167
+ target,
168
+ packageRoot,
169
+ id: options.checkId,
170
+ requirement: options.checkRequirement,
171
+ argv: options.commandArgv,
172
+ details: options.checkDetails ?? undefined,
173
+ timeoutMs: options.timeoutMs ?? undefined,
174
+ taskId: options.taskId,
175
+ authorityContext,
176
+ runtimeContext,
177
+ });
178
+ return { result, exitCode: result.check.status === "passed" ? 0 : 1 };
179
+ },
180
+ "run-action": async ({ target, packageRoot, options, authorityContext, runtimeContext }) => {
181
+ const result = await runAction({ target, packageRoot, taskId: options.taskId,
182
+ actionId: options.actionId, capability: options.actionCapability,
183
+ effectClass: options.actionEffectClass, actionTarget: options.actionTarget,
184
+ idempotencyKey: options.actionIdempotencyKey, requirement: options.actionRequirement,
185
+ requiredForCompletion: options.actionRequiredForCompletion, argv: options.commandArgv,
186
+ approvalId: options.approvalId, timeoutMs: options.timeoutMs,
187
+ authorityContext, runtimeContext });
188
+ return { result, exitCode: result.action.state === "COMMITTED" ? 0 : 1 };
189
+ },
190
+ "action-propose": async ({ target, packageRoot, options }) => ({ result: await runActionPropose({
191
+ target, packageRoot, taskId: options.taskId, input: { actionId: options.actionId,
192
+ capability: options.actionCapability, effectClass: options.actionEffectClass,
193
+ target: options.actionTarget, operation: options.actionOperation,
194
+ idempotencyKey: options.actionIdempotencyKey, requirement: options.actionRequirement,
195
+ requiredForCompletion: options.actionRequiredForCompletion },
196
+ }), exitCode: 0 }),
197
+ "action-record": async ({ target, packageRoot, options }) => ({ result: await runActionRecord({
198
+ target, packageRoot, taskId: options.taskId, actionId: options.actionId,
199
+ state: options.actionState, provenance: options.actionProvenance,
200
+ evidenceRef: options.actionEvidenceRef,
201
+ }), exitCode: 0 }),
202
+ "action-show": async ({ target, packageRoot, options }) => ({ result: await runActionShow({
203
+ target, packageRoot, taskId: options.taskId, actionId: options.actionId,
204
+ }), exitCode: 0 }),
205
+ "action-authorize": async ({ target, packageRoot, options, authorityContext }) => ({
206
+ result: await runActionAuthorize({
207
+ target,
208
+ packageRoot,
209
+ taskId: options.taskId,
210
+ actionId: options.actionId,
211
+ approvalId: options.approvalId,
212
+ // Trusted authority arrives out-of-band only; never from actor input.
213
+ authorityContext,
214
+ }),
215
+ exitCode: 0,
216
+ }),
217
+ "action-verify": async ({ target, packageRoot, options }) => ({ result: await runActionVerify({
218
+ target, packageRoot, taskId: options.taskId, actionId: options.actionId,
219
+ evidenceRef: options.actionEvidenceRef,
220
+ }), exitCode: 0 }),
221
+ "action-reconcile": async ({ target, packageRoot, options, authorityContext }) => ({ result: await runActionReconcile({
222
+ target, packageRoot, taskId: options.taskId, actionId: options.actionId,
223
+ outcome: options.reconciliationOutcome, evidenceRefs: options.evidenceRefs ?? [],
224
+ observedAt: options.observedAt,
225
+ // Trusted settlement authority travels only through the out-of-band
226
+ // executor parameter; actor input can never supply it.
227
+ authorityContext,
228
+ }), exitCode: 0 }),
229
+ metrics: async ({ target, packageRoot, options }) => ({ result: await runMetrics({ target, packageRoot, taskId: options.taskId }), exitCode: 0 }),
230
+ eval: async ({ target, packageRoot, options }) => {
231
+ const result = await runEval({ target, packageRoot, taskId: options.taskId, scenarioPath: options.scenarioPath });
232
+ return { result, exitCode: result.result === "PASS" ? 0 : 1 };
233
+ },
234
+ "approval-request": async ({ target, packageRoot, options }) => ({ result: await runApprovalRequest({ target, packageRoot, taskId: options.taskId, approvalId: options.approvalId, actionId: options.actionId, reason: options.reason }), exitCode: 0 }),
235
+ "approval-resolve": async ({ target, packageRoot, options, authorityContext }) => ({ result: await runApprovalResolve({ target, packageRoot, taskId: options.taskId, approvalId: options.approvalId, decision: options.approvalDecision, authorityKind: options.approvalAuthorityKind, hostGrantRef: options.hostGrantRef, reason: options.reason, authorityContext }), exitCode: 0 }),
236
+ "record-check": async ({ target, packageRoot, options }) => ({
237
+ result: await runRecordCheck({
238
+ target,
239
+ packageRoot,
240
+ id: options.checkId,
241
+ kind: options.checkKind ?? "command",
242
+ requirement: options.checkRequirement,
243
+ status: options.checkStatus,
244
+ evidenceKind: options.checkEvidenceKind,
245
+ command: options.checkCommand ?? undefined,
246
+ result: options.checkResult ?? undefined,
247
+ ...(options.checkExitCode === null ? {} : { exitCode: options.checkExitCode }),
248
+ details: options.checkDetails ?? undefined,
249
+ executionRef: options.checkExecutionRef ?? undefined,
250
+ provenance: options.checkProvenance ?? undefined,
251
+ taskId: options.taskId,
252
+ }),
253
+ exitCode: 0,
254
+ }),
255
+ "record-terminal-result": async ({ target, packageRoot, options }) => ({
256
+ result: await runRecordTerminalResult({
257
+ target,
258
+ packageRoot,
259
+ requirement: options.checkRequirement,
260
+ type: options.checkType,
261
+ status: options.checkStatus,
262
+ source: options.checkSource ?? options.checkCommand,
263
+ result: options.checkResult,
264
+ details: options.checkDetails ?? undefined,
265
+ taskId: options.taskId,
266
+ }),
267
+ exitCode: 0,
268
+ }),
269
+ "record-diagnosis": async ({ target, packageRoot, options }) => ({
270
+ result: await runRecordDiagnosis({
271
+ target,
272
+ packageRoot,
273
+ file: options.file ?? null,
274
+ hypothesis: options.hypothesis,
275
+ failureClass: options.failureClass,
276
+ evidenceRefs: options.evidenceRefs,
277
+ settledBy: options.settledBy,
278
+ nextSafeAction: options.nextSafeAction,
279
+ taskId: options.taskId,
280
+ }),
281
+ exitCode: 0,
282
+ }),
283
+ "record-intervention": async ({ target, packageRoot, options }) => ({
284
+ result: await runRecordIntervention({
285
+ target,
286
+ packageRoot,
287
+ file: options.file ?? null,
288
+ taskId: options.taskId,
289
+ }),
290
+ exitCode: 0,
291
+ }),
292
+ "record-hypothesis-disposition": async ({ target, packageRoot, options }) => ({
293
+ result: await runRecordHypothesisDisposition({
294
+ target,
295
+ packageRoot,
296
+ hypothesis: options.hypothesis,
297
+ status: options.dispositionStatus,
298
+ evidenceRefs: options.evidenceRefs,
299
+ reason: options.reason,
300
+ taskId: options.taskId,
301
+ }),
302
+ exitCode: 0,
303
+ }),
304
+ history: async ({ target, packageRoot, options }) => {
305
+ const result = await runHistory({
306
+ target,
307
+ packageRoot,
308
+ taskId: options.taskId,
309
+ filters: {
310
+ type: options.historyType ?? null,
311
+ phase: options.historyPhase ?? null,
312
+ failures: Boolean(options.historyFailures),
313
+ checks: Boolean(options.historyChecks),
314
+ since: options.historySince ?? null,
315
+ until: options.historyUntil ?? null,
316
+ limit: Number.isInteger(options.historyLimit) ? options.historyLimit : null,
317
+ },
318
+ });
319
+ return { result, exitCode: result.integrity.valid ? 0 : 1 };
320
+ },
321
+ trace: async ({ target, packageRoot, options }) => {
322
+ const result = await runTrace({ target, packageRoot, taskId: options.taskId });
323
+ return { result, exitCode: result.integrity.valid ? 0 : 1 };
324
+ },
325
+ reflect: async ({ target, packageRoot, options }) => {
326
+ const result = await runReflect({ target, packageRoot, taskId: options.taskId });
327
+ return { result, exitCode: result.status === "STALLED" ? 1 : 0 };
328
+ },
329
+ progress: async ({ target, packageRoot, options }) => {
330
+ const result = await runProgress({ target, packageRoot, taskId: options.taskId });
331
+ return { result, exitCode: result.status === "STALLED" ? 1 : 0 };
332
+ },
333
+ "record-decision-criterion": async ({ target, packageRoot, options }) => ({
334
+ result: await runRecordDecisionCriterion({
335
+ target,
336
+ packageRoot,
337
+ decision: options.decision,
338
+ settledBy: options.settledBy,
339
+ taskId: options.taskId,
340
+ }),
341
+ exitCode: 0,
342
+ }),
343
+ complete: async ({ target, packageRoot, options, authorityContext, runtimeContext }) => {
344
+ const result = await runComplete({
345
+ target,
346
+ packageRoot,
347
+ strict: options.strict,
348
+ taskId: options.taskId,
349
+ authorityContext,
350
+ runtimeContext,
351
+ });
352
+ return { result, exitCode: result.status === "VALID" ? 0 : 1 };
353
+ },
354
+ audit: async ({ target, packageRoot, options, authorityContext, runtimeContext }) => {
355
+ const result = await runAudit({
356
+ target,
357
+ packageRoot,
358
+ strict: options.strict,
359
+ taskId: options.taskId,
360
+ authorityContext,
361
+ runtimeContext,
362
+ });
363
+ return { result, exitCode: result.status === "VALID" ? 0 : 1 };
364
+ },
365
+ report: async ({ target, packageRoot, options, authorityContext, runtimeContext }) => {
366
+ const result = await runReport({
367
+ target,
368
+ packageRoot,
369
+ strict: options.strict,
370
+ taskId: options.taskId,
371
+ authorityContext,
372
+ runtimeContext,
373
+ });
374
+ return { result, exitCode: result.verdict === "VALID" ? 0 : 1 };
375
+ },
376
+ policy: async ({ target, packageRoot, options }) => ({
377
+ result: await runPolicy({ target, packageRoot, name: options.policy, taskId: options.taskId }),
378
+ exitCode: 0,
379
+ }),
380
+ "policy-discover": async ({ target, packageRoot, options }) => ({
381
+ result: await runPolicyDiscover({ target, packageRoot, write: options.write }),
382
+ exitCode: 0,
383
+ }),
384
+ "policy-status": async ({ target, packageRoot, options }) => {
385
+ const result = await runPolicyStatus({ target, packageRoot, taskId: options.taskId });
386
+ return { result, exitCode: result.status === "VALID" ? 0 : 1 };
387
+ },
388
+ "policy-diff": async ({ target, packageRoot, options }) => ({
389
+ result: await runPolicyDiff({ target, packageRoot, taskId: options.taskId, before: options.before, after: options.after }),
390
+ exitCode: 0,
391
+ }),
392
+ "rule-verify": async ({ target, packageRoot, options }) => {
393
+ const result = await runRuleVerify({ target, packageRoot, rule: options.rule });
394
+ return { result, exitCode: result.status === "VALID" ? 0 : 1 };
395
+ },
396
+ baseline: async ({ target, packageRoot, options }) => ({
397
+ result: await runBaseline({
398
+ target,
399
+ packageRoot,
400
+ record: options.record,
401
+ update: options.update,
402
+ policyResetAuthorized: options.policyResetAuthorized,
403
+ }),
404
+ exitCode: 0,
405
+ }),
406
+ "profile-interview": async ({ target, packageRoot, options }) => ({
407
+ result: await runProfileInterview({ target, packageRoot, dryRun: options.dryRun }),
408
+ exitCode: 0,
409
+ }),
410
+ bundle: async ({ target, packageRoot, options }) => ({
411
+ result: await runBundle({ target, packageRoot, taskId: options.taskId }),
412
+ exitCode: 0,
413
+ }),
414
+ inspect: async ({ target, packageRoot, options, authorityContext, runtimeContext }) => {
415
+ const result = await inspectTarget({
416
+ target,
417
+ packageRoot,
418
+ contractFile: options.contractFile,
419
+ taskId: options.taskId,
420
+ authorityContext,
421
+ runtimeContext,
422
+ });
423
+ return { result, exitCode: result.ok ? 0 : 1 };
424
+ },
425
+ "validate-receipt": async ({ target, packageRoot, options }) => ({
426
+ result: await runValidateReceipt({ target, packageRoot, file: options.file, taskId: options.taskId }),
427
+ exitCode: 0,
428
+ }),
429
+ "validate-protocol": async ({ target, packageRoot, options }) => {
430
+ const result = await runValidateProtocol({
431
+ target,
432
+ packageRoot,
433
+ stateFile: options.stateFile,
434
+ receiptFile: options.receiptFile,
435
+ routeFile: options.routeFile,
436
+ contractFile: options.contractFile,
437
+ continuityFile: options.continuityFile,
438
+ taskBriefFiles: options.taskBriefFiles,
439
+ delegatedResultFiles: options.delegatedResultFiles,
440
+ taskId: options.taskId,
441
+ });
442
+ return { result, exitCode: result.status === "VALID" ? 0 : 1 };
443
+ },
444
+ status: async ({ target, packageRoot, options }) => ({
445
+ result: await runStatus({ target, packageRoot, contractFile: options.contractFile, taskId: options.taskId }),
446
+ exitCode: 0,
447
+ }),
448
+ "validate-state": async ({ target, packageRoot, options }) => {
449
+ const result = await runValidateState({ target, packageRoot, taskId: options.taskId });
450
+ return { result, exitCode: result.ok ? 0 : 1 };
451
+ },
452
+ "clear-state": async ({ target, options }) => ({
453
+ result: await runClearState({ target, taskId: options.taskId }),
454
+ exitCode: 0,
455
+ }),
456
+ "task-create": async ({ target, packageRoot, options }) => ({
457
+ result: await runTaskCreate({
458
+ target,
459
+ packageRoot,
460
+ taskId: options.taskId,
461
+ claims: options.claims,
462
+ contractFile: options.contractFile,
463
+ }),
464
+ exitCode: 0,
465
+ }),
466
+ "task-list": async ({ target, packageRoot }) => ({
467
+ result: await runTaskList({ target, packageRoot }),
468
+ exitCode: 0,
469
+ }),
470
+ "task-show": async ({ target, packageRoot, options }) => ({
471
+ result: await runTaskShow({ target, packageRoot, taskId: options.taskId }),
472
+ exitCode: 0,
473
+ }),
474
+ "task-lock-status": async ({ target, packageRoot, options }) => ({
475
+ result: await runTaskLockStatus({ target, packageRoot, taskId: options.taskId }),
476
+ exitCode: 0,
477
+ }),
478
+ "task-scope": async ({ target, packageRoot, options }) => ({
479
+ result: await runTaskScope({
480
+ target,
481
+ packageRoot,
482
+ taskId: options.taskId,
483
+ claims: options.claims,
484
+ }),
485
+ exitCode: 0,
486
+ }),
487
+ "task-migrate": async ({ target, packageRoot, options }) => ({
488
+ result: await runTaskMigrate({ target, packageRoot, dryRun: options.dryRun }),
489
+ exitCode: 0,
490
+ }),
491
+ "migrate-protocol": async ({ target, packageRoot, options }) => ({
492
+ result: await runMigrateProtocol({ target, packageRoot, to: options.to, dryRun: options.dryRun }),
493
+ exitCode: 0,
494
+ }),
495
+ "task-unlock": async ({ target, packageRoot, options }) => ({
496
+ result: await runTaskUnlock({ target, packageRoot, taskId: options.taskId, force: options.force, staleOnly: options.staleOnly }),
497
+ exitCode: 0,
498
+ }),
499
+ "task-recover": async ({ target, packageRoot, options }) => ({
500
+ result: await runTaskRecover({
501
+ target,
502
+ packageRoot,
503
+ taskId: options.taskId,
504
+ acknowledgeRecovery: options.acknowledgeRecovery,
505
+ operatorAuthorized: options.operatorAuthorized,
506
+ }),
507
+ exitCode: 0,
508
+ }),
509
+ "task-resume": async ({ target, packageRoot, options }) => ({
510
+ result: await runTaskResume({ target, packageRoot, taskId: options.taskId, claims: options.claims }),
511
+ exitCode: 0,
512
+ }),
513
+ "task-repair-legacy-recovery": async ({ target, packageRoot, options }) => ({
514
+ result: await runTaskRepairLegacyRecovery({
515
+ target,
516
+ packageRoot,
517
+ taskId: options.taskId,
518
+ acknowledgeRecovery: options.acknowledgeRecovery,
519
+ }),
520
+ exitCode: 0,
521
+ }),
522
+ "reconcile-closure": async ({ target, packageRoot, options }) => ({
523
+ result: await reconcileClosure({
524
+ target,
525
+ packageRoot,
526
+ taskId: options.taskId,
527
+ checkId: options.checkId,
528
+ checkRequirement: options.checkRequirement,
529
+ checkDetails: options.checkDetails,
530
+ commandArgv: options.commandArgv,
531
+ }),
532
+ exitCode: 0,
533
+ }),
534
+ update: async ({ target, packageRoot, packageVersion, options }) => {
535
+ const result = await runUpdate({ target, dryRun: options.dryRun, packageRoot, packageVersion });
536
+ return { result, exitCode: result.conflicts.length === 0 ? 0 : 1 };
537
+ },
538
+ };
539
+
540
+ export const EXECUTOR_EXCEPTIONS = Object.freeze([
541
+ // Bootstrap/presentation-only behaviors intentionally without executors:
542
+ // none currently. Every canonical command definition must have an executor.
543
+ ]);
@@ -0,0 +1,107 @@
1
+ import { continuityOptionDefaults, validateContinuityOptions } from "./continuity-cli-options.js";
2
+
3
+ /**
4
+ * Transport-neutral option defaults shared by the CLI parser and the
5
+ * programmatic command runtime so every executor observes the same
6
+ * normalized input shape regardless of transport.
7
+ */
8
+ export function defaultCommandInputValues() {
9
+ return {
10
+ path: ".",
11
+ dryRun: false,
12
+ json: false,
13
+ strict: false,
14
+ fix: false,
15
+ adopt: [],
16
+ workType: null,
17
+ surfaces: [],
18
+ risks: [],
19
+ platforms: [],
20
+ behaviorChange: false,
21
+ executableChange: false,
22
+ to: null,
23
+ file: null,
24
+ contractFile: null,
25
+ routeFile: null,
26
+ stateFile: null,
27
+ receiptFile: null,
28
+ continuityFile: null,
29
+ taskBriefFiles: [],
30
+ delegatedResultFiles: [],
31
+ checkId: null,
32
+ checkKind: null,
33
+ checkRequirement: null,
34
+ checkStatus: null,
35
+ checkEvidenceKind: null,
36
+ checkCommand: null,
37
+ checkResult: null,
38
+ checkExitCode: null,
39
+ checkDetails: null,
40
+ checkExecutionRef: null,
41
+ checkProvenance: null,
42
+ commandArgv: [],
43
+ checkType: null,
44
+ checkSource: null,
45
+ policy: null,
46
+ taskId: null,
47
+ help: false,
48
+ version: false,
49
+ ...continuityOptionDefaults(),
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Canonical semantic validation shared by the CLI argv parser and
55
+ * programmatic integrations. JSON-Schema style checks cannot express these
56
+ * cross-field rules, so every transport must run this after its own parsing.
57
+ */
58
+ export function validateForgeLoopCommandInput({ command, input, help = false } = {}) {
59
+ const options = input ?? {};
60
+ if (!command) return;
61
+
62
+ if (command === "policy" && !options.policy) {
63
+ throw new Error("policy requires a name");
64
+ }
65
+ if (command !== "policy" && options.policy) {
66
+ throw new Error(`Policy name is not valid for ${command}`);
67
+ }
68
+ if (command === "bundle" && !options.taskId) {
69
+ throw new Error("bundle requires --task");
70
+ }
71
+ if (command === "task-create" && !options.taskId) {
72
+ throw new Error("task-create requires --task");
73
+ }
74
+
75
+ validateContinuityOptions(command, options);
76
+
77
+ if (command === "record-check" && !help) {
78
+ if (!options.checkId) throw new Error("record-check requires --id");
79
+ if (!options.checkRequirement) throw new Error("record-check requires --requirement");
80
+ if (!options.checkStatus) throw new Error("record-check requires --status");
81
+ if (!options.checkEvidenceKind) throw new Error("record-check requires --evidence-kind");
82
+ if (!options.checkCommand && !options.checkResult) throw new Error("record-check requires --command or --result");
83
+ }
84
+ if (command === "run-check" && !help) {
85
+ if (!options.checkId) throw new Error("run-check requires --id");
86
+ if (!options.checkRequirement) throw new Error("run-check requires --requirement");
87
+ if (options.checkKind || options.checkStatus || options.checkEvidenceKind || options.checkCommand
88
+ || options.checkResult || options.checkExitCode !== null || options.checkExecutionRef || options.checkProvenance) {
89
+ throw new Error("run-check accepts only --id, --requirement, --details, --timeout-ms, and -- <argv>");
90
+ }
91
+ if (!Array.isArray(options.commandArgv) || options.commandArgv.length === 0) {
92
+ throw new Error("run-check requires -- followed by an exact command argv");
93
+ }
94
+ }
95
+ if (command === "reconcile-closure" && !help) {
96
+ if (!options.taskId) throw new Error("reconcile-closure requires --task");
97
+ if (!options.checkId) throw new Error("reconcile-closure requires --id");
98
+ if (!options.checkRequirement) throw new Error("reconcile-closure requires --requirement");
99
+ if (options.checkKind || options.checkStatus || options.checkEvidenceKind || options.checkCommand
100
+ || options.checkResult || options.checkExitCode !== null || options.checkExecutionRef || options.checkProvenance) {
101
+ throw new Error("reconcile-closure accepts only --id, --requirement, --details, and -- <argv>");
102
+ }
103
+ if (!Array.isArray(options.commandArgv) || options.commandArgv.length === 0) {
104
+ throw new Error("reconcile-closure requires -- followed by an exact command argv");
105
+ }
106
+ }
107
+ }