goalforge-claude 1.0.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.
- package/README.md +343 -0
- package/dist/components/claude-cli.d.ts +14 -0
- package/dist/components/claude-cli.d.ts.map +1 -0
- package/dist/components/claude-cli.js +50 -0
- package/dist/components/claude-cli.js.map +1 -0
- package/dist/components/cost-optimizer.d.ts +43 -0
- package/dist/components/cost-optimizer.d.ts.map +1 -0
- package/dist/components/cost-optimizer.js +140 -0
- package/dist/components/cost-optimizer.js.map +1 -0
- package/dist/components/executor.d.ts +18 -0
- package/dist/components/executor.d.ts.map +1 -0
- package/dist/components/executor.js +154 -0
- package/dist/components/executor.js.map +1 -0
- package/dist/components/memory-store.d.ts +47 -0
- package/dist/components/memory-store.d.ts.map +1 -0
- package/dist/components/memory-store.js +168 -0
- package/dist/components/memory-store.js.map +1 -0
- package/dist/components/planner.d.ts +22 -0
- package/dist/components/planner.d.ts.map +1 -0
- package/dist/components/planner.js +164 -0
- package/dist/components/planner.js.map +1 -0
- package/dist/components/reviewer.d.ts +19 -0
- package/dist/components/reviewer.d.ts.map +1 -0
- package/dist/components/reviewer.js +162 -0
- package/dist/components/reviewer.js.map +1 -0
- package/dist/components/task-queue.d.ts +36 -0
- package/dist/components/task-queue.d.ts.map +1 -0
- package/dist/components/task-queue.js +156 -0
- package/dist/components/task-queue.js.map +1 -0
- package/dist/components/test-runner.d.ts +20 -0
- package/dist/components/test-runner.d.ts.map +1 -0
- package/dist/components/test-runner.js +201 -0
- package/dist/components/test-runner.js.map +1 -0
- package/dist/core/config.d.ts +5 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +38 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/logger.d.ts +16 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +78 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/types.d.ts +122 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +4 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +137 -0
- package/dist/index.js.map +1 -0
- package/dist/loop-controller.d.ts +39 -0
- package/dist/loop-controller.d.ts.map +1 -0
- package/dist/loop-controller.js +272 -0
- package/dist/loop-controller.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# GoalForge — Developer Reference
|
|
2
|
+
|
|
3
|
+
Describe what you want. Claude builds it. No API key needed.
|
|
4
|
+
|
|
5
|
+
An autonomous AI development loop that decomposes a high-level goal into tasks, executes them via Claude, validates the output, and iterates until the goal is met or a budget/iteration limit is hit.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [Architecture](#architecture)
|
|
12
|
+
2. [Component Reference](#component-reference)
|
|
13
|
+
3. [Data Flow](#data-flow)
|
|
14
|
+
4. [Memory Layout](#memory-layout)
|
|
15
|
+
5. [Exit Conditions](#exit-conditions)
|
|
16
|
+
6. [Configuration](#configuration)
|
|
17
|
+
7. [Running Locally](#running-locally)
|
|
18
|
+
8. [Testing](#testing)
|
|
19
|
+
9. [Extending the System](#extending-the-system)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Architecture
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
index.ts
|
|
27
|
+
└── LoopController ← main event loop
|
|
28
|
+
├── Planner ← goal → ordered task list (Claude)
|
|
29
|
+
├── TaskQueue ← dependency-aware in-memory queue + disk persistence
|
|
30
|
+
├── Executor ← task → files + shell commands (Claude)
|
|
31
|
+
├── TestRunner ← runs jest/npm test in workspace, parses report
|
|
32
|
+
├── Reviewer ← critiques completed task output (Claude)
|
|
33
|
+
├── CostOptimizer ← spend budget tracking + prompt-level response cache
|
|
34
|
+
└── MemoryStore ← file-system KV store for all persistent state
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Each iteration of the loop runs six phases in order:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
PLAN → EXECUTE → TEST → REVIEW → COST CHECK → MEMORY UPDATE → (repeat or exit)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Component Reference
|
|
46
|
+
|
|
47
|
+
### `LoopController` (`src/loop-controller.ts`)
|
|
48
|
+
|
|
49
|
+
The main orchestrator. Owns all component instances and drives the six-phase loop.
|
|
50
|
+
|
|
51
|
+
**Key methods**
|
|
52
|
+
|
|
53
|
+
| Method | Description |
|
|
54
|
+
|--------|-------------|
|
|
55
|
+
| `run()` | Start the loop. Returns a `LoopExitReason` when done. |
|
|
56
|
+
| `getState()` | Snapshot of current `ProjectState` (safe to call before `run()`). |
|
|
57
|
+
|
|
58
|
+
**Loop phases**
|
|
59
|
+
|
|
60
|
+
| Phase | What it does |
|
|
61
|
+
|-------|-------------|
|
|
62
|
+
| `planPhase` | Skips re-planning if eligible tasks exist; otherwise calls `Planner`. |
|
|
63
|
+
| `executePhase` | Runs up to 3 eligible tasks per iteration. |
|
|
64
|
+
| `testPhase` | Calls `TestRunner`, updates coverage + pass/fail on state. |
|
|
65
|
+
| `reviewPhase` | Reviews the last 3 completed tasks; requeues if score < 70 and `retryCount < 2`. |
|
|
66
|
+
| `costCheckPhase` | Exits loop if total spend exceeds `maxCostUsd`. |
|
|
67
|
+
| `updateMemoryPhase` | Persists `ProjectState` to disk and logs memory summary; `checkExitConditions()` is called immediately after by the loop. |
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### `Planner` (`src/components/planner.ts`)
|
|
72
|
+
|
|
73
|
+
Calls Claude with a structured prompt and the current project state to produce a prioritised task list and architecture decisions.
|
|
74
|
+
|
|
75
|
+
**Caching**: the response cache key is a SHA-256 hash of the full prompt (goal + context). In dry-run mode responses are never cached to disk (use the `dryRun` flag for tests).
|
|
76
|
+
|
|
77
|
+
**Output shape** (`PlannerOutput[]`)
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
{
|
|
81
|
+
objective: string;
|
|
82
|
+
priority: number; // 1 = highest
|
|
83
|
+
dependencies: string[]; // index strings ("0", "1") referencing tasks in the same planner response
|
|
84
|
+
estimatedEffort: 'low' | 'medium' | 'high';
|
|
85
|
+
rationale?: string;
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### `TaskQueue` (`src/components/task-queue.ts`)
|
|
92
|
+
|
|
93
|
+
In-memory map of `Task` objects backed by `MemoryStore`. Dependency resolution happens at eligibility check time — a task is eligible only if all its dependency IDs have `status === 'COMPLETE'`.
|
|
94
|
+
|
|
95
|
+
**Key methods**
|
|
96
|
+
|
|
97
|
+
| Method | Description |
|
|
98
|
+
|--------|-------------|
|
|
99
|
+
| `nextEligible()` | Highest-priority PENDING task whose deps are all COMPLETE, or `null`. |
|
|
100
|
+
| `enqueueBatch(plans)` | Bulk enqueue from planner output. |
|
|
101
|
+
| `start(id)` | PENDING → RUNNING. Throws if deps unresolved. |
|
|
102
|
+
| `complete(id)` | RUNNING → COMPLETE. |
|
|
103
|
+
| `fail(id, reason?)` | Any → FAILED. |
|
|
104
|
+
| `retry(id)` | Any → PENDING, increments `retryCount`. |
|
|
105
|
+
| `isComplete()` | `true` if queue is non-empty and every task is COMPLETE or FAILED. |
|
|
106
|
+
|
|
107
|
+
**Hydration**: on construction the queue loads all persisted tasks from `MemoryStore`. RUNNING tasks are reset to PENDING (crash recovery).
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
### `Executor` (`src/components/executor.ts`)
|
|
112
|
+
|
|
113
|
+
Calls Claude to implement a single task. The model returns JSON describing files to write and shell commands to run. The executor writes the files under `workspaceDir` and runs the commands (skipped in dry-run mode).
|
|
114
|
+
|
|
115
|
+
**dry-run output**: writes `dry-run/{taskId}.txt` to the workspace — a harmless placeholder.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### `Reviewer` (`src/components/reviewer.ts`)
|
|
120
|
+
|
|
121
|
+
Calls Claude to score completed task output (0–100). A score ≥ 70 with no `critical` critiques counts as `passed`. Failed reviews trigger a retry via `TaskQueue.retry()` (max 2 retries per task).
|
|
122
|
+
|
|
123
|
+
**dry-run output**: always returns score 85, passed: true, one low-severity placeholder critique.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### `TestRunner` (`src/components/test-runner.ts`)
|
|
128
|
+
|
|
129
|
+
Runs the test suite inside `workspaceDir` and returns a structured `TestReport`.
|
|
130
|
+
|
|
131
|
+
**Runner detection order**
|
|
132
|
+
|
|
133
|
+
1. `jest.config.ts / .js / .json` found → `npx jest --json --coverage`
|
|
134
|
+
2. `package.json` with jest dependency → `npx jest --coverage`
|
|
135
|
+
3. `package.json` with `scripts.test` → `npm test`
|
|
136
|
+
4. Neither found → returns an empty report immediately (no command run)
|
|
137
|
+
|
|
138
|
+
> **Important**: the workspace must contain its own `package.json` for the runner to execute. Without one, the runner exits early. This prevents `npm` from crawling up to a parent `package.json` and triggering unintended test runs.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### `CostOptimizer` (`src/components/cost-optimizer.ts`)
|
|
143
|
+
|
|
144
|
+
Tracks cumulative spend across all claude CLI calls and provides a prompt-level response cache backed by `MemoryStore`. Cost is recorded via `recordCost(usd)` using the value reported by the CLI; token-based estimation is used only for pre-call budget checks.
|
|
145
|
+
|
|
146
|
+
**Budget enforcement**: before every claude CLI call, `estimate()` is called. If the projected cost would exceed the remaining budget it returns `recommendedAction: 'skip'` and the caller must not proceed.
|
|
147
|
+
|
|
148
|
+
**Cache**: `buildCacheKey(...parts)` produces a 32-char SHA-256 hex key. `getCachedResponse` / `putCachedResponse` delegate to `MemoryStore.getCached` / `putCache`.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### `MemoryStore` (`src/components/memory-store.ts`)
|
|
153
|
+
|
|
154
|
+
File-system backed key-value store. No external services. Layout:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
memory/
|
|
158
|
+
state/project.json ← single ProjectState document
|
|
159
|
+
tasks/<uuid>.json ← one file per task
|
|
160
|
+
critiques/<uuid>.json ← one file per Critique
|
|
161
|
+
decisions/<uuid>.json ← one file per ArchitectureDecision
|
|
162
|
+
files/<path-hash>.json ← metadata for each generated file
|
|
163
|
+
cache/<sha256>.json ← CostOptimizer response cache entries
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Data Flow
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
┌─────────────────────────────────┐
|
|
172
|
+
│ LoopController │
|
|
173
|
+
│ │
|
|
174
|
+
goal ───►│ initState() ──► MemoryStore │
|
|
175
|
+
│ │
|
|
176
|
+
│ ┌── ITERATION N ─────────────┐ │
|
|
177
|
+
│ │ │ │
|
|
178
|
+
│ │ Planner.plan() │ │
|
|
179
|
+
│ │ └─► claude CLI │ │
|
|
180
|
+
│ │ └─► TaskQueue.enqueueBatch│ │
|
|
181
|
+
│ │ └─► MemoryStore.saveDecision│
|
|
182
|
+
│ │ │ │
|
|
183
|
+
│ │ Executor.execute(task) │ │
|
|
184
|
+
│ │ └─► claude CLI │ │
|
|
185
|
+
│ │ └─► write files to workspace│
|
|
186
|
+
│ │ └─► run shell commands │ │
|
|
187
|
+
│ │ │ │
|
|
188
|
+
│ │ TestRunner.run() │ │
|
|
189
|
+
│ │ └─► npx jest in workspace│ │
|
|
190
|
+
│ │ │ │
|
|
191
|
+
│ │ Reviewer.review(task) │ │
|
|
192
|
+
│ │ └─► claude CLI │ │
|
|
193
|
+
│ │ └─► MemoryStore.saveCritique│
|
|
194
|
+
│ │ │ │
|
|
195
|
+
│ │ CostOptimizer.isBudgetExceeded?│
|
|
196
|
+
│ │ checkExitConditions? │ │
|
|
197
|
+
│ └────────────────────────────┘ │
|
|
198
|
+
│ │
|
|
199
|
+
│ return LoopExitReason │
|
|
200
|
+
└─────────────────────────────────┘
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Memory Layout
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
<project-root>/
|
|
209
|
+
engine/
|
|
210
|
+
memory/
|
|
211
|
+
state/project.json
|
|
212
|
+
tasks/
|
|
213
|
+
critiques/
|
|
214
|
+
decisions/
|
|
215
|
+
files/
|
|
216
|
+
cache/
|
|
217
|
+
workspace/ ← generated code lives here
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Paths are configured via `workspaceDir` and `memoryDir` in `LoopConfig`. Tests write to isolated temp directories and clean up in `beforeEach` and `afterAll`.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Exit Conditions
|
|
225
|
+
|
|
226
|
+
The loop exits (returning a `LoopExitReason`) when the first of these is true:
|
|
227
|
+
|
|
228
|
+
| Reason | Condition |
|
|
229
|
+
|--------|-----------|
|
|
230
|
+
| `no-critical-issues` | `coveragePercent >= targetCoveragePercent` AND `testsPassing` AND `criticalIssueCount <= maxCriticalIssues` |
|
|
231
|
+
| `all-tasks-complete` | Queue is complete (all COMPLETE/FAILED) AND at least one task was completed |
|
|
232
|
+
| `cost-exceeded` | `totalSpendUsd >= maxCostUsd` (checked after execute phase and after cost phase) |
|
|
233
|
+
| `max-iterations` | Loop counter reaches `maxIterations` |
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Configuration
|
|
238
|
+
|
|
239
|
+
All configuration lives in `LoopConfig`. Set via environment variables when using the default `index.ts` entry point.
|
|
240
|
+
|
|
241
|
+
| Env var | Default | Description |
|
|
242
|
+
|---------|---------|-------------|
|
|
243
|
+
| `GOAL` | `'Build a production-ready stock fundamental analysis application'` | What the loop tries to build |
|
|
244
|
+
| `PROJECT_ID` | `project-<timestamp>` | Unique identifier for memory persistence |
|
|
245
|
+
| `MAX_ITERATIONS` | `20` | Hard cap on loop iterations |
|
|
246
|
+
| `MAX_COST_USD` | `10` | Spend cap in USD as reported by the claude CLI (subscription billing — governs usage, not direct charges) |
|
|
247
|
+
| `TARGET_COVERAGE` | `95` | Test coverage % needed to exit cleanly |
|
|
248
|
+
| `DRY_RUN` | `false` | Set to `true` to skip all claude CLI calls and file writes |
|
|
249
|
+
| `LOG_LEVEL` | `INFO` | `DEBUG` / `INFO` / `WARN` / `ERROR` |
|
|
250
|
+
|
|
251
|
+
Budget constants (not env-configurable without code change):
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
// src/core/config.ts
|
|
255
|
+
DEFAULT_BUDGET = {
|
|
256
|
+
maxCostUsd: 10.0,
|
|
257
|
+
maxInputTokensPerCall: 100_000,
|
|
258
|
+
maxOutputTokensPerCall: 8_000,
|
|
259
|
+
warnThresholdPercent: 80,
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Model: determined by the `claude` CLI session (whichever model your Claude.ai subscription uses by default).
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Running Locally
|
|
268
|
+
|
|
269
|
+
**Prerequisites**: Node.js 20+, the `claude` CLI installed and logged in (`claude login`).
|
|
270
|
+
|
|
271
|
+
No `ANTHROPIC_API_KEY` is required. The orchestrator calls Claude via the `claude` CLI, which uses your Claude.ai subscription (Pro/Teams) for authentication.
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
cd engine
|
|
275
|
+
|
|
276
|
+
# Install dependencies
|
|
277
|
+
npm install
|
|
278
|
+
|
|
279
|
+
# Build TypeScript
|
|
280
|
+
npm run build
|
|
281
|
+
|
|
282
|
+
# Dry run (no Claude calls, no file writes)
|
|
283
|
+
DRY_RUN=true npm start
|
|
284
|
+
|
|
285
|
+
# Real run with a custom goal
|
|
286
|
+
GOAL="Build a REST API for user authentication" npm start
|
|
287
|
+
|
|
288
|
+
# Override budget and iteration limit
|
|
289
|
+
GOAL="..." MAX_COST_USD=5 MAX_ITERATIONS=10 npm start
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Generated code is written to `../workspace/` (sibling of the `engine/` directory).
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Testing
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
cd engine
|
|
300
|
+
|
|
301
|
+
# Run all tests with coverage
|
|
302
|
+
npm test
|
|
303
|
+
|
|
304
|
+
# Watch mode
|
|
305
|
+
npm run test:watch
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**Coverage thresholds** (enforced by jest):
|
|
309
|
+
|
|
310
|
+
| Metric | Threshold |
|
|
311
|
+
|--------|-----------|
|
|
312
|
+
| Lines | 70% |
|
|
313
|
+
| Functions | 70% |
|
|
314
|
+
| Branches | 60% |
|
|
315
|
+
| Statements | 70% |
|
|
316
|
+
|
|
317
|
+
**Test isolation**: each test suite writes to its own temp directory (e.g. `task-queue-test-tmp/`) and cleans it up in both `beforeEach` and `afterAll`. Do not share `MemoryStore` instances or temp directories across test suites.
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Extending the System
|
|
322
|
+
|
|
323
|
+
### Swap in a different model
|
|
324
|
+
|
|
325
|
+
Pass `--model <model-id>` in the `spawn` call inside `src/components/claude-cli.ts`. The default is the model your `claude` CLI session is configured to use.
|
|
326
|
+
|
|
327
|
+
### Add a new phase to the loop
|
|
328
|
+
|
|
329
|
+
1. Add the method to `LoopController` following the existing phase pattern.
|
|
330
|
+
2. Call it inside the `while` loop in `run()`.
|
|
331
|
+
3. If it can trigger an early exit, return a `LoopExitReason`; otherwise return `null`.
|
|
332
|
+
|
|
333
|
+
### Add a new exit condition
|
|
334
|
+
|
|
335
|
+
Add a branch to `checkExitConditions()` and add the new reason string to the `LoopExitReason.reason` union type in `src/core/types.ts`.
|
|
336
|
+
|
|
337
|
+
### Change the planner prompt
|
|
338
|
+
|
|
339
|
+
Edit `SYSTEM_PROMPT` in `src/components/planner.ts`. The JSON schema returned by the model must match `PlannerResponse`; update both if you change the shape.
|
|
340
|
+
|
|
341
|
+
### Persist additional data
|
|
342
|
+
|
|
343
|
+
Add a new subdirectory constant to `MemoryStore.dirs`, create the directory in the constructor, and add typed `save*` / `load*` methods following the existing pattern.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface CliResult {
|
|
2
|
+
text: string;
|
|
3
|
+
costUsd: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Call Claude via the `claude` CLI (uses Claude.ai subscription auth —
|
|
7
|
+
* no ANTHROPIC_API_KEY required).
|
|
8
|
+
*
|
|
9
|
+
* Spawns: claude -p --output-format json --dangerously-skip-permissions
|
|
10
|
+
* Sends the combined system+user prompt via stdin.
|
|
11
|
+
* Returns the result text and reported cost.
|
|
12
|
+
*/
|
|
13
|
+
export declare function callClaude(systemPrompt: string, userPrompt: string, timeoutMs?: number): Promise<CliResult>;
|
|
14
|
+
//# sourceMappingURL=claude-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-cli.d.ts","sourceRoot":"","sources":["../../src/components/claude-cli.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,SAAS,SAAU,GAClB,OAAO,CAAC,SAAS,CAAC,CA8CpB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.callClaude = callClaude;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
/**
|
|
6
|
+
* Call Claude via the `claude` CLI (uses Claude.ai subscription auth —
|
|
7
|
+
* no ANTHROPIC_API_KEY required).
|
|
8
|
+
*
|
|
9
|
+
* Spawns: claude -p --output-format json --dangerously-skip-permissions
|
|
10
|
+
* Sends the combined system+user prompt via stdin.
|
|
11
|
+
* Returns the result text and reported cost.
|
|
12
|
+
*/
|
|
13
|
+
async function callClaude(systemPrompt, userPrompt, timeoutMs = 180000) {
|
|
14
|
+
const fullPrompt = `${systemPrompt}\n\n---\n\n${userPrompt}`;
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const child = (0, child_process_1.spawn)('claude', ['-p', '--output-format', 'json', '--dangerously-skip-permissions'], { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
17
|
+
let stdout = '';
|
|
18
|
+
let stderr = '';
|
|
19
|
+
child.stdout.on('data', (chunk) => { stdout += chunk.toString(); });
|
|
20
|
+
child.stderr.on('data', (chunk) => { stderr += chunk.toString(); });
|
|
21
|
+
const timer = setTimeout(() => {
|
|
22
|
+
child.kill('SIGTERM');
|
|
23
|
+
reject(new Error(`claude CLI timed out after ${timeoutMs}ms`));
|
|
24
|
+
}, timeoutMs);
|
|
25
|
+
child.on('close', (code) => {
|
|
26
|
+
clearTimeout(timer);
|
|
27
|
+
if (code !== 0) {
|
|
28
|
+
reject(new Error(`claude exited ${code}: ${stderr.slice(0, 500)}`));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const envelope = JSON.parse(stdout.trim());
|
|
33
|
+
resolve({
|
|
34
|
+
text: envelope.result ?? '',
|
|
35
|
+
costUsd: typeof envelope.total_cost_usd === 'number' ? envelope.total_cost_usd : 0,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
reject(new Error(`Failed to parse claude CLI output: ${err}. stdout: ${stdout.slice(0, 300)}`));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
child.on('error', (err) => {
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
reject(new Error(`Failed to spawn claude CLI: ${err.message}. Is claude installed and on PATH?`));
|
|
45
|
+
});
|
|
46
|
+
child.stdin.write(fullPrompt);
|
|
47
|
+
child.stdin.end();
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=claude-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-cli.js","sourceRoot":"","sources":["../../src/components/claude-cli.ts"],"names":[],"mappings":";;AAeA,gCAkDC;AAjED,iDAAsC;AAOtC;;;;;;;GAOG;AACI,KAAK,UAAU,UAAU,CAC9B,YAAoB,EACpB,UAAkB,EAClB,SAAS,GAAG,MAAO;IAEnB,MAAM,UAAU,GAAG,GAAG,YAAY,cAAc,UAAU,EAAE,CAAC;IAE7D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,IAAA,qBAAK,EACjB,QAAQ,EACR,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,gCAAgC,CAAC,EACnE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACpC,CAAC;QAEF,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5E,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAE5E,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,MAAM,CAAC,IAAI,KAAK,CAAC,8BAA8B,SAAS,IAAI,CAAC,CAAC,CAAC;QACjE,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;gBACpE,OAAO;YACT,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC3C,OAAO,CAAC;oBACN,IAAI,EAAE,QAAQ,CAAC,MAAM,IAAI,EAAE;oBAC3B,OAAO,EAAE,OAAO,QAAQ,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;iBACnF,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,KAAK,CAAC,sCAAsC,GAAG,aAAa,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAClG,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,OAAO,oCAAoC,CAAC,CAAC,CAAC;QACpG,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC9B,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CostBudget, CostEstimate, TokenUsage } from '../core/types';
|
|
2
|
+
import { MemoryStore } from './memory-store';
|
|
3
|
+
/**
|
|
4
|
+
* Tracks cumulative token spend, enforces budget, and provides a hash-keyed
|
|
5
|
+
* response cache so identical prompts never hit the API twice.
|
|
6
|
+
*/
|
|
7
|
+
export declare class CostOptimizer {
|
|
8
|
+
private readonly budget;
|
|
9
|
+
private readonly memory;
|
|
10
|
+
private totalInputTokens;
|
|
11
|
+
private totalOutputTokens;
|
|
12
|
+
private directCostUsd;
|
|
13
|
+
private callCount;
|
|
14
|
+
private readonly log;
|
|
15
|
+
constructor(budget: CostBudget, memory: MemoryStore);
|
|
16
|
+
/** Deterministic cache key from prompt text + any context strings. */
|
|
17
|
+
buildCacheKey(prompt: string, ...contextParts: string[]): string;
|
|
18
|
+
getCachedResponse(cacheKey: string): string | null;
|
|
19
|
+
putCachedResponse(cacheKey: string, response: string): void;
|
|
20
|
+
/**
|
|
21
|
+
* Call before every LLM request.
|
|
22
|
+
* Returns a CostEstimate that includes a recommendedAction.
|
|
23
|
+
* Callers MUST respect 'skip' — it means the budget is exhausted.
|
|
24
|
+
*/
|
|
25
|
+
estimate(promptText: string, estimatedOutputTokens: number, cacheKey: string): CostEstimate;
|
|
26
|
+
/** Record actual usage after an API call completes (token-based billing). */
|
|
27
|
+
recordUsage(usage: TokenUsage): void;
|
|
28
|
+
/** Record cost reported directly by the claude CLI (subscription billing). */
|
|
29
|
+
recordCost(usd: number): void;
|
|
30
|
+
totalSpend(): number;
|
|
31
|
+
isBudgetExceeded(): boolean;
|
|
32
|
+
getStats(): {
|
|
33
|
+
callCount: number;
|
|
34
|
+
totalInputTokens: number;
|
|
35
|
+
totalOutputTokens: number;
|
|
36
|
+
totalSpendUsd: number;
|
|
37
|
+
remainingBudgetUsd: number;
|
|
38
|
+
cacheEntries: number;
|
|
39
|
+
};
|
|
40
|
+
/** Sync cumulative totals from a ProjectState so they survive process restarts. */
|
|
41
|
+
restoreFromState(inputTokens: number, outputTokens: number): void;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=cost-optimizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-optimizer.d.ts","sourceRoot":"","sources":["../../src/components/cost-optimizer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C;;;GAGG;AACH,qBAAa,aAAa;IAQtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAiC;gBAGlC,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,WAAW;IAKtC,sEAAsE;IACtE,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM;IAKhE,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAQlD,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAM3D;;;;OAIG;IACH,QAAQ,CACN,UAAU,EAAE,MAAM,EAClB,qBAAqB,EAAE,MAAM,EAC7B,QAAQ,EAAE,MAAM,GACf,YAAY;IA2Df,6EAA6E;IAC7E,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAYpC,8EAA8E;IAC9E,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAY7B,UAAU,IAAI,MAAM;IAIpB,gBAAgB,IAAI,OAAO;IAI3B,QAAQ,IAAI;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,gBAAgB,EAAE,MAAM,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,aAAa,EAAE,MAAM,CAAC;QACtB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,YAAY,EAAE,MAAM,CAAC;KACtB;IAYD,mFAAmF;IACnF,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;CAIlE"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CostOptimizer = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const config_1 = require("../core/config");
|
|
6
|
+
const logger_1 = require("../core/logger");
|
|
7
|
+
/**
|
|
8
|
+
* Tracks cumulative token spend, enforces budget, and provides a hash-keyed
|
|
9
|
+
* response cache so identical prompts never hit the API twice.
|
|
10
|
+
*/
|
|
11
|
+
class CostOptimizer {
|
|
12
|
+
constructor(budget, memory) {
|
|
13
|
+
this.budget = budget;
|
|
14
|
+
this.memory = memory;
|
|
15
|
+
this.totalInputTokens = 0;
|
|
16
|
+
this.totalOutputTokens = 0;
|
|
17
|
+
this.directCostUsd = 0;
|
|
18
|
+
this.callCount = 0;
|
|
19
|
+
this.log = (0, logger_1.createLogger)('CostOptimizer');
|
|
20
|
+
}
|
|
21
|
+
// ── Cache ──────────────────────────────────────────────────────────────────
|
|
22
|
+
/** Deterministic cache key from prompt text + any context strings. */
|
|
23
|
+
buildCacheKey(prompt, ...contextParts) {
|
|
24
|
+
const raw = [prompt, ...contextParts].join('\n---\n');
|
|
25
|
+
return (0, crypto_1.createHash)('sha256').update(raw).digest('hex').slice(0, 32);
|
|
26
|
+
}
|
|
27
|
+
getCachedResponse(cacheKey) {
|
|
28
|
+
const hit = this.memory.getCached(cacheKey);
|
|
29
|
+
if (hit) {
|
|
30
|
+
this.log.debug('Cache hit', { cacheKey: cacheKey.slice(0, 8) + '…' });
|
|
31
|
+
}
|
|
32
|
+
return hit;
|
|
33
|
+
}
|
|
34
|
+
putCachedResponse(cacheKey, response) {
|
|
35
|
+
this.memory.putCache(cacheKey, response);
|
|
36
|
+
}
|
|
37
|
+
// ── Budget ─────────────────────────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Call before every LLM request.
|
|
40
|
+
* Returns a CostEstimate that includes a recommendedAction.
|
|
41
|
+
* Callers MUST respect 'skip' — it means the budget is exhausted.
|
|
42
|
+
*/
|
|
43
|
+
estimate(promptText, estimatedOutputTokens, cacheKey) {
|
|
44
|
+
const isHit = this.memory.getCached(cacheKey) !== null;
|
|
45
|
+
if (isHit) {
|
|
46
|
+
return {
|
|
47
|
+
cacheKey,
|
|
48
|
+
isCacheHit: true,
|
|
49
|
+
inputTokens: 0,
|
|
50
|
+
outputTokens: 0,
|
|
51
|
+
estimatedCostUsd: 0,
|
|
52
|
+
recommendedAction: 'cache-hit',
|
|
53
|
+
reason: 'Response already cached — no API call needed',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// rough token estimate: 4 chars ≈ 1 token
|
|
57
|
+
const estimatedInput = Math.ceil(promptText.length / 4);
|
|
58
|
+
const estimatedCost = (0, config_1.calcCost)(estimatedInput, estimatedOutputTokens);
|
|
59
|
+
const currentSpend = this.totalSpend();
|
|
60
|
+
const remainingBudget = this.budget.maxCostUsd - currentSpend;
|
|
61
|
+
if (estimatedCost > remainingBudget) {
|
|
62
|
+
return {
|
|
63
|
+
cacheKey,
|
|
64
|
+
isCacheHit: false,
|
|
65
|
+
inputTokens: estimatedInput,
|
|
66
|
+
outputTokens: estimatedOutputTokens,
|
|
67
|
+
estimatedCostUsd: estimatedCost,
|
|
68
|
+
recommendedAction: 'skip',
|
|
69
|
+
reason: `Budget exhausted — $${currentSpend.toFixed(4)} of $${this.budget.maxCostUsd} spent`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const spendPercent = (currentSpend / this.budget.maxCostUsd) * 100;
|
|
73
|
+
if (spendPercent >= this.budget.warnThresholdPercent) {
|
|
74
|
+
this.log.warn('Approaching budget limit', {
|
|
75
|
+
spentUsd: currentSpend.toFixed(4),
|
|
76
|
+
limitUsd: this.budget.maxCostUsd,
|
|
77
|
+
pct: spendPercent.toFixed(1) + '%',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const action = estimatedInput > this.budget.maxInputTokensPerCall ? 'optimize' : 'proceed';
|
|
81
|
+
return {
|
|
82
|
+
cacheKey,
|
|
83
|
+
isCacheHit: false,
|
|
84
|
+
inputTokens: estimatedInput,
|
|
85
|
+
outputTokens: estimatedOutputTokens,
|
|
86
|
+
estimatedCostUsd: estimatedCost,
|
|
87
|
+
recommendedAction: action,
|
|
88
|
+
reason: action === 'optimize'
|
|
89
|
+
? `Prompt is large (${estimatedInput} estimated tokens) — consider trimming`
|
|
90
|
+
: 'Within limits — proceed',
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Record actual usage after an API call completes (token-based billing). */
|
|
94
|
+
recordUsage(usage) {
|
|
95
|
+
this.totalInputTokens += usage.inputTokens;
|
|
96
|
+
this.totalOutputTokens += usage.outputTokens;
|
|
97
|
+
this.callCount++;
|
|
98
|
+
this.log.debug('Usage recorded', {
|
|
99
|
+
callCount: this.callCount,
|
|
100
|
+
totalInputTokens: this.totalInputTokens,
|
|
101
|
+
totalOutputTokens: this.totalOutputTokens,
|
|
102
|
+
totalSpendUsd: this.totalSpend().toFixed(4),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/** Record cost reported directly by the claude CLI (subscription billing). */
|
|
106
|
+
recordCost(usd) {
|
|
107
|
+
this.directCostUsd += usd;
|
|
108
|
+
this.callCount++;
|
|
109
|
+
this.log.debug('CLI cost recorded', {
|
|
110
|
+
callCount: this.callCount,
|
|
111
|
+
directCostUsd: this.directCostUsd.toFixed(4),
|
|
112
|
+
totalSpendUsd: this.totalSpend().toFixed(4),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
// ── Stats ──────────────────────────────────────────────────────────────────
|
|
116
|
+
totalSpend() {
|
|
117
|
+
return (0, config_1.calcCost)(this.totalInputTokens, this.totalOutputTokens) + this.directCostUsd;
|
|
118
|
+
}
|
|
119
|
+
isBudgetExceeded() {
|
|
120
|
+
return this.totalSpend() >= this.budget.maxCostUsd;
|
|
121
|
+
}
|
|
122
|
+
getStats() {
|
|
123
|
+
const totalSpendUsd = this.totalSpend();
|
|
124
|
+
return {
|
|
125
|
+
callCount: this.callCount,
|
|
126
|
+
totalInputTokens: this.totalInputTokens,
|
|
127
|
+
totalOutputTokens: this.totalOutputTokens,
|
|
128
|
+
totalSpendUsd,
|
|
129
|
+
remainingBudgetUsd: Math.max(0, this.budget.maxCostUsd - totalSpendUsd),
|
|
130
|
+
cacheEntries: this.memory.getCacheSize(),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Sync cumulative totals from a ProjectState so they survive process restarts. */
|
|
134
|
+
restoreFromState(inputTokens, outputTokens) {
|
|
135
|
+
this.totalInputTokens = inputTokens;
|
|
136
|
+
this.totalOutputTokens = outputTokens;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.CostOptimizer = CostOptimizer;
|
|
140
|
+
//# sourceMappingURL=cost-optimizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-optimizer.js","sourceRoot":"","sources":["../../src/components/cost-optimizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Task, TaskResult } from '../core/types';
|
|
2
|
+
import { CostOptimizer } from './cost-optimizer';
|
|
3
|
+
import { MemoryStore } from './memory-store';
|
|
4
|
+
export declare class Executor {
|
|
5
|
+
private readonly workspaceDir;
|
|
6
|
+
private readonly optimizer;
|
|
7
|
+
private readonly memory;
|
|
8
|
+
private readonly dryRun;
|
|
9
|
+
private readonly log;
|
|
10
|
+
constructor(workspaceDir: string, optimizer: CostOptimizer, memory: MemoryStore, dryRun?: boolean);
|
|
11
|
+
execute(task: Task): Promise<TaskResult>;
|
|
12
|
+
private buildContext;
|
|
13
|
+
private callApi;
|
|
14
|
+
private parse;
|
|
15
|
+
private apply;
|
|
16
|
+
private dryRunResponse;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/components/executor.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAiC7C,qBAAa,QAAQ;IAIjB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA4B;gBAG7B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,aAAa,EACxB,MAAM,EAAE,WAAW,EACnB,MAAM,UAAQ;IAK3B,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC;IA0C9C,OAAO,CAAC,YAAY;YAuBN,OAAO;IASrB,OAAO,CAAC,KAAK;YAKC,KAAK;IA0CnB,OAAO,CAAC,cAAc;CAavB"}
|