@indigoai-us/hq-cli 5.342.3 → 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 +5 -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/main.js +2 -0
- 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,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.342.4] — 2026-10-04
|
|
6
|
+
|
|
5
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
|
+
|
|
6
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.
|
|
7
12
|
|
|
8
13
|
## [5.342.2] — 2026-10-04
|
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
|
}
|
package/dist/main.js
CHANGED
|
@@ -53,6 +53,7 @@ import { emitPlanLimitNag } from "./lib/plan-limit-nag.js";
|
|
|
53
53
|
import { kickFlagRegistryReadiness } from "./lib/flag-registry.js";
|
|
54
54
|
import { isPackageRootResolutionError, packageRootCaptureContext, } from "./utils/package-root-diagnostics.js";
|
|
55
55
|
import { registerCommandsWithRecovery } from "./startup-registration.js";
|
|
56
|
+
import { releasePackageUseLeaseAfterCommandLoad } from "./utils/package-use-lease.js";
|
|
56
57
|
import { installTreeTornCaptureContext, installTreeTornStderrLine, isInstallTreeTornError, } from "./utils/install-tree-torn.js";
|
|
57
58
|
import { isVaultAccessDeniedError, vaultAccessDeniedMessage, } from "./utils/vault-access-denied-error.js";
|
|
58
59
|
import { fallbackOperatorMessage, unexpectedCliErrorMessage } from "./utils/unexpected-cli-error.js";
|
|
@@ -261,6 +262,7 @@ export async function runCli() {
|
|
|
261
262
|
reexecStatus = registration.reexecStatus;
|
|
262
263
|
return;
|
|
263
264
|
}
|
|
265
|
+
await releasePackageUseLeaseAfterCommandLoad(process.argv);
|
|
264
266
|
await program.parseAsync();
|
|
265
267
|
maybeShowFirstSyncNextStep();
|
|
266
268
|
}
|
|
@@ -16,6 +16,12 @@ export declare function packageUseUpdateRequestPath(prefix: string, stateDirecto
|
|
|
16
16
|
declare function waitForUpdateRequest(requestPath: string, timeoutMs: number): void;
|
|
17
17
|
export declare function acquirePackageUseLease(prefix: string, hqVersion: string, stateDirectory?: string): PackageUseLease;
|
|
18
18
|
export declare function acquireCurrentPackageUseLease(): PackageUseLease | null;
|
|
19
|
+
/** Release this process's package-use lease after a long-running command has loaded its package modules. */
|
|
20
|
+
export declare function releaseCurrentPackageUseLease(): void;
|
|
21
|
+
/** The lease remains held through command execution and is released on process exit. */
|
|
22
|
+
export declare function releasePackageUseLeaseAfterCommandLoad(_argv?: readonly string[], _release?: () => void): void;
|
|
23
|
+
/** Release only after a command-specific preload succeeds; failures are reported and keep the lease. */
|
|
24
|
+
export declare function releasePackageUseLeaseAfterResidentPreload(preload: () => Promise<void>, reportFailure: (error: unknown) => void, release?: () => void): Promise<void>;
|
|
19
25
|
/** True only when a valid update request belongs to a live updater process. */
|
|
20
26
|
export declare function packageUseUpdatePending(prefix: string, stateDirectory?: string): boolean;
|
|
21
27
|
/** True while the desktop updater owns the per-prefix update request. */
|
|
@@ -12,6 +12,7 @@ export class PackageUseUpdatePendingError extends Error {
|
|
|
12
12
|
this.name = "PackageUseUpdatePendingError";
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
let currentPackageUseLease = null;
|
|
15
16
|
function errorLabel(error) {
|
|
16
17
|
if (error && typeof error === "object") {
|
|
17
18
|
const value = error;
|
|
@@ -195,7 +196,29 @@ export function acquireCurrentPackageUseLease() {
|
|
|
195
196
|
if (nodeModules > 0 && parts[nodeModules - 1] !== "lib")
|
|
196
197
|
return null;
|
|
197
198
|
}
|
|
198
|
-
|
|
199
|
+
const lease = acquirePackageUseLease(prefix, pkg.version);
|
|
200
|
+
currentPackageUseLease = lease;
|
|
201
|
+
return lease;
|
|
202
|
+
}
|
|
203
|
+
/** Release this process's package-use lease after a long-running command has loaded its package modules. */
|
|
204
|
+
export function releaseCurrentPackageUseLease() {
|
|
205
|
+
currentPackageUseLease?.release();
|
|
206
|
+
currentPackageUseLease = null;
|
|
207
|
+
}
|
|
208
|
+
/** The lease remains held through command execution and is released on process exit. */
|
|
209
|
+
export function releasePackageUseLeaseAfterCommandLoad(_argv = process.argv, _release = releaseCurrentPackageUseLease) {
|
|
210
|
+
// The package-use lease's process-exit listener owns its normal release.
|
|
211
|
+
}
|
|
212
|
+
/** Release only after a command-specific preload succeeds; failures are reported and keep the lease. */
|
|
213
|
+
export async function releasePackageUseLeaseAfterResidentPreload(preload, reportFailure, release = releaseCurrentPackageUseLease) {
|
|
214
|
+
try {
|
|
215
|
+
await preload();
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
reportFailure(error);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
release();
|
|
199
222
|
}
|
|
200
223
|
/** True only when a valid update request belongs to a live updater process. */
|
|
201
224
|
export function packageUseUpdatePending(prefix, stateDirectory) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type ResidentPackagePath = "bot" | "mcp";
|
|
2
|
+
/** Package imports reachable lazily from each resident command's runtime graph. */
|
|
3
|
+
export declare const RESIDENT_PACKAGE_MODULES: Record<ResidentPackagePath, readonly string[]>;
|
|
4
|
+
export declare class ResidentPackagePreloadError extends Error {
|
|
5
|
+
readonly moduleSpecifier: string;
|
|
6
|
+
readonly errorClass: string;
|
|
7
|
+
constructor(moduleSpecifier: string, errorClass: string);
|
|
8
|
+
}
|
|
9
|
+
/** Report only bounded runtime metadata; never include an exception message or path. */
|
|
10
|
+
export declare function reportResidentPackagePreloadFailure(error: unknown): void;
|
|
11
|
+
/** Resolve every lazy package module before a resident command releases its lease. */
|
|
12
|
+
export declare function preloadResidentPackageModules(residentPath: ResidentPackagePath, load?: () => Promise<unknown>): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=resident-package-preload.d.ts.map
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** Package imports reachable lazily from each resident command's runtime graph. */
|
|
2
|
+
export const RESIDENT_PACKAGE_MODULES = {
|
|
3
|
+
bot: ["../lib/flag-registry.js", "../commands/access.js", "../sentry.js", "open"],
|
|
4
|
+
mcp: [
|
|
5
|
+
"../lib/mcp/tools.js",
|
|
6
|
+
"../lib/mcp/prompts.js",
|
|
7
|
+
"../utils/cognito-session.js",
|
|
8
|
+
"../lib/daemon/mcp-oauth.js",
|
|
9
|
+
"../commands/access.js",
|
|
10
|
+
"../lib/flag-registry.js",
|
|
11
|
+
"@modelcontextprotocol/sdk/client/index.js",
|
|
12
|
+
"@modelcontextprotocol/sdk/client/streamableHttp.js",
|
|
13
|
+
"../sentry.js",
|
|
14
|
+
"open",
|
|
15
|
+
"./staged-npm-install.js",
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
const LOADERS = {
|
|
19
|
+
bot: [
|
|
20
|
+
() => import("../lib/flag-registry.js"),
|
|
21
|
+
() => import("../commands/access.js"),
|
|
22
|
+
() => import("../sentry.js"),
|
|
23
|
+
() => import("open"),
|
|
24
|
+
],
|
|
25
|
+
mcp: [
|
|
26
|
+
() => import("../lib/mcp/tools.js"),
|
|
27
|
+
() => import("../lib/mcp/prompts.js"),
|
|
28
|
+
() => import("../utils/cognito-session.js"),
|
|
29
|
+
() => import("../lib/daemon/mcp-oauth.js"),
|
|
30
|
+
() => import("../commands/access.js"),
|
|
31
|
+
() => import("../lib/flag-registry.js"),
|
|
32
|
+
() => import("@modelcontextprotocol/sdk/client/index.js"),
|
|
33
|
+
() => import("@modelcontextprotocol/sdk/client/streamableHttp.js"),
|
|
34
|
+
() => import("../sentry.js"),
|
|
35
|
+
() => import("open"),
|
|
36
|
+
() => import("./staged-npm-install.js"),
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
export class ResidentPackagePreloadError extends Error {
|
|
40
|
+
moduleSpecifier;
|
|
41
|
+
errorClass;
|
|
42
|
+
constructor(moduleSpecifier, errorClass) {
|
|
43
|
+
super("Resident package module preload failed");
|
|
44
|
+
this.moduleSpecifier = moduleSpecifier;
|
|
45
|
+
this.errorClass = errorClass;
|
|
46
|
+
this.name = "ResidentPackagePreloadError";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function boundedErrorClass(error) {
|
|
50
|
+
const value = error && typeof error === "object"
|
|
51
|
+
? error
|
|
52
|
+
: {};
|
|
53
|
+
const label = typeof value.code === "string" ? value.code : typeof value.name === "string" ? value.name : "Error";
|
|
54
|
+
return /^[A-Za-z][A-Za-z0-9_]{0,39}$/.test(label) ? label : "Error";
|
|
55
|
+
}
|
|
56
|
+
/** Report only bounded runtime metadata; never include an exception message or path. */
|
|
57
|
+
export function reportResidentPackagePreloadFailure(error) {
|
|
58
|
+
const failure = error instanceof ResidentPackagePreloadError
|
|
59
|
+
? error
|
|
60
|
+
: new ResidentPackagePreloadError("unknown", boundedErrorClass(error));
|
|
61
|
+
process.stderr.write(`hq-cli resident package preload failed (class=${failure.errorClass}, module=${failure.moduleSpecifier})\n`);
|
|
62
|
+
}
|
|
63
|
+
/** Resolve every lazy package module before a resident command releases its lease. */
|
|
64
|
+
export async function preloadResidentPackageModules(residentPath, load) {
|
|
65
|
+
if (load) {
|
|
66
|
+
await load();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
await Promise.all(LOADERS[residentPath].map(async (loader, index) => {
|
|
70
|
+
try {
|
|
71
|
+
await loader();
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
throw new ResidentPackagePreloadError(RESIDENT_PACKAGE_MODULES[residentPath][index] ?? "unknown", boundedErrorClass(error));
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=resident-package-preload.js.map
|