@os-eco/overstory-cli 0.6.11 → 0.7.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 +7 -9
- package/agents/lead.md +20 -19
- package/package.json +5 -3
- package/src/agents/overlay.test.ts +23 -0
- package/src/agents/overlay.ts +5 -4
- package/src/commands/coordinator.ts +21 -9
- package/src/commands/costs.test.ts +1 -1
- package/src/commands/costs.ts +13 -20
- package/src/commands/dashboard.ts +38 -138
- package/src/commands/doctor.test.ts +1 -1
- package/src/commands/doctor.ts +2 -2
- package/src/commands/ecosystem.ts +2 -1
- package/src/commands/errors.test.ts +4 -5
- package/src/commands/errors.ts +4 -62
- package/src/commands/feed.test.ts +2 -2
- package/src/commands/feed.ts +12 -106
- package/src/commands/inspect.ts +10 -44
- package/src/commands/logs.ts +7 -63
- package/src/commands/metrics.test.ts +2 -2
- package/src/commands/metrics.ts +3 -17
- package/src/commands/monitor.ts +17 -7
- package/src/commands/replay.test.ts +2 -2
- package/src/commands/replay.ts +12 -135
- package/src/commands/run.ts +7 -23
- package/src/commands/sling.test.ts +53 -0
- package/src/commands/sling.ts +25 -10
- package/src/commands/status.ts +4 -17
- package/src/commands/supervisor.ts +18 -8
- package/src/commands/trace.test.ts +5 -6
- package/src/commands/trace.ts +11 -109
- package/src/config.ts +10 -0
- package/src/index.ts +2 -1
- package/src/logging/format.ts +214 -0
- package/src/logging/theme.ts +132 -0
- package/src/metrics/store.test.ts +46 -0
- package/src/metrics/store.ts +11 -0
- package/src/mulch/client.test.ts +20 -0
- package/src/mulch/client.ts +312 -45
- package/src/runtimes/claude.test.ts +616 -0
- package/src/runtimes/claude.ts +218 -0
- package/src/runtimes/registry.test.ts +53 -0
- package/src/runtimes/registry.ts +33 -0
- package/src/runtimes/types.ts +125 -0
- package/src/types.ts +4 -0
- package/src/worktree/tmux.test.ts +28 -13
- package/src/worktree/tmux.ts +14 -28
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ Every command supports `--json` where noted. Global flags: `-q`/`--quiet`, `--ti
|
|
|
75
75
|
| Command | Description |
|
|
76
76
|
|---------|-------------|
|
|
77
77
|
| `ov init` | Initialize `.overstory/` in current project (`--yes`, `--name`) |
|
|
78
|
-
| `ov sling <task-id>` | Spawn a worker agent (`--capability`, `--name`, `--spec`, `--files`, `--parent`, `--depth`, `--skip-scout`, `--skip-review`, `--max-agents`, `--dispatch-max-agents`, `--skip-task-check`, `--json`) |
|
|
78
|
+
| `ov sling <task-id>` | Spawn a worker agent (`--capability`, `--name`, `--spec`, `--files`, `--parent`, `--depth`, `--skip-scout`, `--skip-review`, `--max-agents`, `--dispatch-max-agents`, `--skip-task-check`, `--runtime`, `--json`) |
|
|
79
79
|
| `ov stop <agent-name>` | Terminate a running agent (`--clean-worktree`, `--json`) |
|
|
80
80
|
| `ov prime` | Load context for orchestrator/agent (`--agent`, `--compact`) |
|
|
81
81
|
| `ov spec write <task-id>` | Write a task specification (`--body`) |
|
|
@@ -250,12 +250,13 @@ overstory/
|
|
|
250
250
|
mail/ SQLite mail system (typed protocol, broadcast)
|
|
251
251
|
merge/ FIFO queue + conflict resolution
|
|
252
252
|
watchdog/ Tiered health monitoring (daemon, triage, health)
|
|
253
|
-
logging/ Multi-format logger + sanitizer + reporter + color control
|
|
253
|
+
logging/ Multi-format logger + sanitizer + reporter + color control + shared theme/format
|
|
254
254
|
metrics/ SQLite metrics + transcript parsing
|
|
255
255
|
doctor/ Health check modules (10 checks)
|
|
256
256
|
insights/ Session insight analyzer for auto-expertise
|
|
257
|
+
runtimes/ AgentRuntime abstraction (registry + adapters)
|
|
257
258
|
tracker/ Pluggable task tracker (beads + seeds backends)
|
|
258
|
-
mulch/ mulch CLI wrapper
|
|
259
|
+
mulch/ mulch client (programmatic API + CLI wrapper)
|
|
259
260
|
e2e/ End-to-end lifecycle tests
|
|
260
261
|
agents/ Base agent definitions (.md, 8 roles) + skill definitions
|
|
261
262
|
templates/ Templates for overlays and hooks
|
|
@@ -265,12 +266,9 @@ overstory/
|
|
|
265
266
|
|
|
266
267
|
Overstory is part of the [os-eco](https://github.com/jayminwest/os-eco) AI agent tooling ecosystem.
|
|
267
268
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ seeds issues
|
|
272
|
-
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ mulch expertise
|
|
273
|
-
```
|
|
269
|
+
<p align="center">
|
|
270
|
+
<img src="https://raw.githubusercontent.com/jayminwest/os-eco/main/branding/logo.png" alt="os-eco" width="444" />
|
|
271
|
+
</p>
|
|
274
272
|
|
|
275
273
|
## Contributing
|
|
276
274
|
|
package/agents/lead.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## propulsion-principle
|
|
2
2
|
|
|
3
|
-
Read your assignment. Assess complexity. For simple tasks, start implementing immediately. For moderate tasks, write a spec and spawn a builder. For complex tasks, spawn scouts and create issues. Do not ask for confirmation, do not propose a plan and wait for approval. Start working within your first tool calls.
|
|
3
|
+
Read your assignment. Assess complexity. For simple tasks, start implementing immediately. For moderate tasks, write a spec and spawn a builder. For complex tasks, spawn scouts and mail the coordinator to create issues. Do not ask for confirmation, do not propose a plan and wait for approval. Start working within your first tool calls.
|
|
4
4
|
|
|
5
5
|
## dispatch-overrides
|
|
6
6
|
|
|
@@ -39,6 +39,7 @@ These are named failures. If you catch yourself doing any of these, stop and cor
|
|
|
39
39
|
- **INCOMPLETE_CLOSE** -- Running `{{TRACKER_CLI}} close` before all subtasks are complete or accounted for, or without sending `merge_ready` to the coordinator.
|
|
40
40
|
- **REVIEW_SKIP** -- Sending `merge_ready` for complex tasks without independent review. For complex multi-file changes, always spawn a reviewer. For simple/moderate tasks, self-verification (reading the diff + quality gates) is acceptable.
|
|
41
41
|
- **MISSING_MULCH_RECORD** -- Closing without recording mulch learnings. Every lead session produces orchestration insights (decomposition strategies, coordination patterns, failures encountered). Skipping `ml record` loses knowledge for future agents.
|
|
42
|
+
- **WORKTREE_ISSUE_CREATE** -- Running `{{TRACKER_CLI}} create` in a worktree. Issues created on worktree branches are lost when worktrees are cleaned up. Mail the coordinator to create issues on main instead.
|
|
42
43
|
|
|
43
44
|
## overlay
|
|
44
45
|
|
|
@@ -55,6 +56,7 @@ Your task-specific context (task ID, spec path, hierarchy depth, agent name, whe
|
|
|
55
56
|
- **Never push to the canonical branch.** Commit to your worktree branch. Merging is handled by the coordinator.
|
|
56
57
|
- **Do not spawn more workers than needed.** Start with the minimum. You can always spawn more later. Target 2-5 builders per lead.
|
|
57
58
|
- **Review before merge for complex tasks.** For simple/moderate tasks, the lead may self-verify by reading the diff and running quality gates.
|
|
59
|
+
- **Never create issues in worktrees.** Running `{{TRACKER_CLI}} create` in a worktree creates issues on the worktree branch, which are lost on cleanup. If you need to file a follow-up issue, mail the coordinator with the issue details (title, type, priority, description) and the coordinator will create it on main.
|
|
58
60
|
|
|
59
61
|
## communication-protocol
|
|
60
62
|
|
|
@@ -62,6 +64,9 @@ Your task-specific context (task ID, spec path, hierarchy depth, agent name, whe
|
|
|
62
64
|
- **To your workers:** Send `status` messages with clarifications or answers to their questions.
|
|
63
65
|
- **Monitoring cadence:** Check mail and `ov status` regularly, especially after spawning workers.
|
|
64
66
|
- When escalating to the coordinator, include: what failed, what you tried, what you need.
|
|
67
|
+
- **Requesting issue creation:** When you discover follow-up work that needs tracking, mail the coordinator:
|
|
68
|
+
`ov mail send --to coordinator --subject "create-issue: <title>" --body "type: <task|bug>, priority: <1-4>, description: <details>" --type status`
|
|
69
|
+
The coordinator will create the issue on main and may reply with the issue ID.
|
|
65
70
|
|
|
66
71
|
## intro
|
|
67
72
|
|
|
@@ -84,7 +89,7 @@ You are primarily a coordinator, but you can also be a doer for simple tasks. Yo
|
|
|
84
89
|
- **Bash:**
|
|
85
90
|
- `git add`, `git commit`, `git diff`, `git log`, `git status`
|
|
86
91
|
{{QUALITY_GATE_CAPABILITIES}}
|
|
87
|
-
- `{{TRACKER_CLI}}
|
|
92
|
+
- `{{TRACKER_CLI}} show`, `{{TRACKER_CLI}} ready`, `{{TRACKER_CLI}} close`, `{{TRACKER_CLI}} update` ({{TRACKER_NAME}} management — read, update, close)
|
|
88
93
|
- `{{TRACKER_CLI}} sync` (sync {{TRACKER_NAME}} with git)
|
|
89
94
|
- `ml prime`, `ml record`, `ml query`, `ml search` (expertise)
|
|
90
95
|
- `ov sling` (spawn sub-workers)
|
|
@@ -164,8 +169,8 @@ Delegate exploration to scouts so you can focus on decomposition and planning.
|
|
|
164
169
|
|
|
165
170
|
Single scout example:
|
|
166
171
|
```bash
|
|
167
|
-
|
|
168
|
-
|
|
172
|
+
ov sling <parent-task-id> --capability scout --name <scout-name> \
|
|
173
|
+
--skip-task-check \
|
|
169
174
|
--parent $OVERSTORY_AGENT_NAME --depth <current+1>
|
|
170
175
|
ov mail send --to <scout-name> --subject "Explore: <area>" \
|
|
171
176
|
--body "Investigate <what to explore>. Report: file layout, existing patterns, types, dependencies." \
|
|
@@ -175,16 +180,16 @@ Delegate exploration to scouts so you can focus on decomposition and planning.
|
|
|
175
180
|
Parallel scouts example:
|
|
176
181
|
```bash
|
|
177
182
|
# Scout 1: implementation files
|
|
178
|
-
|
|
179
|
-
|
|
183
|
+
ov sling <parent-task-id> --capability scout --name <scout1-name> \
|
|
184
|
+
--skip-task-check \
|
|
180
185
|
--parent $OVERSTORY_AGENT_NAME --depth <current+1>
|
|
181
186
|
ov mail send --to <scout1-name> --subject "Explore: implementation" \
|
|
182
187
|
--body "Investigate implementation files: <files>. Report: patterns, types, dependencies." \
|
|
183
188
|
--type dispatch
|
|
184
189
|
|
|
185
190
|
# Scout 2: tests and interfaces
|
|
186
|
-
|
|
187
|
-
|
|
191
|
+
ov sling <parent-task-id> --capability scout --name <scout2-name> \
|
|
192
|
+
--skip-task-check \
|
|
188
193
|
--parent $OVERSTORY_AGENT_NAME --depth <current+1>
|
|
189
194
|
ov mail send --to <scout2-name> --subject "Explore: tests and interfaces" \
|
|
190
195
|
--body "Investigate test files and type definitions: <files>. Report: test patterns, type contracts." \
|
|
@@ -204,17 +209,14 @@ Write specs from scout findings and dispatch builders.
|
|
|
204
209
|
- File scope (which files the builder owns -- non-overlapping)
|
|
205
210
|
- Context (relevant types, interfaces, existing patterns from scout findings)
|
|
206
211
|
- Dependencies (what must be true before this work starts)
|
|
207
|
-
7. **
|
|
212
|
+
7. **Spawn builders** for parallel tasks:
|
|
208
213
|
```bash
|
|
209
|
-
|
|
210
|
-
```
|
|
211
|
-
8. **Spawn builders** for parallel tasks:
|
|
212
|
-
```bash
|
|
213
|
-
ov sling <bead-id> --capability builder --name <builder-name> \
|
|
214
|
+
ov sling <parent-task-id> --capability builder --name <builder-name> \
|
|
214
215
|
--spec .overstory/specs/<bead-id>.md --files <scoped-files> \
|
|
216
|
+
--skip-task-check \
|
|
215
217
|
--parent $OVERSTORY_AGENT_NAME --depth <current+1>
|
|
216
218
|
```
|
|
217
|
-
|
|
219
|
+
8. **Send dispatch mail** to each builder:
|
|
218
220
|
```bash
|
|
219
221
|
ov mail send --to <builder-name> --subject "Build: <task>" \
|
|
220
222
|
--body "Spec: .overstory/specs/<bead-id>.md. Begin immediately." --type dispatch
|
|
@@ -248,10 +250,9 @@ Review is a quality investment. For complex, multi-file changes, spawn a reviewe
|
|
|
248
250
|
|
|
249
251
|
To spawn a reviewer:
|
|
250
252
|
```bash
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
--
|
|
254
|
-
--depth <current+1>
|
|
253
|
+
ov sling <parent-task-id> --capability reviewer --name review-<builder-name> \
|
|
254
|
+
--spec .overstory/specs/<builder-bead-id>.md --skip-task-check \
|
|
255
|
+
--parent $OVERSTORY_AGENT_NAME --depth <current+1>
|
|
255
256
|
ov mail send --to review-<builder-name> \
|
|
256
257
|
--subject "Review: <builder-task>" \
|
|
257
258
|
--body "Review the changes on branch <builder-branch>. Spec: .overstory/specs/<builder-bead-id>.md. Run quality gates and report PASS or FAIL." \
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@os-eco/overstory-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Multi-agent orchestration for Claude Code — spawn worker agents in git worktrees via tmux, coordinate through SQLite mail, merge with tiered conflict resolution",
|
|
5
5
|
"author": "Jaymin West",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,12 +44,14 @@
|
|
|
44
44
|
"version:bump": "bun scripts/version-bump.ts"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
+
"@os-eco/mulch-cli": "^0.6.2",
|
|
47
48
|
"chalk": "^5.6.2",
|
|
48
49
|
"commander": "^14.0.3"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
52
|
+
"@biomejs/biome": "^2.3.15",
|
|
51
53
|
"@types/bun": "latest",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
+
"@types/js-yaml": "^4.0.9",
|
|
55
|
+
"typescript": "^5.9.0"
|
|
54
56
|
}
|
|
55
57
|
}
|
|
@@ -736,6 +736,29 @@ describe("writeOverlay", () => {
|
|
|
736
736
|
const exists = await Bun.file(outputPath).exists();
|
|
737
737
|
expect(exists).toBe(true);
|
|
738
738
|
});
|
|
739
|
+
|
|
740
|
+
test("writes to custom instruction path when provided", async () => {
|
|
741
|
+
const worktreePath = join(tempDir, "worktree");
|
|
742
|
+
const config = makeConfig();
|
|
743
|
+
await writeOverlay(worktreePath, config, "/nonexistent-canonical-root", "AGENTS.md");
|
|
744
|
+
const outputPath = join(worktreePath, "AGENTS.md");
|
|
745
|
+
expect(await Bun.file(outputPath).exists()).toBe(true);
|
|
746
|
+
expect(await Bun.file(join(worktreePath, ".claude", "CLAUDE.md")).exists()).toBe(false);
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
test("custom instruction path creates necessary subdirectories", async () => {
|
|
750
|
+
const worktreePath = join(tempDir, "worktree");
|
|
751
|
+
const config = makeConfig();
|
|
752
|
+
await writeOverlay(
|
|
753
|
+
worktreePath,
|
|
754
|
+
config,
|
|
755
|
+
"/nonexistent-canonical-root",
|
|
756
|
+
".pi/instructions/AGENT.md",
|
|
757
|
+
);
|
|
758
|
+
expect(await Bun.file(join(worktreePath, ".pi", "instructions", "AGENT.md")).exists()).toBe(
|
|
759
|
+
true,
|
|
760
|
+
);
|
|
761
|
+
});
|
|
739
762
|
});
|
|
740
763
|
|
|
741
764
|
describe("isCanonicalRoot", () => {
|
package/src/agents/overlay.ts
CHANGED
|
@@ -369,6 +369,7 @@ export async function writeOverlay(
|
|
|
369
369
|
worktreePath: string,
|
|
370
370
|
config: OverlayConfig,
|
|
371
371
|
canonicalRoot: string,
|
|
372
|
+
instructionPath = ".claude/CLAUDE.md",
|
|
372
373
|
): Promise<void> {
|
|
373
374
|
// Guard: never write agent overlays to the canonical project root.
|
|
374
375
|
// The project root's .claude/CLAUDE.md belongs to the orchestrator/user.
|
|
@@ -383,13 +384,13 @@ export async function writeOverlay(
|
|
|
383
384
|
}
|
|
384
385
|
|
|
385
386
|
const content = await generateOverlay(config);
|
|
386
|
-
const
|
|
387
|
-
const
|
|
387
|
+
const outputPath = join(worktreePath, instructionPath);
|
|
388
|
+
const outputDir = dirname(outputPath);
|
|
388
389
|
|
|
389
390
|
try {
|
|
390
|
-
await mkdir(
|
|
391
|
+
await mkdir(outputDir, { recursive: true });
|
|
391
392
|
} catch (err) {
|
|
392
|
-
throw new AgentError(`Failed to create
|
|
393
|
+
throw new AgentError(`Failed to create directory for instruction file at: ${outputDir}`, {
|
|
393
394
|
agentName: config.agentName,
|
|
394
395
|
cause: err instanceof Error ? err : undefined,
|
|
395
396
|
});
|
|
@@ -22,6 +22,7 @@ import { loadConfig } from "../config.ts";
|
|
|
22
22
|
import { AgentError, ValidationError } from "../errors.ts";
|
|
23
23
|
import { jsonOutput } from "../json.ts";
|
|
24
24
|
import { printHint, printSuccess, printWarning } from "../logging/color.ts";
|
|
25
|
+
import { getRuntime } from "../runtimes/registry.ts";
|
|
25
26
|
import { openSessionStore } from "../sessions/compat.ts";
|
|
26
27
|
import { createRunStore } from "../sessions/store.ts";
|
|
27
28
|
import { resolveBackend, trackerCliName } from "../tracker/factory.ts";
|
|
@@ -62,6 +63,7 @@ export interface CoordinatorDeps {
|
|
|
62
63
|
sendKeys: (name: string, keys: string) => Promise<void>;
|
|
63
64
|
waitForTuiReady: (
|
|
64
65
|
name: string,
|
|
66
|
+
detectReady: (paneContent: string) => import("../runtimes/types.ts").ReadyState,
|
|
65
67
|
timeoutMs?: number,
|
|
66
68
|
pollIntervalMs?: number,
|
|
67
69
|
) => Promise<boolean>;
|
|
@@ -347,7 +349,8 @@ async function startCoordinator(
|
|
|
347
349
|
join(projectRoot, config.agents.baseDir),
|
|
348
350
|
);
|
|
349
351
|
const manifest = await manifestLoader.load();
|
|
350
|
-
const
|
|
352
|
+
const resolvedModel = resolveModel(config, manifest, "coordinator", "opus");
|
|
353
|
+
const runtime = getRuntime(undefined, config);
|
|
351
354
|
|
|
352
355
|
// Preflight: verify tmux is installed before attempting to spawn.
|
|
353
356
|
// Without this check, a missing tmux leads to cryptic errors later.
|
|
@@ -359,15 +362,22 @@ async function startCoordinator(
|
|
|
359
362
|
// (overstory-gaio, overstory-0kwf).
|
|
360
363
|
const agentDefPath = join(projectRoot, ".overstory", "agent-defs", "coordinator.md");
|
|
361
364
|
const agentDefFile = Bun.file(agentDefPath);
|
|
362
|
-
let
|
|
365
|
+
let appendSystemPrompt: string | undefined;
|
|
363
366
|
if (await agentDefFile.exists()) {
|
|
364
|
-
|
|
365
|
-
// Single-quote the content for safe shell expansion (only escape single quotes)
|
|
366
|
-
const escaped = agentDef.replace(/'/g, "'\\''");
|
|
367
|
-
claudeCmd += ` --append-system-prompt '${escaped}'`;
|
|
367
|
+
appendSystemPrompt = await agentDefFile.text();
|
|
368
368
|
}
|
|
369
|
-
const
|
|
370
|
-
|
|
369
|
+
const spawnCmd = runtime.buildSpawnCommand({
|
|
370
|
+
model: resolvedModel.model,
|
|
371
|
+
permissionMode: "bypass",
|
|
372
|
+
cwd: projectRoot,
|
|
373
|
+
appendSystemPrompt,
|
|
374
|
+
env: {
|
|
375
|
+
...runtime.buildEnv(resolvedModel),
|
|
376
|
+
OVERSTORY_AGENT_NAME: COORDINATOR_NAME,
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
const pid = await tmux.createSession(tmuxSession, projectRoot, spawnCmd, {
|
|
380
|
+
...runtime.buildEnv(resolvedModel),
|
|
371
381
|
OVERSTORY_AGENT_NAME: COORDINATOR_NAME,
|
|
372
382
|
});
|
|
373
383
|
|
|
@@ -397,7 +407,9 @@ async function startCoordinator(
|
|
|
397
407
|
store.upsert(session);
|
|
398
408
|
|
|
399
409
|
// Wait for Claude Code TUI to render before sending input
|
|
400
|
-
const tuiReady = await tmux.waitForTuiReady(tmuxSession)
|
|
410
|
+
const tuiReady = await tmux.waitForTuiReady(tmuxSession, (content) =>
|
|
411
|
+
runtime.detectReady(content),
|
|
412
|
+
);
|
|
401
413
|
if (!tuiReady) {
|
|
402
414
|
// Session may have died — check liveness before proceeding
|
|
403
415
|
const alive = await tmux.isSessionAlive(tmuxSession);
|
package/src/commands/costs.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { loadConfig } from "../config.ts";
|
|
|
13
13
|
import { ValidationError } from "../errors.ts";
|
|
14
14
|
import { jsonError, jsonOutput } from "../json.ts";
|
|
15
15
|
import { color } from "../logging/color.ts";
|
|
16
|
+
import { renderHeader, separator } from "../logging/theme.ts";
|
|
16
17
|
import { createMetricsStore } from "../metrics/store.ts";
|
|
17
18
|
import { estimateCost, parseTranscriptUsage } from "../metrics/transcript.ts";
|
|
18
19
|
import { openSessionStore } from "../sessions/compat.ts";
|
|
@@ -141,10 +142,8 @@ function groupByCapability(sessions: SessionMetrics[]): CapabilityGroup[] {
|
|
|
141
142
|
/** Print the standard per-agent cost summary table. */
|
|
142
143
|
function printCostSummary(sessions: SessionMetrics[]): void {
|
|
143
144
|
const w = process.stdout.write.bind(process.stdout);
|
|
144
|
-
const separator = "\u2500".repeat(70);
|
|
145
145
|
|
|
146
|
-
w(`${
|
|
147
|
-
w(`${"=".repeat(70)}\n`);
|
|
146
|
+
w(`${renderHeader("Cost Summary")}\n`);
|
|
148
147
|
|
|
149
148
|
if (sessions.length === 0) {
|
|
150
149
|
w(`${color.dim("No session data found.")}\n`);
|
|
@@ -156,7 +155,7 @@ function printCostSummary(sessions: SessionMetrics[]): void {
|
|
|
156
155
|
`${padLeft("Input", 10)}${padLeft("Output", 10)}` +
|
|
157
156
|
`${padLeft("Cache", 10)}${padLeft("Cost", 10)}\n`,
|
|
158
157
|
);
|
|
159
|
-
w(`${color.dim(separator)}\n`);
|
|
158
|
+
w(`${color.dim(separator())}\n`);
|
|
160
159
|
|
|
161
160
|
for (const s of sessions) {
|
|
162
161
|
const cacheTotal = s.cacheReadTokens + s.cacheCreationTokens;
|
|
@@ -170,7 +169,7 @@ function printCostSummary(sessions: SessionMetrics[]): void {
|
|
|
170
169
|
}
|
|
171
170
|
|
|
172
171
|
const totals = computeTotals(sessions);
|
|
173
|
-
w(`${color.dim(separator)}\n`);
|
|
172
|
+
w(`${color.dim(separator())}\n`);
|
|
174
173
|
w(
|
|
175
174
|
`${color.green(
|
|
176
175
|
color.bold(
|
|
@@ -187,10 +186,8 @@ function printCostSummary(sessions: SessionMetrics[]): void {
|
|
|
187
186
|
/** Print the capability-grouped cost table. */
|
|
188
187
|
function printByCapability(sessions: SessionMetrics[]): void {
|
|
189
188
|
const w = process.stdout.write.bind(process.stdout);
|
|
190
|
-
const separator = "\u2500".repeat(70);
|
|
191
189
|
|
|
192
|
-
w(`${
|
|
193
|
-
w(`${"=".repeat(70)}\n`);
|
|
190
|
+
w(`${renderHeader("Cost by Capability")}\n`);
|
|
194
191
|
|
|
195
192
|
if (sessions.length === 0) {
|
|
196
193
|
w(`${color.dim("No session data found.")}\n`);
|
|
@@ -202,7 +199,7 @@ function printByCapability(sessions: SessionMetrics[]): void {
|
|
|
202
199
|
`${padLeft("Input", 10)}${padLeft("Output", 10)}` +
|
|
203
200
|
`${padLeft("Cache", 10)}${padLeft("Cost", 10)}\n`,
|
|
204
201
|
);
|
|
205
|
-
w(`${color.dim(separator)}\n`);
|
|
202
|
+
w(`${color.dim(separator())}\n`);
|
|
206
203
|
|
|
207
204
|
const groups = groupByCapability(sessions);
|
|
208
205
|
|
|
@@ -218,7 +215,7 @@ function printByCapability(sessions: SessionMetrics[]): void {
|
|
|
218
215
|
}
|
|
219
216
|
|
|
220
217
|
const totals = computeTotals(sessions);
|
|
221
|
-
w(`${color.dim(separator)}\n`);
|
|
218
|
+
w(`${color.dim(separator())}\n`);
|
|
222
219
|
w(
|
|
223
220
|
`${color.green(
|
|
224
221
|
color.bold(
|
|
@@ -299,17 +296,15 @@ async function executeCosts(opts: CostsOpts): Promise<void> {
|
|
|
299
296
|
});
|
|
300
297
|
} else {
|
|
301
298
|
const w = process.stdout.write.bind(process.stdout);
|
|
302
|
-
const separator = "\u2500".repeat(70);
|
|
303
299
|
|
|
304
|
-
w(`${
|
|
305
|
-
w(`${"=".repeat(70)}\n`);
|
|
300
|
+
w(`${renderHeader("Orchestrator Session Cost")}\n`);
|
|
306
301
|
w(`${padRight("Model:", 12)}${usage.modelUsed ?? "unknown"}\n`);
|
|
307
302
|
w(`${padRight("Transcript:", 12)}${transcriptPath}\n`);
|
|
308
|
-
w(`${color.dim(separator)}\n`);
|
|
303
|
+
w(`${color.dim(separator())}\n`);
|
|
309
304
|
w(`${padRight("Input tokens:", 22)}${padLeft(formatNumber(usage.inputTokens), 12)}\n`);
|
|
310
305
|
w(`${padRight("Output tokens:", 22)}${padLeft(formatNumber(usage.outputTokens), 12)}\n`);
|
|
311
306
|
w(`${padRight("Cache tokens:", 22)}${padLeft(formatNumber(cacheTotal), 12)}\n`);
|
|
312
|
-
w(`${color.dim(separator)}\n`);
|
|
307
|
+
w(`${color.dim(separator())}\n`);
|
|
313
308
|
w(
|
|
314
309
|
`${color.green(color.bold(padRight("Estimated cost:", 22) + padLeft(formatCost(cost), 12)))}\n`,
|
|
315
310
|
);
|
|
@@ -453,16 +448,14 @@ async function executeCosts(opts: CostsOpts): Promise<void> {
|
|
|
453
448
|
});
|
|
454
449
|
} else {
|
|
455
450
|
const w = process.stdout.write.bind(process.stdout);
|
|
456
|
-
const separator = "\u2500".repeat(70);
|
|
457
451
|
|
|
458
|
-
w(`${
|
|
459
|
-
w(`${"=".repeat(70)}\n`);
|
|
452
|
+
w(`${renderHeader(`Live Token Usage (${agentData.length} active agents)`)}\n`);
|
|
460
453
|
w(
|
|
461
454
|
`${padRight("Agent", 19)}${padRight("Capability", 12)}` +
|
|
462
455
|
`${padLeft("Input", 10)}${padLeft("Output", 10)}` +
|
|
463
456
|
`${padLeft("Cache", 10)}${padLeft("Cost", 10)}\n`,
|
|
464
457
|
);
|
|
465
|
-
w(`${color.dim(separator)}\n`);
|
|
458
|
+
w(`${color.dim(separator())}\n`);
|
|
466
459
|
|
|
467
460
|
for (const agent of agentData) {
|
|
468
461
|
const cacheTotal = agent.cacheReadTokens + agent.cacheCreationTokens;
|
|
@@ -475,7 +468,7 @@ async function executeCosts(opts: CostsOpts): Promise<void> {
|
|
|
475
468
|
);
|
|
476
469
|
}
|
|
477
470
|
|
|
478
|
-
w(`${color.dim(separator)}\n`);
|
|
471
|
+
w(`${color.dim(separator())}\n`);
|
|
479
472
|
w(
|
|
480
473
|
`${color.green(
|
|
481
474
|
color.bold(
|