martin-loop 0.1.5 → 1.3.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 (274) hide show
  1. package/CODE_OF_CONDUCT.md +32 -0
  2. package/LICENSE +21 -21
  3. package/README.md +307 -398
  4. package/demo/seeded-workspace/README.md +35 -35
  5. package/demo/seeded-workspace/TASKS.md +29 -29
  6. package/demo/seeded-workspace/martin.config.yaml +11 -11
  7. package/demo/seeded-workspace/package.json +8 -8
  8. package/demo/seeded-workspace/src/invoice-summary.js +11 -11
  9. package/demo/seeded-workspace/test/invoice-summary.test.js +20 -20
  10. package/dist/bin/martin-loop.js +0 -0
  11. package/dist/vendor/adapters/counter.d.ts +1 -0
  12. package/dist/vendor/adapters/counter.js +4 -0
  13. package/dist/vendor/adapters/git-baseline.d.ts +50 -0
  14. package/dist/vendor/adapters/git-baseline.js +233 -0
  15. package/dist/vendor/adapters/openrouter-adapter.d.ts +15 -0
  16. package/dist/vendor/adapters/openrouter-adapter.js +302 -0
  17. package/dist/vendor/adapters/usage.d.ts +48 -0
  18. package/dist/vendor/adapters/usage.js +66 -0
  19. package/dist/vendor/cli/bin/exit.d.ts +12 -0
  20. package/dist/vendor/cli/bin/exit.js +28 -0
  21. package/dist/vendor/cli/commands/analyze.d.ts +5 -0
  22. package/dist/vendor/cli/commands/analyze.js +58 -0
  23. package/dist/vendor/cli/commands/audit-log-verify.d.ts +34 -0
  24. package/dist/vendor/cli/commands/audit-log-verify.js +99 -0
  25. package/dist/vendor/cli/commands/audit.d.ts +8 -0
  26. package/dist/vendor/cli/commands/audit.js +199 -0
  27. package/dist/vendor/cli/commands/corpus.d.ts +5 -0
  28. package/dist/vendor/cli/commands/corpus.js +60 -0
  29. package/dist/vendor/cli/commands/doctor.d.ts +8 -0
  30. package/dist/vendor/cli/commands/doctor.js +219 -0
  31. package/dist/vendor/cli/commands/explain.d.ts +17 -0
  32. package/dist/vendor/cli/commands/explain.js +176 -0
  33. package/dist/vendor/cli/commands/export.d.ts +5 -0
  34. package/dist/vendor/cli/commands/export.js +60 -0
  35. package/dist/vendor/cli/commands/governance.d.ts +8 -0
  36. package/dist/vendor/cli/commands/governance.js +95 -0
  37. package/dist/vendor/cli/commands/improve.d.ts +18 -0
  38. package/dist/vendor/cli/commands/improve.js +396 -0
  39. package/dist/vendor/cli/commands/init.d.ts +8 -0
  40. package/dist/vendor/cli/commands/init.js +281 -0
  41. package/dist/vendor/cli/commands/migration.d.ts +8 -0
  42. package/dist/vendor/cli/commands/migration.js +67 -0
  43. package/dist/vendor/cli/commands/prior.d.ts +23 -0
  44. package/dist/vendor/cli/commands/prior.js +145 -0
  45. package/dist/vendor/cli/commands/resume.d.ts +21 -0
  46. package/dist/vendor/cli/commands/resume.js +73 -0
  47. package/dist/vendor/cli/commands/verify.d.ts +6 -0
  48. package/dist/vendor/cli/commands/verify.js +43 -0
  49. package/dist/vendor/cli/research/public-corpus.d.ts +43 -0
  50. package/dist/vendor/cli/research/public-corpus.js +151 -0
  51. package/dist/vendor/cli/ui/error-card.d.ts +38 -0
  52. package/dist/vendor/cli/ui/error-card.js +103 -0
  53. package/dist/vendor/cli/ui/mission-brief.d.ts +41 -0
  54. package/dist/vendor/cli/ui/mission-brief.js +173 -0
  55. package/dist/vendor/cli/ui/summary-card.d.ts +34 -0
  56. package/dist/vendor/cli/ui/summary-card.js +102 -0
  57. package/dist/vendor/contracts/audit.d.ts +46 -0
  58. package/dist/vendor/contracts/audit.js +360 -0
  59. package/dist/vendor/contracts/post-phase15.d.ts +240 -0
  60. package/dist/vendor/contracts/post-phase15.js +166 -0
  61. package/dist/vendor/core/agent/mandates.d.ts +46 -0
  62. package/dist/vendor/core/agent/mandates.js +178 -0
  63. package/dist/vendor/core/agent/receipts.d.ts +38 -0
  64. package/dist/vendor/core/agent/receipts.js +131 -0
  65. package/dist/vendor/core/agent/signing.d.ts +17 -0
  66. package/dist/vendor/core/agent/signing.js +91 -0
  67. package/dist/vendor/core/attestation/sign.d.ts +25 -0
  68. package/dist/vendor/core/attestation/sign.js +216 -0
  69. package/dist/vendor/core/autonomy/autonomous-promotion.d.ts +120 -0
  70. package/dist/vendor/core/autonomy/autonomous-promotion.js +346 -0
  71. package/dist/vendor/core/autonomy/envelope-v2.d.ts +29 -0
  72. package/dist/vendor/core/autonomy/envelope-v2.js +60 -0
  73. package/dist/vendor/core/autonomy/envelope.d.ts +17 -0
  74. package/dist/vendor/core/autonomy/envelope.js +27 -0
  75. package/dist/vendor/core/autonomy/escalation-ledger.d.ts +20 -0
  76. package/dist/vendor/core/autonomy/escalation-ledger.js +18 -0
  77. package/dist/vendor/core/autonomy/resume.d.ts +15 -0
  78. package/dist/vendor/core/autonomy/resume.js +23 -0
  79. package/dist/vendor/core/circuit/circuit-breaker.d.ts +60 -0
  80. package/dist/vendor/core/circuit/circuit-breaker.js +143 -0
  81. package/dist/vendor/core/context-distillation.d.ts +3 -0
  82. package/dist/vendor/core/context-distillation.js +44 -0
  83. package/dist/vendor/core/context-flow/compile-context.d.ts +8 -0
  84. package/dist/vendor/core/context-flow/compile-context.js +111 -0
  85. package/dist/vendor/core/context-flow/entities.d.ts +2 -0
  86. package/dist/vendor/core/context-flow/entities.js +44 -0
  87. package/dist/vendor/core/context-flow/evaluate-policy.d.ts +2 -0
  88. package/dist/vendor/core/context-flow/evaluate-policy.js +42 -0
  89. package/dist/vendor/core/context-flow/index.d.ts +11 -0
  90. package/dist/vendor/core/context-flow/index.js +24 -0
  91. package/dist/vendor/core/context-flow/labels.d.ts +3 -0
  92. package/dist/vendor/core/context-flow/labels.js +17 -0
  93. package/dist/vendor/core/context-flow/normalizer.d.ts +9 -0
  94. package/dist/vendor/core/context-flow/normalizer.js +69 -0
  95. package/dist/vendor/core/context-flow/profiles.d.ts +33 -0
  96. package/dist/vendor/core/context-flow/profiles.js +36 -0
  97. package/dist/vendor/core/context-flow/redaction.d.ts +1 -0
  98. package/dist/vendor/core/context-flow/redaction.js +6 -0
  99. package/dist/vendor/core/context-flow/sensitivity.d.ts +2 -0
  100. package/dist/vendor/core/context-flow/sensitivity.js +27 -0
  101. package/dist/vendor/core/context-flow/sync-preview.d.ts +2 -0
  102. package/dist/vendor/core/context-flow/sync-preview.js +22 -0
  103. package/dist/vendor/core/context-flow/token-estimator.d.ts +3 -0
  104. package/dist/vendor/core/context-flow/token-estimator.js +13 -0
  105. package/dist/vendor/core/context-flow/types.d.ts +91 -0
  106. package/dist/vendor/core/context-flow/types.js +2 -0
  107. package/dist/vendor/core/context-utility.d.ts +47 -0
  108. package/dist/vendor/core/context-utility.js +405 -0
  109. package/dist/vendor/core/cost/pipeline.d.ts +92 -0
  110. package/dist/vendor/core/cost/pipeline.js +141 -0
  111. package/dist/vendor/core/cost/tagged-cost.d.ts +27 -0
  112. package/dist/vendor/core/cost/tagged-cost.js +55 -0
  113. package/dist/vendor/core/cost-governor.d.ts +2 -0
  114. package/dist/vendor/core/cost-governor.js +50 -0
  115. package/dist/vendor/core/cve/cve-check.d.ts +80 -0
  116. package/dist/vendor/core/cve/cve-check.js +172 -0
  117. package/dist/vendor/core/digital-twin/index.d.ts +27 -0
  118. package/dist/vendor/core/digital-twin/index.js +90 -0
  119. package/dist/vendor/core/drift/drift-graph.d.ts +47 -0
  120. package/dist/vendor/core/drift/drift-graph.js +100 -0
  121. package/dist/vendor/core/drift/objective-lock.d.ts +69 -0
  122. package/dist/vendor/core/drift/objective-lock.js +88 -0
  123. package/dist/vendor/core/drift/scope.d.ts +46 -0
  124. package/dist/vendor/core/drift/scope.js +102 -0
  125. package/dist/vendor/core/drift/signature-lock.d.ts +48 -0
  126. package/dist/vendor/core/drift/signature-lock.js +202 -0
  127. package/dist/vendor/core/drift/stale-proof-gate.d.ts +21 -0
  128. package/dist/vendor/core/drift/stale-proof-gate.js +19 -0
  129. package/dist/vendor/core/eval/known-bad-world-runner.d.ts +24 -0
  130. package/dist/vendor/core/eval/known-bad-world-runner.js +256 -0
  131. package/dist/vendor/core/evidence/claim-audit.d.ts +18 -0
  132. package/dist/vendor/core/evidence/claim-audit.js +89 -0
  133. package/dist/vendor/core/exit-intelligence.d.ts +2 -0
  134. package/dist/vendor/core/exit-intelligence.js +58 -0
  135. package/dist/vendor/core/explain/formatter.d.ts +42 -0
  136. package/dist/vendor/core/explain/formatter.js +171 -0
  137. package/dist/vendor/core/explain/timeline.d.ts +29 -0
  138. package/dist/vendor/core/explain/timeline.js +213 -0
  139. package/dist/vendor/core/failure-taxonomy.d.ts +2 -0
  140. package/dist/vendor/core/failure-taxonomy.js +76 -0
  141. package/dist/vendor/core/gateway/index.d.ts +10 -0
  142. package/dist/vendor/core/gateway/index.js +12 -0
  143. package/dist/vendor/core/gateway/registry.d.ts +40 -0
  144. package/dist/vendor/core/gateway/registry.js +97 -0
  145. package/dist/vendor/core/gateway/transport.d.ts +31 -0
  146. package/dist/vendor/core/gateway/transport.js +82 -0
  147. package/dist/vendor/core/gateway/vault.d.ts +19 -0
  148. package/dist/vendor/core/gateway/vault.js +29 -0
  149. package/dist/vendor/core/graph/adapters.d.ts +43 -0
  150. package/dist/vendor/core/graph/adapters.js +91 -0
  151. package/dist/vendor/core/graph/hotspots.d.ts +22 -0
  152. package/dist/vendor/core/graph/hotspots.js +30 -0
  153. package/dist/vendor/core/graph/index.d.ts +1 -0
  154. package/dist/vendor/core/graph/index.js +2 -0
  155. package/dist/vendor/core/honey/honey-tokens.d.ts +32 -0
  156. package/dist/vendor/core/honey/honey-tokens.js +44 -0
  157. package/dist/vendor/core/index.d.ts +2 -2
  158. package/dist/vendor/core/index.js +38 -12
  159. package/dist/vendor/core/learning/bayesian-update.d.ts +31 -0
  160. package/dist/vendor/core/learning/bayesian-update.js +60 -0
  161. package/dist/vendor/core/learning/prior-sets.d.ts +42 -0
  162. package/dist/vendor/core/learning/prior-sets.js +111 -0
  163. package/dist/vendor/core/learning/promotion-gate.d.ts +17 -0
  164. package/dist/vendor/core/learning/promotion-gate.js +23 -0
  165. package/dist/vendor/core/leash/blast-radius.d.ts +42 -0
  166. package/dist/vendor/core/leash/blast-radius.js +156 -0
  167. package/dist/vendor/core/leash/policy-leash.d.ts +31 -0
  168. package/dist/vendor/core/leash/policy-leash.js +117 -0
  169. package/dist/vendor/core/memo/memo.d.ts +63 -0
  170. package/dist/vendor/core/memo/memo.js +97 -0
  171. package/dist/vendor/core/memory/learning-pipeline.d.ts +154 -0
  172. package/dist/vendor/core/memory/learning-pipeline.js +391 -0
  173. package/dist/vendor/core/memory/palace.d.ts +84 -0
  174. package/dist/vendor/core/memory/palace.js +379 -0
  175. package/dist/vendor/core/merge/ast-merge.d.ts +22 -0
  176. package/dist/vendor/core/merge/ast-merge.js +350 -0
  177. package/dist/vendor/core/merge/text-merge.d.ts +12 -0
  178. package/dist/vendor/core/merge/text-merge.js +182 -0
  179. package/dist/vendor/core/otel/tracer.d.ts +45 -0
  180. package/dist/vendor/core/otel/tracer.js +116 -0
  181. package/dist/vendor/core/parallel/parallel-attempts.d.ts +28 -0
  182. package/dist/vendor/core/parallel/parallel-attempts.js +41 -0
  183. package/dist/vendor/core/parallel/scorer.d.ts +24 -0
  184. package/dist/vendor/core/parallel/scorer.js +65 -0
  185. package/dist/vendor/core/pattern-detection.d.ts +64 -0
  186. package/dist/vendor/core/pattern-detection.js +108 -0
  187. package/dist/vendor/core/persistence/checkpoint.d.ts +44 -0
  188. package/dist/vendor/core/persistence/checkpoint.js +156 -0
  189. package/dist/vendor/core/persistence/cleanup.d.ts +22 -0
  190. package/dist/vendor/core/persistence/cleanup.js +131 -0
  191. package/dist/vendor/core/persistence/index.d.ts +2 -0
  192. package/dist/vendor/core/persistence/index.js +1 -0
  193. package/dist/vendor/core/persistence/runs-reader.d.ts +52 -0
  194. package/dist/vendor/core/persistence/runs-reader.js +84 -0
  195. package/dist/vendor/core/persistence/store.d.ts +6 -1
  196. package/dist/vendor/core/persistence/store.js +5 -0
  197. package/dist/vendor/core/policy/file-touch-quota.d.ts +60 -0
  198. package/dist/vendor/core/policy/file-touch-quota.js +105 -0
  199. package/dist/vendor/core/policy/policy-loader.d.ts +30 -0
  200. package/dist/vendor/core/policy/policy-loader.js +170 -0
  201. package/dist/vendor/core/policy/policy-schema.d.ts +55 -0
  202. package/dist/vendor/core/policy/policy-schema.js +78 -0
  203. package/dist/vendor/core/probe/probe.d.ts +49 -0
  204. package/dist/vendor/core/probe/probe.js +115 -0
  205. package/dist/vendor/core/proof/patch-proof.d.ts +58 -0
  206. package/dist/vendor/core/proof/patch-proof.js +84 -0
  207. package/dist/vendor/core/proof/semantic-probe.d.ts +25 -0
  208. package/dist/vendor/core/proof/semantic-probe.js +82 -0
  209. package/dist/vendor/core/recovery/failure-mode-runner.d.ts +29 -0
  210. package/dist/vendor/core/recovery/failure-mode-runner.js +39 -0
  211. package/dist/vendor/core/red-blue/red-phase.d.ts +64 -0
  212. package/dist/vendor/core/red-blue/red-phase.js +141 -0
  213. package/dist/vendor/core/red-blue/risk-tiers.d.ts +22 -0
  214. package/dist/vendor/core/red-blue/risk-tiers.js +33 -0
  215. package/dist/vendor/core/replay/replay.d.ts +85 -0
  216. package/dist/vendor/core/replay/replay.js +109 -0
  217. package/dist/vendor/core/router/engine.d.ts +54 -0
  218. package/dist/vendor/core/router/engine.js +131 -0
  219. package/dist/vendor/core/router/index.d.ts +1 -0
  220. package/dist/vendor/core/router/index.js +2 -0
  221. package/dist/vendor/core/router/trust-calibration.d.ts +57 -0
  222. package/dist/vendor/core/router/trust-calibration.js +127 -0
  223. package/dist/vendor/core/run-martin.d.ts +2 -0
  224. package/dist/vendor/core/run-martin.js +287 -0
  225. package/dist/vendor/core/security/cve-scanner.d.ts +62 -0
  226. package/dist/vendor/core/security/cve-scanner.js +178 -0
  227. package/dist/vendor/core/sentinel/efficiency-sentinel.d.ts +29 -0
  228. package/dist/vendor/core/sentinel/efficiency-sentinel.js +30 -0
  229. package/dist/vendor/core/sentinel/progress-guard.d.ts +35 -0
  230. package/dist/vendor/core/sentinel/progress-guard.js +46 -0
  231. package/dist/vendor/core/siem/siem-emitter.d.ts +49 -0
  232. package/dist/vendor/core/siem/siem-emitter.js +157 -0
  233. package/dist/vendor/core/strategy/attempt-brief.d.ts +22 -0
  234. package/dist/vendor/core/strategy/attempt-brief.js +89 -0
  235. package/dist/vendor/core/summarize/diff-summary.d.ts +35 -0
  236. package/dist/vendor/core/summarize/diff-summary.js +204 -0
  237. package/dist/vendor/core/surface-signals.d.ts +21 -0
  238. package/dist/vendor/core/surface-signals.js +139 -0
  239. package/dist/vendor/core/truth/truth-wall.d.ts +51 -0
  240. package/dist/vendor/core/truth/truth-wall.js +69 -0
  241. package/dist/vendor/core/truth-spine.d.ts +26 -0
  242. package/dist/vendor/core/truth-spine.js +62 -0
  243. package/dist/vendor/core/types.d.ts +115 -0
  244. package/dist/vendor/core/types.js +2 -0
  245. package/dist/vendor/core/verification/tiered-verify.d.ts +17 -0
  246. package/dist/vendor/core/verification/tiered-verify.js +29 -0
  247. package/dist/vendor/core/verifier-pyramid.d.ts +32 -0
  248. package/dist/vendor/core/verifier-pyramid.js +111 -0
  249. package/dist/vendor/core/workflow-artifacts.d.ts +99 -0
  250. package/dist/vendor/core/workflow-artifacts.js +668 -0
  251. package/dist/vendor/core/wrap/supervised-run.d.ts +96 -0
  252. package/dist/vendor/core/wrap/supervised-run.js +178 -0
  253. package/docs/assets/cli-animated.svg +139 -0
  254. package/docs/assets/cli-static.svg +34 -0
  255. package/docs/assets/github-hero-v2.svg +23 -0
  256. package/docs/assets/martin-raplph.png.jpg +0 -0
  257. package/docs/assets/martinloop-logo.png +0 -0
  258. package/docs/assets/nvidia-inception-program-light.png +0 -0
  259. package/docs/assets/nvidia-inception-program.png +0 -0
  260. package/docs/assets/phase3c-sidesidebyside-demo.html +228 -0
  261. package/docs/assets/side-by-side.svg +134 -0
  262. package/docs/oss/CLAUDE-CODE-WALKTHROUGH.md +142 -142
  263. package/docs/oss/EXAMPLES.md +134 -134
  264. package/docs/oss/OSS-BOUNDARY-REPORT.json +1 -1
  265. package/docs/oss/OSS-BOUNDARY-REPORT.md +1 -1
  266. package/docs/oss/QUICKSTART.md +170 -165
  267. package/docs/oss/RALPH-LOOP-SAFETY.md +113 -113
  268. package/docs/oss/README.md +96 -96
  269. package/docs/oss/RELEASE-SURFACE-REPORT.json +2 -1
  270. package/docs/oss/RELEASE-SURFACE-REPORT.md +2 -1
  271. package/package.json +130 -58
  272. package/docs/distribution/DIRECTORY-SUBMISSIONS.md +0 -89
  273. package/docs/distribution/INTEGRATION-OUTREACH.md +0 -61
  274. package/docs/distribution/UNDER-3-CHALLENGE.md +0 -65
@@ -0,0 +1,102 @@
1
+ /**
2
+ * summary-card.ts
3
+ *
4
+ * Renders a human-readable run summary card to stdout after every martin run.
5
+ * Respects --json flag and MARTIN_NO_SUMMARY env var.
6
+ * Width: 56 chars to fit any terminal >= 60 cols.
7
+ */
8
+ const CARD_WIDTH = 56;
9
+ const INNER_WIDTH = CARD_WIDTH - 4; // 2 border chars + 2 padding spaces
10
+ export function shouldRenderSummaryCard(args) {
11
+ if (process.env.MARTIN_NO_SUMMARY === "1")
12
+ return false;
13
+ if (args.includes("--json"))
14
+ return false;
15
+ // Only render when stdout is a TTY or when explicitly forced
16
+ if (!process.stdout.isTTY && process.env.MARTIN_FORCE_SUMMARY !== "1")
17
+ return false;
18
+ return true;
19
+ }
20
+ export function renderSummaryCard(input) {
21
+ const lines = [];
22
+ const top = `╔${"═".repeat(CARD_WIDTH - 2)}╗`;
23
+ const bottom = `╚${"═".repeat(CARD_WIDTH - 2)}╝`;
24
+ const divider = `╠${"═".repeat(CARD_WIDTH - 2)}╣`;
25
+ const title = input.succeeded
26
+ ? "Martin Loop — Run Complete"
27
+ : "Martin Loop — Run Failed";
28
+ lines.push(top);
29
+ lines.push(row(title));
30
+ lines.push(divider);
31
+ if (input.succeeded) {
32
+ const attemptLabel = input.attemptCount === 1
33
+ ? "1 attempt"
34
+ : `attempt ${input.attemptCount} of ${input.maxAttempts}`;
35
+ lines.push(row(`Outcome SUCCEEDED (${attemptLabel})`));
36
+ lines.push(row(`Objective ${truncate(input.objective, INNER_WIDTH - 12)}`));
37
+ if (input.grade) {
38
+ const grounding = input.groundingScore !== undefined
39
+ ? ` (grounding: ${input.groundingScore.toFixed(2)})`
40
+ : "";
41
+ lines.push(row(`Patch grade ${input.grade}${grounding}`));
42
+ }
43
+ if (input.modelName) {
44
+ const probe = input.probeTier ? ` (probe: ${input.probeTier})` : "";
45
+ lines.push(row(`Model ${truncate(input.modelName + probe, INNER_WIDTH - 12)}`));
46
+ }
47
+ const probeNote = input.probeCostUsd !== undefined
48
+ ? ` (probe $${input.probeCostUsd.toFixed(2)} + attempts $${(input.costUsd - input.probeCostUsd).toFixed(2)})`
49
+ : "";
50
+ lines.push(row(`Cost $${input.costUsd.toFixed(2)}${probeNote}`));
51
+ if (input.routerSelectedModel !== undefined) {
52
+ const routerCostStr = input.routerCostPer1kTcs !== undefined
53
+ ? ` · $${input.routerCostPer1kTcs.toFixed(4)}/1kTcs`
54
+ : "";
55
+ const tierStr = input.routerTrustTier ? ` [${input.routerTrustTier}]` : "";
56
+ lines.push(row(`Route ${truncate(input.routerSelectedModel + routerCostStr + tierStr, INNER_WIDTH - 12)}`));
57
+ }
58
+ if (input.blastRadius !== undefined) {
59
+ lines.push(row(`Blast radius ${input.blastRadius}/100`));
60
+ }
61
+ lines.push(row(`Duration ${formatDuration(input.durationMs)}`));
62
+ }
63
+ else {
64
+ lines.push(row(`Outcome FAILED after ${input.attemptCount} attempt${input.attemptCount !== 1 ? "s" : ""}`));
65
+ lines.push(row(`Objective ${truncate(input.objective, INNER_WIDTH - 12)}`));
66
+ if (input.lastBlockReason) {
67
+ lines.push(row(`Last block ${truncate(input.lastBlockReason, INNER_WIDTH - 12)}`));
68
+ }
69
+ lines.push(row(`Cost $${input.costUsd.toFixed(2)} (all attempts charged)`));
70
+ const rollbackStr = input.rollbackComplete === false
71
+ ? "incomplete — check workspace"
72
+ : "complete — workspace restored";
73
+ lines.push(row(`Rollback ${rollbackStr}`));
74
+ }
75
+ lines.push(divider);
76
+ lines.push(row(`Audit trail → ~/.martin/runs/${truncate(input.loopId, INNER_WIDTH - 22)}`));
77
+ if (!input.succeeded) {
78
+ lines.push(row(`Tip: martin explain ${truncate(input.loopId, INNER_WIDTH - 22)}`));
79
+ }
80
+ lines.push(bottom);
81
+ return lines.join("\n");
82
+ }
83
+ function row(content) {
84
+ const remaining = CARD_WIDTH - 4 - content.length;
85
+ const padding = remaining > 0 ? " ".repeat(remaining) : "";
86
+ return `║ ${content}${padding} ║`;
87
+ }
88
+ function truncate(str, maxLen) {
89
+ if (str.length <= maxLen)
90
+ return str;
91
+ return `${str.slice(0, maxLen - 3)}...`;
92
+ }
93
+ function formatDuration(ms) {
94
+ if (ms < 1000)
95
+ return `${ms}ms`;
96
+ if (ms < 60_000)
97
+ return `${(ms / 1000).toFixed(1)}s`;
98
+ const mins = Math.floor(ms / 60_000);
99
+ const secs = Math.round((ms % 60_000) / 1000);
100
+ return `${mins}m ${secs}s`;
101
+ }
102
+ //# sourceMappingURL=summary-card.js.map
@@ -0,0 +1,46 @@
1
+ export interface AuditManifestEntry {
2
+ path: string;
3
+ sha256: string;
4
+ sizeBytes: number;
5
+ }
6
+ export interface AuditManifest {
7
+ runId: string;
8
+ generatedAt: string;
9
+ generatedBy: string;
10
+ files: AuditManifestEntry[];
11
+ manifestVersion: "h3.v1";
12
+ tamperEvident: boolean;
13
+ }
14
+ export interface AuditPackFile {
15
+ path: string;
16
+ content: string;
17
+ }
18
+ export interface AuditPackInput {
19
+ runId: string;
20
+ generatedBy: string;
21
+ generatedAt: string;
22
+ files: AuditPackFile[];
23
+ }
24
+ export interface GenerateAuditPackFromRunDirectoryOptions {
25
+ runId: string;
26
+ runDir: string;
27
+ outputDir: string;
28
+ generatedBy?: string;
29
+ generatedAt?: string;
30
+ truthFacts?: unknown[];
31
+ treatyTimeline?: unknown[];
32
+ }
33
+ export interface AuditPackGenerationResult {
34
+ packPath: string;
35
+ manifest: AuditManifest;
36
+ }
37
+ export interface AuditPackVerificationResult {
38
+ ok: boolean;
39
+ manifest: AuditManifest;
40
+ checkedFiles: AuditManifestEntry[];
41
+ failures: string[];
42
+ }
43
+ export declare function generateAuditPackFromRunDirectory(options: GenerateAuditPackFromRunDirectoryOptions): Promise<AuditPackGenerationResult>;
44
+ export declare function writeAuditPack(packPath: string, input: AuditPackInput): Promise<AuditPackGenerationResult>;
45
+ export declare function verifyAuditPack(packPath: string): Promise<AuditPackVerificationResult>;
46
+ export declare function stableStringify(value: unknown): string;
@@ -0,0 +1,360 @@
1
+ import crypto from "node:crypto";
2
+ import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
3
+ import { basename, join, relative, resolve } from "node:path";
4
+ const AUDIT_DIRECTORIES = [
5
+ "patch-proofs",
6
+ "drift-reports",
7
+ "truth-facts",
8
+ "treaty-timeline",
9
+ "red-findings",
10
+ "hypothesis-ledger"
11
+ ];
12
+ export async function generateAuditPackFromRunDirectory(options) {
13
+ const runSource = await readRunAuditSource(options.runDir);
14
+ const generatedAt = options.generatedAt ??
15
+ (typeof runSource.state?.updatedAt === "string" ? runSource.state.updatedAt : undefined) ??
16
+ (typeof runSource.contract.createdAt === "string" ? runSource.contract.createdAt : undefined) ??
17
+ new Date().toISOString();
18
+ const files = buildAuditPackFiles({
19
+ runId: options.runId,
20
+ runSource,
21
+ truthFacts: options.truthFacts ?? [],
22
+ treatyTimeline: options.treatyTimeline ?? []
23
+ });
24
+ const packPath = join(resolve(options.outputDir), `audit-pack-${options.runId}`);
25
+ return writeAuditPack(packPath, {
26
+ runId: options.runId,
27
+ generatedAt,
28
+ generatedBy: options.generatedBy ?? "martin",
29
+ files
30
+ });
31
+ }
32
+ export async function writeAuditPack(packPath, input) {
33
+ const normalizedFiles = [...input.files].sort((left, right) => left.path.localeCompare(right.path));
34
+ const manifest = createAuditManifest(input.runId, input.generatedAt, input.generatedBy, normalizedFiles);
35
+ await mkdir(packPath, { recursive: true });
36
+ for (const directory of AUDIT_DIRECTORIES) {
37
+ await mkdir(join(packPath, directory), { recursive: true });
38
+ }
39
+ for (const file of normalizedFiles) {
40
+ await mkdir(join(packPath, relative(".", file.path).split(/[\\/]/u).slice(0, -1).join("/")), {
41
+ recursive: true
42
+ });
43
+ await writeFile(join(packPath, file.path), file.content, "utf8");
44
+ }
45
+ await writeFile(join(packPath, "MANIFEST.json"), `${stableStringify(manifest)}\n`, "utf8");
46
+ return {
47
+ packPath,
48
+ manifest
49
+ };
50
+ }
51
+ export async function verifyAuditPack(packPath) {
52
+ const resolvedPackPath = resolve(packPath);
53
+ const manifest = JSON.parse(await readFile(join(resolvedPackPath, "MANIFEST.json"), "utf8"));
54
+ const actualFiles = await collectAuditManifestEntries(resolvedPackPath);
55
+ const manifestFiles = [...manifest.files].sort((left, right) => left.path.localeCompare(right.path));
56
+ const failures = [];
57
+ const actualPaths = new Set(actualFiles.map((entry) => entry.path));
58
+ const manifestPaths = new Set(manifestFiles.map((entry) => entry.path));
59
+ for (const entry of manifestFiles) {
60
+ if (!actualPaths.has(entry.path)) {
61
+ failures.push(`Missing file: ${entry.path}`);
62
+ continue;
63
+ }
64
+ const actual = actualFiles.find((candidate) => candidate.path === entry.path);
65
+ if (!actual) {
66
+ failures.push(`Missing file: ${entry.path}`);
67
+ continue;
68
+ }
69
+ if (actual.sha256 !== entry.sha256) {
70
+ failures.push(`Checksum mismatch: ${entry.path}`);
71
+ }
72
+ if (actual.sizeBytes !== entry.sizeBytes) {
73
+ failures.push(`Size mismatch: ${entry.path}`);
74
+ }
75
+ }
76
+ for (const actual of actualFiles) {
77
+ if (!manifestPaths.has(actual.path)) {
78
+ failures.push(`Unexpected file not covered by manifest: ${actual.path}`);
79
+ }
80
+ }
81
+ return {
82
+ ok: failures.length === 0,
83
+ manifest,
84
+ checkedFiles: actualFiles,
85
+ failures
86
+ };
87
+ }
88
+ export function stableStringify(value) {
89
+ return JSON.stringify(sortValue(value), null, 2);
90
+ }
91
+ function createAuditManifest(runId, generatedAt, generatedBy, files) {
92
+ const entries = files.map((file) => ({
93
+ path: normalizeAuditPath(file.path),
94
+ sha256: hashContent(file.content),
95
+ sizeBytes: Buffer.byteLength(file.content, "utf8")
96
+ }));
97
+ return {
98
+ runId,
99
+ generatedAt,
100
+ generatedBy,
101
+ files: entries,
102
+ manifestVersion: "h3.v1",
103
+ tamperEvident: true
104
+ };
105
+ }
106
+ function buildAuditPackFiles(input) {
107
+ const { runId, runSource, truthFacts, treatyTimeline } = input;
108
+ const patchProofs = buildPatchProofs(runSource);
109
+ const driftReports = buildDriftReports(runSource);
110
+ const redFindings = buildRedFindings(runSource);
111
+ const hypothesisLedger = buildHypothesisLedger(runId, runSource);
112
+ return [
113
+ {
114
+ path: "patch-proofs/contract.json",
115
+ content: `${stableStringify(runSource.contract)}\n`
116
+ },
117
+ {
118
+ path: "patch-proofs/ledger.jsonl",
119
+ content: runSource.ledgerLines.length > 0 ? `${runSource.ledgerLines.join("\n")}\n` : ""
120
+ },
121
+ {
122
+ path: "patch-proofs/attempts.json",
123
+ content: `${stableStringify(patchProofs)}\n`
124
+ },
125
+ {
126
+ path: "drift-reports/drift-summary.json",
127
+ content: `${stableStringify(driftReports)}\n`
128
+ },
129
+ {
130
+ path: "truth-facts/truth-facts.json",
131
+ content: `${stableStringify({ runId, facts: truthFacts })}\n`
132
+ },
133
+ {
134
+ path: "treaty-timeline/treaty-timeline.json",
135
+ content: `${stableStringify({ runId, transitions: treatyTimeline })}\n`
136
+ },
137
+ {
138
+ path: "red-findings/red-findings.json",
139
+ content: `${stableStringify({ runId, findings: redFindings })}\n`
140
+ },
141
+ {
142
+ path: "hypothesis-ledger/hypothesis-ledger.json",
143
+ content: `${stableStringify(hypothesisLedger)}\n`
144
+ },
145
+ ...collectAttemptFiles(runSource.attempts, "patch-proofs", [
146
+ "diff.patch",
147
+ "patch-decision.json",
148
+ "patch-score.json",
149
+ "final-semantic-verification.json",
150
+ "attempt-semantic-check.json"
151
+ ]),
152
+ ...collectAttemptFiles(runSource.attempts, "drift-reports", [
153
+ "grounding-scan.json",
154
+ "scope-surface.json",
155
+ "leash.json",
156
+ "rollback-outcome.json",
157
+ "rollback-boundary.json"
158
+ ])
159
+ ];
160
+ }
161
+ function buildPatchProofs(runSource) {
162
+ return {
163
+ attemptCount: runSource.attempts.length,
164
+ attempts: runSource.attempts.map((attempt) => ({
165
+ attempt: attempt.attemptLabel,
166
+ files: Object.keys(attempt.files).filter((file) => [
167
+ "diff.patch",
168
+ "patch-decision.json",
169
+ "patch-score.json",
170
+ "final-semantic-verification.json",
171
+ "attempt-semantic-check.json"
172
+ ].includes(file))
173
+ }))
174
+ };
175
+ }
176
+ function buildDriftReports(runSource) {
177
+ return {
178
+ state: runSource.state,
179
+ attemptCount: runSource.attempts.length,
180
+ attempts: runSource.attempts.map((attempt) => {
181
+ const grounding = parseOptionalJson(attempt.files["grounding-scan.json"]);
182
+ const leash = parseOptionalJson(attempt.files["leash.json"]);
183
+ return {
184
+ attempt: attempt.attemptLabel,
185
+ hasGroundingScan: attempt.files["grounding-scan.json"] !== undefined,
186
+ hasScopeSurface: attempt.files["scope-surface.json"] !== undefined,
187
+ hasLeash: attempt.files["leash.json"] !== undefined,
188
+ groundingViolations: Array.isArray(grounding?.violations) ? grounding.violations.length : 0,
189
+ safetyBlocked: typeof leash?.blocked === "boolean" ? leash.blocked : false
190
+ };
191
+ })
192
+ };
193
+ }
194
+ function buildRedFindings(runSource) {
195
+ const findings = [];
196
+ for (const event of runSource.ledgerEvents) {
197
+ const kind = typeof event.kind === "string" ? event.kind : "";
198
+ if (kind.includes("violation") ||
199
+ kind.includes("discard") ||
200
+ kind.includes("escalat") ||
201
+ kind.includes("blocked")) {
202
+ findings.push({
203
+ source: "ledger",
204
+ kind,
205
+ payload: typeof event.payload === "object" && event.payload !== null ? event.payload : {}
206
+ });
207
+ }
208
+ }
209
+ for (const attempt of runSource.attempts) {
210
+ const grounding = parseOptionalJson(attempt.files["grounding-scan.json"]);
211
+ if (Array.isArray(grounding?.violations) && grounding.violations.length > 0) {
212
+ findings.push({
213
+ source: attempt.attemptLabel,
214
+ kind: "grounding.violations_found",
215
+ violations: grounding.violations
216
+ });
217
+ }
218
+ }
219
+ return findings;
220
+ }
221
+ function buildHypothesisLedger(runId, runSource) {
222
+ const task = typeof runSource.contract.task === "object" && runSource.contract.task !== null
223
+ ? runSource.contract.task
224
+ : null;
225
+ return {
226
+ runId,
227
+ objective: (typeof runSource.contract.objective === "string" ? runSource.contract.objective : undefined) ??
228
+ (typeof task?.objective === "string" ? task.objective : undefined) ??
229
+ null,
230
+ verificationPlan: task?.verificationPlan ?? [],
231
+ eventKinds: runSource.ledgerEvents
232
+ .map((event) => (typeof event.kind === "string" ? event.kind : null))
233
+ .filter((value) => value !== null),
234
+ attempts: runSource.attempts.map((attempt) => ({
235
+ attempt: attempt.attemptLabel,
236
+ hasPatchDecision: attempt.files["patch-decision.json"] !== undefined,
237
+ hasPatchScore: attempt.files["patch-score.json"] !== undefined,
238
+ hasGroundingScan: attempt.files["grounding-scan.json"] !== undefined
239
+ }))
240
+ };
241
+ }
242
+ function collectAttemptFiles(attempts, section, names) {
243
+ const files = [];
244
+ for (const attempt of attempts) {
245
+ for (const name of names) {
246
+ const content = attempt.files[name];
247
+ if (content === undefined) {
248
+ continue;
249
+ }
250
+ files.push({
251
+ path: `${section}/${attempt.attemptLabel}/${name}`,
252
+ content: ensureTrailingNewline(content)
253
+ });
254
+ }
255
+ }
256
+ return files;
257
+ }
258
+ async function readRunAuditSource(runDir) {
259
+ const resolvedRunDir = resolve(runDir);
260
+ const contract = JSON.parse(await readFile(join(resolvedRunDir, "contract.json"), "utf8"));
261
+ const state = await readJsonIfExists(join(resolvedRunDir, "state.json"));
262
+ const ledgerPath = join(resolvedRunDir, "ledger.jsonl");
263
+ const ledgerRaw = await readFile(ledgerPath, "utf8").catch(() => "");
264
+ const ledgerLines = ledgerRaw.split(/\r?\n/u).filter((line) => line.length > 0);
265
+ const ledgerEvents = ledgerLines.map((line) => JSON.parse(line));
266
+ const artifactsRoot = join(resolvedRunDir, "artifacts");
267
+ const attemptEntries = await readdir(artifactsRoot, { withFileTypes: true }).catch(() => []);
268
+ const attempts = [];
269
+ for (const entry of attemptEntries.sort((left, right) => left.name.localeCompare(right.name))) {
270
+ if (!entry.isDirectory()) {
271
+ continue;
272
+ }
273
+ const attemptDir = join(artifactsRoot, entry.name);
274
+ const fileEntries = await readdir(attemptDir, { withFileTypes: true });
275
+ const files = {};
276
+ for (const fileEntry of fileEntries) {
277
+ if (!fileEntry.isFile()) {
278
+ continue;
279
+ }
280
+ const fileName = fileEntry.name;
281
+ files[fileName] = await readFile(join(attemptDir, fileName), "utf8");
282
+ }
283
+ attempts.push({
284
+ attemptLabel: entry.name,
285
+ files
286
+ });
287
+ }
288
+ return {
289
+ contract,
290
+ state,
291
+ ledgerLines,
292
+ ledgerEvents,
293
+ attempts
294
+ };
295
+ }
296
+ async function collectAuditManifestEntries(packPath) {
297
+ const entries = [];
298
+ await collectFilesRecursive(packPath, packPath, entries);
299
+ return entries.sort((left, right) => left.path.localeCompare(right.path));
300
+ }
301
+ async function collectFilesRecursive(root, current, entries) {
302
+ const fileEntries = await readdir(current, { withFileTypes: true });
303
+ for (const entry of fileEntries) {
304
+ const fullPath = join(current, entry.name);
305
+ if (entry.isDirectory()) {
306
+ await collectFilesRecursive(root, fullPath, entries);
307
+ continue;
308
+ }
309
+ if (basename(fullPath) === "MANIFEST.json") {
310
+ continue;
311
+ }
312
+ const content = await readFile(fullPath, "utf8");
313
+ const fileStat = await stat(fullPath);
314
+ entries.push({
315
+ path: normalizeAuditPath(relative(root, fullPath)),
316
+ sha256: hashContent(content),
317
+ sizeBytes: fileStat.size
318
+ });
319
+ }
320
+ }
321
+ async function readJsonIfExists(pathname) {
322
+ try {
323
+ return JSON.parse(await readFile(pathname, "utf8"));
324
+ }
325
+ catch {
326
+ return null;
327
+ }
328
+ }
329
+ function parseOptionalJson(content) {
330
+ if (!content) {
331
+ return null;
332
+ }
333
+ try {
334
+ return JSON.parse(content);
335
+ }
336
+ catch {
337
+ return null;
338
+ }
339
+ }
340
+ function hashContent(content) {
341
+ return crypto.createHash("sha256").update(content).digest("hex");
342
+ }
343
+ function normalizeAuditPath(pathname) {
344
+ return pathname.replace(/\\/gu, "/");
345
+ }
346
+ function ensureTrailingNewline(content) {
347
+ return content.endsWith("\n") ? content : `${content}\n`;
348
+ }
349
+ function sortValue(value) {
350
+ if (Array.isArray(value)) {
351
+ return value.map((entry) => sortValue(entry));
352
+ }
353
+ if (value && typeof value === "object") {
354
+ return Object.fromEntries(Object.entries(value)
355
+ .sort(([left], [right]) => left.localeCompare(right))
356
+ .map(([key, entry]) => [key, sortValue(entry)]));
357
+ }
358
+ return value;
359
+ }
360
+ //# sourceMappingURL=audit.js.map