@agenti-os/cli 0.2.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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +164 -0
  3. package/dashboard/404/index.html +1 -0
  4. package/dashboard/404.html +1 -0
  5. package/dashboard/_next/static/chunks/111-83d9bd0855b2c216.js +1 -0
  6. package/dashboard/_next/static/chunks/458.6c27f5996829de5b.js +1 -0
  7. package/dashboard/_next/static/chunks/583.6051aee384433b11.js +1 -0
  8. package/dashboard/_next/static/chunks/74ce447c-ca924ebf577cd4a4.js +1 -0
  9. package/dashboard/_next/static/chunks/915-98c767e3b9eb8028.js +1 -0
  10. package/dashboard/_next/static/chunks/app/_not-found/page-c4e9dc1c64d4da80.js +1 -0
  11. package/dashboard/_next/static/chunks/app/health/page-1c057112a2d6fae4.js +1 -0
  12. package/dashboard/_next/static/chunks/app/inbox/page-b7271d9a24defeff.js +1 -0
  13. package/dashboard/_next/static/chunks/app/layout-a3e5ee55560bf39f.js +1 -0
  14. package/dashboard/_next/static/chunks/app/page-10b9e09a1a14a650.js +1 -0
  15. package/dashboard/_next/static/chunks/app/timeline/page-7fe0c8e8c7d028b8.js +1 -0
  16. package/dashboard/_next/static/chunks/framework-1c02a2e60068b586.js +1 -0
  17. package/dashboard/_next/static/chunks/main-0e2c8558bbf18f15.js +1 -0
  18. package/dashboard/_next/static/chunks/main-app-48902e05be997ee5.js +1 -0
  19. package/dashboard/_next/static/chunks/pages/_app-bd106308c06033e9.js +1 -0
  20. package/dashboard/_next/static/chunks/pages/_error-034fd19974bd12e6.js +1 -0
  21. package/dashboard/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  22. package/dashboard/_next/static/chunks/webpack-3aabda247bd1875f.js +1 -0
  23. package/dashboard/_next/static/css/53ea3bb274b2b444.css +3 -0
  24. package/dashboard/_next/static/wIIqV_03htqo96M3P8FEG/_buildManifest.js +1 -0
  25. package/dashboard/_next/static/wIIqV_03htqo96M3P8FEG/_ssgManifest.js +1 -0
  26. package/dashboard/health/index.html +1 -0
  27. package/dashboard/health/index.txt +20 -0
  28. package/dashboard/inbox/index.html +1 -0
  29. package/dashboard/inbox/index.txt +20 -0
  30. package/dashboard/index.html +1 -0
  31. package/dashboard/index.txt +20 -0
  32. package/dashboard/timeline/index.html +1 -0
  33. package/dashboard/timeline/index.txt +20 -0
  34. package/dist/chunk-4J3VBGVR.js +168 -0
  35. package/dist/chunk-CPCT2FTQ.js +48 -0
  36. package/dist/chunk-I442WICJ.js +155 -0
  37. package/dist/display-ZLPTSJQM.js +8 -0
  38. package/dist/dist-SD33RKHO.js +48 -0
  39. package/dist/gateway-client-RSQFHBFE.js +11 -0
  40. package/dist/index.js +1018 -0
  41. package/package.json +51 -0
package/dist/index.js ADDED
@@ -0,0 +1,1018 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ display
4
+ } from "./chunk-4J3VBGVR.js";
5
+ import {
6
+ GatewayNotRunningError,
7
+ gateway
8
+ } from "./chunk-I442WICJ.js";
9
+ import {
10
+ GATEWAY_BASE_URL
11
+ } from "./chunk-CPCT2FTQ.js";
12
+
13
+ // src/index.ts
14
+ import { Command } from "commander";
15
+ import chalk5 from "chalk";
16
+
17
+ // src/commands/init.ts
18
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
19
+ import { join } from "path";
20
+ import chalk from "chalk";
21
+ var AGENTOS_DIR = ".agentos";
22
+ function registerInitCommand(program2) {
23
+ program2.command("init").description("Initialize Agent OS in the current repository").option("--force", "Overwrite existing configuration files").action((opts) => {
24
+ runInit(opts.force);
25
+ });
26
+ }
27
+ function runInit(force = false) {
28
+ const cwd = process.cwd();
29
+ if (!existsSync(join(cwd, ".git"))) {
30
+ display.warning("No .git directory found. Agent OS works best inside a Git repository.");
31
+ console.log(chalk.grey(" Continuing anyway...\n"));
32
+ }
33
+ console.log(chalk.bold("\n Initializing Agent OS\n"));
34
+ const dirs = [
35
+ AGENTOS_DIR,
36
+ join(AGENTOS_DIR, "context"),
37
+ join(AGENTOS_DIR, "context", "api-contracts"),
38
+ join(AGENTOS_DIR, "context", "decisions"),
39
+ join(AGENTOS_DIR, "missions"),
40
+ join(AGENTOS_DIR, "runs"),
41
+ join(AGENTOS_DIR, "artifacts"),
42
+ join(AGENTOS_DIR, "approvals"),
43
+ join(AGENTOS_DIR, "workspaces"),
44
+ join(AGENTOS_DIR, ".secrets")
45
+ ];
46
+ for (const dir of dirs) {
47
+ mkdirSync(join(cwd, dir), { recursive: true });
48
+ console.log(chalk.grey(` created `) + dir + "/");
49
+ }
50
+ const files = [
51
+ {
52
+ path: join(AGENTOS_DIR, "config.yml"),
53
+ content: CONFIG_YML
54
+ },
55
+ {
56
+ path: join(AGENTOS_DIR, "agents.yml"),
57
+ content: AGENTS_YML
58
+ },
59
+ {
60
+ path: join(AGENTOS_DIR, "policies.yml"),
61
+ content: POLICIES_YML
62
+ },
63
+ {
64
+ path: join(AGENTOS_DIR, "context", "product.md"),
65
+ content: PRODUCT_MD
66
+ },
67
+ {
68
+ path: join(AGENTOS_DIR, "context", "architecture.md"),
69
+ content: ARCHITECTURE_MD
70
+ },
71
+ {
72
+ path: join(AGENTOS_DIR, "context", "constraints.md"),
73
+ content: CONSTRAINTS_MD
74
+ },
75
+ {
76
+ path: join(AGENTOS_DIR, "context", "glossary.md"),
77
+ content: GLOSSARY_MD
78
+ },
79
+ {
80
+ path: join(AGENTOS_DIR, ".gitignore"),
81
+ content: GITIGNORE
82
+ }
83
+ ];
84
+ for (const file of files) {
85
+ const fullPath = join(cwd, file.path);
86
+ if (existsSync(fullPath) && !force) {
87
+ console.log(chalk.grey(` exists `) + file.path);
88
+ } else {
89
+ writeFileSync(fullPath, file.content, "utf-8");
90
+ console.log(chalk.green(` created `) + file.path);
91
+ }
92
+ }
93
+ console.log("\n" + chalk.bold.green(" \u2713 Agent OS initialized\n"));
94
+ console.log(chalk.grey(" Next steps:"));
95
+ console.log(chalk.grey(" 1. Edit .agentos/context/product.md with your project description"));
96
+ console.log(chalk.grey(" 2. Run: ") + chalk.white("agentos daemon start"));
97
+ console.log(chalk.grey(" 3. Run: ") + chalk.white("agentos agent add claude --role frontend"));
98
+ console.log();
99
+ }
100
+ var CONFIG_YML = `# Agent OS configuration
101
+ # This file is committed to your repository.
102
+ version: "1"
103
+
104
+ gateway:
105
+ port: 47821
106
+ log_level: info
107
+
108
+ dashboard:
109
+ port: 47822
110
+
111
+ context:
112
+ token_budget_default: 8000
113
+ token_budget_max: 16000
114
+
115
+ workspace:
116
+ base_path: .agentos/workspaces
117
+ strategy: git_worktree
118
+ `;
119
+ var AGENTS_YML = `# Registered agents
120
+ # This file is committed to your repository.
121
+ # Credentials are stored in the OS keychain \u2014 never here.
122
+ version: "1"
123
+ agents: []
124
+ `;
125
+ var POLICIES_YML = `# Risk policies for Agent OS
126
+ # This file is committed to your repository.
127
+ version: "1"
128
+
129
+ risk_thresholds:
130
+ auto_approve: 30
131
+ ask_user: 70
132
+ block: 100
133
+
134
+ sensitive_paths:
135
+ - ".env*"
136
+ - "**/secrets/**"
137
+ - "infra/**"
138
+ - "db/migrations/**"
139
+ - "auth/**"
140
+ - "payments/**"
141
+
142
+ dangerous_commands:
143
+ - "rm -rf"
144
+ - "drop database"
145
+ - "git push --force"
146
+ - "curl * | sh"
147
+ - "chmod -R 777"
148
+ - "npm publish"
149
+ - "vercel --prod"
150
+ - "supabase db push --linked"
151
+
152
+ auto_approve_patterns:
153
+ - "npm test"
154
+ - "pytest"
155
+ - "git status"
156
+ - "git diff"
157
+ `;
158
+ var PRODUCT_MD = `# Product Context
159
+
160
+ <!--
161
+ Fill this in with your project's product context.
162
+ This document is injected into every agent's context pack.
163
+ -->
164
+
165
+ ## What this product is
166
+ [Describe what the app does and who it serves]
167
+
168
+ ## Target users
169
+ [Who uses this app and what are their main goals]
170
+
171
+ ## Key features
172
+ [List the main features]
173
+
174
+ ## Current status
175
+ [What phase of development are you in]
176
+ `;
177
+ var ARCHITECTURE_MD = `# Architecture Context
178
+
179
+ <!--
180
+ Fill this in with your project's technical architecture.
181
+ Agents use this to understand the codebase structure and conventions.
182
+ -->
183
+
184
+ ## Stack
185
+ [List your tech stack]
186
+
187
+ ## Folder structure
188
+ [Describe your key directories]
189
+
190
+ ## Conventions
191
+ [List coding conventions, naming patterns, etc.]
192
+
193
+ ## Key dependencies
194
+ [List important libraries and why they're used]
195
+ `;
196
+ var CONSTRAINTS_MD = `# Agent Constraints
197
+
198
+ <!--
199
+ Hard rules that ALL agents must follow, regardless of task.
200
+ These are injected into every context pack.
201
+ -->
202
+
203
+ ## Always
204
+ - Follow existing code style and conventions
205
+ - Write tests for new functionality
206
+ - Keep changes within your assigned scope
207
+ - Commit working code only \u2014 no broken states
208
+
209
+ ## Never
210
+ - Modify files outside your assigned scope
211
+ - Remove existing tests
212
+ - Change configuration that affects other agents' work
213
+ - Deploy to production without explicit approval
214
+ `;
215
+ var GLOSSARY_MD = `# Project Glossary
216
+
217
+ <!--
218
+ Define project-specific terms agents need to understand.
219
+ Add entries as your project develops domain-specific vocabulary.
220
+ -->
221
+
222
+ | Term | Definition |
223
+ |------|-----------|
224
+ | [term] | [definition] |
225
+ `;
226
+ var GITIGNORE = `# Agent OS \u2014 never commit these
227
+ .secrets/
228
+ runs/
229
+ workspaces/
230
+ approvals/
231
+ *.db
232
+ *.db-wal
233
+ *.db-shm
234
+ `;
235
+
236
+ // src/commands/daemon.ts
237
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync as writeFileSync2, unlinkSync } from "fs";
238
+ import { join as join2 } from "path";
239
+ import { spawn } from "child_process";
240
+ import ora from "ora";
241
+ var PID_FILE = ".agentos/gateway.pid";
242
+ var LOG_FILE = ".agentos/gateway.log";
243
+ function registerDaemonCommand(program2) {
244
+ const daemon = program2.command("daemon").description("Manage the Agent OS gateway daemon");
245
+ daemon.command("start").description("Start the gateway daemon in the background").option("--port <port>", "Port to run on (default: 47821)").action(async (opts) => {
246
+ await startDaemon(opts.port ? parseInt(opts.port) : void 0);
247
+ });
248
+ daemon.command("stop").description("Stop the running gateway daemon").action(stopDaemon);
249
+ daemon.command("status").description("Check if the gateway daemon is running").action(daemonStatus);
250
+ }
251
+ async function startDaemon(port) {
252
+ const spinner = ora("Starting Agent OS gateway...").start();
253
+ try {
254
+ const health = await gateway.health();
255
+ spinner.succeed(
256
+ `Gateway already running (v${health.version}, uptime: ${String(Math.floor(health.uptime_seconds))}s)`
257
+ );
258
+ return;
259
+ } catch (err) {
260
+ if (!(err instanceof GatewayNotRunningError)) {
261
+ spinner.fail("Unexpected error checking gateway status");
262
+ display.error(String(err));
263
+ process.exit(1);
264
+ }
265
+ }
266
+ const userProjectDir = process.cwd();
267
+ const env = {
268
+ ...process.env,
269
+ AGENTOS_PORT: String(port ?? 47821),
270
+ AGENTOS_LOG_LEVEL: "info"
271
+ };
272
+ const logPath = join2(userProjectDir, LOG_FILE);
273
+ const pidPath = join2(userProjectDir, PID_FILE);
274
+ const proc = spawn(
275
+ "python",
276
+ ["-m", "agentos_gateway"],
277
+ {
278
+ cwd: userProjectDir,
279
+ env,
280
+ detached: true,
281
+ stdio: ["ignore", "pipe", "pipe"]
282
+ }
283
+ );
284
+ mkdirSync2(join2(userProjectDir, ".agentos"), { recursive: true });
285
+ writeFileSync2(pidPath, String(proc.pid), "utf-8");
286
+ const logStream = (await import("fs")).createWriteStream(logPath, { flags: "a" });
287
+ proc.stdout.pipe(logStream);
288
+ proc.stderr.pipe(logStream);
289
+ proc.unref();
290
+ const maxWait = 1e4;
291
+ const interval = 200;
292
+ let elapsed = 0;
293
+ while (elapsed < maxWait) {
294
+ await new Promise((r) => setTimeout(r, interval));
295
+ elapsed += interval;
296
+ try {
297
+ const health = await gateway.health();
298
+ spinner.succeed(`Gateway started (v${health.version}, port: ${String(port ?? 47821)})`);
299
+ display.info(`Logs: ${logPath}`);
300
+ display.info(`PID: ${String(proc.pid)}`);
301
+ return;
302
+ } catch {
303
+ }
304
+ }
305
+ spinner.fail("Gateway did not start within 10 seconds");
306
+ display.info(`Check logs: ${logPath}`);
307
+ process.exit(1);
308
+ }
309
+ function stopDaemon() {
310
+ const pidPath = join2(process.cwd(), PID_FILE);
311
+ if (!existsSync2(pidPath)) {
312
+ display.warning("No gateway PID file found. Is the daemon running?");
313
+ process.exit(1);
314
+ }
315
+ const pid = parseInt(readFileSync(pidPath, "utf-8").trim());
316
+ try {
317
+ process.kill(pid, "SIGTERM");
318
+ unlinkSync(pidPath);
319
+ display.success(`Gateway stopped (PID: ${String(pid)})`);
320
+ } catch (err) {
321
+ if (err instanceof Error && "code" in err && err.code === "ESRCH") {
322
+ display.warning(`Process ${String(pid)} not found \u2014 removing stale PID file`);
323
+ unlinkSync(pidPath);
324
+ } else {
325
+ display.error(`Failed to stop gateway: ${String(err)}`);
326
+ process.exit(1);
327
+ }
328
+ }
329
+ }
330
+ async function daemonStatus() {
331
+ const pidPath = join2(process.cwd(), PID_FILE);
332
+ const pidExists = existsSync2(pidPath);
333
+ try {
334
+ const health = await gateway.health();
335
+ display.success("Gateway is running");
336
+ display.info(`Version: ${health.version}`);
337
+ display.info(`Uptime: ${String(Math.floor(health.uptime_seconds))}s`);
338
+ display.info(`Active missions: ${String(health.active_missions)}`);
339
+ display.info(`Active agents: ${String(health.active_agents)}`);
340
+ if (pidExists) {
341
+ const pid = readFileSync(pidPath, "utf-8").trim();
342
+ display.info(`PID: ${pid}`);
343
+ }
344
+ } catch (err) {
345
+ if (err instanceof GatewayNotRunningError) {
346
+ display.error("Gateway is not running");
347
+ if (pidExists) {
348
+ display.warning("Stale PID file found. Run: agentos daemon start");
349
+ }
350
+ process.exit(1);
351
+ }
352
+ throw err;
353
+ }
354
+ }
355
+
356
+ // src/commands/agent.ts
357
+ function collect(value, previous) {
358
+ return [...previous, value];
359
+ }
360
+ function registerAgentCommand(program2) {
361
+ const agent = program2.command("agent").description("Manage registered agents");
362
+ agent.command("add <name>").description("Register a new agent").option("--role <role>", "Role this agent plays (e.g. frontend, backend)", "general").option("--cmd <command>", "CLI command to invoke the agent (e.g. claude, codex)").option("--fallback <agent_id>", "Agent to route to on credential failure").option("--adapter <adapter>", "Adapter type: claude-code | codex | mock", "claude-code").option("--capability <cap>", "A capability this agent has (repeatable)", collect, []).action(async (name, opts) => {
363
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
364
+ if (!opts.cmd) {
365
+ display.error("--cmd is required (the CLI command to invoke the agent)");
366
+ process.exit(1);
367
+ }
368
+ try {
369
+ const created = await gateway2.registerAgent({
370
+ display_name: name,
371
+ adapter: opts.adapter,
372
+ command: opts.cmd,
373
+ role: opts.role ?? "general",
374
+ capabilities: opts.capability,
375
+ ...opts.fallback ? { fallback_agent_id: opts.fallback } : {}
376
+ });
377
+ display.success(`Registered agent "${created.display_name}" (id: ${created.id})`);
378
+ } catch (err) {
379
+ display.gatewayError(err);
380
+ }
381
+ });
382
+ agent.command("remove <id>").description("Remove a registered agent").action(async (id) => {
383
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
384
+ try {
385
+ await gateway2.removeAgent(id);
386
+ display.success(`Removed agent ${id}`);
387
+ } catch (err) {
388
+ display.gatewayError(err);
389
+ }
390
+ });
391
+ const agents = program2.command("agents").description("List all agents").action(async () => {
392
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
393
+ try {
394
+ const list = await gateway2.listAgents();
395
+ if (list.length === 0) {
396
+ display.info("No agents registered. Run: agentos agent add");
397
+ return;
398
+ }
399
+ display.agentTable(list);
400
+ } catch (err) {
401
+ display.gatewayError(err);
402
+ }
403
+ });
404
+ agents.command("health").description("Show credential health for every registered agent").action(async () => {
405
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
406
+ try {
407
+ const list = await gateway2.listAgents();
408
+ if (list.length === 0) {
409
+ display.info("No agents registered. Run: agentos agent add");
410
+ return;
411
+ }
412
+ const rows = await Promise.all(
413
+ list.map(async (a) => {
414
+ let health = null;
415
+ try {
416
+ health = await gateway2.getAgentHealth(a.id);
417
+ } catch {
418
+ health = null;
419
+ }
420
+ return { agent: a, health };
421
+ })
422
+ );
423
+ display.agentHealthTable(rows);
424
+ } catch (err) {
425
+ display.gatewayError(err);
426
+ }
427
+ });
428
+ }
429
+
430
+ // src/commands/mission.ts
431
+ function deriveTitle(objective) {
432
+ return objective.length > 60 ? `${objective.slice(0, 57)}...` : objective;
433
+ }
434
+ function registerMissionCommand(program2) {
435
+ const mission = program2.command("mission").description("Manage missions");
436
+ mission.command("create <objective>").description("Create a new mission from a natural-language objective").option("--title <title>", "Short title for the mission (derived from objective if omitted)").action(async (objective, opts) => {
437
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
438
+ try {
439
+ const created = await gateway2.createMission(opts.title ?? deriveTitle(objective), objective);
440
+ display.success(`Created mission "${created.title}" (id: ${created.id})`);
441
+ } catch (err) {
442
+ display.gatewayError(err);
443
+ }
444
+ });
445
+ mission.command("plan <mission_id>").description("Generate the task breakdown for a mission").action(async (missionId) => {
446
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
447
+ try {
448
+ const [plan, agents] = await Promise.all([
449
+ gateway2.planMission(missionId),
450
+ gateway2.listAgents()
451
+ ]);
452
+ const nameById = new Map(agents.map((a) => [a.id, a.display_name]));
453
+ display.success(`Planned ${String(plan.tasks.length)} tasks`);
454
+ for (const task of plan.tasks) {
455
+ const agentName = task.assigned_agent_id ? nameById.get(task.assigned_agent_id) ?? task.assigned_agent_id : "unassigned";
456
+ console.log(
457
+ ` ${display.riskBadge(task.risk_level)} ${task.title} \u2014 ${agentName}` + (task.depends_on.length > 0 ? ` (depends on: ${task.depends_on.join(", ")})` : "")
458
+ );
459
+ }
460
+ } catch (err) {
461
+ display.gatewayError(err);
462
+ }
463
+ });
464
+ mission.command("run <mission_id>").description("Start mission execution and stream live events until it stops running").option("--parallel", "Run ready tasks in parallel", true).action(async (missionId, opts) => {
465
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
466
+ try {
467
+ const result = await gateway2.runMission(missionId, opts.parallel);
468
+ display.success(`Started ${String(result.started_tasks.length)} task(s)`);
469
+ } catch (err) {
470
+ display.gatewayError(err);
471
+ }
472
+ const { GATEWAY_BASE_URL: GATEWAY_BASE_URL2 } = await import("./dist-SD33RKHO.js");
473
+ const { EventSource } = await import("eventsource");
474
+ display.info("Streaming live events \u2014 press Ctrl+C to stop watching");
475
+ const es = new EventSource(`${GATEWAY_BASE_URL2}/events/stream?mission_id=${missionId}`);
476
+ let stopped = false;
477
+ const stop = () => {
478
+ if (stopped) return;
479
+ stopped = true;
480
+ es.close();
481
+ clearInterval(poll);
482
+ };
483
+ es.onmessage = (msg) => {
484
+ try {
485
+ const event = JSON.parse(String(msg.data));
486
+ console.log(` ${chalkTime(event.timestamp)} ${event.source}: ${event.type}`);
487
+ } catch {
488
+ }
489
+ };
490
+ es.onerror = () => {
491
+ };
492
+ const poll = setInterval(() => {
493
+ void gateway2.getMissionStatus(missionId).then((status) => {
494
+ if (status.status !== "running") {
495
+ display.success(`Mission ${status.status}`);
496
+ stop();
497
+ }
498
+ }).catch(() => {
499
+ stop();
500
+ });
501
+ }, 2e3);
502
+ await new Promise((resolve) => {
503
+ const check = setInterval(() => {
504
+ if (stopped) {
505
+ clearInterval(check);
506
+ resolve();
507
+ }
508
+ }, 250);
509
+ });
510
+ });
511
+ mission.command("pause <mission_id>").description("Pause a running mission \u2014 stops live agent runs and freezes their workspaces").action(async (missionId) => {
512
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
513
+ try {
514
+ const result = await gateway2.pauseMission(missionId);
515
+ display.success(
516
+ `Paused mission ${missionId} \u2014 stopped ${String(result.paused_tasks.length)} task(s)`
517
+ );
518
+ for (const skipped of result.skipped_tasks) {
519
+ display.warning(`Task ${skipped.task_id} could not be stopped: ${skipped.reason}`);
520
+ }
521
+ } catch (err) {
522
+ display.gatewayError(err);
523
+ }
524
+ });
525
+ mission.command("resume <mission_id>").description("Resume a paused mission \u2014 relaunches paused tasks with their preserved work").action(async (missionId) => {
526
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
527
+ try {
528
+ const result = await gateway2.resumeMission(missionId);
529
+ const started = result.started_tasks.length > 0 ? `, started ${String(result.started_tasks.length)} newly-ready task(s)` : "";
530
+ display.success(
531
+ `Resumed mission ${missionId} \u2014 relaunched ${String(result.resumed_tasks.length)} task(s)${started}`
532
+ );
533
+ for (const skipped of result.skipped_tasks) {
534
+ display.warning(`Task ${skipped.task_id} not resumed: ${skipped.reason}`);
535
+ }
536
+ } catch (err) {
537
+ display.gatewayError(err);
538
+ }
539
+ });
540
+ }
541
+ function chalkTime(iso) {
542
+ return new Date(iso).toLocaleTimeString();
543
+ }
544
+
545
+ // src/commands/inbox.ts
546
+ function scopeFromOptions(opts) {
547
+ if (opts.always) return "always";
548
+ if (opts.mission) return "mission";
549
+ return "once";
550
+ }
551
+ function registerInboxCommand(program2) {
552
+ program2.command("inbox").description("Show pending approvals, credential failures, and conflicts").action(async () => {
553
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
554
+ try {
555
+ const inbox = await gateway2.getInbox();
556
+ if (inbox.action_requests.length === 0 && inbox.credential_events.length === 0 && inbox.conflicts.length === 0) {
557
+ display.success("Inbox is empty \u2014 no pending items");
558
+ return;
559
+ }
560
+ display.inboxActionRequests(inbox.action_requests);
561
+ display.inboxCredentialEvents(inbox.credential_events);
562
+ display.inboxConflicts(inbox.conflicts);
563
+ } catch (err) {
564
+ display.gatewayError(err);
565
+ }
566
+ });
567
+ program2.command("approve <id>").description("Approve a pending action request").option("--once", "Approve this single occurrence only (default)").option("--mission", "Approve for the rest of the current mission").option("--always", "Always auto-approve this pattern going forward").action(async (id, opts) => {
568
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
569
+ const scope = scopeFromOptions(opts);
570
+ try {
571
+ await gateway2.approve(id, { scope });
572
+ display.success(`Approved ${id} (scope: ${scope})`);
573
+ } catch (err) {
574
+ display.gatewayError(err);
575
+ }
576
+ });
577
+ program2.command("deny <id>").description("Deny a pending action request").action(async (id) => {
578
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
579
+ try {
580
+ await gateway2.deny(id);
581
+ display.success(`Denied ${id}`);
582
+ } catch (err) {
583
+ display.gatewayError(err);
584
+ }
585
+ });
586
+ }
587
+
588
+ // src/commands/workspace.ts
589
+ import chalk2 from "chalk";
590
+ function printDiff(diffText) {
591
+ for (const line of diffText.split("\n")) {
592
+ if (line.startsWith("+") && !line.startsWith("+++")) {
593
+ console.log(chalk2.green(line));
594
+ } else if (line.startsWith("-") && !line.startsWith("---")) {
595
+ console.log(chalk2.red(line));
596
+ } else {
597
+ console.log(chalk2.grey(line));
598
+ }
599
+ }
600
+ }
601
+ function registerWorkspaceCommands(program2) {
602
+ program2.command("diff <task_id>").description("View agent changes for a task").action(async (taskId) => {
603
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
604
+ try {
605
+ const diff = await gateway2.getDiff(taskId);
606
+ if (!diff.diff_text) {
607
+ display.info("No changes yet for this task");
608
+ return;
609
+ }
610
+ printDiff(diff.diff_text);
611
+ } catch (err) {
612
+ display.gatewayError(err);
613
+ }
614
+ });
615
+ program2.command("merge <task_id>").description("Merge approved task work into the base branch").action(async (taskId) => {
616
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
617
+ try {
618
+ const result = await gateway2.mergeTask(taskId);
619
+ display.success(`Merged task ${taskId} (sha: ${result.merged_sha.slice(0, 8)})`);
620
+ } catch (err) {
621
+ display.gatewayError(err);
622
+ }
623
+ });
624
+ program2.command("rollback <task_id>").description("Discard a task's latest run and restore the last clean state").action(async (taskId) => {
625
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
626
+ try {
627
+ const result = await gateway2.rollbackTask(taskId);
628
+ display.success(`Rolled back task ${taskId} to ${result.rolled_back_to_sha.slice(0, 8)}`);
629
+ } catch (err) {
630
+ display.gatewayError(err);
631
+ }
632
+ });
633
+ program2.command("route <task_id>").description("Reroute a task to a different agent").requiredOption("--to <agent_id>", "Target agent ID").action(async (taskId, opts) => {
634
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
635
+ try {
636
+ const result = await gateway2.routeTask(taskId, opts.to);
637
+ display.success(`Routed task ${taskId} to ${opts.to} (new run: ${result.new_run_id})`);
638
+ } catch (err) {
639
+ display.gatewayError(err);
640
+ }
641
+ });
642
+ }
643
+
644
+ // src/commands/context.ts
645
+ import { copyFileSync, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
646
+ import { basename, extname, join as join3 } from "path";
647
+ var CONTEXT_DIR = ".agentos/context";
648
+ function registerContextCommand(program2) {
649
+ const context = program2.command("context").description("Manage the context vault");
650
+ context.command("add <file>").description("Copy a document into the local context vault (.agentos/context/)").action((file) => {
651
+ const cwd = process.cwd();
652
+ if (!existsSync3(file)) {
653
+ display.error(`File not found: ${file}`);
654
+ process.exit(1);
655
+ }
656
+ if (extname(file).toLowerCase() !== ".md") {
657
+ display.error(`Not a Markdown file: ${file}`);
658
+ process.exit(1);
659
+ }
660
+ const destDir = join3(cwd, CONTEXT_DIR);
661
+ mkdirSync3(destDir, { recursive: true });
662
+ const dest = join3(destDir, basename(file));
663
+ copyFileSync(file, dest);
664
+ display.success(`Added ${basename(file)} to context vault`);
665
+ });
666
+ context.command("show <task_id>").description("Show the most recent context pack built for a task (documents, token usage, preview)").action(async (taskId) => {
667
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
668
+ try {
669
+ const pack = await gateway2.getLatestContextPackForTask(taskId);
670
+ display.info(`Context pack ${pack.id} for task ${pack.task_id}`);
671
+ console.log(` documents: ${pack.documents.length > 0 ? pack.documents.join(", ") : "(none)"}`);
672
+ console.log(` tokens used: ${String(pack.tokens_used)} / ${String(pack.token_budget)}`);
673
+ if (pack.content) {
674
+ const preview = pack.content.length > 500 ? `${pack.content.slice(0, 500)}...` : pack.content;
675
+ console.log(" preview:");
676
+ console.log(preview);
677
+ }
678
+ } catch (err) {
679
+ display.gatewayError(err);
680
+ }
681
+ });
682
+ }
683
+
684
+ // src/commands/credentials.ts
685
+ function registerCredentialsCommand(program2) {
686
+ const creds = program2.command("credentials").description("Manage agent credentials");
687
+ creds.command("rotate <agent_id>").description("Rotate the stored credential for an agent (prompts for the new value)").action(async (agentId) => {
688
+ const { default: inquirer } = await import("inquirer");
689
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
690
+ const { credentialValue } = await inquirer.prompt([
691
+ {
692
+ type: "password",
693
+ name: "credentialValue",
694
+ message: `New credential value for agent ${agentId}:`,
695
+ mask: "*"
696
+ }
697
+ ]);
698
+ try {
699
+ const result = await gateway2.rotateCredential(agentId, credentialValue);
700
+ display.success(
701
+ `Rotated credential for ${agentId} \u2014 validated: ${result.validated ? "yes" : "no"}`
702
+ );
703
+ } catch (err) {
704
+ display.gatewayError(err);
705
+ }
706
+ });
707
+ }
708
+
709
+ // src/commands/conflicts.ts
710
+ function registerConflictsCommand(program2) {
711
+ program2.command("conflicts").description("List all active conflicts in the current mission").action(async () => {
712
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
713
+ try {
714
+ const inbox = await gateway2.getInbox();
715
+ display.inboxConflicts(inbox.conflicts);
716
+ } catch (err) {
717
+ display.gatewayError(err);
718
+ }
719
+ });
720
+ }
721
+
722
+ // src/commands/logs.ts
723
+ import chalk3 from "chalk";
724
+ function severityColor(severity) {
725
+ switch (severity) {
726
+ case "warning":
727
+ return chalk3.yellow;
728
+ case "error":
729
+ return chalk3.red;
730
+ case "critical":
731
+ return chalk3.red.bold;
732
+ default:
733
+ return chalk3.grey;
734
+ }
735
+ }
736
+ function sourceLabel(source) {
737
+ if (source === "gateway") return chalk3.grey.italic(source);
738
+ if (source === "user") return chalk3.white(source);
739
+ return chalk3.cyan(source);
740
+ }
741
+ function formatEvent(event) {
742
+ const time = new Date(event.timestamp).toLocaleTimeString();
743
+ const severity = severityColor(event.severity)(`[${event.severity}]`);
744
+ const source = sourceLabel(event.source);
745
+ const prefix = `[${time}] ${severity} ${source}: ${chalk3.bold(event.type)}`;
746
+ if (event.type === "agent.output") {
747
+ const preview = event.payload.content_preview.slice(0, 80);
748
+ return `${prefix} \u2014 "${preview}"`;
749
+ }
750
+ const payload = JSON.stringify(event.payload);
751
+ const truncated = payload.length > 120 ? `${payload.slice(0, 117)}...` : payload;
752
+ return `${prefix} \u2014 ${chalk3.grey(truncated)}`;
753
+ }
754
+ function registerLogsCommand(program2) {
755
+ program2.command("logs").description("Stream or view recent event logs").option("--follow", "Keep streaming live events instead of exiting after the last 50").option("--run <id>", "Filter by run ID").option("--mission <id>", "Filter by mission ID").action(async (opts) => {
756
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
757
+ if (!opts.follow) {
758
+ try {
759
+ const result = await gateway2.listEvents({
760
+ ...opts.run ? { run_id: opts.run } : {},
761
+ ...opts.mission ? { mission_id: opts.mission } : {},
762
+ limit: 50
763
+ });
764
+ if (result.events.length === 0) {
765
+ display.info("No events recorded yet");
766
+ return;
767
+ }
768
+ for (const event of result.events) {
769
+ console.log(formatEvent(event));
770
+ }
771
+ } catch (err) {
772
+ display.gatewayError(err);
773
+ }
774
+ return;
775
+ }
776
+ const { GATEWAY_BASE_URL: GATEWAY_BASE_URL2 } = await import("./dist-SD33RKHO.js");
777
+ const { EventSource } = await import("eventsource");
778
+ const params = new URLSearchParams();
779
+ if (opts.run) params.set("run_id", opts.run);
780
+ if (opts.mission) params.set("mission_id", opts.mission);
781
+ const query = params.toString();
782
+ display.info("Following live events \u2014 press Ctrl+C to stop");
783
+ const es = new EventSource(`${GATEWAY_BASE_URL2}/events/stream${query ? `?${query}` : ""}`);
784
+ es.onmessage = (msg) => {
785
+ try {
786
+ const event = JSON.parse(String(msg.data));
787
+ console.log(formatEvent(event));
788
+ } catch {
789
+ }
790
+ };
791
+ await new Promise(() => {
792
+ });
793
+ });
794
+ }
795
+
796
+ // src/commands/start.ts
797
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
798
+ import { dirname, join as join4 } from "path";
799
+ import { exec } from "child_process";
800
+ import { fileURLToPath } from "url";
801
+ import chalk4 from "chalk";
802
+ var DASHBOARD_URL = `${GATEWAY_BASE_URL}/ui`;
803
+ function registerStartCommand(program2) {
804
+ program2.command("start").description("Start the gateway, open the dashboard, and stream live events").action(runStart);
805
+ }
806
+ async function runStart() {
807
+ const cwd = process.cwd();
808
+ const bundledDashboardPath = join4(dirname(fileURLToPath(import.meta.url)), "../dashboard");
809
+ if (existsSync4(bundledDashboardPath)) {
810
+ process.env.AGENTOS_DASHBOARD_PATH = bundledDashboardPath;
811
+ }
812
+ let gatewayRunning = true;
813
+ try {
814
+ await gateway.health();
815
+ } catch (err) {
816
+ if (!(err instanceof GatewayNotRunningError)) {
817
+ display.gatewayError(err);
818
+ }
819
+ gatewayRunning = false;
820
+ }
821
+ if (!gatewayRunning) {
822
+ await startDaemon();
823
+ }
824
+ const repoRoot = findRepoRoot(cwd);
825
+ const dashboardBuiltInRepo = repoRoot !== null && existsSync4(join4(repoRoot, "apps", "dashboard", "out"));
826
+ const dashboardAvailable = dashboardBuiltInRepo || existsSync4(bundledDashboardPath);
827
+ if (dashboardAvailable) {
828
+ display.success(`Dashboard at ${DASHBOARD_URL}`);
829
+ } else {
830
+ display.warning(
831
+ "Dashboard not available. To enable it:\n pnpm build:dashboard && pnpm build"
832
+ );
833
+ display.info(`Gateway API available at ${GATEWAY_BASE_URL}`);
834
+ display.info("Use the CLI for all operations.");
835
+ }
836
+ console.log(`
837
+ Agent OS v0.2.0
838
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
839
+ Gateway ${GATEWAY_BASE_URL} \u2713
840
+ Dashboard ${DASHBOARD_URL} ${dashboardAvailable ? "\u2713" : "\u2717"}
841
+ Project ${cwd}
842
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
843
+ Streaming live events (Ctrl+C to stop, gateway keeps running)
844
+ `);
845
+ if (dashboardAvailable) {
846
+ openBrowser(DASHBOARD_URL);
847
+ }
848
+ await streamEvents();
849
+ }
850
+ function findRepoRoot(startDir) {
851
+ let dir = startDir;
852
+ for (; ; ) {
853
+ const pkgPath = join4(dir, "package.json");
854
+ if (existsSync4(pkgPath)) {
855
+ try {
856
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
857
+ if (pkg.name === "agent-os") return dir;
858
+ } catch {
859
+ }
860
+ }
861
+ const parent = dirname(dir);
862
+ if (parent === dir) return null;
863
+ dir = parent;
864
+ }
865
+ }
866
+ function openBrowser(url) {
867
+ try {
868
+ const command = process.platform === "win32" ? `start ${url}` : process.platform === "darwin" ? `open ${url}` : `xdg-open ${url}`;
869
+ exec(command, () => {
870
+ });
871
+ } catch {
872
+ }
873
+ }
874
+ function severityColor2(severity) {
875
+ switch (severity) {
876
+ case "warning":
877
+ return chalk4.yellow;
878
+ case "error":
879
+ return chalk4.red;
880
+ case "critical":
881
+ return chalk4.red.bold;
882
+ default:
883
+ return (text) => text;
884
+ }
885
+ }
886
+ function formatEvent2(event) {
887
+ const time = new Date(event.timestamp).toLocaleTimeString("en-GB", { hour12: false });
888
+ const color = severityColor2(event.severity);
889
+ const base = `[${time}] [${color(event.severity)}] ${event.source}: ${event.type}`;
890
+ if (event.type === "agent.output") {
891
+ return `${base} \u2014 ${event.payload.content_preview}`;
892
+ }
893
+ if (event.type === "tool.requested") {
894
+ const line = `\u26A0 ${base} \u2014 risk: ${event.payload.risk_level}
895
+ \u2192 agentos approve ${event.payload.action_request_id} --once`;
896
+ return line;
897
+ }
898
+ const preview = JSON.stringify(event.payload);
899
+ const truncated = preview.length > 120 ? `${preview.slice(0, 117)}...` : preview;
900
+ return `${base} \u2014 ${truncated}`;
901
+ }
902
+ async function streamEvents() {
903
+ const { EventSource } = await import("eventsource");
904
+ const es = new EventSource(`${GATEWAY_BASE_URL}/events/stream`);
905
+ es.onmessage = (msg) => {
906
+ try {
907
+ const event = JSON.parse(String(msg.data));
908
+ console.log(formatEvent2(event));
909
+ } catch {
910
+ }
911
+ };
912
+ process.on("SIGINT", () => {
913
+ console.log("\n Gateway is still running. Use: agentos daemon stop");
914
+ process.exit(0);
915
+ });
916
+ await new Promise(() => {
917
+ });
918
+ }
919
+
920
+ // src/commands/stop.ts
921
+ import { createInterface } from "readline";
922
+ function registerStopCommand(program2) {
923
+ program2.command("stop").description("Stop the Agent OS gateway").action(runStop);
924
+ }
925
+ async function runStop() {
926
+ try {
927
+ await gateway.health();
928
+ } catch (err) {
929
+ if (err instanceof GatewayNotRunningError) {
930
+ display.info("Gateway is not running");
931
+ process.exit(0);
932
+ }
933
+ display.gatewayError(err);
934
+ }
935
+ const runningMissions = await gateway.listMissions("running");
936
+ if (runningMissions.length > 0) {
937
+ const proceed = await confirm("Active mission running. Stop anyway? (y/N) ");
938
+ if (!proceed) {
939
+ process.exit(0);
940
+ }
941
+ }
942
+ stopDaemon();
943
+ display.success("Agent OS stopped");
944
+ }
945
+ function confirm(question) {
946
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
947
+ return new Promise((resolve) => {
948
+ rl.question(question, (answer) => {
949
+ rl.close();
950
+ resolve(answer.trim().toLowerCase() === "y");
951
+ });
952
+ });
953
+ }
954
+
955
+ // src/commands/stop-task.ts
956
+ function registerStopTaskCommand(program2) {
957
+ program2.command("stop-task <task_id>").description("Stop the live agent run on a task \u2014 preserves partial work via a workspace freeze").action(stopTask);
958
+ }
959
+ async function stopTask(taskId) {
960
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
961
+ try {
962
+ const result = await gateway2.stopTask(taskId);
963
+ display.success(`Stopped run ${result.run_id} \u2014 task ${result.task_id} is paused`);
964
+ if (result.workspace_state) {
965
+ display.info(`Workspace frozen (${result.workspace_state}) \u2014 partial work preserved`);
966
+ }
967
+ display.info(`Resume by routing to another agent: agentos route ${taskId} --to <agent_id>`);
968
+ } catch (err) {
969
+ display.gatewayError(err);
970
+ }
971
+ }
972
+
973
+ // src/index.ts
974
+ var program = new Command();
975
+ program.name("agentos").description(
976
+ chalk5.bold("Agent OS") + " \u2014 Personal control plane for AI coding agents"
977
+ ).version("0.2.0", "-v, --version", "Print version").helpOption("-h, --help", "Show help");
978
+ registerInitCommand(program);
979
+ registerDaemonCommand(program);
980
+ registerAgentCommand(program);
981
+ registerMissionCommand(program);
982
+ registerInboxCommand(program);
983
+ registerWorkspaceCommands(program);
984
+ registerContextCommand(program);
985
+ registerCredentialsCommand(program);
986
+ registerConflictsCommand(program);
987
+ registerLogsCommand(program);
988
+ registerStartCommand(program);
989
+ registerStopCommand(program);
990
+ registerStopTaskCommand(program);
991
+ program.command("status").description("Show current mission and agent status").action(async () => {
992
+ const { gateway: gateway2 } = await import("./gateway-client-RSQFHBFE.js");
993
+ const { display: display2 } = await import("./display-ZLPTSJQM.js");
994
+ try {
995
+ const health = await gateway2.health();
996
+ display2.success(
997
+ `Gateway v${health.version} \u2014 ${String(health.active_missions)} active missions, ${String(health.active_agents)} active agents`
998
+ );
999
+ const agents = await gateway2.listAgents();
1000
+ if (agents.length === 0) {
1001
+ display2.info("No agents registered. Run: agentos agent add");
1002
+ return;
1003
+ }
1004
+ display2.agentTable(agents);
1005
+ } catch (err) {
1006
+ display2.gatewayError(err);
1007
+ }
1008
+ });
1009
+ program.exitOverride();
1010
+ try {
1011
+ await program.parseAsync(process.argv);
1012
+ } catch (err) {
1013
+ if (err instanceof Error && err.name === "CommanderError") {
1014
+ process.exit(err.exitCode ?? 1);
1015
+ }
1016
+ console.error(chalk5.red("Unexpected error:"), err);
1017
+ process.exit(1);
1018
+ }