@suwujs/king-ai 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 (104) hide show
  1. package/README.md +96 -0
  2. package/dist/src/agent-config-validation.d.ts +9 -0
  3. package/dist/src/agent-config-validation.js +30 -0
  4. package/dist/src/api.d.ts +4 -0
  5. package/dist/src/api.js +48 -0
  6. package/dist/src/attachments.d.ts +45 -0
  7. package/dist/src/attachments.js +322 -0
  8. package/dist/src/cli.d.ts +20 -0
  9. package/dist/src/cli.js +1697 -0
  10. package/dist/src/config.d.ts +3 -0
  11. package/dist/src/config.js +20 -0
  12. package/dist/src/cron.d.ts +11 -0
  13. package/dist/src/cron.js +65 -0
  14. package/dist/src/daemon.d.ts +36 -0
  15. package/dist/src/daemon.js +373 -0
  16. package/dist/src/engine.d.ts +32 -0
  17. package/dist/src/engine.js +1014 -0
  18. package/dist/src/heartbeat.d.ts +18 -0
  19. package/dist/src/heartbeat.js +28 -0
  20. package/dist/src/host-api.d.ts +40 -0
  21. package/dist/src/host-api.js +59 -0
  22. package/dist/src/host-control.d.ts +48 -0
  23. package/dist/src/host-control.js +1279 -0
  24. package/dist/src/host-export.d.ts +50 -0
  25. package/dist/src/host-export.js +187 -0
  26. package/dist/src/host-feedback.d.ts +78 -0
  27. package/dist/src/host-feedback.js +178 -0
  28. package/dist/src/host-home.d.ts +13 -0
  29. package/dist/src/host-home.js +54 -0
  30. package/dist/src/host-ledger.d.ts +261 -0
  31. package/dist/src/host-ledger.js +554 -0
  32. package/dist/src/host-loop-events.d.ts +69 -0
  33. package/dist/src/host-loop-events.js +288 -0
  34. package/dist/src/host-permission.d.ts +36 -0
  35. package/dist/src/host-permission.js +180 -0
  36. package/dist/src/host-policy.d.ts +15 -0
  37. package/dist/src/host-policy.js +36 -0
  38. package/dist/src/host-run-executor.d.ts +13 -0
  39. package/dist/src/host-run-executor.js +221 -0
  40. package/dist/src/host-run-heartbeat.d.ts +40 -0
  41. package/dist/src/host-run-heartbeat.js +103 -0
  42. package/dist/src/host-run-layout.d.ts +17 -0
  43. package/dist/src/host-run-layout.js +387 -0
  44. package/dist/src/host-run-meta.d.ts +41 -0
  45. package/dist/src/host-run-meta.js +115 -0
  46. package/dist/src/host-run-spec.d.ts +149 -0
  47. package/dist/src/host-run-spec.js +465 -0
  48. package/dist/src/host-runs.d.ts +77 -0
  49. package/dist/src/host-runs.js +195 -0
  50. package/dist/src/host-sdk.d.ts +412 -0
  51. package/dist/src/host-sdk.js +628 -0
  52. package/dist/src/host-server.d.ts +26 -0
  53. package/dist/src/host-server.js +921 -0
  54. package/dist/src/host-timeline.d.ts +24 -0
  55. package/dist/src/host-timeline.js +161 -0
  56. package/dist/src/jsonl.d.ts +13 -0
  57. package/dist/src/jsonl.js +47 -0
  58. package/dist/src/lifecycle.d.ts +5 -0
  59. package/dist/src/lifecycle.js +18 -0
  60. package/dist/src/message-routing.d.ts +32 -0
  61. package/dist/src/message-routing.js +119 -0
  62. package/dist/src/paths.d.ts +19 -0
  63. package/dist/src/paths.js +26 -0
  64. package/dist/src/project-profile.d.ts +49 -0
  65. package/dist/src/project-profile.js +356 -0
  66. package/dist/src/remediation.d.ts +14 -0
  67. package/dist/src/remediation.js +114 -0
  68. package/dist/src/remote-devices.d.ts +41 -0
  69. package/dist/src/remote-devices.js +156 -0
  70. package/dist/src/remote-diagnostics.d.ts +39 -0
  71. package/dist/src/remote-diagnostics.js +199 -0
  72. package/dist/src/remote-ssh.d.ts +39 -0
  73. package/dist/src/remote-ssh.js +129 -0
  74. package/dist/src/run-stream.d.ts +57 -0
  75. package/dist/src/run-stream.js +119 -0
  76. package/dist/src/runner.d.ts +131 -0
  77. package/dist/src/runner.js +1161 -0
  78. package/dist/src/runtime-data.d.ts +68 -0
  79. package/dist/src/runtime-data.js +172 -0
  80. package/dist/src/service.d.ts +114 -0
  81. package/dist/src/service.js +631 -0
  82. package/dist/src/shared-skills.d.ts +26 -0
  83. package/dist/src/shared-skills.js +85 -0
  84. package/dist/src/shim.d.ts +1 -0
  85. package/dist/src/shim.js +64 -0
  86. package/dist/src/skill-check.d.ts +17 -0
  87. package/dist/src/skill-check.js +158 -0
  88. package/dist/src/sse.d.ts +9 -0
  89. package/dist/src/sse.js +36 -0
  90. package/dist/src/team-routing.d.ts +55 -0
  91. package/dist/src/team-routing.js +131 -0
  92. package/dist/src/team-workflow.d.ts +78 -0
  93. package/dist/src/team-workflow.js +253 -0
  94. package/dist/src/text.d.ts +7 -0
  95. package/dist/src/text.js +27 -0
  96. package/dist/src/types.d.ts +98 -0
  97. package/dist/src/types.js +1 -0
  98. package/dist/src/usage.d.ts +116 -0
  99. package/dist/src/usage.js +350 -0
  100. package/dist/src/workspace.d.ts +9 -0
  101. package/dist/src/workspace.js +56 -0
  102. package/dist/src/worktree.d.ts +47 -0
  103. package/dist/src/worktree.js +201 -0
  104. package/package.json +63 -0
@@ -0,0 +1,1697 @@
1
+ #!/usr/bin/env node
2
+ import { cli, command } from "cleye";
3
+ import { pathToFileURL } from "node:url";
4
+ import { CURRENT_VERSION, DEFAULT_SERVER, normalizeCommandName } from "./paths.js";
5
+ import { doPair, doRun, runDoctor } from "./daemon.js";
6
+ import { cleanupWorktrees, installService, isServiceInstalled, prepareWorktrees, printStatus, readRunningState, reloadService, restartService, stopService, tailLogs, uninstallService, watchStatus } from "./service.js";
7
+ import { runSkillCheck } from "./skill-check.js";
8
+ import { runProjectProfile } from "./project-profile.js";
9
+ import { formatUsageExpenses, formatUsageSummary, listUsageExpenses, summarizeAgentUsage, tokenBudgetFromEnv, usagePricingFromEnv } from "./usage.js";
10
+ import { buildUsageRuntimeData, formatProviderCapabilities, formatRuntimeResultsTable, writeUsageRuntimeData } from "./runtime-data.js";
11
+ import { buildHostStatusSnapshot, formatHostStatusSnapshot } from "./host-api.js";
12
+ import { listHostCommands, runHostCommand } from "./host-control.js";
13
+ import { DEFAULT_HOST_SERVER_HOST, hostServerPortFromEnv, serveHostStatus } from "./host-server.js";
14
+ import { scenarioTemplate } from "./team-workflow.js";
15
+ export function commandNameFromArgv(argv0) {
16
+ return normalizeCommandName(argv0);
17
+ }
18
+ export function versionText(commandName, version = CURRENT_VERSION) {
19
+ return `${commandName} ${version}`;
20
+ }
21
+ export function defaultServerForCommand(_commandName) {
22
+ return DEFAULT_SERVER;
23
+ }
24
+ export function hasExplicitServerArg(args) {
25
+ return args.some((arg) => arg === "--server" || arg.startsWith("--server="));
26
+ }
27
+ export function computerHelpText(defaultServer = DEFAULT_SERVER, commandName = "king-ai") {
28
+ return [
29
+ `${commandName} agent computer - run local BYOA agents on THIS machine`,
30
+ "",
31
+ "The daemon talks to a runtime server over HTTP and drives a local agent",
32
+ "engine (Claude Code or Codex). Pair once, then it can run in the background.",
33
+ "",
34
+ "Usage:",
35
+ ` ${commandName} agent computer --pair <code> [--server <url>] [--engine <id>]`,
36
+ ` ${commandName} agent computer [--server <url>] [--tenant <id>]`,
37
+ "",
38
+ "Setup:",
39
+ " --pair <code> pair this machine with the runtime",
40
+ ` --server <url> runtime server URL (default: ${defaultServer})`,
41
+ " --tenant <id> runtime tenant id on multi-tenant GUI servers",
42
+ " --engine <id> force an engine: claude | codex",
43
+ "",
44
+ "Background service:",
45
+ " --install-service install + start the background supervisor",
46
+ " --uninstall-service remove the background supervisor",
47
+ " --restart restart the background service",
48
+ " --stop stop the background service and foreground daemon",
49
+ " --status show pairing + service status",
50
+ " --watch watch running daemon state",
51
+ " --logs tail daemon logs",
52
+ " --prepare-worktrees show planned agent git worktrees from running state",
53
+ " --cleanup-worktrees show removable agent git worktrees from running state",
54
+ " --yes with --prepare-worktrees or --cleanup-worktrees, execute",
55
+ "",
56
+ "Diagnostics:",
57
+ " --doctor check engines, PATH, login/quota",
58
+ " --version, -v print the daemon version",
59
+ " --help, -h show this help",
60
+ "",
61
+ "With no flags it starts the daemon in the foreground (must be paired first)."
62
+ ].join("\n");
63
+ }
64
+ export function normalizeComputerArgs(args) {
65
+ const normalized = [...args];
66
+ if (normalized[1] === "help")
67
+ normalized[1] = "--help";
68
+ if (normalized[1] === "doctor")
69
+ normalized[1] = "--doctor";
70
+ return normalized;
71
+ }
72
+ export function shouldRunAfterPair(serviceInstalled) {
73
+ return !serviceInstalled;
74
+ }
75
+ const computerCommand = command({
76
+ name: "computer",
77
+ flags: {
78
+ help: {
79
+ type: Boolean,
80
+ alias: "h",
81
+ description: "Show help"
82
+ },
83
+ pair: {
84
+ type: String,
85
+ description: "Pairing code from the runtime server"
86
+ },
87
+ server: {
88
+ type: String,
89
+ description: "Runtime server URL",
90
+ default: DEFAULT_SERVER
91
+ },
92
+ tenant: {
93
+ type: String,
94
+ description: "Runtime tenant id for multi-tenant GUI servers"
95
+ },
96
+ engine: {
97
+ type: String,
98
+ description: "Preferred local engine: claude or codex"
99
+ },
100
+ installService: {
101
+ type: Boolean,
102
+ description: "Install and start a background service"
103
+ },
104
+ uninstallService: {
105
+ type: Boolean,
106
+ description: "Remove the background service"
107
+ },
108
+ restart: {
109
+ type: Boolean,
110
+ description: "Restart the background service"
111
+ },
112
+ stop: {
113
+ type: Boolean,
114
+ description: "Stop the background service and tracked foreground daemon"
115
+ },
116
+ status: {
117
+ type: Boolean,
118
+ description: "Print pairing and service status"
119
+ },
120
+ logs: {
121
+ type: Boolean,
122
+ description: "Tail daemon logs"
123
+ },
124
+ watch: {
125
+ type: Boolean,
126
+ description: "Watch running daemon state"
127
+ },
128
+ prepareWorktrees: {
129
+ type: Boolean,
130
+ description: "Show or create planned git worktrees from running daemon state"
131
+ },
132
+ cleanupWorktrees: {
133
+ type: Boolean,
134
+ description: "Show or remove planned git worktrees from running daemon state"
135
+ },
136
+ yes: {
137
+ type: Boolean,
138
+ description: "Confirm creating or removing worktrees"
139
+ },
140
+ doctor: {
141
+ type: Boolean,
142
+ description: "Check local Claude/Codex availability"
143
+ },
144
+ version: {
145
+ type: Boolean,
146
+ alias: "v",
147
+ description: "Print the daemon version"
148
+ }
149
+ },
150
+ help: false
151
+ }, async (argv) => {
152
+ const flags = argv.flags;
153
+ const commandName = commandNameFromArgv(process.argv[1]);
154
+ const explicitServer = hasExplicitServerArg(process.argv.slice(2));
155
+ const selectedServer = explicitServer ? flags.server : defaultServerForCommand(commandName);
156
+ const serverUrl = selectedServer.replace(/\/+$/, "");
157
+ const tenantId = typeof flags.tenant === "string" && flags.tenant.trim() ? flags.tenant.trim() : undefined;
158
+ const engine = flags.engine;
159
+ if (engine && engine !== "claude" && engine !== "codex")
160
+ throw new Error("--engine must be claude or codex");
161
+ if (flags.help) {
162
+ console.log(computerHelpText(selectedServer, commandName));
163
+ return;
164
+ }
165
+ if (flags.version) {
166
+ console.log(versionText(commandName));
167
+ return;
168
+ }
169
+ if (flags.doctor)
170
+ return runDoctor();
171
+ if (flags.status)
172
+ return printStatus(commandName);
173
+ if (flags.watch)
174
+ return watchStatus();
175
+ if (flags.logs)
176
+ return tailLogs(commandName);
177
+ if (flags.prepareWorktrees)
178
+ return prepareWorktrees({ execute: flags.yes });
179
+ if (flags.cleanupWorktrees)
180
+ return cleanupWorktrees({ execute: flags.yes });
181
+ if (flags.restart)
182
+ return restartService(commandName);
183
+ if (flags.stop)
184
+ return stopService(commandName);
185
+ if (flags.uninstallService)
186
+ return uninstallService(commandName);
187
+ if (flags.pair)
188
+ await doPair(flags.pair, serverUrl, engine, tenantId);
189
+ if (flags.installService)
190
+ return installService(explicitServer ? serverUrl : undefined, commandName);
191
+ if (flags.pair) {
192
+ const serviceInstalled = isServiceInstalled(commandName);
193
+ if (serviceInstalled) {
194
+ await reloadService(commandName);
195
+ console.log("re-paired; reloaded the background service with the new config");
196
+ return;
197
+ }
198
+ if (!shouldRunAfterPair(serviceInstalled))
199
+ return;
200
+ }
201
+ return doRun(explicitServer ? serverUrl : undefined, tenantId);
202
+ });
203
+ const agentCommand = command({
204
+ name: "agent",
205
+ parameters: ["[agent arguments...]"],
206
+ flags: {
207
+ help: {
208
+ type: Boolean,
209
+ alias: "h",
210
+ description: "Show help"
211
+ }
212
+ },
213
+ help: false,
214
+ strictFlags: false
215
+ }, async (argv) => {
216
+ void argv;
217
+ await cli({
218
+ name: `${commandNameFromArgv(process.argv[1])} agent`,
219
+ strictFlags: true,
220
+ commands: [computerCommand],
221
+ help: {
222
+ description: "Agent hosting commands"
223
+ }
224
+ }, () => {
225
+ const commandName = commandNameFromArgv(process.argv[1]);
226
+ console.log(`Run \`${commandName} agent --help\` for usage.`);
227
+ }, normalizeComputerArgs(process.argv.slice(3)));
228
+ });
229
+ const skillCheckCommand = command({
230
+ name: "skill-check",
231
+ parameters: ["[skillsDir]"],
232
+ flags: {
233
+ help: {
234
+ type: Boolean,
235
+ alias: "h",
236
+ description: "Show help"
237
+ }
238
+ },
239
+ help: {
240
+ description: "Validate king-ai command references in SKILL.md files"
241
+ }
242
+ }, (argv) => {
243
+ const commandName = commandNameFromArgv(process.argv[1]);
244
+ const skillsDir = argv._.skillsDir || process.cwd();
245
+ runSkillCheck(skillsDir, commandName);
246
+ });
247
+ const projectProfileCommand = command({
248
+ name: "project-profile",
249
+ parameters: ["[path]"],
250
+ flags: {
251
+ help: {
252
+ type: Boolean,
253
+ alias: "h",
254
+ description: "Show help"
255
+ }
256
+ },
257
+ help: {
258
+ description: "Inspect a local repository and render a takeover-ready project profile"
259
+ }
260
+ }, (argv) => {
261
+ const projectPath = argv._.path || process.cwd();
262
+ runProjectProfile(projectPath);
263
+ });
264
+ const usageCommand = command({
265
+ name: "usage",
266
+ parameters: ["[action]"],
267
+ flags: {
268
+ help: {
269
+ type: Boolean,
270
+ alias: "h",
271
+ description: "Show help"
272
+ },
273
+ json: {
274
+ type: Boolean,
275
+ description: "Print structured runtime data JSON"
276
+ },
277
+ out: {
278
+ type: String,
279
+ description: "Output path for `king-ai usage export`"
280
+ },
281
+ results: {
282
+ type: Boolean,
283
+ description: "Print TSV runtime results rows"
284
+ },
285
+ capabilities: {
286
+ type: Boolean,
287
+ description: "Print provider usage capability notes"
288
+ }
289
+ },
290
+ help: {
291
+ description: "Summarize local agent run usage from the running daemon state, list expenses, or export runtime data"
292
+ }
293
+ }, async (argv) => {
294
+ const state = await readRunningState();
295
+ const pricingRules = usagePricingFromEnv();
296
+ const runtimeData = buildUsageRuntimeData(state, { budget: tokenBudgetFromEnv(), pricingRules });
297
+ const usageSummary = summarizeAgentUsage(state?.agents ?? [], tokenBudgetFromEnv(), pricingRules);
298
+ if (argv._.action === "export") {
299
+ const out = await writeUsageRuntimeData(argv.flags.out || "king-ai-runtime-data.json", runtimeData);
300
+ console.log(`usage runtime data written: ${out}`);
301
+ return;
302
+ }
303
+ if (argv._.action === "expenses") {
304
+ const rows = listUsageExpenses(usageSummary);
305
+ if (argv.flags.json) {
306
+ console.log(JSON.stringify({ expenses: rows, usage: usageSummary }, null, 2));
307
+ }
308
+ else {
309
+ console.log(formatUsageExpenses(rows));
310
+ }
311
+ return;
312
+ }
313
+ if (argv.flags.json) {
314
+ console.log(JSON.stringify(runtimeData, null, 2));
315
+ return;
316
+ }
317
+ if (argv.flags.results) {
318
+ console.log(formatRuntimeResultsTable(runtimeData.runtimeResults).trimEnd());
319
+ return;
320
+ }
321
+ const lines = [formatUsageSummary(usageSummary)];
322
+ if (argv.flags.capabilities)
323
+ lines.push(formatProviderCapabilities(runtimeData.providerCapabilities));
324
+ console.log(lines.join("\n"));
325
+ });
326
+ function formatTeamScenario(scenario) {
327
+ return [
328
+ `team scenario: ${scenario.id}`,
329
+ `name: ${scenario.name}`,
330
+ `goal: ${scenario.goal}`,
331
+ `roles: ${scenario.team.roles.map((role) => `${role.id}:${role.template}`).join(", ")}`,
332
+ "tasks:",
333
+ ...scenario.tasks.map((task, index) => {
334
+ const review = task.reviewerRole ? ` reviewerRole=${task.reviewerRole}` : "";
335
+ const deps = task.dependsOn?.length ? ` dependsOn=${task.dependsOn.join(",")}` : "";
336
+ return ` ${index + 1}. ownerRole=${task.ownerRole}${review}${deps} ${task.title}`;
337
+ }),
338
+ "acceptance:",
339
+ ...scenario.acceptance.map((entry) => ` - ${entry}`)
340
+ ].join("\n");
341
+ }
342
+ const teamCommand = command({
343
+ name: "team",
344
+ parameters: ["<scenario>"],
345
+ flags: {
346
+ help: {
347
+ type: Boolean,
348
+ alias: "h",
349
+ description: "Show help"
350
+ },
351
+ json: {
352
+ type: Boolean,
353
+ description: "Print structured team scenario JSON"
354
+ },
355
+ output: {
356
+ type: String,
357
+ description: "Materialize the scenario into this host output directory"
358
+ },
359
+ role: {
360
+ type: String,
361
+ description: "Act as a team role while materializing workflow cards"
362
+ }
363
+ },
364
+ help: {
365
+ description: "Preview or materialize built-in multi-role team workflow scenarios"
366
+ }
367
+ }, async (argv) => {
368
+ const scenarioId = argv._.scenario;
369
+ if (scenarioId !== "repo-takeover" && scenarioId !== "bug-investigation" && scenarioId !== "product-design" && scenarioId !== "release-check" && scenarioId !== "research-brief") {
370
+ throw new Error("team scenario must be repo-takeover, bug-investigation, product-design, release-check, or research-brief");
371
+ }
372
+ const scenario = scenarioTemplate(scenarioId);
373
+ if (argv.flags.output) {
374
+ const result = await materializeTeamScenario(scenario, argv.flags.output, argv.flags.role);
375
+ console.log(argv.flags.json ? JSON.stringify(result, null, 2) : formatMaterializedTeamScenario(result));
376
+ return;
377
+ }
378
+ console.log(argv.flags.json ? JSON.stringify(scenario, null, 2) : formatTeamScenario(scenario));
379
+ });
380
+ export async function materializeTeamScenario(scenario, outputDir, actorRole) {
381
+ const cards = [];
382
+ const initiative = await runHostCommandFromCli({
383
+ command: "initiative-create",
384
+ format: "json",
385
+ actorRole,
386
+ input: {
387
+ outputDir,
388
+ id: `initiative-${scenario.id}`,
389
+ title: scenario.name,
390
+ ownerRole: "planner",
391
+ acceptance: scenario.acceptance,
392
+ detail: scenario.goal
393
+ }
394
+ });
395
+ if (!initiative.ok)
396
+ throw new Error(initiative.error ?? initiative.text);
397
+ cards.push(initiative.json.card);
398
+ for (const [index, task] of scenario.tasks.entries()) {
399
+ const id = `task-${index + 1}`;
400
+ const result = await runHostCommandFromCli({
401
+ command: "workflow-create",
402
+ format: "json",
403
+ actorRole,
404
+ input: {
405
+ outputDir,
406
+ kind: "task",
407
+ id,
408
+ title: task.title,
409
+ status: "assigned",
410
+ ownerRole: task.ownerRole,
411
+ reviewerRole: task.reviewerRole,
412
+ dependsOn: task.dependsOn,
413
+ acceptance: task.acceptance,
414
+ sourceId: `initiative-${scenario.id}`
415
+ }
416
+ });
417
+ if (!result.ok)
418
+ throw new Error(result.error ?? result.text);
419
+ cards.push(result.json.card);
420
+ }
421
+ return { scenario: scenario.id, outputDir, cards };
422
+ }
423
+ export function formatMaterializedTeamScenario(result) {
424
+ return [
425
+ `team scenario materialized: ${result.scenario}`,
426
+ `output: ${result.outputDir}`,
427
+ `workflow cards: ${result.cards.length}`
428
+ ].join("\n");
429
+ }
430
+ const hostStatusCommand = command({
431
+ name: "status",
432
+ flags: {
433
+ help: {
434
+ type: Boolean,
435
+ alias: "h",
436
+ description: "Show help"
437
+ },
438
+ json: {
439
+ type: Boolean,
440
+ description: "Print structured JSON for host applications"
441
+ }
442
+ },
443
+ help: {
444
+ description: "Print the app-facing local host status snapshot"
445
+ }
446
+ }, async (argv) => {
447
+ const state = await readRunningState();
448
+ const snapshot = buildHostStatusSnapshot(state, tokenBudgetFromEnv());
449
+ console.log(argv.flags.json ? JSON.stringify(snapshot, null, 2) : formatHostStatusSnapshot(snapshot));
450
+ });
451
+ const hostServeCommand = command({
452
+ name: "serve",
453
+ flags: {
454
+ help: {
455
+ type: Boolean,
456
+ alias: "h",
457
+ description: "Show help"
458
+ },
459
+ host: {
460
+ type: String,
461
+ description: "Local bind host: 127.0.0.1, ::1, or localhost",
462
+ default: DEFAULT_HOST_SERVER_HOST
463
+ },
464
+ port: {
465
+ type: String,
466
+ description: "Local bind port",
467
+ default: String(hostServerPortFromEnv())
468
+ },
469
+ executeRuns: {
470
+ type: Boolean,
471
+ description: "Automatically consume pending safe host run requests"
472
+ },
473
+ executeRunsInterval: {
474
+ type: String,
475
+ description: "Auto executor polling interval in milliseconds",
476
+ default: "1000"
477
+ }
478
+ },
479
+ help: {
480
+ description: "Run a read-only localhost HTTP server for host applications"
481
+ }
482
+ }, async (argv) => {
483
+ const port = Number.parseInt(argv.flags.port, 10);
484
+ if (!Number.isFinite(port) || port < 0 || port > 65535)
485
+ throw new Error("--port must be between 0 and 65535");
486
+ const executeRunsIntervalMs = Number.parseInt(argv.flags.executeRunsInterval, 10);
487
+ if (!Number.isFinite(executeRunsIntervalMs) || executeRunsIntervalMs < 1)
488
+ throw new Error("--execute-runs-interval must be a positive integer");
489
+ await serveHostStatus({
490
+ host: argv.flags.host,
491
+ port,
492
+ executeRuns: argv.flags.executeRuns,
493
+ executeRunsIntervalMs
494
+ });
495
+ });
496
+ const hostCommandsCommand = command({
497
+ name: "commands",
498
+ flags: {
499
+ help: {
500
+ type: Boolean,
501
+ alias: "h",
502
+ description: "Show help"
503
+ },
504
+ json: {
505
+ type: Boolean,
506
+ description: "Print structured JSON for host applications"
507
+ }
508
+ },
509
+ help: {
510
+ description: "List controlled host commands available to applications"
511
+ }
512
+ }, (argv) => {
513
+ const commands = listHostCommands();
514
+ if (argv.flags.json) {
515
+ console.log(JSON.stringify({ ok: true, commands }, null, 2));
516
+ return;
517
+ }
518
+ console.log(commands.map((entry) => `${entry.name}\t${entry.description}`).join("\n"));
519
+ });
520
+ function runHostCommandFromCli(request) {
521
+ return runHostCommand(request, { recordTimeline: true });
522
+ }
523
+ async function printHostCommandResult(request, json) {
524
+ const result = await runHostCommandFromCli({ ...request, format: json ? "json" : "text" });
525
+ console.log(json ? JSON.stringify(result.json ?? result, null, 2) : result.text);
526
+ if (!result.ok || result.exitCode !== 0)
527
+ process.exitCode = result.exitCode || 1;
528
+ }
529
+ const roleFlag = {
530
+ role: {
531
+ type: String,
532
+ description: "Act as a team role; applies opt-in governance/audit policy (or set KING_AI_TEAM_ROLE)"
533
+ }
534
+ };
535
+ function parseJsonInput(value) {
536
+ if (!value)
537
+ return undefined;
538
+ try {
539
+ return JSON.parse(value);
540
+ }
541
+ catch (err) {
542
+ throw new Error(`--input must be valid JSON: ${err instanceof Error ? err.message : String(err)}`);
543
+ }
544
+ }
545
+ const hostRunCommand = command({
546
+ name: "run",
547
+ parameters: ["<command>"],
548
+ flags: {
549
+ help: {
550
+ type: Boolean,
551
+ alias: "h",
552
+ description: "Show help"
553
+ },
554
+ json: {
555
+ type: Boolean,
556
+ description: "Print structured JSON for host applications"
557
+ },
558
+ input: {
559
+ type: String,
560
+ description: "JSON object input for the host command"
561
+ },
562
+ role: {
563
+ type: String,
564
+ description: "Act as a team role; applies opt-in governance/audit policy (or set KING_AI_TEAM_ROLE)"
565
+ }
566
+ },
567
+ help: {
568
+ description: "Run an allowlisted local host command"
569
+ }
570
+ }, async (argv) => {
571
+ const result = await runHostCommandFromCli({
572
+ command: argv._.command,
573
+ format: argv.flags.json ? "json" : "text",
574
+ input: parseJsonInput(argv.flags.input),
575
+ actorRole: argv.flags.role
576
+ });
577
+ if (argv.flags.json) {
578
+ console.log(JSON.stringify(result, null, 2));
579
+ }
580
+ else {
581
+ console.log(result.text);
582
+ }
583
+ if (!result.ok || result.exitCode !== 0)
584
+ process.exitCode = result.exitCode || 1;
585
+ });
586
+ const hostPlanRunCommand = command({
587
+ name: "plan-run",
588
+ parameters: ["<goal>"],
589
+ flags: {
590
+ help: {
591
+ type: Boolean,
592
+ alias: "h",
593
+ description: "Show help"
594
+ },
595
+ json: {
596
+ type: Boolean,
597
+ description: "Print structured JSON for host applications"
598
+ },
599
+ project: {
600
+ type: String,
601
+ description: "Existing local project directory"
602
+ },
603
+ engine: {
604
+ type: String,
605
+ description: "Preferred local engine: claude or codex"
606
+ },
607
+ model: {
608
+ type: String,
609
+ description: "Model override"
610
+ },
611
+ fastModel: {
612
+ type: String,
613
+ description: "Fast model override"
614
+ },
615
+ loops: {
616
+ type: String,
617
+ description: "Maximum polling loops",
618
+ default: "100"
619
+ },
620
+ infinite: {
621
+ type: Boolean,
622
+ description: "Create an infinite loop plan"
623
+ },
624
+ output: {
625
+ type: String,
626
+ description: "Output directory",
627
+ default: "deliverables"
628
+ },
629
+ roleProfile: {
630
+ type: String,
631
+ description: "Default local role profile: small, engineering, product, or full"
632
+ }
633
+ },
634
+ help: {
635
+ description: "Preview a reproducible host app run request"
636
+ }
637
+ }, async (argv) => {
638
+ const engine = argv.flags.engine;
639
+ if (engine && engine !== "claude" && engine !== "codex")
640
+ throw new Error("--engine must be claude or codex");
641
+ const loops = Number.parseInt(argv.flags.loops, 10);
642
+ if (!Number.isFinite(loops) || loops < 1)
643
+ throw new Error("--loops must be a positive integer");
644
+ const result = await runHostCommandFromCli({
645
+ command: "plan-run",
646
+ format: argv.flags.json ? "json" : "text",
647
+ input: {
648
+ goal: argv._.goal,
649
+ mode: "run",
650
+ projectDir: argv.flags.project,
651
+ roleProfile: argv.flags.roleProfile,
652
+ options: {
653
+ engine,
654
+ model: argv.flags.model,
655
+ fastModel: argv.flags.fastModel,
656
+ loops: argv.flags.infinite ? Infinity : loops,
657
+ loopMode: argv.flags.infinite ? "infinite" : "bounded",
658
+ outputDir: argv.flags.output
659
+ }
660
+ }
661
+ });
662
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
663
+ });
664
+ const hostPreflightCommand = command({
665
+ name: "preflight",
666
+ parameters: ["<goal>"],
667
+ flags: {
668
+ help: {
669
+ type: Boolean,
670
+ alias: "h",
671
+ description: "Show help"
672
+ },
673
+ json: {
674
+ type: Boolean,
675
+ description: "Print structured JSON for host applications"
676
+ },
677
+ project: {
678
+ type: String,
679
+ description: "Existing local project directory"
680
+ },
681
+ engine: {
682
+ type: String,
683
+ description: "Preferred local engine: claude or codex"
684
+ },
685
+ takeover: {
686
+ type: Boolean,
687
+ description: "Preflight a takeover-style run"
688
+ },
689
+ roleProfile: {
690
+ type: String,
691
+ description: "Default local role profile: small, engineering, product, or full"
692
+ }
693
+ },
694
+ help: {
695
+ description: "Check whether a host app run request is ready to launch"
696
+ }
697
+ }, async (argv) => {
698
+ const engine = argv.flags.engine;
699
+ if (engine && engine !== "claude" && engine !== "codex")
700
+ throw new Error("--engine must be claude or codex");
701
+ const result = await runHostCommandFromCli({
702
+ command: "preflight",
703
+ format: argv.flags.json ? "json" : "text",
704
+ input: {
705
+ goal: argv._.goal,
706
+ mode: argv.flags.takeover ? "takeover" : "run",
707
+ projectDir: argv.flags.project,
708
+ roleProfile: argv.flags.roleProfile,
709
+ options: { engine }
710
+ }
711
+ });
712
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
713
+ if (!result.ok || result.exitCode !== 0)
714
+ process.exitCode = result.exitCode || 1;
715
+ });
716
+ const hostPrepareRunLayoutCommand = command({
717
+ name: "prepare-run-layout",
718
+ parameters: ["<goal>"],
719
+ flags: {
720
+ help: {
721
+ type: Boolean,
722
+ alias: "h",
723
+ description: "Show help"
724
+ },
725
+ json: {
726
+ type: Boolean,
727
+ description: "Print structured JSON for host applications"
728
+ },
729
+ project: {
730
+ type: String,
731
+ description: "Existing local project directory"
732
+ },
733
+ engine: {
734
+ type: String,
735
+ description: "Preferred local engine: claude or codex"
736
+ },
737
+ output: {
738
+ type: String,
739
+ description: "Output directory",
740
+ default: "deliverables"
741
+ },
742
+ runId: {
743
+ type: String,
744
+ description: "Stable run id"
745
+ },
746
+ force: {
747
+ type: Boolean,
748
+ description: "Replace an existing prepared layout with the same run id"
749
+ },
750
+ roleProfile: {
751
+ type: String,
752
+ description: "Default local role profile: small, engineering, product, or full"
753
+ }
754
+ },
755
+ help: {
756
+ description: "Materialize a local host run layout after explicit confirmation"
757
+ }
758
+ }, async (argv) => {
759
+ const engine = argv.flags.engine;
760
+ if (engine && engine !== "claude" && engine !== "codex")
761
+ throw new Error("--engine must be claude or codex");
762
+ const result = await runHostCommandFromCli({
763
+ command: "prepare-run-layout",
764
+ format: argv.flags.json ? "json" : "text",
765
+ input: {
766
+ goal: argv._.goal,
767
+ runId: argv.flags.runId,
768
+ projectDir: argv.flags.project,
769
+ roleProfile: argv.flags.roleProfile,
770
+ force: argv.flags.force,
771
+ confirmed: true,
772
+ options: {
773
+ engine,
774
+ outputDir: argv.flags.output
775
+ }
776
+ }
777
+ });
778
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
779
+ if (!result.ok || result.exitCode !== 0)
780
+ process.exitCode = result.exitCode || 1;
781
+ });
782
+ const hostSubmitRunCommand = command({
783
+ name: "submit-run",
784
+ parameters: ["<goal>"],
785
+ flags: {
786
+ help: {
787
+ type: Boolean,
788
+ alias: "h",
789
+ description: "Show help"
790
+ },
791
+ json: {
792
+ type: Boolean,
793
+ description: "Print structured JSON for host applications"
794
+ },
795
+ project: {
796
+ type: String,
797
+ description: "Existing local project directory"
798
+ },
799
+ engine: {
800
+ type: String,
801
+ description: "Preferred local engine: claude or codex"
802
+ },
803
+ model: {
804
+ type: String,
805
+ description: "Model override"
806
+ },
807
+ requestId: {
808
+ type: String,
809
+ description: "Stable app-side request id"
810
+ },
811
+ takeover: {
812
+ type: Boolean,
813
+ description: "Submit a takeover-style run request"
814
+ },
815
+ roleProfile: {
816
+ type: String,
817
+ description: "Default local role profile: small, engineering, product, or full"
818
+ },
819
+ ...roleFlag
820
+ },
821
+ help: {
822
+ description: "Persist a pending host app run request"
823
+ }
824
+ }, async (argv) => {
825
+ const engine = argv.flags.engine;
826
+ if (engine && engine !== "claude" && engine !== "codex")
827
+ throw new Error("--engine must be claude or codex");
828
+ const result = await runHostCommandFromCli({
829
+ command: "submit-run",
830
+ format: argv.flags.json ? "json" : "text",
831
+ actorRole: argv.flags.role,
832
+ input: {
833
+ goal: argv._.goal,
834
+ requestId: argv.flags.requestId,
835
+ mode: argv.flags.takeover ? "takeover" : "run",
836
+ projectDir: argv.flags.project,
837
+ roleProfile: argv.flags.roleProfile,
838
+ options: {
839
+ engine,
840
+ model: argv.flags.model
841
+ }
842
+ }
843
+ });
844
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
845
+ if (!result.ok || result.exitCode !== 0)
846
+ process.exitCode = result.exitCode || 1;
847
+ });
848
+ const hostRunRequestsCommand = command({
849
+ name: "run-requests",
850
+ flags: {
851
+ help: {
852
+ type: Boolean,
853
+ alias: "h",
854
+ description: "Show help"
855
+ },
856
+ json: {
857
+ type: Boolean,
858
+ description: "Print structured JSON for host applications"
859
+ },
860
+ limit: {
861
+ type: String,
862
+ description: "Maximum requests to print",
863
+ default: "20"
864
+ },
865
+ status: {
866
+ type: String,
867
+ description: "Filter by status: pending, running, completed, failed, or cancelled"
868
+ }
869
+ },
870
+ help: {
871
+ description: "List pending host app run requests"
872
+ }
873
+ }, async (argv) => {
874
+ const limit = Number.parseInt(argv.flags.limit, 10);
875
+ if (!Number.isFinite(limit) || limit < 1)
876
+ throw new Error("--limit must be a positive integer");
877
+ const result = await runHostCommandFromCli({
878
+ command: "run-requests",
879
+ format: argv.flags.json ? "json" : "text",
880
+ input: { limit, status: argv.flags.status }
881
+ });
882
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
883
+ });
884
+ const hostRunRequestCommand = command({
885
+ name: "run-request",
886
+ parameters: ["<id>"],
887
+ flags: {
888
+ help: {
889
+ type: Boolean,
890
+ alias: "h",
891
+ description: "Show help"
892
+ },
893
+ json: {
894
+ type: Boolean,
895
+ description: "Print structured JSON for host applications"
896
+ }
897
+ },
898
+ help: {
899
+ description: "Show one host app run request"
900
+ }
901
+ }, async (argv) => {
902
+ const result = await runHostCommandFromCli({
903
+ command: "run-request",
904
+ format: argv.flags.json ? "json" : "text",
905
+ input: { id: argv._.id }
906
+ });
907
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
908
+ if (!result.ok || result.exitCode !== 0)
909
+ process.exitCode = result.exitCode || 1;
910
+ });
911
+ const hostUpdateRunCommand = command({
912
+ name: "update-run",
913
+ parameters: ["<id>", "<status>"],
914
+ flags: {
915
+ help: {
916
+ type: Boolean,
917
+ alias: "h",
918
+ description: "Show help"
919
+ },
920
+ json: {
921
+ type: Boolean,
922
+ description: "Print structured JSON for host applications"
923
+ },
924
+ detail: {
925
+ type: String,
926
+ description: "Short status detail"
927
+ },
928
+ ...roleFlag
929
+ },
930
+ help: {
931
+ description: "Append a lifecycle status update for a host app run request"
932
+ }
933
+ }, async (argv) => {
934
+ const result = await runHostCommandFromCli({
935
+ command: "update-run",
936
+ format: argv.flags.json ? "json" : "text",
937
+ actorRole: argv.flags.role,
938
+ input: {
939
+ id: argv._.id,
940
+ status: argv._.status,
941
+ detail: argv.flags.detail
942
+ }
943
+ });
944
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
945
+ if (!result.ok || result.exitCode !== 0)
946
+ process.exitCode = result.exitCode || 1;
947
+ });
948
+ const hostCancelRunCommand = command({
949
+ name: "cancel-run",
950
+ parameters: ["<id>"],
951
+ flags: {
952
+ help: {
953
+ type: Boolean,
954
+ alias: "h",
955
+ description: "Show help"
956
+ },
957
+ json: {
958
+ type: Boolean,
959
+ description: "Print structured JSON for host applications"
960
+ },
961
+ detail: {
962
+ type: String,
963
+ description: "Short cancellation detail"
964
+ },
965
+ ...roleFlag
966
+ },
967
+ help: {
968
+ description: "Cancel a queued or active host app run request"
969
+ }
970
+ }, async (argv) => {
971
+ const result = await runHostCommandFromCli({
972
+ command: "cancel-run",
973
+ format: argv.flags.json ? "json" : "text",
974
+ actorRole: argv.flags.role,
975
+ input: {
976
+ id: argv._.id,
977
+ detail: argv.flags.detail
978
+ }
979
+ });
980
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
981
+ if (!result.ok || result.exitCode !== 0)
982
+ process.exitCode = result.exitCode || 1;
983
+ });
984
+ const hostExecuteRunCommand = command({
985
+ name: "execute-run",
986
+ parameters: ["[id]"],
987
+ flags: {
988
+ help: {
989
+ type: Boolean,
990
+ alias: "h",
991
+ description: "Show help"
992
+ },
993
+ json: {
994
+ type: Boolean,
995
+ description: "Print structured JSON for host applications"
996
+ },
997
+ ...roleFlag
998
+ },
999
+ help: {
1000
+ description: "Consume one pending host app run request with a safe local executor"
1001
+ }
1002
+ }, async (argv) => {
1003
+ const result = await runHostCommandFromCli({
1004
+ command: "execute-run",
1005
+ format: argv.flags.json ? "json" : "text",
1006
+ actorRole: argv.flags.role,
1007
+ input: argv._.id ? { id: argv._.id } : {}
1008
+ });
1009
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1010
+ if (!result.ok || result.exitCode !== 0)
1011
+ process.exitCode = result.exitCode || 1;
1012
+ });
1013
+ const hostWatchRunCommand = command({
1014
+ name: "watch-run",
1015
+ parameters: ["[id]"],
1016
+ flags: {
1017
+ help: {
1018
+ type: Boolean,
1019
+ alias: "h",
1020
+ description: "Show help"
1021
+ },
1022
+ json: {
1023
+ type: Boolean,
1024
+ description: "Print structured JSON for host applications"
1025
+ },
1026
+ file: {
1027
+ type: String,
1028
+ description: "Path to loop-events.ndjson"
1029
+ },
1030
+ output: {
1031
+ type: String,
1032
+ description: "Run output directory"
1033
+ },
1034
+ tail: {
1035
+ type: String,
1036
+ description: "Maximum events to print",
1037
+ default: "20"
1038
+ },
1039
+ type: {
1040
+ type: String,
1041
+ description: "Filter by loop event type"
1042
+ },
1043
+ agent: {
1044
+ type: String,
1045
+ description: "Filter by agent id or name"
1046
+ },
1047
+ classification: {
1048
+ type: String,
1049
+ description: "Filter by loop classification"
1050
+ }
1051
+ },
1052
+ help: {
1053
+ description: "Read King AI loop events from a host run output"
1054
+ }
1055
+ }, async (argv) => {
1056
+ const tail = Number.parseInt(argv.flags.tail, 10);
1057
+ if (!Number.isFinite(tail) || tail < 1)
1058
+ throw new Error("--tail must be a positive integer");
1059
+ const result = await runHostCommandFromCli({
1060
+ command: "watch-run",
1061
+ format: argv.flags.json ? "json" : "text",
1062
+ input: {
1063
+ id: argv._.id,
1064
+ file: argv.flags.file,
1065
+ outputDir: argv.flags.output,
1066
+ tail,
1067
+ type: argv.flags.type,
1068
+ agent: argv.flags.agent,
1069
+ classification: argv.flags.classification
1070
+ }
1071
+ });
1072
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1073
+ });
1074
+ const hostEmitRunEventCommand = command({
1075
+ name: "emit-run-event",
1076
+ parameters: ["<id>", "<type>"],
1077
+ flags: {
1078
+ help: {
1079
+ type: Boolean,
1080
+ alias: "h",
1081
+ description: "Show help"
1082
+ },
1083
+ json: {
1084
+ type: Boolean,
1085
+ description: "Print structured JSON for host applications"
1086
+ },
1087
+ file: {
1088
+ type: String,
1089
+ description: "Path to loop-events.ndjson"
1090
+ },
1091
+ output: {
1092
+ type: String,
1093
+ description: "Run output directory"
1094
+ },
1095
+ agent: {
1096
+ type: String,
1097
+ description: "Agent id or app source"
1098
+ },
1099
+ loop: {
1100
+ type: String,
1101
+ description: "Loop number"
1102
+ },
1103
+ classification: {
1104
+ type: String,
1105
+ description: "Loop classification"
1106
+ },
1107
+ detail: {
1108
+ type: String,
1109
+ description: "Short event detail"
1110
+ },
1111
+ message: {
1112
+ type: String,
1113
+ description: "Human-readable event message"
1114
+ },
1115
+ payload: {
1116
+ type: String,
1117
+ description: "Optional JSON payload"
1118
+ }
1119
+ },
1120
+ help: {
1121
+ description: "Append an app-facing event to a host run output"
1122
+ }
1123
+ }, async (argv) => {
1124
+ const loop = argv.flags.loop === undefined ? undefined : Number(argv.flags.loop);
1125
+ if (loop !== undefined && (!Number.isFinite(loop) || loop < 0))
1126
+ throw new Error("--loop must be a non-negative number");
1127
+ const payload = argv.flags.payload === undefined ? undefined : JSON.parse(argv.flags.payload);
1128
+ const result = await runHostCommandFromCli({
1129
+ command: "emit-run-event",
1130
+ format: argv.flags.json ? "json" : "text",
1131
+ input: {
1132
+ id: argv._.id,
1133
+ file: argv.flags.file,
1134
+ outputDir: argv.flags.output,
1135
+ type: argv._.type,
1136
+ agent: argv.flags.agent,
1137
+ loop,
1138
+ classification: argv.flags.classification,
1139
+ detail: argv.flags.detail,
1140
+ message: argv.flags.message,
1141
+ payload
1142
+ }
1143
+ });
1144
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1145
+ if (!result.ok || result.exitCode !== 0)
1146
+ process.exitCode = result.exitCode || 1;
1147
+ });
1148
+ const hostRunResultsCommand = command({
1149
+ name: "run-results",
1150
+ parameters: ["[id]"],
1151
+ flags: {
1152
+ help: {
1153
+ type: Boolean,
1154
+ alias: "h",
1155
+ description: "Show help"
1156
+ },
1157
+ json: {
1158
+ type: Boolean,
1159
+ description: "Print structured JSON for host applications"
1160
+ },
1161
+ file: {
1162
+ type: String,
1163
+ description: "Path to loop-events.ndjson"
1164
+ },
1165
+ results: {
1166
+ type: String,
1167
+ description: "Path to results.tsv"
1168
+ },
1169
+ output: {
1170
+ type: String,
1171
+ description: "Run output directory"
1172
+ }
1173
+ },
1174
+ help: {
1175
+ description: "Read King AI results.tsv rows from a host run output"
1176
+ }
1177
+ }, async (argv) => {
1178
+ const result = await runHostCommandFromCli({
1179
+ command: "run-results",
1180
+ format: argv.flags.json ? "json" : "text",
1181
+ input: {
1182
+ id: argv._.id,
1183
+ file: argv.flags.file,
1184
+ resultsFile: argv.flags.results,
1185
+ outputDir: argv.flags.output
1186
+ }
1187
+ });
1188
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1189
+ });
1190
+ const hostRunHeartbeatCommand = command({
1191
+ name: "run-heartbeat",
1192
+ parameters: ["[id]"],
1193
+ flags: {
1194
+ help: {
1195
+ type: Boolean,
1196
+ alias: "h",
1197
+ description: "Show help"
1198
+ },
1199
+ json: {
1200
+ type: Boolean,
1201
+ description: "Print structured JSON for host applications"
1202
+ },
1203
+ file: {
1204
+ type: String,
1205
+ description: "Path to .king-ai/heartbeat.json"
1206
+ },
1207
+ output: {
1208
+ type: String,
1209
+ description: "Run output directory"
1210
+ }
1211
+ },
1212
+ help: {
1213
+ description: "Read a host run heartbeat file"
1214
+ }
1215
+ }, async (argv) => {
1216
+ const result = await runHostCommandFromCli({
1217
+ command: "run-heartbeat",
1218
+ format: argv.flags.json ? "json" : "text",
1219
+ input: {
1220
+ id: argv._.id,
1221
+ file: argv.flags.file,
1222
+ outputDir: argv.flags.output
1223
+ }
1224
+ });
1225
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1226
+ });
1227
+ const hostRunMetaCommand = command({
1228
+ name: "run-meta",
1229
+ parameters: ["[id]"],
1230
+ flags: {
1231
+ help: {
1232
+ type: Boolean,
1233
+ alias: "h",
1234
+ description: "Show help"
1235
+ },
1236
+ json: {
1237
+ type: Boolean,
1238
+ description: "Print structured JSON for host applications"
1239
+ },
1240
+ file: {
1241
+ type: String,
1242
+ description: "Path to meta.json"
1243
+ },
1244
+ output: {
1245
+ type: String,
1246
+ description: "Run output directory"
1247
+ }
1248
+ },
1249
+ help: {
1250
+ description: "Read a host run meta.json file"
1251
+ }
1252
+ }, async (argv) => {
1253
+ const result = await runHostCommandFromCli({
1254
+ command: "run-meta",
1255
+ format: argv.flags.json ? "json" : "text",
1256
+ input: {
1257
+ id: argv._.id,
1258
+ file: argv.flags.file,
1259
+ outputDir: argv.flags.output
1260
+ }
1261
+ });
1262
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1263
+ });
1264
+ function hostExportInputFromFlags(flags) {
1265
+ return {
1266
+ workspaceRoot: flags.workspace,
1267
+ repoRoot: flags.repo,
1268
+ outputDir: flags.output,
1269
+ runId: flags.runId,
1270
+ includeWorkspace: flags.noWorkspace ? false : undefined,
1271
+ includeRepoPatch: flags.noRepoPatch ? false : undefined,
1272
+ capsuleId: flags.capsuleId,
1273
+ capsulesFile: flags.capsulesFile
1274
+ };
1275
+ }
1276
+ const hostPlanExportCommand = command({
1277
+ name: "plan-export",
1278
+ flags: {
1279
+ help: {
1280
+ type: Boolean,
1281
+ alias: "h",
1282
+ description: "Show help"
1283
+ },
1284
+ json: {
1285
+ type: Boolean,
1286
+ description: "Print structured JSON for host applications"
1287
+ },
1288
+ workspace: {
1289
+ type: String,
1290
+ description: "Agent workspace directory to export"
1291
+ },
1292
+ repo: {
1293
+ type: String,
1294
+ description: "Git repository root to export status and patches from"
1295
+ },
1296
+ output: {
1297
+ type: String,
1298
+ description: "Output directory",
1299
+ default: "deliverables"
1300
+ },
1301
+ runId: {
1302
+ type: String,
1303
+ description: "Stable export id"
1304
+ },
1305
+ noWorkspace: {
1306
+ type: Boolean,
1307
+ description: "Do not export workspace files"
1308
+ },
1309
+ noRepoPatch: {
1310
+ type: Boolean,
1311
+ description: "Do not export repository status or patches"
1312
+ },
1313
+ capsuleId: {
1314
+ type: String,
1315
+ description: "Capsule id to include from capsules.jsonl"
1316
+ },
1317
+ capsulesFile: {
1318
+ type: String,
1319
+ description: "Explicit capsules.jsonl path"
1320
+ }
1321
+ },
1322
+ help: {
1323
+ description: "Preview host artifact and repo patch export outputs"
1324
+ }
1325
+ }, async (argv) => {
1326
+ const result = await runHostCommandFromCli({
1327
+ command: "plan-export",
1328
+ format: argv.flags.json ? "json" : "text",
1329
+ input: hostExportInputFromFlags(argv.flags)
1330
+ });
1331
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1332
+ });
1333
+ const hostExportCommand = command({
1334
+ name: "export",
1335
+ flags: {
1336
+ help: {
1337
+ type: Boolean,
1338
+ alias: "h",
1339
+ description: "Show help"
1340
+ },
1341
+ json: {
1342
+ type: Boolean,
1343
+ description: "Print structured JSON for host applications"
1344
+ },
1345
+ workspace: {
1346
+ type: String,
1347
+ description: "Agent workspace directory to export"
1348
+ },
1349
+ repo: {
1350
+ type: String,
1351
+ description: "Git repository root to export status and patches from"
1352
+ },
1353
+ output: {
1354
+ type: String,
1355
+ description: "Output directory",
1356
+ default: "deliverables"
1357
+ },
1358
+ runId: {
1359
+ type: String,
1360
+ description: "Stable export id"
1361
+ },
1362
+ noWorkspace: {
1363
+ type: Boolean,
1364
+ description: "Do not export workspace files"
1365
+ },
1366
+ noRepoPatch: {
1367
+ type: Boolean,
1368
+ description: "Do not export repository status or patches"
1369
+ },
1370
+ capsuleId: {
1371
+ type: String,
1372
+ description: "Capsule id to include from capsules.jsonl"
1373
+ },
1374
+ capsulesFile: {
1375
+ type: String,
1376
+ description: "Explicit capsules.jsonl path"
1377
+ },
1378
+ ...roleFlag
1379
+ },
1380
+ help: {
1381
+ description: "Export host artifacts and repo patches to an output directory"
1382
+ }
1383
+ }, async (argv) => {
1384
+ const result = await runHostCommandFromCli({
1385
+ command: "export",
1386
+ format: argv.flags.json ? "json" : "text",
1387
+ actorRole: argv.flags.role,
1388
+ input: { ...hostExportInputFromFlags(argv.flags), confirmed: true }
1389
+ });
1390
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1391
+ });
1392
+ const hostPolicyCommand = command({
1393
+ name: "policy",
1394
+ parameters: ["<command>"],
1395
+ flags: {
1396
+ help: {
1397
+ type: Boolean,
1398
+ alias: "h",
1399
+ description: "Show help"
1400
+ },
1401
+ json: {
1402
+ type: Boolean,
1403
+ description: "Print structured JSON for host applications"
1404
+ },
1405
+ confirm: {
1406
+ type: Boolean,
1407
+ description: "Include explicit operator confirmation"
1408
+ }
1409
+ },
1410
+ help: {
1411
+ description: "Check host command safety policy"
1412
+ }
1413
+ }, async (argv) => {
1414
+ const result = await runHostCommandFromCli({
1415
+ command: "policy",
1416
+ format: argv.flags.json ? "json" : "text",
1417
+ input: {
1418
+ command: argv._.command,
1419
+ confirmed: argv.flags.confirm
1420
+ }
1421
+ });
1422
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1423
+ if (!result.ok || result.exitCode !== 0)
1424
+ process.exitCode = result.exitCode || 1;
1425
+ });
1426
+ const hostTimelineCommand = command({
1427
+ name: "timeline",
1428
+ flags: {
1429
+ help: {
1430
+ type: Boolean,
1431
+ alias: "h",
1432
+ description: "Show help"
1433
+ },
1434
+ json: {
1435
+ type: Boolean,
1436
+ description: "Print structured JSON for host applications"
1437
+ },
1438
+ limit: {
1439
+ type: String,
1440
+ description: "Maximum events to print",
1441
+ default: "20"
1442
+ },
1443
+ ...roleFlag
1444
+ },
1445
+ help: {
1446
+ description: "Show recent host command audit events"
1447
+ }
1448
+ }, async (argv) => {
1449
+ const limit = Number.parseInt(argv.flags.limit, 10);
1450
+ if (!Number.isFinite(limit) || limit < 1)
1451
+ throw new Error("--limit must be a positive integer");
1452
+ const result = await runHostCommandFromCli({
1453
+ command: "timeline",
1454
+ format: argv.flags.json ? "json" : "text",
1455
+ actorRole: argv.flags.role,
1456
+ input: { limit }
1457
+ });
1458
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1459
+ });
1460
+ const remoteCommonFlags = {
1461
+ json: {
1462
+ type: Boolean,
1463
+ description: "Print structured JSON for host applications"
1464
+ },
1465
+ device: {
1466
+ type: String,
1467
+ description: "Remote test device id or host"
1468
+ },
1469
+ timeout: {
1470
+ type: String,
1471
+ description: "Remote command timeout in milliseconds"
1472
+ },
1473
+ maxOutput: {
1474
+ type: String,
1475
+ description: "Maximum output bytes to keep"
1476
+ }
1477
+ };
1478
+ function remoteInput(flags) {
1479
+ return {
1480
+ ...(flags.device ? { device: flags.device } : {}),
1481
+ ...(flags.timeout ? { timeoutMs: flags.timeout } : {}),
1482
+ ...(flags.maxOutput ? { maxOutputBytes: flags.maxOutput } : {})
1483
+ };
1484
+ }
1485
+ const hostRemoteListCommand = command({
1486
+ name: "remote-list",
1487
+ flags: {
1488
+ help: { type: Boolean, alias: "h", description: "Show help" },
1489
+ json: { type: Boolean, description: "Print structured JSON for host applications" }
1490
+ },
1491
+ help: { description: "List configured remote test devices" }
1492
+ }, async (argv) => {
1493
+ await printHostCommandResult({ command: "remote-list" }, Boolean(argv.flags.json));
1494
+ });
1495
+ const hostRemoteProbeCommand = command({
1496
+ name: "remote-probe",
1497
+ flags: {
1498
+ help: { type: Boolean, alias: "h", description: "Show help" },
1499
+ ...remoteCommonFlags
1500
+ },
1501
+ help: { description: "Probe SSH connectivity for a remote test device" }
1502
+ }, async (argv) => {
1503
+ await printHostCommandResult({ command: "remote-probe", input: remoteInput(argv.flags) }, Boolean(argv.flags.json));
1504
+ });
1505
+ const hostRemoteProfileCommand = command({
1506
+ name: "remote-profile",
1507
+ flags: {
1508
+ help: { type: Boolean, alias: "h", description: "Show help" },
1509
+ ...remoteCommonFlags
1510
+ },
1511
+ help: { description: "Collect a remote test device profile" }
1512
+ }, async (argv) => {
1513
+ await printHostCommandResult({ command: "remote-profile", input: remoteInput(argv.flags) }, Boolean(argv.flags.json));
1514
+ });
1515
+ const hostRemoteRunCommand = command({
1516
+ name: "remote-run",
1517
+ flags: {
1518
+ help: { type: Boolean, alias: "h", description: "Show help" },
1519
+ ...remoteCommonFlags,
1520
+ cmd: { type: String, description: "Shell command to run on the remote test device" }
1521
+ },
1522
+ help: { description: "Run a command on a remote test device" }
1523
+ }, async (argv) => {
1524
+ if (!argv.flags.cmd)
1525
+ throw new Error("--cmd is required");
1526
+ await printHostCommandResult({ command: "remote-run", input: { ...remoteInput(argv.flags), cmd: argv.flags.cmd } }, Boolean(argv.flags.json));
1527
+ });
1528
+ const hostRemoteLogsCommand = command({
1529
+ name: "remote-logs",
1530
+ flags: {
1531
+ help: { type: Boolean, alias: "h", description: "Show help" },
1532
+ ...remoteCommonFlags,
1533
+ app: { type: String, description: "Configured app name" },
1534
+ path: { type: String, description: "Log file path" },
1535
+ tail: { type: String, description: "Number of lines to tail", default: "200" }
1536
+ },
1537
+ help: { description: "Tail logs on a remote test device" }
1538
+ }, async (argv) => {
1539
+ await printHostCommandResult({ command: "remote-logs", input: { ...remoteInput(argv.flags), app: argv.flags.app, path: argv.flags.path, tail: argv.flags.tail } }, Boolean(argv.flags.json));
1540
+ });
1541
+ const hostRemoteFindLogsCommand = command({
1542
+ name: "remote-find-logs",
1543
+ flags: {
1544
+ help: { type: Boolean, alias: "h", description: "Show help" },
1545
+ ...remoteCommonFlags,
1546
+ app: { type: String, description: "Configured app name" },
1547
+ path: { type: String, description: "Log file or directory path" },
1548
+ pattern: { type: String, description: "grep -E pattern to search" },
1549
+ since: { type: String, description: "Human label for the intended time window" },
1550
+ tail: { type: String, description: "Number of matches to keep", default: "200" }
1551
+ },
1552
+ help: { description: "Search logs on a remote test device" }
1553
+ }, async (argv) => {
1554
+ if (!argv.flags.pattern)
1555
+ throw new Error("--pattern is required");
1556
+ await printHostCommandResult({ command: "remote-find-logs", input: { ...remoteInput(argv.flags), app: argv.flags.app, path: argv.flags.path, pattern: argv.flags.pattern, since: argv.flags.since, tail: argv.flags.tail } }, Boolean(argv.flags.json));
1557
+ });
1558
+ const hostRemotePgCommand = command({
1559
+ name: "remote-pg",
1560
+ flags: {
1561
+ help: { type: Boolean, alias: "h", description: "Show help" },
1562
+ ...remoteCommonFlags,
1563
+ db: { type: String, description: "Configured database name", default: "default" },
1564
+ sql: { type: String, description: "SQL to execute through the configured psql command" }
1565
+ },
1566
+ help: { description: "Run PostgreSQL SQL on a remote test device" }
1567
+ }, async (argv) => {
1568
+ if (!argv.flags.sql)
1569
+ throw new Error("--sql is required");
1570
+ await printHostCommandResult({ command: "remote-pg", input: { ...remoteInput(argv.flags), db: argv.flags.db, sql: argv.flags.sql } }, Boolean(argv.flags.json));
1571
+ });
1572
+ const hostRemoteRedisCommand = command({
1573
+ name: "remote-redis",
1574
+ flags: {
1575
+ help: { type: Boolean, alias: "h", description: "Show help" },
1576
+ ...remoteCommonFlags,
1577
+ name: { type: String, description: "Configured Redis name", default: "default" },
1578
+ cmd: { type: String, description: "Redis command arguments" }
1579
+ },
1580
+ help: { description: "Run Redis command on a remote test device" }
1581
+ }, async (argv) => {
1582
+ if (!argv.flags.cmd)
1583
+ throw new Error("--cmd is required");
1584
+ await printHostCommandResult({ command: "remote-redis", input: { ...remoteInput(argv.flags), name: argv.flags.name, cmd: argv.flags.cmd } }, Boolean(argv.flags.json));
1585
+ });
1586
+ const hostWorkflowCommand = command({
1587
+ name: "workflow",
1588
+ parameters: ["<action>"],
1589
+ flags: {
1590
+ help: {
1591
+ type: Boolean,
1592
+ alias: "h",
1593
+ description: "Show help"
1594
+ },
1595
+ json: {
1596
+ type: Boolean,
1597
+ description: "Print structured JSON for host applications"
1598
+ },
1599
+ input: {
1600
+ type: String,
1601
+ description: "JSON input for workflow-create/list/update"
1602
+ },
1603
+ ...roleFlag
1604
+ },
1605
+ help: {
1606
+ description: "Create, list, or update first-class host workflow objects"
1607
+ }
1608
+ }, async (argv) => {
1609
+ const action = argv._.action;
1610
+ const commandName = action === "create" || action === "list" || action === "update"
1611
+ ? `workflow-${action}`
1612
+ : action === "initiative" || action === "handoff" || action === "review" || action === "decision" || action === "artifact"
1613
+ ? `${action}-create`
1614
+ : undefined;
1615
+ if (!commandName)
1616
+ throw new Error("workflow action must be create, list, update, initiative, handoff, review, decision, or artifact");
1617
+ const result = await runHostCommandFromCli({
1618
+ command: commandName,
1619
+ format: argv.flags.json ? "json" : "text",
1620
+ actorRole: argv.flags.role,
1621
+ input: parseJsonInput(argv.flags.input) ?? {}
1622
+ });
1623
+ console.log(argv.flags.json ? JSON.stringify(result.json, null, 2) : result.text);
1624
+ if (!result.ok || result.exitCode !== 0)
1625
+ process.exitCode = result.exitCode || 1;
1626
+ });
1627
+ const hostCommand = command({
1628
+ name: "host",
1629
+ parameters: ["[host arguments...]"],
1630
+ flags: {
1631
+ help: {
1632
+ type: Boolean,
1633
+ alias: "h",
1634
+ description: "Show help"
1635
+ }
1636
+ },
1637
+ help: false,
1638
+ strictFlags: false
1639
+ }, async () => {
1640
+ await cli({
1641
+ name: `${commandNameFromArgv(process.argv[1])} host`,
1642
+ strictFlags: true,
1643
+ commands: [hostStatusCommand, hostServeCommand, hostCommandsCommand, hostRunCommand, hostPlanRunCommand, hostPreflightCommand, hostPrepareRunLayoutCommand, hostSubmitRunCommand, hostRunRequestsCommand, hostRunRequestCommand, hostUpdateRunCommand, hostCancelRunCommand, hostExecuteRunCommand, hostEmitRunEventCommand, hostWatchRunCommand, hostRunResultsCommand, hostRunHeartbeatCommand, hostRunMetaCommand, hostPlanExportCommand, hostExportCommand, hostTimelineCommand, hostPolicyCommand, hostRemoteListCommand, hostRemoteProbeCommand, hostRemoteProfileCommand, hostRemoteRunCommand, hostRemoteLogsCommand, hostRemoteFindLogsCommand, hostRemotePgCommand, hostRemoteRedisCommand, hostWorkflowCommand],
1644
+ help: {
1645
+ description: "Host application integration commands"
1646
+ }
1647
+ }, () => {
1648
+ const commandName = commandNameFromArgv(process.argv[1]);
1649
+ console.log(`Run \`${commandName} host --help\` for usage.`);
1650
+ }, process.argv.slice(3));
1651
+ });
1652
+ async function main() {
1653
+ await cli({
1654
+ name: commandNameFromArgv(process.argv[1]),
1655
+ version: "0.1.0",
1656
+ strictFlags: true,
1657
+ commands: [agentCommand, skillCheckCommand, projectProfileCommand, usageCommand, teamCommand, hostCommand],
1658
+ help: {
1659
+ description: "Local BYOA agent daemon",
1660
+ examples: [
1661
+ `${commandNameFromArgv(process.argv[1])} agent computer --pair abc123 --server https://runtime.example`,
1662
+ `${commandNameFromArgv(process.argv[1])} agent computer --doctor`,
1663
+ `${commandNameFromArgv(process.argv[1])} usage`,
1664
+ `${commandNameFromArgv(process.argv[1])} team repo-takeover --json`,
1665
+ `${commandNameFromArgv(process.argv[1])} host status --json`,
1666
+ `${commandNameFromArgv(process.argv[1])} host run status --json`,
1667
+ `${commandNameFromArgv(process.argv[1])} host plan-run "review this repo" --project . --json`,
1668
+ `${commandNameFromArgv(process.argv[1])} host preflight "review this repo" --project .`,
1669
+ `${commandNameFromArgv(process.argv[1])} host prepare-run-layout "review this repo" --project . --run-id demo`,
1670
+ `${commandNameFromArgv(process.argv[1])} host submit-run "review this repo" --project . --json`,
1671
+ `${commandNameFromArgv(process.argv[1])} host run-requests --json`,
1672
+ `${commandNameFromArgv(process.argv[1])} host emit-run-event demo app.note --message "reviewed"`,
1673
+ `${commandNameFromArgv(process.argv[1])} host watch-run demo --tail 20`,
1674
+ `${commandNameFromArgv(process.argv[1])} host run-results demo --json`,
1675
+ `${commandNameFromArgv(process.argv[1])} host run-heartbeat demo --json`,
1676
+ `${commandNameFromArgv(process.argv[1])} host run-meta demo --json`,
1677
+ `${commandNameFromArgv(process.argv[1])} host execute-run`,
1678
+ `${commandNameFromArgv(process.argv[1])} host plan-export --workspace ./agent-workspace --repo . --json`,
1679
+ `${commandNameFromArgv(process.argv[1])} host timeline --json`,
1680
+ `${commandNameFromArgv(process.argv[1])} host policy export --json`,
1681
+ `${commandNameFromArgv(process.argv[1])} host serve --port 8799`,
1682
+ `${commandNameFromArgv(process.argv[1])} host serve --execute-runs`,
1683
+ `${commandNameFromArgv(process.argv[1])} skill-check ./skills`,
1684
+ `${commandNameFromArgv(process.argv[1])} project-profile .`
1685
+ ]
1686
+ }
1687
+ }, () => {
1688
+ const commandName = commandNameFromArgv(process.argv[1]);
1689
+ console.log(`Run \`${commandName} --help\` for usage.`);
1690
+ });
1691
+ }
1692
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
1693
+ void main().catch((err) => {
1694
+ process.stderr.write(`${commandNameFromArgv(process.argv[1])}: ${err instanceof Error ? err.message : String(err)}\n`);
1695
+ process.exit(70);
1696
+ });
1697
+ }