@indigoai-us/hq-cli 5.342.2 → 5.342.4
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 +8 -0
- package/dist/commands/bot.js +3 -0
- package/dist/commands/daemon.d.ts +4 -0
- package/dist/commands/daemon.js +6 -1
- package/dist/commands/mcp-serve.d.ts +12 -0
- package/dist/commands/mcp-serve.js +33 -10
- package/dist/commands/secrets-env-exit.d.ts +6 -0
- package/dist/commands/secrets-env-exit.js +28 -0
- package/dist/lib/flag-registry-refresh-wait.d.ts +7 -0
- package/dist/lib/flag-registry-refresh-wait.js +10 -0
- 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/flag-registry-worker.js +6 -1
- package/dist/lib/flag-registry.d.ts +12 -1
- package/dist/lib/flag-registry.js +125 -5
- package/dist/main.js +10 -2
- package/dist/secrets-env-action.js +4 -4
- package/dist/utils/package-use-lease.d.ts +6 -0
- package/dist/utils/package-use-lease.js +24 -1
- package/dist/utils/resident-package-preload.d.ts +13 -0
- package/dist/utils/resident-package-preload.js +78 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.342.4] — 2026-10-04
|
|
6
|
+
|
|
7
|
+
## [5.342.3] — 2026-10-04
|
|
8
|
+
|
|
9
|
+
- Release package-use leases after daemon, bot, and mesh-daemon modules load; `hq mcp serve` starts its resident preload only after the first reply is written, so resident CLI processes do not block Desktop updates or slow MCP start-up.
|
|
10
|
+
|
|
11
|
+
- `hq secrets env` now waits briefly for the company flag snapshot refresh before its synchronous exit, allowing the fast-path gate to use a persisted snapshot on later invocations.
|
|
12
|
+
|
|
5
13
|
## [5.342.2] — 2026-10-04
|
|
6
14
|
- Load the shared `secrets env` action without importing the full secrets command module on the enabled fast route.
|
|
7
15
|
|
package/dist/commands/bot.js
CHANGED
|
@@ -26,6 +26,8 @@ import { hasPromotionHold, promotionHoldSummary } from "../lib/bot/promotion-hol
|
|
|
26
26
|
* list (online flag), and rm. Secrets are never printed.
|
|
27
27
|
*/
|
|
28
28
|
import { promoteLocalBot } from "../lib/bot/promote.js";
|
|
29
|
+
import { releaseCurrentPackageUseLease, releasePackageUseLeaseAfterResidentPreload } from "../utils/package-use-lease.js";
|
|
30
|
+
import { preloadResidentPackageModules, reportResidentPackagePreloadFailure } from "../utils/resident-package-preload.js";
|
|
29
31
|
import { CLI_UPDATE_DISABLE_ENV, createCliUpdateWatcher, handOffToUpdatedCli } from "../lib/bot/cli-update.js";
|
|
30
32
|
import { createVaultObjectDownloader } from "../lib/agent-kit/attachment-download.js";
|
|
31
33
|
import { addBotToCompanies, describeCompanyFailures, removeBotFromCompanies } from "./bot-companies.js";
|
|
@@ -854,6 +856,7 @@ export async function runBotWorkers(opts) {
|
|
|
854
856
|
}
|
|
855
857
|
// ── run (resident) ───────────────────────────────────────────────────────────
|
|
856
858
|
async function runBotResident(nameArg) {
|
|
859
|
+
await releasePackageUseLeaseAfterResidentPreload(() => preloadResidentPackageModules("bot"), reportResidentPackagePreloadFailure, releaseCurrentPackageUseLease);
|
|
857
860
|
const name = validateBotName(nameArg);
|
|
858
861
|
const dir = botDir(name);
|
|
859
862
|
const config = readBotConfig(dir);
|
|
@@ -18,6 +18,9 @@ import { type LegacyUnit } from "../lib/daemon/legacy.js";
|
|
|
18
18
|
import type { HostApp } from "../lib/daemon/supervisor.js";
|
|
19
19
|
import { type SyncModeVaultClient } from "./sync-mode.js";
|
|
20
20
|
import type { RunCommand } from "../lib/service-manager/launchd.js";
|
|
21
|
+
type DaemonRunnerModule = typeof import("../lib/daemon/run.js");
|
|
22
|
+
/** Load the daemon runtime without releasing its lease: it reads package files while resident. */
|
|
23
|
+
export declare function loadDaemonRunner(_release?: () => void, load?: () => Promise<DaemonRunnerModule>): Promise<DaemonRunnerModule["runDaemon"]>;
|
|
21
24
|
export interface DaemonCommandDeps {
|
|
22
25
|
env: NodeJS.ProcessEnv;
|
|
23
26
|
home: string;
|
|
@@ -62,4 +65,5 @@ export declare function resolveDaemonHqRoot(flag: string | undefined, where: {
|
|
|
62
65
|
home: string;
|
|
63
66
|
}): string | undefined;
|
|
64
67
|
export declare function registerDaemonCommand(program: Command, over?: Partial<DaemonCommandDeps>): Command;
|
|
68
|
+
export {};
|
|
65
69
|
//# sourceMappingURL=daemon.d.ts.map
|
package/dist/commands/daemon.js
CHANGED
|
@@ -35,6 +35,11 @@ import { requireAnywhereRuntime } from "./anywhere-runtime-flag.js";
|
|
|
35
35
|
import { hqdRequest, hqdSocketPath, HqdClientError } from "../lib/daemon/protocol.js";
|
|
36
36
|
import { parseStdinMachineCredentials } from "../lib/daemon/machine-login.js";
|
|
37
37
|
import { resolveDefaultHqRoot } from "../utils/cognito-session.js";
|
|
38
|
+
/** Load the daemon runtime without releasing its lease: it reads package files while resident. */
|
|
39
|
+
export async function loadDaemonRunner(_release = () => undefined, load = () => import("../lib/daemon/run.js")) {
|
|
40
|
+
const { runDaemon } = await load();
|
|
41
|
+
return runDaemon;
|
|
42
|
+
}
|
|
38
43
|
class DaemonCommandError extends Error {
|
|
39
44
|
}
|
|
40
45
|
/**
|
|
@@ -778,7 +783,7 @@ export function registerDaemonCommand(program, over = {}) {
|
|
|
778
783
|
.option("--host <app>", "Run as a child of this app (only \"desktop\"), which has handed sync over to the daemon")
|
|
779
784
|
.action(wrap(async (d, opts) => {
|
|
780
785
|
const host = parseDaemonHost(opts.host);
|
|
781
|
-
const
|
|
786
|
+
const runDaemon = await loadDaemonRunner();
|
|
782
787
|
// Services inherit this environment, so they see the same folder.
|
|
783
788
|
const env = opts.daemonDir ? { ...d.env, HQ_DAEMON_DIR: opts.daemonDir } : d.env;
|
|
784
789
|
process.exitCode = await runDaemon({
|
|
@@ -20,9 +20,21 @@ export interface McpServeOptions {
|
|
|
20
20
|
cwd?: string;
|
|
21
21
|
/** Per-call hqd budget. Default 120s; policy checks and hq-mcp tools can be slow. */
|
|
22
22
|
timeoutMs?: number;
|
|
23
|
+
/** Test seam for the resident module preload; production uses the default loader. */
|
|
24
|
+
preloadResidentModules?: (residentPath: "mcp", modules: readonly string[]) => Promise<void>;
|
|
25
|
+
/** Test seam for releasing the process package lease after resident preload. */
|
|
26
|
+
releasePackageUseLease?: () => void;
|
|
23
27
|
}
|
|
24
28
|
/** HQ root for prompts: HQ_ROOT, else the ~/.hq/root pointer written by `hq install --global`. */
|
|
25
29
|
export declare function readHqRoot(env: NodeJS.ProcessEnv, home: string): string | null;
|
|
30
|
+
type McpToolsModule = typeof import("../lib/mcp/tools.js");
|
|
31
|
+
type McpPromptsModule = typeof import("../lib/mcp/prompts.js");
|
|
32
|
+
/** Load request handlers required to answer MCP requests. */
|
|
33
|
+
export declare function loadMcpPackageHandlers(loadTools?: () => Promise<McpToolsModule>, loadPrompts?: () => Promise<McpPromptsModule>): Promise<{
|
|
34
|
+
tools: McpToolsModule;
|
|
35
|
+
prompts: McpPromptsModule;
|
|
36
|
+
}>;
|
|
26
37
|
/** Run the server until input ends. Resolves when stdin closes. */
|
|
27
38
|
export declare function runMcpServe(opts?: McpServeOptions): Promise<void>;
|
|
39
|
+
export {};
|
|
28
40
|
//# sourceMappingURL=mcp-serve.d.ts.map
|
|
@@ -18,6 +18,8 @@ import { CLI_VERSION } from "../cli-version.js";
|
|
|
18
18
|
import { HQ_ANYWHERE_RUNTIME_FLAG } from "../lib/anywhere-runtime-flag-key.js";
|
|
19
19
|
import { anywhereRuntimeEnabledFromSnapshot } from "../lib/anywhere-runtime-fast-flag.js";
|
|
20
20
|
import { createLineSplitter, HqdClientError, hqdRequest, hqdSocketPath } from "../lib/daemon/protocol.js";
|
|
21
|
+
import { releaseCurrentPackageUseLease, releasePackageUseLeaseAfterResidentPreload } from "../utils/package-use-lease.js";
|
|
22
|
+
import { preloadResidentPackageModules, reportResidentPackagePreloadFailure, RESIDENT_PACKAGE_MODULES } from "../utils/resident-package-preload.js";
|
|
21
23
|
export const MCP_PROTOCOL_VERSIONS = ["2025-06-18", "2025-03-26", "2024-11-05"];
|
|
22
24
|
const UNREACHABLE_CODES = new Set(["ENOENT", "ECONNREFUSED", "ECONNRESET", "EPIPE", "ETIMEDOUT", "ESOCKET", "EACCES"]);
|
|
23
25
|
/** HQ root for prompts: HQ_ROOT, else the ~/.hq/root pointer written by `hq install --global`. */
|
|
@@ -39,8 +41,12 @@ function toolError(code, message) {
|
|
|
39
41
|
const error = { code, message };
|
|
40
42
|
return { content: [{ type: "text", text: JSON.stringify({ error }, null, 2) }], structuredContent: { error }, isError: true };
|
|
41
43
|
}
|
|
44
|
+
/** Load request handlers required to answer MCP requests. */
|
|
45
|
+
export async function loadMcpPackageHandlers(loadTools = () => import("../lib/mcp/tools.js"), loadPrompts = () => import("../lib/mcp/prompts.js")) {
|
|
46
|
+
return Promise.all([loadTools(), loadPrompts()]).then(([tools, prompts]) => ({ tools, prompts }));
|
|
47
|
+
}
|
|
42
48
|
/** Run the server until input ends. Resolves when stdin closes. */
|
|
43
|
-
export function runMcpServe(opts = {}) {
|
|
49
|
+
export async function runMcpServe(opts = {}) {
|
|
44
50
|
const input = opts.input ?? process.stdin;
|
|
45
51
|
const output = opts.output ?? process.stdout;
|
|
46
52
|
const env = opts.env ?? process.env;
|
|
@@ -51,15 +57,33 @@ export function runMcpServe(opts = {}) {
|
|
|
51
57
|
if (!anywhereRuntimeEnabledFromSnapshot(env)) {
|
|
52
58
|
process.stderr.write(`HQ Anywhere is not enabled. Enable the ${HQ_ANYWHERE_RUNTIME_FLAG} flag to use hq mcp serve.\n`);
|
|
53
59
|
process.exitCode = 1;
|
|
54
|
-
return
|
|
60
|
+
return;
|
|
55
61
|
}
|
|
56
|
-
const
|
|
62
|
+
const { tools, prompts } = await loadMcpPackageHandlers();
|
|
63
|
+
const preload = (residentPath, modules) => opts.preloadResidentModules
|
|
64
|
+
? opts.preloadResidentModules(residentPath, modules)
|
|
65
|
+
: preloadResidentPackageModules(residentPath);
|
|
66
|
+
let residentPreloadStarted = false;
|
|
67
|
+
const startResidentPreload = () => {
|
|
68
|
+
if (residentPreloadStarted)
|
|
69
|
+
return;
|
|
70
|
+
residentPreloadStarted = true;
|
|
71
|
+
void releasePackageUseLeaseAfterResidentPreload(() => preload("mcp", RESIDENT_PACKAGE_MODULES.mcp), reportResidentPackagePreloadFailure, opts.releasePackageUseLease ?? releaseCurrentPackageUseLease).catch(() => {
|
|
72
|
+
process.exitCode = process.exitCode ?? 1;
|
|
73
|
+
process.emitWarning("hq-cli resident package preload completion failed (class=Error, module=unknown)");
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
const send = (msg) => {
|
|
77
|
+
const response = `${JSON.stringify({ jsonrpc: "2.0", ...msg })}\n`;
|
|
78
|
+
if (residentPreloadStarted)
|
|
79
|
+
return output.write(response);
|
|
80
|
+
return output.write(response, startResidentPreload);
|
|
81
|
+
};
|
|
57
82
|
const reply = (id, result) => send({ id, result });
|
|
58
83
|
const replyError = (id, code, message) => send({ id, error: { code, message } });
|
|
59
84
|
const callTool = async (params) => {
|
|
60
|
-
const { MCP_TOOLS } = await import("../lib/mcp/tools.js");
|
|
61
85
|
const name = params.name;
|
|
62
|
-
if (typeof name !== "string" || !MCP_TOOLS.some((t) => t.name === name)) {
|
|
86
|
+
if (typeof name !== "string" || !tools.MCP_TOOLS.some((t) => t.name === name)) {
|
|
63
87
|
return toolError("unknown_tool", `unknown tool ${String(name)}`);
|
|
64
88
|
}
|
|
65
89
|
const args = params.arguments && typeof params.arguments === "object" ? params.arguments : {};
|
|
@@ -95,22 +119,21 @@ export function runMcpServe(opts = {}) {
|
|
|
95
119
|
reply(id, {});
|
|
96
120
|
return;
|
|
97
121
|
case "tools/list":
|
|
98
|
-
reply(id, { tools:
|
|
122
|
+
reply(id, { tools: tools.MCP_TOOLS });
|
|
99
123
|
return;
|
|
100
124
|
case "tools/call":
|
|
101
125
|
reply(id, await callTool(params));
|
|
102
126
|
return;
|
|
103
127
|
case "prompts/list":
|
|
104
|
-
reply(id, { prompts:
|
|
128
|
+
reply(id, { prompts: prompts.MCP_PROMPTS });
|
|
105
129
|
return;
|
|
106
130
|
case "prompts/get": {
|
|
107
|
-
const { getPrompt, PromptNotFoundError } = await import("../lib/mcp/prompts.js");
|
|
108
131
|
const args = params.arguments && typeof params.arguments === "object" ? params.arguments : {};
|
|
109
132
|
try {
|
|
110
|
-
reply(id, getPrompt(String(params.name), args, readHqRoot(env, home)));
|
|
133
|
+
reply(id, prompts.getPrompt(String(params.name), args, readHqRoot(env, home)));
|
|
111
134
|
}
|
|
112
135
|
catch (err) {
|
|
113
|
-
if (!(err instanceof PromptNotFoundError))
|
|
136
|
+
if (!(err instanceof prompts.PromptNotFoundError))
|
|
114
137
|
throw err;
|
|
115
138
|
replyError(id, -32602, err.message);
|
|
116
139
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { writeSync } from "node:fs";
|
|
2
|
+
/** Write the resolved exports synchronously and exit even if the pipe is closed. */
|
|
3
|
+
export declare function emitEnvExportsAndExit(payload: string, exit?: (code: number) => never, write?: typeof writeSync): never;
|
|
4
|
+
/** Wait for a company snapshot before the synchronous env-command exit. */
|
|
5
|
+
export declare function finishEnvExportsAndExit(payload: string, waitForSnapshot?: (timeoutMs?: number, companyUid?: string) => Promise<void>, exit?: (code: number) => never, write?: typeof writeSync, shouldWaitForSnapshot?: boolean, companyUid?: string): Promise<never>;
|
|
6
|
+
//# sourceMappingURL=secrets-env-exit.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { writeSync } from "node:fs";
|
|
2
|
+
import { waitForRegisteredFlagRegistryRefresh } from "../lib/flag-registry-refresh-wait.js";
|
|
3
|
+
/** Write the resolved exports synchronously and exit even if the pipe is closed. */
|
|
4
|
+
export function emitEnvExportsAndExit(payload, exit = process.exit, write = writeSync) {
|
|
5
|
+
const buf = Buffer.from(payload, "utf8");
|
|
6
|
+
const MAX_EAGAIN_RETRIES = 10_000;
|
|
7
|
+
let offset = 0;
|
|
8
|
+
let eagainRetries = 0;
|
|
9
|
+
while (offset < buf.length) {
|
|
10
|
+
try {
|
|
11
|
+
offset += write(1, buf, offset, buf.length - offset);
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
const code = err.code;
|
|
15
|
+
if (code === "EAGAIN" && eagainRetries++ < MAX_EAGAIN_RETRIES)
|
|
16
|
+
continue;
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return exit(0);
|
|
21
|
+
}
|
|
22
|
+
/** Wait for a company snapshot before the synchronous env-command exit. */
|
|
23
|
+
export async function finishEnvExportsAndExit(payload, waitForSnapshot = waitForRegisteredFlagRegistryRefresh, exit = process.exit, write = writeSync, shouldWaitForSnapshot = true, companyUid) {
|
|
24
|
+
if (shouldWaitForSnapshot)
|
|
25
|
+
await waitForSnapshot(500, companyUid);
|
|
26
|
+
return emitEnvExportsAndExit(payload, exit, write);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=secrets-env-exit.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type FlagRegistryRefreshWaiter = (timeoutMs?: number, companyUid?: string) => Promise<void>;
|
|
2
|
+
/** Install the worker-backed waiter from the CLI's early registry bootstrap. */
|
|
3
|
+
export declare function registerFlagRegistryRefreshWaiter(nextWaiter: FlagRegistryRefreshWaiter): void;
|
|
4
|
+
/** Wait for a registry refresh when the CLI bootstrap installed a worker. */
|
|
5
|
+
export declare function waitForRegisteredFlagRegistryRefresh(timeoutMs?: number, companyUid?: string): Promise<void>;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=flag-registry-refresh-wait.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
let waiter = async () => { };
|
|
2
|
+
/** Install the worker-backed waiter from the CLI's early registry bootstrap. */
|
|
3
|
+
export function registerFlagRegistryRefreshWaiter(nextWaiter) {
|
|
4
|
+
waiter = nextWaiter;
|
|
5
|
+
}
|
|
6
|
+
/** Wait for a registry refresh when the CLI bootstrap installed a worker. */
|
|
7
|
+
export function waitForRegisteredFlagRegistryRefresh(timeoutMs = 500, companyUid) {
|
|
8
|
+
return waiter(timeoutMs, companyUid);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=flag-registry-refresh-wait.js.map
|