@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.
- package/README.md +145 -0
- package/bin/autoloop +2 -0
- package/dist/backend/index.d.ts +10 -0
- package/dist/backend/index.js +59 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/run-command.d.ts +7 -0
- package/dist/backend/run-command.js +50 -0
- package/dist/backend/run-command.js.map +1 -0
- package/dist/backend/run-mock.d.ts +1 -0
- package/dist/backend/run-mock.js +6 -0
- package/dist/backend/run-mock.js.map +1 -0
- package/dist/backend/run-pi.d.ts +5 -0
- package/dist/backend/run-pi.js +5 -0
- package/dist/backend/run-pi.js.map +1 -0
- package/dist/backend/types.d.ts +21 -0
- package/dist/backend/types.js +2 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/chains/budget.d.ts +7 -0
- package/dist/chains/budget.js +42 -0
- package/dist/chains/budget.js.map +1 -0
- package/dist/chains/load.d.ts +12 -0
- package/dist/chains/load.js +80 -0
- package/dist/chains/load.js.map +1 -0
- package/dist/chains/render.d.ts +2 -0
- package/dist/chains/render.js +46 -0
- package/dist/chains/render.js.map +1 -0
- package/dist/chains/run.d.ts +17 -0
- package/dist/chains/run.js +175 -0
- package/dist/chains/run.js.map +1 -0
- package/dist/chains/types.d.ts +37 -0
- package/dist/chains/types.js +2 -0
- package/dist/chains/types.js.map +1 -0
- package/dist/chains.d.ts +5 -0
- package/dist/chains.js +5 -0
- package/dist/chains.js.map +1 -0
- package/dist/commands/chain.d.ts +1 -0
- package/dist/commands/chain.js +51 -0
- package/dist/commands/chain.js.map +1 -0
- package/dist/commands/inspect.d.ts +1 -0
- package/dist/commands/inspect.js +95 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +12 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/loops.d.ts +1 -0
- package/dist/commands/loops.js +72 -0
- package/dist/commands/loops.js.map +1 -0
- package/dist/commands/memory.d.ts +1 -0
- package/dist/commands/memory.js +65 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/pi-adapter.d.ts +1 -0
- package/dist/commands/pi-adapter.js +6 -0
- package/dist/commands/pi-adapter.js.map +1 -0
- package/dist/commands/run.d.ts +1 -0
- package/dist/commands/run.js +185 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.js +169 -0
- package/dist/config.js.map +1 -0
- package/dist/events/decode.d.ts +2 -0
- package/dist/events/decode.js +45 -0
- package/dist/events/decode.js.map +1 -0
- package/dist/events/encode.d.ts +2 -0
- package/dist/events/encode.js +33 -0
- package/dist/events/encode.js.map +1 -0
- package/dist/events/guards.d.ts +5 -0
- package/dist/events/guards.js +42 -0
- package/dist/events/guards.js.map +1 -0
- package/dist/events/types.d.ts +25 -0
- package/dist/events/types.js +2 -0
- package/dist/events/types.js.map +1 -0
- package/dist/harness/config-helpers.d.ts +24 -0
- package/dist/harness/config-helpers.js +231 -0
- package/dist/harness/config-helpers.js.map +1 -0
- package/dist/harness/coordination.d.ts +1 -0
- package/dist/harness/coordination.js +127 -0
- package/dist/harness/coordination.js.map +1 -0
- package/dist/harness/display.d.ts +20 -0
- package/dist/harness/display.js +130 -0
- package/dist/harness/display.js.map +1 -0
- package/dist/harness/emit.d.ts +15 -0
- package/dist/harness/emit.js +220 -0
- package/dist/harness/emit.js.map +1 -0
- package/dist/harness/index.d.ts +13 -0
- package/dist/harness/index.js +124 -0
- package/dist/harness/index.js.map +1 -0
- package/dist/harness/iteration.d.ts +4 -0
- package/dist/harness/iteration.js +129 -0
- package/dist/harness/iteration.js.map +1 -0
- package/dist/harness/journal.d.ts +13 -0
- package/dist/harness/journal.js +106 -0
- package/dist/harness/journal.js.map +1 -0
- package/dist/harness/metareview.d.ts +4 -0
- package/dist/harness/metareview.js +33 -0
- package/dist/harness/metareview.js.map +1 -0
- package/dist/harness/metrics.d.ts +12 -0
- package/dist/harness/metrics.js +180 -0
- package/dist/harness/metrics.js.map +1 -0
- package/dist/harness/parallel.d.ts +37 -0
- package/dist/harness/parallel.js +158 -0
- package/dist/harness/parallel.js.map +1 -0
- package/dist/harness/prompt.d.ts +35 -0
- package/dist/harness/prompt.js +328 -0
- package/dist/harness/prompt.js.map +1 -0
- package/dist/harness/scratchpad.d.ts +2 -0
- package/dist/harness/scratchpad.js +65 -0
- package/dist/harness/scratchpad.js.map +1 -0
- package/dist/harness/stop.d.ts +5 -0
- package/dist/harness/stop.js +63 -0
- package/dist/harness/stop.js.map +1 -0
- package/dist/harness/tools.d.ts +3 -0
- package/dist/harness/tools.js +39 -0
- package/dist/harness/tools.js.map +1 -0
- package/dist/harness/types.d.ts +81 -0
- package/dist/harness/types.js +2 -0
- package/dist/harness/types.js.map +1 -0
- package/dist/harness/wave/finalize-wave.d.ts +9 -0
- package/dist/harness/wave/finalize-wave.js +60 -0
- package/dist/harness/wave/finalize-wave.js.map +1 -0
- package/dist/harness/wave/launch-branches.d.ts +6 -0
- package/dist/harness/wave/launch-branches.js +218 -0
- package/dist/harness/wave/launch-branches.js.map +1 -0
- package/dist/harness/wave/parse-objectives.d.ts +3 -0
- package/dist/harness/wave/parse-objectives.js +29 -0
- package/dist/harness/wave/parse-objectives.js.map +1 -0
- package/dist/harness/wave/types.d.ts +43 -0
- package/dist/harness/wave/types.js +2 -0
- package/dist/harness/wave/types.js.map +1 -0
- package/dist/harness/wave.d.ts +6 -0
- package/dist/harness/wave.js +98 -0
- package/dist/harness/wave.js.map +1 -0
- package/dist/json.d.ts +8 -0
- package/dist/json.js +80 -0
- package/dist/json.js.map +1 -0
- package/dist/loops/health.d.ts +14 -0
- package/dist/loops/health.js +104 -0
- package/dist/loops/health.js.map +1 -0
- package/dist/loops/list.d.ts +6 -0
- package/dist/loops/list.js +21 -0
- package/dist/loops/list.js.map +1 -0
- package/dist/loops/render.d.ts +18 -0
- package/dist/loops/render.js +87 -0
- package/dist/loops/render.js.map +1 -0
- package/dist/loops/show.d.ts +8 -0
- package/dist/loops/show.js +31 -0
- package/dist/loops/show.js.map +1 -0
- package/dist/loops/watch.d.ts +8 -0
- package/dist/loops/watch.js +77 -0
- package/dist/loops/watch.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +101 -0
- package/dist/main.js.map +1 -0
- package/dist/markdown.d.ts +10 -0
- package/dist/markdown.js +66 -0
- package/dist/markdown.js.map +1 -0
- package/dist/memory-render.d.ts +6 -0
- package/dist/memory-render.js +81 -0
- package/dist/memory-render.js.map +1 -0
- package/dist/memory.d.ts +23 -0
- package/dist/memory.js +314 -0
- package/dist/memory.js.map +1 -0
- package/dist/pi-adapter.d.ts +1 -0
- package/dist/pi-adapter.js +220 -0
- package/dist/pi-adapter.js.map +1 -0
- package/dist/registry/derive.d.ts +8 -0
- package/dist/registry/derive.js +81 -0
- package/dist/registry/derive.js.map +1 -0
- package/dist/registry/harness.d.ts +7 -0
- package/dist/registry/harness.js +57 -0
- package/dist/registry/harness.js.map +1 -0
- package/dist/registry/index.d.ts +5 -0
- package/dist/registry/index.js +5 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/read.d.ts +11 -0
- package/dist/registry/read.js +50 -0
- package/dist/registry/read.js.map +1 -0
- package/dist/registry/rebuild.d.ts +5 -0
- package/dist/registry/rebuild.js +19 -0
- package/dist/registry/rebuild.js.map +1 -0
- package/dist/registry/types.d.ts +19 -0
- package/dist/registry/types.js +2 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/registry/update.d.ts +2 -0
- package/dist/registry/update.js +7 -0
- package/dist/registry/update.js.map +1 -0
- package/dist/testing/mock-backend.d.ts +11 -0
- package/dist/testing/mock-backend.js +76 -0
- package/dist/testing/mock-backend.js.map +1 -0
- package/dist/topology.d.ts +25 -0
- package/dist/topology.js +188 -0
- package/dist/topology.js.map +1 -0
- package/dist/usage.d.ts +8 -0
- package/dist/usage.js +114 -0
- package/dist/usage.js.map +1 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +79 -0
- package/dist/utils.js.map +1 -0
- package/package.json +52 -0
- package/presets/autocode/README.md +81 -0
- package/presets/autocode/autoloops.toml +22 -0
- package/presets/autocode/harness.md +19 -0
- package/presets/autocode/miniloops.toml +22 -0
- package/presets/autocode/roles/build.md +33 -0
- package/presets/autocode/roles/critic.md +40 -0
- package/presets/autocode/roles/finalizer.md +43 -0
- package/presets/autocode/roles/planner.md +40 -0
- package/presets/autocode/topology.toml +32 -0
- package/presets/autodoc/README.md +42 -0
- package/presets/autodoc/autoloops.toml +21 -0
- package/presets/autodoc/harness.md +19 -0
- package/presets/autodoc/miniloops.toml +21 -0
- package/presets/autodoc/roles/auditor.md +39 -0
- package/presets/autodoc/roles/checker.md +43 -0
- package/presets/autodoc/roles/publisher.md +51 -0
- package/presets/autodoc/roles/writer.md +37 -0
- package/presets/autodoc/topology.toml +31 -0
- package/presets/autofix/README.md +56 -0
- package/presets/autofix/autoloops.toml +21 -0
- package/presets/autofix/harness.md +24 -0
- package/presets/autofix/miniloops.toml +21 -0
- package/presets/autofix/roles/closer.md +48 -0
- package/presets/autofix/roles/diagnoser.md +42 -0
- package/presets/autofix/roles/fixer.md +28 -0
- package/presets/autofix/roles/verifier.md +31 -0
- package/presets/autofix/topology.toml +33 -0
- package/presets/autoideas/README.md +73 -0
- package/presets/autoideas/autoloops.toml +18 -0
- package/presets/autoideas/harness.md +31 -0
- package/presets/autoideas/miniloops.toml +18 -0
- package/presets/autoideas/roles/analyst.md +32 -0
- package/presets/autoideas/roles/reviewer.md +36 -0
- package/presets/autoideas/roles/scanner.md +26 -0
- package/presets/autoideas/roles/synthesizer.md +48 -0
- package/presets/autoideas/topology.toml +32 -0
- package/presets/autoperf/README.md +56 -0
- package/presets/autoperf/autoloops.toml +21 -0
- package/presets/autoperf/harness.md +21 -0
- package/presets/autoperf/miniloops.toml +21 -0
- package/presets/autoperf/roles/judge.md +38 -0
- package/presets/autoperf/roles/measurer.md +36 -0
- package/presets/autoperf/roles/optimizer.md +35 -0
- package/presets/autoperf/roles/profiler.md +38 -0
- package/presets/autoperf/topology.toml +32 -0
- package/presets/autoqa/README.md +76 -0
- package/presets/autoqa/autoloops.toml +21 -0
- package/presets/autoqa/harness.md +30 -0
- package/presets/autoqa/miniloops.toml +21 -0
- package/presets/autoqa/roles/executor.md +43 -0
- package/presets/autoqa/roles/inspector.md +45 -0
- package/presets/autoqa/roles/planner.md +55 -0
- package/presets/autoqa/roles/reporter.md +74 -0
- package/presets/autoqa/topology.toml +31 -0
- package/presets/autoresearch/README.md +63 -0
- package/presets/autoresearch/autoloops.toml +18 -0
- package/presets/autoresearch/harness.md +28 -0
- package/presets/autoresearch/miniloops.toml +18 -0
- package/presets/autoresearch/roles/benchmarker.md +34 -0
- package/presets/autoresearch/roles/evaluator.md +33 -0
- package/presets/autoresearch/roles/implementer.md +26 -0
- package/presets/autoresearch/roles/strategist.md +43 -0
- package/presets/autoresearch/topology.toml +31 -0
- package/presets/autoreview/README.md +51 -0
- package/presets/autoreview/autoloops.toml +21 -0
- package/presets/autoreview/harness.md +20 -0
- package/presets/autoreview/miniloops.toml +21 -0
- package/presets/autoreview/roles/checker.md +36 -0
- package/presets/autoreview/roles/reader.md +33 -0
- package/presets/autoreview/roles/suggester.md +26 -0
- package/presets/autoreview/roles/summarizer.md +57 -0
- package/presets/autoreview/topology.toml +31 -0
- package/presets/autosec/README.md +51 -0
- package/presets/autosec/autoloops.toml +21 -0
- package/presets/autosec/harness.md +20 -0
- package/presets/autosec/miniloops.toml +21 -0
- package/presets/autosec/roles/analyst.md +38 -0
- package/presets/autosec/roles/hardener.md +36 -0
- package/presets/autosec/roles/reporter.md +63 -0
- package/presets/autosec/roles/scanner.md +38 -0
- package/presets/autosec/topology.toml +31 -0
- package/presets/autosimplify/README.md +83 -0
- package/presets/autosimplify/autoloops.toml +22 -0
- package/presets/autosimplify/harness.md +25 -0
- package/presets/autosimplify/miniloops.toml +22 -0
- package/presets/autosimplify/roles/reviewer.md +38 -0
- package/presets/autosimplify/roles/scoper.md +42 -0
- package/presets/autosimplify/roles/simplifier.md +51 -0
- package/presets/autosimplify/roles/verifier.md +40 -0
- package/presets/autosimplify/topology.toml +32 -0
- package/presets/autospec/README.md +84 -0
- package/presets/autospec/autoloops.toml +21 -0
- package/presets/autospec/harness.md +23 -0
- package/presets/autospec/miniloops.toml +21 -0
- package/presets/autospec/roles/clarifier.md +38 -0
- package/presets/autospec/roles/critic.md +41 -0
- package/presets/autospec/roles/designer.md +37 -0
- package/presets/autospec/roles/planner.md +38 -0
- package/presets/autospec/roles/researcher.md +33 -0
- package/presets/autospec/topology.toml +38 -0
- package/presets/autotest/README.md +55 -0
- package/presets/autotest/autoloops.toml +21 -0
- package/presets/autotest/harness.md +21 -0
- package/presets/autotest/miniloops.toml +21 -0
- package/presets/autotest/roles/assessor.md +57 -0
- package/presets/autotest/roles/runner.md +31 -0
- package/presets/autotest/roles/surveyor.md +39 -0
- package/presets/autotest/roles/writer.md +37 -0
- 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,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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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,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;
|