@indigoai-us/hq-cli 5.345.22 → 5.345.23

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/commands/core-audit-log-fast.d.ts +2 -0
  3. package/dist/commands/core-audit-log-fast.js +12 -0
  4. package/dist/commands/core-detect-stale-core-policy-mirror-fast.d.ts +2 -0
  5. package/dist/commands/core-detect-stale-core-policy-mirror-fast.js +5 -0
  6. package/dist/commands/core-dm-bind-fast.d.ts +2 -0
  7. package/dist/commands/core-dm-bind-fast.js +14 -0
  8. package/dist/commands/core-generate-workers-registry-fast.d.ts +2 -0
  9. package/dist/commands/core-generate-workers-registry-fast.js +5 -0
  10. package/dist/commands/core-git-pack-extension-check-fast.d.ts +2 -0
  11. package/dist/commands/core-git-pack-extension-check-fast.js +12 -0
  12. package/dist/commands/core-refresh-vault-access-fast.d.ts +2 -0
  13. package/dist/commands/core-refresh-vault-access-fast.js +12 -0
  14. package/dist/commands/core-refresh-vault-access-native.d.ts +1 -0
  15. package/dist/commands/core-refresh-vault-access-native.js +10 -5
  16. package/dist/commands/core-scan-packages-fast.d.ts +2 -0
  17. package/dist/commands/core-scan-packages-fast.js +5 -0
  18. package/dist/commands/core-work-mesh-bind-trusted-fast.d.ts +2 -0
  19. package/dist/commands/core-work-mesh-bind-trusted-fast.js +12 -0
  20. package/dist/fast-core.js +6 -3
  21. package/dist/fast-scaffold.d.ts +1 -1
  22. package/dist/fast-scaffold.js +101 -0
  23. package/dist/lib/daemon/flag.d.ts +2 -0
  24. package/dist/lib/daemon/flag.js +2 -1
  25. package/dist/lib/daemon/server.d.ts +2 -1
  26. package/dist/lib/daemon/server.js +38 -21
  27. package/dist/lib/daemon/session-registry.d.ts +1 -0
  28. package/dist/lib/daemon/session-registry.js +3 -0
  29. package/dist/lib/scan-packages/index.js +1 -1
  30. package/dist/utils/pack-contribution-links.d.ts +15 -0
  31. package/dist/utils/pack-contribution-links.js +33 -0
  32. package/dist/utils/pack-contributions.d.ts +2 -14
  33. package/dist/utils/pack-contributions.js +3 -55
  34. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.345.23] — 2026-10-06
6
+ - Route eight additional isolated native core commands through the fast CLI entry.
7
+ - hqd applies the runtime kill switch to new hook and MCP operations within the existing 60-second freshness bound. A local opt-out also disables the daemon, while a local opt-in cannot override an operator-off value.
8
+
5
9
  ## [5.345.22] — 2026-10-06
6
10
  - Fix Claude quota holds so time-only reset messages keep accounts unavailable until the provider's stated UTC reset, and expose the hold state in host capacity output.
7
11
 
@@ -0,0 +1,2 @@
1
+ export declare function runAuditLogFast(args: string[], _stdin: string, _cwd: string, hqRoot?: string): number;
2
+ //# sourceMappingURL=core-audit-log-fast.d.ts.map
@@ -0,0 +1,12 @@
1
+ import { runAuditLog } from "./core-audit-log-native.js";
2
+ export function runAuditLogFast(args, _stdin, _cwd, hqRoot) {
3
+ const result = runAuditLog(args, { root: hqRoot ?? process.cwd(), now: () => new Date() });
4
+ if (result.stdout)
5
+ process.stdout.write(result.stdout);
6
+ if (result.stderrBytes)
7
+ process.stderr.write(result.stderrBytes);
8
+ else if (result.stderr)
9
+ process.stderr.write(result.stderr);
10
+ return result.code;
11
+ }
12
+ //# sourceMappingURL=core-audit-log-fast.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runDetectStaleCorePolicyMirrorFast(args: string[], _stdin: string, _cwd: string, hqRoot?: string): number;
2
+ //# sourceMappingURL=core-detect-stale-core-policy-mirror-fast.d.ts.map
@@ -0,0 +1,5 @@
1
+ import { detectStaleCorePolicyMirror } from "../lib/core-utils/detect-stale-core-policy-mirror.js";
2
+ export function runDetectStaleCorePolicyMirrorFast(args, _stdin, _cwd, hqRoot) {
3
+ return detectStaleCorePolicyMirror(args, { root: hqRoot ?? process.cwd() });
4
+ }
5
+ //# sourceMappingURL=core-detect-stale-core-policy-mirror-fast.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runDmBindFast(args: string[], stdin: string, cwd: string, hqRoot?: string): Promise<number>;
2
+ //# sourceMappingURL=core-dm-bind-fast.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { createDmBindDeps, runDmBind } from "./core-dm-bind-native.js";
2
+ export async function runDmBindFast(args, stdin, cwd, hqRoot) {
3
+ const deps = createDmBindDeps(hqRoot ?? cwd, cwd, process.env, () => new Date());
4
+ deps.readStdin = async () => stdin;
5
+ const result = await runDmBind(args, deps);
6
+ if (result.stdout)
7
+ process.stdout.write(result.stdout);
8
+ if (result.stderrBytes)
9
+ process.stderr.write(result.stderrBytes);
10
+ else if (result.stderr)
11
+ process.stderr.write(result.stderr);
12
+ return result.code;
13
+ }
14
+ //# sourceMappingURL=core-dm-bind-fast.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runGenerateWorkersRegistryFast(_args: string[], _stdin: string, _cwd: string, hqRoot?: string): number;
2
+ //# sourceMappingURL=core-generate-workers-registry-fast.d.ts.map
@@ -0,0 +1,5 @@
1
+ import { generateWorkersRegistry } from "../lib/workers-registry/index.js";
2
+ export function runGenerateWorkersRegistryFast(_args, _stdin, _cwd, hqRoot) {
3
+ return generateWorkersRegistry(hqRoot ?? process.cwd()).status;
4
+ }
5
+ //# sourceMappingURL=core-generate-workers-registry-fast.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runGitPackExtensionCheckFast(args: string[], _stdin: string, cwd: string): number;
2
+ //# sourceMappingURL=core-git-pack-extension-check-fast.d.ts.map
@@ -0,0 +1,12 @@
1
+ import { runGitPackExtensionCheck } from "./core-git-pack-extension-check-native.js";
2
+ export function runGitPackExtensionCheckFast(args, _stdin, cwd) {
3
+ const result = runGitPackExtensionCheck(args, { cwd, env: process.env });
4
+ if (result.stdout)
5
+ process.stdout.write(result.stdout);
6
+ if (result.stderrBytes)
7
+ process.stderr.write(result.stderrBytes);
8
+ else if (result.stderr)
9
+ process.stderr.write(result.stderr);
10
+ return result.code;
11
+ }
12
+ //# sourceMappingURL=core-git-pack-extension-check-fast.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runRefreshVaultAccessFast(args: string[], _stdin: string, cwd: string): number;
2
+ //# sourceMappingURL=core-refresh-vault-access-fast.d.ts.map
@@ -0,0 +1,12 @@
1
+ import { createRefreshVaultAccessDependencies, runRefreshVaultAccess } from "./core-refresh-vault-access-native.js";
2
+ export function runRefreshVaultAccessFast(args, _stdin, cwd) {
3
+ const result = runRefreshVaultAccess(args, createRefreshVaultAccessDependencies(cwd, process.env, () => new Date()));
4
+ if (result.stdout)
5
+ process.stdout.write(result.stdout);
6
+ if (result.stderrBytes)
7
+ process.stderr.write(result.stderrBytes);
8
+ else if (result.stderr)
9
+ process.stderr.write(result.stderr);
10
+ return result.code;
11
+ }
12
+ //# sourceMappingURL=core-refresh-vault-access-fast.js.map
@@ -15,6 +15,7 @@ export type RefreshVaultAccessDependencies = {
15
15
  hqAvailable: boolean;
16
16
  runHq?: (args: string[], cwd: string) => HqResult;
17
17
  };
18
+ export declare function createRefreshVaultAccessDependencies(cwd: string, env: NodeJS.ProcessEnv, now: () => Date): RefreshVaultAccessDependencies;
18
19
  export declare function runRefreshVaultAccess(args: string[], deps: RefreshVaultAccessDependencies): UtilityOutput;
19
20
  export declare function registerCoreRefreshVaultAccessNative(core: Command): void;
20
21
  //# sourceMappingURL=core-refresh-vault-access-native.d.ts.map
@@ -59,6 +59,15 @@ function executableOnPath(name, value) {
59
59
  }
60
60
  return false;
61
61
  }
62
+ export function createRefreshVaultAccessDependencies(cwd, env, now) {
63
+ return {
64
+ cwd,
65
+ env,
66
+ now,
67
+ hqAvailable: executableOnPath("hq", env.PATH),
68
+ runHq: (args, directory) => defaultHq(args, directory, env),
69
+ };
70
+ }
62
71
  function isHqRoot(root) {
63
72
  const candidate = root.endsWith(path.sep) ? root.slice(0, -1) : root;
64
73
  if (!candidate)
@@ -219,11 +228,7 @@ export function registerCoreRefreshVaultAccessNative(core) {
219
228
  registerNativeUtility(core, {
220
229
  name: "refresh-vault-access", asset: REFRESH_VAULT_ACCESS_ASSET, root: "cwd", summary: "Refresh the local vault access manifest",
221
230
  resolveRoot: (cwd) => cwd,
222
- run: (args, context) => runRefreshVaultAccess(args, {
223
- cwd: context.cwd, env: context.env, now: context.now,
224
- hqAvailable: executableOnPath("hq", context.env.PATH),
225
- runHq: (args, cwd) => defaultHq(args, cwd, context.env),
226
- }),
231
+ run: (args, context) => runRefreshVaultAccess(args, createRefreshVaultAccessDependencies(context.cwd, context.env, context.now)),
227
232
  });
228
233
  }
229
234
  //# sourceMappingURL=core-refresh-vault-access-native.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runScanPackagesFast(_args: string[], _stdin: string, _cwd: string, hqRoot?: string): number;
2
+ //# sourceMappingURL=core-scan-packages-fast.d.ts.map
@@ -0,0 +1,5 @@
1
+ import { scanPackages } from "../lib/scan-packages/index.js";
2
+ export function runScanPackagesFast(_args, _stdin, _cwd, hqRoot) {
3
+ return scanPackages(hqRoot ?? process.cwd(), { quiet: process.env.HQ_SCAN_QUIET === "1" }).status;
4
+ }
5
+ //# sourceMappingURL=core-scan-packages-fast.js.map
@@ -0,0 +1,2 @@
1
+ export declare function runWorkMeshBindTrustedFast(args: string[], _stdin: string, cwd: string, hqRoot?: string): number;
2
+ //# sourceMappingURL=core-work-mesh-bind-trusted-fast.d.ts.map
@@ -0,0 +1,12 @@
1
+ import { createWorkMeshBindDeps, runWorkMeshBindTrusted } from "./core-work-mesh-bind-trusted-native.js";
2
+ export function runWorkMeshBindTrustedFast(args, _stdin, cwd, hqRoot) {
3
+ const result = runWorkMeshBindTrusted(args, createWorkMeshBindDeps(hqRoot ?? cwd, cwd, process.env, () => new Date()));
4
+ if (result.stdout)
5
+ process.stdout.write(result.stdout);
6
+ if (result.stderrBytes)
7
+ process.stderr.write(result.stderrBytes);
8
+ else if (result.stderr)
9
+ process.stderr.write(result.stderr);
10
+ return result.code;
11
+ }
12
+ //# sourceMappingURL=core-work-mesh-bind-trusted-fast.js.map
package/dist/fast-core.js CHANGED
@@ -65,7 +65,7 @@ export async function runFastCore(argv, parsed = parseFastCore(argv)) {
65
65
  worktreeScopeFixEnabled = await coreRrrWorktreeScopeFixFastFlagEnabled(process.env);
66
66
  }
67
67
  const shouldInjectRoot = useShell
68
- ? entry.shellHqRoot === "live" || (entry.shellHqRoot === "reconcile-default" &&
68
+ ? entry.shellHqRoot === "cwd" || entry.shellHqRoot === "live" || (entry.shellHqRoot === "reconcile-default" &&
69
69
  !parsed.args.includes("--hq-root") && !parsed.args.includes("--help") && !parsed.args.includes("-h"))
70
70
  : entry.kind === "shell"
71
71
  ? true
@@ -76,7 +76,10 @@ export async function runFastCore(argv, parsed = parseFastCore(argv)) {
76
76
  // its expected-user-error formatting remains authoritative.
77
77
  let hqRoot;
78
78
  const rootResolutionStartedAt = profileMark();
79
- if (shouldInjectRoot) {
79
+ if (useShell && entry.kind === "native" && entry.shellHqRoot === "cwd") {
80
+ hqRoot = process.cwd();
81
+ }
82
+ else if (shouldInjectRoot) {
80
83
  const shortcutRoot = entry.name === "checkpoint-stop-gate" || entry.name === "session-journal"
81
84
  ? resolveExplicitFastLiveRoot(parsed.hqRootArg, process.env)
82
85
  : undefined;
@@ -146,7 +149,7 @@ export async function runFastCore(argv, parsed = parseFastCore(argv)) {
146
149
  ? hqRoot ?? process.cwd()
147
150
  : process.cwd();
148
151
  const injectRoot = entry.kind === "shell" || entry.kind === "native" &&
149
- (entry.shellHqRoot === "live" || entry.shellHqRoot === "reconcile-default" && shouldInjectRoot);
152
+ (entry.shellHqRoot === "cwd" || entry.shellHqRoot === "live" || entry.shellHqRoot === "reconcile-default" && shouldInjectRoot);
150
153
  const childEnv = {
151
154
  ...(entry.name === "hq-session" ? { HQ_HQ_SESSION_NO_CLI: "1" } : {}),
152
155
  ...(entry.name === "migrate-policy-triggers"
@@ -39,7 +39,7 @@ export type FastScaffoldScript = {
39
39
  /** Cwd used for a shell rollback companion. Defaults to the caller cwd. */
40
40
  shellCwd?: "caller" | "live";
41
41
  /** Root injection behavior for a shell rollback companion. */
42
- shellHqRoot?: "none" | "live" | "reconcile-default";
42
+ shellHqRoot?: "none" | "cwd" | "live" | "reconcile-default";
43
43
  /** Whether this handler consumes stdin. Shell companions inherit stdin directly. */
44
44
  readsStdin?: boolean;
45
45
  /** Bound bytes buffered from stdin; overflow is treated as empty input. */
@@ -432,6 +432,107 @@ export const FAST_SCAFFOLD_SCRIPTS = [
432
432
  shellCwd: "caller",
433
433
  shellHqRoot: name === "source-yaml-validate" ? "none" : "live",
434
434
  })),
435
+ {
436
+ name: "audit-log",
437
+ kind: "native",
438
+ modulePath: "./commands/core-audit-log-fast.js",
439
+ exportName: "runAuditLogFast",
440
+ flagKey: "hq-core-native-fast-route",
441
+ familyFlagKey: "core-native-utilities",
442
+ asset: "core/scripts/audit-log.sh",
443
+ root: "live",
444
+ shellCwd: "live",
445
+ shellHqRoot: "live",
446
+ },
447
+ {
448
+ name: "refresh-vault-access",
449
+ kind: "native",
450
+ modulePath: "./commands/core-refresh-vault-access-fast.js",
451
+ exportName: "runRefreshVaultAccessFast",
452
+ flagKey: "hq-core-native-fast-route",
453
+ familyFlagKey: "core-native-utilities",
454
+ asset: "core/scripts/refresh-vault-access.sh",
455
+ root: "cwd",
456
+ shellCwd: "caller",
457
+ shellHqRoot: "cwd",
458
+ },
459
+ {
460
+ name: "generate-workers-registry",
461
+ kind: "native",
462
+ modulePath: "./commands/core-generate-workers-registry-fast.js",
463
+ exportName: "runGenerateWorkersRegistryFast",
464
+ flagKey: "hq-core-native-fast-route",
465
+ root: "live",
466
+ asset: "core/scripts/generate-workers-registry.sh",
467
+ },
468
+ {
469
+ name: "dm-bind",
470
+ kind: "native",
471
+ modulePath: "./commands/core-dm-bind-fast.js",
472
+ exportName: "runDmBindFast",
473
+ flagKey: "hq-core-native-fast-route",
474
+ familyFlagKey: "core-native-utilities",
475
+ asset: "core/scripts/hq-dm-bind.sh",
476
+ root: "live",
477
+ shellCwd: "live",
478
+ shellHqRoot: "live",
479
+ readsStdinFor: (args) => {
480
+ if (args[0] !== "post")
481
+ return false;
482
+ const valueOptions = new Set(["--topic", "--under", "--to", "--title", "--state", "--line", "--next", "--ask"]);
483
+ for (let index = 1; index < args.length; index += 1) {
484
+ if (args[index] === "-")
485
+ return true;
486
+ if (valueOptions.has(args[index] ?? ""))
487
+ index += 1;
488
+ }
489
+ return false;
490
+ },
491
+ requiresNodeNetworkCompatibility: true,
492
+ },
493
+ {
494
+ name: "git-pack-extension-check",
495
+ kind: "native",
496
+ modulePath: "./commands/core-git-pack-extension-check-fast.js",
497
+ exportName: "runGitPackExtensionCheckFast",
498
+ flagKey: "hq-core-native-fast-route",
499
+ familyFlagKey: "core-native-utilities",
500
+ asset: "core/scripts/git-pack-extension-check.sh",
501
+ root: "cwd",
502
+ shellCwd: "caller",
503
+ shellHqRoot: "cwd",
504
+ },
505
+ {
506
+ name: "scan-packages",
507
+ kind: "native",
508
+ modulePath: "./commands/core-scan-packages-fast.js",
509
+ exportName: "runScanPackagesFast",
510
+ flagKey: "hq-core-native-fast-route",
511
+ asset: "core/scripts/scan-packages.sh",
512
+ root: "live",
513
+ },
514
+ {
515
+ name: "detect-stale-core-policy-mirror",
516
+ kind: "native",
517
+ modulePath: "./commands/core-detect-stale-core-policy-mirror-fast.js",
518
+ exportName: "runDetectStaleCorePolicyMirrorFast",
519
+ flagKey: "hq-core-native-fast-route",
520
+ asset: "core/scripts/detect-stale-core-policy-mirror.sh",
521
+ root: "live",
522
+ },
523
+ {
524
+ name: "work-mesh-bind-trusted",
525
+ kind: "native",
526
+ modulePath: "./commands/core-work-mesh-bind-trusted-fast.js",
527
+ exportName: "runWorkMeshBindTrustedFast",
528
+ flagKey: "hq-core-native-fast-route",
529
+ familyFlagKey: "core-native-utilities",
530
+ asset: "core/scripts/work-mesh-live-bind-trusted.sh",
531
+ root: "live",
532
+ shellCwd: "live",
533
+ shellHqRoot: "live",
534
+ requiresNodeNetworkCompatibility: true,
535
+ },
435
536
  ];
436
537
  /**
437
538
  * Parse the small, non-ambiguous `hq secrets env` surface for the gated entry
@@ -17,6 +17,8 @@ export interface DaemonFlagClient {
17
17
  }
18
18
  export interface ReadDaemonFlagOptions {
19
19
  env?: NodeJS.ProcessEnv;
20
+ /** Controls how this read combines a local person setting with the registry value. */
21
+ localOverrideMode?: "respect" | "off-only" | "ignore";
20
22
  createClient?: (options: FlagClientOptions) => DaemonFlagClient;
21
23
  getToken?: () => Promise<string>;
22
24
  onError?: (error: unknown) => void;
@@ -15,7 +15,8 @@ const READ_TIMEOUT_MS = 5_000;
15
15
  export async function readDaemonFlag(flagKey, options = {}) {
16
16
  const env = options.env ?? process.env;
17
17
  const override = readLocalOverride(flagKey, env);
18
- if (override !== null)
18
+ const localOverrideMode = options.localOverrideMode ?? "respect";
19
+ if (override !== null && (localOverrideMode === "respect" || (localOverrideMode === "off-only" && !override)))
19
20
  return override;
20
21
  let failed = false;
21
22
  let reportedError;
@@ -12,6 +12,7 @@ import { readCompaniesManifestMap } from "../work-context/repo-remote.js";
12
12
  import { SessionRegistry } from "./session-registry.js";
13
13
  import { HqMcpBridge, type RunWorkerRequest } from "./ops/mcp.js";
14
14
  import { type StdinMachineCredentials } from "./machine-login.js";
15
+ import { type ReadDaemonFlagOptions } from "./flag.js";
15
16
  import { type WindowsPipeAclReport, type WindowsPipeHost } from "./windows-pipe-host.js";
16
17
  export interface HqdServerOptions {
17
18
  socketPath: string;
@@ -41,7 +42,7 @@ export interface HqdServerOptions {
41
42
  /** Test seam for the hq-anywhere-runtime default-off gate. */
42
43
  mcpEnabled?: () => boolean | Promise<boolean>;
43
44
  /** Test seam for the live hq-flags read used by the daemon's bounded runtime monitor. */
44
- runtimeFlagReader?: () => Promise<boolean>;
45
+ runtimeFlagReader?: (options: ReadDaemonFlagOptions) => Promise<boolean>;
45
46
  /** Test seam for the hosted Streamable HTTP MCP transport. */
46
47
  mcpBridge?: HqMcpBridge;
47
48
  /** Test seam for machine login while keeping production credentials off disk. */
@@ -396,14 +396,22 @@ export async function startHqdServer(opts) {
396
396
  }
397
397
  }
398
398
  const runtimeFlagMonitor = opts.mcpEnabled ? undefined : createBoundedDaemonFlagMonitor({
399
- read: opts.runtimeFlagReader ?? (() => readDaemonFlag(HQ_ANYWHERE_RUNTIME_FLAG, {
400
- env,
401
- throwOnError: true,
402
- })),
399
+ read: () => {
400
+ const options = {
401
+ env,
402
+ throwOnError: true,
403
+ // A local opt-out is honored, while a local opt-in cannot override the operator kill switch.
404
+ localOverrideMode: "off-only",
405
+ };
406
+ return opts.runtimeFlagReader
407
+ ? opts.runtimeFlagReader(options)
408
+ : readDaemonFlag(HQ_ANYWHERE_RUNTIME_FLAG, options);
409
+ },
403
410
  onChange: (enabled) => {
404
411
  if (!enabled) {
405
412
  flagRevocationGeneration += 1;
406
413
  ephemeralMachineToken = undefined;
414
+ sessions.clear();
407
415
  }
408
416
  },
409
417
  onReadError: (error) => {
@@ -426,8 +434,22 @@ export async function startHqdServer(opts) {
426
434
  socket: healthSocket(socketPath, isPipe),
427
435
  };
428
436
  };
429
- /** Synchronous ops answer in request order; policy.check and mcp.call may return a promise. */
437
+ const alwaysAvailableOps = new Set(["ping", "health", "auth.status", "shutdown"]);
438
+ const allowedWhileDisabled = new Set(["session.get", "session.close"]);
439
+ /** Gate each external hqd request once, leaving diagnostics and cleanup available while disabled. */
430
440
  const handle = (req) => {
441
+ const requestStartedAt = Date.now();
442
+ if (alwaysAvailableOps.has(req.op))
443
+ return dispatch(req, requestStartedAt);
444
+ return Promise.resolve(mcpEnabled()).then((enabled) => {
445
+ if (!enabled && !allowedWhileDisabled.has(req.op)) {
446
+ throw new OpError("anywhere_disabled", `HQ Anywhere is disabled by the ${HQ_ANYWHERE_RUNTIME_FLAG} flag.`);
447
+ }
448
+ return dispatch(req, requestStartedAt);
449
+ });
450
+ };
451
+ /** Internal MCP sub-operations reuse the already-gated external request. */
452
+ const dispatch = (req, requestStartedAt = Date.now()) => {
431
453
  const args = req.args ?? {};
432
454
  switch (req.op) {
433
455
  case "ping":
@@ -565,7 +587,6 @@ export async function startHqdServer(opts) {
565
587
  }, { hqRoot: opts.hqRoot, workMeshRoot: opts.workMeshRoot, env, now: clock });
566
588
  }
567
589
  case "mcp.call": {
568
- const requestStartedAt = Date.now();
569
590
  const name = stringArg(args, "name");
570
591
  const raw = args.arguments ?? {};
571
592
  if (raw === null || typeof raw !== "object" || Array.isArray(raw))
@@ -581,7 +602,7 @@ export async function startHqdServer(opts) {
581
602
  companyArgs.runtime = runtime;
582
603
  if (sessionId !== undefined)
583
604
  companyArgs.sessionId = sessionId;
584
- const call = (op, a) => handle({ id: req.id, op, args: a });
605
+ const call = (op, a) => dispatch({ id: req.id, op, args: a });
585
606
  const asResult = (value) => (value instanceof Promise ? value.then(jsonResult) : jsonResult(value));
586
607
  const policyGuardedCall = (run) => {
587
608
  const company = companyFor(companyArgs);
@@ -601,7 +622,11 @@ export async function startHqdServer(opts) {
601
622
  const reason = Array.isArray(decision.reasons) ? decision.reasons.filter((r) => typeof r === "string").join("; ") : "policy check did not allow this tool";
602
623
  throw new OpError("policy_blocked", reason || "policy check did not allow this tool");
603
624
  }
604
- return run();
625
+ return Promise.resolve(mcpEnabled()).then((enabled) => {
626
+ if (!enabled)
627
+ throw new OpError("anywhere_disabled", `HQ Anywhere is disabled by the ${HQ_ANYWHERE_RUNTIME_FLAG} flag.`);
628
+ return run();
629
+ });
605
630
  });
606
631
  };
607
632
  switch (name) {
@@ -628,10 +653,7 @@ export async function startHqdServer(opts) {
628
653
  ? Math.max(1, Math.min(args.timeoutMs, 120_000))
629
654
  : HQD_DEFAULT_REQUEST_TIMEOUT_MS;
630
655
  const deadline = requestStartedAt + timeoutMs;
631
- const forward = () => Promise.resolve(mcpEnabled()).then((enabled) => {
632
- if (!enabled) {
633
- throw new OpError("anywhere_disabled", `Hosted hq-mcp forwarding is disabled by the ${HQ_ANYWHERE_RUNTIME_FLAG} flag.`);
634
- }
656
+ const forward = () => {
635
657
  const remainingMs = Math.floor(deadline - Date.now());
636
658
  if (remainingMs <= 0) {
637
659
  throw new McpOpError("hq_mcp_timeout", `Hosted hq-mcp request exceeded its ${timeoutMs}ms end-to-end deadline before forwarding.`);
@@ -650,15 +672,10 @@ export async function startHqdServer(opts) {
650
672
  },
651
673
  });
652
674
  return hqMcp.callTool(name, raw, remainingMs);
653
- });
654
- return Promise.resolve(mcpEnabled()).then((enabled) => {
655
- if (!enabled) {
656
- throw new OpError("anywhere_disabled", `Hosted hq-mcp forwarding is disabled by the ${HQ_ANYWHERE_RUNTIME_FLAG} flag.`);
657
- }
658
- return !MCP_READ_ONLY_TOOL_NAMES.has(name)
659
- ? policyGuardedCall(forward)
660
- : forward();
661
- });
675
+ };
676
+ return !MCP_READ_ONLY_TOOL_NAMES.has(name)
677
+ ? policyGuardedCall(forward)
678
+ : forward();
662
679
  }
663
680
  }
664
681
  }
@@ -24,6 +24,7 @@ export declare class SessionRegistry {
24
24
  }): HqdSession;
25
25
  get(runtime: string, sessionId: string): HqdSession | null;
26
26
  close(runtime: string, sessionId: string): boolean;
27
+ clear(): void;
27
28
  list(): HqdSession[];
28
29
  get size(): number;
29
30
  }
@@ -32,6 +32,9 @@ export class SessionRegistry {
32
32
  close(runtime, sessionId) {
33
33
  return this.sessions.delete(sessionKey(runtime, sessionId));
34
34
  }
35
+ clear() {
36
+ this.sessions.clear();
37
+ }
35
38
  list() {
36
39
  return [...this.sessions.values()];
37
40
  }
@@ -2,7 +2,7 @@
2
2
  import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
4
  import * as yaml from 'js-yaml';
5
- import { contributionLinks } from '../../utils/pack-contributions.js';
5
+ import { contributionLinks } from '../../utils/pack-contribution-links.js';
6
6
  import { CONTRIBUTION_TABLE } from '../../utils/contribution-table.js';
7
7
  function isDirectory(target) { try {
8
8
  return fs.statSync(target).isDirectory();
@@ -0,0 +1,15 @@
1
+ import type { PackContributeKey } from '../types.js';
2
+ /** A single symlink a pack contributes: dst (host path) -> src (inside pack). */
3
+ export interface WiredLink {
4
+ key: PackContributeKey;
5
+ item: string;
6
+ src: string;
7
+ dst: string;
8
+ }
9
+ /**
10
+ * Every SYMLINK a pack's `contributes` block declares. Empty subfields and
11
+ * non-array values are ignored, mirroring scan-packages.sh. `wire: 'merge'`
12
+ * keys (e.g. `mcp`) produce no symlink and are skipped here.
13
+ */
14
+ export declare function contributionLinks(hqRoot: string, packDir: string, contributes: Partial<Record<PackContributeKey, string[]>>): WiredLink[];
15
+ //# sourceMappingURL=pack-contribution-links.d.ts.map
@@ -0,0 +1,33 @@
1
+ import * as path from 'node:path';
2
+ import { CONTRIBUTION_TABLE, payloadFor } from './contribution-table.js';
3
+ /**
4
+ * Every SYMLINK a pack's `contributes` block declares. Empty subfields and
5
+ * non-array values are ignored, mirroring scan-packages.sh. `wire: 'merge'`
6
+ * keys (e.g. `mcp`) produce no symlink and are skipped here.
7
+ */
8
+ export function contributionLinks(hqRoot, packDir, contributes) {
9
+ const links = [];
10
+ for (const [key, items] of Object.entries(contributes)) {
11
+ if (!(key in CONTRIBUTION_TABLE))
12
+ continue;
13
+ if (!Array.isArray(items))
14
+ continue;
15
+ if (CONTRIBUTION_TABLE[key].wire !== 'symlink')
16
+ continue;
17
+ for (const item of items) {
18
+ if (typeof item !== 'string' || item.length === 0)
19
+ continue;
20
+ const row = CONTRIBUTION_TABLE[key];
21
+ const payloadRel = payloadFor(key, item);
22
+ const dstRel = path.join(row.host, path.basename(payloadRel));
23
+ links.push({
24
+ key,
25
+ item,
26
+ src: path.join(packDir, payloadRel),
27
+ dst: path.join(hqRoot, dstRel),
28
+ });
29
+ }
30
+ }
31
+ return links;
32
+ }
33
+ //# sourceMappingURL=pack-contribution-links.js.map
@@ -38,6 +38,8 @@
38
38
  */
39
39
  import type { PackManifest, PackContributeKey } from '../types.js';
40
40
  import { type WireMode } from './contribution-table.js';
41
+ import { type WiredLink } from './pack-contribution-links.js';
42
+ export { contributionLinks, type WiredLink } from './pack-contribution-links.js';
41
43
  import { type UnregisterServerResult, type SafeWriteEnv, type AcquireLockOptions } from '../commands/mcp-registration.js';
42
44
  export { readHqVersion, readRecommendedPackages } from './hq-core-yaml.js';
43
45
  export type { WireMode };
@@ -62,21 +64,7 @@ export declare function mcpServerNameForContribution(packName: string, contribut
62
64
  * order, de-duplicated.
63
65
  */
64
66
  export declare function mergeKeys(contributes: Partial<Record<PackContributeKey, string[]>>): PackContributeKey[];
65
- /** A single symlink a pack contributes: dst (host path) -> src (inside pack). */
66
- export interface WiredLink {
67
- key: PackContributeKey;
68
- item: string;
69
- src: string;
70
- dst: string;
71
- }
72
67
  export type LinkStatus = 'live' | 'broken' | 'missing' | 'foreign';
73
- /**
74
- * Every SYMLINK a pack's `contributes` block declares. Empty subfields and
75
- * non-array values are ignored, mirroring scan-packages.sh. `wire: 'merge'`
76
- * keys (e.g. `mcp`) produce no symlink and are skipped here -- their host
77
- * effect (a config merge) is handled separately (US-004/US-005).
78
- */
79
- export declare function contributionLinks(hqRoot: string, packDir: string, contributes: Partial<Record<PackContributeKey, string[]>>): WiredLink[];
80
68
  /** Classify a host path against the link that should own it. */
81
69
  export declare function linkStatus(link: WiredLink, packDir?: string): LinkStatus;
82
70
  /** A content pack's manifest plus the install-time stamped source. */
@@ -39,7 +39,9 @@
39
39
  import * as fs from 'fs';
40
40
  import * as path from 'path';
41
41
  import * as yaml from 'js-yaml';
42
- import { CONTRIBUTION_TABLE, payloadFor } from './contribution-table.js';
42
+ import { CONTRIBUTION_TABLE } from './contribution-table.js';
43
+ import { contributionLinks } from './pack-contribution-links.js';
44
+ export { contributionLinks } from './pack-contribution-links.js';
43
45
  import { unregisterMcpServers, } from '../commands/mcp-registration.js';
44
46
  export { readHqVersion, readRecommendedPackages } from './hq-core-yaml.js';
45
47
  /**
@@ -78,60 +80,6 @@ export function mergeKeys(contributes) {
78
80
  }
79
81
  return out;
80
82
  }
81
- /**
82
- * Map one SYMLINK contributes entry to its source/host paths, READING the
83
- * single-source `CONTRIBUTION_TABLE` (US-003). The src is the expanded pack
84
- * payload; the dst is `<host-dir>/<payload-basename>` so per-key suffixes
85
- * (`.md`, `.sh`, none) carry through.
86
- *
87
- * Returns `null` for a `wire: 'merge'` key (e.g. `mcp`): a merge contribution
88
- * is not a symlink and has no `WiredLink`. Callers that only handle symlinks
89
- * (contributionLinks/unwirePack) skip those keys.
90
- */
91
- function linkFor(hqRoot, packDir, key, item) {
92
- const row = CONTRIBUTION_TABLE[key];
93
- if (row.wire !== 'symlink')
94
- return null;
95
- const payloadRel = payloadFor(key, item); // e.g. commands/foo.md
96
- // dst keeps the payload's basename (so the suffix carries through) under the
97
- // host directory declared in the table.
98
- const dstRel = path.join(row.host, path.basename(payloadRel));
99
- return {
100
- key,
101
- item,
102
- src: path.join(packDir, payloadRel),
103
- dst: path.join(hqRoot, dstRel),
104
- };
105
- }
106
- /**
107
- * Every SYMLINK a pack's `contributes` block declares. Empty subfields and
108
- * non-array values are ignored, mirroring scan-packages.sh. `wire: 'merge'`
109
- * keys (e.g. `mcp`) produce no symlink and are skipped here -- their host
110
- * effect (a config merge) is handled separately (US-004/US-005).
111
- */
112
- export function contributionLinks(hqRoot, packDir, contributes) {
113
- const links = [];
114
- for (const [key, items] of Object.entries(contributes)) {
115
- if (!(key in CONTRIBUTION_TABLE))
116
- continue; // unknown key -> ignore
117
- if (!Array.isArray(items))
118
- continue;
119
- // INVARIANT (US-005): merge keys are NEVER symlinked. They route to
120
- // registerMcpServers (commands/mcp-registration.ts) instead. Skip them
121
- // explicitly here -- not just via linkFor returning null -- so the symlink
122
- // path provably excludes them.
123
- if (routeContribution(key) === 'merge')
124
- continue;
125
- for (const item of items) {
126
- if (typeof item !== 'string' || item.length === 0)
127
- continue;
128
- const link = linkFor(hqRoot, packDir, key, item);
129
- if (link)
130
- links.push(link); // null for merge keys -- skip
131
- }
132
- }
133
- return links;
134
- }
135
83
  /**
136
84
  * Canonical absolute path — resolves symlinks and platform aliases such as
137
85
  * macOS `/var` ↔ `/private/var` so equivalent paths compare equal.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.345.22",
3
+ "version": "5.345.23",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {