@cassiomc1/forgeloop 1.12.0 → 1.14.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 (249) hide show
  1. package/.github/copilot-instructions.md +1 -1
  2. package/AGENTS.md +1 -1
  3. package/AGENT_COMPATIBILITY.md +8 -0
  4. package/CLAUDE.md +1 -1
  5. package/CONTRIBUTING.md +90 -0
  6. package/DOCS_INDEX.md +46 -12
  7. package/ENG/c-development-eng.md +112 -0
  8. package/ENG/cpp-development-eng.md +109 -0
  9. package/ENG/dotnet-aspnetcore-development-eng.md +401 -0
  10. package/ENG/go-development-eng.md +103 -0
  11. package/ENG/java-development-eng.md +125 -0
  12. package/ENG/nodejs-backend-development-eng.md +605 -0
  13. package/ENG/php-development-eng.md +104 -0
  14. package/ENG/rust-development-eng.md +422 -0
  15. package/ENG/sec-code-eng.md +7 -7
  16. package/ENG/sql-development-eng.md +108 -0
  17. package/ENG/swift-development-eng.md +111 -0
  18. package/ENG/typescript-development-eng.md +108 -0
  19. package/EXECUTION_STATE.md +12 -0
  20. package/GUIDE_ROUTER.md +418 -9
  21. package/LOOP_ENGINEERING.md +28 -2
  22. package/ORCHESTRATOR_INTEGRATION.md +9 -5
  23. package/PROTOCOL_INTEGRATION.md +55 -2
  24. package/QUALITY_SCORECARD.md +1 -0
  25. package/README.md +78 -52
  26. package/TERMINOLOGY.md +2 -0
  27. package/THIRD_PARTY_NOTICES.md +19 -7
  28. package/THREAT_MODEL.md +140 -1
  29. package/completions/_forgeloop +22 -4
  30. package/completions/forgeloop.bash +40 -4
  31. package/completions/forgeloop.fish +130 -1
  32. package/docs/ADVISORY_CONTEXT.md +25 -0
  33. package/docs/AGENT_BROWSER_ADAPTER.md +81 -0
  34. package/docs/AGENT_BROWSER_VERIFICATION.md +6 -0
  35. package/docs/AGENT_PROTOCOL_SUMMARY.md +81 -3
  36. package/docs/AGENT_SKILL.md +66 -0
  37. package/docs/ARTIFACT_REFERENCE.md +123 -0
  38. package/docs/AUDIT_UX.md +46 -0
  39. package/docs/BROWSER_VERIFICATION.md +136 -0
  40. package/docs/CLI_REFERENCE.md +392 -10
  41. package/docs/CODE_ATTESTATION.md +2 -2
  42. package/docs/DOCUMENTATION_GUIDE.md +34 -12
  43. package/docs/GETTING_STARTED.md +59 -0
  44. package/docs/JEV_BENCHMARKS.md +31 -0
  45. package/docs/MODEL_ROUTING.md +37 -0
  46. package/docs/OPENSRC_ADAPTER.md +241 -0
  47. package/docs/PACKAGE_CONTENTS.md +60 -19
  48. package/docs/PROVIDERS.md +126 -0
  49. package/docs/PROVIDER_ARCHITECTURE.md +199 -0
  50. package/docs/RECIPES.md +32 -0
  51. package/docs/RELEASE_CHECKLIST.md +66 -5
  52. package/docs/SECURITY_REVIEW.md +71 -0
  53. package/docs/SEMANTIC_DECISION_PLANE.md +71 -0
  54. package/docs/TEST_INTELLIGENCE.md +29 -0
  55. package/docs/TEST_PRUNING.md +14 -0
  56. package/docs/TROUBLESHOOTING.md +298 -3
  57. package/docs/UNIVERSAL_INTEGRATION.md +31 -0
  58. package/docs/assets/diagrams/forgeloop-code-attestation-flow.html +2 -2
  59. package/docs/assets/diagrams/forgeloop-code-attestation-flow.receipt.json +5 -5
  60. package/docs/assets/diagrams/forgeloop-code-attestation-flow.svg +1 -1
  61. package/docs/assets/diagrams/forgeloop-engineering-flow.html +39 -26
  62. package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +6 -6
  63. package/docs/assets/diagrams/forgeloop-engineering-flow.svg +26 -26
  64. package/docs/assets/diagrams/forgeloop-verification-trust-flow.html +2 -1
  65. package/docs/assets/diagrams/forgeloop-verification-trust-flow.receipt.json +5 -5
  66. package/docs/assets/diagrams/forgeloop-verification-trust-flow.svg +1 -1
  67. package/docs/diagrams/README.md +13 -9
  68. package/docs/diagrams/forgeloop-code-attestation-flow.workflow.json +1 -1
  69. package/docs/diagrams/forgeloop-engineering-flow.workflow.json +24 -19
  70. package/docs/diagrams/forgeloop-verification-trust-flow.workflow.json +1 -0
  71. package/docs/diagrams/reviews/forgeloop-code-attestation-flow.review.json +4 -4
  72. package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +4 -4
  73. package/docs/diagrams/reviews/forgeloop-verification-trust-flow.review.json +4 -4
  74. package/docs/documentation-manifest.json +1397 -0
  75. package/docs/protocol-requirements.json +101 -0
  76. package/package.json +46 -4
  77. package/schemas/config.schema.json +14 -0
  78. package/schemas/context-plan.schema.json +18 -0
  79. package/schemas/routing-input.schema.json +1 -1
  80. package/schemas/semantic-decision.schema.json +46 -0
  81. package/schemas/test-utility.schema.json +44 -0
  82. package/scripts/CI_VALIDATORS.md +84 -11
  83. package/scripts/benchmark-jev.mjs +5 -0
  84. package/scripts/benchmark-test-intelligence.mjs +4 -0
  85. package/scripts/generate-agent-protocol-summary.mjs +40 -1
  86. package/scripts/generate-forgeloop-skill.mjs +133 -0
  87. package/scripts/jev-smoke.mjs +19 -0
  88. package/skills/forgeloop/README.md +9 -0
  89. package/skills/forgeloop/SKILL.md +77 -0
  90. package/skills/forgeloop/references/lifecycle.md +9 -0
  91. package/skills/forgeloop/references/recovery.md +7 -0
  92. package/skills/forgeloop/references/verification.md +7 -0
  93. package/src/adapters/agent-browser/assertions.js +47 -0
  94. package/src/adapters/agent-browser/commands.js +54 -0
  95. package/src/adapters/agent-browser/index.js +3 -0
  96. package/src/adapters/agent-browser/locator.js +40 -0
  97. package/src/adapters/agent-browser/process.js +215 -0
  98. package/src/adapters/agent-browser/provider.js +313 -0
  99. package/src/adapters/emulated-services/constants.js +24 -0
  100. package/src/adapters/emulated-services/index.js +7 -0
  101. package/src/adapters/emulated-services/process.js +162 -0
  102. package/src/adapters/emulated-services/provider.js +282 -0
  103. package/src/adapters/opensrc/normalize.js +90 -0
  104. package/src/adapters/opensrc/process.js +248 -0
  105. package/src/adapters/opensrc/provider.js +338 -0
  106. package/src/adapters/opensrc/search.js +264 -0
  107. package/src/adapters/typesafe/client.js +28 -0
  108. package/src/adapters/typesafe/engine.js +63 -0
  109. package/src/adapters/typesafe/normalize.js +41 -0
  110. package/src/cli.js +108 -0
  111. package/src/commands/checkpoint-revalidate.js +176 -0
  112. package/src/commands/context-plan.js +38 -0
  113. package/src/commands/contract-create.js +264 -0
  114. package/src/commands/contract-revise.js +236 -0
  115. package/src/commands/decision-show.js +14 -0
  116. package/src/commands/decision-status.js +22 -0
  117. package/src/commands/discover.js +41 -0
  118. package/src/commands/doctor.js +15 -0
  119. package/src/commands/gate-record.js +205 -0
  120. package/src/commands/gate-revalidate.js +137 -0
  121. package/src/commands/model-route.js +32 -0
  122. package/src/commands/next.js +19 -7
  123. package/src/commands/route.js +146 -18
  124. package/src/commands/semantic-plan.js +17 -0
  125. package/src/commands/task-abandon.js +224 -0
  126. package/src/commands/task-create.js +84 -25
  127. package/src/commands/task-list.js +22 -2
  128. package/src/commands/task-migrate-contract-bootstrap-repair.js +288 -0
  129. package/src/commands/task-repair-contract-bootstrap.js +263 -0
  130. package/src/commands/test-inventory.js +5 -0
  131. package/src/commands/test-prune-plan.js +5 -0
  132. package/src/commands/test-prune-probe.js +5 -0
  133. package/src/commands/test-utility.js +5 -0
  134. package/src/commands/validate-protocol.js +10 -1
  135. package/src/config/guides.json +44 -0
  136. package/src/core/artifact-registry.js +24 -0
  137. package/src/core/audit-ux.js +514 -0
  138. package/src/core/browser-verification/constants.js +149 -0
  139. package/src/core/browser-verification/normalize.js +254 -0
  140. package/src/core/browser-verification/provider.js +519 -0
  141. package/src/core/browser-verification/service.js +115 -0
  142. package/src/core/build-script.js +151 -0
  143. package/src/core/c-cpp-project.js +143 -0
  144. package/src/core/checkpoint-revalidation.js +319 -0
  145. package/src/core/cli-command-definitions.js +249 -1
  146. package/src/core/command-executors.js +115 -3
  147. package/src/core/command-input.js +212 -102
  148. package/src/core/completion-artifacts.js +14 -5
  149. package/src/core/completion.js +4 -6
  150. package/src/core/config.js +3 -0
  151. package/src/core/context-compiler/budget.js +9 -0
  152. package/src/core/context-compiler/candidates.js +39 -0
  153. package/src/core/context-compiler/compiler.js +63 -0
  154. package/src/core/context-compiler/fingerprint.js +11 -0
  155. package/src/core/context-compiler/policy.js +13 -0
  156. package/src/core/context-compiler/result.js +23 -0
  157. package/src/core/contract-bootstrap-recovery.js +655 -0
  158. package/src/core/contract-presets.js +82 -0
  159. package/src/core/contract-revision.js +210 -0
  160. package/src/core/decision/artifact.js +69 -0
  161. package/src/core/decision/benchmarks.js +103 -0
  162. package/src/core/decision/cache.js +27 -0
  163. package/src/core/decision/constants.js +58 -0
  164. package/src/core/decision/cutover.js +34 -0
  165. package/src/core/decision/engine.js +22 -0
  166. package/src/core/decision/errors.js +68 -0
  167. package/src/core/decision/events.js +101 -0
  168. package/src/core/decision/freshness.js +19 -0
  169. package/src/core/decision/normalizers/index.js +115 -0
  170. package/src/core/decision/policy.js +18 -0
  171. package/src/core/decision/projection.js +16 -0
  172. package/src/core/decision/question-registry.js +201 -0
  173. package/src/core/decision/request.js +26 -0
  174. package/src/core/decision/resolver.js +130 -0
  175. package/src/core/decision/result.js +58 -0
  176. package/src/core/decision/service.js +156 -0
  177. package/src/core/decision/state-builder.js +65 -0
  178. package/src/core/decision/task-bindings.js +30 -0
  179. package/src/core/decision/test-provider.js +32 -0
  180. package/src/core/decision/thresholds.js +15 -0
  181. package/src/core/error-codes.js +281 -3
  182. package/src/core/events.js +226 -57
  183. package/src/core/evidence-readiness.js +9 -0
  184. package/src/core/execution-prerequisites.js +14 -0
  185. package/src/core/execution-profile.js +63 -38
  186. package/src/core/filesystem.js +1 -10
  187. package/src/core/gate-provenance.js +124 -0
  188. package/src/core/go-project.js +206 -0
  189. package/src/core/integration-invocation-policy.js +27 -4
  190. package/src/core/integration-resources.js +86 -61
  191. package/src/core/java-project.js +403 -0
  192. package/src/core/model-router/constants.js +10 -0
  193. package/src/core/model-router/policy.js +103 -0
  194. package/src/core/model-router/router.js +37 -0
  195. package/src/core/multi-language-project.js +117 -0
  196. package/src/core/next-action-model.js +58 -0
  197. package/src/core/next-action-phases.js +130 -42
  198. package/src/core/next-action-refresh.js +43 -9
  199. package/src/core/next-action-review-phase.js +7 -2
  200. package/src/core/next-action.js +35 -7
  201. package/src/core/next-explanation.js +63 -0
  202. package/src/core/phase.js +128 -10
  203. package/src/core/php-project.js +85 -0
  204. package/src/core/preflight-consistency.js +23 -9
  205. package/src/core/preflight-loaders.js +37 -5
  206. package/src/core/project-detection.js +1760 -52
  207. package/src/core/protocol-info.js +65 -0
  208. package/src/core/protocol.js +20 -0
  209. package/src/core/reconcile-closure.js +132 -53
  210. package/src/core/recovery-history.js +1 -0
  211. package/src/core/resumability.js +154 -44
  212. package/src/core/route-artifact.js +15 -1
  213. package/src/core/router.js +223 -4
  214. package/src/core/runtime-context.js +118 -61
  215. package/src/core/rust-project.js +400 -0
  216. package/src/core/schema-validation.js +3 -0
  217. package/src/core/security-review/constants.js +64 -0
  218. package/src/core/security-review/normalize.js +245 -0
  219. package/src/core/security-review/provider.js +204 -0
  220. package/src/core/security-review/service.js +134 -0
  221. package/src/core/semantic-planning/constants.js +19 -0
  222. package/src/core/semantic-planning/projection.js +94 -0
  223. package/src/core/semantic-planning/service.js +15 -0
  224. package/src/core/sources.js +37 -0
  225. package/src/core/sql-project.js +141 -0
  226. package/src/core/swift-project.js +200 -0
  227. package/src/core/task-claim-state.js +201 -1
  228. package/src/core/task-conflict-inspection.js +31 -5
  229. package/src/core/task-paths.js +13 -0
  230. package/src/core/task-recovery.js +1 -0
  231. package/src/core/templates.js +3 -0
  232. package/src/core/test-intelligence/benchmarks.js +68 -0
  233. package/src/core/test-intelligence/inventory.js +73 -0
  234. package/src/core/test-intelligence/prune.js +90 -0
  235. package/src/core/test-intelligence/semantic-state.js +15 -0
  236. package/src/core/test-intelligence/service.js +40 -0
  237. package/src/core/test-intelligence/utility.js +50 -0
  238. package/src/core/trace.js +11 -7
  239. package/src/core/transaction.js +1 -0
  240. package/src/core/typescript-project.js +349 -0
  241. package/src/core/xml-structure.js +123 -0
  242. package/src/integration.d.ts +492 -0
  243. package/src/integration.js +54 -0
  244. package/src/providers/README.md +47 -0
  245. package/src/providers/capabilities.js +46 -0
  246. package/src/providers/errors.js +15 -0
  247. package/src/providers/index.js +29 -0
  248. package/src/providers/json-snapshot.js +105 -0
  249. package/src/providers/registry.js +152 -0
@@ -0,0 +1,41 @@
1
+ import { normalizeDecisionResult } from "../../core/decision/result.js";
2
+ import { safeDecisionError } from "../../core/decision/errors.js";
3
+
4
+ function finiteProbability(value) {
5
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
6
+ }
7
+
8
+ function confidenceFromAnswer(answer) {
9
+ if (!answer || typeof answer !== "object" || Array.isArray(answer)) return null;
10
+ if (finiteProbability(answer.confidence)) return answer.confidence;
11
+ if (answer.type === "noul" && finiteProbability(answer.noul)) {
12
+ return Math.max(answer.noul, 1 - answer.noul);
13
+ }
14
+ return null;
15
+ }
16
+
17
+ // The live TypeSafe SystemOne result carries per-answer confidence inside each
18
+ // answer (choice.confidence, or the noul judgment probability itself) and no
19
+ // top-level confidence map; translate that into the canonical
20
+ // answer-name -> confidence shape ForgeLoop's decision layer consumes. A
21
+ // provider-reported top-level map remains authoritative per key when present.
22
+ function deriveTypesafeConfidence(raw) {
23
+ const answers = raw?.answers;
24
+ const derived = answers && typeof answers === "object" && !Array.isArray(answers)
25
+ ? Object.fromEntries(Object.entries(answers).map(([name, answer]) => [name, confidenceFromAnswer(answer)]))
26
+ : {};
27
+ const provided = raw?.confidence;
28
+ if (!provided || typeof provided !== "object" || Array.isArray(provided)) return derived;
29
+ for (const [name, value] of Object.entries(provided)) {
30
+ if (finiteProbability(value)) derived[name] = value;
31
+ }
32
+ return derived;
33
+ }
34
+
35
+ export function normalizeTypesafeResult(raw, questionSet) {
36
+ try {
37
+ return normalizeDecisionResult({ ...raw, confidence: deriveTypesafeConfidence(raw) }, { questionSet });
38
+ } catch (error) {
39
+ throw safeDecisionError(error, "E_DECISION_RESULT_INVALID");
40
+ }
41
+ }
package/src/cli.js CHANGED
@@ -7,6 +7,7 @@ import { fileURLToPath } from "node:url";
7
7
  import { formatStatusResult } from "./commands/status.js";
8
8
  import { formatValidateStateResult } from "./commands/validate-state.js";
9
9
  import { formatClearStateResult } from "./commands/clear-state.js";
10
+ import { formatCheckpointRevalidateResult } from "./commands/checkpoint-revalidate.js";
10
11
  import { formatInspectResult } from "./commands/inspect.js";
11
12
  import { formatRouteResult } from "./commands/route.js";
12
13
  import { formatValidateProtocolResult } from "./commands/validate-protocol.js";
@@ -54,6 +55,9 @@ import { formatReflectResult } from "./commands/reflect.js";
54
55
  import { formatProgressResult } from "./commands/progress.js";
55
56
  import { formatRecordDecisionCriterionResult } from "./commands/record-decision-criterion.js";
56
57
  import { formatNextActionResult, formatCompactNextActionResult } from "./commands/next.js";
58
+ import { formatDiscoverResult } from "./commands/discover.js";
59
+ import { formatContractCreateResult } from "./commands/contract-create.js";
60
+ import { formatContractReviseResult } from "./commands/contract-revise.js";
57
61
  import { formatContinuityResult } from "./commands/continuity.js";
58
62
  import { formatRecordContinuityResult } from "./commands/record-continuity.js";
59
63
  import { formatReconcileContinuityResult } from "./commands/reconcile-continuity.js";
@@ -66,10 +70,13 @@ import { formatTaskMigrateResult } from "./commands/task-migrate.js";
66
70
  import { formatMigrateProtocolResult } from "./commands/migrate-protocol.js";
67
71
  import { formatTaskUnlockResult } from "./commands/task-unlock.js";
68
72
  import { formatTaskRecoverResult } from "./commands/task-recover.js";
73
+ import { formatTaskAbandonResult } from "./commands/task-abandon.js";
69
74
  import { formatTaskResumeResult } from "./commands/task-resume.js";
70
75
  import {
71
76
  formatTaskRepairLegacyRecoveryResult,
72
77
  } from "./commands/task-repair-legacy-recovery.js";
78
+ import { formatTaskRepairContractBootstrapResult } from "./commands/task-repair-contract-bootstrap.js";
79
+ import { formatTaskMigrateContractBootstrapRepairResult } from "./commands/task-migrate-contract-bootstrap-repair.js";
73
80
  import { formatTaskLockStatusResult } from "./commands/task-lock-status.js";
74
81
  import { formatProtocolInfoResult } from "./commands/protocol-info.js";
75
82
  import { formatWorkspaceBindResult } from "./commands/workspace-bind.js";
@@ -92,6 +99,17 @@ import {
92
99
  } from "./commands/repository-index.js";
93
100
  import { defaultCommandInputValues, validateForgeLoopCommandInput } from "./core/command-input.js";
94
101
  import { COMMAND_EXECUTORS } from "./core/command-executors.js";
102
+ import { formatGateRecordResult } from "./commands/gate-record.js";
103
+ import { formatGateRevalidateResult } from "./commands/gate-revalidate.js";
104
+ import { formatDecisionStatusResult } from "./commands/decision-status.js";
105
+ import { formatDecisionShowResult } from "./commands/decision-show.js";
106
+ import { formatContextPlanResult } from "./commands/context-plan.js";
107
+ import { formatModelRouteResult } from "./commands/model-route.js";
108
+ import { formatSemanticPlanResult } from "./commands/semantic-plan.js";
109
+ import { formatTestInventoryResult } from "./commands/test-inventory.js";
110
+ import { formatTestUtilityResult } from "./commands/test-utility.js";
111
+ import { formatTestPrunePlanResult } from "./commands/test-prune-plan.js";
112
+ import { formatTestPruneProbeResult } from "./commands/test-prune-probe.js";
95
113
  import { resolveTarget } from "./core/filesystem.js";
96
114
  import { getPackageRoot } from "./core/templates.js";
97
115
  import { CLI_COMMAND_DEFINITIONS, buildOptionLookup, getPositionalDefinitions } from "./core/cli-command-definitions.js";
@@ -349,11 +367,81 @@ function renderJsonOr(options, result, formatter) {
349
367
  }
350
368
 
351
369
  export const COMMAND_HANDLERS = Object.freeze({
370
+ discover: async ({ target, packageRoot, options }) => {
371
+ const { result } = await COMMAND_EXECUTORS.discover({ target, packageRoot, options });
372
+ renderJsonOr(options, result, formatDiscoverResult);
373
+ return 0;
374
+ },
375
+ "contract-create": async ({ target, packageRoot, options }) => {
376
+ const { result } = await COMMAND_EXECUTORS["contract-create"]({ target, packageRoot, options });
377
+ renderJsonOr(options, result, formatContractCreateResult);
378
+ return 0;
379
+ },
380
+ "contract-revise": async ({ target, packageRoot, options }) => {
381
+ const { result } = await COMMAND_EXECUTORS["contract-revise"]({ target, packageRoot, options });
382
+ renderJsonOr(options, result, formatContractReviseResult);
383
+ return 0;
384
+ },
385
+ "gate-record": async ({ target, packageRoot, options }) => {
386
+ const { result } = await COMMAND_EXECUTORS["gate-record"]({ target, packageRoot, options });
387
+ renderJsonOr(options, result, formatGateRecordResult);
388
+ return 0;
389
+ },
390
+ "gate-revalidate": async ({ target, packageRoot, options }) => {
391
+ const { result } = await COMMAND_EXECUTORS["gate-revalidate"]({ target, packageRoot, options });
392
+ renderJsonOr(options, result, formatGateRevalidateResult);
393
+ return 0;
394
+ },
352
395
  "protocol-info": async ({ packageVersion, options }) => {
353
396
  const { result } = await COMMAND_EXECUTORS["protocol-info"]({ packageVersion, options });
354
397
  renderJsonOr(options, result, formatProtocolInfoResult);
355
398
  return 0;
356
399
  },
400
+ "decision-status": async ({ target, packageRoot, options }) => {
401
+ const { result } = await COMMAND_EXECUTORS["decision-status"]({ target, packageRoot, options });
402
+ renderJsonOr(options, result, formatDecisionStatusResult);
403
+ return 0;
404
+ },
405
+ "decision-show": async ({ target, packageRoot, options }) => {
406
+ const { result } = await COMMAND_EXECUTORS["decision-show"]({ target, packageRoot, options });
407
+ renderJsonOr(options, result, formatDecisionShowResult);
408
+ return 0;
409
+ },
410
+ "context-plan": async ({ options }) => {
411
+ const { result } = await COMMAND_EXECUTORS["context-plan"]({ options });
412
+ renderJsonOr(options, result, formatContextPlanResult);
413
+ return 0;
414
+ },
415
+ "model-route": async ({ options }) => {
416
+ const { result } = await COMMAND_EXECUTORS["model-route"]({ options });
417
+ renderJsonOr(options, result, formatModelRouteResult);
418
+ return 0;
419
+ },
420
+ "semantic-plan": async ({ options }) => {
421
+ const { result } = await COMMAND_EXECUTORS["semantic-plan"]({ options });
422
+ renderJsonOr(options, result, formatSemanticPlanResult);
423
+ return 0;
424
+ },
425
+ "test-inventory": async ({ target, options }) => {
426
+ const { result } = await COMMAND_EXECUTORS["test-inventory"]({ target, options });
427
+ renderJsonOr(options, result, formatTestInventoryResult);
428
+ return 0;
429
+ },
430
+ "test-utility": async ({ target, packageRoot, options }) => {
431
+ const { result } = await COMMAND_EXECUTORS["test-utility"]({ target, packageRoot, options });
432
+ renderJsonOr(options, result, formatTestUtilityResult);
433
+ return 0;
434
+ },
435
+ "test-prune-plan": async ({ target, packageRoot, options }) => {
436
+ const { result } = await COMMAND_EXECUTORS["test-prune-plan"]({ target, packageRoot, options });
437
+ renderJsonOr(options, result, formatTestPrunePlanResult);
438
+ return 0;
439
+ },
440
+ "test-prune-probe": async ({ target, packageRoot, options }) => {
441
+ const { result } = await COMMAND_EXECUTORS["test-prune-probe"]({ target, packageRoot, options });
442
+ renderJsonOr(options, result, formatTestPruneProbeResult);
443
+ return 0;
444
+ },
357
445
  init: async ({ target, packageRoot, packageVersion, options }) => {
358
446
  const { result } = await COMMAND_EXECUTORS.init({ target, packageRoot, packageVersion, options });
359
447
  printActions(result.actions);
@@ -784,11 +872,31 @@ export const COMMAND_HANDLERS = Object.freeze({
784
872
  renderJsonOr(options, result, formatTaskRecoverResult);
785
873
  return 0;
786
874
  },
875
+ "task-abandon": async ({ target, packageRoot, options }) => {
876
+ const { result } = await COMMAND_EXECUTORS["task-abandon"]({ target, packageRoot, options });
877
+ renderJsonOr(options, result, formatTaskAbandonResult);
878
+ return 0;
879
+ },
787
880
  "task-resume": async ({ target, packageRoot, options }) => {
788
881
  const { result } = await COMMAND_EXECUTORS["task-resume"]({ target, packageRoot, options });
789
882
  renderJsonOr(options, result, formatTaskResumeResult);
790
883
  return 0;
791
884
  },
885
+ "task-repair-contract-bootstrap": async ({ target, packageRoot, options }) => {
886
+ const { result } = await COMMAND_EXECUTORS["task-repair-contract-bootstrap"]({ target, packageRoot, options });
887
+ renderJsonOr(options, result, formatTaskRepairContractBootstrapResult);
888
+ return 0;
889
+ },
890
+ "task-migrate-contract-bootstrap-repair": async ({ target, packageRoot, options }) => {
891
+ const { result } = await COMMAND_EXECUTORS["task-migrate-contract-bootstrap-repair"]({ target, packageRoot, options });
892
+ renderJsonOr(options, result, formatTaskMigrateContractBootstrapRepairResult);
893
+ return 0;
894
+ },
895
+ "checkpoint-revalidate": async ({ target, packageRoot, options }) => {
896
+ const { result } = await COMMAND_EXECUTORS["checkpoint-revalidate"]({ target, packageRoot, options });
897
+ renderJsonOr(options, result, formatCheckpointRevalidateResult);
898
+ return 0;
899
+ },
792
900
  "task-repair-legacy-recovery": async ({ target, packageRoot, options }) => {
793
901
  const { result } = await COMMAND_EXECUTORS["task-repair-legacy-recovery"]({ target, packageRoot, options });
794
902
  renderJsonOr(options, result, formatTaskRepairLegacyRecoveryResult);
@@ -0,0 +1,176 @@
1
+ import { canonicalFingerprint } from "../core/artifacts.js";
2
+ import { readContract } from "../core/contract.js";
3
+ import {
4
+ appendProtocolEvent,
5
+ validateEventLedger,
6
+ validateStateLedgerCoherence,
7
+ } from "../core/events.js";
8
+ import { readPersistedRoute } from "../core/route-artifact.js";
9
+ import { currentRepositoryFingerprint } from "../core/repository.js";
10
+ import { resolveTaskContext } from "../core/task-context.js";
11
+ import { taskArtifactPath } from "../core/task-paths.js";
12
+ import { assertTaskMutationAllowed } from "../core/task-claim-state.js";
13
+ import { withTaskTransaction } from "../core/transaction.js";
14
+ import {
15
+ CHECKPOINT_REVALIDATED_EVENT,
16
+ assertCheckpointRevalidatedDetails,
17
+ assertRepositoryFingerprint,
18
+ } from "../core/checkpoint-revalidation.js";
19
+ import { resolveTaskClaimState } from "../core/task-claim-state.js";
20
+ import { sameCanonicalGuideList, resolveEffectiveContractBootstrapRepairAnchor } from "../core/contract-bootstrap-recovery.js";
21
+ import {
22
+ classifyLoadedWorkState,
23
+ createWorkState,
24
+ mutateWorkState,
25
+ readWorkState,
26
+ } from "../core/work-state.js";
27
+
28
+ function revalidationError(message, details = {}) {
29
+ const error = new Error(message);
30
+ error.code = "E_CHECKPOINT_REVALIDATION_UNSAFE";
31
+ Object.assign(error, details);
32
+ return error;
33
+ }
34
+
35
+ function sameRepositoryFingerprint(left, right) {
36
+ return left?.branch === right?.branch && left?.head === right?.head;
37
+ }
38
+
39
+ function assertRouteIdentity(state, contract, route) {
40
+ if (!route || route.value?.contractFingerprint !== contract.fingerprint
41
+ || state.routeFingerprint !== route.fingerprint
42
+ || !sameCanonicalGuideList(state.selectedGuides, route.value.guides)) {
43
+ throw revalidationError("ROUTED checkpoint route identity cannot be proven safe", {
44
+ artifacts: [taskArtifactPath(state.taskId, "state"), taskArtifactPath(state.taskId, "route")],
45
+ });
46
+ }
47
+ }
48
+
49
+ async function inspectEligibility(target, packageRoot, taskId) {
50
+ const state = await readWorkState(target, { packageRoot, taskId });
51
+ if (!state) throw revalidationError("A persisted work-state checkpoint is required");
52
+ if (state.phase !== "ROUTED") throw revalidationError(`Checkpoint revalidation supports phase ROUTED, found ${state.phase}`);
53
+
54
+ const ledger = await validateEventLedger(target, packageRoot, { taskId });
55
+ if (!ledger.valid) throw revalidationError("Checkpoint revalidation requires a structurally valid event ledger", { errors: ledger.errors });
56
+ if (ledger.events.some((event) => event.event === "EXECUTION_STARTED")) {
57
+ throw revalidationError("Checkpoint revalidation is unavailable after execution has started");
58
+ }
59
+ const coherenceErrors = validateStateLedgerCoherence(state, ledger.events);
60
+ if (coherenceErrors.length > 0) throw revalidationError("Checkpoint revalidation requires coherent state and ledger", { errors: coherenceErrors });
61
+ const ownership = await resolveTaskClaimState(target, { taskId, packageRoot });
62
+ if (!ownership.ownershipValid || !ownership.mutationAllowed) {
63
+ throw revalidationError("Checkpoint revalidation cannot bypass invalid task ownership", { errors: ownership.ownershipErrors });
64
+ }
65
+ const contract = await readContract(target, packageRoot, { taskId });
66
+ if (state.contractFingerprint !== contract.fingerprint) {
67
+ throw revalidationError("Checkpoint contract identity changed; use the contract revision path");
68
+ }
69
+ const route = await readPersistedRoute(target, packageRoot, { taskId });
70
+ assertRouteIdentity(state, contract, route);
71
+
72
+ const freshness = await classifyLoadedWorkState({
73
+ target,
74
+ state,
75
+ contractFile: taskArtifactPath(taskId, "contract"),
76
+ });
77
+ const repository = freshness.repository;
78
+ assertRepositoryFingerprint(repository, "current repository fingerprint", { requireHead: true });
79
+ const reasons = [...new Set(freshness.reasons)].sort();
80
+ if (reasons.length === 0) {
81
+ return { state, contract, route, ledger, repository, freshness, alreadyFresh: true };
82
+ }
83
+ if (reasons.length !== 1 || reasons[0] !== "REPOSITORY_CHANGED") {
84
+ throw revalidationError(`Checkpoint freshness is not repository-only: ${reasons.join(", ")}`);
85
+ }
86
+ const repairAnchor = resolveEffectiveContractBootstrapRepairAnchor(ledger.events);
87
+ if (repairAnchor && (repairAnchor.details.contractFingerprint !== contract.fingerprint
88
+ || repairAnchor.details.routeFingerprint !== route.fingerprint)) {
89
+ throw revalidationError("Repaired checkpoint identity does not match the current contract and route");
90
+ }
91
+ return { state, contract, route, ledger, repository, freshness, repairAnchor, alreadyFresh: false };
92
+ }
93
+
94
+ function resultFor(taskId, state, repository, event = null, transaction = null, alreadyFresh = false) {
95
+ return {
96
+ taskId,
97
+ revalidated: !alreadyFresh,
98
+ alreadyFresh,
99
+ phase: state.phase,
100
+ previousRevision: event ? event.details.previousStateRevision : state.revision,
101
+ revalidatedRevision: event ? event.details.revalidatedStateRevision : state.revision,
102
+ previousRepositoryFingerprint: event?.details.previousRepositoryFingerprint ?? repository,
103
+ repositoryFingerprint: event?.details.repositoryFingerprint ?? repository,
104
+ eventSeq: event?.seq ?? null,
105
+ transactionCommitSeq: transaction?.seq ?? null,
106
+ };
107
+ }
108
+
109
+ async function revalidateLocked(target, packageRoot, taskId, transaction) {
110
+ const ownership = await resolveTaskClaimState(target, { taskId, packageRoot });
111
+ if (!ownership.ownershipValid || !ownership.mutationAllowed) {
112
+ throw revalidationError("Checkpoint revalidation cannot bypass invalid task ownership", { errors: ownership.ownershipErrors });
113
+ }
114
+ await assertTaskMutationAllowed(target, { taskId, packageRoot });
115
+ const inspected = await inspectEligibility(target, packageRoot, taskId);
116
+ if (inspected.alreadyFresh) return resultFor(taskId, inspected.state, inspected.repository, null, null, true);
117
+
118
+ const before = inspected.state;
119
+ const previousStateFingerprint = canonicalFingerprint(before);
120
+ const previousRepositoryFingerprint = structuredClone(before.repositoryFingerprint);
121
+ const repository = await currentRepositoryFingerprint(target);
122
+ assertRepositoryFingerprint(repository, "current repository fingerprint", { requireHead: true });
123
+ if (!sameRepositoryFingerprint(repository, inspected.repository)) {
124
+ throw revalidationError("Repository identity changed during checkpoint revalidation");
125
+ }
126
+ const next = await mutateWorkState(target, {
127
+ expectedRevision: before.revision,
128
+ packageRoot,
129
+ taskId,
130
+ }, (current) => createWorkState({
131
+ ...current,
132
+ repositoryFingerprint: repository,
133
+ lastUpdated: new Date().toISOString(),
134
+ }));
135
+ const details = {
136
+ phase: next.phase,
137
+ previousRepositoryFingerprint,
138
+ repositoryFingerprint: structuredClone(repository),
139
+ contractFingerprint: next.contractFingerprint,
140
+ routeFingerprint: next.routeFingerprint,
141
+ previousStateRevision: before.revision,
142
+ revalidatedStateRevision: next.revision,
143
+ previousStateFingerprint,
144
+ revalidatedStateFingerprint: canonicalFingerprint(next),
145
+ };
146
+ assertCheckpointRevalidatedDetails(details);
147
+ const event = await appendProtocolEvent(target, {
148
+ taskId,
149
+ event: CHECKPOINT_REVALIDATED_EVENT,
150
+ details,
151
+ }, packageRoot, { taskId });
152
+ const commitEvent = await appendProtocolEvent(target, {
153
+ taskId,
154
+ event: "TRANSACTION_COMMITTED",
155
+ details: { transactionId: transaction.transactionId, operation: "checkpoint-revalidate" },
156
+ }, packageRoot, { taskId });
157
+ return resultFor(taskId, next, repository, event, commitEvent, false);
158
+ }
159
+
160
+ export async function runCheckpointRevalidate({ target, packageRoot, taskId } = {}) {
161
+ const context = await resolveTaskContext(target, { taskId, packageRoot, explicitRequired: true });
162
+ const effectiveTaskId = context.taskId;
163
+ const initial = await inspectEligibility(target, packageRoot, effectiveTaskId);
164
+ if (initial.alreadyFresh) return resultFor(effectiveTaskId, initial.state, initial.repository, null, null, true);
165
+ return withTaskTransaction({
166
+ target,
167
+ taskId: effectiveTaskId,
168
+ operation: "checkpoint-revalidate",
169
+ packageRoot,
170
+ recordCommitEvent: false,
171
+ }, async (transaction) => revalidateLocked(target, packageRoot, effectiveTaskId, transaction));
172
+ }
173
+
174
+ export function formatCheckpointRevalidateResult(result) {
175
+ return `${JSON.stringify(result, null, 2)}\n`;
176
+ }
@@ -0,0 +1,38 @@
1
+ import { compileContext } from "../core/context-compiler/compiler.js";
2
+ import { normalizeContextCandidates } from "../core/context-compiler/candidates.js";
3
+ import { canonicalFingerprint } from "../core/artifacts.js";
4
+ import { buildContextQuestionSet } from "../core/decision/question-registry.js";
5
+ import { ensureSemanticDecision } from "../core/decision/service.js";
6
+
7
+ export async function runContextPlan({ target, packageRoot, taskId, decisionId, profile = "balanced", candidates = [], mandatoryIds = [], provider = null, readOnly = false } = {}) {
8
+ if (readOnly) return compileContext({ profile, candidates, mandatoryIds });
9
+ if (target && taskId) {
10
+ const normalized = normalizeContextCandidates(candidates);
11
+ const candidateSetFingerprint = canonicalFingerprint(normalized.map((candidate) => ({
12
+ id: candidate.id, sourceRef: candidate.sourceRef, summary: candidate.summary,
13
+ required: candidate.required, mandatory: candidate.mandatory,
14
+ })));
15
+ const questionSet = buildContextQuestionSet(normalized);
16
+ const decision = await ensureSemanticDecision({
17
+ target, packageRoot, taskId, decisionId, provider, allowNetwork: !readOnly,
18
+ request: {
19
+ decisionKind: "CONTEXT_PLAN", questionSetId: questionSet.id, questionSet,
20
+ state: { candidates: normalized.map(({ id, sourceRef, kind, summary, required, mandatory, risk, trust }) => ({ id, sourceRef, kind, summary, required, mandatory, risk, trust })) },
21
+ candidateIds: normalized.map((candidate) => candidate.id), candidateSetFingerprint,
22
+ },
23
+ });
24
+ return compileContext({ profile, candidates, mandatoryIds, semanticRanker: () => ({ rankedIds: decision.artifact.decision?.rankedIds ?? [], excludedIds: decision.artifact.decision?.excludedIds ?? [] }) });
25
+ }
26
+ return compileContext({ profile, candidates, mandatoryIds });
27
+ }
28
+
29
+ export function formatContextPlanResult(result) {
30
+ return [
31
+ `Context plan: ${result.selectedItems}/${result.candidateItems} items`,
32
+ `Profile: ${result.profile}`,
33
+ `Selected chars: ${result.selectedChars}/${result.budget.maxChars}`,
34
+ `Prompt-injection candidates: ${result.promptInjectionIds.length}`,
35
+ `Fingerprint: ${result.decisionFingerprint}`,
36
+ "",
37
+ ].join("\n");
38
+ }