@indigoai-us/hq-cli 5.162.0 → 5.163.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 (64) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/command-catalog.generated.d.ts +188 -0
  3. package/dist/command-catalog.generated.js +235 -0
  4. package/dist/command-registration-plan.d.ts +7 -0
  5. package/dist/command-registration-plan.js +1 -0
  6. package/dist/commands/agent-enroll.d.ts +6 -1
  7. package/dist/commands/agent-enroll.js +30 -3
  8. package/dist/commands/agents.js +15 -22
  9. package/dist/commands/bot.js +56 -6
  10. package/dist/commands/daemon.d.ts +53 -0
  11. package/dist/commands/daemon.js +554 -0
  12. package/dist/commands/lanes.js +7 -0
  13. package/dist/commands/meetings.js +18 -16
  14. package/dist/commands/mesh.js +9 -0
  15. package/dist/lib/daemon/catalog.d.ts +85 -0
  16. package/dist/lib/daemon/catalog.js +274 -0
  17. package/dist/lib/daemon/config.d.ts +26 -0
  18. package/dist/lib/daemon/config.js +85 -0
  19. package/dist/lib/daemon/handoff.d.ts +53 -0
  20. package/dist/lib/daemon/handoff.js +136 -0
  21. package/dist/lib/daemon/install.d.ts +76 -0
  22. package/dist/lib/daemon/install.js +299 -0
  23. package/dist/lib/daemon/legacy.d.ts +35 -0
  24. package/dist/lib/daemon/legacy.js +120 -0
  25. package/dist/lib/daemon/lock.d.ts +47 -0
  26. package/dist/lib/daemon/lock.js +138 -0
  27. package/dist/lib/daemon/machine-type.d.ts +48 -0
  28. package/dist/lib/daemon/machine-type.js +139 -0
  29. package/dist/lib/daemon/migrate.d.ts +61 -0
  30. package/dist/lib/daemon/migrate.js +238 -0
  31. package/dist/lib/daemon/paths.d.ts +22 -0
  32. package/dist/lib/daemon/paths.js +42 -0
  33. package/dist/lib/daemon/remote-control.d.ts +35 -0
  34. package/dist/lib/daemon/remote-control.js +47 -0
  35. package/dist/lib/daemon/requests.d.ts +24 -0
  36. package/dist/lib/daemon/requests.js +63 -0
  37. package/dist/lib/daemon/run.d.ts +41 -0
  38. package/dist/lib/daemon/run.js +319 -0
  39. package/dist/lib/daemon/supervisor.d.ts +87 -0
  40. package/dist/lib/daemon/supervisor.js +523 -0
  41. package/dist/lib/daemon/updater.d.ts +39 -0
  42. package/dist/lib/daemon/updater.js +103 -0
  43. package/dist/lib/flag-registry.d.ts +7 -1
  44. package/dist/lib/flag-registry.js +8 -0
  45. package/dist/lib/mesh/live/backoff.d.ts +2 -2
  46. package/dist/lib/mesh/live/backoff.js +16 -3
  47. package/dist/lib/mesh/live/daemon/run.d.ts +2 -2
  48. package/dist/lib/mesh/live/daemon/run.js +5 -2
  49. package/dist/lib/mesh/live/flush.d.ts +3 -2
  50. package/dist/lib/mesh/live/flush.js +34 -7
  51. package/dist/lib/mesh/live/session-events-client.d.ts +2 -0
  52. package/dist/lib/mesh/live/session-events-client.js +25 -0
  53. package/dist/lib/service-manager/systemd.d.ts +2 -2
  54. package/dist/lib/service-manager/systemd.js +1 -1
  55. package/dist/lib/service-manager/types.d.ts +2 -0
  56. package/dist/main.d.ts +6 -0
  57. package/dist/main.js +53 -13
  58. package/dist/utils/cognito-session.d.ts +4 -0
  59. package/dist/utils/cognito-session.js +11 -10
  60. package/dist/utils/plan-gate-error.d.ts +27 -13
  61. package/dist/utils/plan-gate-error.js +133 -58
  62. package/dist/utils/self-update.d.ts +9 -0
  63. package/dist/utils/self-update.js +15 -2
  64. package/package.json +1 -1
@@ -39,8 +39,10 @@ import { DEFAULT_COGNITO, ensureCognitoToken, resolveDefaultHqRoot, } from "../u
39
39
  import { peekHqApiKey } from "../utils/resolve-vault-credential.js";
40
40
  import { getCompanyUid, resolveCallerPersonUid } from "../utils/vault-api.js";
41
41
  import { resolveHqBinary } from "../lib/mesh/live/daemon/install.js";
42
+ import { askDaemonToStart, askDaemonToStop, daemonOwnsProcess, daemonSupervises, daemonWillSupervise, handOffInstallHere, } from "../lib/daemon/handoff.js";
43
+ import { daemonPaths } from "../lib/daemon/paths.js";
42
44
  import { runtimeDisplayName } from "../lib/bot/runtime-sign-in.js";
43
- import { BotApi, BotApiError, BOT_RESTORE_DEFAULTS, buildBotLocalConfig, describeBotLocalConfig, orphanBotRunMessage, parseBotLocalConfig, removeOrphanBotDaemon, botDaemonStatus, botDir, botCredsPath, botLogPath, botsRoot, botTokenStateDir, botWorkerRelDir, buildBotDaemonPaths, createBotLogger, deleteBotCreds, installBotDaemon, repairBotDaemonIfStale, introDmText, isBotMemoryMode, botLocalMemoryDir, botMemoryMode, resolveBotMemoryDir, validateBotIntro, validateBotKickoff, validateBotEffort, validateBotModel, effectiveBotEffort, BOT_EFFORT_LEVELS, DEFAULT_BOT_EFFORT, BOT_MEMORY_MODES, BOT_KINDS, isBotKind, effectiveBotKind, effectiveBotCompanies, normalizeBotCompanies, SETUP_BOT_WORKER_ID, isBotRuntimeId, localNameForRemoteBot, remoteBotRunnability, isPidAlive, listBotWorkerOptions, patchBotConfig, readBotConfig, readBotCredsIdentity, readBotStatus, resolveBotWorker, runBot, runtimeFor, scaffoldBotMemory, scaffoldBotWorker, startBotDaemon, stopBotDaemon, uninstallBotDaemon, validateBotName, writeBotConfig, writeBotCreds, BOT_RUNTIMES, BOT_INTRO_MAX_CHARS, BOT_KICKOFF_MAX_CHARS, } from "../lib/bot/index.js";
45
+ import { BotApi, BotApiError, BOT_RESTORE_DEFAULTS, buildBotLocalConfig, describeBotLocalConfig, orphanBotRunMessage, parseBotLocalConfig, removeOrphanBotDaemon, botDaemonStatus, botDir, botCredsPath, botLogPath, botsRoot, botTokenStateDir, botWorkerRelDir, buildBotDaemonPaths, createBotLogger, deleteBotCreds, installBotDaemon, repairBotDaemonIfStale, introDmText, isBotMemoryMode, botLocalMemoryDir, botMemoryMode, resolveBotMemoryDir, validateBotIntro, validateBotKickoff, validateBotEffort, validateBotModel, effectiveBotEffort, BOT_EFFORT_LEVELS, DEFAULT_BOT_EFFORT, BOT_MEMORY_MODES, BOT_KINDS, isBotKind, effectiveBotKind, effectiveBotCompanies, normalizeBotCompanies, SETUP_BOT_WORKER_ID, isBotRuntimeId, localNameForRemoteBot, remoteBotRunnability, isPidAlive, listBotWorkerOptions, patchBotConfig, readBotConfig, readBotCredsIdentity, readBotStatus, resolveBotWorker, runBot, runtimeFor, scaffoldBotMemory, scaffoldBotWorker, startBotDaemon, stopBotDaemon, uninstallBotDaemon, validateBotName, writeBotConfig, writeBotCreds, BOT_RUNTIMES, BOT_INTRO_MAX_CHARS, BOT_KICKOFF_MAX_CHARS, detectBotPlatform, } from "../lib/bot/index.js";
44
46
  function collectRepeated(value, previous) {
45
47
  return [...previous, value];
46
48
  }
@@ -74,6 +76,13 @@ export const RESERVED_SETUP_BOT_NAME = "setup";
74
76
  function daemonDeps() {
75
77
  return process.platform === "darwin" ? { launchctl: defaultLaunchctl } : {};
76
78
  }
79
+ /** Install the bot's LaunchAgent, unless `hq daemon` runs local bots on this machine. */
80
+ function installBotAgent(p) {
81
+ const handedOff = handOffInstallHere(["bots"]);
82
+ if (handedOff)
83
+ return { platform: detectBotPlatform(), action: "install", installed: true, loaded: true, message: handedOff };
84
+ return installBotDaemon(p, daemonDeps());
85
+ }
77
86
  export function listBotNames(root) {
78
87
  if (!fs.existsSync(root))
79
88
  return [];
@@ -252,8 +261,22 @@ async function startBot(name, dir, config, output, extra = {}) {
252
261
  patchBotConfig(dir, { enabled: true });
253
262
  const paths = buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot });
254
263
  const d = botDaemonStatus(paths, daemonDeps());
264
+ const hqDaemon = daemonPaths();
255
265
  let how;
256
- if (d.installed && process.platform === "darwin") {
266
+ // A bot created since the daemon last read its plan is the daemon's too,
267
+ // unless its own LaunchAgent runs it.
268
+ if (daemonSupervises(hqDaemon, `bots:${name}`) || (!d.installed && daemonWillSupervise(hqDaemon, `bots:${name}`))) {
269
+ // `hq daemon` runs this bot; starting a copy here would run it twice.
270
+ const before = readBotStatus(dir);
271
+ if (before && isPidAlive(before.pid) && before.state === "running") {
272
+ how = `already running under hq daemon (pid ${before.pid})`;
273
+ }
274
+ else {
275
+ askDaemonToStart(hqDaemon, `bots:${name}`);
276
+ how = "started by hq daemon";
277
+ }
278
+ }
279
+ else if (d.installed && process.platform === "darwin") {
257
280
  repairBotDaemonIfStale(paths, daemonDeps());
258
281
  const r = startBotDaemon(paths, daemonDeps());
259
282
  how = r.message;
@@ -298,6 +321,33 @@ async function stopBot(name, dir, config, output) {
298
321
  if (hasPromotionHold(dir))
299
322
  throw new Error("This bot is held for cloud promotion. Continue its promotion before changing local settings or lifecycle.");
300
323
  const paths = buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot });
324
+ const hqDaemon = daemonPaths();
325
+ const before = readBotStatus(dir);
326
+ const wasRunning = !!before && isPidAlive(before.pid);
327
+ const supervised = daemonSupervises(hqDaemon, `bots:${name}`);
328
+ // Keep the daemon's copy down either way, so it does not start one as soon as this bot is gone.
329
+ if (supervised)
330
+ askDaemonToStop(hqDaemon, `bots:${name}`);
331
+ // A bot started before the daemon is not the daemon's child; stop it directly below.
332
+ if (supervised && (!wasRunning || daemonOwnsProcess(hqDaemon, `bots:${name}`, before.pid))) {
333
+ // The daemon stops it (escalating to SIGKILL itself) and keeps it down; a
334
+ // kill from here would look like a crash and be restarted.
335
+ const gone = await waitFor(() => {
336
+ const s = readBotStatus(dir);
337
+ return !s || !isPidAlive(s.pid);
338
+ }, 20_000);
339
+ if (output === "silent")
340
+ return;
341
+ if (output === "json") {
342
+ console.log(JSON.stringify({ ok: gone, name, signalled: wasRunning, stopped: gone, how: "stopped by hq daemon" }, null, 2));
343
+ return;
344
+ }
345
+ if (gone)
346
+ console.log(chalk.green(`${name} stopped`) + chalk.dim(" (by hq daemon)"));
347
+ else
348
+ console.log(chalk.yellow(`${name} did not stop within 20s`) + chalk.dim(` (logs: hq daemon logs bots:${name})`));
349
+ return;
350
+ }
301
351
  if (process.platform === "darwin")
302
352
  stopBotDaemon(paths, daemonDeps());
303
353
  const signalled = stopProcess(dir);
@@ -540,7 +590,7 @@ export async function runBotCreate(nameArg, opts) {
540
590
  };
541
591
  let daemonMessage = null;
542
592
  if (opts.daemon !== false && process.platform === "darwin") {
543
- const r = installBotDaemon(buildBotDaemonPaths({ name, botDir: dir, hqRoot }), daemonDeps());
593
+ const r = installBotAgent(buildBotDaemonPaths({ name, botDir: dir, hqRoot }));
544
594
  daemonMessage = r.message;
545
595
  }
546
596
  if (!opts.json) {
@@ -1304,7 +1354,7 @@ async function adoptRemoteBot(input) {
1304
1354
  createBotLogger(dir)("info", `adopted ${name} (${bot.agentUid}) on ${localMachineId()} kind=${config.kind}${local ? "" : " (no saved settings; defaults)"} runtime=${config.runtime}`);
1305
1355
  let daemonMessage = null;
1306
1356
  if (input.daemon && process.platform === "darwin") {
1307
- daemonMessage = installBotDaemon(buildBotDaemonPaths({ name, botDir: dir, hqRoot: input.hqRoot }), daemonDeps()).message;
1357
+ daemonMessage = installBotAgent(buildBotDaemonPaths({ name, botDir: dir, hqRoot: input.hqRoot })).message;
1308
1358
  }
1309
1359
  return {
1310
1360
  config,
@@ -1407,7 +1457,7 @@ async function repairLocalBot(name, api, bot, daemon) {
1407
1457
  });
1408
1458
  createBotLogger(dir)("info", `re-issued machine credentials for ${name} (${bot.agentUid}) on ${localMachineId()}`);
1409
1459
  if (daemon && process.platform === "darwin") {
1410
- installBotDaemon(buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot }), daemonDeps());
1460
+ installBotAgent(buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot }));
1411
1461
  }
1412
1462
  return "new credentials, startup agent reinstalled";
1413
1463
  }
@@ -1694,7 +1744,7 @@ export function registerBotCommand(program) {
1694
1744
  .option("--json", "Print machine-readable JSON")
1695
1745
  .action((name, opts) => wrap(async () => {
1696
1746
  const b = requireBot(name);
1697
- const r = installBotDaemon(buildBotDaemonPaths({ name: b.name, botDir: b.dir, hqRoot: b.config.hqRoot }), daemonDeps());
1747
+ const r = installBotAgent(buildBotDaemonPaths({ name: b.name, botDir: b.dir, hqRoot: b.config.hqRoot }));
1698
1748
  console.log(opts.json ? JSON.stringify({ ok: r.installed, ...r }, null, 2) : r.message);
1699
1749
  })());
1700
1750
  daemon
@@ -0,0 +1,53 @@
1
+ /**
2
+ * `hq daemon` — one supervisor for every HQ background service on a machine.
3
+ *
4
+ * hq daemon status (same as `hq daemon status`)
5
+ * hq daemon install detect the machine type, install the one OS unit
6
+ * hq daemon run what the OS unit runs; starts the default services
7
+ * hq daemon status [--json]
8
+ * hq daemon logs [unit] [--follow] [--lines N]
9
+ * hq daemon restart [unit] | trigger <unit>
10
+ * hq daemon enable|disable <service...> per-machine overrides
11
+ * hq daemon migrate list the older units it would take over (read-only)
12
+ * hq daemon uninstall [--purge]
13
+ *
14
+ * Hidden from `hq --help` while it rolls out.
15
+ */
16
+ import type { Command } from "commander";
17
+ import { type LegacyUnit } from "../lib/daemon/legacy.js";
18
+ import type { RunCommand } from "../lib/service-manager/launchd.js";
19
+ export interface DaemonCommandDeps {
20
+ env: NodeJS.ProcessEnv;
21
+ home: string;
22
+ platform: NodeJS.Platform;
23
+ out: (line: string) => void;
24
+ err: (line: string) => void;
25
+ run: RunCommand;
26
+ nodeBinary: string;
27
+ hqBinary: string;
28
+ uid: number;
29
+ isRoot: boolean;
30
+ fileExists: (p: string) => boolean;
31
+ readFile: (p: string) => string;
32
+ legacyUnits: () => LegacyUnit[];
33
+ resolveHqRoot: (flag: string | undefined) => string | undefined;
34
+ /** Home folder of the login user a box's system unit runs as. */
35
+ userHome: (user: string) => string;
36
+ /** The pid is a live `hq daemon run`. */
37
+ daemonAlive: (pid: number) => boolean;
38
+ windowsUser?: string;
39
+ windowsHeadlessLauncher?: string;
40
+ systemUnitDir?: string;
41
+ }
42
+ /**
43
+ * The HQ folder install records: --hq-root, else the CLI's shared resolution
44
+ * (HQ_ROOT, the tree around the current folder, the folder the installer or
45
+ * menubar recorded, the well-known locations). Undefined when none resolves.
46
+ */
47
+ export declare function resolveDaemonHqRoot(flag: string | undefined, where: {
48
+ env: NodeJS.ProcessEnv;
49
+ cwd: string;
50
+ home: string;
51
+ }): string | undefined;
52
+ export declare function registerDaemonCommand(program: Command, over?: Partial<DaemonCommandDeps>): Command;
53
+ //# sourceMappingURL=daemon.d.ts.map