@indigoai-us/hq-cli 5.108.8 → 5.108.10
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 +4 -0
- package/dist/lazy-commands.d.ts +55 -0
- package/dist/lazy-commands.js +68 -0
- package/dist/lib/doctor/checks/runtime-probe.d.ts +56 -0
- package/dist/lib/doctor/checks/runtime-probe.js +158 -0
- package/dist/lib/doctor/compat.d.ts +16 -0
- package/dist/lib/doctor/compat.js +12 -1
- package/dist/lib/mesh/live/daemon/index.d.ts +1 -1
- package/dist/lib/mesh/live/daemon/index.js +1 -1
- package/dist/lib/mesh/live/daemon/presence.d.ts +19 -0
- package/dist/lib/mesh/live/daemon/presence.js +57 -6
- package/dist/lib/mesh/live/daemon/run.js +3 -0
- package/dist/main.js +14 -199
- package/dist/register-all.d.ts +32 -0
- package/dist/register-all.js +231 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hot-command manifest for the entrypoint's lazy registration.
|
|
3
|
+
*
|
|
4
|
+
* main.ts used to import the entire ~60-module command graph at module scope,
|
|
5
|
+
* so every invocation paid for every command. That is fine for a human typing
|
|
6
|
+
* one command and ruinous for the calls automation makes in a loop: the
|
|
7
|
+
* hq-sentry agent fleet on an outpost runs `hq secrets` about 39 times a minute
|
|
8
|
+
* (each worker resolves credentials before every external command it executes),
|
|
9
|
+
* and each of those processes spent ~0.75 CPU-seconds importing commands it
|
|
10
|
+
* never ran — around half a core, continuously. Measured on Outpost 2
|
|
11
|
+
* (i-09424eff61920a4ac) 2026-09-05; see register-all.ts for the numbers.
|
|
12
|
+
*
|
|
13
|
+
* A command listed here registers ITSELF and nothing else. Anything not listed
|
|
14
|
+
* — `--help`, a bare `hq`, an unknown command, every other command — falls back
|
|
15
|
+
* to `registerAllCommands`, the complete unchanged graph. That fallback is what
|
|
16
|
+
* makes this safe to extend one command at a time: an entry is a performance
|
|
17
|
+
* opt-in, never a behaviour change, and a command that is absent here is simply
|
|
18
|
+
* as fast as it was before.
|
|
19
|
+
*
|
|
20
|
+
* This mirrors commands/scaffold-fast.ts, which does the same thing for the
|
|
21
|
+
* relocated `hq core …` scripts, and carries the same anti-drift discipline: a
|
|
22
|
+
* parity test registers each entry BOTH ways and asserts the resulting command
|
|
23
|
+
* shape is identical, so a manifest entry cannot silently diverge from the real
|
|
24
|
+
* registration.
|
|
25
|
+
*
|
|
26
|
+
* TO ADD A COMMAND: it must register exactly one top-level command, be
|
|
27
|
+
* registered onto `program` (not onto a subcommand group), and have no other
|
|
28
|
+
* module contributing subcommands to it. The parity test enforces the shape;
|
|
29
|
+
* these three conditions are what make the entry correct in the first place.
|
|
30
|
+
*/
|
|
31
|
+
import type { Command } from "commander";
|
|
32
|
+
export type LazyCommand = {
|
|
33
|
+
/** The top-level token this matches — `hq <name> …`. */
|
|
34
|
+
name: string;
|
|
35
|
+
/** Registers this one command onto `program`, importing only its module. */
|
|
36
|
+
register: (program: Command) => Promise<void>;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* The hot paths, in descending order of how often automation calls them.
|
|
40
|
+
*
|
|
41
|
+
* `secrets` and `run` are the two commands HQ's own tooling puts on the inner
|
|
42
|
+
* loop: every fleet worker shells through one of them before each external
|
|
43
|
+
* command, which is exactly the shape that makes eager import expensive.
|
|
44
|
+
*/
|
|
45
|
+
export declare const LAZY_COMMANDS: readonly LazyCommand[];
|
|
46
|
+
/**
|
|
47
|
+
* Resolve `process.argv` to a manifest entry, or null to use the full graph.
|
|
48
|
+
*
|
|
49
|
+
* argv is `[node, hq, <name>, ...rest]`. `hq` declares no program-level options
|
|
50
|
+
* before the command name, so argv[2] is the command token when there is one;
|
|
51
|
+
* `--help`, `--version`, and a bare `hq` all fail the lookup and take the
|
|
52
|
+
* fallback, which is the intended behaviour — help must list every command.
|
|
53
|
+
*/
|
|
54
|
+
export declare function findLazyCommand(argv: readonly string[]): LazyCommand | null;
|
|
55
|
+
//# sourceMappingURL=lazy-commands.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hot-command manifest for the entrypoint's lazy registration.
|
|
3
|
+
*
|
|
4
|
+
* main.ts used to import the entire ~60-module command graph at module scope,
|
|
5
|
+
* so every invocation paid for every command. That is fine for a human typing
|
|
6
|
+
* one command and ruinous for the calls automation makes in a loop: the
|
|
7
|
+
* hq-sentry agent fleet on an outpost runs `hq secrets` about 39 times a minute
|
|
8
|
+
* (each worker resolves credentials before every external command it executes),
|
|
9
|
+
* and each of those processes spent ~0.75 CPU-seconds importing commands it
|
|
10
|
+
* never ran — around half a core, continuously. Measured on Outpost 2
|
|
11
|
+
* (i-09424eff61920a4ac) 2026-09-05; see register-all.ts for the numbers.
|
|
12
|
+
*
|
|
13
|
+
* A command listed here registers ITSELF and nothing else. Anything not listed
|
|
14
|
+
* — `--help`, a bare `hq`, an unknown command, every other command — falls back
|
|
15
|
+
* to `registerAllCommands`, the complete unchanged graph. That fallback is what
|
|
16
|
+
* makes this safe to extend one command at a time: an entry is a performance
|
|
17
|
+
* opt-in, never a behaviour change, and a command that is absent here is simply
|
|
18
|
+
* as fast as it was before.
|
|
19
|
+
*
|
|
20
|
+
* This mirrors commands/scaffold-fast.ts, which does the same thing for the
|
|
21
|
+
* relocated `hq core …` scripts, and carries the same anti-drift discipline: a
|
|
22
|
+
* parity test registers each entry BOTH ways and asserts the resulting command
|
|
23
|
+
* shape is identical, so a manifest entry cannot silently diverge from the real
|
|
24
|
+
* registration.
|
|
25
|
+
*
|
|
26
|
+
* TO ADD A COMMAND: it must register exactly one top-level command, be
|
|
27
|
+
* registered onto `program` (not onto a subcommand group), and have no other
|
|
28
|
+
* module contributing subcommands to it. The parity test enforces the shape;
|
|
29
|
+
* these three conditions are what make the entry correct in the first place.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* The hot paths, in descending order of how often automation calls them.
|
|
33
|
+
*
|
|
34
|
+
* `secrets` and `run` are the two commands HQ's own tooling puts on the inner
|
|
35
|
+
* loop: every fleet worker shells through one of them before each external
|
|
36
|
+
* command, which is exactly the shape that makes eager import expensive.
|
|
37
|
+
*/
|
|
38
|
+
export const LAZY_COMMANDS = [
|
|
39
|
+
{
|
|
40
|
+
name: "secrets",
|
|
41
|
+
register: async (program) => {
|
|
42
|
+
const { registerSecretsCommand } = await import("./commands/secrets.js");
|
|
43
|
+
registerSecretsCommand(program);
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "run",
|
|
48
|
+
register: async (program) => {
|
|
49
|
+
const { registerRunCommand } = await import("./commands/run.js");
|
|
50
|
+
registerRunCommand(program);
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
/**
|
|
55
|
+
* Resolve `process.argv` to a manifest entry, or null to use the full graph.
|
|
56
|
+
*
|
|
57
|
+
* argv is `[node, hq, <name>, ...rest]`. `hq` declares no program-level options
|
|
58
|
+
* before the command name, so argv[2] is the command token when there is one;
|
|
59
|
+
* `--help`, `--version`, and a bare `hq` all fail the lookup and take the
|
|
60
|
+
* fallback, which is the intended behaviour — help must list every command.
|
|
61
|
+
*/
|
|
62
|
+
export function findLazyCommand(argv) {
|
|
63
|
+
const name = argv[2];
|
|
64
|
+
if (typeof name !== "string")
|
|
65
|
+
return null;
|
|
66
|
+
return LAZY_COMMANDS.find((candidate) => candidate.name === name) ?? null;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=lazy-commands.js.map
|
|
@@ -49,6 +49,25 @@ export declare const RUNTIME_PROBE_PREFIX = "hooks.runtime";
|
|
|
49
49
|
export declare const POLICY_TRIGGER_LEDGER_RELPATH = "workspace/orchestrator/policy-trigger-state";
|
|
50
50
|
/** The two lifecycle events `check-hq-hooks.sh` requires a command hook on. */
|
|
51
51
|
export declare const REQUIRED_HOOK_EVENTS: readonly ["SessionStart", "PreToolUse"];
|
|
52
|
+
/**
|
|
53
|
+
* Default runtime marker path an agents-v2 (hermes) box writes its runtime mode
|
|
54
|
+
* to. Overridable via `HQ_RUNTIME_MARKER_FILE`, exactly as the shell reads
|
|
55
|
+
* `${HQ_RUNTIME_MARKER_FILE:-/var/lib/hq-agent/runtime.json}`.
|
|
56
|
+
*/
|
|
57
|
+
export declare const HQ_RUNTIME_MARKER_DEFAULT = "/var/lib/hq-agent/runtime.json";
|
|
58
|
+
/**
|
|
59
|
+
* Path (relative to the HQ root) of the on-box agents-v2 hook adapter. Its
|
|
60
|
+
* presence under the tree is one of the two signals that the runtime is
|
|
61
|
+
* agents-v2, mirroring `hq_runtime_mode` in `check-hq-hooks.sh`.
|
|
62
|
+
*/
|
|
63
|
+
export declare const AGENTS_V2_ADAPTER_RELPATH = ".agents-v2-hooks/hq-agents-v2-hook-adapter.sh";
|
|
64
|
+
/**
|
|
65
|
+
* Default hours a policy-trigger ledger may age and still evidence a live
|
|
66
|
+
* agents-v2 turn when no exact session id is given. Overridable via
|
|
67
|
+
* `HQ_V2_LEDGER_MAX_AGE_HOURS`, matching the shell's
|
|
68
|
+
* `HQ_V2_LEDGER_MAX_AGE_HOURS="${HQ_V2_LEDGER_MAX_AGE_HOURS:-24}"`.
|
|
69
|
+
*/
|
|
70
|
+
export declare const HQ_V2_LEDGER_MAX_AGE_HOURS_DEFAULT = 24;
|
|
52
71
|
/** Whether the ledger was found. Mirrors the script's `present`/`missing`. */
|
|
53
72
|
export type LedgerState = "present" | "missing";
|
|
54
73
|
/** Options for {@link reproduceCheckHqHooks}. */
|
|
@@ -92,6 +111,43 @@ export interface HookLoadReproduction {
|
|
|
92
111
|
* exception, so the probe degrades exactly like the defensively-written script.
|
|
93
112
|
*/
|
|
94
113
|
export declare function reproduceCheckHqHooks(opts: ReproduceOptions): HookLoadReproduction;
|
|
114
|
+
/** Inputs for the agents-v2 attestation helpers. */
|
|
115
|
+
export interface AgentsV2AttestationOptions {
|
|
116
|
+
/** Absolute HQ tree root. */
|
|
117
|
+
hqRoot: string;
|
|
118
|
+
/** Optional session scope for the ledger check (the `--session-id` flag). */
|
|
119
|
+
sessionId?: string;
|
|
120
|
+
/** Environment to read (marker path, freshness window). Default: process.env. */
|
|
121
|
+
env?: NodeJS.ProcessEnv;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Whether the runtime is agents-v2. Two signals, either sufficient — the same
|
|
125
|
+
* two `hq_runtime_mode` uses: the runtime marker
|
|
126
|
+
* (`HQ_RUNTIME_MARKER_FILE`, default {@link HQ_RUNTIME_MARKER_DEFAULT}) reads
|
|
127
|
+
* `runtimeMode == "agents-v2"`, OR the on-box adapter is installed under the
|
|
128
|
+
* tree at {@link AGENTS_V2_ADAPTER_RELPATH}.
|
|
129
|
+
*/
|
|
130
|
+
export declare function isAgentsV2Runtime(hqRoot: string, env?: NodeJS.ProcessEnv): boolean;
|
|
131
|
+
/**
|
|
132
|
+
* Whether `.claude/settings.json` wires the on-box agents-v2 hook adapter — a
|
|
133
|
+
* raw substring match on the file, exactly like the shell's
|
|
134
|
+
* `grep -q 'hq-agents-v2-hook-adapter\.sh'` in `hq_settings_wires_v2_adapter`.
|
|
135
|
+
*/
|
|
136
|
+
export declare function settingsWireV2Adapter(hqRoot: string): boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Whether a policy-trigger ledger evidencing a live agents-v2 turn is present:
|
|
139
|
+
* the exact session's ledger when a session id is given (session identity
|
|
140
|
+
* implies freshness), otherwise any ledger modified within the freshness window
|
|
141
|
+
* so a long-dead tree cannot self-attest off a stale file. Mirrors
|
|
142
|
+
* `hq_v2_ledger_present`.
|
|
143
|
+
*/
|
|
144
|
+
export declare function v2LedgerPresent(opts: AgentsV2AttestationOptions): boolean;
|
|
145
|
+
/**
|
|
146
|
+
* All three agents-v2 self-attestation conditions. Used only to GRANT PASS to a
|
|
147
|
+
* hermes box that host detection leaves platform-unknown; never to withhold it.
|
|
148
|
+
* The exact conjunction of `agents_v2_attested` in `check-hq-hooks.sh`.
|
|
149
|
+
*/
|
|
150
|
+
export declare function agentsV2Attested(opts: AgentsV2AttestationOptions): boolean;
|
|
95
151
|
/**
|
|
96
152
|
* The runtime-probe check family entry. Reproduces the script verdict, then
|
|
97
153
|
* renders it as a single platform-aware doctor result. See the module header for
|
|
@@ -51,6 +51,25 @@ export const RUNTIME_PROBE_PREFIX = "hooks.runtime";
|
|
|
51
51
|
export const POLICY_TRIGGER_LEDGER_RELPATH = "workspace/orchestrator/policy-trigger-state";
|
|
52
52
|
/** The two lifecycle events `check-hq-hooks.sh` requires a command hook on. */
|
|
53
53
|
export const REQUIRED_HOOK_EVENTS = ["SessionStart", "PreToolUse"];
|
|
54
|
+
/**
|
|
55
|
+
* Default runtime marker path an agents-v2 (hermes) box writes its runtime mode
|
|
56
|
+
* to. Overridable via `HQ_RUNTIME_MARKER_FILE`, exactly as the shell reads
|
|
57
|
+
* `${HQ_RUNTIME_MARKER_FILE:-/var/lib/hq-agent/runtime.json}`.
|
|
58
|
+
*/
|
|
59
|
+
export const HQ_RUNTIME_MARKER_DEFAULT = "/var/lib/hq-agent/runtime.json";
|
|
60
|
+
/**
|
|
61
|
+
* Path (relative to the HQ root) of the on-box agents-v2 hook adapter. Its
|
|
62
|
+
* presence under the tree is one of the two signals that the runtime is
|
|
63
|
+
* agents-v2, mirroring `hq_runtime_mode` in `check-hq-hooks.sh`.
|
|
64
|
+
*/
|
|
65
|
+
export const AGENTS_V2_ADAPTER_RELPATH = ".agents-v2-hooks/hq-agents-v2-hook-adapter.sh";
|
|
66
|
+
/**
|
|
67
|
+
* Default hours a policy-trigger ledger may age and still evidence a live
|
|
68
|
+
* agents-v2 turn when no exact session id is given. Overridable via
|
|
69
|
+
* `HQ_V2_LEDGER_MAX_AGE_HOURS`, matching the shell's
|
|
70
|
+
* `HQ_V2_LEDGER_MAX_AGE_HOURS="${HQ_V2_LEDGER_MAX_AGE_HOURS:-24}"`.
|
|
71
|
+
*/
|
|
72
|
+
export const HQ_V2_LEDGER_MAX_AGE_HOURS_DEFAULT = 24;
|
|
54
73
|
/**
|
|
55
74
|
* Faithfully reproduce `core/scripts/check-hq-hooks.sh --require-ledger` in
|
|
56
75
|
* TypeScript. The checks, in the script's order:
|
|
@@ -110,6 +129,117 @@ export function reproduceCheckHqHooks(opts) {
|
|
|
110
129
|
}
|
|
111
130
|
return { ok: issues.length === 0, ledgerState, issues };
|
|
112
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Whether the runtime is agents-v2. Two signals, either sufficient — the same
|
|
134
|
+
* two `hq_runtime_mode` uses: the runtime marker
|
|
135
|
+
* (`HQ_RUNTIME_MARKER_FILE`, default {@link HQ_RUNTIME_MARKER_DEFAULT}) reads
|
|
136
|
+
* `runtimeMode == "agents-v2"`, OR the on-box adapter is installed under the
|
|
137
|
+
* tree at {@link AGENTS_V2_ADAPTER_RELPATH}.
|
|
138
|
+
*/
|
|
139
|
+
export function isAgentsV2Runtime(hqRoot, env = process.env) {
|
|
140
|
+
const markerPath = env.HQ_RUNTIME_MARKER_FILE?.trim() || HQ_RUNTIME_MARKER_DEFAULT;
|
|
141
|
+
if (readRuntimeMarkerMode(markerPath) === "agents-v2")
|
|
142
|
+
return true;
|
|
143
|
+
return isFile(path.join(hqRoot, ...AGENTS_V2_ADAPTER_RELPATH.split("/")));
|
|
144
|
+
}
|
|
145
|
+
/** The `runtimeMode` field of the runtime marker JSON, or null when unreadable. */
|
|
146
|
+
function readRuntimeMarkerMode(markerPath) {
|
|
147
|
+
let raw;
|
|
148
|
+
try {
|
|
149
|
+
raw = fs.readFileSync(markerPath, "utf8");
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const parsed = JSON.parse(raw);
|
|
156
|
+
return typeof parsed.runtimeMode === "string" ? parsed.runtimeMode : null;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Whether `.claude/settings.json` wires the on-box agents-v2 hook adapter — a
|
|
164
|
+
* raw substring match on the file, exactly like the shell's
|
|
165
|
+
* `grep -q 'hq-agents-v2-hook-adapter\.sh'` in `hq_settings_wires_v2_adapter`.
|
|
166
|
+
*/
|
|
167
|
+
export function settingsWireV2Adapter(hqRoot) {
|
|
168
|
+
let raw;
|
|
169
|
+
try {
|
|
170
|
+
raw = fs.readFileSync(path.join(hqRoot, ".claude", "settings.json"), "utf8");
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
return raw.includes("hq-agents-v2-hook-adapter.sh");
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Whether a policy-trigger ledger evidencing a live agents-v2 turn is present:
|
|
179
|
+
* the exact session's ledger when a session id is given (session identity
|
|
180
|
+
* implies freshness), otherwise any ledger modified within the freshness window
|
|
181
|
+
* so a long-dead tree cannot self-attest off a stale file. Mirrors
|
|
182
|
+
* `hq_v2_ledger_present`.
|
|
183
|
+
*/
|
|
184
|
+
export function v2LedgerPresent(opts) {
|
|
185
|
+
const env = opts.env ?? process.env;
|
|
186
|
+
const dir = path.join(opts.hqRoot, ...POLICY_TRIGGER_LEDGER_RELPATH.split("/"));
|
|
187
|
+
if (!isDir(dir))
|
|
188
|
+
return false;
|
|
189
|
+
if (opts.sessionId) {
|
|
190
|
+
return isFile(path.join(dir, `${opts.sessionId}.txt`));
|
|
191
|
+
}
|
|
192
|
+
const cutoffMs = Date.now() - resolveMaxLedgerAgeHours(env) * 60 * 60 * 1000;
|
|
193
|
+
return ledgerDirHasFreshTxt(dir, cutoffMs);
|
|
194
|
+
}
|
|
195
|
+
/** The freshness window in hours, from the env override or the default. */
|
|
196
|
+
function resolveMaxLedgerAgeHours(env) {
|
|
197
|
+
const raw = env.HQ_V2_LEDGER_MAX_AGE_HOURS?.trim();
|
|
198
|
+
if (!raw)
|
|
199
|
+
return HQ_V2_LEDGER_MAX_AGE_HOURS_DEFAULT;
|
|
200
|
+
const parsed = Number.parseInt(raw, 10);
|
|
201
|
+
return Number.isFinite(parsed) && parsed >= 0
|
|
202
|
+
? parsed
|
|
203
|
+
: HQ_V2_LEDGER_MAX_AGE_HOURS_DEFAULT;
|
|
204
|
+
}
|
|
205
|
+
/** True when any `*.txt` under `dir` (recursive) was modified at/after `cutoffMs`. */
|
|
206
|
+
function ledgerDirHasFreshTxt(dir, cutoffMs) {
|
|
207
|
+
let entries;
|
|
208
|
+
try {
|
|
209
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
for (const entry of entries) {
|
|
215
|
+
const full = path.join(dir, entry.name);
|
|
216
|
+
if (entry.isDirectory()) {
|
|
217
|
+
if (ledgerDirHasFreshTxt(full, cutoffMs))
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
else if (entry.isFile() && entry.name.endsWith(".txt")) {
|
|
221
|
+
try {
|
|
222
|
+
if (fs.statSync(full).mtimeMs >= cutoffMs)
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// Unreadable entry: ignore, keep scanning.
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* All three agents-v2 self-attestation conditions. Used only to GRANT PASS to a
|
|
234
|
+
* hermes box that host detection leaves platform-unknown; never to withhold it.
|
|
235
|
+
* The exact conjunction of `agents_v2_attested` in `check-hq-hooks.sh`.
|
|
236
|
+
*/
|
|
237
|
+
export function agentsV2Attested(opts) {
|
|
238
|
+
const env = opts.env ?? process.env;
|
|
239
|
+
return (isAgentsV2Runtime(opts.hqRoot, env) &&
|
|
240
|
+
settingsWireV2Adapter(opts.hqRoot) &&
|
|
241
|
+
v2LedgerPresent({ ...opts, env }));
|
|
242
|
+
}
|
|
113
243
|
/**
|
|
114
244
|
* The runtime-probe check family entry. Reproduces the script verdict, then
|
|
115
245
|
* renders it as a single platform-aware doctor result. See the module header for
|
|
@@ -122,6 +252,26 @@ export function checkRuntimeProbe(context) {
|
|
|
122
252
|
const checkId = `${RUNTIME_PROBE_PREFIX}.enforcement`;
|
|
123
253
|
const target = POLICY_TRIGGER_LEDGER_RELPATH;
|
|
124
254
|
const scope = sessionId ? ` for session ${sessionId}` : "";
|
|
255
|
+
// agents-v2 (hermes) self-attestation. hq doctor leaves the hermes host
|
|
256
|
+
// platform-unknown and, on an unknown host, the probe would report UNKNOWN
|
|
257
|
+
// below. But the on-box adapter provably wrote the ledger through the same
|
|
258
|
+
// .claude hooks, so grant PASS — and report platform "agents-v2" — when, and
|
|
259
|
+
// only when, the runtime is agents-v2, settings wire the on-box adapter, and a
|
|
260
|
+
// ledger exists (the exact session's under --session-id; otherwise any ledger
|
|
261
|
+
// fresh within the window). Requires the on-box marker/adapter, so this never
|
|
262
|
+
// changes the verdict for any other host. See agentsV2Attested().
|
|
263
|
+
if (agentsV2Attested({ hqRoot, sessionId })) {
|
|
264
|
+
return [
|
|
265
|
+
{
|
|
266
|
+
status: "PASS",
|
|
267
|
+
checkId,
|
|
268
|
+
target,
|
|
269
|
+
message: `Host platform is agents-v2 (hermes fleet): the on-box adapter wrote the ` +
|
|
270
|
+
`policy-trigger ledger through the same .claude hooks, so hook dispatch was ` +
|
|
271
|
+
`observed this session — the ledger has an entry${scope}.`,
|
|
272
|
+
},
|
|
273
|
+
];
|
|
274
|
+
}
|
|
125
275
|
const repro = reproduceCheckHqHooks({ hqRoot, sessionId });
|
|
126
276
|
// Unknown host: the label cannot be trusted, so live enforcement cannot be
|
|
127
277
|
// verified in either direction. UNKNOWN (never PASS or FAIL) is the honest
|
|
@@ -332,4 +482,12 @@ function isFile(file) {
|
|
|
332
482
|
return false;
|
|
333
483
|
}
|
|
334
484
|
}
|
|
485
|
+
function isDir(dir) {
|
|
486
|
+
try {
|
|
487
|
+
return fs.statSync(dir).isDirectory();
|
|
488
|
+
}
|
|
489
|
+
catch {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
335
493
|
//# sourceMappingURL=runtime-probe.js.map
|
|
@@ -74,6 +74,22 @@ export interface DeriveVerdictOptions {
|
|
|
74
74
|
* inline script treats a missing ledger — regardless of platform.
|
|
75
75
|
*/
|
|
76
76
|
requireLedger?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Whether this is an attested agents-v2 (hermes) box: the runtime is
|
|
79
|
+
* agents-v2, `.claude/settings.json` wires the on-box adapter, and a
|
|
80
|
+
* policy-trigger ledger exists (the exact session's when a session id is
|
|
81
|
+
* given; otherwise a ledger fresh within the freshness window). When true,
|
|
82
|
+
* OBSERVED is granted even though the doctor's runtime check did not report
|
|
83
|
+
* PASS — because hq doctor leaves the hermes host platform-unknown, yet the
|
|
84
|
+
* on-box adapter provably wrote the ledger through the same .claude hooks.
|
|
85
|
+
*
|
|
86
|
+
* This is the exact twin of the `agents_v2_attested` override in
|
|
87
|
+
* `render_from_doctor` (`core/scripts/check-hq-hooks.sh`). Establish it with
|
|
88
|
+
* {@link agentsV2Attested} in `checks/runtime-probe.ts` — the same three
|
|
89
|
+
* signals the shell's `agents_v2_attested` reads. It can only GRANT OBSERVED,
|
|
90
|
+
* never withhold it, so every non-agents-v2 caller is unaffected.
|
|
91
|
+
*/
|
|
92
|
+
agentsV2Attested?: boolean;
|
|
77
93
|
}
|
|
78
94
|
/**
|
|
79
95
|
* Derive the check-hq-hooks.sh verdict from a `hq doctor --json` document,
|
|
@@ -80,7 +80,18 @@ export function deriveCheckHqHooksVerdict(doc, options = {}) {
|
|
|
80
80
|
// for --require-ledger, matching the inline script's "fail on a missing
|
|
81
81
|
// ledger" contract.
|
|
82
82
|
const runtimeResult = doc.results.find((result) => result.checkId === RUNTIME_ENFORCEMENT_CHECK_ID);
|
|
83
|
-
|
|
83
|
+
let runtime = observeRuntime(runtimeResult?.status, requireLedger);
|
|
84
|
+
// agents-v2 self-attestation: hq doctor leaves the hermes host
|
|
85
|
+
// platform-unknown and so does not report the runtime check as PASS, but the
|
|
86
|
+
// on-box adapter provably wrote the ledger through the same .claude hooks.
|
|
87
|
+
// Grant the identical OBSERVED verdict rather than relaying the host-unknown
|
|
88
|
+
// status as a failure. Mirrors render_from_doctor()'s agents_v2_attested
|
|
89
|
+
// override in check-hq-hooks.sh; only ever grants OBSERVED, never withholds it.
|
|
90
|
+
if (requireLedger &&
|
|
91
|
+
runtime !== "OBSERVED" &&
|
|
92
|
+
options.agentsV2Attested === true) {
|
|
93
|
+
runtime = "OBSERVED";
|
|
94
|
+
}
|
|
84
95
|
if (requireLedger && runtime !== "OBSERVED") {
|
|
85
96
|
messages.push(runtimeResult?.message ??
|
|
86
97
|
"policy-trigger ledger was not found under workspace/orchestrator/policy-trigger-state");
|
|
@@ -5,7 +5,7 @@ export { CREDENTIAL_RENEWAL_FRACTION, DEFAULT_REFUSED_RETRY_MS, MAX_RETRY_DELAY_
|
|
|
5
5
|
export type { BoundedTimeoutHandle, Contract3Bundle, CredentialRenewalErrorInfo, CredentialVendFailureKind, CredentialVendPostResult, CredentialsFetcher, PresenceCompany, TimerHost, } from "./credentials.js";
|
|
6
6
|
export { amzDateOf, hex, presignIotWssUrl, rfc3986Encode } from "./presign.js";
|
|
7
7
|
export type { IotCredentials } from "./presign.js";
|
|
8
|
-
export { PresenceClient, backoffDelayMs, buildPresencePayload, defaultMqttConnect, isOwnPresenceTopic, } from "./presence.js";
|
|
8
|
+
export { CLOSE_LOG_ALWAYS_COUNT, CLOSE_LOG_INTERVAL_MS, CONNECT_STABLE_GRACE_MS, PresenceClient, backoffDelayMs, buildPresencePayload, defaultMqttConnect, isOwnPresenceTopic, } from "./presence.js";
|
|
9
9
|
export type { MeshMqttClientLike, MqttConnectFn, MqttConnectionState, PresenceClientOptions, PresencePayload, PresenceRefusal, } from "./presence.js";
|
|
10
10
|
export { defaultDaemonState, patchDaemonState, readDaemonState, writeDaemonState, } from "./state.js";
|
|
11
11
|
export type { DaemonStateFile, PresenceRefusalState } from "./state.js";
|
|
@@ -2,7 +2,7 @@ export { DAEMON_DIRNAME, DAEMON_LOG_MAX_BYTES, DAEMON_LOG_NAME, DAEMON_PID_NAME,
|
|
|
2
2
|
export { acquirePidLock, defaultPidLockDeps, parsePidLock, pidLockStatus, readPidLock, releasePidLock, resolveDaemonDir, } from "./pid-lock.js";
|
|
3
3
|
export { CREDENTIAL_RENEWAL_FRACTION, DEFAULT_REFUSED_RETRY_MS, MAX_RETRY_DELAY_MS, MAX_TIMER_DELAY_MS, MQTT_KEEPALIVE_SECONDS, REALTIME_CREDENTIALS_PATH, REFUSED_RETRY_ENV, CredentialRenewalManager, CredentialVendError, classifyCredentialVendFailure, clampRetryDelayMs, createContract3Fetcher, defaultRefusedRetryMs, extractVendErrorCode, isCredentialVendRefused, normalizeContract3Bundle, parseRetryAfterMs, realTimerHost, refusedRetryDelayMs, renewalDelayMs, scheduleBoundedTimeout, } from "./credentials.js";
|
|
4
4
|
export { amzDateOf, hex, presignIotWssUrl, rfc3986Encode } from "./presign.js";
|
|
5
|
-
export { PresenceClient, backoffDelayMs, buildPresencePayload, defaultMqttConnect, isOwnPresenceTopic, } from "./presence.js";
|
|
5
|
+
export { CLOSE_LOG_ALWAYS_COUNT, CLOSE_LOG_INTERVAL_MS, CONNECT_STABLE_GRACE_MS, PresenceClient, backoffDelayMs, buildPresencePayload, defaultMqttConnect, isOwnPresenceTopic, } from "./presence.js";
|
|
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";
|
|
@@ -7,11 +7,22 @@
|
|
|
7
7
|
* - Offline is server-only (IoT lifecycle → PresenceIngestFunction)
|
|
8
8
|
* - Never subscribes to thread topics
|
|
9
9
|
* - Reconnects with monotonic full-jitter backoff 1s–60s on close / network
|
|
10
|
+
* - Backoff resets only after the connection stays up past
|
|
11
|
+
* {@link CONNECT_STABLE_GRACE_MS} (broker accept-then-close must not reset)
|
|
10
12
|
* - Server credential refusals use a long retry (default 10m ±20%)
|
|
11
13
|
*/
|
|
12
14
|
import { type IClientOptions, type MqttClient } from "mqtt";
|
|
13
15
|
import { type Contract3Bundle, type CredentialsFetcher, type TimerHost } from "./credentials.js";
|
|
14
16
|
export type MqttConnectionState = "idle" | "connecting" | "connected" | "reconnecting" | "closed";
|
|
17
|
+
/**
|
|
18
|
+
* A connection that drops before this grace window after `connect` is treated
|
|
19
|
+
* as a failed attempt: backoff counters are not reset (AWS IoT often accepts
|
|
20
|
+
* then closes immediately after a denied publish).
|
|
21
|
+
*/
|
|
22
|
+
export declare const CONNECT_STABLE_GRACE_MS = 5000;
|
|
23
|
+
/** Always emit the first N close info lines, then at most one per interval. */
|
|
24
|
+
export declare const CLOSE_LOG_ALWAYS_COUNT = 3;
|
|
25
|
+
export declare const CLOSE_LOG_INTERVAL_MS = 60000;
|
|
15
26
|
export interface PresencePayload {
|
|
16
27
|
v: 1;
|
|
17
28
|
status: "online" | "offline";
|
|
@@ -49,6 +60,8 @@ export interface PresenceClientOptions {
|
|
|
49
60
|
onOnline?: (companies: string[]) => void;
|
|
50
61
|
onState?: (state: MqttConnectionState) => void;
|
|
51
62
|
onError?: (err: unknown) => void;
|
|
63
|
+
/** Non-error info lines (e.g. rate-limited mqtt close / backoff). */
|
|
64
|
+
onInfo?: (message: string) => void;
|
|
52
65
|
/** Fired when refusal appears, code changes, clears, or nextRetryAt updates. */
|
|
53
66
|
onRefusal?: (refusal: PresenceRefusal | null) => void;
|
|
54
67
|
now?: () => Date;
|
|
@@ -78,6 +91,10 @@ export declare class PresenceClient {
|
|
|
78
91
|
private attempt;
|
|
79
92
|
private lastBackoffMs;
|
|
80
93
|
private reconnectHandle;
|
|
94
|
+
private stableHandle;
|
|
95
|
+
private connectedAtMs;
|
|
96
|
+
private closeLogCount;
|
|
97
|
+
private lastCloseLogAtMs;
|
|
81
98
|
private stopped;
|
|
82
99
|
private generation;
|
|
83
100
|
private publishedTopics;
|
|
@@ -118,7 +135,9 @@ export declare class PresenceClient {
|
|
|
118
135
|
/** Publish retained online to every own presence topic (connect / renew). */
|
|
119
136
|
private publishAll;
|
|
120
137
|
private scheduleReconnect;
|
|
138
|
+
private maybeLogClose;
|
|
121
139
|
private clearReconnect;
|
|
140
|
+
private clearStableTimer;
|
|
122
141
|
}
|
|
123
142
|
/** Production mqtt.connect wrapper (typed). */
|
|
124
143
|
export declare function defaultMqttConnect(url: string, opts: IClientOptions): MqttClient;
|
|
@@ -7,11 +7,22 @@
|
|
|
7
7
|
* - Offline is server-only (IoT lifecycle → PresenceIngestFunction)
|
|
8
8
|
* - Never subscribes to thread topics
|
|
9
9
|
* - Reconnects with monotonic full-jitter backoff 1s–60s on close / network
|
|
10
|
+
* - Backoff resets only after the connection stays up past
|
|
11
|
+
* {@link CONNECT_STABLE_GRACE_MS} (broker accept-then-close must not reset)
|
|
10
12
|
* - Server credential refusals use a long retry (default 10m ±20%)
|
|
11
13
|
*/
|
|
12
14
|
import mqtt from "mqtt";
|
|
13
15
|
import { CredentialVendError, CredentialRenewalManager, MQTT_KEEPALIVE_SECONDS, clampRetryDelayMs, defaultRefusedRetryMs, realTimerHost, refusedRetryDelayMs, scheduleBoundedTimeout, } from "./credentials.js";
|
|
14
16
|
import { presignIotWssUrl } from "./presign.js";
|
|
17
|
+
/**
|
|
18
|
+
* A connection that drops before this grace window after `connect` is treated
|
|
19
|
+
* as a failed attempt: backoff counters are not reset (AWS IoT often accepts
|
|
20
|
+
* then closes immediately after a denied publish).
|
|
21
|
+
*/
|
|
22
|
+
export const CONNECT_STABLE_GRACE_MS = 5_000;
|
|
23
|
+
/** Always emit the first N close info lines, then at most one per interval. */
|
|
24
|
+
export const CLOSE_LOG_ALWAYS_COUNT = 3;
|
|
25
|
+
export const CLOSE_LOG_INTERVAL_MS = 60_000;
|
|
15
26
|
/**
|
|
16
27
|
* Full-jitter capped exponential backoff (1s base → 60s cap by default),
|
|
17
28
|
* floored at `previousMs` so consecutive failures never shrink the delay.
|
|
@@ -50,6 +61,10 @@ export class PresenceClient {
|
|
|
50
61
|
attempt = 0;
|
|
51
62
|
lastBackoffMs = 0;
|
|
52
63
|
reconnectHandle = null;
|
|
64
|
+
stableHandle = null;
|
|
65
|
+
connectedAtMs = null;
|
|
66
|
+
closeLogCount = 0;
|
|
67
|
+
lastCloseLogAtMs = Number.NEGATIVE_INFINITY;
|
|
53
68
|
stopped = false;
|
|
54
69
|
generation = 0;
|
|
55
70
|
publishedTopics = [];
|
|
@@ -113,6 +128,8 @@ export class PresenceClient {
|
|
|
113
128
|
this.generation += 1;
|
|
114
129
|
this.renewal.stop();
|
|
115
130
|
this.clearReconnect();
|
|
131
|
+
this.clearStableTimer();
|
|
132
|
+
this.connectedAtMs = null;
|
|
116
133
|
this.teardownClient(false);
|
|
117
134
|
this.clearRefusal(/* logClear */ false);
|
|
118
135
|
this.setState("closed");
|
|
@@ -128,7 +145,7 @@ export class PresenceClient {
|
|
|
128
145
|
return;
|
|
129
146
|
}
|
|
130
147
|
}
|
|
131
|
-
// Backoff counters reset only
|
|
148
|
+
// Backoff counters reset only after a stable connection — not here.
|
|
132
149
|
this.clearReconnect();
|
|
133
150
|
void this.connectOnce();
|
|
134
151
|
}
|
|
@@ -155,7 +172,7 @@ export class PresenceClient {
|
|
|
155
172
|
this.clearRefusal(true);
|
|
156
173
|
if (this.stopped)
|
|
157
174
|
return;
|
|
158
|
-
// Reconnect with the new presigned URL; backoff resets only
|
|
175
|
+
// Reconnect with the new presigned URL; backoff resets only after stable connect.
|
|
159
176
|
await this.connectOnce();
|
|
160
177
|
}
|
|
161
178
|
handleRenewalError(err, info) {
|
|
@@ -200,6 +217,8 @@ export class PresenceClient {
|
|
|
200
217
|
if (this.stopped)
|
|
201
218
|
return;
|
|
202
219
|
this.clearReconnect();
|
|
220
|
+
this.clearStableTimer();
|
|
221
|
+
this.connectedAtMs = null;
|
|
203
222
|
const generation = ++this.generation;
|
|
204
223
|
this.teardownClient(true);
|
|
205
224
|
try {
|
|
@@ -233,8 +252,17 @@ export class PresenceClient {
|
|
|
233
252
|
client.on("connect", () => {
|
|
234
253
|
if (this.stopped || generation !== this.generation)
|
|
235
254
|
return;
|
|
236
|
-
|
|
237
|
-
|
|
255
|
+
// Do not reset attempt here — broker may accept then close immediately
|
|
256
|
+
// (denied publish / policy). Reset only after CONNECT_STABLE_GRACE_MS.
|
|
257
|
+
this.connectedAtMs = this.timers.now();
|
|
258
|
+
this.clearStableTimer();
|
|
259
|
+
this.stableHandle = scheduleBoundedTimeout(this.timers, () => {
|
|
260
|
+
this.stableHandle = null;
|
|
261
|
+
if (this.stopped || generation !== this.generation)
|
|
262
|
+
return;
|
|
263
|
+
this.attempt = 0;
|
|
264
|
+
this.lastBackoffMs = 0;
|
|
265
|
+
}, CONNECT_STABLE_GRACE_MS);
|
|
238
266
|
this.setState("connected");
|
|
239
267
|
void this.publishAll("online").then(() => {
|
|
240
268
|
this.options.onOnline?.(bundle.companies.map((c) => c.companyUid));
|
|
@@ -248,7 +276,13 @@ export class PresenceClient {
|
|
|
248
276
|
client.on("close", () => {
|
|
249
277
|
if (this.stopped || generation !== this.generation)
|
|
250
278
|
return;
|
|
251
|
-
this.
|
|
279
|
+
const elapsedMs = this.connectedAtMs != null
|
|
280
|
+
? Math.max(0, this.timers.now() - this.connectedAtMs)
|
|
281
|
+
: 0;
|
|
282
|
+
this.connectedAtMs = null;
|
|
283
|
+
this.clearStableTimer();
|
|
284
|
+
const delay = this.scheduleReconnect();
|
|
285
|
+
this.maybeLogClose(elapsedMs, delay);
|
|
252
286
|
});
|
|
253
287
|
}
|
|
254
288
|
catch (err) {
|
|
@@ -295,7 +329,7 @@ export class PresenceClient {
|
|
|
295
329
|
}
|
|
296
330
|
scheduleReconnect(opts) {
|
|
297
331
|
if (this.stopped)
|
|
298
|
-
return;
|
|
332
|
+
return 0;
|
|
299
333
|
this.setState("reconnecting");
|
|
300
334
|
this.clearReconnect();
|
|
301
335
|
let delay;
|
|
@@ -326,6 +360,17 @@ export class PresenceClient {
|
|
|
326
360
|
}
|
|
327
361
|
void this.connectOnce();
|
|
328
362
|
}, delay);
|
|
363
|
+
return delay;
|
|
364
|
+
}
|
|
365
|
+
maybeLogClose(elapsedMs, delayMs) {
|
|
366
|
+
const now = this.timers.now();
|
|
367
|
+
const withinAlways = this.closeLogCount < CLOSE_LOG_ALWAYS_COUNT;
|
|
368
|
+
const intervalElapsed = now - this.lastCloseLogAtMs >= CLOSE_LOG_INTERVAL_MS;
|
|
369
|
+
if (!withinAlways && !intervalElapsed)
|
|
370
|
+
return;
|
|
371
|
+
this.closeLogCount += 1;
|
|
372
|
+
this.lastCloseLogAtMs = now;
|
|
373
|
+
this.options.onInfo?.(`presence mqtt closed after ${elapsedMs}ms; reconnect in ${delayMs}ms`);
|
|
329
374
|
}
|
|
330
375
|
clearReconnect() {
|
|
331
376
|
if (this.reconnectHandle !== null) {
|
|
@@ -333,6 +378,12 @@ export class PresenceClient {
|
|
|
333
378
|
this.reconnectHandle = null;
|
|
334
379
|
}
|
|
335
380
|
}
|
|
381
|
+
clearStableTimer() {
|
|
382
|
+
if (this.stableHandle !== null) {
|
|
383
|
+
this.stableHandle.clear();
|
|
384
|
+
this.stableHandle = null;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
336
387
|
}
|
|
337
388
|
/** Production mqtt.connect wrapper (typed). */
|
|
338
389
|
export function defaultMqttConnect(url, opts) {
|
|
@@ -153,6 +153,9 @@ export async function runMeshDaemon(deps = {}) {
|
|
|
153
153
|
patchDaemonState(dir, { lastErrorCode: msg.slice(0, 120) }, now);
|
|
154
154
|
log(dir, `presence error: ${msg.slice(0, 200)}`);
|
|
155
155
|
},
|
|
156
|
+
onInfo: (message) => {
|
|
157
|
+
log(dir, message.slice(0, 200));
|
|
158
|
+
},
|
|
156
159
|
};
|
|
157
160
|
presence = new PresenceClient(presenceOpts);
|
|
158
161
|
try {
|
package/dist/main.js
CHANGED
|
@@ -8,60 +8,6 @@ import "./node-preflight.js";
|
|
|
8
8
|
import "./node-network-compat.js";
|
|
9
9
|
import { Command } from "commander";
|
|
10
10
|
import { initSentry, Sentry } from "./sentry.js";
|
|
11
|
-
import { registerAddCommand } from "./commands/add.js";
|
|
12
|
-
import { registerSyncCommand } from "./commands/sync.js";
|
|
13
|
-
import { registerListCommand } from "./commands/list.js";
|
|
14
|
-
import { registerUpdateCommand } from "./commands/update.js";
|
|
15
|
-
import { registerCloudCommands } from "./commands/cloud.js";
|
|
16
|
-
import { registerSyncModeCommand } from "./commands/sync-mode.js";
|
|
17
|
-
import { registerSyncNarrowCommand } from "./commands/sync-narrow.js";
|
|
18
|
-
import { registerCloudProvisionCommands } from "./commands/cloud-provision.js";
|
|
19
|
-
import { registerCloudDemoteCommands } from "./commands/cloud-demote.js";
|
|
20
|
-
import { registerLoginCommand } from "./commands/login.js";
|
|
21
|
-
import { registerLogoutCommand } from "./commands/logout.js";
|
|
22
|
-
import { registerWhoamiCommand } from "./commands/whoami.js";
|
|
23
|
-
import { registerOnboardCommand } from "./commands/onboard.js";
|
|
24
|
-
import { registerPackageInstallCommand } from "./commands/pkg-install.js";
|
|
25
|
-
import { registerPackageRemoveCommand } from "./commands/pkg-remove.js";
|
|
26
|
-
import { registerPackageUpdateCommand } from "./commands/pkg-update.js";
|
|
27
|
-
import { registerPackageListCommand } from "./commands/pkg-list.js";
|
|
28
|
-
import { registerPacksCommand } from "./commands/packs.js";
|
|
29
|
-
import { registerPublishCommand } from "./commands/publish.js";
|
|
30
|
-
import { registerCreatorsCommand } from "./commands/creators.js";
|
|
31
|
-
import { registerTeamSyncCommand } from "./commands/team-sync.js";
|
|
32
|
-
import { registerAuthCommands } from "./commands/auth.js";
|
|
33
|
-
import { registerApiKeysCommand } from "./commands/api-keys.js";
|
|
34
|
-
import { registerSecretsCommand } from "./commands/secrets.js";
|
|
35
|
-
import { registerRunCommand } from "./commands/run.js";
|
|
36
|
-
import { registerGroupsCommand } from "./commands/groups.js";
|
|
37
|
-
import { registerWorkersCommand } from "./commands/workers.js";
|
|
38
|
-
import { registerGroupGrantsCommand } from "./commands/group-grants.js";
|
|
39
|
-
import { registerFilesCommand } from "./commands/files.js";
|
|
40
|
-
import { registerFilesBrowseCommands } from "./commands/files-browse.js";
|
|
41
|
-
import { registerSkillCommand } from "./commands/skill.js";
|
|
42
|
-
import { registerMembersCommand } from "./commands/members.js";
|
|
43
|
-
import { registerPeopleCommand } from "./commands/people.js";
|
|
44
|
-
import { registerDmCommand } from "./commands/dm.js";
|
|
45
|
-
import { registerChannelsCommand } from "./commands/channels.js";
|
|
46
|
-
import { registerFeedbackCommand } from "./commands/feedback.js";
|
|
47
|
-
import { registerMeetingsCommand } from "./commands/meetings.js";
|
|
48
|
-
import { registerSourcesCommand } from "./commands/sources.js";
|
|
49
|
-
import { registerSignalsCommand } from "./commands/signals.js";
|
|
50
|
-
import { registerIntegrationsCommand } from "./commands/integrations.js";
|
|
51
|
-
import { registerReindexCommand } from "./commands/reindex.js";
|
|
52
|
-
import { registerRescueCommand } from "./commands/rescue.js";
|
|
53
|
-
import { registerMcpCommand } from "./commands/mcp-status.js";
|
|
54
|
-
import { registerCrmCommand } from "./commands/crm.js";
|
|
55
|
-
import { registerCompanyCommand } from "./commands/company.js";
|
|
56
|
-
import { registerAgentsCommand } from "./commands/agents.js";
|
|
57
|
-
import { registerOutpostsCommand } from "./commands/outposts.js";
|
|
58
|
-
import { registerBillingCommand } from "./commands/billing.js";
|
|
59
|
-
import { registerDbCommand } from "./commands/db.js";
|
|
60
|
-
import { registerCoreCommands } from "./commands/core.js";
|
|
61
|
-
import { registerSearchCommand } from "./commands/search.js";
|
|
62
|
-
import { registerIndexCommand } from "./commands/index-cmd.js";
|
|
63
|
-
import { registerDoctorCommand } from "./commands/doctor.js";
|
|
64
|
-
import { registerMeshCommand } from "./commands/mesh.js";
|
|
65
11
|
import { sanitizeArgv } from "./utils/feedback-diagnostics.js";
|
|
66
12
|
import { environmentalFsErrorMessage } from "./utils/environmental-error.js";
|
|
67
13
|
import { syncStateLockMessage } from "./utils/sync-state-lock-error.js";
|
|
@@ -92,6 +38,7 @@ import { refreshVersionCache, staleAgainstCachedLatest, } from "./utils/version-
|
|
|
92
38
|
import { enforceVersionGate, shouldSkipGate, } from "./utils/version-gate.js";
|
|
93
39
|
import { autoUpdateAndReexec } from "./utils/self-update.js";
|
|
94
40
|
import { CLI_VERSION } from "./cli-version.js";
|
|
41
|
+
import { findLazyCommand } from "./lazy-commands.js";
|
|
95
42
|
import { emitCliSessionStarted } from "./utils/cli-telemetry.js";
|
|
96
43
|
import { reportCliClientHealthInvocation } from "./utils/client-health.js";
|
|
97
44
|
import { settleWithin } from "./utils/settle-with-timeout.js";
|
|
@@ -148,151 +95,6 @@ program
|
|
|
148
95
|
.name("hq")
|
|
149
96
|
.description("HQ management CLI — modules, packages, and cloud sync")
|
|
150
97
|
.version(CLI_VERSION);
|
|
151
|
-
// Module management subcommand group
|
|
152
|
-
const modulesCmd = program
|
|
153
|
-
.command("modules")
|
|
154
|
-
.description("Module management commands");
|
|
155
|
-
registerAddCommand(modulesCmd);
|
|
156
|
-
registerSyncCommand(modulesCmd);
|
|
157
|
-
registerListCommand(modulesCmd);
|
|
158
|
-
registerUpdateCommand(modulesCmd);
|
|
159
|
-
// Package management subcommand group
|
|
160
|
-
const packagesCmd = program
|
|
161
|
-
.command("packages")
|
|
162
|
-
.description("Package management commands");
|
|
163
|
-
registerPackageInstallCommand(packagesCmd);
|
|
164
|
-
registerPackageRemoveCommand(packagesCmd);
|
|
165
|
-
registerPackageUpdateCommand(packagesCmd);
|
|
166
|
-
registerPackageListCommand(packagesCmd);
|
|
167
|
-
// Content-pack lifecycle (core/packages/hq-pack-*). Distinct from the registry
|
|
168
|
-
// `packages` system above. Available as both `hq packages packs …` (grouped)
|
|
169
|
-
// and `hq packs …` (top-level convenience).
|
|
170
|
-
registerPacksCommand(packagesCmd);
|
|
171
|
-
registerPacksCommand(program);
|
|
172
|
-
// Top-level shortcuts for package commands
|
|
173
|
-
// "hq install <slug>" = "hq packages install <slug>"
|
|
174
|
-
// "hq remove <slug>" = "hq packages remove <slug>"
|
|
175
|
-
registerPackageInstallCommand(program);
|
|
176
|
-
registerPackageRemoveCommand(program);
|
|
177
|
-
// Marketplace publish (top-level — packer + authenticated upload, US-004)
|
|
178
|
-
// "hq publish <skill-or-worker-path>" packages and submits a pack to the
|
|
179
|
-
// marketplace via POST /v1/listings.
|
|
180
|
-
registerPublishCommand(program);
|
|
181
|
-
// `hq creators apply` — request verified-creator access (required to publish).
|
|
182
|
-
registerCreatorsCommand(program);
|
|
183
|
-
// Cloud sync subcommand group
|
|
184
|
-
const syncCmd = program
|
|
185
|
-
.command("sync")
|
|
186
|
-
.description("Cloud sync commands — sync HQ to S3 for mobile access");
|
|
187
|
-
registerCloudCommands(syncCmd);
|
|
188
|
-
registerSyncModeCommand(syncCmd);
|
|
189
|
-
registerSyncNarrowCommand(syncCmd);
|
|
190
|
-
// Cloud provisioning subcommand group (entity + bucket + initial sync)
|
|
191
|
-
// Distinct from `hq sync` which assumes provisioning has already happened.
|
|
192
|
-
const cloudCmd = program
|
|
193
|
-
.command("cloud")
|
|
194
|
-
.description("Cloud commands — provision entities and manage cloud-backed companies");
|
|
195
|
-
registerCloudProvisionCommands(cloudCmd);
|
|
196
|
-
registerCloudDemoteCommands(cloudCmd);
|
|
197
|
-
// Team commands (top-level)
|
|
198
|
-
registerTeamSyncCommand(program);
|
|
199
|
-
// Auth commands (top-level — Cognito OAuth)
|
|
200
|
-
registerLoginCommand(program);
|
|
201
|
-
registerLogoutCommand(program);
|
|
202
|
-
registerWhoamiCommand(program);
|
|
203
|
-
registerAuthCommands(program);
|
|
204
|
-
// Secrets management (subcommand group — hq secrets set|get|list|delete|exec|generate-link|cache)
|
|
205
|
-
registerSecretsCommand(program);
|
|
206
|
-
// Vault databases (subcommand group — hq db status|sql|migrate|provision)
|
|
207
|
-
registerDbCommand(program);
|
|
208
|
-
// API key management (subcommand group — hq api-keys create|list|revoke)
|
|
209
|
-
registerApiKeysCommand(program);
|
|
210
|
-
// Schema-driven dev runner — hq run [options] -- <cmd>
|
|
211
|
-
registerRunCommand(program);
|
|
212
|
-
// Groups management (subcommand group — hq groups create|delete|add|remove|list|members)
|
|
213
|
-
registerGroupsCommand(program);
|
|
214
|
-
// Worker discovery + sharing (subcommand group — hq workers list|share)
|
|
215
|
-
registerWorkersCommand(program);
|
|
216
|
-
// Cross-company group grants (subcommand group —
|
|
217
|
-
// hq group-grants grant|revoke|outbound|inbound)
|
|
218
|
-
registerGroupGrantsCommand(program);
|
|
219
|
-
// Files ACL management (subcommand group — hq files share|unshare|acl)
|
|
220
|
-
// `registerFilesCommand` returns the `files` group so we can attach the
|
|
221
|
-
// browse-vs-sync subcommands (`hq files browse`/`cat`) onto the same group.
|
|
222
|
-
const filesCmd = registerFilesCommand(program);
|
|
223
|
-
registerFilesBrowseCommands(filesCmd);
|
|
224
|
-
// Comment-only skill improvement loop. Structured suggestion/review commands are
|
|
225
|
-
// intentionally absent; live content changes remain governed by FILE_ACL sync.
|
|
226
|
-
registerSkillCommand(program);
|
|
227
|
-
// Membership management (subcommand group — hq members invite|list|revoke)
|
|
228
|
-
registerMembersCommand(program);
|
|
229
|
-
// People directory (subcommand group — hq people list|search|resolve), reading
|
|
230
|
-
// the local companies/<co>/people store scoped to one company.
|
|
231
|
-
registerPeopleCommand(program);
|
|
232
|
-
registerDmCommand(program);
|
|
233
|
-
registerChannelsCommand(program);
|
|
234
|
-
// Onboarding (top-level — Cognito + vault-service provisioning)
|
|
235
|
-
registerOnboardCommand(program);
|
|
236
|
-
// Feedback (subcommand group — hq feedback bug|feature)
|
|
237
|
-
registerFeedbackCommand(program);
|
|
238
|
-
// Meetings (subcommand group — hq meetings list|get|search|transcript|notes)
|
|
239
|
-
registerMeetingsCommand(program);
|
|
240
|
-
// Sources read surface (subcommand group — hq sources list|get|channels|entities)
|
|
241
|
-
registerSourcesCommand(program);
|
|
242
|
-
// Signals read surface (subcommand group — hq signals list|get|types|entities)
|
|
243
|
-
registerSignalsCommand(program);
|
|
244
|
-
// Company-connected apps via the governed integration gateway
|
|
245
|
-
// (subcommand group — hq integrations list|tools|call|approve|reject)
|
|
246
|
-
registerIntegrationsCommand(program);
|
|
247
|
-
// Skill/personal-overlay mirroring + workers-registry regen. Invoked by the
|
|
248
|
-
// hq-core reindex hook shim (Stop / PostToolUse) and by sync()/rescue() after
|
|
249
|
-
// they change on-disk sources. Keeps a `master-sync` alias for one release.
|
|
250
|
-
// Implementation lives in @indigoai-us/hq-cloud.
|
|
251
|
-
registerReindexCommand(program);
|
|
252
|
-
// Drift-preserving HQ-core re-sync (top-level — `hq rescue`). CLI sibling of
|
|
253
|
-
// the HQ Sync app's "Update / Restore" pill; drives the same replace-rescue.sh
|
|
254
|
-
// shipped from @indigoai-us/hq-cloud.
|
|
255
|
-
registerRescueCommand(program);
|
|
256
|
-
// MCP pack observability (subcommand group — `hq mcp status`). Read-only
|
|
257
|
-
// provenance-based status across BOTH Claude + Codex runtimes (reads `_hqPack`
|
|
258
|
-
// off the configs, NOT linkStatus), with secret-redacted output + `--json`.
|
|
259
|
-
registerMcpCommand(program);
|
|
260
|
-
// Native CRM entity upsert (subcommand group — `hq crm entity upsert`). Wraps
|
|
261
|
-
// POST /crm/entities (the ontology write gate) so an authenticated company
|
|
262
|
-
// member can create/update canonical CRM entities in the company vault.
|
|
263
|
-
registerCrmCommand(program);
|
|
264
|
-
// Company settings (subcommand group — `hq company settings set`). Owner-only
|
|
265
|
-
// toggles for crmEnabled / ontologyEnabled via PUT /company-settings.
|
|
266
|
-
registerCompanyCommand(program);
|
|
267
|
-
// Cloud agent management (subcommand group — `hq agents …`). Rename, reconfigure,
|
|
268
|
-
// start/stop, and tear down a company's fleet agents via the hq-pro /v1/agents
|
|
269
|
-
// control plane — the same routes the web console's agents panel calls.
|
|
270
|
-
registerAgentsCommand(program);
|
|
271
|
-
// Personal Outpost management (subcommand group — `hq outposts …`). List, inspect,
|
|
272
|
-
// enable Codex on, refresh login for, and destroy your EC2 boxes via the hq-pro
|
|
273
|
-
// /outpost/* control plane.
|
|
274
|
-
registerOutpostsCommand(program);
|
|
275
|
-
// Billing (subcommand group — `hq billing …`). Check subscription/card state and
|
|
276
|
-
// mint a shareable Stripe card-capture link — the client side of the paid-
|
|
277
|
-
// provisioning gate for agents & Outposts.
|
|
278
|
-
registerBillingCommand(program);
|
|
279
|
-
// HQ scaffold scripts hosted by the CLI (hidden group — `hq core …`). Not a
|
|
280
|
-
// public surface: every entry is invoked by an HQ skill, hook, or forwarder, and
|
|
281
|
-
// the source-root entries are maintainer tools that must never touch a live
|
|
282
|
-
// install. Registered from a manifest in the module, not wired per script here.
|
|
283
|
-
registerCoreCommands(program);
|
|
284
|
-
// Local qmd search and index management. Kept distinct from `hq reindex`,
|
|
285
|
-
// which converges scaffold-owned files and hooks rather than search data.
|
|
286
|
-
registerSearchCommand(program);
|
|
287
|
-
registerIndexCommand(program);
|
|
288
|
-
// Hook guardrail diagnostics (top-level — `hq doctor`). Read-only, offline
|
|
289
|
-
// verification that HQ's hooks are wired and firing, backed by an extensible
|
|
290
|
-
// check registry so later check families (vault, sync, MCP, …) plug in without
|
|
291
|
-
// engine changes.
|
|
292
|
-
registerDoctorCommand(program);
|
|
293
|
-
// Work mesh (subcommand group — `hq mesh …`). Native REST + cache. Distinct
|
|
294
|
-
// from `hq doctor` (hook guardrails). Does not start MQTT listen.
|
|
295
|
-
registerMeshCommand(program);
|
|
296
98
|
program.hook("preAction", async () => {
|
|
297
99
|
// Both are best-effort and fully swallowed: neither can change the command's
|
|
298
100
|
// result or exit code. The 1.2s bound they carry is a TIMER, so it only
|
|
@@ -351,6 +153,19 @@ export async function runCli() {
|
|
|
351
153
|
}
|
|
352
154
|
}
|
|
353
155
|
}
|
|
156
|
+
// Register only what this invocation needs. A hot command named in the
|
|
157
|
+
// lazy manifest imports its own module and nothing else; everything else —
|
|
158
|
+
// `--help`, a bare `hq`, an unknown command, any command not on the
|
|
159
|
+
// manifest — falls back to the complete graph, so its behaviour is
|
|
160
|
+
// unchanged. See register-all.ts for the measurements that motivated this.
|
|
161
|
+
const lazy = findLazyCommand(process.argv);
|
|
162
|
+
if (lazy) {
|
|
163
|
+
await lazy.register(program);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const { registerAllCommands } = await import("./register-all.js");
|
|
167
|
+
registerAllCommands(program);
|
|
168
|
+
}
|
|
354
169
|
await program.parseAsync();
|
|
355
170
|
}
|
|
356
171
|
catch (err) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The full hq command graph — every `register*Command` call, moved here verbatim
|
|
3
|
+
* from main.ts.
|
|
4
|
+
*
|
|
5
|
+
* WHY IT IS ITS OWN MODULE: these 54 imports pull ~60 command modules and their
|
|
6
|
+
* dependency subtrees, and main.ts used to load all of them at module scope. On
|
|
7
|
+
* an outpost that cost real CPU, because the agent fleet calls `hq secrets`
|
|
8
|
+
* about 39 times a minute and each invocation paid for the entire graph before
|
|
9
|
+
* running one command. Measured on Outpost 2 (i-09424eff61920a4ac), CPU-seconds
|
|
10
|
+
* per process:
|
|
11
|
+
*
|
|
12
|
+
* node -e "" 0.03
|
|
13
|
+
* dist/commands/secrets.js 1.13 <- what `hq secrets` actually needs
|
|
14
|
+
* dist/main.js (full graph) 1.88 <- what it used to pay
|
|
15
|
+
*
|
|
16
|
+
* So ~0.75 CPU-seconds of every `hq secrets` was spent importing commands it
|
|
17
|
+
* never ran. At 39 invocations/minute that is ~0.5 of a core, continuously.
|
|
18
|
+
*
|
|
19
|
+
* Splitting the graph out lets the entrypoint import ONE command module for the
|
|
20
|
+
* hot paths named in lazy-commands.ts, and fall back to this module — the
|
|
21
|
+
* complete, unchanged registration — for everything else: `--help`, a bare
|
|
22
|
+
* `hq`, an unknown command, and every command not in that manifest. Anything
|
|
23
|
+
* not on the manifest therefore behaves exactly as before.
|
|
24
|
+
*
|
|
25
|
+
* Keep this list and lazy-commands.ts in sync through the parity test in
|
|
26
|
+
* lazy-commands.test.ts, which registers both ways and compares the resulting
|
|
27
|
+
* command shapes. Same discipline as commands/scaffold-fast.ts and core.ts.
|
|
28
|
+
*/
|
|
29
|
+
import type { Command } from "commander";
|
|
30
|
+
/** Register the complete hq command graph onto `program`. */
|
|
31
|
+
export declare function registerAllCommands(program: Command): void;
|
|
32
|
+
//# sourceMappingURL=register-all.d.ts.map
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The full hq command graph — every `register*Command` call, moved here verbatim
|
|
3
|
+
* from main.ts.
|
|
4
|
+
*
|
|
5
|
+
* WHY IT IS ITS OWN MODULE: these 54 imports pull ~60 command modules and their
|
|
6
|
+
* dependency subtrees, and main.ts used to load all of them at module scope. On
|
|
7
|
+
* an outpost that cost real CPU, because the agent fleet calls `hq secrets`
|
|
8
|
+
* about 39 times a minute and each invocation paid for the entire graph before
|
|
9
|
+
* running one command. Measured on Outpost 2 (i-09424eff61920a4ac), CPU-seconds
|
|
10
|
+
* per process:
|
|
11
|
+
*
|
|
12
|
+
* node -e "" 0.03
|
|
13
|
+
* dist/commands/secrets.js 1.13 <- what `hq secrets` actually needs
|
|
14
|
+
* dist/main.js (full graph) 1.88 <- what it used to pay
|
|
15
|
+
*
|
|
16
|
+
* So ~0.75 CPU-seconds of every `hq secrets` was spent importing commands it
|
|
17
|
+
* never ran. At 39 invocations/minute that is ~0.5 of a core, continuously.
|
|
18
|
+
*
|
|
19
|
+
* Splitting the graph out lets the entrypoint import ONE command module for the
|
|
20
|
+
* hot paths named in lazy-commands.ts, and fall back to this module — the
|
|
21
|
+
* complete, unchanged registration — for everything else: `--help`, a bare
|
|
22
|
+
* `hq`, an unknown command, and every command not in that manifest. Anything
|
|
23
|
+
* not on the manifest therefore behaves exactly as before.
|
|
24
|
+
*
|
|
25
|
+
* Keep this list and lazy-commands.ts in sync through the parity test in
|
|
26
|
+
* lazy-commands.test.ts, which registers both ways and compares the resulting
|
|
27
|
+
* command shapes. Same discipline as commands/scaffold-fast.ts and core.ts.
|
|
28
|
+
*/
|
|
29
|
+
import { registerAddCommand } from "./commands/add.js";
|
|
30
|
+
import { registerSyncCommand } from "./commands/sync.js";
|
|
31
|
+
import { registerListCommand } from "./commands/list.js";
|
|
32
|
+
import { registerUpdateCommand } from "./commands/update.js";
|
|
33
|
+
import { registerCloudCommands } from "./commands/cloud.js";
|
|
34
|
+
import { registerSyncModeCommand } from "./commands/sync-mode.js";
|
|
35
|
+
import { registerSyncNarrowCommand } from "./commands/sync-narrow.js";
|
|
36
|
+
import { registerCloudProvisionCommands } from "./commands/cloud-provision.js";
|
|
37
|
+
import { registerCloudDemoteCommands } from "./commands/cloud-demote.js";
|
|
38
|
+
import { registerLoginCommand } from "./commands/login.js";
|
|
39
|
+
import { registerLogoutCommand } from "./commands/logout.js";
|
|
40
|
+
import { registerWhoamiCommand } from "./commands/whoami.js";
|
|
41
|
+
import { registerOnboardCommand } from "./commands/onboard.js";
|
|
42
|
+
import { registerPackageInstallCommand } from "./commands/pkg-install.js";
|
|
43
|
+
import { registerPackageRemoveCommand } from "./commands/pkg-remove.js";
|
|
44
|
+
import { registerPackageUpdateCommand } from "./commands/pkg-update.js";
|
|
45
|
+
import { registerPackageListCommand } from "./commands/pkg-list.js";
|
|
46
|
+
import { registerPacksCommand } from "./commands/packs.js";
|
|
47
|
+
import { registerPublishCommand } from "./commands/publish.js";
|
|
48
|
+
import { registerCreatorsCommand } from "./commands/creators.js";
|
|
49
|
+
import { registerTeamSyncCommand } from "./commands/team-sync.js";
|
|
50
|
+
import { registerAuthCommands } from "./commands/auth.js";
|
|
51
|
+
import { registerApiKeysCommand } from "./commands/api-keys.js";
|
|
52
|
+
import { registerSecretsCommand } from "./commands/secrets.js";
|
|
53
|
+
import { registerRunCommand } from "./commands/run.js";
|
|
54
|
+
import { registerGroupsCommand } from "./commands/groups.js";
|
|
55
|
+
import { registerWorkersCommand } from "./commands/workers.js";
|
|
56
|
+
import { registerGroupGrantsCommand } from "./commands/group-grants.js";
|
|
57
|
+
import { registerFilesCommand } from "./commands/files.js";
|
|
58
|
+
import { registerFilesBrowseCommands } from "./commands/files-browse.js";
|
|
59
|
+
import { registerSkillCommand } from "./commands/skill.js";
|
|
60
|
+
import { registerMembersCommand } from "./commands/members.js";
|
|
61
|
+
import { registerPeopleCommand } from "./commands/people.js";
|
|
62
|
+
import { registerDmCommand } from "./commands/dm.js";
|
|
63
|
+
import { registerChannelsCommand } from "./commands/channels.js";
|
|
64
|
+
import { registerFeedbackCommand } from "./commands/feedback.js";
|
|
65
|
+
import { registerMeetingsCommand } from "./commands/meetings.js";
|
|
66
|
+
import { registerSourcesCommand } from "./commands/sources.js";
|
|
67
|
+
import { registerSignalsCommand } from "./commands/signals.js";
|
|
68
|
+
import { registerIntegrationsCommand } from "./commands/integrations.js";
|
|
69
|
+
import { registerReindexCommand } from "./commands/reindex.js";
|
|
70
|
+
import { registerRescueCommand } from "./commands/rescue.js";
|
|
71
|
+
import { registerMcpCommand } from "./commands/mcp-status.js";
|
|
72
|
+
import { registerCrmCommand } from "./commands/crm.js";
|
|
73
|
+
import { registerCompanyCommand } from "./commands/company.js";
|
|
74
|
+
import { registerAgentsCommand } from "./commands/agents.js";
|
|
75
|
+
import { registerOutpostsCommand } from "./commands/outposts.js";
|
|
76
|
+
import { registerBillingCommand } from "./commands/billing.js";
|
|
77
|
+
import { registerDbCommand } from "./commands/db.js";
|
|
78
|
+
import { registerCoreCommands } from "./commands/core.js";
|
|
79
|
+
import { registerSearchCommand } from "./commands/search.js";
|
|
80
|
+
import { registerIndexCommand } from "./commands/index-cmd.js";
|
|
81
|
+
import { registerDoctorCommand } from "./commands/doctor.js";
|
|
82
|
+
import { registerMeshCommand } from "./commands/mesh.js";
|
|
83
|
+
/** Register the complete hq command graph onto `program`. */
|
|
84
|
+
export function registerAllCommands(program) {
|
|
85
|
+
// Module management subcommand group
|
|
86
|
+
const modulesCmd = program
|
|
87
|
+
.command("modules")
|
|
88
|
+
.description("Module management commands");
|
|
89
|
+
registerAddCommand(modulesCmd);
|
|
90
|
+
registerSyncCommand(modulesCmd);
|
|
91
|
+
registerListCommand(modulesCmd);
|
|
92
|
+
registerUpdateCommand(modulesCmd);
|
|
93
|
+
// Package management subcommand group
|
|
94
|
+
const packagesCmd = program
|
|
95
|
+
.command("packages")
|
|
96
|
+
.description("Package management commands");
|
|
97
|
+
registerPackageInstallCommand(packagesCmd);
|
|
98
|
+
registerPackageRemoveCommand(packagesCmd);
|
|
99
|
+
registerPackageUpdateCommand(packagesCmd);
|
|
100
|
+
registerPackageListCommand(packagesCmd);
|
|
101
|
+
// Content-pack lifecycle (core/packages/hq-pack-*). Distinct from the registry
|
|
102
|
+
// `packages` system above. Available as both `hq packages packs …` (grouped)
|
|
103
|
+
// and `hq packs …` (top-level convenience).
|
|
104
|
+
registerPacksCommand(packagesCmd);
|
|
105
|
+
registerPacksCommand(program);
|
|
106
|
+
// Top-level shortcuts for package commands
|
|
107
|
+
// "hq install <slug>" = "hq packages install <slug>"
|
|
108
|
+
// "hq remove <slug>" = "hq packages remove <slug>"
|
|
109
|
+
registerPackageInstallCommand(program);
|
|
110
|
+
registerPackageRemoveCommand(program);
|
|
111
|
+
// Marketplace publish (top-level — packer + authenticated upload, US-004)
|
|
112
|
+
// "hq publish <skill-or-worker-path>" packages and submits a pack to the
|
|
113
|
+
// marketplace via POST /v1/listings.
|
|
114
|
+
registerPublishCommand(program);
|
|
115
|
+
// `hq creators apply` — request verified-creator access (required to publish).
|
|
116
|
+
registerCreatorsCommand(program);
|
|
117
|
+
// Cloud sync subcommand group
|
|
118
|
+
const syncCmd = program
|
|
119
|
+
.command("sync")
|
|
120
|
+
.description("Cloud sync commands — sync HQ to S3 for mobile access");
|
|
121
|
+
registerCloudCommands(syncCmd);
|
|
122
|
+
registerSyncModeCommand(syncCmd);
|
|
123
|
+
registerSyncNarrowCommand(syncCmd);
|
|
124
|
+
// Cloud provisioning subcommand group (entity + bucket + initial sync)
|
|
125
|
+
// Distinct from `hq sync` which assumes provisioning has already happened.
|
|
126
|
+
const cloudCmd = program
|
|
127
|
+
.command("cloud")
|
|
128
|
+
.description("Cloud commands — provision entities and manage cloud-backed companies");
|
|
129
|
+
registerCloudProvisionCommands(cloudCmd);
|
|
130
|
+
registerCloudDemoteCommands(cloudCmd);
|
|
131
|
+
// Team commands (top-level)
|
|
132
|
+
registerTeamSyncCommand(program);
|
|
133
|
+
// Auth commands (top-level — Cognito OAuth)
|
|
134
|
+
registerLoginCommand(program);
|
|
135
|
+
registerLogoutCommand(program);
|
|
136
|
+
registerWhoamiCommand(program);
|
|
137
|
+
registerAuthCommands(program);
|
|
138
|
+
// Secrets management (subcommand group — hq secrets set|get|list|delete|exec|generate-link|cache)
|
|
139
|
+
registerSecretsCommand(program);
|
|
140
|
+
// Vault databases (subcommand group — hq db status|sql|migrate|provision)
|
|
141
|
+
registerDbCommand(program);
|
|
142
|
+
// API key management (subcommand group — hq api-keys create|list|revoke)
|
|
143
|
+
registerApiKeysCommand(program);
|
|
144
|
+
// Schema-driven dev runner — hq run [options] -- <cmd>
|
|
145
|
+
registerRunCommand(program);
|
|
146
|
+
// Groups management (subcommand group — hq groups create|delete|add|remove|list|members)
|
|
147
|
+
registerGroupsCommand(program);
|
|
148
|
+
// Worker discovery + sharing (subcommand group — hq workers list|share)
|
|
149
|
+
registerWorkersCommand(program);
|
|
150
|
+
// Cross-company group grants (subcommand group —
|
|
151
|
+
// hq group-grants grant|revoke|outbound|inbound)
|
|
152
|
+
registerGroupGrantsCommand(program);
|
|
153
|
+
// Files ACL management (subcommand group — hq files share|unshare|acl)
|
|
154
|
+
// `registerFilesCommand` returns the `files` group so we can attach the
|
|
155
|
+
// browse-vs-sync subcommands (`hq files browse`/`cat`) onto the same group.
|
|
156
|
+
const filesCmd = registerFilesCommand(program);
|
|
157
|
+
registerFilesBrowseCommands(filesCmd);
|
|
158
|
+
// Comment-only skill improvement loop. Structured suggestion/review commands are
|
|
159
|
+
// intentionally absent; live content changes remain governed by FILE_ACL sync.
|
|
160
|
+
registerSkillCommand(program);
|
|
161
|
+
// Membership management (subcommand group — hq members invite|list|revoke)
|
|
162
|
+
registerMembersCommand(program);
|
|
163
|
+
// People directory (subcommand group — hq people list|search|resolve), reading
|
|
164
|
+
// the local companies/<co>/people store scoped to one company.
|
|
165
|
+
registerPeopleCommand(program);
|
|
166
|
+
registerDmCommand(program);
|
|
167
|
+
registerChannelsCommand(program);
|
|
168
|
+
// Onboarding (top-level — Cognito + vault-service provisioning)
|
|
169
|
+
registerOnboardCommand(program);
|
|
170
|
+
// Feedback (subcommand group — hq feedback bug|feature)
|
|
171
|
+
registerFeedbackCommand(program);
|
|
172
|
+
// Meetings (subcommand group — hq meetings list|get|search|transcript|notes)
|
|
173
|
+
registerMeetingsCommand(program);
|
|
174
|
+
// Sources read surface (subcommand group — hq sources list|get|channels|entities)
|
|
175
|
+
registerSourcesCommand(program);
|
|
176
|
+
// Signals read surface (subcommand group — hq signals list|get|types|entities)
|
|
177
|
+
registerSignalsCommand(program);
|
|
178
|
+
// Company-connected apps via the governed integration gateway
|
|
179
|
+
// (subcommand group — hq integrations list|tools|call|approve|reject)
|
|
180
|
+
registerIntegrationsCommand(program);
|
|
181
|
+
// Skill/personal-overlay mirroring + workers-registry regen. Invoked by the
|
|
182
|
+
// hq-core reindex hook shim (Stop / PostToolUse) and by sync()/rescue() after
|
|
183
|
+
// they change on-disk sources. Keeps a `master-sync` alias for one release.
|
|
184
|
+
// Implementation lives in @indigoai-us/hq-cloud.
|
|
185
|
+
registerReindexCommand(program);
|
|
186
|
+
// Drift-preserving HQ-core re-sync (top-level — `hq rescue`). CLI sibling of
|
|
187
|
+
// the HQ Sync app's "Update / Restore" pill; drives the same replace-rescue.sh
|
|
188
|
+
// shipped from @indigoai-us/hq-cloud.
|
|
189
|
+
registerRescueCommand(program);
|
|
190
|
+
// MCP pack observability (subcommand group — `hq mcp status`). Read-only
|
|
191
|
+
// provenance-based status across BOTH Claude + Codex runtimes (reads `_hqPack`
|
|
192
|
+
// off the configs, NOT linkStatus), with secret-redacted output + `--json`.
|
|
193
|
+
registerMcpCommand(program);
|
|
194
|
+
// Native CRM entity upsert (subcommand group — `hq crm entity upsert`). Wraps
|
|
195
|
+
// POST /crm/entities (the ontology write gate) so an authenticated company
|
|
196
|
+
// member can create/update canonical CRM entities in the company vault.
|
|
197
|
+
registerCrmCommand(program);
|
|
198
|
+
// Company settings (subcommand group — `hq company settings set`). Owner-only
|
|
199
|
+
// toggles for crmEnabled / ontologyEnabled via PUT /company-settings.
|
|
200
|
+
registerCompanyCommand(program);
|
|
201
|
+
// Cloud agent management (subcommand group — `hq agents …`). Rename, reconfigure,
|
|
202
|
+
// start/stop, and tear down a company's fleet agents via the hq-pro /v1/agents
|
|
203
|
+
// control plane — the same routes the web console's agents panel calls.
|
|
204
|
+
registerAgentsCommand(program);
|
|
205
|
+
// Personal Outpost management (subcommand group — `hq outposts …`). List, inspect,
|
|
206
|
+
// enable Codex on, refresh login for, and destroy your EC2 boxes via the hq-pro
|
|
207
|
+
// /outpost/* control plane.
|
|
208
|
+
registerOutpostsCommand(program);
|
|
209
|
+
// Billing (subcommand group — `hq billing …`). Check subscription/card state and
|
|
210
|
+
// mint a shareable Stripe card-capture link — the client side of the paid-
|
|
211
|
+
// provisioning gate for agents & Outposts.
|
|
212
|
+
registerBillingCommand(program);
|
|
213
|
+
// HQ scaffold scripts hosted by the CLI (hidden group — `hq core …`). Not a
|
|
214
|
+
// public surface: every entry is invoked by an HQ skill, hook, or forwarder, and
|
|
215
|
+
// the source-root entries are maintainer tools that must never touch a live
|
|
216
|
+
// install. Registered from a manifest in the module, not wired per script here.
|
|
217
|
+
registerCoreCommands(program);
|
|
218
|
+
// Local qmd search and index management. Kept distinct from `hq reindex`,
|
|
219
|
+
// which converges scaffold-owned files and hooks rather than search data.
|
|
220
|
+
registerSearchCommand(program);
|
|
221
|
+
registerIndexCommand(program);
|
|
222
|
+
// Hook guardrail diagnostics (top-level — `hq doctor`). Read-only, offline
|
|
223
|
+
// verification that HQ's hooks are wired and firing, backed by an extensible
|
|
224
|
+
// check registry so later check families (vault, sync, MCP, …) plug in without
|
|
225
|
+
// engine changes.
|
|
226
|
+
registerDoctorCommand(program);
|
|
227
|
+
// Work mesh (subcommand group — `hq mesh …`). Native REST + cache. Distinct
|
|
228
|
+
// from `hq doctor` (hook guardrails). Does not start MQTT listen.
|
|
229
|
+
registerMeshCommand(program);
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=register-all.js.map
|