@katyella/legio 0.1.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/CHANGELOG.md +422 -0
- package/LICENSE +21 -0
- package/README.md +555 -0
- package/agents/builder.md +141 -0
- package/agents/coordinator.md +351 -0
- package/agents/cto.md +196 -0
- package/agents/gateway.md +276 -0
- package/agents/lead.md +281 -0
- package/agents/merger.md +156 -0
- package/agents/monitor.md +212 -0
- package/agents/reviewer.md +142 -0
- package/agents/scout.md +131 -0
- package/agents/supervisor.md +416 -0
- package/bin/legio.mjs +38 -0
- package/package.json +77 -0
- package/src/agents/checkpoint.test.ts +88 -0
- package/src/agents/checkpoint.ts +102 -0
- package/src/agents/hooks-deployer.test.ts +1820 -0
- package/src/agents/hooks-deployer.ts +574 -0
- package/src/agents/identity.test.ts +614 -0
- package/src/agents/identity.ts +385 -0
- package/src/agents/lifecycle.test.ts +202 -0
- package/src/agents/lifecycle.ts +184 -0
- package/src/agents/manifest.test.ts +558 -0
- package/src/agents/manifest.ts +297 -0
- package/src/agents/overlay.test.ts +592 -0
- package/src/agents/overlay.ts +316 -0
- package/src/beads/client.test.ts +210 -0
- package/src/beads/client.ts +227 -0
- package/src/beads/molecules.test.ts +320 -0
- package/src/beads/molecules.ts +209 -0
- package/src/commands/agents.test.ts +325 -0
- package/src/commands/agents.ts +286 -0
- package/src/commands/clean.test.ts +730 -0
- package/src/commands/clean.ts +653 -0
- package/src/commands/completions.test.ts +346 -0
- package/src/commands/completions.ts +950 -0
- package/src/commands/coordinator.test.ts +1524 -0
- package/src/commands/coordinator.ts +880 -0
- package/src/commands/costs.test.ts +1015 -0
- package/src/commands/costs.ts +473 -0
- package/src/commands/dashboard.test.ts +94 -0
- package/src/commands/dashboard.ts +607 -0
- package/src/commands/doctor.test.ts +295 -0
- package/src/commands/doctor.ts +213 -0
- package/src/commands/down.test.ts +308 -0
- package/src/commands/down.ts +124 -0
- package/src/commands/errors.test.ts +648 -0
- package/src/commands/errors.ts +255 -0
- package/src/commands/feed.test.ts +579 -0
- package/src/commands/feed.ts +368 -0
- package/src/commands/gateway.test.ts +698 -0
- package/src/commands/gateway.ts +419 -0
- package/src/commands/group.test.ts +262 -0
- package/src/commands/group.ts +539 -0
- package/src/commands/hooks.test.ts +292 -0
- package/src/commands/hooks.ts +210 -0
- package/src/commands/init.test.ts +211 -0
- package/src/commands/init.ts +622 -0
- package/src/commands/inspect.test.ts +670 -0
- package/src/commands/inspect.ts +455 -0
- package/src/commands/log.test.ts +1556 -0
- package/src/commands/log.ts +752 -0
- package/src/commands/logs.test.ts +379 -0
- package/src/commands/logs.ts +544 -0
- package/src/commands/mail.test.ts +1726 -0
- package/src/commands/mail.ts +926 -0
- package/src/commands/merge.test.ts +676 -0
- package/src/commands/merge.ts +374 -0
- package/src/commands/metrics.test.ts +444 -0
- package/src/commands/metrics.ts +150 -0
- package/src/commands/monitor.test.ts +151 -0
- package/src/commands/monitor.ts +394 -0
- package/src/commands/nudge.test.ts +230 -0
- package/src/commands/nudge.ts +373 -0
- package/src/commands/prime.test.ts +467 -0
- package/src/commands/prime.ts +386 -0
- package/src/commands/replay.test.ts +742 -0
- package/src/commands/replay.ts +367 -0
- package/src/commands/run.test.ts +443 -0
- package/src/commands/run.ts +365 -0
- package/src/commands/server.test.ts +626 -0
- package/src/commands/server.ts +298 -0
- package/src/commands/sling.test.ts +810 -0
- package/src/commands/sling.ts +700 -0
- package/src/commands/spec.test.ts +206 -0
- package/src/commands/spec.ts +171 -0
- package/src/commands/status.test.ts +276 -0
- package/src/commands/status.ts +339 -0
- package/src/commands/stop.test.ts +357 -0
- package/src/commands/stop.ts +119 -0
- package/src/commands/supervisor.test.ts +186 -0
- package/src/commands/supervisor.ts +544 -0
- package/src/commands/trace.test.ts +746 -0
- package/src/commands/trace.ts +332 -0
- package/src/commands/up.test.ts +597 -0
- package/src/commands/up.ts +275 -0
- package/src/commands/watch.test.ts +152 -0
- package/src/commands/watch.ts +238 -0
- package/src/commands/worktree.test.ts +648 -0
- package/src/commands/worktree.ts +266 -0
- package/src/config.test.ts +496 -0
- package/src/config.ts +616 -0
- package/src/doctor/agents.test.ts +448 -0
- package/src/doctor/agents.ts +396 -0
- package/src/doctor/config-check.test.ts +184 -0
- package/src/doctor/config-check.ts +185 -0
- package/src/doctor/consistency.test.ts +645 -0
- package/src/doctor/consistency.ts +294 -0
- package/src/doctor/databases.test.ts +284 -0
- package/src/doctor/databases.ts +211 -0
- package/src/doctor/dependencies.test.ts +150 -0
- package/src/doctor/dependencies.ts +179 -0
- package/src/doctor/logs.test.ts +244 -0
- package/src/doctor/logs.ts +295 -0
- package/src/doctor/merge-queue.test.ts +210 -0
- package/src/doctor/merge-queue.ts +144 -0
- package/src/doctor/structure.test.ts +285 -0
- package/src/doctor/structure.ts +195 -0
- package/src/doctor/types.ts +37 -0
- package/src/doctor/version.test.ts +130 -0
- package/src/doctor/version.ts +131 -0
- package/src/e2e/chat-flow.test.ts +346 -0
- package/src/e2e/init-sling-lifecycle.test.ts +288 -0
- package/src/errors.test.ts +21 -0
- package/src/errors.ts +246 -0
- package/src/events/store.test.ts +660 -0
- package/src/events/store.ts +344 -0
- package/src/events/tool-filter.test.ts +330 -0
- package/src/events/tool-filter.ts +126 -0
- package/src/global-setup.ts +14 -0
- package/src/index.ts +339 -0
- package/src/insights/analyzer.test.ts +466 -0
- package/src/insights/analyzer.ts +203 -0
- package/src/logging/color.test.ts +118 -0
- package/src/logging/color.ts +71 -0
- package/src/logging/logger.test.ts +812 -0
- package/src/logging/logger.ts +266 -0
- package/src/logging/reporter.test.ts +258 -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 +873 -0
- package/src/mail/client.ts +236 -0
- package/src/mail/store.test.ts +815 -0
- package/src/mail/store.ts +402 -0
- package/src/merge/queue.test.ts +449 -0
- package/src/merge/queue.ts +262 -0
- package/src/merge/resolver.test.ts +1453 -0
- package/src/merge/resolver.ts +759 -0
- package/src/metrics/store.test.ts +1167 -0
- package/src/metrics/store.ts +511 -0
- package/src/metrics/summary.test.ts +397 -0
- package/src/metrics/summary.ts +178 -0
- package/src/metrics/transcript.test.ts +643 -0
- package/src/metrics/transcript.ts +351 -0
- package/src/mulch/client.test.ts +547 -0
- package/src/mulch/client.ts +416 -0
- package/src/server/audit-store.test.ts +384 -0
- package/src/server/audit-store.ts +257 -0
- package/src/server/headless.test.ts +180 -0
- package/src/server/headless.ts +151 -0
- package/src/server/index.test.ts +241 -0
- package/src/server/index.ts +317 -0
- package/src/server/public/app.js +187 -0
- package/src/server/public/apple-touch-icon.png +0 -0
- package/src/server/public/components/agent-badge.js +37 -0
- package/src/server/public/components/data-table.js +114 -0
- package/src/server/public/components/gateway-chat.js +256 -0
- package/src/server/public/components/issue-card.js +96 -0
- package/src/server/public/components/layout.js +88 -0
- package/src/server/public/components/message-bubble.js +120 -0
- package/src/server/public/components/stat-card.js +26 -0
- package/src/server/public/components/terminal-panel.js +140 -0
- package/src/server/public/favicon-16.png +0 -0
- package/src/server/public/favicon-32.png +0 -0
- package/src/server/public/favicon.ico +0 -0
- package/src/server/public/favicon.png +0 -0
- package/src/server/public/index.html +64 -0
- package/src/server/public/lib/api.js +35 -0
- package/src/server/public/lib/markdown.js +8 -0
- package/src/server/public/lib/preact-setup.js +8 -0
- package/src/server/public/lib/state.js +99 -0
- package/src/server/public/lib/utils.js +309 -0
- package/src/server/public/lib/ws.js +79 -0
- package/src/server/public/views/chat.js +983 -0
- package/src/server/public/views/costs.js +692 -0
- package/src/server/public/views/dashboard.js +781 -0
- package/src/server/public/views/gateway-chat.js +622 -0
- package/src/server/public/views/inspect.js +399 -0
- package/src/server/public/views/issues.js +470 -0
- package/src/server/public/views/setup.js +94 -0
- package/src/server/public/views/task-detail.js +422 -0
- package/src/server/routes.test.ts +3816 -0
- package/src/server/routes.ts +1964 -0
- package/src/server/websocket.test.ts +288 -0
- package/src/server/websocket.ts +196 -0
- package/src/sessions/compat.test.ts +109 -0
- package/src/sessions/compat.ts +17 -0
- package/src/sessions/store.test.ts +969 -0
- package/src/sessions/store.ts +480 -0
- package/src/test-helpers.test.ts +97 -0
- package/src/test-helpers.ts +143 -0
- package/src/types.ts +708 -0
- package/src/watchdog/daemon.test.ts +1233 -0
- package/src/watchdog/daemon.ts +533 -0
- package/src/watchdog/health.test.ts +371 -0
- package/src/watchdog/health.ts +248 -0
- package/src/watchdog/triage.test.ts +162 -0
- package/src/watchdog/triage.ts +193 -0
- package/src/worktree/manager.test.ts +444 -0
- package/src/worktree/manager.ts +224 -0
- package/src/worktree/tmux.test.ts +1238 -0
- package/src/worktree/tmux.ts +644 -0
- package/templates/CLAUDE.md.tmpl +89 -0
- package/templates/hooks.json.tmpl +132 -0
- package/templates/overlay.md.tmpl +79 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: legio stop
|
|
3
|
+
*
|
|
4
|
+
* Stops active agent sessions deepest-first (leaf agents before parents).
|
|
5
|
+
* Kills each agent's tmux session and marks the session as completed in
|
|
6
|
+
* the session store.
|
|
7
|
+
*
|
|
8
|
+
* If --agent <name> is provided, stops only that specific agent.
|
|
9
|
+
* Otherwise stops all active sessions (state: booting, working, stalled).
|
|
10
|
+
*
|
|
11
|
+
* Uses DI (StopDeps._tmux) for tmux operations, matching coordinator.ts pattern.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { loadConfig } from "../config.ts";
|
|
16
|
+
import { AgentError } from "../errors.ts";
|
|
17
|
+
import { openSessionStore } from "../sessions/compat.ts";
|
|
18
|
+
import { isSessionAlive, killSession } from "../worktree/tmux.ts";
|
|
19
|
+
|
|
20
|
+
function hasFlag(args: string[], flag: string): boolean {
|
|
21
|
+
return args.includes(flag);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getFlagValue(args: string[], flag: string): string | undefined {
|
|
25
|
+
const idx = args.indexOf(flag);
|
|
26
|
+
if (idx === -1) return undefined;
|
|
27
|
+
return args[idx + 1];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Dependency injection interface for testing. */
|
|
31
|
+
export interface StopDeps {
|
|
32
|
+
_tmux?: {
|
|
33
|
+
isSessionAlive: (name: string) => Promise<boolean>;
|
|
34
|
+
killSession: (name: string) => Promise<void>;
|
|
35
|
+
};
|
|
36
|
+
_projectRoot?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const STOP_HELP = `legio stop — Stop active agent sessions
|
|
40
|
+
|
|
41
|
+
Usage: legio stop [options]
|
|
42
|
+
|
|
43
|
+
Options:
|
|
44
|
+
--agent <name> Stop only the named agent (default: stop all active agents)
|
|
45
|
+
--json JSON output
|
|
46
|
+
--help, -h Show this help
|
|
47
|
+
|
|
48
|
+
Agents are stopped deepest-first (leaf agents before their parents).
|
|
49
|
+
Running legio stop when no agents are active is a safe no-op.`;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Entry point for \`legio stop [options]\`.
|
|
53
|
+
*
|
|
54
|
+
* @param args - CLI arguments after "stop"
|
|
55
|
+
* @param deps - Optional dependency injection for testing
|
|
56
|
+
*/
|
|
57
|
+
export async function stopCommand(args: string[], deps: StopDeps = {}): Promise<void> {
|
|
58
|
+
if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
|
|
59
|
+
process.stdout.write(`${STOP_HELP}\n`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const json = hasFlag(args, "--json");
|
|
64
|
+
const agentFilter = getFlagValue(args, "--agent");
|
|
65
|
+
const tmux = deps._tmux ?? { isSessionAlive, killSession };
|
|
66
|
+
const projectRoot = deps._projectRoot ?? process.cwd();
|
|
67
|
+
|
|
68
|
+
const config = await loadConfig(projectRoot);
|
|
69
|
+
const legioDir = join(config.project.root, ".legio");
|
|
70
|
+
const { store } = openSessionStore(legioDir);
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const sessions = agentFilter
|
|
74
|
+
? (() => {
|
|
75
|
+
const session = store.getByName(agentFilter);
|
|
76
|
+
if (!session) {
|
|
77
|
+
throw new AgentError(`No session found for agent '${agentFilter}'`, {
|
|
78
|
+
agentName: agentFilter,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return [session];
|
|
82
|
+
})()
|
|
83
|
+
: store.getActive();
|
|
84
|
+
|
|
85
|
+
if (sessions.length === 0) {
|
|
86
|
+
if (json) {
|
|
87
|
+
process.stdout.write(`${JSON.stringify({ stopped: [], nothingToStop: true })}\n`);
|
|
88
|
+
} else {
|
|
89
|
+
process.stdout.write("Nothing to stop\n");
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Sort deepest-first: leaf agents die before their parents
|
|
95
|
+
const sorted = [...sessions].sort((a, b) => b.depth - a.depth);
|
|
96
|
+
|
|
97
|
+
const stopped: string[] = [];
|
|
98
|
+
|
|
99
|
+
for (const session of sorted) {
|
|
100
|
+
const alive = await tmux.isSessionAlive(session.tmuxSession);
|
|
101
|
+
if (alive) {
|
|
102
|
+
await tmux.killSession(session.tmuxSession);
|
|
103
|
+
}
|
|
104
|
+
store.updateState(session.agentName, "completed");
|
|
105
|
+
stopped.push(session.agentName);
|
|
106
|
+
if (!json) {
|
|
107
|
+
process.stdout.write(`Stopped: ${session.agentName} (${session.tmuxSession})\n`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (json) {
|
|
112
|
+
process.stdout.write(`${JSON.stringify({ stopped, nothingToStop: false })}\n`);
|
|
113
|
+
} else {
|
|
114
|
+
process.stdout.write(`Stopped ${stopped.length} agent${stopped.length === 1 ? "" : "s"}\n`);
|
|
115
|
+
}
|
|
116
|
+
} finally {
|
|
117
|
+
store.close();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { buildSupervisorBeacon, supervisorCommand } from "./supervisor.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tests for supervisor command functions.
|
|
6
|
+
*
|
|
7
|
+
* Session persistence is now handled by SessionStore (SQLite).
|
|
8
|
+
* Those tests live in src/sessions/store.test.ts and src/sessions/compat.test.ts.
|
|
9
|
+
* Here we test beacon generation.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
describe("buildSupervisorBeacon", () => {
|
|
13
|
+
test("contains agent name and beadId from opts", () => {
|
|
14
|
+
const beacon = buildSupervisorBeacon({
|
|
15
|
+
name: "supervisor-1",
|
|
16
|
+
beadId: "task-abc123",
|
|
17
|
+
depth: 1,
|
|
18
|
+
parent: "coordinator",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
expect(beacon).toContain("supervisor-1");
|
|
22
|
+
expect(beacon).toContain("task-abc123");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("contains [LEGIO] prefix", () => {
|
|
26
|
+
const beacon = buildSupervisorBeacon({
|
|
27
|
+
name: "supervisor-1",
|
|
28
|
+
beadId: "task-1",
|
|
29
|
+
depth: 1,
|
|
30
|
+
parent: "coordinator",
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(beacon).toContain("[LEGIO]");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("contains (supervisor) designation", () => {
|
|
37
|
+
const beacon = buildSupervisorBeacon({
|
|
38
|
+
name: "supervisor-1",
|
|
39
|
+
beadId: "task-1",
|
|
40
|
+
depth: 1,
|
|
41
|
+
parent: "coordinator",
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(beacon).toContain("(supervisor)");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("contains depth and parent info from opts", () => {
|
|
48
|
+
const beacon = buildSupervisorBeacon({
|
|
49
|
+
name: "supervisor-1",
|
|
50
|
+
beadId: "task-1",
|
|
51
|
+
depth: 2,
|
|
52
|
+
parent: "lead-cli",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(beacon).toContain("Depth: 2");
|
|
56
|
+
expect(beacon).toContain("Parent: lead-cli");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("contains startup instructions", () => {
|
|
60
|
+
const beacon = buildSupervisorBeacon({
|
|
61
|
+
name: "supervisor-1",
|
|
62
|
+
beadId: "task-1",
|
|
63
|
+
depth: 1,
|
|
64
|
+
parent: "coordinator",
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Should include mulch prime
|
|
68
|
+
expect(beacon).toContain("mulch prime");
|
|
69
|
+
|
|
70
|
+
// Should include mail check with agent name
|
|
71
|
+
expect(beacon).toContain("legio mail check --agent supervisor-1");
|
|
72
|
+
|
|
73
|
+
// Should include bd show with beadId
|
|
74
|
+
expect(beacon).toContain("bd show task-1");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("contains ISO timestamp", () => {
|
|
78
|
+
const before = new Date();
|
|
79
|
+
const beacon = buildSupervisorBeacon({
|
|
80
|
+
name: "supervisor-1",
|
|
81
|
+
beadId: "task-1",
|
|
82
|
+
depth: 1,
|
|
83
|
+
parent: "coordinator",
|
|
84
|
+
});
|
|
85
|
+
const after = new Date();
|
|
86
|
+
|
|
87
|
+
// Extract timestamp from beacon (format: [LEGIO] {name} (supervisor) {timestamp} task:{beadId})
|
|
88
|
+
const timestampMatch = beacon.match(/\(supervisor\)\s+(\S+)\s+task:/);
|
|
89
|
+
expect(timestampMatch).toBeTruthy();
|
|
90
|
+
|
|
91
|
+
if (timestampMatch?.[1]) {
|
|
92
|
+
const timestamp = new Date(timestampMatch[1]);
|
|
93
|
+
expect(timestamp.getTime()).toBeGreaterThanOrEqual(before.getTime());
|
|
94
|
+
expect(timestamp.getTime()).toBeLessThanOrEqual(after.getTime());
|
|
95
|
+
|
|
96
|
+
// Verify ISO format (should parse correctly)
|
|
97
|
+
expect(timestamp.toISOString()).toBeTruthy();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("supervisorCommand", () => {
|
|
103
|
+
test("--help prints help containing required keywords", async () => {
|
|
104
|
+
const originalWrite = process.stdout.write;
|
|
105
|
+
let output = "";
|
|
106
|
+
process.stdout.write = ((chunk: string) => {
|
|
107
|
+
output += chunk;
|
|
108
|
+
return true;
|
|
109
|
+
}) as typeof process.stdout.write;
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
await supervisorCommand(["--help"]);
|
|
113
|
+
expect(output).toContain("legio supervisor");
|
|
114
|
+
expect(output).toContain("start");
|
|
115
|
+
expect(output).toContain("stop");
|
|
116
|
+
expect(output).toContain("status");
|
|
117
|
+
expect(output).toContain("--task");
|
|
118
|
+
expect(output).toContain("--name");
|
|
119
|
+
} finally {
|
|
120
|
+
process.stdout.write = originalWrite;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("-h prints help", async () => {
|
|
125
|
+
const originalWrite = process.stdout.write;
|
|
126
|
+
let output = "";
|
|
127
|
+
process.stdout.write = ((chunk: string) => {
|
|
128
|
+
output += chunk;
|
|
129
|
+
return true;
|
|
130
|
+
}) as typeof process.stdout.write;
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
await supervisorCommand(["-h"]);
|
|
134
|
+
expect(output).toContain("legio supervisor");
|
|
135
|
+
} finally {
|
|
136
|
+
process.stdout.write = originalWrite;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("empty args [] shows help", async () => {
|
|
141
|
+
const originalWrite = process.stdout.write;
|
|
142
|
+
let output = "";
|
|
143
|
+
process.stdout.write = ((chunk: string) => {
|
|
144
|
+
output += chunk;
|
|
145
|
+
return true;
|
|
146
|
+
}) as typeof process.stdout.write;
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
await supervisorCommand([]);
|
|
150
|
+
expect(output).toContain("legio supervisor");
|
|
151
|
+
} finally {
|
|
152
|
+
process.stdout.write = originalWrite;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("unknown subcommand throws ValidationError with bad value in message", async () => {
|
|
157
|
+
await expect(supervisorCommand(["invalid-subcommand"])).rejects.toThrow(/invalid-subcommand/);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("start without --task throws ValidationError", async () => {
|
|
161
|
+
await expect(supervisorCommand(["start", "--name", "supervisor-1"])).rejects.toThrow(/--task/);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("start without --name throws ValidationError", async () => {
|
|
165
|
+
await expect(supervisorCommand(["start", "--task", "task-1"])).rejects.toThrow(/--name/);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("stop without --name throws ValidationError", async () => {
|
|
169
|
+
await expect(supervisorCommand(["stop"])).rejects.toThrow(/--name/);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("start throws ValidationError with uid field when running as root", async () => {
|
|
173
|
+
const original = process.getuid;
|
|
174
|
+
process.getuid = () => 0;
|
|
175
|
+
try {
|
|
176
|
+
await expect(
|
|
177
|
+
supervisorCommand(["start", "--task", "legio-test", "--name", "sup-1"]),
|
|
178
|
+
).rejects.toMatchObject({
|
|
179
|
+
name: "ValidationError",
|
|
180
|
+
field: "uid",
|
|
181
|
+
});
|
|
182
|
+
} finally {
|
|
183
|
+
process.getuid = original;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
});
|