@indigoai-us/hq-cli 5.180.0 → 5.182.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.182.0] — 2026-09-24
6
+
7
+ ### Fixed
8
+
9
+ - `hq mesh daemon status` now asks the service manager whether the daemon is loaded (`launchctl print` on macOS, `systemctl --user is-active` on Linux). Before, it never probed and always reported "installed (not loaded)" or "installed (inactive)", even while the daemon was running.
10
+
11
+ ## [5.181.0] — 2026-09-24
12
+
13
+ ### Changed
14
+
15
+ - `hq daemon` runs the session host from the hq-cloud copy it keeps up to date (hq-cloud's `hq-outpost-session-host`, when that copy has it), the same way it already runs sync and the outpost heartbeat, and restarts it after an hq-cloud update. Session-host fixes, such as starting on an Outpost that signs in with machine credentials, now reach boxes without an hq CLI release.
16
+
5
17
  ## [5.180.0] — 2026-09-24
6
18
 
7
19
  ## [5.179.1] — 2026-09-24
@@ -432,7 +432,7 @@ async function runServiceSelfUpdate(d) {
432
432
  updateCli: cliSelfUpdatable() ? () => daemonSelfUpdate({ env }) : null,
433
433
  tools: TOOL_NAMES.map((name) => hostToolUpdater(name, env, d.home)),
434
434
  updateHqCloud: async () => updateManagedHqCloud(paths.root, env),
435
- hqCloudUnits: hqCloudUnits(detected.type),
435
+ hqCloudUnits: hqCloudUnits(detected.type, enabledServices(detected.type, readDaemonConfig(paths.configPath))),
436
436
  requestDaemonRestart: () => writeControlRequest(paths.requestsDir, { action: "restart-daemon" }),
437
437
  requestRestart: (unit) => writeControlRequest(paths.requestsDir, { action: "restart", unit }),
438
438
  log: d.out,
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import { Command } from "commander";
9
9
  import { type MeshCompany, type MeshThread } from "../lib/mesh/api.js";
10
+ import { type DaemonInstallPlatform, type InstallPaths } from "../lib/mesh/live/daemon/index.js";
11
+ import { type RunCommand } from "../lib/service-manager/launchd.js";
10
12
  export declare function formatCheckLines(threads: MeshThread[], company: MeshCompany, projectId?: string): string[];
11
13
  /** Injectable confirmation seam for `hq mesh context correct` (stubbed in tests). */
12
14
  export type MeshConfirmFn = (message: string) => Promise<boolean>;
@@ -24,4 +26,13 @@ export declare function runContextCorrect(opts: {
24
26
  confirm?: MeshConfirmFn;
25
27
  }): Promise<void>;
26
28
  export declare function registerMeshCommand(program: Command): void;
29
+ export declare function runDaemonStatus(opts: {
30
+ json?: boolean;
31
+ }, deps?: {
32
+ platform?: DaemonInstallPlatform;
33
+ paths?: InstallPaths;
34
+ /** launchctl/systemctl runner for the loaded probe (tests inject). */
35
+ run?: RunCommand;
36
+ uid?: number;
37
+ }): Promise<void>;
27
38
  //# sourceMappingURL=mesh.d.ts.map
@@ -35,7 +35,7 @@ import { generateUlid } from "../lib/mesh/live/ulid.js";
35
35
  import { readLegacyBacklog } from "../lib/mesh/live/emit-replay.js";
36
36
  import { resolveMeshEmitMode, writeMeshConfigMode, } from "../lib/mesh/live/daemon/mode.js";
37
37
  import { workMeshRoot } from "../lib/mesh/live/paths.js";
38
- import { buildInstallPaths, collectDaemonDoctor, daemonServiceStatus, findAncestorHqRoot, resolveInstallHqRoot, detectPlatform, formatCliIdentityLines, formatDaemonDoctor, installDaemonIfStale, installDaemonService, readDaemonState, resolveAbsoluteNodeBinary, resolveRunningCliEntry, runMeshDaemon, uninstallDaemonService, daemonDir, } from "../lib/mesh/live/daemon/index.js";
38
+ import { buildInstallPaths, collectDaemonDoctor, daemonServiceIsLoaded, daemonServiceStatus, findAncestorHqRoot, resolveInstallHqRoot, detectPlatform, formatCliIdentityLines, formatDaemonDoctor, installDaemonIfStale, installDaemonService, readDaemonState, resolveAbsoluteNodeBinary, resolveRunningCliEntry, runMeshDaemon, uninstallDaemonService, } from "../lib/mesh/live/daemon/index.js";
39
39
  import { defaultRunCommand } from "../lib/service-manager/launchd.js";
40
40
  import { workContextRoot } from "../lib/work-context/paths.js";
41
41
  import { formatMigrateConfirmation, submitSessionMigration, } from "../lib/work-context/migrate.js";
@@ -2122,12 +2122,14 @@ async function runDaemonUninstall(opts) {
2122
2122
  }
2123
2123
  console.log(result.message);
2124
2124
  }
2125
- async function runDaemonStatus(opts) {
2125
+ export async function runDaemonStatus(opts, deps = {}) {
2126
+ const paths = deps.paths ?? buildInstallPaths({});
2126
2127
  const result = daemonServiceStatus({
2127
- platform: detectPlatform(),
2128
- paths: buildInstallPaths({}),
2128
+ platform: deps.platform ?? detectPlatform(),
2129
+ paths,
2130
+ isLoaded: daemonServiceIsLoaded(deps.run ?? defaultRunCommand, deps.uid),
2129
2131
  });
2130
- const state = readDaemonState(daemonDir());
2132
+ const state = readDaemonState(paths.daemonDir);
2131
2133
  const presenceRefusal = state?.presenceRefusal ?? null;
2132
2134
  if (opts.json) {
2133
2135
  console.log(JSON.stringify({
@@ -64,6 +64,8 @@ export interface PlanContext {
64
64
  syncRunnerPath: string | null;
65
65
  /** hq-cloud's `hq-outpost-heartbeat` bin, when the hq-cloud in use has one. */
66
66
  heartbeatRunnerPath: string | null;
67
+ /** hq-cloud's `hq-outpost-session-host` bin, when the hq-cloud in use has one. */
68
+ sessionHostRunnerPath: string | null;
67
69
  signedIn: boolean;
68
70
  /** ~/.hq-agent/kit.json exists. */
69
71
  kitConfigured: boolean;
@@ -89,11 +91,12 @@ export interface PlanContext {
89
91
  codexRunnerScript: string | null;
90
92
  }
91
93
  /**
92
- * The units that run hq-cloud's code on a machine type, restarted after the
93
- * updater installs a new hq-cloud. Only outposts and self-hosted machines run
94
- * the outpost heartbeat; agent machines run the agent kit's own.
94
+ * The units that run hq-cloud's code on this host, restarted after the updater
95
+ * installs a new hq-cloud. Only outposts and self-hosted machines run the
96
+ * outpost heartbeat (agent machines run the agent kit's own); the session host
97
+ * is included wherever it is enabled.
95
98
  */
96
- export declare function hqCloudUnits(machineType: MachineType): ServiceName[];
99
+ export declare function hqCloudUnits(machineType: MachineType, enabled: readonly ServiceName[]): ServiceName[];
97
100
  /** Written by outpost provisioning; the daemon runs it rather than re-implementing Codex login and relay setup. */
98
101
  export declare const CODEX_RUNNER_SCRIPT = "/usr/local/bin/outpost-codex-runner.sh";
99
102
  /** The outpost's Claude runner script, read for the session name it uses. */
@@ -97,12 +97,18 @@ function firstBlock(checks) {
97
97
  return hit ? { state: "waiting", reason: hit[1] } : undefined;
98
98
  }
99
99
  /**
100
- * The units that run hq-cloud's code on a machine type, restarted after the
101
- * updater installs a new hq-cloud. Only outposts and self-hosted machines run
102
- * the outpost heartbeat; agent machines run the agent kit's own.
100
+ * The units that run hq-cloud's code on this host, restarted after the updater
101
+ * installs a new hq-cloud. Only outposts and self-hosted machines run the
102
+ * outpost heartbeat (agent machines run the agent kit's own); the session host
103
+ * is included wherever it is enabled.
103
104
  */
104
- export function hqCloudUnits(machineType) {
105
- return machineType === "outpost" || machineType === "self-hosted" ? ["sync", "heartbeat"] : ["sync"];
105
+ export function hqCloudUnits(machineType, enabled) {
106
+ const units = ["sync"];
107
+ if (machineType === "outpost" || machineType === "self-hosted")
108
+ units.push("heartbeat");
109
+ if (enabled.includes("session-host"))
110
+ units.push("session-host");
111
+ return units;
106
112
  }
107
113
  /** Written by outpost provisioning; the daemon runs it rather than re-implementing Codex login and relay setup. */
108
114
  export const CODEX_RUNNER_SCRIPT = "/usr/local/bin/outpost-codex-runner.sh";
@@ -181,7 +187,10 @@ function planService(service, ctx) {
181
187
  case "session-host":
182
188
  return [
183
189
  base(service, {
184
- command: { type: "hq", args: ["outposts", "session-host"] },
190
+ // hq-cloud's own session host picks up hq-cloud updates without a CLI release.
191
+ command: ctx.sessionHostRunnerPath
192
+ ? { type: "node", script: ctx.sessionHostRunnerPath, args: [] }
193
+ : { type: "hq", args: ["outposts", "session-host"] },
185
194
  env: ctx.hqRoot ? { HQ_ROOT: ctx.hqRoot } : {},
186
195
  blocked: firstBlock([[!ctx.signedIn, NOT_SIGNED_IN]]),
187
196
  }),
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Which hq-cloud the daemon runs sync and the outpost heartbeat from.
2
+ * Which hq-cloud the daemon runs sync, the outpost heartbeat and the session host from.
3
3
  *
4
4
  * The hq CLI ships with a copy of hq-cloud, but hq-cloud releases more often
5
5
  * than the CLI. The updater keeps a newer copy of the same major version in
@@ -27,6 +27,8 @@ export interface HqCloudRunners {
27
27
  syncRunner: string | null;
28
28
  /** `hq-outpost-heartbeat`, which older hq-cloud releases do not have. */
29
29
  heartbeat: string | null;
30
+ /** `hq-outpost-session-host`, which older hq-cloud releases do not have. */
31
+ sessionHost: string | null;
30
32
  }
31
33
  export declare function hqCloudRunners(root: string, exists?: (p: string) => boolean): HqCloudRunners;
32
34
  /** Install the newest release of the bundled major version, never older than the bundled copy. */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Which hq-cloud the daemon runs sync and the outpost heartbeat from.
2
+ * Which hq-cloud the daemon runs sync, the outpost heartbeat and the session host from.
3
3
  *
4
4
  * The hq CLI ships with a copy of hq-cloud, but hq-cloud releases more often
5
5
  * than the CLI. The updater keeps a newer copy of the same major version in
@@ -48,7 +48,11 @@ export function hqCloudRunners(root, exists = fs.existsSync) {
48
48
  const p = path.join(root, "dist", "bin", name);
49
49
  return exists(p) ? p : null;
50
50
  };
51
- return { syncRunner: bin("sync-runner.js"), heartbeat: bin("outpost-heartbeat.js") };
51
+ return {
52
+ syncRunner: bin("sync-runner.js"),
53
+ heartbeat: bin("outpost-heartbeat.js"),
54
+ sessionHost: bin("outpost-session-host.js"),
55
+ };
52
56
  }
53
57
  /** Install the newest release of the bundled major version, never older than the bundled copy. */
54
58
  export function hqCloudInstallCommand(prefix, bundledVersion, platform = process.platform) {
@@ -249,7 +249,7 @@ export async function runDaemon(opts) {
249
249
  const hqRoot = configured && fs.existsSync(configured) ? configured : undefined;
250
250
  // Re-picked every reconcile, so a newer hq-cloud from the updater is used as soon as it lands.
251
251
  const hqCloud = currentHqCloud(paths.root);
252
- const runners = hqCloud ? hqCloudRunners(hqCloud.root) : { syncRunner: null, heartbeat: null };
252
+ const runners = hqCloud ? hqCloudRunners(hqCloud.root) : { syncRunner: null, heartbeat: null, sessionHost: null };
253
253
  return planUnits(enabledServices(machineType, config), {
254
254
  machineType,
255
255
  platform,
@@ -257,6 +257,7 @@ export async function runDaemon(opts) {
257
257
  hqRoot,
258
258
  syncRunnerPath: runners.syncRunner,
259
259
  heartbeatRunnerPath: runners.heartbeat,
260
+ sessionHostRunnerPath: runners.sessionHost,
260
261
  signedIn: signedIn(env, home, log),
261
262
  kitConfigured: fs.existsSync(agentKitPaths(home, env).kitConfigPath),
262
263
  desktopAppManagesSync: machineType === "desktop" &&
@@ -12,7 +12,7 @@ export type { DaemonStateFile, PresenceRefusalState } from "./state.js";
12
12
  export { appendDaemonLog, daemonLogLine, ensureDaemonLog, resolveDaemonAssetDir, rotateDaemonLogIfNeeded, } from "./log.js";
13
13
  export { BOARD_REFRESH_INTERVAL_MS, createVaultBoardReader, formatBoardMarkdown, refreshBoundSessionBoards, writeBoardMarkdown, } from "./board-refresh.js";
14
14
  export type { BoardReader, BoardRefreshDeps, BoardStorySnapshot } from "./board-refresh.js";
15
- export { buildInstallPaths, daemonServiceStatus, detectPlatform, installDaemonIfStale, installDaemonService, isNewerCliVersion, readAssetTemplate, restartDaemonServiceIfInstalled, renderLaunchdPlist, renderSystemdSystemUnit, renderSystemdUserUnit, resolveAbsoluteNodeBinary, resolveHqBinary, resolveNodeBinary, resolveRunningCliEntry, parseSchtasksLastResult, parseWindowsTaskHqRoot, readRecordedWindowsHqRoot, schtasksLastResultFailed, uninstallDaemonService, windowsLaunchMode, windowsLogonNotice, } from "./install.js";
15
+ export { buildInstallPaths, daemonServiceIsLoaded, daemonServiceStatus, detectPlatform, installDaemonIfStale, installDaemonService, isNewerCliVersion, readAssetTemplate, restartDaemonServiceIfInstalled, renderLaunchdPlist, renderSystemdSystemUnit, renderSystemdUserUnit, resolveAbsoluteNodeBinary, resolveHqBinary, resolveNodeBinary, resolveRunningCliEntry, parseSchtasksLastResult, parseWindowsTaskHqRoot, readRecordedWindowsHqRoot, schtasksLastResultFailed, uninstallDaemonService, windowsLaunchMode, windowsLogonNotice, } from "./install.js";
16
16
  export type { DaemonInstallPlatform, InstallIfStaleResult, InstallPaths, InstallResult, } from "./install.js";
17
17
  export { daemonConfigPath, findAncestorHqRoot, isInstallableHqRoot, readDaemonConfig, registerTrustedHqRoot, resolveInstallHqRoot, verifyHqRoot, } from "./config.js";
18
18
  export type { InstallHqRootResolution } from "./config.js";
@@ -6,7 +6,7 @@ export { CLOSE_LOG_ALWAYS_COUNT, CLOSE_LOG_INTERVAL_MS, CONNECT_STABLE_GRACE_MS,
6
6
  export { defaultDaemonState, patchDaemonState, readDaemonState, writeDaemonState, } from "./state.js";
7
7
  export { appendDaemonLog, daemonLogLine, ensureDaemonLog, resolveDaemonAssetDir, rotateDaemonLogIfNeeded, } from "./log.js";
8
8
  export { BOARD_REFRESH_INTERVAL_MS, createVaultBoardReader, formatBoardMarkdown, refreshBoundSessionBoards, writeBoardMarkdown, } from "./board-refresh.js";
9
- export { buildInstallPaths, daemonServiceStatus, detectPlatform, installDaemonIfStale, installDaemonService, isNewerCliVersion, readAssetTemplate, restartDaemonServiceIfInstalled, renderLaunchdPlist, renderSystemdSystemUnit, renderSystemdUserUnit, resolveAbsoluteNodeBinary, resolveHqBinary, resolveNodeBinary, resolveRunningCliEntry, parseSchtasksLastResult, parseWindowsTaskHqRoot, readRecordedWindowsHqRoot, schtasksLastResultFailed, uninstallDaemonService, windowsLaunchMode, windowsLogonNotice, } from "./install.js";
9
+ export { buildInstallPaths, daemonServiceIsLoaded, daemonServiceStatus, detectPlatform, installDaemonIfStale, installDaemonService, isNewerCliVersion, readAssetTemplate, restartDaemonServiceIfInstalled, renderLaunchdPlist, renderSystemdSystemUnit, renderSystemdUserUnit, resolveAbsoluteNodeBinary, resolveHqBinary, resolveNodeBinary, resolveRunningCliEntry, parseSchtasksLastResult, parseWindowsTaskHqRoot, readRecordedWindowsHqRoot, schtasksLastResultFailed, uninstallDaemonService, windowsLaunchMode, windowsLogonNotice, } from "./install.js";
10
10
  export { daemonConfigPath, findAncestorHqRoot, isInstallableHqRoot, readDaemonConfig, registerTrustedHqRoot, resolveInstallHqRoot, verifyHqRoot, } from "./config.js";
11
11
  export { UNHEALTHY_SPOOL_AGE_MS, collectDaemonDoctor, formatCliIdentityLines, formatCliMismatchLine, formatDaemonDoctor, listHqBinariesOnPath, } from "./doctor.js";
12
12
  export { scopeBundleToAgentIdentity, } from "./credentials.js";
@@ -312,6 +312,11 @@ export declare function uninstallDaemonService(opts: {
312
312
  /** Windows: terminate the recorded daemon pid after `schtasks /End` (tests inject). */
313
313
  kill?: (pid: number) => void;
314
314
  }): InstallResult;
315
+ /**
316
+ * Live service-manager probe for `daemonServiceStatus`: `launchctl print
317
+ * gui/<uid>/<label>` on macOS, `systemctl --user is-active` on Linux.
318
+ */
319
+ export declare function daemonServiceIsLoaded(run: RunCommand, uid?: number): (platform: DaemonInstallPlatform, dest: string) => boolean;
315
320
  export declare function daemonServiceStatus(opts: {
316
321
  platform?: DaemonInstallPlatform;
317
322
  paths?: InstallPaths;
@@ -22,8 +22,8 @@ import { isInstallableHqRoot, readDaemonConfig, registerTrustedHqRoot, verifyHqR
22
22
  import { defaultPidLockDeps, pidLockStatus, readPidLock } from "./pid-lock.js";
23
23
  import { retireLegacyListen } from "./legacy-listen.js";
24
24
  import { readDaemonState } from "./state.js";
25
- import { activateLaunchd, launchdPlistProgramArguments, launchdProgramArgumentsDiffer, parseLaunchctlPrintArguments, } from "../../../service-manager/launchd.js";
26
- import { activateSystemd } from "../../../service-manager/systemd.js";
25
+ import { activateLaunchd, launchdIsLoaded, launchdPlistProgramArguments, launchdProgramArgumentsDiffer, parseLaunchctlPrintArguments, } from "../../../service-manager/launchd.js";
26
+ import { activateSystemd, systemdIsActive } from "../../../service-manager/systemd.js";
27
27
  import { nodeBinaryProblem, preferStableNodeBinary } from "../../../node-binary.js";
28
28
  /**
29
29
  * `schtasks /End` terminates the task's root process only. The daemon is
@@ -990,6 +990,19 @@ export function uninstallDaemonService(opts) {
990
990
  message: "Nothing to uninstall on this platform",
991
991
  };
992
992
  }
993
+ /**
994
+ * Live service-manager probe for `daemonServiceStatus`: `launchctl print
995
+ * gui/<uid>/<label>` on macOS, `systemctl --user is-active` on Linux.
996
+ */
997
+ export function daemonServiceIsLoaded(run, uid) {
998
+ return (platform) => {
999
+ if (platform === "darwin")
1000
+ return launchdIsLoaded(LAUNCHD_LABEL, run, uid);
1001
+ if (platform === "linux")
1002
+ return systemdIsActive(SYSTEMD_UNIT_NAME, run);
1003
+ return false;
1004
+ };
1005
+ }
993
1006
  export function daemonServiceStatus(opts) {
994
1007
  const platform = opts.platform ?? detectPlatform();
995
1008
  const paths = opts.paths ?? buildInstallPaths({});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.180.0",
3
+ "version": "5.182.0",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {