@os-eco/overstory-cli 0.6.1 → 0.6.5
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 +8 -7
- package/package.json +12 -4
- package/src/agents/checkpoint.test.ts +2 -2
- package/src/agents/hooks-deployer.test.ts +131 -16
- package/src/agents/hooks-deployer.ts +33 -1
- package/src/agents/identity.test.ts +27 -27
- package/src/agents/identity.ts +10 -10
- package/src/agents/lifecycle.test.ts +6 -6
- package/src/agents/lifecycle.ts +2 -2
- package/src/agents/manifest.test.ts +86 -0
- package/src/agents/overlay.test.ts +9 -9
- package/src/agents/overlay.ts +4 -4
- package/src/commands/agents.test.ts +8 -8
- package/src/commands/agents.ts +62 -91
- package/src/commands/clean.test.ts +36 -51
- package/src/commands/clean.ts +28 -49
- package/src/commands/completions.ts +14 -0
- package/src/commands/coordinator.test.ts +133 -26
- package/src/commands/coordinator.ts +101 -64
- package/src/commands/costs.test.ts +47 -47
- package/src/commands/costs.ts +96 -75
- package/src/commands/dashboard.test.ts +2 -2
- package/src/commands/dashboard.ts +75 -95
- package/src/commands/doctor.test.ts +2 -2
- package/src/commands/doctor.ts +92 -79
- package/src/commands/errors.test.ts +2 -2
- package/src/commands/errors.ts +56 -50
- package/src/commands/feed.test.ts +2 -2
- package/src/commands/feed.ts +86 -83
- package/src/commands/group.ts +167 -177
- package/src/commands/hooks.test.ts +2 -2
- package/src/commands/hooks.ts +52 -42
- package/src/commands/init.test.ts +19 -19
- package/src/commands/init.ts +7 -16
- package/src/commands/inspect.test.ts +18 -18
- package/src/commands/inspect.ts +55 -58
- package/src/commands/log.test.ts +26 -31
- package/src/commands/log.ts +97 -91
- package/src/commands/logs.test.ts +1 -1
- package/src/commands/logs.ts +101 -104
- package/src/commands/mail.test.ts +5 -5
- package/src/commands/mail.ts +157 -169
- package/src/commands/merge.test.ts +28 -66
- package/src/commands/merge.ts +21 -51
- package/src/commands/metrics.test.ts +8 -8
- package/src/commands/metrics.ts +34 -35
- package/src/commands/monitor.test.ts +3 -3
- package/src/commands/monitor.ts +57 -62
- package/src/commands/nudge.test.ts +1 -1
- package/src/commands/nudge.ts +41 -89
- package/src/commands/prime.test.ts +19 -51
- package/src/commands/prime.ts +13 -50
- package/src/commands/replay.test.ts +2 -2
- package/src/commands/replay.ts +79 -86
- package/src/commands/run.test.ts +1 -1
- package/src/commands/run.ts +97 -77
- package/src/commands/sling.test.ts +201 -5
- package/src/commands/sling.ts +37 -64
- package/src/commands/spec.test.ts +14 -40
- package/src/commands/spec.ts +32 -101
- package/src/commands/status.test.ts +97 -1
- package/src/commands/status.ts +63 -58
- package/src/commands/stop.test.ts +22 -40
- package/src/commands/stop.ts +18 -33
- package/src/commands/supervisor.test.ts +12 -14
- package/src/commands/supervisor.ts +144 -165
- package/src/commands/trace.test.ts +15 -15
- package/src/commands/trace.ts +59 -82
- package/src/commands/watch.test.ts +2 -2
- package/src/commands/watch.ts +38 -45
- package/src/commands/worktree.test.ts +213 -37
- package/src/commands/worktree.ts +110 -55
- package/src/config.test.ts +96 -0
- package/src/doctor/consistency.test.ts +14 -14
- package/src/doctor/databases.test.ts +22 -2
- package/src/doctor/databases.ts +16 -0
- package/src/doctor/dependencies.test.ts +55 -1
- package/src/doctor/dependencies.ts +113 -18
- package/src/doctor/merge-queue.test.ts +4 -4
- package/src/e2e/init-sling-lifecycle.test.ts +8 -8
- package/src/errors.ts +1 -1
- package/src/index.ts +223 -213
- package/src/logging/color.test.ts +74 -91
- package/src/logging/color.ts +52 -46
- package/src/logging/reporter.test.ts +10 -10
- package/src/logging/reporter.ts +6 -5
- package/src/mail/broadcast.test.ts +1 -1
- package/src/mail/client.test.ts +6 -6
- package/src/mail/store.test.ts +3 -3
- package/src/merge/queue.test.ts +73 -7
- package/src/merge/queue.ts +17 -2
- package/src/merge/resolver.test.ts +159 -7
- package/src/merge/resolver.ts +46 -2
- package/src/metrics/store.test.ts +44 -44
- package/src/metrics/store.ts +2 -2
- package/src/metrics/summary.test.ts +35 -35
- package/src/mulch/client.test.ts +1 -1
- package/src/schema-consistency.test.ts +239 -0
- package/src/sessions/compat.test.ts +3 -3
- package/src/sessions/compat.ts +2 -2
- package/src/sessions/store.test.ts +41 -4
- package/src/sessions/store.ts +13 -2
- package/src/types.ts +14 -14
- package/src/watchdog/daemon.test.ts +10 -10
- package/src/watchdog/daemon.ts +1 -1
- package/src/watchdog/health.test.ts +1 -1
- package/src/worktree/manager.test.ts +20 -20
- package/src/worktree/manager.ts +120 -4
- package/src/worktree/tmux.test.ts +98 -9
- package/src/worktree/tmux.ts +18 -0
package/src/commands/errors.ts
CHANGED
|
@@ -7,27 +7,13 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { join } from "node:path";
|
|
10
|
+
import { Command } from "commander";
|
|
10
11
|
import { loadConfig } from "../config.ts";
|
|
11
12
|
import { ValidationError } from "../errors.ts";
|
|
12
13
|
import { createEventStore } from "../events/store.ts";
|
|
13
14
|
import { color } from "../logging/color.ts";
|
|
14
15
|
import type { StoredEvent } from "../types.ts";
|
|
15
16
|
|
|
16
|
-
/**
|
|
17
|
-
* Parse a named flag value from args.
|
|
18
|
-
*/
|
|
19
|
-
function getFlag(args: string[], flag: string): string | undefined {
|
|
20
|
-
const idx = args.indexOf(flag);
|
|
21
|
-
if (idx === -1 || idx + 1 >= args.length) {
|
|
22
|
-
return undefined;
|
|
23
|
-
}
|
|
24
|
-
return args[idx + 1];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function hasFlag(args: string[], flag: string): boolean {
|
|
28
|
-
return args.includes(flag);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
17
|
/**
|
|
32
18
|
* Format an absolute time from an ISO timestamp.
|
|
33
19
|
* Returns "HH:MM:SS" portion.
|
|
@@ -109,15 +95,15 @@ function groupByAgent(events: StoredEvent[]): Map<string, StoredEvent[]> {
|
|
|
109
95
|
function printErrors(events: StoredEvent[]): void {
|
|
110
96
|
const w = process.stdout.write.bind(process.stdout);
|
|
111
97
|
|
|
112
|
-
w(`${color.bold
|
|
98
|
+
w(`${color.bold(color.red("Errors"))}\n`);
|
|
113
99
|
w(`${"=".repeat(70)}\n`);
|
|
114
100
|
|
|
115
101
|
if (events.length === 0) {
|
|
116
|
-
w(`${color.dim
|
|
102
|
+
w(`${color.dim("No errors found.")}\n`);
|
|
117
103
|
return;
|
|
118
104
|
}
|
|
119
105
|
|
|
120
|
-
w(`${color.dim
|
|
106
|
+
w(`${color.dim(`${events.length} error${events.length === 1 ? "" : "s"}`)}\n\n`);
|
|
121
107
|
|
|
122
108
|
const grouped = groupByAgent(events);
|
|
123
109
|
|
|
@@ -129,7 +115,7 @@ function printErrors(events: StoredEvent[]): void {
|
|
|
129
115
|
firstGroup = false;
|
|
130
116
|
|
|
131
117
|
w(
|
|
132
|
-
`${color.bold
|
|
118
|
+
`${color.bold(agentName)} ${color.dim(`(${agentEvents.length} error${agentEvents.length === 1 ? "" : "s"})`)}\n`,
|
|
133
119
|
);
|
|
134
120
|
|
|
135
121
|
for (const event of agentEvents) {
|
|
@@ -138,43 +124,29 @@ function printErrors(events: StoredEvent[]): void {
|
|
|
138
124
|
const timestamp = date ? `${date} ${time}` : time;
|
|
139
125
|
|
|
140
126
|
const detail = buildErrorDetail(event);
|
|
141
|
-
const detailSuffix = detail ? ` ${color.dim
|
|
127
|
+
const detailSuffix = detail ? ` ${color.dim(detail)}` : "";
|
|
142
128
|
|
|
143
|
-
w(
|
|
144
|
-
` ${color.dim}${timestamp}${color.reset} ${color.red}${color.bold}ERROR${color.reset}${detailSuffix}\n`,
|
|
145
|
-
);
|
|
129
|
+
w(` ${color.dim(timestamp)} ${color.red(color.bold("ERROR"))}${detailSuffix}\n`);
|
|
146
130
|
}
|
|
147
131
|
}
|
|
148
132
|
}
|
|
149
133
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
--until <timestamp> End time filter (ISO 8601)
|
|
159
|
-
--limit <n> Max errors to show (default: 100)
|
|
160
|
-
--json Output as JSON array of StoredEvent objects
|
|
161
|
-
--help, -h Show this help`;
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Entry point for `overstory errors [--agent <name>] [--run <id>] [--json] [--since] [--until] [--limit]`.
|
|
165
|
-
*/
|
|
166
|
-
export async function errorsCommand(args: string[]): Promise<void> {
|
|
167
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
168
|
-
process.stdout.write(`${ERRORS_HELP}\n`);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
134
|
+
interface ErrorsOpts {
|
|
135
|
+
agent?: string;
|
|
136
|
+
run?: string;
|
|
137
|
+
since?: string;
|
|
138
|
+
until?: string;
|
|
139
|
+
limit?: string;
|
|
140
|
+
json?: boolean;
|
|
141
|
+
}
|
|
171
142
|
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
const
|
|
143
|
+
async function executeErrors(opts: ErrorsOpts): Promise<void> {
|
|
144
|
+
const json = opts.json ?? false;
|
|
145
|
+
const agentName = opts.agent;
|
|
146
|
+
const runId = opts.run;
|
|
147
|
+
const sinceStr = opts.since;
|
|
148
|
+
const untilStr = opts.until;
|
|
149
|
+
const limitStr = opts.limit;
|
|
178
150
|
const limit = limitStr ? Number.parseInt(limitStr, 10) : 100;
|
|
179
151
|
|
|
180
152
|
if (Number.isNaN(limit) || limit < 1) {
|
|
@@ -246,3 +218,37 @@ export async function errorsCommand(args: string[]): Promise<void> {
|
|
|
246
218
|
eventStore.close();
|
|
247
219
|
}
|
|
248
220
|
}
|
|
221
|
+
|
|
222
|
+
export function createErrorsCommand(): Command {
|
|
223
|
+
return new Command("errors")
|
|
224
|
+
.description("Aggregated error view across agents")
|
|
225
|
+
.option("--agent <name>", "Filter errors by agent name")
|
|
226
|
+
.option("--run <id>", "Filter errors by run ID")
|
|
227
|
+
.option("--since <timestamp>", "Start time filter (ISO 8601)")
|
|
228
|
+
.option("--until <timestamp>", "End time filter (ISO 8601)")
|
|
229
|
+
.option("--limit <n>", "Max errors to show (default: 100)")
|
|
230
|
+
.option("--json", "Output as JSON array of StoredEvent objects")
|
|
231
|
+
.action(async (opts: ErrorsOpts) => {
|
|
232
|
+
await executeErrors(opts);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export async function errorsCommand(args: string[]): Promise<void> {
|
|
237
|
+
const cmd = createErrorsCommand();
|
|
238
|
+
cmd.exitOverride();
|
|
239
|
+
try {
|
|
240
|
+
await cmd.parseAsync(args, { from: "user" });
|
|
241
|
+
} catch (err: unknown) {
|
|
242
|
+
if (err && typeof err === "object" && "code" in err) {
|
|
243
|
+
const code = (err as { code: string }).code;
|
|
244
|
+
if (code === "commander.helpDisplayed" || code === "commander.version") {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (code.startsWith("commander.")) {
|
|
248
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
249
|
+
throw new ValidationError(message, { field: "args" });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
throw err;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -78,7 +78,7 @@ describe("feedCommand", () => {
|
|
|
78
78
|
await feedCommand(["--help"]);
|
|
79
79
|
const out = output();
|
|
80
80
|
|
|
81
|
-
expect(out).toContain("
|
|
81
|
+
expect(out).toContain("feed");
|
|
82
82
|
expect(out).toContain("--follow");
|
|
83
83
|
expect(out).toContain("--agent");
|
|
84
84
|
expect(out).toContain("--run");
|
|
@@ -92,7 +92,7 @@ describe("feedCommand", () => {
|
|
|
92
92
|
await feedCommand(["-h"]);
|
|
93
93
|
const out = output();
|
|
94
94
|
|
|
95
|
-
expect(out).toContain("
|
|
95
|
+
expect(out).toContain("feed");
|
|
96
96
|
});
|
|
97
97
|
});
|
|
98
98
|
|
package/src/commands/feed.ts
CHANGED
|
@@ -7,14 +7,16 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { join } from "node:path";
|
|
10
|
+
import { Command } from "commander";
|
|
10
11
|
import { loadConfig } from "../config.ts";
|
|
11
12
|
import { ValidationError } from "../errors.ts";
|
|
12
13
|
import { createEventStore } from "../events/store.ts";
|
|
14
|
+
import type { ColorFn } from "../logging/color.ts";
|
|
13
15
|
import { color } from "../logging/color.ts";
|
|
14
16
|
import type { EventType, StoredEvent } from "../types.ts";
|
|
15
17
|
|
|
16
18
|
/** Compact 5-char labels for feed output. */
|
|
17
|
-
const EVENT_LABELS: Record<EventType, { label: string; color:
|
|
19
|
+
const EVENT_LABELS: Record<EventType, { label: string; color: ColorFn }> = {
|
|
18
20
|
tool_start: { label: "TOOL+", color: color.blue },
|
|
19
21
|
tool_end: { label: "TOOL-", color: color.blue },
|
|
20
22
|
session_start: { label: "SESS+", color: color.green },
|
|
@@ -26,41 +28,14 @@ const EVENT_LABELS: Record<EventType, { label: string; color: string }> = {
|
|
|
26
28
|
custom: { label: "CUSTM", color: color.gray },
|
|
27
29
|
};
|
|
28
30
|
|
|
29
|
-
/**
|
|
30
|
-
const AGENT_COLORS
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (idx === -1 || idx + 1 >= args.length) {
|
|
38
|
-
return undefined;
|
|
39
|
-
}
|
|
40
|
-
return args[idx + 1];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Parse all occurrences of a named flag from args.
|
|
45
|
-
* Returns an array of values (e.g., --agent a --agent b => ["a", "b"]).
|
|
46
|
-
*/
|
|
47
|
-
function getAllFlags(args: string[], flag: string): string[] {
|
|
48
|
-
const values: string[] = [];
|
|
49
|
-
for (let i = 0; i < args.length; i++) {
|
|
50
|
-
if (args[i] === flag && i + 1 < args.length) {
|
|
51
|
-
const value = args[i + 1];
|
|
52
|
-
if (value !== undefined) {
|
|
53
|
-
values.push(value);
|
|
54
|
-
}
|
|
55
|
-
i++; // skip the value
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return values;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function hasFlag(args: string[], flag: string): boolean {
|
|
62
|
-
return args.includes(flag);
|
|
63
|
-
}
|
|
31
|
+
/** Color functions assigned to agents in order of first appearance. */
|
|
32
|
+
const AGENT_COLORS: readonly ColorFn[] = [
|
|
33
|
+
color.blue,
|
|
34
|
+
color.green,
|
|
35
|
+
color.yellow,
|
|
36
|
+
color.cyan,
|
|
37
|
+
color.magenta,
|
|
38
|
+
];
|
|
64
39
|
|
|
65
40
|
/**
|
|
66
41
|
* Format an absolute time from an ISO timestamp.
|
|
@@ -114,16 +89,16 @@ function buildEventDetail(event: StoredEvent): string {
|
|
|
114
89
|
}
|
|
115
90
|
|
|
116
91
|
/**
|
|
117
|
-
* Assign a stable color to each agent based on order of first appearance.
|
|
92
|
+
* Assign a stable color function to each agent based on order of first appearance.
|
|
118
93
|
*/
|
|
119
|
-
function buildAgentColorMap(events: StoredEvent[]): Map<string,
|
|
120
|
-
const colorMap = new Map<string,
|
|
94
|
+
function buildAgentColorMap(events: StoredEvent[]): Map<string, ColorFn> {
|
|
95
|
+
const colorMap = new Map<string, ColorFn>();
|
|
121
96
|
for (const event of events) {
|
|
122
97
|
if (!colorMap.has(event.agentName)) {
|
|
123
98
|
const colorIndex = colorMap.size % AGENT_COLORS.length;
|
|
124
|
-
const
|
|
125
|
-
if (
|
|
126
|
-
colorMap.set(event.agentName,
|
|
99
|
+
const agentColorFn = AGENT_COLORS[colorIndex];
|
|
100
|
+
if (agentColorFn !== undefined) {
|
|
101
|
+
colorMap.set(event.agentName, agentColorFn);
|
|
127
102
|
}
|
|
128
103
|
}
|
|
129
104
|
}
|
|
@@ -134,7 +109,7 @@ function buildAgentColorMap(events: StoredEvent[]): Map<string, string> {
|
|
|
134
109
|
* Print a single event in compact feed format:
|
|
135
110
|
* HH:MM:SS LABEL agentname detail
|
|
136
111
|
*/
|
|
137
|
-
function printEvent(event: StoredEvent, colorMap: Map<string,
|
|
112
|
+
function printEvent(event: StoredEvent, colorMap: Map<string, ColorFn>): void {
|
|
138
113
|
const w = process.stdout.write.bind(process.stdout);
|
|
139
114
|
|
|
140
115
|
const timeStr = formatAbsoluteTime(event.createdAt);
|
|
@@ -144,55 +119,43 @@ function printEvent(event: StoredEvent, colorMap: Map<string, string>): void {
|
|
|
144
119
|
color: color.gray,
|
|
145
120
|
};
|
|
146
121
|
|
|
147
|
-
const
|
|
148
|
-
event.level === "error" ? color.red : event.level === "warn" ? color.yellow :
|
|
149
|
-
const
|
|
122
|
+
const levelColorFn =
|
|
123
|
+
event.level === "error" ? color.red : event.level === "warn" ? color.yellow : null;
|
|
124
|
+
const applyLevel = (text: string) => (levelColorFn ? levelColorFn(text) : text);
|
|
150
125
|
|
|
151
126
|
const detail = buildEventDetail(event);
|
|
152
|
-
const detailSuffix = detail ? ` ${color.dim
|
|
127
|
+
const detailSuffix = detail ? ` ${color.dim(detail)}` : "";
|
|
153
128
|
|
|
154
|
-
const
|
|
155
|
-
const agentLabel = ` ${
|
|
129
|
+
const agentColorFn = colorMap.get(event.agentName) ?? color.gray;
|
|
130
|
+
const agentLabel = ` ${agentColorFn(event.agentName.padEnd(15))}`;
|
|
156
131
|
|
|
157
132
|
w(
|
|
158
|
-
`${color.dim
|
|
159
|
-
`${
|
|
133
|
+
`${color.dim(timeStr)} ` +
|
|
134
|
+
`${applyLevel(eventInfo.color(color.bold(eventInfo.label)))}` +
|
|
160
135
|
`${agentLabel}${detailSuffix}\n`,
|
|
161
136
|
);
|
|
162
137
|
}
|
|
163
138
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
--since <timestamp> Start time (ISO 8601, default: 5 minutes ago)
|
|
174
|
-
--limit <n> Max initial events to show (default: 50)
|
|
175
|
-
--json Output events as JSON (one per line in follow mode)
|
|
176
|
-
--help, -h Show this help`;
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Entry point for `overstory feed [--follow] [--agent <name>...] [--run <id>] [--json]`.
|
|
180
|
-
*/
|
|
181
|
-
export async function feedCommand(args: string[]): Promise<void> {
|
|
182
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
183
|
-
process.stdout.write(`${FEED_HELP}\n`);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
139
|
+
interface FeedOpts {
|
|
140
|
+
follow?: boolean;
|
|
141
|
+
interval?: string;
|
|
142
|
+
agent: string[]; // repeatable
|
|
143
|
+
run?: string;
|
|
144
|
+
since?: string;
|
|
145
|
+
limit?: string;
|
|
146
|
+
json?: boolean;
|
|
147
|
+
}
|
|
186
148
|
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
const
|
|
149
|
+
async function executeFeed(opts: FeedOpts): Promise<void> {
|
|
150
|
+
const json = opts.json ?? false;
|
|
151
|
+
const follow = opts.follow ?? false;
|
|
152
|
+
const runId = opts.run;
|
|
153
|
+
const agentNames = opts.agent;
|
|
154
|
+
const sinceStr = opts.since;
|
|
155
|
+
const limitStr = opts.limit;
|
|
193
156
|
const limit = limitStr ? Number.parseInt(limitStr, 10) : 50;
|
|
194
157
|
|
|
195
|
-
const intervalStr =
|
|
158
|
+
const intervalStr = opts.interval;
|
|
196
159
|
const interval = intervalStr ? Number.parseInt(intervalStr, 10) : 1000;
|
|
197
160
|
|
|
198
161
|
if (Number.isNaN(limit) || limit < 1) {
|
|
@@ -330,9 +293,9 @@ export async function feedCommand(args: string[]): Promise<void> {
|
|
|
330
293
|
for (const event of newEvents) {
|
|
331
294
|
if (!globalColorMap.has(event.agentName)) {
|
|
332
295
|
const colorIndex = globalColorMap.size % AGENT_COLORS.length;
|
|
333
|
-
const
|
|
334
|
-
if (
|
|
335
|
-
globalColorMap.set(event.agentName,
|
|
296
|
+
const agentColorFn = AGENT_COLORS[colorIndex];
|
|
297
|
+
if (agentColorFn !== undefined) {
|
|
298
|
+
globalColorMap.set(event.agentName, agentColorFn);
|
|
336
299
|
}
|
|
337
300
|
}
|
|
338
301
|
}
|
|
@@ -359,3 +322,43 @@ export async function feedCommand(args: string[]): Promise<void> {
|
|
|
359
322
|
eventStore.close();
|
|
360
323
|
}
|
|
361
324
|
}
|
|
325
|
+
|
|
326
|
+
export function createFeedCommand(): Command {
|
|
327
|
+
return new Command("feed")
|
|
328
|
+
.description("Unified real-time event stream across all agents")
|
|
329
|
+
.option("-f, --follow", "Continuously poll for new events (like tail -f)")
|
|
330
|
+
.option("--interval <ms>", "Polling interval for --follow (default: 1000, min: 200)")
|
|
331
|
+
.option(
|
|
332
|
+
"--agent <name>",
|
|
333
|
+
"Filter by agent name (can appear multiple times)",
|
|
334
|
+
(val: string, prev: string[]) => [...prev, val],
|
|
335
|
+
[] as string[],
|
|
336
|
+
)
|
|
337
|
+
.option("--run <id>", "Filter events by run ID")
|
|
338
|
+
.option("--since <timestamp>", "Start time (ISO 8601, default: 5 minutes ago)")
|
|
339
|
+
.option("--limit <n>", "Max initial events to show (default: 50)")
|
|
340
|
+
.option("--json", "Output events as JSON (one per line in follow mode)")
|
|
341
|
+
.action(async (opts: FeedOpts) => {
|
|
342
|
+
await executeFeed(opts);
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export async function feedCommand(args: string[]): Promise<void> {
|
|
347
|
+
const cmd = createFeedCommand();
|
|
348
|
+
cmd.exitOverride();
|
|
349
|
+
try {
|
|
350
|
+
await cmd.parseAsync(args, { from: "user" });
|
|
351
|
+
} catch (err: unknown) {
|
|
352
|
+
if (err && typeof err === "object" && "code" in err) {
|
|
353
|
+
const code = (err as { code: string }).code;
|
|
354
|
+
if (code === "commander.helpDisplayed" || code === "commander.version") {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (code.startsWith("commander.")) {
|
|
358
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
359
|
+
throw new ValidationError(message, { field: "args" });
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
throw err;
|
|
363
|
+
}
|
|
364
|
+
}
|