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,58 @@
1
+ export function inferExit(input) {
2
+ if (input.lastResult?.status === "completed" && input.lastResult.verification.passed) {
3
+ return {
4
+ shouldExit: true,
5
+ lifecycleState: "completed",
6
+ reason: input.lastResult.verification.summary
7
+ };
8
+ }
9
+ if (input.costState.shouldStop) {
10
+ return {
11
+ shouldExit: true,
12
+ lifecycleState: "budget_exit",
13
+ reason: "Budget governor reached a hard limit."
14
+ };
15
+ }
16
+ if (input.lastFailure) {
17
+ const repeatedFailures = countRecentFailureMatches(input.loop.attempts, input.lastFailure.failureClass);
18
+ if (input.lastFailure.failureClass === "environment_mismatch" && repeatedFailures >= 2) {
19
+ return {
20
+ shouldExit: true,
21
+ lifecycleState: "human_escalation",
22
+ reason: "Repeated environment_mismatch failures require a human to repair the runtime."
23
+ };
24
+ }
25
+ if (repeatedFailures >= 2) {
26
+ return {
27
+ shouldExit: true,
28
+ lifecycleState: "diminishing_returns",
29
+ reason: `Repeated ${input.lastFailure.failureClass} failures suggest diminishing returns.`
30
+ };
31
+ }
32
+ }
33
+ if (input.lastResult?.status === "stalled" || repeatedSummary(input)) {
34
+ return {
35
+ shouldExit: true,
36
+ lifecycleState: "stuck_exit",
37
+ reason: "The loop is repeating the same stalled output."
38
+ };
39
+ }
40
+ return {
41
+ shouldExit: false,
42
+ lifecycleState: "running",
43
+ reason: "Another attempt is still justified."
44
+ };
45
+ }
46
+ function countRecentFailureMatches(attempts, failureClass) {
47
+ return attempts.slice(-3).filter((attempt) => attempt.failureClass === failureClass).length;
48
+ }
49
+ function repeatedSummary(input) {
50
+ if (!input.lastResult?.summary) {
51
+ return false;
52
+ }
53
+ const normalized = input.lastResult.summary.trim().toLowerCase();
54
+ return input.loop.attempts
55
+ .slice(-2)
56
+ .filter((attempt) => attempt.summary?.trim().toLowerCase() === normalized).length >= 2;
57
+ }
58
+ //# sourceMappingURL=exit-intelligence.js.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * formatter.ts — SLICE-25
3
+ *
4
+ * Pure artifact-to-explanation formatter. No model calls.
5
+ * Reads StoredAttemptArtifact structures and produces plain-English Markdown
6
+ * and structured JSON explaining every gate decision.
7
+ */
8
+ import type { StoredAttemptArtifact } from "../replay/replay.js";
9
+ export interface ExplainOptions {
10
+ loopId: string;
11
+ /** --attempt N — filter to a single attempt index (1-based) */
12
+ attemptFilter?: number;
13
+ /** --decision <gate> — filter to only one gate's explanation */
14
+ decisionFilter?: string;
15
+ /** --json — request structured JSON output in addition to Markdown */
16
+ json?: boolean;
17
+ }
18
+ export interface ExplainAttempt {
19
+ attemptId: string;
20
+ attemptNumber: number;
21
+ verdict: string;
22
+ grade: string;
23
+ costUsd: number;
24
+ leashBlocked: boolean;
25
+ leashPattern?: string;
26
+ verifierPasses: number;
27
+ verifierTotal: number;
28
+ blockReason?: string;
29
+ warning?: string;
30
+ }
31
+ export interface ExplainJson {
32
+ loopId: string;
33
+ objective: string;
34
+ outcome: string;
35
+ totalCostUsd: number;
36
+ attempts: ExplainAttempt[];
37
+ }
38
+ export interface ExplainOutput {
39
+ markdown: string;
40
+ json: ExplainJson;
41
+ }
42
+ export declare function formatRunExplanation(artifacts: StoredAttemptArtifact[], options: ExplainOptions): ExplainOutput;
@@ -0,0 +1,171 @@
1
+ /**
2
+ * formatter.ts — SLICE-25
3
+ *
4
+ * Pure artifact-to-explanation formatter. No model calls.
5
+ * Reads StoredAttemptArtifact structures and produces plain-English Markdown
6
+ * and structured JSON explaining every gate decision.
7
+ */
8
+ // ─── Formatter ────────────────────────────────────────────────────────────────
9
+ export function formatRunExplanation(artifacts, options) {
10
+ const { loopId, attemptFilter, decisionFilter, json: jsonMode } = options;
11
+ // Build attempt models with safe access for potentially-broken artifacts
12
+ const allAttempts = artifacts.map((art, idx) => {
13
+ return buildAttemptModel(art, idx + 1);
14
+ });
15
+ // Apply attempt filter (1-based)
16
+ const filteredAttempts = attemptFilter != null
17
+ ? allAttempts.filter(a => a.attemptNumber === attemptFilter)
18
+ : allAttempts;
19
+ const objective = artifacts[0]?.objective ?? "unknown";
20
+ const totalCostUsd = allAttempts.reduce((sum, a) => sum + a.costUsd, 0);
21
+ const lastVerdict = allAttempts[allAttempts.length - 1]?.verdict ?? "UNKNOWN";
22
+ // Build JSON output
23
+ const jsonOutput = {
24
+ loopId,
25
+ objective,
26
+ outcome: lastVerdict,
27
+ totalCostUsd,
28
+ attempts: filteredAttempts
29
+ };
30
+ // Build Markdown output
31
+ const lines = [];
32
+ lines.push(`# Run Explanation — ${loopId}`);
33
+ lines.push("");
34
+ lines.push(`**Objective:** ${objective}`);
35
+ lines.push(`**Outcome:** ${lastVerdict}`);
36
+ lines.push(`**Total Cost:** $${totalCostUsd.toFixed(4)}`);
37
+ lines.push("");
38
+ for (const attempt of filteredAttempts) {
39
+ if (attempt.warning) {
40
+ lines.push(`> **Warning:** ${attempt.warning}`);
41
+ lines.push("");
42
+ }
43
+ if (decisionFilter) {
44
+ lines.push(...renderGateSection(attempt, decisionFilter));
45
+ }
46
+ else {
47
+ lines.push(...renderFullAttempt(attempt));
48
+ }
49
+ lines.push("");
50
+ }
51
+ return {
52
+ markdown: lines.join("\n"),
53
+ json: jsonOutput
54
+ };
55
+ }
56
+ // ─── Internal builders ────────────────────────────────────────────────────────
57
+ function buildAttemptModel(artifact, attemptNumber) {
58
+ // Safe access — artifact may be partially broken
59
+ const decisions = artifact.decisions ?? {};
60
+ const leash = decisions.leash ?? { blocked: false };
61
+ const proof = decisions.proof;
62
+ const finalVerdict = decisions.finalVerdict ?? "UNKNOWN";
63
+ let warning;
64
+ let grade = "unknown";
65
+ let verifierPasses = 0;
66
+ let verifierTotal = 0;
67
+ let blockReason;
68
+ if (!proof || typeof proof.grade !== "string") {
69
+ warning = "invalid or missing proof gate data in artifact";
70
+ }
71
+ else {
72
+ grade = proof.grade;
73
+ }
74
+ // Support optional extended fields on artifact (attached by callers)
75
+ const extended = artifact;
76
+ const costUsd = typeof extended.costUsd === "number" ? extended.costUsd : 0;
77
+ if (typeof extended.verifierPasses === "number")
78
+ verifierPasses = extended.verifierPasses;
79
+ if (typeof extended.verifierTotal === "number")
80
+ verifierTotal = extended.verifierTotal;
81
+ if (typeof extended.blockReason === "string")
82
+ blockReason = extended.blockReason;
83
+ return {
84
+ attemptId: artifact.attemptId,
85
+ attemptNumber,
86
+ verdict: finalVerdict,
87
+ grade,
88
+ costUsd,
89
+ leashBlocked: leash.blocked,
90
+ leashPattern: leash.matchedPattern,
91
+ verifierPasses,
92
+ verifierTotal,
93
+ blockReason,
94
+ warning
95
+ };
96
+ }
97
+ function renderFullAttempt(attempt) {
98
+ const lines = [];
99
+ lines.push(`## Attempt ${attempt.attemptNumber}`);
100
+ lines.push("");
101
+ if (attempt.verdict === "ACCEPTED") {
102
+ lines.push(`Attempt ${attempt.attemptNumber} — ACCEPTED. Grade: ${attempt.grade}. ` +
103
+ `Verifier: ${attempt.verifierPasses}/${attempt.verifierTotal} passing. ` +
104
+ `Cost: $${attempt.costUsd.toFixed(4)}.`);
105
+ }
106
+ else if (attempt.leashBlocked) {
107
+ lines.push(`Attempt ${attempt.attemptNumber} — REJECTED by leash. ` +
108
+ `Pattern matched: ${attempt.leashPattern ?? "unknown"}. ` +
109
+ `Cost: $${attempt.costUsd.toFixed(4)}.`);
110
+ }
111
+ else if (attempt.grade === "C") {
112
+ const reason = attempt.blockReason ?? "grade C";
113
+ lines.push(`Attempt ${attempt.attemptNumber} — REJECTED at patch-proof gate. ` +
114
+ `Grade: C. Reason: ${reason}. ` +
115
+ `Cost: $${attempt.costUsd.toFixed(4)}.`);
116
+ }
117
+ else {
118
+ lines.push(`Attempt ${attempt.attemptNumber} — REJECTED. Grade: ${attempt.grade}. ` +
119
+ `Cost: $${attempt.costUsd.toFixed(4)}.`);
120
+ }
121
+ return lines;
122
+ }
123
+ function renderGateSection(attempt, gate) {
124
+ const lines = [];
125
+ lines.push(`## Attempt ${attempt.attemptNumber} — ${gate} gate`);
126
+ lines.push("");
127
+ switch (gate) {
128
+ case "leash": {
129
+ if (attempt.leashBlocked) {
130
+ lines.push(`Attempt ${attempt.attemptNumber} — REJECTED by leash. ` +
131
+ `Pattern matched: ${attempt.leashPattern ?? "unknown"}. ` +
132
+ `Cost: $${attempt.costUsd.toFixed(4)}.`);
133
+ }
134
+ else {
135
+ lines.push(`Attempt ${attempt.attemptNumber} — leash gate PASSED (no dangerous patterns detected).`);
136
+ }
137
+ break;
138
+ }
139
+ case "patch-proof": {
140
+ if (attempt.grade === "C") {
141
+ const reason = attempt.blockReason ?? "grade C";
142
+ lines.push(`Attempt ${attempt.attemptNumber} — REJECTED at patch-proof gate. ` +
143
+ `Grade: C. Reason: ${reason}. ` +
144
+ `Cost: $${attempt.costUsd.toFixed(4)}.`);
145
+ }
146
+ else {
147
+ lines.push(`Attempt ${attempt.attemptNumber} — patch-proof gate PASSED. ` +
148
+ `Grade: ${attempt.grade}. ` +
149
+ `Verifier: ${attempt.verifierPasses}/${attempt.verifierTotal} passing.`);
150
+ }
151
+ break;
152
+ }
153
+ case "grounding": {
154
+ lines.push(`Attempt ${attempt.attemptNumber} — grounding gate. Verdict: ${attempt.verdict}.`);
155
+ break;
156
+ }
157
+ case "budget": {
158
+ lines.push(`Attempt ${attempt.attemptNumber} — cost at this attempt: $${attempt.costUsd.toFixed(4)}.`);
159
+ break;
160
+ }
161
+ case "rollback": {
162
+ lines.push(`Attempt ${attempt.attemptNumber} — rollback gate. Verdict: ${attempt.verdict}.`);
163
+ break;
164
+ }
165
+ default: {
166
+ lines.push(`Attempt ${attempt.attemptNumber} — gate "${gate}" not recognised. Verdict: ${attempt.verdict}.`);
167
+ }
168
+ }
169
+ return lines;
170
+ }
171
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1,29 @@
1
+ import type { LoopEvent, LoopLifecycleState } from "../../contracts/index.js";
2
+ import type { LedgerEvent } from "../persistence/ledger.js";
3
+ export interface RunTimelineEntry {
4
+ timestamp: string;
5
+ source: "loop" | "ledger";
6
+ label: string;
7
+ detail: string;
8
+ severity: "info" | "ok" | "warn";
9
+ attemptIndex?: number;
10
+ }
11
+ export interface RunTimelineJson {
12
+ loopId: string;
13
+ objective: string;
14
+ lifecycleState?: LoopLifecycleState;
15
+ entries: RunTimelineEntry[];
16
+ }
17
+ export interface RunTimelineOutput {
18
+ markdown: string;
19
+ html: string;
20
+ json: RunTimelineJson;
21
+ }
22
+ export interface FormatRunTimelineInput {
23
+ loopId: string;
24
+ objective: string;
25
+ lifecycleState?: LoopLifecycleState;
26
+ events?: LoopEvent[];
27
+ ledgerEvents?: LedgerEvent[];
28
+ }
29
+ export declare function formatRunTimeline(input: FormatRunTimelineInput): RunTimelineOutput;
@@ -0,0 +1,213 @@
1
+ export function formatRunTimeline(input) {
2
+ const entries = buildRunTimelineEntries(input);
3
+ const json = {
4
+ loopId: input.loopId,
5
+ objective: input.objective,
6
+ ...(input.lifecycleState ? { lifecycleState: input.lifecycleState } : {}),
7
+ entries
8
+ };
9
+ return {
10
+ markdown: renderTimelineMarkdown(json),
11
+ html: renderTimelineHtml(json),
12
+ json
13
+ };
14
+ }
15
+ function buildRunTimelineEntries(input) {
16
+ const loopEntries = (input.events ?? []).map(mapLoopEvent);
17
+ const ledgerEntries = (input.ledgerEvents ?? []).map(mapLedgerEvent);
18
+ return [...loopEntries, ...ledgerEntries].sort((left, right) => left.timestamp.localeCompare(right.timestamp));
19
+ }
20
+ function mapLoopEvent(event) {
21
+ switch (event.type) {
22
+ case "run.started":
23
+ return {
24
+ timestamp: event.timestamp,
25
+ source: "loop",
26
+ label: "Run started",
27
+ detail: stringifyPayload(event.payload),
28
+ severity: "info"
29
+ };
30
+ case "attempt.started":
31
+ return {
32
+ timestamp: event.timestamp,
33
+ source: "loop",
34
+ label: "Attempt started",
35
+ detail: stringifyPayload(event.payload),
36
+ severity: "info"
37
+ };
38
+ case "attempt.completed":
39
+ return {
40
+ timestamp: event.timestamp,
41
+ source: "loop",
42
+ label: "Attempt completed",
43
+ detail: stringifyPayload(event.payload),
44
+ severity: "ok"
45
+ };
46
+ case "pattern.detected":
47
+ return {
48
+ timestamp: event.timestamp,
49
+ source: "loop",
50
+ label: "Pattern detected",
51
+ detail: stringifyPayload(event.payload),
52
+ severity: "warn"
53
+ };
54
+ case "failure.classified":
55
+ return {
56
+ timestamp: event.timestamp,
57
+ source: "loop",
58
+ label: "Failure classified",
59
+ detail: stringifyPayload(event.payload),
60
+ severity: "warn"
61
+ };
62
+ case "intervention.selected":
63
+ return {
64
+ timestamp: event.timestamp,
65
+ source: "loop",
66
+ label: "Intervention selected",
67
+ detail: stringifyPayload(event.payload),
68
+ severity: "info"
69
+ };
70
+ case "verification.completed":
71
+ return {
72
+ timestamp: event.timestamp,
73
+ source: "loop",
74
+ label: "Verification completed",
75
+ detail: stringifyPayload(event.payload),
76
+ severity: "ok"
77
+ };
78
+ case "budget.updated":
79
+ return {
80
+ timestamp: event.timestamp,
81
+ source: "loop",
82
+ label: "Budget updated",
83
+ detail: stringifyPayload(event.payload),
84
+ severity: "info"
85
+ };
86
+ case "run.completed":
87
+ return {
88
+ timestamp: event.timestamp,
89
+ source: "loop",
90
+ label: "Run completed",
91
+ detail: stringifyPayload(event.payload),
92
+ severity: "ok"
93
+ };
94
+ }
95
+ }
96
+ function mapLedgerEvent(event) {
97
+ const labelMap = {
98
+ "contract.created": "Contract created",
99
+ "attempt.admitted": "Attempt admitted",
100
+ "attempt.rejected": "Attempt rejected",
101
+ "prompt.compiled": "Prompt compiled",
102
+ "patch.generated": "Patch generated",
103
+ "verification.completed": "Verification completed",
104
+ "grounding.violations_found": "Grounding violation",
105
+ "safety.violations_found": "Safety violation",
106
+ "budget.settled": "Budget settled",
107
+ "attempt.kept": "Attempt kept",
108
+ "attempt.discarded": "Attempt discarded",
109
+ "run.exited": "Run exited"
110
+ };
111
+ const severity = event.kind === "attempt.rejected" ||
112
+ event.kind === "grounding.violations_found" ||
113
+ event.kind === "safety.violations_found" ||
114
+ event.kind === "attempt.discarded" ||
115
+ event.kind === "run.exited"
116
+ ? "warn"
117
+ : event.kind === "attempt.kept" || event.kind === "verification.completed"
118
+ ? "ok"
119
+ : "info";
120
+ return {
121
+ timestamp: event.timestamp,
122
+ source: "ledger",
123
+ label: labelMap[event.kind],
124
+ detail: stringifyPayload(event.payload),
125
+ severity,
126
+ ...(event.attemptIndex !== undefined ? { attemptIndex: event.attemptIndex } : {})
127
+ };
128
+ }
129
+ function renderTimelineMarkdown(timeline) {
130
+ const lines = [
131
+ `# Run Timeline — ${timeline.loopId}`,
132
+ "",
133
+ `**Objective:** ${timeline.objective}`,
134
+ ...(timeline.lifecycleState ? [`**Lifecycle:** ${timeline.lifecycleState}`, ""] : [""]),
135
+ "| Time | Source | Event | Detail |",
136
+ "| --- | --- | --- | --- |",
137
+ ...timeline.entries.map((entry) => {
138
+ const detail = entry.detail.replace(/\|/g, "\\|");
139
+ return `| ${entry.timestamp} | ${entry.source} | ${entry.label} | ${detail} |`;
140
+ })
141
+ ];
142
+ return lines.join("\n");
143
+ }
144
+ function renderTimelineHtml(timeline) {
145
+ const rows = timeline.entries
146
+ .map((entry) => {
147
+ const badgeClass = `badge-${entry.severity}`;
148
+ return [
149
+ "<tr>",
150
+ `<td>${escapeHtml(entry.timestamp)}</td>`,
151
+ `<td><span class="source-chip">${escapeHtml(entry.source)}</span></td>`,
152
+ `<td><span class="badge ${badgeClass}">${escapeHtml(entry.label)}</span></td>`,
153
+ `<td>${escapeHtml(entry.detail)}</td>`,
154
+ "</tr>"
155
+ ].join("");
156
+ })
157
+ .join("\n");
158
+ return [
159
+ "<!DOCTYPE html>",
160
+ '<html lang="en">',
161
+ "<head>",
162
+ '<meta charset="UTF-8" />',
163
+ '<meta name="viewport" content="width=device-width, initial-scale=1.0" />',
164
+ `<title>Run Timeline — ${escapeHtml(timeline.loopId)}</title>`,
165
+ "<style>",
166
+ "body{margin:0;background:#f8f5ed;color:#18181b;font-family:'General Sans',-apple-system,BlinkMacSystemFont,sans-serif;padding:40px;}",
167
+ "h1{font-family:'Fraunces',Georgia,serif;font-size:42px;line-height:1.05;margin:0 0 12px;}",
168
+ "p.meta{color:#5c6170;margin:0 0 28px;font-size:16px;}",
169
+ ".wrap{max-width:1100px;margin:0 auto;}",
170
+ "table{width:100%;border-collapse:collapse;background:#fff;border:1px solid #e6e0d4;border-radius:18px;overflow:hidden;box-shadow:0 18px 50px rgba(17,17,17,.06);}",
171
+ "th,td{padding:14px 16px;border-bottom:1px solid #eee8dc;text-align:left;vertical-align:top;font-size:14px;}",
172
+ "th{font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:#6b7280;background:#fcfbf7;}",
173
+ ".badge,.source-chip{display:inline-flex;align-items:center;border-radius:999px;padding:4px 10px;font-size:12px;font-weight:700;}",
174
+ ".badge-info{background:#ece8ff;color:#4f46e5;}.badge-ok{background:#dcfce7;color:#166534;}.badge-warn{background:#fef3c7;color:#92400e;}",
175
+ ".source-chip{background:#f3f4f6;color:#4b5563;}",
176
+ "</style>",
177
+ "</head>",
178
+ "<body>",
179
+ '<div class="wrap">',
180
+ `<h1>Run timeline</h1>`,
181
+ `<p class="meta"><strong>Loop:</strong> ${escapeHtml(timeline.loopId)}<br/><strong>Objective:</strong> ${escapeHtml(timeline.objective)}${timeline.lifecycleState ? `<br/><strong>Lifecycle:</strong> ${escapeHtml(timeline.lifecycleState)}` : ""}</p>`,
182
+ "<table>",
183
+ "<thead><tr><th>Time</th><th>Source</th><th>Event</th><th>Detail</th></tr></thead>",
184
+ `<tbody>${rows}</tbody>`,
185
+ "</table>",
186
+ "</div>",
187
+ "</body>",
188
+ "</html>"
189
+ ].join("");
190
+ }
191
+ function stringifyPayload(payload) {
192
+ const flattened = Object.entries(payload)
193
+ .map(([key, value]) => `${key}=${formatValue(value)}`)
194
+ .join("; ");
195
+ return flattened || "no additional payload";
196
+ }
197
+ function formatValue(value) {
198
+ if (Array.isArray(value)) {
199
+ return value.join(", ");
200
+ }
201
+ if (value && typeof value === "object") {
202
+ return JSON.stringify(value);
203
+ }
204
+ return String(value);
205
+ }
206
+ function escapeHtml(value) {
207
+ return value
208
+ .replace(/&/g, "&amp;")
209
+ .replace(/</g, "&lt;")
210
+ .replace(/>/g, "&gt;")
211
+ .replace(/"/g, "&quot;");
212
+ }
213
+ //# sourceMappingURL=timeline.js.map
@@ -0,0 +1,2 @@
1
+ import type { FailureAssessment, FailureClassificationInput } from "./types.js";
2
+ export declare function classifyFailure(input: FailureClassificationInput): FailureAssessment;
@@ -0,0 +1,76 @@
1
+ export function classifyFailure(input) {
2
+ const failureClass = detectFailureClass(input);
3
+ const repeatedCount = countRecentMatches(input.attempts, failureClass);
4
+ const retryable = failureClass !== "environment_mismatch";
5
+ const recommendedIntervention = chooseIntervention(failureClass, repeatedCount);
6
+ return {
7
+ failureClass,
8
+ retryable,
9
+ recommendedIntervention,
10
+ rationale: buildRationale(failureClass, input, repeatedCount, recommendedIntervention)
11
+ };
12
+ }
13
+ function detectFailureClass(input) {
14
+ const hint = input.result.failure?.classHint;
15
+ if (hint) {
16
+ return hint;
17
+ }
18
+ const haystack = [
19
+ input.result.summary,
20
+ input.result.verification.summary,
21
+ input.result.failure?.message
22
+ ]
23
+ .filter((value) => typeof value === "string")
24
+ .join(" ")
25
+ .toLowerCase();
26
+ if (containsAny(haystack, ["enoent", "command not found", "missing from path", "permission denied"])) {
27
+ return "environment_mismatch";
28
+ }
29
+ if (containsAny(haystack, ["syntax", "parse", "eslint", "ts1"])) {
30
+ return "syntax_error";
31
+ }
32
+ if (containsAny(haystack, ["budget", "token", "limit", "cost"])) {
33
+ return "budget_pressure";
34
+ }
35
+ if (containsAny(haystack, ["scope", "too broad", "expanded"])) {
36
+ return "scope_creep";
37
+ }
38
+ if (containsAny(haystack, ["hallucin", "invented", "made up"])) {
39
+ return "hallucination";
40
+ }
41
+ if (!input.result.verification.passed) {
42
+ return "verification_failure";
43
+ }
44
+ return "logic_error";
45
+ }
46
+ function chooseIntervention(failureClass, repeatedCount) {
47
+ if (failureClass === "environment_mismatch") {
48
+ return repeatedCount >= 2 ? "switch_adapter" : "escalate_human";
49
+ }
50
+ if (failureClass === "budget_pressure") {
51
+ return "compress_context";
52
+ }
53
+ if (failureClass === "scope_creep") {
54
+ return "tighten_task";
55
+ }
56
+ if (failureClass === "verification_failure" || failureClass === "syntax_error") {
57
+ return "run_verifier";
58
+ }
59
+ if (repeatedCount >= 2) {
60
+ return "change_model";
61
+ }
62
+ return "change_model";
63
+ }
64
+ function buildRationale(failureClass, input, repeatedCount, intervention) {
65
+ const evidence = input.result.failure?.message ?? input.result.verification.summary;
66
+ const repetitionNote = repeatedCount >= 2 ? ` The same failure appeared in ${repeatedCount} recent attempts.` : "";
67
+ return `${failureClass} inferred from "${evidence}". Recommended intervention: ${intervention}.${repetitionNote}`;
68
+ }
69
+ function countRecentMatches(attempts, failureClass) {
70
+ const recent = attempts.slice(-3).filter((attempt) => attempt.failureClass === failureClass);
71
+ return recent.length;
72
+ }
73
+ function containsAny(value, needles) {
74
+ return needles.some((needle) => value.includes(needle));
75
+ }
76
+ //# sourceMappingURL=failure-taxonomy.js.map
@@ -0,0 +1,10 @@
1
+ export * from "./registry.js";
2
+ export * from "./transport.js";
3
+ export * from "./vault.js";
4
+ import { McpServerRegistry, type McpServerConfig } from "./registry.js";
5
+ import { McpHttpTransport } from "./transport.js";
6
+ import type { McpTokenVault } from "./vault.js";
7
+ export declare function createGateway(servers: McpServerConfig[], vault?: McpTokenVault): {
8
+ registry: McpServerRegistry;
9
+ transport: McpHttpTransport;
10
+ };
@@ -0,0 +1,12 @@
1
+ export * from "./registry.js";
2
+ export * from "./transport.js";
3
+ export * from "./vault.js";
4
+ import { McpServerRegistry } from "./registry.js";
5
+ import { McpHttpTransport } from "./transport.js";
6
+ export function createGateway(servers, vault) {
7
+ return {
8
+ registry: new McpServerRegistry(servers),
9
+ transport: new McpHttpTransport(vault)
10
+ };
11
+ }
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,40 @@
1
+ export interface McpServerConfig {
2
+ id: string;
3
+ name: string;
4
+ url: string;
5
+ headers?: Record<string, string>;
6
+ trustTier: "system" | "verified" | "untrusted";
7
+ allowedTools: string[];
8
+ blockedTools: string[];
9
+ }
10
+ export type ToolPolicyDecision = {
11
+ action: "allow";
12
+ } | {
13
+ action: "deny";
14
+ reason: string;
15
+ } | {
16
+ action: "simulate";
17
+ mockResponse: unknown;
18
+ } | {
19
+ action: "review";
20
+ reason: string;
21
+ };
22
+ export interface ToolExecutionAttempt {
23
+ serverId: string;
24
+ toolName: string;
25
+ args: Record<string, unknown>;
26
+ context: {
27
+ loopId: string;
28
+ executionProfile?: string;
29
+ };
30
+ }
31
+ export declare class McpServerRegistry {
32
+ private readonly servers;
33
+ constructor(initialServers?: McpServerConfig[]);
34
+ register(server: McpServerConfig): void;
35
+ unregister(serverId: string): boolean;
36
+ getServer(serverId: string): McpServerConfig | undefined;
37
+ listServers(): McpServerConfig[];
38
+ evaluateToolPolicy(attempt: ToolExecutionAttempt): ToolPolicyDecision;
39
+ private matchesPattern;
40
+ }