@indigoai-us/hq-cli 5.322.0 → 5.324.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 +11 -0
- package/assets/scaffold/core/scripts/derive-trigger-facts.sh +263 -0
- package/assets/scaffold/core/scripts/lib/transcript-tail.sh +98 -0
- package/assets/scaffold/core/scripts/lib/trigger-fact-text.awk +86 -0
- package/dist/bin/hq-auth-refresh.d.ts +5 -1
- package/dist/bin/hq-auth-refresh.js +33 -1
- package/dist/command-catalog.generated.d.ts +138 -6
- package/dist/command-catalog.generated.js +178 -6
- package/dist/command-registration-plan.d.ts +24 -0
- package/dist/command-registration-plan.js +4 -0
- package/dist/commands/anywhere-runtime-flag.d.ts +9 -0
- package/dist/commands/anywhere-runtime-flag.js +22 -0
- package/dist/commands/cloud.js +23 -4
- package/dist/commands/core-derive-trigger-facts-command.d.ts +3 -0
- package/dist/commands/core-derive-trigger-facts-command.js +47 -0
- package/dist/commands/core-derive-trigger-facts-native.d.ts +21 -0
- package/dist/commands/core-derive-trigger-facts-native.js +492 -0
- package/dist/commands/core.js +6 -0
- package/dist/commands/daemon.js +39 -2
- package/dist/commands/db-provision.js +6 -1
- package/dist/commands/doctor.js +8 -4
- package/dist/commands/feedback.d.ts +2 -0
- package/dist/commands/feedback.js +10 -0
- package/dist/commands/install-global.d.ts +46 -0
- package/dist/commands/install-global.js +674 -0
- package/dist/commands/link.d.ts +30 -0
- package/dist/commands/link.js +184 -0
- package/dist/commands/mcp-status.d.ts +6 -0
- package/dist/commands/mcp-status.js +21 -4
- package/dist/commands/pkg-install.js +20 -1
- package/dist/commands/update.d.ts +19 -0
- package/dist/commands/update.js +52 -6
- package/dist/fast-core.d.ts +2 -1
- package/dist/fast-core.js +12 -8
- package/dist/fast-scaffold.js +13 -0
- package/dist/index.js +9 -7
- package/dist/lib/cli-invite-nudge.d.ts +25 -0
- package/dist/lib/cli-invite-nudge.js +152 -0
- package/dist/lib/core-utils/timeout-guard-native-flags.d.ts +6 -0
- package/dist/lib/core-utils/timeout-guard-native-flags.js +30 -0
- package/dist/lib/core-utils/timeout-guard-native.d.ts +0 -3
- package/dist/lib/core-utils/timeout-guard-native.js +4 -30
- package/dist/lib/core-utils/timeout-guard.d.ts +2 -0
- package/dist/lib/core-utils/timeout-guard.js +2 -1
- package/dist/lib/daemon/convergence.d.ts +42 -0
- package/dist/lib/daemon/convergence.js +66 -0
- package/dist/lib/daemon/heartbeat.d.ts +43 -0
- package/dist/lib/daemon/heartbeat.js +70 -0
- package/dist/lib/daemon/ops/journal.d.ts +29 -0
- package/dist/lib/daemon/ops/journal.js +141 -0
- package/dist/lib/daemon/ops/memory.d.ts +20 -0
- package/dist/lib/daemon/ops/memory.js +65 -0
- package/dist/lib/daemon/ops/mesh.d.ts +38 -0
- package/dist/lib/daemon/ops/mesh.js +70 -0
- package/dist/lib/daemon/ops/policy.d.ts +78 -0
- package/dist/lib/daemon/ops/policy.js +283 -0
- package/dist/lib/daemon/protocol.d.ts +68 -0
- package/dist/lib/daemon/protocol.js +154 -0
- package/dist/lib/daemon/run.d.ts +10 -0
- package/dist/lib/daemon/run.js +85 -3
- package/dist/lib/daemon/server.d.ts +36 -0
- package/dist/lib/daemon/server.js +306 -0
- package/dist/lib/daemon/session-registry.d.ts +30 -0
- package/dist/lib/daemon/session-registry.js +42 -0
- package/dist/lib/doctor/checks/anywhere.d.ts +38 -0
- package/dist/lib/doctor/checks/anywhere.js +182 -0
- package/dist/lib/doctor/registry.js +6 -0
- package/dist/lib/first-sync-next-step.d.ts +10 -1
- package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
- package/dist/lib/flag-registry-worker-source.generated.js +1 -1
- package/dist/lib/install/claude-targets.d.ts +47 -0
- package/dist/lib/install/claude-targets.js +203 -0
- package/dist/lib/install/codex-targets.d.ts +57 -0
- package/dist/lib/install/codex-targets.js +187 -0
- package/dist/lib/mesh/live/session-seq.js +62 -9
- package/dist/lib/registry/normalize-remote.d.ts +21 -0
- package/dist/lib/registry/normalize-remote.js +68 -0
- package/dist/lib/registry/registry.d.ts +75 -0
- package/dist/lib/registry/registry.js +261 -0
- package/dist/main.js +3 -1
- package/dist/utils/cli-telemetry.d.ts +11 -0
- package/dist/utils/cli-telemetry.js +76 -0
- package/dist/utils/cognito-session.d.ts +5 -1
- package/dist/utils/cognito-session.js +8 -12
- package/dist/utils/feedback-diagnostics.d.ts +2 -0
- package/dist/utils/run-bundled-script.d.ts +7 -4
- package/dist/utils/run-bundled-script.js +47 -12
- package/dist/utils/version-check.d.ts +2 -0
- package/dist/utils/version-check.js +7 -0
- package/package.json +2 -2
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory session registry hosted by hqd (hq-anywhere US-008). Keyed by
|
|
3
|
+
* runtime + session id; nothing is persisted, so a daemon restart starts empty
|
|
4
|
+
* and sessions re-open on their next hook.
|
|
5
|
+
*/
|
|
6
|
+
export interface HqdSession {
|
|
7
|
+
runtime: string;
|
|
8
|
+
sessionId: string;
|
|
9
|
+
cwd: string;
|
|
10
|
+
company: string | null;
|
|
11
|
+
startedAt: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function sessionKey(runtime: string, sessionId: string): string;
|
|
14
|
+
export declare class SessionRegistry {
|
|
15
|
+
private readonly now;
|
|
16
|
+
private readonly sessions;
|
|
17
|
+
constructor(now?: () => Date);
|
|
18
|
+
/** Open or refresh a session. Re-opening keeps the original startedAt. */
|
|
19
|
+
open(input: {
|
|
20
|
+
runtime: string;
|
|
21
|
+
sessionId: string;
|
|
22
|
+
cwd: string;
|
|
23
|
+
company: string | null;
|
|
24
|
+
}): HqdSession;
|
|
25
|
+
get(runtime: string, sessionId: string): HqdSession | null;
|
|
26
|
+
close(runtime: string, sessionId: string): boolean;
|
|
27
|
+
list(): HqdSession[];
|
|
28
|
+
get size(): number;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=session-registry.d.ts.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory session registry hosted by hqd (hq-anywhere US-008). Keyed by
|
|
3
|
+
* runtime + session id; nothing is persisted, so a daemon restart starts empty
|
|
4
|
+
* and sessions re-open on their next hook.
|
|
5
|
+
*/
|
|
6
|
+
export function sessionKey(runtime, sessionId) {
|
|
7
|
+
return `${runtime}\u0000${sessionId}`;
|
|
8
|
+
}
|
|
9
|
+
export class SessionRegistry {
|
|
10
|
+
now;
|
|
11
|
+
sessions = new Map();
|
|
12
|
+
constructor(now = () => new Date()) {
|
|
13
|
+
this.now = now;
|
|
14
|
+
}
|
|
15
|
+
/** Open or refresh a session. Re-opening keeps the original startedAt. */
|
|
16
|
+
open(input) {
|
|
17
|
+
const key = sessionKey(input.runtime, input.sessionId);
|
|
18
|
+
const prior = this.sessions.get(key);
|
|
19
|
+
const session = {
|
|
20
|
+
runtime: input.runtime,
|
|
21
|
+
sessionId: input.sessionId,
|
|
22
|
+
cwd: input.cwd,
|
|
23
|
+
company: input.company,
|
|
24
|
+
startedAt: prior?.startedAt ?? this.now().toISOString(),
|
|
25
|
+
};
|
|
26
|
+
this.sessions.set(key, session);
|
|
27
|
+
return session;
|
|
28
|
+
}
|
|
29
|
+
get(runtime, sessionId) {
|
|
30
|
+
return this.sessions.get(sessionKey(runtime, sessionId)) ?? null;
|
|
31
|
+
}
|
|
32
|
+
close(runtime, sessionId) {
|
|
33
|
+
return this.sessions.delete(sessionKey(runtime, sessionId));
|
|
34
|
+
}
|
|
35
|
+
list() {
|
|
36
|
+
return [...this.sessions.values()];
|
|
37
|
+
}
|
|
38
|
+
get size() {
|
|
39
|
+
return this.sessions.size;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=session-registry.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `hq doctor` anywhere family (hq-anywhere US-012).
|
|
3
|
+
*
|
|
4
|
+
* Checks the pieces that let a session in any repo pick up HQ: the ~/.hq/root
|
|
5
|
+
* pointer, the repo registry, the hqd daemon service and socket, version
|
|
6
|
+
* convergence between hqd and the installed hq-cli, the heartbeat, the Claude
|
|
7
|
+
* and Codex MCP registrations, and the hq-* skill links. Every line is PASS,
|
|
8
|
+
* WARN or FAIL with a remediation command. When anywhere was never installed
|
|
9
|
+
* on this machine the family reports a single NA line.
|
|
10
|
+
*/
|
|
11
|
+
import type { CheckContext, CheckFamily, CheckResult } from "../types.js";
|
|
12
|
+
export declare const ANYWHERE_FAMILY_ID = "anywhere";
|
|
13
|
+
export declare const REMEDIATION: {
|
|
14
|
+
readonly installClaude: "hq install --global --runtime claude";
|
|
15
|
+
readonly installCodex: "hq install --global --runtime codex";
|
|
16
|
+
readonly daemonInstall: "hq daemon install";
|
|
17
|
+
readonly daemonRestart: "hq daemon restart --daemon";
|
|
18
|
+
readonly link: "hq link <repo-dir> <company>";
|
|
19
|
+
};
|
|
20
|
+
export interface DaemonServiceState {
|
|
21
|
+
installed: boolean;
|
|
22
|
+
loaded: boolean;
|
|
23
|
+
detail: string;
|
|
24
|
+
}
|
|
25
|
+
export interface AnywhereDeps {
|
|
26
|
+
home?: string;
|
|
27
|
+
env?: NodeJS.ProcessEnv;
|
|
28
|
+
/** Version hqd reports; rejects when the socket is unreachable. */
|
|
29
|
+
ping?: () => Promise<string>;
|
|
30
|
+
/** The hq-cli version installed on this machine. Default: this CLI's version. */
|
|
31
|
+
cliVersion?: string;
|
|
32
|
+
serviceState?: () => DaemonServiceState;
|
|
33
|
+
now?: () => Date;
|
|
34
|
+
}
|
|
35
|
+
export declare function createAnywhereFamily(deps?: AnywhereDeps): CheckFamily;
|
|
36
|
+
export declare const anywhereFamily: CheckFamily;
|
|
37
|
+
export declare function runAnywhereChecks(_context: CheckContext, deps?: AnywhereDeps): Promise<CheckResult[]>;
|
|
38
|
+
//# sourceMappingURL=anywhere.d.ts.map
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `hq doctor` anywhere family (hq-anywhere US-012).
|
|
3
|
+
*
|
|
4
|
+
* Checks the pieces that let a session in any repo pick up HQ: the ~/.hq/root
|
|
5
|
+
* pointer, the repo registry, the hqd daemon service and socket, version
|
|
6
|
+
* convergence between hqd and the installed hq-cli, the heartbeat, the Claude
|
|
7
|
+
* and Codex MCP registrations, and the hq-* skill links. Every line is PASS,
|
|
8
|
+
* WARN or FAIL with a remediation command. When anywhere was never installed
|
|
9
|
+
* on this machine the family reports a single NA line.
|
|
10
|
+
*/
|
|
11
|
+
import { spawnSync } from "node:child_process";
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
import * as os from "node:os";
|
|
14
|
+
import * as path from "node:path";
|
|
15
|
+
import { CLI_VERSION } from "../../../cli-version.js";
|
|
16
|
+
import { computeMcpStatus } from "../../../commands/mcp-status.js";
|
|
17
|
+
import { HQ_MCP_SERVER_NAME, SKILL_LINK_PREFIX, claudeTargets } from "../../install/claude-targets.js";
|
|
18
|
+
import { codexTargets } from "../../install/codex-targets.js";
|
|
19
|
+
import { pingHqdVersion } from "../../daemon/convergence.js";
|
|
20
|
+
import { daemonPresenceLabel, heartbeatFile, readHeartbeat } from "../../daemon/heartbeat.js";
|
|
21
|
+
import { DAEMON_LAUNCHD_LABEL, DAEMON_SYSTEMD_UNIT, DAEMON_WINDOWS_TASK } from "../../daemon/install.js";
|
|
22
|
+
import { hqdSocketPath } from "../../daemon/protocol.js";
|
|
23
|
+
import { readRegistry, registryDir, registryFile } from "../../registry/registry.js";
|
|
24
|
+
export const ANYWHERE_FAMILY_ID = "anywhere";
|
|
25
|
+
export const REMEDIATION = {
|
|
26
|
+
installClaude: "hq install --global --runtime claude",
|
|
27
|
+
installCodex: "hq install --global --runtime codex",
|
|
28
|
+
daemonInstall: "hq daemon install",
|
|
29
|
+
daemonRestart: "hq daemon restart --daemon",
|
|
30
|
+
link: "hq link <repo-dir> <company>",
|
|
31
|
+
};
|
|
32
|
+
export function createAnywhereFamily(deps = {}) {
|
|
33
|
+
return { id: ANYWHERE_FAMILY_ID, title: "HQ anywhere runtime", run: (context) => runAnywhereChecks(context, deps) };
|
|
34
|
+
}
|
|
35
|
+
export const anywhereFamily = createAnywhereFamily();
|
|
36
|
+
function result(status, checkId, message, remediation, target) {
|
|
37
|
+
return { status, checkId: `anywhere.${checkId}`, message, ...(remediation ? { remediation } : {}), ...(target ? { target } : {}) };
|
|
38
|
+
}
|
|
39
|
+
export async function runAnywhereChecks(_context, deps = {}) {
|
|
40
|
+
const home = deps.home ?? os.homedir();
|
|
41
|
+
const env = deps.env ?? process.env;
|
|
42
|
+
const claude = claudeTargets(home);
|
|
43
|
+
const codex = codexTargets(home);
|
|
44
|
+
const installed = [claude.hqPointer, claude.stateFile, codex.stateFile].some((p) => fs.existsSync(p));
|
|
45
|
+
if (!installed) {
|
|
46
|
+
return [result("NA", "installed", "HQ anywhere is not installed on this machine", REMEDIATION.installClaude)];
|
|
47
|
+
}
|
|
48
|
+
const out = [];
|
|
49
|
+
out.push(checkPointer(claude.hqPointer));
|
|
50
|
+
out.push(checkRegistry(registryFile(registryDir(home, env))));
|
|
51
|
+
const service = (deps.serviceState ?? (() => defaultServiceState(home)))();
|
|
52
|
+
if (!service.installed)
|
|
53
|
+
out.push(result("FAIL", "daemon-installed", `daemon service is not installed (${service.detail})`, REMEDIATION.daemonInstall));
|
|
54
|
+
else if (!service.loaded)
|
|
55
|
+
out.push(result("FAIL", "daemon-installed", `daemon service is installed but not loaded (${service.detail})`, REMEDIATION.daemonRestart));
|
|
56
|
+
else
|
|
57
|
+
out.push(result("PASS", "daemon-installed", `daemon service is installed and loaded (${service.detail})`));
|
|
58
|
+
const socketPath = hqdSocketPath(home, env);
|
|
59
|
+
const ping = deps.ping ?? (() => pingHqdVersion(socketPath, 2_000));
|
|
60
|
+
let running = null;
|
|
61
|
+
try {
|
|
62
|
+
running = await ping();
|
|
63
|
+
out.push(result("PASS", "socket", `hqd answered on ${socketPath}`, undefined, socketPath));
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
out.push(result("FAIL", "socket", `hqd is not reachable: ${err instanceof Error ? err.message : String(err)}`, REMEDIATION.daemonInstall, socketPath));
|
|
67
|
+
}
|
|
68
|
+
const cliVersion = deps.cliVersion ?? CLI_VERSION;
|
|
69
|
+
if (running === null)
|
|
70
|
+
out.push(result("FAIL", "version", `cannot compare versions: hqd did not answer (hq-cli is ${cliVersion})`, REMEDIATION.daemonInstall));
|
|
71
|
+
else if (running !== cliVersion)
|
|
72
|
+
out.push(result("FAIL", "version", `hqd runs ${running} but hq-cli ${cliVersion} is installed`, REMEDIATION.daemonRestart));
|
|
73
|
+
else
|
|
74
|
+
out.push(result("PASS", "version", `hqd and hq-cli both run ${cliVersion}`));
|
|
75
|
+
out.push(checkHeartbeat(heartbeatFile(home, env), (deps.now ?? (() => new Date()))()));
|
|
76
|
+
const mcp = computeMcpStatus({ home });
|
|
77
|
+
const server = mcp.servers.find((s) => s.server === HQ_MCP_SERVER_NAME);
|
|
78
|
+
out.push(checkRegistration("claude", server?.claude, mcp.runtimes.claude, REMEDIATION.installClaude));
|
|
79
|
+
out.push(checkRegistration("codex", server?.codex, mcp.runtimes.codex, REMEDIATION.installCodex));
|
|
80
|
+
out.push(checkSkillLinks("claude", claude.skillsDir, REMEDIATION.installClaude));
|
|
81
|
+
if (mcp.runtimes.codex.installed)
|
|
82
|
+
out.push(checkSkillLinks("codex", codex.skillsDir, REMEDIATION.installCodex));
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
function checkPointer(file) {
|
|
86
|
+
let root;
|
|
87
|
+
try {
|
|
88
|
+
root = fs.readFileSync(file, "utf8").trim();
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return result("FAIL", "pointer", `${file} is missing`, REMEDIATION.installClaude, file);
|
|
92
|
+
}
|
|
93
|
+
const valid = root && path.isAbsolute(root) && [".claude", "core"].every((m) => fs.existsSync(path.join(root, m)));
|
|
94
|
+
if (!valid)
|
|
95
|
+
return result("FAIL", "pointer", `${file} points at ${root || "(empty)"}, which is not an HQ root`, REMEDIATION.installClaude, file);
|
|
96
|
+
return result("PASS", "pointer", `${file} points at ${root}`, undefined, file);
|
|
97
|
+
}
|
|
98
|
+
function checkRegistry(file) {
|
|
99
|
+
if (!fs.existsSync(file))
|
|
100
|
+
return result("WARN", "registry", `${file} does not exist yet; no repos are linked`, REMEDIATION.link, file);
|
|
101
|
+
try {
|
|
102
|
+
const registry = readRegistry(file);
|
|
103
|
+
const count = Object.keys(registry.entries).length;
|
|
104
|
+
return result("PASS", "registry", `${file} is readable (${count} entries)`, undefined, file);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
return result("FAIL", "registry", `${file} is unreadable: ${err.message}`, `mv ${file} ${file}.bad && ${REMEDIATION.installClaude}`, file);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function checkHeartbeat(file, now) {
|
|
111
|
+
let state;
|
|
112
|
+
try {
|
|
113
|
+
state = readHeartbeat(file);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
return result("FAIL", "heartbeat", `heartbeat record is unreadable: ${err.message}`, REMEDIATION.daemonRestart, file);
|
|
117
|
+
}
|
|
118
|
+
if (!state)
|
|
119
|
+
return result("WARN", "heartbeat", "no hqd heartbeat recorded yet", REMEDIATION.daemonRestart, file);
|
|
120
|
+
if (daemonPresenceLabel(state, now) !== "daemon live")
|
|
121
|
+
return result("WARN", "heartbeat", `daemon stale: last heartbeat at ${state.at}`, REMEDIATION.daemonRestart, file);
|
|
122
|
+
return result("PASS", "heartbeat", `last heartbeat at ${state.at} (hqd ${state.version}, ${state.sessions} sessions)`, undefined, file);
|
|
123
|
+
}
|
|
124
|
+
function checkRegistration(runtimeName, status, runtimeState, fix) {
|
|
125
|
+
const id = `${runtimeName}-registration`;
|
|
126
|
+
if (!runtimeState.installed)
|
|
127
|
+
return result("WARN", id, `${runtimeName} is not installed, so hq is not registered there`, fix);
|
|
128
|
+
if (!runtimeState.parses)
|
|
129
|
+
return result("FAIL", id, `${runtimeName} MCP config cannot be parsed`, fix);
|
|
130
|
+
if (!status || status.presence === "absent" || status.presence === "not-installed")
|
|
131
|
+
return result("WARN", id, `the hq MCP server is not registered in ${runtimeName}`, fix);
|
|
132
|
+
if (status.presence === "unparseable")
|
|
133
|
+
return result("FAIL", id, `${runtimeName} MCP config cannot be parsed`, fix);
|
|
134
|
+
if (!status.healthy)
|
|
135
|
+
return result("FAIL", id, `${runtimeName} hq MCP entry does not use absolute paths that exist (${status.target ?? ""})`, fix);
|
|
136
|
+
return result("PASS", id, `hq MCP server registered in ${runtimeName} with absolute paths`);
|
|
137
|
+
}
|
|
138
|
+
function checkSkillLinks(runtime, dir, fix) {
|
|
139
|
+
const id = `${runtime}-skills`;
|
|
140
|
+
let names;
|
|
141
|
+
try {
|
|
142
|
+
names = fs.readdirSync(dir).filter((n) => n.startsWith(SKILL_LINK_PREFIX));
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return result("WARN", id, `${dir} does not exist`, fix, dir);
|
|
146
|
+
}
|
|
147
|
+
const links = names.filter((n) => fs.lstatSync(path.join(dir, n)).isSymbolicLink());
|
|
148
|
+
if (links.length === 0)
|
|
149
|
+
return result("WARN", id, `no hq-* skill links in ${dir}`, fix, dir);
|
|
150
|
+
const broken = links.filter((n) => !fs.existsSync(path.join(dir, n)));
|
|
151
|
+
if (broken.length > 0)
|
|
152
|
+
return result("FAIL", id, `${broken.length} broken skill links in ${dir}: ${broken.slice(0, 5).join(", ")}`, fix, dir);
|
|
153
|
+
return result("PASS", id, `${links.length} hq-* skill links in ${dir} resolve`, undefined, dir);
|
|
154
|
+
}
|
|
155
|
+
function defaultServiceState(home) {
|
|
156
|
+
if (process.platform === "darwin") {
|
|
157
|
+
const plist = path.join(home, "Library", "LaunchAgents", `${DAEMON_LAUNCHD_LABEL}.plist`);
|
|
158
|
+
if (!fs.existsSync(plist))
|
|
159
|
+
return { installed: false, loaded: false, detail: `no ${plist}` };
|
|
160
|
+
const uid = process.getuid?.() ?? 0;
|
|
161
|
+
const probe = spawnSync("launchctl", ["print", `gui/${uid}/${DAEMON_LAUNCHD_LABEL}`], { encoding: "utf8", timeout: 5_000 });
|
|
162
|
+
return { installed: true, loaded: probe.status === 0, detail: `launchd ${DAEMON_LAUNCHD_LABEL}` };
|
|
163
|
+
}
|
|
164
|
+
if (process.platform === "linux") {
|
|
165
|
+
const unit = path.join(home, ".config", "systemd", "user", DAEMON_SYSTEMD_UNIT);
|
|
166
|
+
const systemUnit = path.join("/etc/systemd/system", DAEMON_SYSTEMD_UNIT);
|
|
167
|
+
if (!fs.existsSync(unit) && !fs.existsSync(systemUnit))
|
|
168
|
+
return { installed: false, loaded: false, detail: `no ${DAEMON_SYSTEMD_UNIT}` };
|
|
169
|
+
const systemScope = fs.existsSync(systemUnit);
|
|
170
|
+
const probe = spawnSync("systemctl", [...(systemScope ? [] : ["--user"]), "is-active", DAEMON_SYSTEMD_UNIT], { encoding: "utf8", timeout: 5_000 });
|
|
171
|
+
return { installed: true, loaded: probe.status === 0, detail: `systemd ${systemScope ? "system" : "user"} ${DAEMON_SYSTEMD_UNIT}` };
|
|
172
|
+
}
|
|
173
|
+
if (process.platform === "win32") {
|
|
174
|
+
const probe = spawnSync("schtasks.exe", ["/Query", "/TN", DAEMON_WINDOWS_TASK, "/FO", "CSV", "/NH"], { encoding: "utf8", timeout: 5_000 });
|
|
175
|
+
if (probe.status !== 0)
|
|
176
|
+
return { installed: false, loaded: false, detail: `no Scheduled Task ${DAEMON_WINDOWS_TASK}` };
|
|
177
|
+
const loaded = /,\s*"?Running"?\s*$/i.test(probe.stdout.trim());
|
|
178
|
+
return { installed: true, loaded, detail: `Scheduled Task ${DAEMON_WINDOWS_TASK}${loaded ? " is running" : " is not running"}` };
|
|
179
|
+
}
|
|
180
|
+
return { installed: false, loaded: false, detail: `${process.platform}: service probe not available` };
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=anywhere.js.map
|
|
@@ -23,9 +23,11 @@ import { integrationsFamily } from "./checks/integrations.js";
|
|
|
23
23
|
import { syncHealthFamily } from "./checks/sync-health.js";
|
|
24
24
|
import { workContextFamily } from "./checks/work-context.js";
|
|
25
25
|
import { botsFamily } from "./checks/bots.js";
|
|
26
|
+
import { anywhereFamily } from "./checks/anywhere.js";
|
|
26
27
|
import { scaffoldCliFloorFamily } from "./checks/scaffold-cli-floor.js";
|
|
27
28
|
import { fixtureCoverageFamily } from "./fixtures/discover.js";
|
|
28
29
|
import { checkClaudeWiring } from "./checks/claude-wiring.js";
|
|
30
|
+
import { anywhereRuntimeEnabled } from "../../commands/anywhere-runtime-flag.js";
|
|
29
31
|
/**
|
|
30
32
|
* An ordered, id-keyed set of check families. Registration order is preserved
|
|
31
33
|
* (Map iteration order), and re-registering an id replaces the family in place
|
|
@@ -262,6 +264,10 @@ export function createDefaultRegistry() {
|
|
|
262
264
|
// Local bots: inbox/heartbeat reachability and a LaunchAgent whose hq
|
|
263
265
|
// path survived an HQ toolchain move. Local-only reads.
|
|
264
266
|
registry.register(botsFamily);
|
|
267
|
+
// HQ anywhere (US-012): pointer, registry, hqd service/socket/version,
|
|
268
|
+
// heartbeat, MCP registrations and skill links. NA when not installed.
|
|
269
|
+
if (anywhereRuntimeEnabled())
|
|
270
|
+
registry.register(anywhereFamily);
|
|
265
271
|
return registry;
|
|
266
272
|
}
|
|
267
273
|
//# sourceMappingURL=registry.js.map
|
|
@@ -12,7 +12,15 @@ export declare function shouldConfirmFirstWorkBearingSync(input: {
|
|
|
12
12
|
alreadyCompleted: boolean;
|
|
13
13
|
workBearing: boolean;
|
|
14
14
|
}): boolean;
|
|
15
|
-
|
|
15
|
+
interface WorkBearingSyncResult {
|
|
16
|
+
aborted?: unknown;
|
|
17
|
+
filesUploaded?: unknown;
|
|
18
|
+
filesDownloaded?: unknown;
|
|
19
|
+
sessionLogUploadedCount?: unknown;
|
|
20
|
+
filesDeleted?: unknown;
|
|
21
|
+
tombstonedCount?: unknown;
|
|
22
|
+
}
|
|
23
|
+
export declare function isWorkBearingSyncResult(result: WorkBearingSyncResult): boolean;
|
|
16
24
|
export declare function isHumanInteractiveCliSession(input: {
|
|
17
25
|
stdoutIsTTY: boolean;
|
|
18
26
|
argv: readonly string[];
|
|
@@ -31,4 +39,5 @@ export declare function maybeShowFirstSyncNextStep(): boolean;
|
|
|
31
39
|
export declare function recordFirstWorkBearingSync(result: Record<string, unknown>): boolean;
|
|
32
40
|
/** Drain outcomes once so each shown/followed event is sent at most once per run. */
|
|
33
41
|
export declare function takeFirstSyncStepOutcomes(): FirstSyncStepOutcome[];
|
|
42
|
+
export {};
|
|
34
43
|
//# sourceMappingURL=first-sync-next-step.d.ts.map
|