@mobrienv/autoloop 0.1.2

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 (307) hide show
  1. package/README.md +145 -0
  2. package/bin/autoloop +2 -0
  3. package/dist/backend/index.d.ts +10 -0
  4. package/dist/backend/index.js +59 -0
  5. package/dist/backend/index.js.map +1 -0
  6. package/dist/backend/run-command.d.ts +7 -0
  7. package/dist/backend/run-command.js +50 -0
  8. package/dist/backend/run-command.js.map +1 -0
  9. package/dist/backend/run-mock.d.ts +1 -0
  10. package/dist/backend/run-mock.js +6 -0
  11. package/dist/backend/run-mock.js.map +1 -0
  12. package/dist/backend/run-pi.d.ts +5 -0
  13. package/dist/backend/run-pi.js +5 -0
  14. package/dist/backend/run-pi.js.map +1 -0
  15. package/dist/backend/types.d.ts +21 -0
  16. package/dist/backend/types.js +2 -0
  17. package/dist/backend/types.js.map +1 -0
  18. package/dist/chains/budget.d.ts +7 -0
  19. package/dist/chains/budget.js +42 -0
  20. package/dist/chains/budget.js.map +1 -0
  21. package/dist/chains/load.d.ts +12 -0
  22. package/dist/chains/load.js +80 -0
  23. package/dist/chains/load.js.map +1 -0
  24. package/dist/chains/render.d.ts +2 -0
  25. package/dist/chains/render.js +46 -0
  26. package/dist/chains/render.js.map +1 -0
  27. package/dist/chains/run.d.ts +17 -0
  28. package/dist/chains/run.js +175 -0
  29. package/dist/chains/run.js.map +1 -0
  30. package/dist/chains/types.d.ts +37 -0
  31. package/dist/chains/types.js +2 -0
  32. package/dist/chains/types.js.map +1 -0
  33. package/dist/chains.d.ts +5 -0
  34. package/dist/chains.js +5 -0
  35. package/dist/chains.js.map +1 -0
  36. package/dist/commands/chain.d.ts +1 -0
  37. package/dist/commands/chain.js +51 -0
  38. package/dist/commands/chain.js.map +1 -0
  39. package/dist/commands/inspect.d.ts +1 -0
  40. package/dist/commands/inspect.js +95 -0
  41. package/dist/commands/inspect.js.map +1 -0
  42. package/dist/commands/list.d.ts +1 -0
  43. package/dist/commands/list.js +12 -0
  44. package/dist/commands/list.js.map +1 -0
  45. package/dist/commands/loops.d.ts +1 -0
  46. package/dist/commands/loops.js +72 -0
  47. package/dist/commands/loops.js.map +1 -0
  48. package/dist/commands/memory.d.ts +1 -0
  49. package/dist/commands/memory.js +65 -0
  50. package/dist/commands/memory.js.map +1 -0
  51. package/dist/commands/pi-adapter.d.ts +1 -0
  52. package/dist/commands/pi-adapter.js +6 -0
  53. package/dist/commands/pi-adapter.js.map +1 -0
  54. package/dist/commands/run.d.ts +1 -0
  55. package/dist/commands/run.js +185 -0
  56. package/dist/commands/run.js.map +1 -0
  57. package/dist/config.d.ts +16 -0
  58. package/dist/config.js +169 -0
  59. package/dist/config.js.map +1 -0
  60. package/dist/events/decode.d.ts +2 -0
  61. package/dist/events/decode.js +45 -0
  62. package/dist/events/decode.js.map +1 -0
  63. package/dist/events/encode.d.ts +2 -0
  64. package/dist/events/encode.js +33 -0
  65. package/dist/events/encode.js.map +1 -0
  66. package/dist/events/guards.d.ts +5 -0
  67. package/dist/events/guards.js +42 -0
  68. package/dist/events/guards.js.map +1 -0
  69. package/dist/events/types.d.ts +25 -0
  70. package/dist/events/types.js +2 -0
  71. package/dist/events/types.js.map +1 -0
  72. package/dist/harness/config-helpers.d.ts +24 -0
  73. package/dist/harness/config-helpers.js +231 -0
  74. package/dist/harness/config-helpers.js.map +1 -0
  75. package/dist/harness/coordination.d.ts +1 -0
  76. package/dist/harness/coordination.js +127 -0
  77. package/dist/harness/coordination.js.map +1 -0
  78. package/dist/harness/display.d.ts +20 -0
  79. package/dist/harness/display.js +130 -0
  80. package/dist/harness/display.js.map +1 -0
  81. package/dist/harness/emit.d.ts +15 -0
  82. package/dist/harness/emit.js +220 -0
  83. package/dist/harness/emit.js.map +1 -0
  84. package/dist/harness/index.d.ts +13 -0
  85. package/dist/harness/index.js +124 -0
  86. package/dist/harness/index.js.map +1 -0
  87. package/dist/harness/iteration.d.ts +4 -0
  88. package/dist/harness/iteration.js +129 -0
  89. package/dist/harness/iteration.js.map +1 -0
  90. package/dist/harness/journal.d.ts +13 -0
  91. package/dist/harness/journal.js +106 -0
  92. package/dist/harness/journal.js.map +1 -0
  93. package/dist/harness/metareview.d.ts +4 -0
  94. package/dist/harness/metareview.js +33 -0
  95. package/dist/harness/metareview.js.map +1 -0
  96. package/dist/harness/metrics.d.ts +12 -0
  97. package/dist/harness/metrics.js +180 -0
  98. package/dist/harness/metrics.js.map +1 -0
  99. package/dist/harness/parallel.d.ts +37 -0
  100. package/dist/harness/parallel.js +158 -0
  101. package/dist/harness/parallel.js.map +1 -0
  102. package/dist/harness/prompt.d.ts +35 -0
  103. package/dist/harness/prompt.js +328 -0
  104. package/dist/harness/prompt.js.map +1 -0
  105. package/dist/harness/scratchpad.d.ts +2 -0
  106. package/dist/harness/scratchpad.js +65 -0
  107. package/dist/harness/scratchpad.js.map +1 -0
  108. package/dist/harness/stop.d.ts +5 -0
  109. package/dist/harness/stop.js +63 -0
  110. package/dist/harness/stop.js.map +1 -0
  111. package/dist/harness/tools.d.ts +3 -0
  112. package/dist/harness/tools.js +39 -0
  113. package/dist/harness/tools.js.map +1 -0
  114. package/dist/harness/types.d.ts +81 -0
  115. package/dist/harness/types.js +2 -0
  116. package/dist/harness/types.js.map +1 -0
  117. package/dist/harness/wave/finalize-wave.d.ts +9 -0
  118. package/dist/harness/wave/finalize-wave.js +60 -0
  119. package/dist/harness/wave/finalize-wave.js.map +1 -0
  120. package/dist/harness/wave/launch-branches.d.ts +6 -0
  121. package/dist/harness/wave/launch-branches.js +218 -0
  122. package/dist/harness/wave/launch-branches.js.map +1 -0
  123. package/dist/harness/wave/parse-objectives.d.ts +3 -0
  124. package/dist/harness/wave/parse-objectives.js +29 -0
  125. package/dist/harness/wave/parse-objectives.js.map +1 -0
  126. package/dist/harness/wave/types.d.ts +43 -0
  127. package/dist/harness/wave/types.js +2 -0
  128. package/dist/harness/wave/types.js.map +1 -0
  129. package/dist/harness/wave.d.ts +6 -0
  130. package/dist/harness/wave.js +98 -0
  131. package/dist/harness/wave.js.map +1 -0
  132. package/dist/json.d.ts +8 -0
  133. package/dist/json.js +80 -0
  134. package/dist/json.js.map +1 -0
  135. package/dist/loops/health.d.ts +14 -0
  136. package/dist/loops/health.js +104 -0
  137. package/dist/loops/health.js.map +1 -0
  138. package/dist/loops/list.d.ts +6 -0
  139. package/dist/loops/list.js +21 -0
  140. package/dist/loops/list.js.map +1 -0
  141. package/dist/loops/render.d.ts +18 -0
  142. package/dist/loops/render.js +87 -0
  143. package/dist/loops/render.js.map +1 -0
  144. package/dist/loops/show.d.ts +8 -0
  145. package/dist/loops/show.js +31 -0
  146. package/dist/loops/show.js.map +1 -0
  147. package/dist/loops/watch.d.ts +8 -0
  148. package/dist/loops/watch.js +77 -0
  149. package/dist/loops/watch.js.map +1 -0
  150. package/dist/main.d.ts +1 -0
  151. package/dist/main.js +101 -0
  152. package/dist/main.js.map +1 -0
  153. package/dist/markdown.d.ts +10 -0
  154. package/dist/markdown.js +66 -0
  155. package/dist/markdown.js.map +1 -0
  156. package/dist/memory-render.d.ts +6 -0
  157. package/dist/memory-render.js +81 -0
  158. package/dist/memory-render.js.map +1 -0
  159. package/dist/memory.d.ts +23 -0
  160. package/dist/memory.js +314 -0
  161. package/dist/memory.js.map +1 -0
  162. package/dist/pi-adapter.d.ts +1 -0
  163. package/dist/pi-adapter.js +220 -0
  164. package/dist/pi-adapter.js.map +1 -0
  165. package/dist/registry/derive.d.ts +8 -0
  166. package/dist/registry/derive.js +81 -0
  167. package/dist/registry/derive.js.map +1 -0
  168. package/dist/registry/harness.d.ts +7 -0
  169. package/dist/registry/harness.js +57 -0
  170. package/dist/registry/harness.js.map +1 -0
  171. package/dist/registry/index.d.ts +5 -0
  172. package/dist/registry/index.js +5 -0
  173. package/dist/registry/index.js.map +1 -0
  174. package/dist/registry/read.d.ts +11 -0
  175. package/dist/registry/read.js +50 -0
  176. package/dist/registry/read.js.map +1 -0
  177. package/dist/registry/rebuild.d.ts +5 -0
  178. package/dist/registry/rebuild.js +19 -0
  179. package/dist/registry/rebuild.js.map +1 -0
  180. package/dist/registry/types.d.ts +19 -0
  181. package/dist/registry/types.js +2 -0
  182. package/dist/registry/types.js.map +1 -0
  183. package/dist/registry/update.d.ts +2 -0
  184. package/dist/registry/update.js +7 -0
  185. package/dist/registry/update.js.map +1 -0
  186. package/dist/testing/mock-backend.d.ts +11 -0
  187. package/dist/testing/mock-backend.js +76 -0
  188. package/dist/testing/mock-backend.js.map +1 -0
  189. package/dist/topology.d.ts +25 -0
  190. package/dist/topology.js +188 -0
  191. package/dist/topology.js.map +1 -0
  192. package/dist/usage.d.ts +8 -0
  193. package/dist/usage.js +114 -0
  194. package/dist/usage.js.map +1 -0
  195. package/dist/utils.d.ts +15 -0
  196. package/dist/utils.js +79 -0
  197. package/dist/utils.js.map +1 -0
  198. package/package.json +52 -0
  199. package/presets/autocode/README.md +81 -0
  200. package/presets/autocode/autoloops.toml +22 -0
  201. package/presets/autocode/harness.md +19 -0
  202. package/presets/autocode/miniloops.toml +22 -0
  203. package/presets/autocode/roles/build.md +33 -0
  204. package/presets/autocode/roles/critic.md +40 -0
  205. package/presets/autocode/roles/finalizer.md +43 -0
  206. package/presets/autocode/roles/planner.md +40 -0
  207. package/presets/autocode/topology.toml +32 -0
  208. package/presets/autodoc/README.md +42 -0
  209. package/presets/autodoc/autoloops.toml +21 -0
  210. package/presets/autodoc/harness.md +19 -0
  211. package/presets/autodoc/miniloops.toml +21 -0
  212. package/presets/autodoc/roles/auditor.md +39 -0
  213. package/presets/autodoc/roles/checker.md +43 -0
  214. package/presets/autodoc/roles/publisher.md +51 -0
  215. package/presets/autodoc/roles/writer.md +37 -0
  216. package/presets/autodoc/topology.toml +31 -0
  217. package/presets/autofix/README.md +56 -0
  218. package/presets/autofix/autoloops.toml +21 -0
  219. package/presets/autofix/harness.md +24 -0
  220. package/presets/autofix/miniloops.toml +21 -0
  221. package/presets/autofix/roles/closer.md +48 -0
  222. package/presets/autofix/roles/diagnoser.md +42 -0
  223. package/presets/autofix/roles/fixer.md +28 -0
  224. package/presets/autofix/roles/verifier.md +31 -0
  225. package/presets/autofix/topology.toml +33 -0
  226. package/presets/autoideas/README.md +73 -0
  227. package/presets/autoideas/autoloops.toml +18 -0
  228. package/presets/autoideas/harness.md +31 -0
  229. package/presets/autoideas/miniloops.toml +18 -0
  230. package/presets/autoideas/roles/analyst.md +32 -0
  231. package/presets/autoideas/roles/reviewer.md +36 -0
  232. package/presets/autoideas/roles/scanner.md +26 -0
  233. package/presets/autoideas/roles/synthesizer.md +48 -0
  234. package/presets/autoideas/topology.toml +32 -0
  235. package/presets/autoperf/README.md +56 -0
  236. package/presets/autoperf/autoloops.toml +21 -0
  237. package/presets/autoperf/harness.md +21 -0
  238. package/presets/autoperf/miniloops.toml +21 -0
  239. package/presets/autoperf/roles/judge.md +38 -0
  240. package/presets/autoperf/roles/measurer.md +36 -0
  241. package/presets/autoperf/roles/optimizer.md +35 -0
  242. package/presets/autoperf/roles/profiler.md +38 -0
  243. package/presets/autoperf/topology.toml +32 -0
  244. package/presets/autoqa/README.md +76 -0
  245. package/presets/autoqa/autoloops.toml +21 -0
  246. package/presets/autoqa/harness.md +30 -0
  247. package/presets/autoqa/miniloops.toml +21 -0
  248. package/presets/autoqa/roles/executor.md +43 -0
  249. package/presets/autoqa/roles/inspector.md +45 -0
  250. package/presets/autoqa/roles/planner.md +55 -0
  251. package/presets/autoqa/roles/reporter.md +74 -0
  252. package/presets/autoqa/topology.toml +31 -0
  253. package/presets/autoresearch/README.md +63 -0
  254. package/presets/autoresearch/autoloops.toml +18 -0
  255. package/presets/autoresearch/harness.md +28 -0
  256. package/presets/autoresearch/miniloops.toml +18 -0
  257. package/presets/autoresearch/roles/benchmarker.md +34 -0
  258. package/presets/autoresearch/roles/evaluator.md +33 -0
  259. package/presets/autoresearch/roles/implementer.md +26 -0
  260. package/presets/autoresearch/roles/strategist.md +43 -0
  261. package/presets/autoresearch/topology.toml +31 -0
  262. package/presets/autoreview/README.md +51 -0
  263. package/presets/autoreview/autoloops.toml +21 -0
  264. package/presets/autoreview/harness.md +20 -0
  265. package/presets/autoreview/miniloops.toml +21 -0
  266. package/presets/autoreview/roles/checker.md +36 -0
  267. package/presets/autoreview/roles/reader.md +33 -0
  268. package/presets/autoreview/roles/suggester.md +26 -0
  269. package/presets/autoreview/roles/summarizer.md +57 -0
  270. package/presets/autoreview/topology.toml +31 -0
  271. package/presets/autosec/README.md +51 -0
  272. package/presets/autosec/autoloops.toml +21 -0
  273. package/presets/autosec/harness.md +20 -0
  274. package/presets/autosec/miniloops.toml +21 -0
  275. package/presets/autosec/roles/analyst.md +38 -0
  276. package/presets/autosec/roles/hardener.md +36 -0
  277. package/presets/autosec/roles/reporter.md +63 -0
  278. package/presets/autosec/roles/scanner.md +38 -0
  279. package/presets/autosec/topology.toml +31 -0
  280. package/presets/autosimplify/README.md +83 -0
  281. package/presets/autosimplify/autoloops.toml +22 -0
  282. package/presets/autosimplify/harness.md +25 -0
  283. package/presets/autosimplify/miniloops.toml +22 -0
  284. package/presets/autosimplify/roles/reviewer.md +38 -0
  285. package/presets/autosimplify/roles/scoper.md +42 -0
  286. package/presets/autosimplify/roles/simplifier.md +51 -0
  287. package/presets/autosimplify/roles/verifier.md +40 -0
  288. package/presets/autosimplify/topology.toml +32 -0
  289. package/presets/autospec/README.md +84 -0
  290. package/presets/autospec/autoloops.toml +21 -0
  291. package/presets/autospec/harness.md +23 -0
  292. package/presets/autospec/miniloops.toml +21 -0
  293. package/presets/autospec/roles/clarifier.md +38 -0
  294. package/presets/autospec/roles/critic.md +41 -0
  295. package/presets/autospec/roles/designer.md +37 -0
  296. package/presets/autospec/roles/planner.md +38 -0
  297. package/presets/autospec/roles/researcher.md +33 -0
  298. package/presets/autospec/topology.toml +38 -0
  299. package/presets/autotest/README.md +55 -0
  300. package/presets/autotest/autoloops.toml +21 -0
  301. package/presets/autotest/harness.md +21 -0
  302. package/presets/autotest/miniloops.toml +21 -0
  303. package/presets/autotest/roles/assessor.md +57 -0
  304. package/presets/autotest/roles/runner.md +31 -0
  305. package/presets/autotest/roles/surveyor.md +39 -0
  306. package/presets/autotest/roles/writer.md +37 -0
  307. package/presets/autotest/topology.toml +32 -0
package/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # autoloop
2
+
3
+ Autonomous LLM loop harness and control plane for long-horizon autonomous work. Runs multi-role, event-driven loops where each iteration is handled by a specialized role (planner, builder, critic, etc.) that hands off to the next via structured events. The harness manages iteration limits, event routing, memory, and completion detection so you can focus on the prompt and preset design.
4
+
5
+ External interfaces — CLI, chat, cron, future API — are thin shells that launch, observe, and report on runs. Presets are the product surface; the append-only journal is the source of truth. See [Platform Architecture](docs/platform.md) for the full model.
6
+
7
+ ## Prerequisites
8
+
9
+ - **Node.js** >= 18 (ES2022 target)
10
+ - **npm**
11
+ - An LLM backend on your `$PATH` — defaults to `pi`, but any CLI that accepts a prompt argument works (e.g. `claude`)
12
+
13
+ ## Install from npm
14
+
15
+ ```bash
16
+ npm install -g @mobrienv/autoloop
17
+ autoloop --help
18
+ ```
19
+
20
+ ## Quick start
21
+
22
+ ```bash
23
+ # Clone and build
24
+ git clone <repo-url> && cd autoloop
25
+ npm install
26
+ npm run build
27
+
28
+ # Run your first autoloop
29
+ node bin/autoloop run autocode "Fix the login bug"
30
+ ```
31
+
32
+ `autocode` is a bundled preset. The quoted string is the prompt passed to the loop. The harness iterates through roles (planner -> builder -> critic -> finalizer) until a `task.complete` event is emitted or the iteration limit is reached.
33
+
34
+ ## Usage
35
+
36
+ ```
37
+ npx @mobrienv/autoloop run <preset> [prompt...] [flags]
38
+ npx @mobrienv/autoloop list
39
+ npx @mobrienv/autoloop emit <topic> [summary]
40
+ npx @mobrienv/autoloop inspect <artifact> [selector] [--format <md|terminal|json|csv>]
41
+ npx @mobrienv/autoloop memory <list|status|find|add|remove> [args]
42
+ npx @mobrienv/autoloop chain <list|run> [args]
43
+ ```
44
+
45
+ ### Flags
46
+
47
+ | Flag | Description |
48
+ |------|-------------|
49
+ | `-h`, `--help` | Show usage |
50
+ | `-v`, `--verbose` | Debug-level logging |
51
+ | `-b`, `--backend` | Override backend command (e.g. `-b claude`) |
52
+ | `-p`, `--preset` | Resolve a named or custom preset |
53
+ | `--chain` | Run an inline chain of comma-separated presets |
54
+
55
+ ### Examples
56
+
57
+ ```bash
58
+ # Run a preset by name
59
+ node bin/autoloop run autocode "Refactor the auth module"
60
+
61
+ # Run from a custom preset directory
62
+ node bin/autoloop run ./my-preset "Analyze the API"
63
+
64
+ # Override the backend
65
+ node bin/autoloop run autoqa -b claude "Review recent changes"
66
+
67
+ # List available presets
68
+ node bin/npx @mobrienv/autoloop list
69
+
70
+ # Run an inline chain
71
+ node bin/autoloop run --chain autospec,autocode "Design and build feature X"
72
+ ```
73
+
74
+ ## Bundled presets
75
+
76
+ | Preset | Purpose |
77
+ |--------|---------|
78
+ | `autocode` | Plan, build, review, and commit code changes |
79
+ | `autodoc` | Audit, write, verify, and publish documentation |
80
+ | `autofix` | Diagnose, fix, and verify bugs |
81
+ | `autoideas` | Scan, analyze, review, and synthesize improvement ideas |
82
+ | `autoperf` | Profile, measure, optimize, and judge performance |
83
+ | `autoqa` | Plan, execute, inspect, and report on QA |
84
+ | `autoresearch` | Research strategies, implement, evaluate, and benchmark |
85
+ | `autoreview` | Read, suggest, check, and summarize code reviews |
86
+ | `autosec` | Scan, analyze, harden, and report on security |
87
+ | `autosimplify` | Scope, simplify, verify, and review code for simplicity |
88
+ | `autospec` | Research, clarify, design, plan, and critique specifications |
89
+ | `autotest` | Survey, write, run, and assess tests |
90
+
91
+ ## Project structure
92
+
93
+ ```
94
+ autoloop/
95
+ ├── bin/autoloop # CLI entry point (Node.js ESM)
96
+ ├── src/ # TypeScript source
97
+ │ ├── main.ts # CLI dispatch
98
+ │ ├── harness/ # Loop engine (iteration, events, routing)
99
+ │ ├── config.ts # TOML config loading
100
+ │ ├── chains.ts # Chain orchestration
101
+ │ ├── memory.ts # Persistent loop memory
102
+ │ └── usage.ts # Help text
103
+ ├── presets/ # Bundled preset definitions
104
+ │ └── <name>/
105
+ │ ├── autoloops.toml # Loop config
106
+ │ ├── topology.toml # Role deck and handoff graph
107
+ │ ├── harness.md # Shared instructions
108
+ │ └── roles/ # Per-role prompt files
109
+ ├── docs/ # Reference documentation
110
+ ├── dist/ # Compiled output (generated)
111
+ └── package.json
112
+ ```
113
+
114
+ ## Creating custom presets
115
+
116
+ A preset is a directory containing `autoloops.toml`, `topology.toml`, `harness.md`, and a `roles/` folder. See [docs/creating-presets.md](docs/creating-presets.md) for the full guide, or examine any `presets/<name>/` directory as a working example.
117
+
118
+ ## Running tests
119
+
120
+ ```bash
121
+ npm test
122
+ ```
123
+
124
+ Runs the test suite via [Vitest](https://vitest.dev/).
125
+
126
+ ### Mock backend
127
+
128
+ A deterministic mock backend (`src/testing/mock-backend.ts`) removes the need for a live LLM backend during testing. Point it at a JSON fixture to control the output, exit code, and emitted events:
129
+
130
+ ```bash
131
+ export MOCK_FIXTURE_PATH=test/fixtures/backend/complete-success.json
132
+ node bin/autoloop run . -b "node dist/testing/mock-backend.js"
133
+ ```
134
+
135
+ See [docs/cli.md](docs/cli.md#mock-backend) for fixture schema and bundled scenarios.
136
+
137
+ ## Further reading
138
+
139
+ - [Platform architecture](docs/platform.md)
140
+ - [Configuration reference](docs/configuration.md)
141
+ - [Creating presets](docs/creating-presets.md)
142
+ - [Topology and event routing](docs/topology.md)
143
+ - [Memory system](docs/memory.md)
144
+ - [Dynamic chains](docs/dynamic-chains.md)
145
+ - [CLI reference](docs/cli.md)
package/bin/autoloop ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import('../dist/main.js');
@@ -0,0 +1,10 @@
1
+ import type { BackendCommandContext, BackendRunResult } from "./types.js";
2
+ export type { BackendSpec, BackendRunResult, BackendCommandContext } from "./types.js";
3
+ export declare function normalizeBackendLabel(command: string): string;
4
+ export declare function buildBackendShellCommand(ctx: BackendCommandContext): string;
5
+ export declare function runBackendCommand(providerKind: string, command: string, timeoutMs: number): BackendRunResult;
6
+ export declare function normalizeProviderKind(spec: {
7
+ kind: string;
8
+ command: string;
9
+ args: string[];
10
+ }): string;
@@ -0,0 +1,59 @@
1
+ import { basename, join } from "node:path";
2
+ import { shellQuote } from "../utils.js";
3
+ import { buildPiAdapterInvocation } from "./run-pi.js";
4
+ import { buildCommandInvocation, runShellCommand } from "./run-command.js";
5
+ import { mockBackend } from "./run-mock.js";
6
+ export function normalizeBackendLabel(command) {
7
+ if (!command)
8
+ return "";
9
+ const base = basename(command);
10
+ if (base === "claude")
11
+ return "claude";
12
+ if (base === "pi")
13
+ return "pi";
14
+ return base || command;
15
+ }
16
+ export function buildBackendShellCommand(ctx) {
17
+ const promptPath = join(ctx.loop.paths.stateDir, "active-prompt.md");
18
+ const envLines = promptRuntimeEnvLines(ctx.spec, ctx.prompt, promptPath, ctx.runtimeEnv);
19
+ const childCommand = ctx.spec.kind === "pi"
20
+ ? buildPiAdapterInvocation(ctx.loop, ctx.spec)
21
+ : buildCommandInvocation(ctx.spec, ctx.prompt);
22
+ return envLines + wrapProcessInvocation(childCommand);
23
+ }
24
+ export function runBackendCommand(providerKind, command, timeoutMs) {
25
+ return runShellCommand(providerKind, command, timeoutMs);
26
+ }
27
+ export function normalizeProviderKind(spec) {
28
+ if (spec.kind === "pi")
29
+ return "pi";
30
+ if (mockBackend(spec.command, spec.args))
31
+ return "mock";
32
+ return spec.kind || "command";
33
+ }
34
+ function promptRuntimeEnvLines(spec, prompt, promptPath, runtimeEnv) {
35
+ let lines = runtimeEnv +
36
+ "export MINILOOPS_PROMPT_PATH=" + shellQuote(promptPath) + "\n" +
37
+ "printf '%s' " + shellQuote(prompt) + " > " + shellQuote(promptPath) + "\n";
38
+ if (spec.kind !== "pi") {
39
+ lines += "export MINILOOPS_PROMPT=" + shellQuote(prompt) + "\n";
40
+ }
41
+ return lines;
42
+ }
43
+ function wrapProcessInvocation(command) {
44
+ return ("autoloops_child_pid=''\n" +
45
+ "autoloops_cleanup() {\n" +
46
+ ' if [ -n "$autoloops_child_pid" ]; then\n' +
47
+ ' kill "$autoloops_child_pid" 2>/dev/null || true\n' +
48
+ ' wait "$autoloops_child_pid" 2>/dev/null || true\n' +
49
+ " fi\n" +
50
+ "}\n" +
51
+ "trap 'autoloops_cleanup; exit 130' INT TERM\n" +
52
+ "(\n" + command + "\n) &\n" +
53
+ "autoloops_child_pid=$!\n" +
54
+ 'wait "$autoloops_child_pid"\n' +
55
+ "autoloops_status=$?\n" +
56
+ "trap - INT TERM\n" +
57
+ 'exit "$autoloops_status"\n');
58
+ }
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAM5C,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACvC,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO,IAAI,IAAI,OAAO,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,GAA0B;IACjE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,qBAAqB,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IACzF,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI;QACzC,CAAC,CAAC,wBAAwB,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC;QAC9C,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjD,OAAO,QAAQ,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,YAAoB,EACpB,OAAe,EACf,SAAiB;IAEjB,OAAO,eAAe,CAAC,YAAY,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAuD;IAC3F,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IACxD,OAAO,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC;AAChC,CAAC;AAED,SAAS,qBAAqB,CAC5B,IAAsB,EACtB,MAAc,EACd,UAAkB,EAClB,UAAkB;IAElB,IAAI,KAAK,GACP,UAAU;QACV,+BAA+B,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,IAAI;QAC/D,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAC9E,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACvB,KAAK,IAAI,0BAA0B,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAClE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAe;IAC5C,OAAO,CACL,0BAA0B;QAC1B,yBAAyB;QACzB,4CAA4C;QAC5C,uDAAuD;QACvD,uDAAuD;QACvD,QAAQ;QACR,KAAK;QACL,+CAA+C;QAC/C,KAAK,GAAG,OAAO,GAAG,SAAS;QAC3B,0BAA0B;QAC1B,+BAA+B;QAC/B,uBAAuB;QACvB,mBAAmB;QACnB,4BAA4B,CAC7B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { BackendRunResult } from "./types.js";
2
+ export declare function buildCommandInvocation(spec: {
3
+ command: string;
4
+ args: string[];
5
+ promptMode: string;
6
+ }, prompt: string): string;
7
+ export declare function runShellCommand(providerKind: string, command: string, timeoutMs: number): BackendRunResult;
@@ -0,0 +1,50 @@
1
+ import { execSync } from "node:child_process";
2
+ import { shellQuote, shellWords } from "../utils.js";
3
+ export function buildCommandInvocation(spec, prompt) {
4
+ const argv = shellWords([spec.command, ...spec.args]);
5
+ if (spec.promptMode === "stdin") {
6
+ return "printf '%s' " + shellQuote(prompt) + " | " + argv;
7
+ }
8
+ return argv + " " + shellQuote(prompt);
9
+ }
10
+ export function runShellCommand(providerKind, command, timeoutMs) {
11
+ try {
12
+ const output = execSync(command, {
13
+ encoding: "utf-8",
14
+ timeout: timeoutMs,
15
+ stdio: ["pipe", "pipe", "inherit"],
16
+ shell: "/bin/sh",
17
+ maxBuffer: 100 * 1024 * 1024,
18
+ });
19
+ return {
20
+ output: output ?? "",
21
+ exitCode: 0,
22
+ timedOut: false,
23
+ providerKind,
24
+ errorCategory: "none",
25
+ };
26
+ }
27
+ catch (err) {
28
+ const e = err;
29
+ if (e.killed ||
30
+ e.signal === "SIGTERM" ||
31
+ e.code === "ETIMEDOUT" ||
32
+ e.message?.includes("ETIMEDOUT")) {
33
+ return {
34
+ output: e.stdout ?? "",
35
+ exitCode: 1,
36
+ timedOut: true,
37
+ providerKind,
38
+ errorCategory: "timeout",
39
+ };
40
+ }
41
+ return {
42
+ output: e.stdout ?? "",
43
+ exitCode: e.status ?? 1,
44
+ timedOut: false,
45
+ providerKind,
46
+ errorCategory: "non_zero_exit",
47
+ };
48
+ }
49
+ }
50
+ //# sourceMappingURL=run-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-command.js","sourceRoot":"","sources":["../../src/backend/run-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGrD,MAAM,UAAU,sBAAsB,CACpC,IAA6D,EAC7D,MAAc;IAEd,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACtD,IAAI,IAAI,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,GAAG,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,YAAoB,EACpB,OAAe,EACf,SAAiB;IAEjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE;YAC/B,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,SAAS;YAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;YAClC,KAAK,EAAE,SAAS;YAChB,SAAS,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI;SAC7B,CAAC,CAAC;QACH,OAAO;YACL,MAAM,EAAE,MAAM,IAAI,EAAE;YACpB,QAAQ,EAAE,CAAC;YACX,QAAQ,EAAE,KAAK;YACf,YAAY;YACZ,aAAa,EAAE,MAAM;SACtB,CAAC;IACJ,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,GAOT,CAAC;QACF,IACE,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,MAAM,KAAK,SAAS;YACtB,CAAC,CAAC,IAAI,KAAK,WAAW;YACtB,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,EAChC,CAAC;YACD,OAAO;gBACL,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;gBACtB,QAAQ,EAAE,CAAC;gBACX,QAAQ,EAAE,IAAI;gBACd,YAAY;gBACZ,aAAa,EAAE,SAAS;aACzB,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;YACtB,QAAQ,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC;YACvB,QAAQ,EAAE,KAAK;YACf,YAAY;YACZ,aAAa,EAAE,eAAe;SAC/B,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function mockBackend(command: string, args: string[]): boolean;
@@ -0,0 +1,6 @@
1
+ export function mockBackend(command, args) {
2
+ if (command.includes("mock-backend"))
3
+ return true;
4
+ return args.some((arg) => arg.includes("mock-backend"));
5
+ }
6
+ //# sourceMappingURL=run-mock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-mock.js","sourceRoot":"","sources":["../../src/backend/run-mock.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,IAAc;IACzD,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;QAAE,OAAO,IAAI,CAAC;IAClD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { LoopContext } from "../harness/types.js";
2
+ export declare function buildPiAdapterInvocation(loop: LoopContext, spec: {
3
+ command: string;
4
+ args: string[];
5
+ }): string;
@@ -0,0 +1,5 @@
1
+ import { shellWords } from "../utils.js";
2
+ export function buildPiAdapterInvocation(loop, spec) {
3
+ return shellWords([loop.paths.piAdapterPath, spec.command, ...spec.args]);
4
+ }
5
+ //# sourceMappingURL=run-pi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-pi.js","sourceRoot":"","sources":["../../src/backend/run-pi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,MAAM,UAAU,wBAAwB,CACtC,IAAiB,EACjB,IAAyC;IAEzC,OAAO,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { LoopContext } from "../harness/types.js";
2
+ export interface BackendSpec {
3
+ kind: string;
4
+ command: string;
5
+ args: string[];
6
+ promptMode: string;
7
+ timeoutMs: number;
8
+ }
9
+ export interface BackendRunResult {
10
+ output: string;
11
+ exitCode: number;
12
+ timedOut: boolean;
13
+ providerKind: string;
14
+ errorCategory: "none" | "timeout" | "non_zero_exit";
15
+ }
16
+ export interface BackendCommandContext {
17
+ loop: LoopContext;
18
+ spec: Pick<BackendSpec, "kind" | "command" | "args" | "promptMode">;
19
+ prompt: string;
20
+ runtimeEnv: string;
21
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/backend/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ import type { Budget, ChainTracker } from "./types.js";
2
+ export declare function defaultBudget(): Budget;
3
+ export declare function checkBudget(budget: Budget, tracker: ChainTracker): {
4
+ ok: boolean;
5
+ reason?: string;
6
+ };
7
+ export declare function parseBudgetFromToml(raw: unknown): Budget;
@@ -0,0 +1,42 @@
1
+ export function defaultBudget() {
2
+ return {
3
+ maxDepth: 5,
4
+ maxSteps: 50,
5
+ maxRuntimeMs: 3600000,
6
+ maxChildren: 10,
7
+ maxConsecutiveFailures: 3,
8
+ };
9
+ }
10
+ export function checkBudget(budget, tracker) {
11
+ if (tracker.depth >= budget.maxDepth) {
12
+ return { ok: false, reason: `max_depth exceeded (${tracker.depth}/${budget.maxDepth})` };
13
+ }
14
+ if (tracker.totalSteps >= budget.maxSteps) {
15
+ return { ok: false, reason: `max_steps exceeded (${tracker.totalSteps}/${budget.maxSteps})` };
16
+ }
17
+ if (tracker.children >= budget.maxChildren) {
18
+ return { ok: false, reason: `max_children exceeded (${tracker.children}/${budget.maxChildren})` };
19
+ }
20
+ if (tracker.consecutiveFailures >= budget.maxConsecutiveFailures) {
21
+ return { ok: false, reason: `max_consecutive_failures exceeded (${tracker.consecutiveFailures}/${budget.maxConsecutiveFailures})` };
22
+ }
23
+ return { ok: true };
24
+ }
25
+ export function parseBudgetFromToml(raw) {
26
+ const budget = defaultBudget();
27
+ if (typeof raw !== "object" || raw === null)
28
+ return budget;
29
+ const obj = raw;
30
+ if (typeof obj.max_depth === "number")
31
+ budget.maxDepth = obj.max_depth;
32
+ if (typeof obj.max_steps === "number")
33
+ budget.maxSteps = obj.max_steps;
34
+ if (typeof obj.max_runtime_ms === "number")
35
+ budget.maxRuntimeMs = obj.max_runtime_ms;
36
+ if (typeof obj.max_children === "number")
37
+ budget.maxChildren = obj.max_children;
38
+ if (typeof obj.max_consecutive_failures === "number")
39
+ budget.maxConsecutiveFailures = obj.max_consecutive_failures;
40
+ return budget;
41
+ }
42
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/chains/budget.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,EAAE;QACZ,YAAY,EAAE,OAAO;QACrB,WAAW,EAAE,EAAE;QACf,sBAAsB,EAAE,CAAC;KAC1B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,MAAc,EACd,OAAqB;IAErB,IAAI,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,QAAQ,GAAG,EAAE,CAAC;IAC3F,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC1C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,GAAG,EAAE,CAAC;IAChG,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QAC3C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,WAAW,GAAG,EAAE,CAAC;IACpG,CAAC;IACD,IAAI,OAAO,CAAC,mBAAmB,IAAI,MAAM,CAAC,sBAAsB,EAAE,CAAC;QACjE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sCAAsC,OAAO,CAAC,mBAAmB,IAAI,MAAM,CAAC,sBAAsB,GAAG,EAAE,CAAC;IACtI,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAC3D,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ;QAAE,MAAM,CAAC,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC;IACvE,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ;QAAE,MAAM,CAAC,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC;IACvE,IAAI,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ;QAAE,MAAM,CAAC,YAAY,GAAG,GAAG,CAAC,cAAc,CAAC;IACrF,IAAI,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ;QAAE,MAAM,CAAC,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC;IAChF,IAAI,OAAO,GAAG,CAAC,wBAAwB,KAAK,QAAQ;QAAE,MAAM,CAAC,sBAAsB,GAAG,GAAG,CAAC,wBAAwB,CAAC;IACnH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ChainSpec, ChainsConfig, Budget } from "./types.js";
2
+ export declare function load(projectDir: string): ChainsConfig;
3
+ export declare function resolveChain(chains: ChainsConfig, name: string): ChainSpec | null;
4
+ export declare function listChains(chains: ChainsConfig): ChainSpec[];
5
+ export declare function parseInlineChain(csvSteps: string, projectDir: string): ChainSpec;
6
+ export declare function loadBudget(projectDir: string): Budget;
7
+ export declare function resolvePresetDir(name: string, projectDir: string): string;
8
+ export declare function listKnownPresets(): string[];
9
+ export declare function validatePresetVocabulary(steps: string[], projectDir: string): {
10
+ ok: boolean;
11
+ reason?: string;
12
+ };
@@ -0,0 +1,80 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import TOML from "@iarna/toml";
4
+ import * as config from "../config.js";
5
+ import { parseStringList } from "../utils.js";
6
+ import { defaultBudget, parseBudgetFromToml } from "./budget.js";
7
+ export function load(projectDir) {
8
+ const path = join(projectDir, "chains.toml");
9
+ if (!existsSync(path))
10
+ return { chains: [], budget: defaultBudget() };
11
+ return loadExisting(path, projectDir);
12
+ }
13
+ export function resolveChain(chains, name) {
14
+ return chains.chains.find((c) => c.name === name) ?? null;
15
+ }
16
+ export function listChains(chains) {
17
+ return chains.chains;
18
+ }
19
+ export function parseInlineChain(csvSteps, projectDir) {
20
+ const stepNames = parseStringList(csvSteps);
21
+ return {
22
+ name: "inline",
23
+ steps: resolveSteps(stepNames, projectDir),
24
+ };
25
+ }
26
+ export function loadBudget(projectDir) {
27
+ const path = join(projectDir, "chains.toml");
28
+ if (!existsSync(path))
29
+ return defaultBudget();
30
+ const parsed = TOML.parse(readFileSync(path, "utf-8"));
31
+ return parseBudgetFromToml(parsed.budget);
32
+ }
33
+ export function resolvePresetDir(name, projectDir) {
34
+ const candidate = join(projectDir, "presets/" + name);
35
+ if (existsSync(candidate))
36
+ return candidate;
37
+ const cwdCandidate = join(".", "presets/" + name);
38
+ if (existsSync(cwdCandidate))
39
+ return cwdCandidate;
40
+ return name;
41
+ }
42
+ export function listKnownPresets() {
43
+ return [
44
+ "autocode", "autosimplify", "autoideas", "autoresearch",
45
+ "autoqa", "autotest", "autofix", "autoreview",
46
+ "autodoc", "autosec", "autoperf", "autospec",
47
+ ];
48
+ }
49
+ export function validatePresetVocabulary(steps, projectDir) {
50
+ const known = listKnownPresets();
51
+ for (const name of steps) {
52
+ if (!known.includes(name) && !config.projectHasConfig(resolvePresetDir(name, projectDir))) {
53
+ return { ok: false, reason: "unknown preset: " + name };
54
+ }
55
+ }
56
+ return { ok: true };
57
+ }
58
+ function loadExisting(path, projectDir) {
59
+ const text = readFileSync(path, "utf-8");
60
+ const parsed = TOML.parse(text);
61
+ return parseChainsFromToml(parsed, projectDir);
62
+ }
63
+ function parseChainsFromToml(parsed, projectDir) {
64
+ const rawChains = (parsed.chain ?? []);
65
+ const chains = rawChains
66
+ .filter((c) => typeof c.name === "string" && c.name !== "")
67
+ .map((c) => ({
68
+ name: c.name,
69
+ steps: resolveSteps(c.steps ?? [], projectDir),
70
+ }));
71
+ const budget = parseBudgetFromToml(parsed.budget);
72
+ return { chains, budget };
73
+ }
74
+ function resolveSteps(stepNames, projectDir) {
75
+ return stepNames.map((name) => ({
76
+ name,
77
+ presetDir: resolvePresetDir(name, projectDir),
78
+ }));
79
+ }
80
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/chains/load.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function renderChainState(projectDir: string): string;
2
+ export declare function renderChainLines(lines: string[]): string;
@@ -0,0 +1,46 @@
1
+ import { extractTopic, extractField, readLines } from "../harness/journal.js";
2
+ import * as config from "../config.js";
3
+ export function renderChainState(projectDir) {
4
+ const journalFile = config.resolveJournalFile(projectDir);
5
+ const lines = readLines(journalFile);
6
+ return renderChainLines(lines);
7
+ }
8
+ export function renderChainLines(lines) {
9
+ const entries = [];
10
+ for (const line of lines) {
11
+ const topic = extractTopic(line);
12
+ if (isChainTopic(topic)) {
13
+ entries.push({ topic, line });
14
+ }
15
+ }
16
+ if (entries.length === 0)
17
+ return "(no chain runs found)";
18
+ let result = "# Chain State\n\n";
19
+ for (const entry of entries) {
20
+ result += renderChainEntry(entry.topic, entry.line);
21
+ }
22
+ return result;
23
+ }
24
+ function isChainTopic(topic) {
25
+ return [
26
+ "chain.start", "chain.step.start", "chain.step.finish",
27
+ "chain.complete", "chain.spawn",
28
+ ].includes(topic);
29
+ }
30
+ function renderChainEntry(topic, line) {
31
+ switch (topic) {
32
+ case "chain.start":
33
+ return "## Chain: " + extractField(line, "name") + "\n" + "Steps: " + extractField(line, "steps") + "\n\n";
34
+ case "chain.step.start":
35
+ return "- Step " + extractField(line, "step") + " (" + extractField(line, "preset") + ") started\n";
36
+ case "chain.step.finish":
37
+ return "- Step " + extractField(line, "step") + " (" + extractField(line, "preset") + ") finished: " + extractField(line, "stop_reason") + "\n";
38
+ case "chain.complete":
39
+ return "\nOutcome: " + extractField(line, "outcome") + " (" + extractField(line, "steps_completed") + " steps completed)\n\n";
40
+ case "chain.spawn":
41
+ return "- Spawned: " + extractField(line, "chain_id") + " (parent: " + extractField(line, "parent_id") + ", steps: " + extractField(line, "steps") + ")\n";
42
+ default:
43
+ return "";
44
+ }
45
+ }
46
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/chains/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AAEvC,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,MAAM,WAAW,GAAG,MAAM,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IACrC,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAe;IAC9C,MAAM,OAAO,GAA2C,EAAE,CAAC;IAC3D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,uBAAuB,CAAC;IACzD,IAAI,MAAM,GAAG,mBAAmB,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,gBAAgB,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO;QACL,aAAa,EAAE,kBAAkB,EAAE,mBAAmB;QACtD,gBAAgB,EAAE,aAAa;KAChC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa,EAAE,IAAY;IACnD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,aAAa;YAChB,OAAO,YAAY,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC;QAC7G,KAAK,kBAAkB;YACrB,OAAO,SAAS,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,aAAa,CAAC;QACtG,KAAK,mBAAmB;YACtB,OAAO,SAAS,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,cAAc,GAAG,YAAY,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,IAAI,CAAC;QAClJ,KAAK,gBAAgB;YACnB,OAAO,aAAa,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,iBAAiB,CAAC,GAAG,uBAAuB,CAAC;QAChI,KAAK,aAAa;YAChB,OAAO,aAAa,GAAG,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,YAAY,GAAG,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,WAAW,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;QAC7J;YACE,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ import * as harness from "../harness/index.js";
2
+ import type { ChainSpec, DynamicChainSpec, StepRecord } from "./types.js";
3
+ export declare function runChain(chainSpec: ChainSpec, projectDir: string, selfCommand: string, runOptions: harness.RunOptions): {
4
+ completed: StepRecord[];
5
+ outcome: string;
6
+ failedStep?: number;
7
+ failedReason?: string;
8
+ };
9
+ export declare function spawnDynamicChain(spec: DynamicChainSpec, projectDir: string, selfCommand: string, runOptions: harness.RunOptions, parentId: string): {
10
+ outcome: string;
11
+ reason?: string;
12
+ chainId?: string;
13
+ completed?: StepRecord[];
14
+ failedStep?: number;
15
+ failedReason?: string;
16
+ };
17
+ export declare function writeDynamicSpec(projectDir: string, spec: DynamicChainSpec): string;