martin-loop 0.1.4 → 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 (286) hide show
  1. package/CODE_OF_CONDUCT.md +32 -0
  2. package/README.md +172 -227
  3. package/demo/seeded-workspace/README.md +35 -0
  4. package/demo/seeded-workspace/TASKS.md +29 -0
  5. package/demo/seeded-workspace/martin.config.yaml +11 -0
  6. package/demo/seeded-workspace/package.json +8 -0
  7. package/demo/seeded-workspace/src/invoice-summary.js +11 -0
  8. package/demo/seeded-workspace/test/invoice-summary.test.js +20 -0
  9. package/dist/bin/martin-loop.js +0 -0
  10. package/dist/vendor/adapters/claude-cli.d.ts +19 -4
  11. package/dist/vendor/adapters/claude-cli.js +55 -24
  12. package/dist/vendor/adapters/cli-bridge.d.ts +1 -0
  13. package/dist/vendor/adapters/cli-bridge.js +154 -28
  14. package/dist/vendor/adapters/counter.d.ts +1 -0
  15. package/dist/vendor/adapters/counter.js +4 -0
  16. package/dist/vendor/adapters/git-baseline.d.ts +50 -0
  17. package/dist/vendor/adapters/git-baseline.js +233 -0
  18. package/dist/vendor/adapters/index.d.ts +1 -0
  19. package/dist/vendor/adapters/index.js +1 -0
  20. package/dist/vendor/adapters/openrouter-adapter.d.ts +15 -0
  21. package/dist/vendor/adapters/openrouter-adapter.js +302 -0
  22. package/dist/vendor/adapters/usage.d.ts +48 -0
  23. package/dist/vendor/adapters/usage.js +66 -0
  24. package/dist/vendor/adapters/verifier-only.d.ts +7 -0
  25. package/dist/vendor/adapters/verifier-only.js +57 -0
  26. package/dist/vendor/cli/bin/exit.d.ts +12 -0
  27. package/dist/vendor/cli/bin/exit.js +28 -0
  28. package/dist/vendor/cli/commands/analyze.d.ts +5 -0
  29. package/dist/vendor/cli/commands/analyze.js +58 -0
  30. package/dist/vendor/cli/commands/audit-log-verify.d.ts +34 -0
  31. package/dist/vendor/cli/commands/audit-log-verify.js +99 -0
  32. package/dist/vendor/cli/commands/audit.d.ts +8 -0
  33. package/dist/vendor/cli/commands/audit.js +199 -0
  34. package/dist/vendor/cli/commands/corpus.d.ts +5 -0
  35. package/dist/vendor/cli/commands/corpus.js +60 -0
  36. package/dist/vendor/cli/commands/doctor.d.ts +8 -0
  37. package/dist/vendor/cli/commands/doctor.js +219 -0
  38. package/dist/vendor/cli/commands/explain.d.ts +17 -0
  39. package/dist/vendor/cli/commands/explain.js +176 -0
  40. package/dist/vendor/cli/commands/export.d.ts +5 -0
  41. package/dist/vendor/cli/commands/export.js +60 -0
  42. package/dist/vendor/cli/commands/governance.d.ts +8 -0
  43. package/dist/vendor/cli/commands/governance.js +95 -0
  44. package/dist/vendor/cli/commands/improve.d.ts +18 -0
  45. package/dist/vendor/cli/commands/improve.js +396 -0
  46. package/dist/vendor/cli/commands/init.d.ts +8 -0
  47. package/dist/vendor/cli/commands/init.js +281 -0
  48. package/dist/vendor/cli/commands/migration.d.ts +8 -0
  49. package/dist/vendor/cli/commands/migration.js +67 -0
  50. package/dist/vendor/cli/commands/prior.d.ts +23 -0
  51. package/dist/vendor/cli/commands/prior.js +145 -0
  52. package/dist/vendor/cli/commands/resume.d.ts +21 -0
  53. package/dist/vendor/cli/commands/resume.js +73 -0
  54. package/dist/vendor/cli/commands/verify.d.ts +6 -0
  55. package/dist/vendor/cli/commands/verify.js +43 -0
  56. package/dist/vendor/cli/index.d.ts +6 -1
  57. package/dist/vendor/cli/index.js +124 -7
  58. package/dist/vendor/cli/research/public-corpus.d.ts +43 -0
  59. package/dist/vendor/cli/research/public-corpus.js +151 -0
  60. package/dist/vendor/cli/ui/error-card.d.ts +38 -0
  61. package/dist/vendor/cli/ui/error-card.js +103 -0
  62. package/dist/vendor/cli/ui/mission-brief.d.ts +41 -0
  63. package/dist/vendor/cli/ui/mission-brief.js +173 -0
  64. package/dist/vendor/cli/ui/summary-card.d.ts +34 -0
  65. package/dist/vendor/cli/ui/summary-card.js +102 -0
  66. package/dist/vendor/contracts/audit.d.ts +46 -0
  67. package/dist/vendor/contracts/audit.js +360 -0
  68. package/dist/vendor/contracts/index.d.ts +3 -1
  69. package/dist/vendor/contracts/post-phase15.d.ts +240 -0
  70. package/dist/vendor/contracts/post-phase15.js +166 -0
  71. package/dist/vendor/core/agent/mandates.d.ts +46 -0
  72. package/dist/vendor/core/agent/mandates.js +178 -0
  73. package/dist/vendor/core/agent/receipts.d.ts +38 -0
  74. package/dist/vendor/core/agent/receipts.js +131 -0
  75. package/dist/vendor/core/agent/signing.d.ts +17 -0
  76. package/dist/vendor/core/agent/signing.js +91 -0
  77. package/dist/vendor/core/attestation/sign.d.ts +25 -0
  78. package/dist/vendor/core/attestation/sign.js +216 -0
  79. package/dist/vendor/core/autonomy/autonomous-promotion.d.ts +120 -0
  80. package/dist/vendor/core/autonomy/autonomous-promotion.js +346 -0
  81. package/dist/vendor/core/autonomy/envelope-v2.d.ts +29 -0
  82. package/dist/vendor/core/autonomy/envelope-v2.js +60 -0
  83. package/dist/vendor/core/autonomy/envelope.d.ts +17 -0
  84. package/dist/vendor/core/autonomy/envelope.js +27 -0
  85. package/dist/vendor/core/autonomy/escalation-ledger.d.ts +20 -0
  86. package/dist/vendor/core/autonomy/escalation-ledger.js +18 -0
  87. package/dist/vendor/core/autonomy/resume.d.ts +15 -0
  88. package/dist/vendor/core/autonomy/resume.js +23 -0
  89. package/dist/vendor/core/circuit/circuit-breaker.d.ts +60 -0
  90. package/dist/vendor/core/circuit/circuit-breaker.js +143 -0
  91. package/dist/vendor/core/compiler.d.ts +2 -0
  92. package/dist/vendor/core/compiler.js +10 -4
  93. package/dist/vendor/core/context-distillation.d.ts +3 -0
  94. package/dist/vendor/core/context-distillation.js +44 -0
  95. package/dist/vendor/core/context-flow/compile-context.d.ts +8 -0
  96. package/dist/vendor/core/context-flow/compile-context.js +111 -0
  97. package/dist/vendor/core/context-flow/entities.d.ts +2 -0
  98. package/dist/vendor/core/context-flow/entities.js +44 -0
  99. package/dist/vendor/core/context-flow/evaluate-policy.d.ts +2 -0
  100. package/dist/vendor/core/context-flow/evaluate-policy.js +42 -0
  101. package/dist/vendor/core/context-flow/index.d.ts +11 -0
  102. package/dist/vendor/core/context-flow/index.js +24 -0
  103. package/dist/vendor/core/context-flow/labels.d.ts +3 -0
  104. package/dist/vendor/core/context-flow/labels.js +17 -0
  105. package/dist/vendor/core/context-flow/normalizer.d.ts +9 -0
  106. package/dist/vendor/core/context-flow/normalizer.js +69 -0
  107. package/dist/vendor/core/context-flow/profiles.d.ts +33 -0
  108. package/dist/vendor/core/context-flow/profiles.js +36 -0
  109. package/dist/vendor/core/context-flow/redaction.d.ts +1 -0
  110. package/dist/vendor/core/context-flow/redaction.js +6 -0
  111. package/dist/vendor/core/context-flow/sensitivity.d.ts +2 -0
  112. package/dist/vendor/core/context-flow/sensitivity.js +27 -0
  113. package/dist/vendor/core/context-flow/sync-preview.d.ts +2 -0
  114. package/dist/vendor/core/context-flow/sync-preview.js +22 -0
  115. package/dist/vendor/core/context-flow/token-estimator.d.ts +3 -0
  116. package/dist/vendor/core/context-flow/token-estimator.js +13 -0
  117. package/dist/vendor/core/context-flow/types.d.ts +91 -0
  118. package/dist/vendor/core/context-flow/types.js +2 -0
  119. package/dist/vendor/core/context-integrity.d.ts +26 -0
  120. package/dist/vendor/core/context-integrity.js +56 -0
  121. package/dist/vendor/core/context-utility.d.ts +47 -0
  122. package/dist/vendor/core/context-utility.js +405 -0
  123. package/dist/vendor/core/cost/pipeline.d.ts +92 -0
  124. package/dist/vendor/core/cost/pipeline.js +141 -0
  125. package/dist/vendor/core/cost/tagged-cost.d.ts +27 -0
  126. package/dist/vendor/core/cost/tagged-cost.js +55 -0
  127. package/dist/vendor/core/cost-governor.d.ts +2 -0
  128. package/dist/vendor/core/cost-governor.js +50 -0
  129. package/dist/vendor/core/cve/cve-check.d.ts +80 -0
  130. package/dist/vendor/core/cve/cve-check.js +172 -0
  131. package/dist/vendor/core/digital-twin/index.d.ts +27 -0
  132. package/dist/vendor/core/digital-twin/index.js +90 -0
  133. package/dist/vendor/core/drift/drift-graph.d.ts +47 -0
  134. package/dist/vendor/core/drift/drift-graph.js +100 -0
  135. package/dist/vendor/core/drift/objective-lock.d.ts +69 -0
  136. package/dist/vendor/core/drift/objective-lock.js +88 -0
  137. package/dist/vendor/core/drift/scope.d.ts +46 -0
  138. package/dist/vendor/core/drift/scope.js +102 -0
  139. package/dist/vendor/core/drift/signature-lock.d.ts +48 -0
  140. package/dist/vendor/core/drift/signature-lock.js +202 -0
  141. package/dist/vendor/core/drift/stale-proof-gate.d.ts +21 -0
  142. package/dist/vendor/core/drift/stale-proof-gate.js +19 -0
  143. package/dist/vendor/core/eval/known-bad-world-runner.d.ts +24 -0
  144. package/dist/vendor/core/eval/known-bad-world-runner.js +256 -0
  145. package/dist/vendor/core/evidence/claim-audit.d.ts +18 -0
  146. package/dist/vendor/core/evidence/claim-audit.js +89 -0
  147. package/dist/vendor/core/exit-intelligence.d.ts +2 -0
  148. package/dist/vendor/core/exit-intelligence.js +58 -0
  149. package/dist/vendor/core/explain/formatter.d.ts +42 -0
  150. package/dist/vendor/core/explain/formatter.js +171 -0
  151. package/dist/vendor/core/explain/timeline.d.ts +29 -0
  152. package/dist/vendor/core/explain/timeline.js +213 -0
  153. package/dist/vendor/core/failure-taxonomy.d.ts +2 -0
  154. package/dist/vendor/core/failure-taxonomy.js +76 -0
  155. package/dist/vendor/core/gateway/index.d.ts +10 -0
  156. package/dist/vendor/core/gateway/index.js +12 -0
  157. package/dist/vendor/core/gateway/registry.d.ts +40 -0
  158. package/dist/vendor/core/gateway/registry.js +97 -0
  159. package/dist/vendor/core/gateway/transport.d.ts +31 -0
  160. package/dist/vendor/core/gateway/transport.js +82 -0
  161. package/dist/vendor/core/gateway/vault.d.ts +19 -0
  162. package/dist/vendor/core/gateway/vault.js +29 -0
  163. package/dist/vendor/core/graph/adapters.d.ts +43 -0
  164. package/dist/vendor/core/graph/adapters.js +91 -0
  165. package/dist/vendor/core/graph/hotspots.d.ts +22 -0
  166. package/dist/vendor/core/graph/hotspots.js +30 -0
  167. package/dist/vendor/core/graph/index.d.ts +1 -0
  168. package/dist/vendor/core/graph/index.js +2 -0
  169. package/dist/vendor/core/honey/honey-tokens.d.ts +32 -0
  170. package/dist/vendor/core/honey/honey-tokens.js +44 -0
  171. package/dist/vendor/core/index.d.ts +7 -4
  172. package/dist/vendor/core/index.js +222 -64
  173. package/dist/vendor/core/learning/bayesian-update.d.ts +31 -0
  174. package/dist/vendor/core/learning/bayesian-update.js +60 -0
  175. package/dist/vendor/core/learning/prior-sets.d.ts +42 -0
  176. package/dist/vendor/core/learning/prior-sets.js +111 -0
  177. package/dist/vendor/core/learning/promotion-gate.d.ts +17 -0
  178. package/dist/vendor/core/learning/promotion-gate.js +23 -0
  179. package/dist/vendor/core/leash/blast-radius.d.ts +42 -0
  180. package/dist/vendor/core/leash/blast-radius.js +156 -0
  181. package/dist/vendor/core/leash/policy-leash.d.ts +31 -0
  182. package/dist/vendor/core/leash/policy-leash.js +117 -0
  183. package/dist/vendor/core/memo/memo.d.ts +63 -0
  184. package/dist/vendor/core/memo/memo.js +97 -0
  185. package/dist/vendor/core/memory/learning-pipeline.d.ts +154 -0
  186. package/dist/vendor/core/memory/learning-pipeline.js +391 -0
  187. package/dist/vendor/core/memory/palace.d.ts +84 -0
  188. package/dist/vendor/core/memory/palace.js +379 -0
  189. package/dist/vendor/core/merge/ast-merge.d.ts +22 -0
  190. package/dist/vendor/core/merge/ast-merge.js +350 -0
  191. package/dist/vendor/core/merge/text-merge.d.ts +12 -0
  192. package/dist/vendor/core/merge/text-merge.js +182 -0
  193. package/dist/vendor/core/otel/tracer.d.ts +45 -0
  194. package/dist/vendor/core/otel/tracer.js +116 -0
  195. package/dist/vendor/core/parallel/parallel-attempts.d.ts +28 -0
  196. package/dist/vendor/core/parallel/parallel-attempts.js +41 -0
  197. package/dist/vendor/core/parallel/scorer.d.ts +24 -0
  198. package/dist/vendor/core/parallel/scorer.js +65 -0
  199. package/dist/vendor/core/pattern-detection.d.ts +64 -0
  200. package/dist/vendor/core/pattern-detection.js +108 -0
  201. package/dist/vendor/core/persistence/checkpoint.d.ts +44 -0
  202. package/dist/vendor/core/persistence/checkpoint.js +156 -0
  203. package/dist/vendor/core/persistence/cleanup.d.ts +22 -0
  204. package/dist/vendor/core/persistence/cleanup.js +131 -0
  205. package/dist/vendor/core/persistence/index.d.ts +2 -0
  206. package/dist/vendor/core/persistence/index.js +1 -0
  207. package/dist/vendor/core/persistence/runs-reader.d.ts +52 -0
  208. package/dist/vendor/core/persistence/runs-reader.js +84 -0
  209. package/dist/vendor/core/persistence/store.d.ts +6 -1
  210. package/dist/vendor/core/persistence/store.js +5 -0
  211. package/dist/vendor/core/policy/file-touch-quota.d.ts +60 -0
  212. package/dist/vendor/core/policy/file-touch-quota.js +105 -0
  213. package/dist/vendor/core/policy/policy-loader.d.ts +30 -0
  214. package/dist/vendor/core/policy/policy-loader.js +170 -0
  215. package/dist/vendor/core/policy/policy-schema.d.ts +55 -0
  216. package/dist/vendor/core/policy/policy-schema.js +78 -0
  217. package/dist/vendor/core/policy.d.ts +6 -0
  218. package/dist/vendor/core/probe/probe.d.ts +49 -0
  219. package/dist/vendor/core/probe/probe.js +115 -0
  220. package/dist/vendor/core/proof/patch-proof.d.ts +58 -0
  221. package/dist/vendor/core/proof/patch-proof.js +84 -0
  222. package/dist/vendor/core/proof/semantic-probe.d.ts +25 -0
  223. package/dist/vendor/core/proof/semantic-probe.js +82 -0
  224. package/dist/vendor/core/recovery/failure-mode-runner.d.ts +29 -0
  225. package/dist/vendor/core/recovery/failure-mode-runner.js +39 -0
  226. package/dist/vendor/core/red-blue/red-phase.d.ts +64 -0
  227. package/dist/vendor/core/red-blue/red-phase.js +141 -0
  228. package/dist/vendor/core/red-blue/risk-tiers.d.ts +22 -0
  229. package/dist/vendor/core/red-blue/risk-tiers.js +33 -0
  230. package/dist/vendor/core/replay/replay.d.ts +85 -0
  231. package/dist/vendor/core/replay/replay.js +109 -0
  232. package/dist/vendor/core/router/engine.d.ts +54 -0
  233. package/dist/vendor/core/router/engine.js +131 -0
  234. package/dist/vendor/core/router/index.d.ts +1 -0
  235. package/dist/vendor/core/router/index.js +2 -0
  236. package/dist/vendor/core/router/trust-calibration.d.ts +57 -0
  237. package/dist/vendor/core/router/trust-calibration.js +127 -0
  238. package/dist/vendor/core/run-martin.d.ts +2 -0
  239. package/dist/vendor/core/run-martin.js +287 -0
  240. package/dist/vendor/core/security/cve-scanner.d.ts +62 -0
  241. package/dist/vendor/core/security/cve-scanner.js +178 -0
  242. package/dist/vendor/core/sentinel/efficiency-sentinel.d.ts +29 -0
  243. package/dist/vendor/core/sentinel/efficiency-sentinel.js +30 -0
  244. package/dist/vendor/core/sentinel/progress-guard.d.ts +35 -0
  245. package/dist/vendor/core/sentinel/progress-guard.js +46 -0
  246. package/dist/vendor/core/siem/siem-emitter.d.ts +49 -0
  247. package/dist/vendor/core/siem/siem-emitter.js +157 -0
  248. package/dist/vendor/core/strategy/attempt-brief.d.ts +22 -0
  249. package/dist/vendor/core/strategy/attempt-brief.js +89 -0
  250. package/dist/vendor/core/summarize/diff-summary.d.ts +35 -0
  251. package/dist/vendor/core/summarize/diff-summary.js +204 -0
  252. package/dist/vendor/core/surface-signals.d.ts +21 -0
  253. package/dist/vendor/core/surface-signals.js +139 -0
  254. package/dist/vendor/core/truth/truth-wall.d.ts +51 -0
  255. package/dist/vendor/core/truth/truth-wall.js +69 -0
  256. package/dist/vendor/core/truth-spine.d.ts +26 -0
  257. package/dist/vendor/core/truth-spine.js +62 -0
  258. package/dist/vendor/core/types.d.ts +115 -0
  259. package/dist/vendor/core/types.js +2 -0
  260. package/dist/vendor/core/verification/tiered-verify.d.ts +17 -0
  261. package/dist/vendor/core/verification/tiered-verify.js +29 -0
  262. package/dist/vendor/core/verifier-pyramid.d.ts +32 -0
  263. package/dist/vendor/core/verifier-pyramid.js +111 -0
  264. package/dist/vendor/core/workflow-artifacts.d.ts +99 -0
  265. package/dist/vendor/core/workflow-artifacts.js +668 -0
  266. package/dist/vendor/core/wrap/supervised-run.d.ts +96 -0
  267. package/dist/vendor/core/wrap/supervised-run.js +178 -0
  268. package/docs/assets/cli-animated.svg +139 -0
  269. package/docs/assets/cli-static.svg +34 -0
  270. package/docs/assets/github-hero-v2.svg +23 -0
  271. package/docs/assets/martin-raplph.png.jpg +0 -0
  272. package/docs/assets/martinloop-logo.png +0 -0
  273. package/docs/assets/nvidia-inception-program-light.png +0 -0
  274. package/docs/assets/nvidia-inception-program.png +0 -0
  275. package/docs/assets/phase3c-sidesidebyside-demo.html +228 -0
  276. package/docs/assets/side-by-side.svg +134 -0
  277. package/docs/oss/CLAUDE-CODE-WALKTHROUGH.md +142 -0
  278. package/docs/oss/EXAMPLES.md +9 -1
  279. package/docs/oss/OSS-BOUNDARY-REPORT.json +109 -113
  280. package/docs/oss/OSS-BOUNDARY-REPORT.md +48 -48
  281. package/docs/oss/QUICKSTART.md +39 -4
  282. package/docs/oss/RALPH-LOOP-SAFETY.md +113 -0
  283. package/docs/oss/README.md +7 -4
  284. package/docs/oss/RELEASE-SURFACE-REPORT.json +46 -45
  285. package/docs/oss/RELEASE-SURFACE-REPORT.md +36 -35
  286. package/package.json +129 -49
@@ -0,0 +1,20 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+
4
+ import { summarizeInvoice } from "../src/invoice-summary.js";
5
+
6
+ test("summarizeInvoice returns subtotal, tax, and total", () => {
7
+ const result = summarizeInvoice(
8
+ [
9
+ { quantity: 2, unitPrice: 19.99 },
10
+ { quantity: 1, unitPrice: 5.5 }
11
+ ],
12
+ 0.13
13
+ );
14
+
15
+ assert.deepEqual(result, {
16
+ subtotal: 45.48,
17
+ tax: 5.91,
18
+ total: 51.39
19
+ });
20
+ });
File without changes
@@ -15,15 +15,18 @@ import type { MartinAdapter } from "../core/index.js";
15
15
  import { type SpawnLike } from "./cli-bridge.js";
16
16
  /**
17
17
  * Given a prompt string, returns the full argv array to pass to spawn().
18
- * Example for Claude: (p) => ["--print", p, "--dangerously-skip-permissions"]
19
- * Example for Codex: (p) => ["--full-auto", p]
18
+ * Example for Claude: () => ["--output-format", "json", "--print"]
19
+ * Example for Codex: () => ["exec", "--sandbox", "workspace-write", "-"]
20
20
  */
21
21
  export type CliArgsBuilder = (prompt: string) => string[];
22
+ export type CliStdinBuilder = (prompt: string) => string | undefined;
22
23
  export interface AgentCliAdapterOptions {
23
24
  /** The executable to spawn (e.g. "claude", "codex"). */
24
25
  command: string;
25
26
  /** Converts a prompt string into the argv array passed to spawn(). */
26
27
  argsBuilder: CliArgsBuilder;
28
+ /** Optional stdin payload for CLIs that accept prompt input via stdin or `-`. */
29
+ stdinBuilder?: CliStdinBuilder;
27
30
  /** Adapter ID suffix. Defaults to command. */
28
31
  adapterIdSuffix?: string;
29
32
  /** Working directory for all subprocesses. Defaults to process.cwd(). */
@@ -63,8 +66,16 @@ export interface CodexCliAdapterOptions {
63
66
  label?: string;
64
67
  /** Override the model passed via --model flag. */
65
68
  model?: string;
66
- /** Run in full-auto mode (--full-auto). Defaults to true. */
69
+ /**
70
+ * Deprecated no-op retained for compatibility.
71
+ *
72
+ * Codex CLI's supported non-interactive entrypoint is `codex exec`.
73
+ * MartinLoop now uses explicit sandboxing instead of the legacy
74
+ * `--full-auto` compatibility path, which can exit before verifier execution.
75
+ */
67
76
  fullAuto?: boolean;
77
+ /** Codex sandbox mode for model-generated commands. Defaults to workspace-write. */
78
+ sandbox?: "read-only" | "workspace-write" | "danger-full-access";
68
79
  /** Extra args appended after core args (before prompt). */
69
80
  extraArgs?: string[];
70
81
  spawnImpl?: SpawnLike;
@@ -81,7 +92,11 @@ export declare function createAgentCliAdapter(options: AgentCliAdapterOptions):
81
92
  */
82
93
  export declare function createClaudeCliAdapter(options?: ClaudeCliAdapterOptions): MartinAdapter;
83
94
  /**
84
- * Spawns `codex [--full-auto] [--model <model>] "<prompt>" [extraArgs]`.
95
+ * Spawns `codex exec --cd <workspace> --sandbox <mode> [--model <model>] [extraArgs] -`.
96
+ *
97
+ * The prompt is delivered via stdin so Windows shell quoting cannot truncate or
98
+ * reinterpret long MartinLoop prompts that contain paths, deny rules, or budget
99
+ * context.
85
100
  *
86
101
  * Requires the Codex CLI to be installed and authenticated:
87
102
  * npm install -g @openai/codex
@@ -129,15 +129,12 @@ export function createAgentCliAdapter(options) {
129
129
  }
130
130
  }
131
131
  const args = options.argsBuilder(prompt);
132
- // stdinPrompt: if argsBuilder signals stdin delivery by returning args ending with "--stdin-prompt",
133
- // remove that sentinel and pass the prompt via stdin instead (avoids Windows shell-escaping issues).
134
- const useStdin = args.at(-1) === "--stdin-prompt";
135
- const spawnArgs = useStdin ? args.slice(0, -1) : args;
136
- const agentResult = await runSubprocess(options.command, spawnArgs, {
132
+ const stdinData = options.stdinBuilder?.(prompt);
133
+ const agentResult = await runSubprocess(options.command, args, {
137
134
  cwd: workingDirectory,
138
135
  timeoutMs,
139
136
  spawnImpl: options.spawnImpl,
140
- ...(useStdin ? { stdinData: prompt } : {})
137
+ ...(stdinData === undefined ? {} : { stdinData })
141
138
  });
142
139
  if (agentResult.timedOut) {
143
140
  return {
@@ -157,18 +154,19 @@ export function createAgentCliAdapter(options) {
157
154
  };
158
155
  }
159
156
  if (agentResult.exitCode !== 0 && agentResult.stdout.trim().length === 0) {
157
+ const failureMessage = formatPreVerifierSubprocessFailure(options.command, agentResult.stderr, agentResult.exitCode);
160
158
  return {
161
159
  status: "failed",
162
- summary: `${options.command} subprocess exited with an error.`,
160
+ summary: `${options.command} subprocess exited before verifier execution.`,
163
161
  usage: normalizeUsage({
164
162
  actualUsd: 0,
165
163
  tokensIn: 0,
166
164
  tokensOut: 0,
167
165
  provenance: "unavailable"
168
166
  }),
169
- verification: { passed: false, summary: "Subprocess error." },
167
+ verification: { passed: false, summary: `Verifier not run: ${failureMessage}` },
170
168
  failure: {
171
- message: `${agentResult.stderr.trim() || `Exit code ${String(agentResult.exitCode)}`}. environment_mismatch`
169
+ message: failureMessage
172
170
  }
173
171
  };
174
172
  }
@@ -355,40 +353,52 @@ export function createClaudeCliAdapter(options = {}) {
355
353
  "--print",
356
354
  "--dangerously-skip-permissions",
357
355
  ...modelArgs,
358
- ...extraArgs,
359
- "--stdin-prompt" // sentinel: tells execute() to deliver prompt via stdin
360
- ]
356
+ ...extraArgs
357
+ ],
358
+ stdinBuilder: (prompt) => prompt
361
359
  });
362
360
  }
363
361
  // ---------------------------------------------------------------------------
364
362
  // Pre-configured: OpenAI Codex CLI
365
363
  // ---------------------------------------------------------------------------
366
364
  /**
367
- * Spawns `codex [--full-auto] [--model <model>] "<prompt>" [extraArgs]`.
365
+ * Spawns `codex exec --cd <workspace> --sandbox <mode> [--model <model>] [extraArgs] -`.
366
+ *
367
+ * The prompt is delivered via stdin so Windows shell quoting cannot truncate or
368
+ * reinterpret long MartinLoop prompts that contain paths, deny rules, or budget
369
+ * context.
368
370
  *
369
371
  * Requires the Codex CLI to be installed and authenticated:
370
372
  * npm install -g @openai/codex
371
373
  */
372
374
  export function createCodexCliAdapter(options = {}) {
373
- const fullAuto = options.fullAuto !== false;
374
375
  const modelArgs = options.model ? ["--model", options.model] : [];
375
376
  const extraArgs = options.extraArgs ?? [];
377
+ const sandbox = options.sandbox ?? "workspace-write";
378
+ const workingDirectory = options.workingDirectory ?? process.cwd();
376
379
  return createAgentCliAdapter({
377
380
  command: "codex",
378
381
  adapterIdSuffix: "codex",
379
382
  model: options.model ?? "codex",
380
383
  label: options.label ?? "Codex CLI adapter",
381
- workingDirectory: options.workingDirectory,
384
+ workingDirectory,
382
385
  timeoutMs: options.timeoutMs,
383
386
  verifyTimeoutMs: options.verifyTimeoutMs,
384
387
  supportsJsonOutput: false,
385
388
  spawnImpl: options.spawnImpl,
386
- argsBuilder: (prompt) => [
387
- ...(fullAuto ? ["--full-auto"] : []),
389
+ argsBuilder: () => [
390
+ "exec",
391
+ "--cd",
392
+ workingDirectory,
393
+ "--sandbox",
394
+ sandbox,
395
+ "--color",
396
+ "never",
388
397
  ...modelArgs,
389
- prompt,
390
- ...extraArgs
391
- ]
398
+ ...extraArgs,
399
+ "-"
400
+ ],
401
+ stdinBuilder: (prompt) => prompt
392
402
  });
393
403
  }
394
404
  // ---------------------------------------------------------------------------
@@ -402,14 +412,23 @@ export function createCodexCliAdapter(options = {}) {
402
412
  // ---------------------------------------------------------------------------
403
413
  function buildPrompt(request) {
404
414
  const lines = [];
415
+ const mutationMode = request.context.mutationMode ?? "edit";
405
416
  lines.push("You are running in autonomous agentic mode.");
406
- lines.push("MAKE ALL REQUIRED FILE EDITS NOW. Do not ask for confirmation. Do not ask clarifying questions.");
407
- lines.push("Do not explain what you found without also making the changes. Edit the files and complete the task.");
417
+ if (mutationMode === "verify_only") {
418
+ lines.push("DO NOT EDIT FILES. Run the verifier only and report whether it passes.");
419
+ lines.push("Do not ask for confirmation. Do not ask clarifying questions.");
420
+ }
421
+ else {
422
+ lines.push("MAKE ALL REQUIRED FILE EDITS NOW. Do not ask for confirmation. Do not ask clarifying questions.");
423
+ lines.push("Do not explain what you found without also making the changes. Edit the files and complete the task.");
424
+ }
408
425
  lines.push("");
409
426
  lines.push("If PROGRESS.md exists in your working directory, read it first for context from prior attempts.");
410
427
  lines.push("If it does not exist, proceed with the objective below.");
411
428
  lines.push("");
412
- lines.push("Complete the following coding task. Make all necessary file changes.");
429
+ lines.push(mutationMode === "verify_only"
430
+ ? "Complete the following verification-only task without making file changes."
431
+ : "Complete the following coding task. Make all necessary file changes.");
413
432
  lines.push("When you are done, the verification commands listed below must pass.");
414
433
  lines.push("");
415
434
  lines.push("OBJECTIVE:");
@@ -447,7 +466,9 @@ function buildPrompt(request) {
447
466
  lines.push(` Attempt ${String(attemptNumber)}`);
448
467
  lines.push(` Remaining budget: $${String(request.context.remainingBudgetUsd)} USD`);
449
468
  lines.push(` Remaining iterations: ${String(request.context.remainingIterations)}`);
450
- lines.push(" Do not expand scope beyond what is needed to pass verification.");
469
+ lines.push(mutationMode === "verify_only"
470
+ ? " Do not modify files; only run verification."
471
+ : " Do not expand scope beyond what is needed to pass verification.");
451
472
  lines.push("");
452
473
  if (request.previousAttempts.length > 0) {
453
474
  lines.push("PRIOR FAILED ATTEMPTS (learn from these — do not repeat the same mistakes):");
@@ -494,6 +515,16 @@ function truncate(text, maxLength) {
494
515
  }
495
516
  return `...${text.slice(-(maxLength - 3))}`;
496
517
  }
518
+ function formatPreVerifierSubprocessFailure(command, stderr, exitCode) {
519
+ const detail = stderr.trim() || `Exit code ${String(exitCode)}`;
520
+ const lowerDetail = detail.toLowerCase();
521
+ const codexLaunchBlocked = command === "codex" &&
522
+ /\b(full-auto|sandbox|approval|permission|trusted|safety|unexpected argument)\b/u.test(lowerDetail);
523
+ if (codexLaunchBlocked) {
524
+ return `Codex CLI failed before patch completion, likely due to its launch/sandbox configuration. MartinLoop invokes Codex through "codex exec --sandbox workspace-write"; verify Codex CLI auth and configuration if this persists. ${detail}. environment_mismatch`;
525
+ }
526
+ return `${detail}. environment_mismatch`;
527
+ }
497
528
  const INJECTION_PATTERNS = [
498
529
  /\[INST\]/gi,
499
530
  /<\/?system>/gi,
@@ -26,3 +26,4 @@ export declare function readGitExecutionArtifacts(repoRoot: string, timeoutMs: n
26
26
  changedFiles?: string[];
27
27
  diffStats?: ReturnType<typeof diffStatsFromNumstat>;
28
28
  }>;
29
+ export declare function splitCommand(command: string): string[];
@@ -1,28 +1,33 @@
1
1
  import { spawn } from "node:child_process";
2
- import { isAbsolute } from "node:path";
2
+ import { delimiter, extname, isAbsolute, join, resolve } from "node:path";
3
+ import { existsSync } from "node:fs";
3
4
  import { diffStatsFromNumstat } from "./runtime-support.js";
4
5
  export async function runSubprocess(command, args, options) {
5
6
  return new Promise((resolve) => {
6
7
  let timedOut = false;
8
+ let settled = false;
7
9
  const stdoutChunks = [];
8
10
  const stderrChunks = [];
9
11
  const stdinMode = options.stdinData !== undefined ? "pipe" : "ignore";
12
+ const resolveOnce = (result) => {
13
+ if (settled) {
14
+ return;
15
+ }
16
+ settled = true;
17
+ resolve(result);
18
+ };
10
19
  let proc;
11
20
  try {
12
- proc = (options.spawnImpl ?? spawn)(command, args, {
21
+ const spawnPlan = createSpawnPlan(command, args, options.cwd, options.spawnImpl !== undefined);
22
+ proc = (options.spawnImpl ?? spawn)(spawnPlan.command, spawnPlan.args, {
13
23
  cwd: options.cwd,
14
24
  stdio: [stdinMode, "pipe", "pipe"],
15
- env: process.env,
16
- // shell: true is required on Windows to resolve PATH shims (e.g. claude.cmd).
17
- // Avoid it for absolute .exe paths because cmd.exe can split paths with spaces.
18
- // Prompt content is never passed as a shell argument, it goes via stdin, so
19
- // injection risk from the DEP0190 warning does not apply here.
20
- shell: shouldUseWindowsShell(command)
25
+ env: process.env
21
26
  });
22
27
  }
23
28
  catch (error) {
24
29
  const message = error instanceof Error ? error.message : String(error);
25
- resolve({
30
+ resolveOnce({
26
31
  exitCode: 1,
27
32
  stdout: "",
28
33
  stderr: message,
@@ -30,38 +35,59 @@ export async function runSubprocess(command, args, options) {
30
35
  });
31
36
  return;
32
37
  }
33
- if (options.stdinData !== undefined && proc.stdin) {
34
- proc.stdin.write(options.stdinData, "utf8");
35
- proc.stdin.end();
36
- }
37
38
  proc.stdout?.on("data", (chunk) => {
38
39
  stdoutChunks.push(chunk);
39
40
  });
40
41
  proc.stderr?.on("data", (chunk) => {
41
42
  stderrChunks.push(chunk);
42
43
  });
44
+ proc.stdin?.on("error", (error) => {
45
+ // Some CLIs exit before consuming stdin in tests and on fast-fail paths.
46
+ // Treat the closed pipe as a handled subprocess lifecycle condition.
47
+ if (error.code === "EPIPE") {
48
+ return;
49
+ }
50
+ stderrChunks.push(Buffer.from(`${error.message}\n`, "utf8"));
51
+ });
43
52
  const timer = setTimeout(() => {
44
53
  timedOut = true;
45
54
  proc.kill("SIGTERM");
46
55
  }, options.timeoutMs);
47
- proc.on("close", (code) => {
48
- clearTimeout(timer);
49
- resolve({
50
- exitCode: code ?? 1,
51
- stdout: Buffer.concat(stdoutChunks).toString("utf8"),
52
- stderr: Buffer.concat(stderrChunks).toString("utf8"),
53
- timedOut
54
- });
55
- });
56
56
  proc.on("error", (error) => {
57
57
  clearTimeout(timer);
58
- resolve({
58
+ resolveOnce({
59
59
  exitCode: 1,
60
60
  stdout: "",
61
61
  stderr: error.message,
62
62
  timedOut: false
63
63
  });
64
64
  });
65
+ proc.on("close", (code) => {
66
+ clearTimeout(timer);
67
+ resolveOnce({
68
+ exitCode: code ?? 1,
69
+ stdout: Buffer.concat(stdoutChunks).toString("utf8"),
70
+ stderr: Buffer.concat(stderrChunks).toString("utf8"),
71
+ timedOut
72
+ });
73
+ });
74
+ if (options.stdinData !== undefined && proc.stdin) {
75
+ try {
76
+ proc.stdin.end(options.stdinData, "utf8");
77
+ }
78
+ catch (error) {
79
+ const stdinError = error;
80
+ if (stdinError.code !== "EPIPE") {
81
+ clearTimeout(timer);
82
+ resolveOnce({
83
+ exitCode: 1,
84
+ stdout: Buffer.concat(stdoutChunks).toString("utf8"),
85
+ stderr: stdinError.message,
86
+ timedOut: false
87
+ });
88
+ }
89
+ }
90
+ }
65
91
  });
66
92
  }
67
93
  export async function runVerification(commands, cwd, timeoutMs, verificationStack, spawnImpl) {
@@ -76,9 +102,8 @@ export async function runVerification(commands, cwd, timeoutMs, verificationStac
76
102
  }
77
103
  const failedSteps = [];
78
104
  for (const step of steps) {
79
- const parts = step.command.trim().split(/\s+/u);
80
- const bin = parts[0];
81
- const args = parts.slice(1);
105
+ const parts = splitCommand(step.command);
106
+ const [bin, ...args] = parts;
82
107
  if (!bin) {
83
108
  continue;
84
109
  }
@@ -115,8 +140,109 @@ export async function readGitExecutionArtifacts(repoRoot, timeoutMs, spawnImpl)
115
140
  ...(diffStats ? { diffStats } : {})
116
141
  };
117
142
  }
118
- function shouldUseWindowsShell(command) {
119
- return process.platform === "win32" && !isAbsolute(command);
143
+ function createSpawnPlan(command, args, cwd, preserveRawForInjectedSpawn) {
144
+ if (preserveRawForInjectedSpawn || process.platform !== "win32" || isAbsolute(command)) {
145
+ return { command, args };
146
+ }
147
+ const resolved = resolveWindowsCommand(command, cwd);
148
+ if (!resolved) {
149
+ return { command, args };
150
+ }
151
+ const extension = extname(resolved).toLowerCase();
152
+ if (extension === ".cmd" || extension === ".bat") {
153
+ return {
154
+ command: process.env.ComSpec || "cmd.exe",
155
+ args: ["/d", "/s", "/c", [quoteWindowsCmdArg(resolved), ...args.map(quoteWindowsCmdArg)].join(" ")]
156
+ };
157
+ }
158
+ return { command: resolved, args };
159
+ }
160
+ function resolveWindowsCommand(command, cwd) {
161
+ const hasPathSegment = command.includes("\\") || command.includes("/");
162
+ const baseCandidates = expandWindowsCommandCandidates(hasPathSegment ? resolve(cwd, command) : command);
163
+ if (hasPathSegment) {
164
+ return baseCandidates.find((candidate) => existsSync(candidate));
165
+ }
166
+ for (const directory of windowsPathDirectories()) {
167
+ for (const candidate of baseCandidates) {
168
+ const fullPath = join(directory, candidate);
169
+ if (existsSync(fullPath)) {
170
+ return fullPath;
171
+ }
172
+ }
173
+ }
174
+ return undefined;
175
+ }
176
+ function expandWindowsCommandCandidates(command) {
177
+ if (extname(command)) {
178
+ return [command];
179
+ }
180
+ const pathExt = process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD";
181
+ return pathExt
182
+ .split(";")
183
+ .map((extension) => extension.trim())
184
+ .filter(Boolean)
185
+ .map((extension) => `${command}${extension.toLowerCase()}`);
186
+ }
187
+ function windowsPathDirectories() {
188
+ const rawPath = process.env.Path ?? process.env.PATH ?? "";
189
+ return rawPath
190
+ .split(delimiter)
191
+ .map((entry) => entry.trim().replace(/^"|"$/g, ""))
192
+ .filter(Boolean);
193
+ }
194
+ function quoteWindowsCmdArg(value) {
195
+ const normalized = value.replace(/\r?\n/gu, " ");
196
+ const escaped = normalized
197
+ .replace(/\^/gu, "^^")
198
+ .replace(/"/gu, '^"')
199
+ .replace(/%/gu, "%%")
200
+ .replace(/!/gu, "^^!")
201
+ .replace(/[&|<>()]/gu, (match) => `^${match}`);
202
+ return `"${escaped}"`;
203
+ }
204
+ export function splitCommand(command) {
205
+ const tokens = [];
206
+ let current = "";
207
+ let quote;
208
+ const trimmed = command.trim();
209
+ for (let index = 0; index < trimmed.length; index += 1) {
210
+ const char = trimmed[index];
211
+ const next = trimmed[index + 1];
212
+ if (char === undefined) {
213
+ continue;
214
+ }
215
+ if (char === "\\") {
216
+ const canEscape = quote !== "'" && (next === quote || next === "\\");
217
+ if (canEscape && next !== undefined) {
218
+ current += next;
219
+ index += 1;
220
+ continue;
221
+ }
222
+ }
223
+ if (char === '"' || char === "'") {
224
+ if (!quote) {
225
+ quote = char;
226
+ continue;
227
+ }
228
+ if (quote === char) {
229
+ quote = undefined;
230
+ continue;
231
+ }
232
+ }
233
+ if (!quote && /\s/u.test(char)) {
234
+ if (current.length > 0) {
235
+ tokens.push(current);
236
+ current = "";
237
+ }
238
+ continue;
239
+ }
240
+ current += char;
241
+ }
242
+ if (current.length > 0) {
243
+ tokens.push(current);
244
+ }
245
+ return tokens;
120
246
  }
121
247
  function truncate(text, maxLength) {
122
248
  if (text.length <= maxLength) {
@@ -0,0 +1 @@
1
+ export declare function calculateIndex(): number;
@@ -0,0 +1,4 @@
1
+ export function calculateIndex() {
2
+ return 10;
3
+ }
4
+ //# sourceMappingURL=counter.js.map
@@ -0,0 +1,50 @@
1
+ import type { MartinAdapterResult } from "../core/index.js";
2
+ import { type SpawnLike } from "./cli-bridge.js";
3
+ type DiffStats = NonNullable<NonNullable<MartinAdapterResult["execution"]>["diffStats"]>;
4
+ export interface GitBaselineArtifact {
5
+ startHeadSha: string;
6
+ startTrackedStatus: string;
7
+ startTrackedSet: string[];
8
+ startTrackedDiffSha256: Record<string, string>;
9
+ startUntrackedSet: string[];
10
+ startTimestamp: string;
11
+ worktreeClean: boolean;
12
+ pilotRepoClass: string | null;
13
+ }
14
+ export interface GitNormalizationArtifact {
15
+ startHeadSha: string;
16
+ endHeadShaBeforeNormalization: string;
17
+ normalizationApplied: boolean;
18
+ normalizationMode: "reset_mixed_to_start_head" | "none";
19
+ normalizationSucceeded: boolean;
20
+ headAfterNormalization: string;
21
+ }
22
+ export interface ScopeSurfaceArtifact {
23
+ trackedChangedPaths: string[];
24
+ deletedPaths: string[];
25
+ newUntrackedPaths: string[];
26
+ allChangedPaths: string[];
27
+ changedBaselinePaths: string[];
28
+ baselineWasClean: boolean;
29
+ noCodeChange: boolean;
30
+ diffStats?: DiffStats;
31
+ }
32
+ export declare function captureBaseline(options: {
33
+ repoRoot: string;
34
+ timeoutMs: number;
35
+ spawnImpl?: SpawnLike;
36
+ pilotRepoClass?: string | null;
37
+ }): Promise<GitBaselineArtifact>;
38
+ export declare function normalizeAdapterGitState(options: {
39
+ repoRoot: string;
40
+ baseline: GitBaselineArtifact;
41
+ timeoutMs: number;
42
+ spawnImpl?: SpawnLike;
43
+ }): Promise<GitNormalizationArtifact>;
44
+ export declare function collectScopeSurface(options: {
45
+ repoRoot: string;
46
+ baseline: GitBaselineArtifact;
47
+ timeoutMs: number;
48
+ spawnImpl?: SpawnLike;
49
+ }): Promise<ScopeSurfaceArtifact>;
50
+ export {};