@os-eco/overstory-cli 0.6.1
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/LICENSE +21 -0
- package/README.md +381 -0
- package/agents/builder.md +137 -0
- package/agents/coordinator.md +263 -0
- package/agents/lead.md +301 -0
- package/agents/merger.md +160 -0
- package/agents/monitor.md +214 -0
- package/agents/reviewer.md +140 -0
- package/agents/scout.md +119 -0
- package/agents/supervisor.md +423 -0
- package/package.json +47 -0
- package/src/agents/checkpoint.test.ts +88 -0
- package/src/agents/checkpoint.ts +101 -0
- package/src/agents/hooks-deployer.test.ts +2040 -0
- package/src/agents/hooks-deployer.ts +607 -0
- package/src/agents/identity.test.ts +603 -0
- package/src/agents/identity.ts +384 -0
- package/src/agents/lifecycle.test.ts +196 -0
- package/src/agents/lifecycle.ts +183 -0
- package/src/agents/manifest.test.ts +746 -0
- package/src/agents/manifest.ts +354 -0
- package/src/agents/overlay.test.ts +676 -0
- package/src/agents/overlay.ts +308 -0
- package/src/beads/client.test.ts +217 -0
- package/src/beads/client.ts +202 -0
- package/src/beads/molecules.test.ts +338 -0
- package/src/beads/molecules.ts +198 -0
- package/src/commands/agents.test.ts +322 -0
- package/src/commands/agents.ts +287 -0
- package/src/commands/clean.test.ts +670 -0
- package/src/commands/clean.ts +618 -0
- package/src/commands/completions.test.ts +342 -0
- package/src/commands/completions.ts +887 -0
- package/src/commands/coordinator.test.ts +1530 -0
- package/src/commands/coordinator.ts +733 -0
- package/src/commands/costs.test.ts +1119 -0
- package/src/commands/costs.ts +564 -0
- package/src/commands/dashboard.test.ts +308 -0
- package/src/commands/dashboard.ts +838 -0
- package/src/commands/doctor.test.ts +294 -0
- package/src/commands/doctor.ts +213 -0
- package/src/commands/errors.test.ts +647 -0
- package/src/commands/errors.ts +248 -0
- package/src/commands/feed.test.ts +578 -0
- package/src/commands/feed.ts +361 -0
- package/src/commands/group.test.ts +262 -0
- package/src/commands/group.ts +511 -0
- package/src/commands/hooks.test.ts +458 -0
- package/src/commands/hooks.ts +253 -0
- package/src/commands/init.test.ts +347 -0
- package/src/commands/init.ts +650 -0
- package/src/commands/inspect.test.ts +670 -0
- package/src/commands/inspect.ts +431 -0
- package/src/commands/log.test.ts +1454 -0
- package/src/commands/log.ts +724 -0
- package/src/commands/logs.test.ts +379 -0
- package/src/commands/logs.ts +546 -0
- package/src/commands/mail.test.ts +1270 -0
- package/src/commands/mail.ts +771 -0
- package/src/commands/merge.test.ts +670 -0
- package/src/commands/merge.ts +355 -0
- package/src/commands/metrics.test.ts +444 -0
- package/src/commands/metrics.ts +143 -0
- package/src/commands/monitor.test.ts +191 -0
- package/src/commands/monitor.ts +390 -0
- package/src/commands/nudge.test.ts +230 -0
- package/src/commands/nudge.ts +372 -0
- package/src/commands/prime.test.ts +470 -0
- package/src/commands/prime.ts +381 -0
- package/src/commands/replay.test.ts +741 -0
- package/src/commands/replay.ts +360 -0
- package/src/commands/run.test.ts +431 -0
- package/src/commands/run.ts +351 -0
- package/src/commands/sling.test.ts +657 -0
- package/src/commands/sling.ts +661 -0
- package/src/commands/spec.test.ts +203 -0
- package/src/commands/spec.ts +168 -0
- package/src/commands/status.test.ts +430 -0
- package/src/commands/status.ts +398 -0
- package/src/commands/stop.test.ts +420 -0
- package/src/commands/stop.ts +151 -0
- package/src/commands/supervisor.test.ts +187 -0
- package/src/commands/supervisor.ts +535 -0
- package/src/commands/trace.test.ts +745 -0
- package/src/commands/trace.ts +325 -0
- package/src/commands/watch.test.ts +145 -0
- package/src/commands/watch.ts +247 -0
- package/src/commands/worktree.test.ts +786 -0
- package/src/commands/worktree.ts +311 -0
- package/src/config.test.ts +822 -0
- package/src/config.ts +829 -0
- package/src/doctor/agents.test.ts +454 -0
- package/src/doctor/agents.ts +396 -0
- package/src/doctor/config-check.test.ts +190 -0
- package/src/doctor/config-check.ts +183 -0
- package/src/doctor/consistency.test.ts +651 -0
- package/src/doctor/consistency.ts +294 -0
- package/src/doctor/databases.test.ts +290 -0
- package/src/doctor/databases.ts +218 -0
- package/src/doctor/dependencies.test.ts +184 -0
- package/src/doctor/dependencies.ts +175 -0
- package/src/doctor/logs.test.ts +251 -0
- package/src/doctor/logs.ts +295 -0
- package/src/doctor/merge-queue.test.ts +216 -0
- package/src/doctor/merge-queue.ts +144 -0
- package/src/doctor/structure.test.ts +291 -0
- package/src/doctor/structure.ts +198 -0
- package/src/doctor/types.ts +37 -0
- package/src/doctor/version.test.ts +136 -0
- package/src/doctor/version.ts +129 -0
- package/src/e2e/init-sling-lifecycle.test.ts +277 -0
- package/src/errors.ts +217 -0
- package/src/events/store.test.ts +660 -0
- package/src/events/store.ts +369 -0
- package/src/events/tool-filter.test.ts +330 -0
- package/src/events/tool-filter.ts +126 -0
- package/src/index.ts +316 -0
- package/src/insights/analyzer.test.ts +466 -0
- package/src/insights/analyzer.ts +203 -0
- package/src/logging/color.test.ts +142 -0
- package/src/logging/color.ts +71 -0
- package/src/logging/logger.test.ts +813 -0
- package/src/logging/logger.ts +266 -0
- package/src/logging/reporter.test.ts +259 -0
- package/src/logging/reporter.ts +109 -0
- package/src/logging/sanitizer.test.ts +190 -0
- package/src/logging/sanitizer.ts +57 -0
- package/src/mail/broadcast.test.ts +203 -0
- package/src/mail/broadcast.ts +92 -0
- package/src/mail/client.test.ts +773 -0
- package/src/mail/client.ts +223 -0
- package/src/mail/store.test.ts +705 -0
- package/src/mail/store.ts +387 -0
- package/src/merge/queue.test.ts +359 -0
- package/src/merge/queue.ts +231 -0
- package/src/merge/resolver.test.ts +1345 -0
- package/src/merge/resolver.ts +645 -0
- package/src/metrics/store.test.ts +667 -0
- package/src/metrics/store.ts +445 -0
- package/src/metrics/summary.test.ts +398 -0
- package/src/metrics/summary.ts +178 -0
- package/src/metrics/transcript.test.ts +356 -0
- package/src/metrics/transcript.ts +175 -0
- package/src/mulch/client.test.ts +671 -0
- package/src/mulch/client.ts +332 -0
- package/src/sessions/compat.test.ts +280 -0
- package/src/sessions/compat.ts +104 -0
- package/src/sessions/store.test.ts +873 -0
- package/src/sessions/store.ts +494 -0
- package/src/test-helpers.test.ts +124 -0
- package/src/test-helpers.ts +126 -0
- package/src/tracker/beads.ts +56 -0
- package/src/tracker/factory.test.ts +80 -0
- package/src/tracker/factory.ts +64 -0
- package/src/tracker/seeds.ts +182 -0
- package/src/tracker/types.ts +52 -0
- package/src/types.ts +724 -0
- package/src/watchdog/daemon.test.ts +1975 -0
- package/src/watchdog/daemon.ts +671 -0
- package/src/watchdog/health.test.ts +431 -0
- package/src/watchdog/health.ts +264 -0
- package/src/watchdog/triage.test.ts +164 -0
- package/src/watchdog/triage.ts +179 -0
- package/src/worktree/manager.test.ts +439 -0
- package/src/worktree/manager.ts +198 -0
- package/src/worktree/tmux.test.ts +1009 -0
- package/src/worktree/tmux.ts +509 -0
- package/templates/CLAUDE.md.tmpl +89 -0
- package/templates/hooks.json.tmpl +105 -0
- package/templates/overlay.md.tmpl +81 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart tool argument filter for observability events.
|
|
3
|
+
*
|
|
4
|
+
* Reduces tool invocation payloads from ~20KB to ~200 bytes by keeping only
|
|
5
|
+
* the fields useful for post-mortem analysis. Each tool type has a custom
|
|
6
|
+
* filter that preserves identifying information while dropping bulky content.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface FilteredToolArgs {
|
|
10
|
+
args: Record<string, unknown>;
|
|
11
|
+
summary: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Filter tool arguments down to what matters for observability.
|
|
16
|
+
*
|
|
17
|
+
* Keeps identifying fields (paths, patterns, commands) and drops bulk content
|
|
18
|
+
* (file bodies, old/new strings, timeouts). Returns a compact summary string
|
|
19
|
+
* suitable for log lines.
|
|
20
|
+
*/
|
|
21
|
+
export function filterToolArgs(
|
|
22
|
+
toolName: string,
|
|
23
|
+
toolInput: Record<string, unknown>,
|
|
24
|
+
): FilteredToolArgs {
|
|
25
|
+
const handler = TOOL_FILTERS[toolName];
|
|
26
|
+
if (handler) {
|
|
27
|
+
return handler(toolInput);
|
|
28
|
+
}
|
|
29
|
+
return { args: {}, summary: toolName };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type ToolFilter = (input: Record<string, unknown>) => FilteredToolArgs;
|
|
33
|
+
|
|
34
|
+
function pickDefined(input: Record<string, unknown>, keys: string[]): Record<string, unknown> {
|
|
35
|
+
const result: Record<string, unknown> = {};
|
|
36
|
+
for (const key of keys) {
|
|
37
|
+
if (key in input && input[key] !== undefined) {
|
|
38
|
+
result[key] = input[key];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function truncate(value: unknown, maxLen: number): string {
|
|
45
|
+
const str = typeof value === "string" ? value : String(value ?? "");
|
|
46
|
+
if (str.length <= maxLen) {
|
|
47
|
+
return str;
|
|
48
|
+
}
|
|
49
|
+
return `${str.slice(0, maxLen)}...`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const TOOL_FILTERS: Record<string, ToolFilter> = {
|
|
53
|
+
Bash: (input) => {
|
|
54
|
+
const args = pickDefined(input, ["command", "description"]);
|
|
55
|
+
const cmd = typeof input.command === "string" ? input.command : "";
|
|
56
|
+
return { args, summary: `bash: ${truncate(cmd, 80)}` };
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
Read: (input) => {
|
|
60
|
+
const args = pickDefined(input, ["file_path", "offset", "limit"]);
|
|
61
|
+
const filePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
62
|
+
const offset = typeof input.offset === "number" ? input.offset : undefined;
|
|
63
|
+
const limit = typeof input.limit === "number" ? input.limit : undefined;
|
|
64
|
+
let summary: string;
|
|
65
|
+
if (offset !== undefined && limit !== undefined) {
|
|
66
|
+
summary = `read: ${filePath} (lines ${offset}-${offset + limit})`;
|
|
67
|
+
} else if (offset !== undefined) {
|
|
68
|
+
summary = `read: ${filePath} (from line ${offset})`;
|
|
69
|
+
} else if (limit !== undefined) {
|
|
70
|
+
summary = `read: ${filePath} (first ${limit} lines)`;
|
|
71
|
+
} else {
|
|
72
|
+
summary = `read: ${filePath}`;
|
|
73
|
+
}
|
|
74
|
+
return { args, summary };
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
Write: (input) => {
|
|
78
|
+
const args = pickDefined(input, ["file_path"]);
|
|
79
|
+
const filePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
80
|
+
return { args, summary: `write: ${filePath}` };
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
Edit: (input) => {
|
|
84
|
+
const args = pickDefined(input, ["file_path"]);
|
|
85
|
+
const filePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
86
|
+
return { args, summary: `edit: ${filePath}` };
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
Glob: (input) => {
|
|
90
|
+
const args = pickDefined(input, ["pattern", "path"]);
|
|
91
|
+
const pattern = typeof input.pattern === "string" ? input.pattern : "";
|
|
92
|
+
const path = typeof input.path === "string" ? input.path : "";
|
|
93
|
+
const summary = path ? `glob: ${pattern} in ${path}` : `glob: ${pattern}`;
|
|
94
|
+
return { args, summary };
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
Grep: (input) => {
|
|
98
|
+
const args = pickDefined(input, ["pattern", "path", "glob", "output_mode"]);
|
|
99
|
+
const pattern = typeof input.pattern === "string" ? input.pattern : "";
|
|
100
|
+
const path = typeof input.path === "string" ? input.path : "";
|
|
101
|
+
const summary = path ? `grep: "${pattern}" in ${path}` : `grep: "${pattern}"`;
|
|
102
|
+
return { args, summary };
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
WebFetch: (input) => {
|
|
106
|
+
const args = pickDefined(input, ["url"]);
|
|
107
|
+
const url = typeof input.url === "string" ? input.url : "";
|
|
108
|
+
return { args, summary: `fetch: ${url}` };
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
WebSearch: (input) => {
|
|
112
|
+
const args = pickDefined(input, ["query"]);
|
|
113
|
+
const query = typeof input.query === "string" ? input.query : "";
|
|
114
|
+
return { args, summary: `search: ${query}` };
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
Task: (input) => {
|
|
118
|
+
const args = pickDefined(input, ["description", "subagent_type"]);
|
|
119
|
+
const description = typeof input.description === "string" ? input.description : "";
|
|
120
|
+
const subagentType = typeof input.subagent_type === "string" ? input.subagent_type : "";
|
|
121
|
+
const summary = subagentType
|
|
122
|
+
? `task: ${description} (${subagentType})`
|
|
123
|
+
: `task: ${description}`;
|
|
124
|
+
return { args, summary };
|
|
125
|
+
},
|
|
126
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Overstory CLI — main entry point and command router.
|
|
5
|
+
*
|
|
6
|
+
* Routes subcommands to their respective handlers in src/commands/.
|
|
7
|
+
* Usage: overstory <command> [args...]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { agentsCommand } from "./commands/agents.ts";
|
|
11
|
+
import { cleanCommand } from "./commands/clean.ts";
|
|
12
|
+
import { completionsCommand } from "./commands/completions.ts";
|
|
13
|
+
import { coordinatorCommand } from "./commands/coordinator.ts";
|
|
14
|
+
import { costsCommand } from "./commands/costs.ts";
|
|
15
|
+
import { dashboardCommand } from "./commands/dashboard.ts";
|
|
16
|
+
import { doctorCommand } from "./commands/doctor.ts";
|
|
17
|
+
import { errorsCommand } from "./commands/errors.ts";
|
|
18
|
+
import { feedCommand } from "./commands/feed.ts";
|
|
19
|
+
import { groupCommand } from "./commands/group.ts";
|
|
20
|
+
import { hooksCommand } from "./commands/hooks.ts";
|
|
21
|
+
import { initCommand } from "./commands/init.ts";
|
|
22
|
+
import { inspectCommand } from "./commands/inspect.ts";
|
|
23
|
+
import { logCommand } from "./commands/log.ts";
|
|
24
|
+
import { logsCommand } from "./commands/logs.ts";
|
|
25
|
+
import { mailCommand } from "./commands/mail.ts";
|
|
26
|
+
import { mergeCommand } from "./commands/merge.ts";
|
|
27
|
+
import { metricsCommand } from "./commands/metrics.ts";
|
|
28
|
+
import { monitorCommand } from "./commands/monitor.ts";
|
|
29
|
+
import { nudgeCommand } from "./commands/nudge.ts";
|
|
30
|
+
import { primeCommand } from "./commands/prime.ts";
|
|
31
|
+
import { replayCommand } from "./commands/replay.ts";
|
|
32
|
+
import { runCommand } from "./commands/run.ts";
|
|
33
|
+
import { slingCommand } from "./commands/sling.ts";
|
|
34
|
+
import { specCommand } from "./commands/spec.ts";
|
|
35
|
+
import { statusCommand } from "./commands/status.ts";
|
|
36
|
+
import { stopCommand } from "./commands/stop.ts";
|
|
37
|
+
import { supervisorCommand } from "./commands/supervisor.ts";
|
|
38
|
+
import { traceCommand } from "./commands/trace.ts";
|
|
39
|
+
import { watchCommand } from "./commands/watch.ts";
|
|
40
|
+
import { worktreeCommand } from "./commands/worktree.ts";
|
|
41
|
+
import { OverstoryError, WorktreeError } from "./errors.ts";
|
|
42
|
+
import { setQuiet } from "./logging/color.ts";
|
|
43
|
+
|
|
44
|
+
const VERSION = "0.6.1";
|
|
45
|
+
|
|
46
|
+
const HELP = `overstory v${VERSION} — Multi-agent orchestration for Claude Code
|
|
47
|
+
|
|
48
|
+
Usage: overstory <command> [args...]
|
|
49
|
+
|
|
50
|
+
Commands:
|
|
51
|
+
agents <sub> Discover and query agents (discover)
|
|
52
|
+
init Initialize .overstory/ in current project
|
|
53
|
+
sling <task-id> Spawn a worker agent
|
|
54
|
+
spec <sub> Manage task specs (write)
|
|
55
|
+
prime Load context for orchestrator/agent
|
|
56
|
+
stop <agent> Terminate a running agent
|
|
57
|
+
status Show all active agents and project state
|
|
58
|
+
dashboard Live TUI dashboard for agent monitoring
|
|
59
|
+
inspect <agent> Deep inspection of a single agent
|
|
60
|
+
coordinator <sub> Persistent coordinator agent (start/stop/status)
|
|
61
|
+
supervisor <sub> Per-project supervisor agent (start/stop/status)
|
|
62
|
+
hooks <sub> Manage orchestrator hooks (install/uninstall/status)
|
|
63
|
+
mail <sub> Mail system (send/check/list/read/reply)
|
|
64
|
+
monitor <sub> Tier 2 monitor agent (start/stop/status)
|
|
65
|
+
merge Merge agent branches into canonical
|
|
66
|
+
nudge <agent> [msg] Send a text nudge to an agent
|
|
67
|
+
group <sub> Task groups (create/status/add/remove/list)
|
|
68
|
+
clean Wipe runtime state (nuclear cleanup)
|
|
69
|
+
doctor Run health checks on overstory setup
|
|
70
|
+
worktree <sub> Manage worktrees (list/clean)
|
|
71
|
+
log <event> Log a hook event
|
|
72
|
+
logs [options] Query NDJSON logs across agents
|
|
73
|
+
watch Start watchdog daemon
|
|
74
|
+
feed [options] Unified real-time event stream across all agents
|
|
75
|
+
trace <target> Chronological event timeline for agent/bead
|
|
76
|
+
errors [options] Aggregated error view across agents
|
|
77
|
+
run [sub] Manage runs (list/show/complete)
|
|
78
|
+
replay [options] Interleaved chronological replay across agents
|
|
79
|
+
costs [options] Token/cost analysis and breakdown
|
|
80
|
+
metrics Show session metrics
|
|
81
|
+
|
|
82
|
+
Options:
|
|
83
|
+
--help, -h Show this help
|
|
84
|
+
--version, -v Show version
|
|
85
|
+
--quiet, -q Suppress non-error output
|
|
86
|
+
--completions <shell> Generate shell completions (bash, zsh, fish)
|
|
87
|
+
|
|
88
|
+
Run 'overstory <command> --help' for command-specific help.`;
|
|
89
|
+
|
|
90
|
+
const COMMANDS = [
|
|
91
|
+
"agents",
|
|
92
|
+
"init",
|
|
93
|
+
"sling",
|
|
94
|
+
"spec",
|
|
95
|
+
"prime",
|
|
96
|
+
"stop",
|
|
97
|
+
"status",
|
|
98
|
+
"dashboard",
|
|
99
|
+
"inspect",
|
|
100
|
+
"clean",
|
|
101
|
+
"doctor",
|
|
102
|
+
"coordinator",
|
|
103
|
+
"supervisor",
|
|
104
|
+
"hooks",
|
|
105
|
+
"monitor",
|
|
106
|
+
"mail",
|
|
107
|
+
"merge",
|
|
108
|
+
"nudge",
|
|
109
|
+
"group",
|
|
110
|
+
"worktree",
|
|
111
|
+
"log",
|
|
112
|
+
"logs",
|
|
113
|
+
"watch",
|
|
114
|
+
"trace",
|
|
115
|
+
"feed",
|
|
116
|
+
"errors",
|
|
117
|
+
"replay",
|
|
118
|
+
"run",
|
|
119
|
+
"costs",
|
|
120
|
+
"metrics",
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
function editDistance(a: string, b: string): number {
|
|
124
|
+
const m = a.length;
|
|
125
|
+
const n = b.length;
|
|
126
|
+
// Use a flat 1D array to avoid nested indexing warnings
|
|
127
|
+
const dp = new Array<number>((m + 1) * (n + 1)).fill(0);
|
|
128
|
+
const idx = (i: number, j: number) => i * (n + 1) + j;
|
|
129
|
+
for (let i = 0; i <= m; i++) dp[idx(i, 0)] = i;
|
|
130
|
+
for (let j = 0; j <= n; j++) dp[idx(0, j)] = j;
|
|
131
|
+
for (let i = 1; i <= m; i++) {
|
|
132
|
+
for (let j = 1; j <= n; j++) {
|
|
133
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
134
|
+
const del = (dp[idx(i - 1, j)] ?? 0) + 1;
|
|
135
|
+
const ins = (dp[idx(i, j - 1)] ?? 0) + 1;
|
|
136
|
+
const sub = (dp[idx(i - 1, j - 1)] ?? 0) + cost;
|
|
137
|
+
dp[idx(i, j)] = Math.min(del, ins, sub);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return dp[idx(m, n)] ?? 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function suggestCommand(input: string): string | undefined {
|
|
144
|
+
let bestMatch: string | undefined;
|
|
145
|
+
let bestDist = 3; // Only suggest if distance <= 2
|
|
146
|
+
for (const cmd of COMMANDS) {
|
|
147
|
+
const dist = editDistance(input, cmd);
|
|
148
|
+
if (dist < bestDist) {
|
|
149
|
+
bestDist = dist;
|
|
150
|
+
bestMatch = cmd;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return bestMatch;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function main(): Promise<void> {
|
|
157
|
+
const args = process.argv.slice(2);
|
|
158
|
+
|
|
159
|
+
// Parse global flags before command routing
|
|
160
|
+
const quietIndex = args.indexOf("--quiet");
|
|
161
|
+
const qIndex = args.indexOf("-q");
|
|
162
|
+
if (quietIndex !== -1 || qIndex !== -1) {
|
|
163
|
+
setQuiet(true);
|
|
164
|
+
// Remove the flag from args so commands do not see it
|
|
165
|
+
if (quietIndex !== -1) args.splice(quietIndex, 1);
|
|
166
|
+
if (qIndex !== -1) {
|
|
167
|
+
const idx = args.indexOf("-q");
|
|
168
|
+
if (idx !== -1) args.splice(idx, 1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const command = args[0];
|
|
173
|
+
const commandArgs = args.slice(1);
|
|
174
|
+
|
|
175
|
+
if (!command || command === "--help" || command === "-h") {
|
|
176
|
+
process.stdout.write(`${HELP}\n`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (command === "--version" || command === "-v") {
|
|
181
|
+
process.stdout.write(`overstory v${VERSION}\n`);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (command === "--completions") {
|
|
186
|
+
completionsCommand(commandArgs);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
switch (command) {
|
|
191
|
+
case "agents":
|
|
192
|
+
await agentsCommand(commandArgs);
|
|
193
|
+
break;
|
|
194
|
+
case "init":
|
|
195
|
+
await initCommand(commandArgs);
|
|
196
|
+
break;
|
|
197
|
+
case "sling":
|
|
198
|
+
await slingCommand(commandArgs);
|
|
199
|
+
break;
|
|
200
|
+
case "spec":
|
|
201
|
+
await specCommand(commandArgs);
|
|
202
|
+
break;
|
|
203
|
+
case "prime":
|
|
204
|
+
await primeCommand(commandArgs);
|
|
205
|
+
break;
|
|
206
|
+
case "stop":
|
|
207
|
+
await stopCommand(commandArgs);
|
|
208
|
+
break;
|
|
209
|
+
case "status":
|
|
210
|
+
await statusCommand(commandArgs);
|
|
211
|
+
break;
|
|
212
|
+
case "dashboard":
|
|
213
|
+
await dashboardCommand(commandArgs);
|
|
214
|
+
break;
|
|
215
|
+
case "inspect":
|
|
216
|
+
await inspectCommand(commandArgs);
|
|
217
|
+
break;
|
|
218
|
+
case "clean":
|
|
219
|
+
await cleanCommand(commandArgs);
|
|
220
|
+
break;
|
|
221
|
+
case "doctor": {
|
|
222
|
+
const exitCode = await doctorCommand(commandArgs);
|
|
223
|
+
if (exitCode !== undefined) {
|
|
224
|
+
process.exitCode = exitCode;
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
case "coordinator":
|
|
229
|
+
await coordinatorCommand(commandArgs);
|
|
230
|
+
break;
|
|
231
|
+
case "supervisor":
|
|
232
|
+
await supervisorCommand(commandArgs);
|
|
233
|
+
break;
|
|
234
|
+
case "hooks":
|
|
235
|
+
await hooksCommand(commandArgs);
|
|
236
|
+
break;
|
|
237
|
+
case "monitor":
|
|
238
|
+
await monitorCommand(commandArgs);
|
|
239
|
+
break;
|
|
240
|
+
case "mail":
|
|
241
|
+
await mailCommand(commandArgs);
|
|
242
|
+
break;
|
|
243
|
+
case "merge":
|
|
244
|
+
await mergeCommand(commandArgs);
|
|
245
|
+
break;
|
|
246
|
+
case "nudge":
|
|
247
|
+
await nudgeCommand(commandArgs);
|
|
248
|
+
break;
|
|
249
|
+
case "group":
|
|
250
|
+
await groupCommand(commandArgs);
|
|
251
|
+
break;
|
|
252
|
+
case "worktree":
|
|
253
|
+
await worktreeCommand(commandArgs);
|
|
254
|
+
break;
|
|
255
|
+
case "log":
|
|
256
|
+
await logCommand(commandArgs);
|
|
257
|
+
break;
|
|
258
|
+
case "logs":
|
|
259
|
+
await logsCommand(commandArgs);
|
|
260
|
+
break;
|
|
261
|
+
case "watch":
|
|
262
|
+
await watchCommand(commandArgs);
|
|
263
|
+
break;
|
|
264
|
+
case "trace":
|
|
265
|
+
await traceCommand(commandArgs);
|
|
266
|
+
break;
|
|
267
|
+
case "feed":
|
|
268
|
+
await feedCommand(commandArgs);
|
|
269
|
+
break;
|
|
270
|
+
case "errors":
|
|
271
|
+
await errorsCommand(commandArgs);
|
|
272
|
+
break;
|
|
273
|
+
case "replay":
|
|
274
|
+
await replayCommand(commandArgs);
|
|
275
|
+
break;
|
|
276
|
+
case "run":
|
|
277
|
+
await runCommand(commandArgs);
|
|
278
|
+
break;
|
|
279
|
+
case "costs":
|
|
280
|
+
await costsCommand(commandArgs);
|
|
281
|
+
break;
|
|
282
|
+
case "metrics":
|
|
283
|
+
await metricsCommand(commandArgs);
|
|
284
|
+
break;
|
|
285
|
+
default: {
|
|
286
|
+
process.stderr.write(`Unknown command: ${command}\n`);
|
|
287
|
+
const suggestion = suggestCommand(command);
|
|
288
|
+
if (suggestion) {
|
|
289
|
+
process.stderr.write(`Did you mean '${suggestion}'?\n`);
|
|
290
|
+
}
|
|
291
|
+
process.stderr.write(`Run 'overstory --help' for usage.\n`);
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
main().catch((err: unknown) => {
|
|
298
|
+
// Friendly message when running outside a git repository
|
|
299
|
+
if (err instanceof WorktreeError && err.message.includes("not a git repository")) {
|
|
300
|
+
process.stderr.write("Not in an overstory project. Run 'overstory init' first.\n");
|
|
301
|
+
process.exit(1);
|
|
302
|
+
}
|
|
303
|
+
if (err instanceof OverstoryError) {
|
|
304
|
+
process.stderr.write(`Error [${err.code}]: ${err.message}\n`);
|
|
305
|
+
process.exit(1);
|
|
306
|
+
}
|
|
307
|
+
if (err instanceof Error) {
|
|
308
|
+
process.stderr.write(`Error: ${err.message}\n`);
|
|
309
|
+
if (process.argv.includes("--verbose")) {
|
|
310
|
+
process.stderr.write(`${err.stack}\n`);
|
|
311
|
+
}
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
process.stderr.write(`Unknown error: ${String(err)}\n`);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
});
|