@indigoai-us/hq-cli 5.273.0-alpha.0 → 5.274.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/CHANGELOG.md +65 -2
  2. package/README.md +32 -1
  3. package/dist/command-catalog.generated.d.ts +83 -536
  4. package/dist/command-catalog.generated.js +129 -714
  5. package/dist/command-registration-plan.d.ts +12 -0
  6. package/dist/command-registration-plan.js +2 -0
  7. package/dist/commands/cloud.js +40 -0
  8. package/dist/commands/core-checkpoint.js +3 -1
  9. package/dist/commands/core-command-catalog.d.ts +32 -0
  10. package/dist/commands/core-command-catalog.js +58 -0
  11. package/dist/commands/core-ontology.js +9 -4
  12. package/dist/commands/core.d.ts +4 -0
  13. package/dist/commands/core.js +79 -75
  14. package/dist/commands/daemon.d.ts +0 -3
  15. package/dist/commands/daemon.js +1 -173
  16. package/dist/commands/deploy-comments.d.ts +3 -0
  17. package/dist/commands/deploy-comments.js +159 -0
  18. package/dist/commands/lanes-checks.d.ts +0 -1
  19. package/dist/commands/lanes-checks.js +217 -54
  20. package/dist/commands/lanes-hold.js +40 -2
  21. package/dist/commands/lanes-message.js +98 -14
  22. package/dist/commands/lanes-move.d.ts +12 -0
  23. package/dist/commands/lanes-move.js +342 -0
  24. package/dist/commands/lanes-resume.js +3 -1
  25. package/dist/commands/lanes-shared.d.ts +39 -3
  26. package/dist/commands/lanes-shared.js +59 -0
  27. package/dist/commands/lanes.d.ts +3 -5
  28. package/dist/commands/lanes.js +206 -478
  29. package/dist/commands/report.js +2 -14
  30. package/dist/commands/sync-mode.d.ts +0 -11
  31. package/dist/commands/sync-mode.js +0 -30
  32. package/dist/fast-core.js +1 -1
  33. package/dist/{commands/scaffold-fast.d.ts → fast-scaffold.d.ts} +1 -1
  34. package/dist/{commands/scaffold-fast.js → fast-scaffold.js} +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.js +2 -2
  37. package/dist/lib/checkpoint-ontology/apply.d.ts +8 -0
  38. package/dist/lib/checkpoint-ontology/apply.js +33 -0
  39. package/dist/lib/checkpoint-ontology/plan.d.ts +15 -0
  40. package/dist/lib/checkpoint-ontology/plan.js +15 -0
  41. package/dist/lib/daemon/catalog.d.ts +2 -18
  42. package/dist/lib/daemon/catalog.js +2 -18
  43. package/dist/lib/daemon/config.d.ts +0 -6
  44. package/dist/lib/daemon/config.js +2 -15
  45. package/dist/lib/daemon/requests.d.ts +0 -4
  46. package/dist/lib/daemon/requests.js +0 -2
  47. package/dist/lib/daemon/run.js +19 -78
  48. package/dist/lib/daemon/supervisor.d.ts +0 -8
  49. package/dist/lib/daemon/supervisor.js +1 -101
  50. package/dist/lib/deploy-api.d.ts +6 -0
  51. package/dist/lib/deploy-api.js +21 -0
  52. package/dist/lib/doctor/checks/scaffold-cli-floor.d.ts +7 -0
  53. package/dist/lib/doctor/checks/scaffold-cli-floor.js +73 -0
  54. package/dist/lib/doctor/fix/apply.d.ts +17 -2
  55. package/dist/lib/doctor/fix/apply.js +111 -57
  56. package/dist/lib/doctor/fix/json-output.d.ts +9 -1
  57. package/dist/lib/doctor/fix/json-output.js +11 -0
  58. package/dist/lib/doctor/registry.js +2 -0
  59. package/dist/lib/first-sync-next-step.d.ts +37 -0
  60. package/dist/lib/first-sync-next-step.js +189 -0
  61. package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
  62. package/dist/lib/flag-registry-worker-source.generated.js +1 -1
  63. package/dist/lib/lanes/hire-grant-dispatch.d.ts +6 -1
  64. package/dist/lib/lanes/hire-grant-dispatch.js +78 -3
  65. package/dist/lib/lanes/keep-alive.d.ts +3 -2
  66. package/dist/lib/lanes/keep-alive.js +2 -2
  67. package/dist/lib/lanes/merge-command.d.ts +1 -0
  68. package/dist/lib/lanes/merge-command.js +299 -33
  69. package/dist/lib/lanes/orphans.d.ts +7 -0
  70. package/dist/lib/lanes/orphans.js +39 -4
  71. package/dist/lib/lanes/tracker-store.d.ts +2 -18
  72. package/dist/lib/lanes/tracker-store.js +1 -172
  73. package/dist/lib/scaffold-cli-floor.d.ts +9 -0
  74. package/dist/lib/scaffold-cli-floor.js +50 -0
  75. package/dist/main.js +4 -1
  76. package/dist/utils/cli-telemetry.d.ts +7 -1
  77. package/dist/utils/cli-telemetry.js +84 -8
  78. package/dist/utils/contribution-table.d.ts +1 -1
  79. package/dist/utils/scaffold-fast-import-guard.d.ts +3 -0
  80. package/dist/utils/scaffold-fast-import-guard.js +28 -0
  81. package/dist/utils/scaffold-packlist-guard.d.ts +7 -0
  82. package/dist/utils/scaffold-packlist-guard.js +23 -0
  83. package/dist/utils/scaffold-sibling-references.d.ts +21 -0
  84. package/dist/utils/scaffold-sibling-references.js +156 -0
  85. package/package.json +2 -2
  86. package/dist/commands/lanes-import.d.ts +0 -14
  87. package/dist/commands/lanes-import.js +0 -1210
  88. package/dist/commands/lanes-tracker.d.ts +0 -18
  89. package/dist/commands/lanes-tracker.js +0 -452
  90. package/dist/lib/daemon/sync-runner.d.ts +0 -58
  91. package/dist/lib/daemon/sync-runner.js +0 -277
@@ -432,6 +432,18 @@ export declare const REGISTRATION_PLAN: readonly [{
432
432
  readonly parent: "program";
433
433
  readonly module: "./commands/report.js";
434
434
  readonly exportName: "registerReportCommand";
435
+ }, {
436
+ readonly type: "group";
437
+ readonly root: "deploy";
438
+ readonly id: "deploy";
439
+ readonly name: "deploy";
440
+ readonly description: "Manage deployments in hq-deploy";
441
+ }, {
442
+ readonly type: "registrar";
443
+ readonly root: "deploy";
444
+ readonly parent: "deploy";
445
+ readonly module: "./commands/deploy-comments.js";
446
+ readonly exportName: "registerDeployCommentsCommand";
435
447
  }, {
436
448
  readonly type: "group";
437
449
  readonly root: "staff";
@@ -74,6 +74,8 @@ export const REGISTRATION_PLAN = [
74
74
  { type: "registrar", root: "daemon", parent: "program", module: "./commands/daemon.js", exportName: "registerDaemonCommand", hidden: true },
75
75
  { type: "registrar", root: "bot", parent: "program", module: "./commands/bot.js", exportName: "registerBotCommand" },
76
76
  { type: "registrar", root: "report", parent: "program", module: "./commands/report.js", exportName: "registerReportCommand" },
77
+ { type: "group", root: "deploy", id: "deploy", name: "deploy", description: "Manage deployments in hq-deploy" },
78
+ { type: "registrar", root: "deploy", parent: "deploy", module: "./commands/deploy-comments.js", exportName: "registerDeployCommentsCommand" },
77
79
  // onboarding-test-accounts US-007 — super-admin staff CLI wrappers over the
78
80
  // hq-pro admin surface. New wrappers land under this group; the reset
79
81
  // command mirrors POST /v1/admin/test-account/reset.
@@ -21,6 +21,7 @@ import { DEFAULT_HQ_ROOT, ensureCognitoToken, buildVaultConfig, } from "../utils
21
21
  import { resolveUploadAuthor } from "../utils/upload-author.js";
22
22
  import { companyFolderExceedsThreshold, emitNarrowHint, isStrictRefusal, resolveBannerLevel, resolveNarrowHintPresentationLevel, resolveNarrowHintMinBytes, } from "../lib/narrow-hint-banner.js";
23
23
  import { beginSyncHealthReport, } from "../utils/client-health.js";
24
+ import { recordFirstWorkBearingSync } from "../lib/first-sync-next-step.js";
24
25
  /**
25
26
  * Terminal-failure signal for the sync fanout runners. The runners
26
27
  * (`runPushAll` / `runPullAll` / `runPullPersonal` / `runNowSingle` /
@@ -882,6 +883,11 @@ export function registerCloudCommands(program) {
882
883
  await syncHealth.failed();
883
884
  process.exit(1);
884
885
  }
886
+ recordFirstWorkBearingSync({
887
+ filesUploaded: result.filesUploaded,
888
+ filesDeleted: result.filesDeleted,
889
+ aborted: result.aborted,
890
+ });
885
891
  if (result.filesExcludedByScope > 0) {
886
892
  log(chalk.yellow(`\n⚠ Pushed ${result.filesUploaded} file(s) (${formatBytes(result.bytesUploaded)}, ` +
887
893
  `${result.filesSkipped} skipped, ${result.filesExcludedByScope} scope-excluded)`));
@@ -1026,6 +1032,10 @@ export function registerCloudCommands(program) {
1026
1032
  await syncHealth.failed();
1027
1033
  process.exit(1);
1028
1034
  }
1035
+ recordFirstWorkBearingSync({
1036
+ filesDownloaded: result.filesDownloaded,
1037
+ aborted: result.aborted,
1038
+ });
1029
1039
  console.log(chalk.green(`\n✓ Pulled ${result.filesDownloaded} file(s) (${formatBytes(result.bytesDownloaded)}, ${result.filesSkipped} skipped, ${result.conflicts} conflicts)`));
1030
1040
  // Emit the hint banner after success so it appears alongside the
1031
1041
  // summary line. Mirrors the wiring in runPullAll and runNowSingle.
@@ -1325,6 +1335,14 @@ async function runPullAll(hqRoot, onConflict, modeAllOverride, skipPersonal, for
1325
1335
  `(${formatBytes(result.bytesDownloaded)}) across ${result.attempted} ` +
1326
1336
  `target(s); ${result.conflicts} conflict(s); ${errored} error(s)`;
1327
1337
  console.log(errored > 0 ? chalk.yellow(summary) : chalk.green(summary));
1338
+ for (const row of result.perCompany) {
1339
+ if (row.result && !row.error) {
1340
+ recordFirstWorkBearingSync({
1341
+ filesDownloaded: row.result.filesDownloaded,
1342
+ aborted: row.result.aborted,
1343
+ });
1344
+ }
1345
+ }
1328
1346
  if (errored > 0)
1329
1347
  throw new SyncExitError(1);
1330
1348
  }
@@ -1355,6 +1373,10 @@ export async function runPullPersonal(hqRoot, onConflict) {
1355
1373
  throw new SyncExitError(1);
1356
1374
  }
1357
1375
  console.log(chalk.green(`\n✓ Pulled ${result.filesDownloaded} file(s) (${formatBytes(result.bytesDownloaded)}, ${result.filesSkipped} skipped, ${result.conflicts} conflicts)`));
1376
+ recordFirstWorkBearingSync({
1377
+ filesDownloaded: result.filesDownloaded,
1378
+ aborted: result.aborted,
1379
+ });
1358
1380
  }
1359
1381
  catch (err) {
1360
1382
  if (err instanceof SyncExitError)
@@ -1454,6 +1476,15 @@ async function runPushAll(hqRoot, message, onConflict, skipPersonal) {
1454
1476
  console.log(errored > 0 || result.filesExcludedByScope > 0
1455
1477
  ? chalk.yellow(summary)
1456
1478
  : chalk.green(summary));
1479
+ for (const row of result.perCompany) {
1480
+ if (row.result && !row.error) {
1481
+ recordFirstWorkBearingSync({
1482
+ filesUploaded: row.result.filesUploaded,
1483
+ filesDeleted: row.result.filesDeleted,
1484
+ aborted: row.result.aborted,
1485
+ });
1486
+ }
1487
+ }
1457
1488
  for (const row of result.perCompany) {
1458
1489
  const excluded = row.result?.filesExcludedByScope ?? 0;
1459
1490
  for (const line of scopeExcludedLines(excluded, row.prefixSet)) {
@@ -1544,6 +1575,11 @@ async function runNowSingle(hqRoot, company, personal, message, onConflict, mode
1544
1575
  console.log(chalk.yellow("\n⚠ Sync now aborted on push leg; pull skipped."));
1545
1576
  throw new SyncExitError(1);
1546
1577
  }
1578
+ recordFirstWorkBearingSync({
1579
+ filesUploaded: pushResult.filesUploaded,
1580
+ filesDeleted: pushResult.filesDeleted,
1581
+ aborted: pushResult.aborted,
1582
+ });
1547
1583
  // US-011: resolve membership sync-config so we can either nudge an
1548
1584
  // all-mode owner or refuse the pull when strict-mode is on. Skipped
1549
1585
  // for personal targets (personal vault has no membership row) and
@@ -1635,6 +1671,10 @@ async function runNowSingle(hqRoot, company, personal, message, onConflict, mode
1635
1671
  console.log(chalk.yellow("\n⚠ Sync now finished with pull leg aborted."));
1636
1672
  throw new SyncExitError(1);
1637
1673
  }
1674
+ recordFirstWorkBearingSync({
1675
+ filesDownloaded: pullResult.filesDownloaded,
1676
+ aborted: pullResult.aborted,
1677
+ });
1638
1678
  // Emit the hint banner after a successful pull so it appears at the
1639
1679
  // bottom of the summary rather than mid-stream. Size-gated: only a large
1640
1680
  // local folder is nudged.
@@ -17,6 +17,7 @@ import { toHqStateWriteError } from "../utils/hq-state-write-error.js";
17
17
  import { checkpointStampWriteErrorFor, isCheckpointStampWriteError, } from "../utils/checkpoint-stamp-write-error.js";
18
18
  import { readBackendPreference } from "../lib/checkpoint-ontology/plan.js";
19
19
  import { resolveOntologyCompany } from "../lib/checkpoint-ontology/company.js";
20
+ import { describeCoreCommand } from "./core-command-catalog.js";
20
21
  const DEFAULT_TRIGGER = "stop-gate";
21
22
  const BACKENDS = new Set(["auto", "claude", "codex", "grok", "none"]);
22
23
  // Pinned by operator directive 2026-09-15; change defaults here deliberately.
@@ -1175,7 +1176,7 @@ function reportUsage(error) {
1175
1176
  }
1176
1177
  /** Attach the native checkpoint command to the hidden `hq core` group. */
1177
1178
  export function registerCoreCheckpointCommand(core) {
1178
- core
1179
+ const checkpoint = core
1179
1180
  .command("checkpoint")
1180
1181
  .description("Record an end-of-turn checkpoint and start HQ maintenance")
1181
1182
  .option("--summary <text>", "1–2 sentence outcome summary")
@@ -1211,5 +1212,6 @@ export function registerCoreCheckpointCommand(core) {
1211
1212
  throw error;
1212
1213
  }
1213
1214
  });
1215
+ describeCoreCommand(checkpoint, { execution: "native", root: "live" });
1214
1216
  }
1215
1217
  //# sourceMappingURL=core-checkpoint.js.map
@@ -0,0 +1,32 @@
1
+ import type { Command } from "commander";
2
+ export type CoreCommandExecution = "native" | "bundled-shell" | "bundled-node";
3
+ export type CoreCommandRoot = "live" | "source" | "cwd";
4
+ export type CoreCommandListingEntry = {
5
+ name: string;
6
+ execution: CoreCommandExecution;
7
+ asset?: string;
8
+ root: CoreCommandRoot;
9
+ };
10
+ type CoreCommandMetadata = (Omit<CoreCommandListingEntry, "name"> & {
11
+ entries?: never;
12
+ }) | {
13
+ entries: readonly CoreCommandListingEntry[];
14
+ };
15
+ /** Mark the exact Commander registration that supplies a catalog row. */
16
+ export declare function describeCoreCommand(command: Command, metadata: CoreCommandMetadata): Command;
17
+ /**
18
+ * Reflect executable leaf commands from the Commander tree. Asset-backed rows
19
+ * are attached at the point where core.ts registers each table entry, so the
20
+ * JSON output cannot drift into a second, hand-maintained command list.
21
+ */
22
+ export declare function registeredCoreCommandListing(core: Command): CoreCommandListingEntry[];
23
+ export declare function fastScaffoldListingMismatches(listing: readonly CoreCommandListingEntry[], fastScripts: readonly {
24
+ name: string;
25
+ asset: string;
26
+ }[]): string[];
27
+ export declare function assertFastScaffoldListingParity(listing: readonly CoreCommandListingEntry[], fastScripts: readonly {
28
+ name: string;
29
+ asset: string;
30
+ }[]): void;
31
+ export {};
32
+ //# sourceMappingURL=core-command-catalog.d.ts.map
@@ -0,0 +1,58 @@
1
+ const metadataByCommand = new WeakMap();
2
+ /** Mark the exact Commander registration that supplies a catalog row. */
3
+ export function describeCoreCommand(command, metadata) {
4
+ metadataByCommand.set(command, metadata);
5
+ return command;
6
+ }
7
+ /**
8
+ * Reflect executable leaf commands from the Commander tree. Asset-backed rows
9
+ * are attached at the point where core.ts registers each table entry, so the
10
+ * JSON output cannot drift into a second, hand-maintained command list.
11
+ */
12
+ export function registeredCoreCommandListing(core) {
13
+ const entries = [];
14
+ const visit = (parent, parents) => {
15
+ for (const command of parent.commands) {
16
+ const path = [...parents, command.name()].join(" ");
17
+ if (command.commands.length > 0) {
18
+ visit(command, [...parents, command.name()]);
19
+ continue;
20
+ }
21
+ const metadata = metadataByCommand.get(command);
22
+ if (!metadata) {
23
+ throw new Error(`hq core command ${path} has no listing metadata`);
24
+ }
25
+ const described = metadata.entries
26
+ ? metadata.entries
27
+ : [{
28
+ name: path,
29
+ execution: metadata.execution,
30
+ ...(metadata.asset ? { asset: metadata.asset } : {}),
31
+ root: metadata.root,
32
+ }];
33
+ entries.push(...described);
34
+ }
35
+ };
36
+ visit(core, []);
37
+ return entries.sort((a, b) => a.name.localeCompare(b.name));
38
+ }
39
+ export function fastScaffoldListingMismatches(listing, fastScripts) {
40
+ const mismatches = [];
41
+ for (const fast of fastScripts) {
42
+ const listed = listing.find((entry) => entry.name === fast.name);
43
+ if (!listed) {
44
+ mismatches.push(`${fast.name} is missing from hq core commands`);
45
+ }
46
+ else if (listed.asset !== fast.asset) {
47
+ mismatches.push(`${fast.name} lists ${listed.asset ?? "no asset"}, fast path uses ${fast.asset}`);
48
+ }
49
+ }
50
+ return mismatches;
51
+ }
52
+ export function assertFastScaffoldListingParity(listing, fastScripts) {
53
+ const mismatches = fastScaffoldListingMismatches(listing, fastScripts);
54
+ if (mismatches.length > 0) {
55
+ throw new Error(mismatches.join("\n"));
56
+ }
57
+ }
58
+ //# sourceMappingURL=core-command-catalog.js.map
@@ -10,6 +10,7 @@
10
10
  import * as fs from "node:fs";
11
11
  import * as path from "node:path";
12
12
  import { resolveLiveRoot } from "../utils/hq-roots.js";
13
+ import { describeCoreCommand } from "./core-command-catalog.js";
13
14
  import { readLanesRegistryFlag } from "../lib/lanes/registry-flag.js";
14
15
  import { MULTI_WRITER_FLAG, planOntologyRun, } from "../lib/checkpoint-ontology/plan.js";
15
16
  import { applyOntologyRun, ApplyError } from "../lib/checkpoint-ontology/apply.js";
@@ -205,7 +206,7 @@ export function registerCoreOntologyCommand(core) {
205
206
  .command("ontology")
206
207
  .description("Checkpoint ontology steps run by the checkpoint sibling (gated by checkpoint.ontology)");
207
208
  const rootFor = (options) => resolveLiveRoot({ hqRoot: options.hqRoot ?? core.opts().hqRoot });
208
- ontology
209
+ const plan = ontology
209
210
  .command("plan")
210
211
  .description("Check the flag and list the changed company files for this checkpoint run")
211
212
  .option("--run-dir <path>", "checkpoint sibling run directory holding payload.json")
@@ -218,7 +219,8 @@ export function registerCoreOntologyCommand(core) {
218
219
  fail(error);
219
220
  }
220
221
  });
221
- ontology
222
+ describeCoreCommand(plan, { execution: "native", root: "live" });
223
+ const duplicates = ontology
222
224
  .command("duplicates")
223
225
  .description("List same-type entities whose names collide, with a proposed survivor (read-only)")
224
226
  .requiredOption("--company <slug>", "company to scan")
@@ -232,7 +234,8 @@ export function registerCoreOntologyCommand(core) {
232
234
  fail(error);
233
235
  }
234
236
  });
235
- ontology
237
+ describeCoreCommand(duplicates, { execution: "native", root: "live" });
238
+ const mergeCopies = ontology
236
239
  .command("merge-copies")
237
240
  .description("Merge '<name> N.md' entity copies into their original, then delete them from the vault (dry run by default)")
238
241
  .requiredOption("--company <slug>", "company to change")
@@ -249,7 +252,8 @@ export function registerCoreOntologyCommand(core) {
249
252
  fail(error);
250
253
  }
251
254
  });
252
- ontology
255
+ describeCoreCommand(mergeCopies, { execution: "native", root: "live" });
256
+ const apply = ontology
253
257
  .command("apply")
254
258
  .description("Validate the run's entity candidates and write them to the payload company")
255
259
  .option("--run-dir <path>", "checkpoint sibling run directory holding the plan and candidates")
@@ -262,5 +266,6 @@ export function registerCoreOntologyCommand(core) {
262
266
  fail(error);
263
267
  }
264
268
  });
269
+ describeCoreCommand(apply, { execution: "native", root: "live" });
265
270
  }
266
271
  //# sourceMappingURL=core-ontology.js.map
@@ -68,6 +68,8 @@ export type ScaffoldCommand = ScaffoldAsset & {
68
68
  export type RebuildIndexTarget = {
69
69
  /** Rebuild target — `hq core rebuild-index <target>`. */
70
70
  target: string;
71
+ /** Legacy scaffold companion, retained for compatibility and packaging. */
72
+ asset: string;
71
73
  /** Native renderer identifier. */
72
74
  renderer: IndexTarget;
73
75
  /** One-line summary, shown in `hq core --help`. */
@@ -87,6 +89,8 @@ export type NativeScaffoldCommand = ScaffoldAsset & {
87
89
  };
88
90
  type NativeUtilityCommand = {
89
91
  name: string;
92
+ /** Retained loose-file companion for old scaffold callers. */
93
+ asset: string;
90
94
  root: ScaffoldRoot;
91
95
  summary: string;
92
96
  run: (args: string[], context: {
@@ -32,7 +32,7 @@ import { Option } from "commander";
32
32
  import { registerCoreCheckpointCommand } from "./core-checkpoint.js";
33
33
  import { registerCoreOntologyCommand } from "./core-ontology.js";
34
34
  import { resolveLiveRoot } from "../utils/hq-roots.js";
35
- import { runBundledScript } from "../utils/run-bundled-script.js";
35
+ import { interpreterFor, runBundledScript } from "../utils/run-bundled-script.js";
36
36
  import { renderIndexTarget } from "../lib/index-render/index.js";
37
37
  import { generateWorkersRegistry } from "../lib/workers-registry/index.js";
38
38
  import { scanPackages } from "../lib/scan-packages/index.js";
@@ -48,21 +48,22 @@ import { qmdReindexAfterSync } from "../lib/core-utils/qmd-reindex-after-sync.js
48
48
  import { softTimeoutCommand } from "../lib/core-utils/soft-timeout.js";
49
49
  import { timeoutGuardCommand } from "../lib/core-utils/timeout-guard.js";
50
50
  import { readSentryReportStdin, reportSentryEvent } from "../lib/core-utils/sentry-report.js";
51
+ import { describeCoreCommand, registeredCoreCommandListing, } from "./core-command-catalog.js";
51
52
  /**
52
53
  * These commands are now native implementations. Their retained shell assets
53
54
  * are deliberately claimed in SCAFFOLD_ONLY_ASSETS: loose HQ trees still ship
54
55
  * them for legacy callers, but `hq core` never dispatches through them again.
55
56
  */
56
57
  export const NATIVE_UTILITY_COMMANDS = [
57
- { name: "detect-stale-core-policy-mirror", root: "live", summary: "Find (and prune) stale personal-policy mirrors in core", run: (args, context) => detectStaleCorePolicyMirror(args, { root: context.hqRoot }) },
58
- { name: "hq-status-summary", root: "cwd", summary: "Summarize working-tree status across the HQ tree", run: (args, context) => summarizeHqStatus(args, { cwd: context.cwd, root: context.hqRoot }) },
59
- { name: "ontology-readme-drift", root: "live", summary: "Check a company's ontology README for drift", run: (args, context) => ontologyReadmeDrift(args, { root: context.hqRoot }) },
60
- { name: "resize-screenshot", root: "cwd", summary: "Downscale a screenshot for context efficiency", run: (args) => resizeScreenshot(args) },
61
- { name: "token-usage-report", root: "cwd", summary: "Report session token usage", run: (args) => tokenUsageReport(args) },
62
- { name: "worktree", root: "live", summary: "Create a git worktree under workspace/worktrees/", run: (args, context) => createWorktree(args, { cwd: context.cwd, hqRoot: context.hqRoot }) },
63
- { name: "codex-skill-bridge", root: "live", summary: "Install/inspect the Codex skill bridge", run: (args, context) => runCodexSkillBridgeCommand(args, { root: context.hqRoot ?? context.cwd }) },
64
- { name: "archive-old-threads", root: "live", summary: "Archive aged session-thread files", run: (args, context) => archiveOldThreads(args, { hqRoot: context.hqRoot ?? context.cwd }) },
65
- { name: "qmd-reindex-after-sync", root: "cwd", summary: "Refresh qmd collections after a sync", run: (args, context) => qmdReindexAfterSync(args, { cwd: context.cwd }) },
58
+ { name: "detect-stale-core-policy-mirror", asset: "core/scripts/detect-stale-core-policy-mirror.sh", root: "live", summary: "Find (and prune) stale personal-policy mirrors in core", run: (args, context) => detectStaleCorePolicyMirror(args, { root: context.hqRoot }) },
59
+ { name: "hq-status-summary", asset: "core/scripts/hq-status-summary.sh", root: "cwd", summary: "Summarize working-tree status across the HQ tree", run: (args, context) => summarizeHqStatus(args, { cwd: context.cwd, root: context.hqRoot }) },
60
+ { name: "ontology-readme-drift", asset: "core/scripts/ontology-readme-drift.sh", root: "live", summary: "Check a company's ontology README for drift", run: (args, context) => ontologyReadmeDrift(args, { root: context.hqRoot }) },
61
+ { name: "resize-screenshot", asset: "core/scripts/resize-screenshot.sh", root: "cwd", summary: "Downscale a screenshot for context efficiency", run: (args) => resizeScreenshot(args) },
62
+ { name: "token-usage-report", asset: "core/scripts/token-usage-report.sh", root: "cwd", summary: "Report session token usage", run: (args) => tokenUsageReport(args) },
63
+ { name: "worktree", asset: "core/scripts/worktree.sh", root: "live", summary: "Create a git worktree under workspace/worktrees/", run: (args, context) => createWorktree(args, { cwd: context.cwd, hqRoot: context.hqRoot }) },
64
+ { name: "codex-skill-bridge", asset: "core/scripts/codex-skill-bridge.sh", root: "live", summary: "Install/inspect the Codex skill bridge", run: (args, context) => runCodexSkillBridgeCommand(args, { root: context.hqRoot ?? context.cwd }) },
65
+ { name: "archive-old-threads", asset: "core/scripts/archive-old-threads.sh", root: "live", summary: "Archive aged session-thread files", run: (args, context) => archiveOldThreads(args, { hqRoot: context.hqRoot ?? context.cwd }) },
66
+ { name: "qmd-reindex-after-sync", asset: "core/scripts/qmd-reindex-after-sync.sh", root: "cwd", summary: "Refresh qmd collections after a sync", run: (args, context) => qmdReindexAfterSync(args, { cwd: context.cwd }) },
66
67
  ];
67
68
  export const NATIVE_SCAFFOLD_COMMANDS = [
68
69
  {
@@ -110,51 +111,61 @@ export const WORKER_SUBCOMMANDS = [
110
111
  export const REBUILD_INDEX_TARGETS = [
111
112
  {
112
113
  target: "all",
114
+ asset: "core/scripts/rebuild-all-indexes.sh",
113
115
  renderer: "all",
114
116
  summary: "Regenerate every INDEX.md across the HQ tree",
115
117
  },
116
118
  {
117
119
  target: "companies",
120
+ asset: "core/scripts/rebuild-companies-index.sh",
118
121
  renderer: "companies",
119
122
  summary: "Regenerate companies/INDEX.md",
120
123
  },
121
124
  {
122
125
  target: "company-knowledge",
126
+ asset: "core/scripts/rebuild-company-knowledge-index.sh",
123
127
  renderer: "company-knowledge",
124
128
  summary: "Regenerate a company's knowledge INDEX.md",
125
129
  },
126
130
  {
127
131
  target: "orchestrator",
132
+ asset: "core/scripts/rebuild-orchestrator-index.sh",
128
133
  renderer: "orchestrator",
129
134
  summary: "Regenerate the orchestrator workspace INDEX.md",
130
135
  },
131
136
  {
132
137
  target: "projects",
138
+ asset: "core/scripts/rebuild-projects-index.sh",
133
139
  renderer: "projects",
134
140
  summary: "Regenerate the projects INDEX.md",
135
141
  },
136
142
  {
137
143
  target: "public-knowledge",
144
+ asset: "core/scripts/rebuild-public-knowledge-index.sh",
138
145
  renderer: "public-knowledge",
139
146
  summary: "Regenerate core/knowledge/public/INDEX.md",
140
147
  },
141
148
  {
142
149
  target: "reports",
150
+ asset: "core/scripts/rebuild-reports-index.sh",
143
151
  renderer: "reports",
144
152
  summary: "Regenerate the reports INDEX.md",
145
153
  },
146
154
  {
147
155
  target: "social-drafts",
156
+ asset: "core/scripts/rebuild-social-drafts-index.sh",
148
157
  renderer: "social-drafts",
149
158
  summary: "Regenerate workspace/social-drafts/INDEX.md",
150
159
  },
151
160
  {
152
161
  target: "threads",
162
+ asset: "core/scripts/rebuild-threads-index.sh",
153
163
  renderer: "threads",
154
164
  summary: "Regenerate the session-threads INDEX.md",
155
165
  },
156
166
  {
157
167
  target: "workers",
168
+ asset: "core/scripts/rebuild-workers-index.sh",
158
169
  renderer: "workers",
159
170
  summary: "Regenerate the workers INDEX.md",
160
171
  },
@@ -201,65 +212,16 @@ export const SCAFFOLD_ONLY_ASSETS = [
201
212
  { asset: "core/scripts/lib/session-scope-capability.sh", root: "live", summary: "Session scope-capability lib sourced by hq-session" },
202
213
  { asset: "core/scripts/lib/session-id.sh", root: "live", summary: "Session-id resolver lib sourced by hq-session" },
203
214
  { asset: "core/scripts/lib/work-mesh-enqueue.sh", root: "live", summary: "Work Mesh Live spool enqueue lib sourced by hooks" },
204
- { asset: "core/scripts/archive-old-threads.sh", root: "live", summary: "Scaffold-only native utility companion" },
205
- { asset: "core/scripts/codex-skill-bridge.sh", root: "live", summary: "Scaffold-only native utility companion" },
206
- { asset: "core/scripts/qmd-reindex-after-sync.sh", root: "cwd", summary: "Scaffold-only native utility companion" },
207
- { asset: "core/scripts/detect-stale-core-policy-mirror.sh", root: "live", summary: "Scaffold-only native utility companion" },
208
- { asset: "core/scripts/hq-status-summary.sh", root: "cwd", summary: "Scaffold-only native utility companion" },
209
- { asset: "core/scripts/ontology-readme-drift.sh", root: "live", summary: "Scaffold-only native utility companion" },
210
- { asset: "core/scripts/resize-screenshot.sh", root: "cwd", summary: "Scaffold-only native utility companion" },
211
- { asset: "core/scripts/token-usage-report.sh", root: "cwd", summary: "Scaffold-only native utility companion" },
212
- { asset: "core/scripts/worktree.sh", root: "live", summary: "Scaffold-only native utility companion" },
213
- {
214
- asset: "core/scripts/rebuild-all-indexes.sh",
215
- root: "cwd",
216
- summary: "Scaffold-only native rebuild-index companion",
217
- },
218
- {
219
- asset: "core/scripts/rebuild-companies-index.sh",
215
+ ...NATIVE_UTILITY_COMMANDS.map(({ asset, root, summary }) => ({
216
+ asset,
217
+ root,
218
+ summary: `Scaffold-only native utility companion: ${summary}`,
219
+ })),
220
+ ...REBUILD_INDEX_TARGETS.map(({ asset }) => ({
221
+ asset,
220
222
  root: "cwd",
221
223
  summary: "Scaffold-only native rebuild-index companion",
222
- },
223
- {
224
- asset: "core/scripts/rebuild-company-knowledge-index.sh",
225
- root: "cwd",
226
- summary: "Scaffold-only native rebuild-index companion",
227
- },
228
- {
229
- asset: "core/scripts/rebuild-orchestrator-index.sh",
230
- root: "cwd",
231
- summary: "Scaffold-only native rebuild-index companion",
232
- },
233
- {
234
- asset: "core/scripts/rebuild-projects-index.sh",
235
- root: "cwd",
236
- summary: "Scaffold-only native rebuild-index companion",
237
- },
238
- {
239
- asset: "core/scripts/rebuild-public-knowledge-index.sh",
240
- root: "cwd",
241
- summary: "Scaffold-only native rebuild-index companion",
242
- },
243
- {
244
- asset: "core/scripts/rebuild-reports-index.sh",
245
- root: "cwd",
246
- summary: "Scaffold-only native rebuild-index companion",
247
- },
248
- {
249
- asset: "core/scripts/rebuild-social-drafts-index.sh",
250
- root: "cwd",
251
- summary: "Scaffold-only native rebuild-index companion",
252
- },
253
- {
254
- asset: "core/scripts/rebuild-threads-index.sh",
255
- root: "cwd",
256
- summary: "Scaffold-only native rebuild-index companion",
257
- },
258
- {
259
- asset: "core/scripts/rebuild-workers-index.sh",
260
- root: "cwd",
261
- summary: "Scaffold-only native rebuild-index companion",
262
- },
224
+ })),
263
225
  ];
264
226
  /** Every claimed bundled asset, used by packaging and interpreter tests. */
265
227
  export const SCAFFOLD_ASSETS = [
@@ -328,7 +290,7 @@ export function registerCoreCommands(program) {
328
290
  // similarly named scaffold assets are forwarders, so sending them through
329
291
  // runEntry would recurse back into this command forever.
330
292
  for (const entry of NATIVE_SCAFFOLD_COMMANDS) {
331
- core
293
+ const command = core
332
294
  .command(entry.name)
333
295
  .description(entry.summary)
334
296
  .allowUnknownOption()
@@ -344,9 +306,14 @@ export function registerCoreCommands(program) {
344
306
  if (result.status !== 0)
345
307
  process.exit(result.status);
346
308
  });
309
+ describeCoreCommand(command, {
310
+ execution: "native",
311
+ asset: entry.asset,
312
+ root: entry.root,
313
+ });
347
314
  }
348
315
  for (const entry of NATIVE_UTILITY_COMMANDS) {
349
- core
316
+ const command = core
350
317
  .command(entry.name)
351
318
  .description(entry.summary)
352
319
  .allowUnknownOption()
@@ -361,6 +328,11 @@ export function registerCoreCommands(program) {
361
328
  if (code !== 0)
362
329
  process.exit(code);
363
330
  });
331
+ describeCoreCommand(command, {
332
+ execution: "native",
333
+ asset: entry.asset,
334
+ root: entry.root,
335
+ });
364
336
  }
365
337
  // `hq core worker <name>` — a nested subgroup for worker-scoped skill
366
338
  // maintenance. Nested (rather than flat `hq core worker-<name>`) so the two
@@ -369,7 +341,7 @@ export function registerCoreCommands(program) {
369
341
  .command("worker")
370
342
  .description("Worker-scoped skill maintenance (lint, share)");
371
343
  for (const entry of WORKER_SUBCOMMANDS) {
372
- worker
344
+ const command = worker
373
345
  .command(entry.name)
374
346
  .description(entry.summary)
375
347
  // Pure passthrough: the wrapped script owns its own argument grammar.
@@ -382,6 +354,11 @@ export function registerCoreCommands(program) {
382
354
  const operands = cmd.args.length > 0 ? cmd.args : args;
383
355
  runEntry(entry, scope, operands);
384
356
  });
357
+ describeCoreCommand(command, {
358
+ execution: interpreterFor(entry.asset) === "node" ? "bundled-node" : "bundled-shell",
359
+ asset: entry.asset,
360
+ root: entry.root,
361
+ });
385
362
  }
386
363
  const runCommand = (entry, args = [], cmd, target) => {
387
364
  const scope = core.opts();
@@ -393,7 +370,7 @@ export function registerCoreCommands(program) {
393
370
  runEntry(entry, scope, passthrough);
394
371
  };
395
372
  const validTargets = REBUILD_INDEX_TARGETS.map((entry) => entry.target);
396
- core
373
+ const rebuildCommand = core
397
374
  .command("rebuild-index <target> [args...]")
398
375
  .description(`Regenerate one index (target: ${validTargets.join(", ")})`)
399
376
  // Pure passthrough: the wrapped script owns its own argument grammar, so
@@ -424,8 +401,16 @@ export function registerCoreCommands(program) {
424
401
  throw expectedUserError(`rebuild-index: refused to overwrite ${refused.length} hand-edited INDEX.md file(s). Re-run with --accept to overwrite.`);
425
402
  }
426
403
  });
404
+ describeCoreCommand(rebuildCommand, {
405
+ entries: REBUILD_INDEX_TARGETS.map((entry) => ({
406
+ name: `rebuild-index ${entry.target}`,
407
+ execution: "native",
408
+ asset: entry.asset,
409
+ root: "live",
410
+ })),
411
+ });
427
412
  for (const entry of SCAFFOLD_COMMANDS) {
428
- core
413
+ const command = core
429
414
  .command(entry.name)
430
415
  .description(entry.summary)
431
416
  // Pure passthrough: the wrapped script owns its own argument grammar, so
@@ -438,12 +423,17 @@ export function registerCoreCommands(program) {
438
423
  .action((args = [], _opts, cmd) => {
439
424
  runCommand(entry, args, cmd);
440
425
  });
426
+ describeCoreCommand(command, {
427
+ execution: interpreterFor(entry.asset) === "node" ? "bundled-node" : "bundled-shell",
428
+ asset: entry.asset,
429
+ root: entry.root,
430
+ });
441
431
  }
442
432
  // `hq core soft-timeout <interval> [--hard-cap <spec>] [--label <name>] -- <cmd…>`
443
433
  // Async and bespoke (the NATIVE_UTILITY_COMMANDS table is synchronous), since
444
434
  // it spawns a child and warns over time. Warn-don't-kill primitive for
445
435
  // finding 2.1 — the CLI-hosted twin of core/scripts/lib/soft-timeout.sh.
446
- core
436
+ const softTimeout = core
447
437
  .command("soft-timeout")
448
438
  .description("Run a command under a soft (warn, don't kill) timeout")
449
439
  // Passthrough: the wrapped command owns everything after `--`.
@@ -457,10 +447,11 @@ export function registerCoreCommands(program) {
457
447
  if (code !== 0)
458
448
  process.exit(code);
459
449
  });
450
+ describeCoreCommand(softTimeout, { execution: "native", root: "cwd" });
460
451
  // `hq core timeout-guard` — PreToolUse decision for the foreground-timeout
461
452
  // guard (finding 2.1). Reads the hook JSON on stdin and exits 2 to block, 0
462
453
  // to allow. The shipped .claude hook is a thin shim over this.
463
- core
454
+ const timeoutGuard = core
464
455
  .command("timeout-guard")
465
456
  .description("PreToolUse guard: block over-ceiling foreground timeouts (reads hook JSON on stdin)")
466
457
  .helpOption(false)
@@ -472,10 +463,11 @@ export function registerCoreCommands(program) {
472
463
  if (code !== 0)
473
464
  process.exit(code);
474
465
  });
466
+ describeCoreCommand(timeoutGuard, { execution: "native", root: "cwd" });
475
467
  // `hq core sentry report` — constrained, stderr-diagnostic-only transport
476
468
  // for hook health events. Event data is accepted only on stdin so it never
477
469
  // appears in the process list shared by the fleet.
478
- core
470
+ const sentryReport = core
479
471
  .command("sentry")
480
472
  .description("Constrained diagnostics transport for HQ hooks")
481
473
  .command("report")
@@ -495,6 +487,18 @@ export function registerCoreCommands(program) {
495
487
  if (result.code !== 0)
496
488
  process.exitCode = result.code;
497
489
  });
490
+ describeCoreCommand(sentryReport, { execution: "native", root: "live" });
491
+ const commands = core
492
+ .command("commands", { hidden: true })
493
+ .description("List registered hq core commands as JSON")
494
+ .option("--json", "Print the command catalog as JSON")
495
+ .action((options) => {
496
+ if (!options.json) {
497
+ throw expectedUserError("Usage: hq core commands --json");
498
+ }
499
+ process.stdout.write(`${JSON.stringify(registeredCoreCommandListing(core))}\n`);
500
+ });
501
+ describeCoreCommand(commands, { execution: "native", root: "cwd" });
498
502
  return core;
499
503
  }
500
504
  //# sourceMappingURL=core.js.map
@@ -16,7 +16,6 @@
16
16
  import type { Command } from "commander";
17
17
  import { type LegacyUnit } from "../lib/daemon/legacy.js";
18
18
  import type { HostApp } from "../lib/daemon/supervisor.js";
19
- import { type SyncModeVaultClient } from "./sync-mode.js";
20
19
  import type { RunCommand } from "../lib/service-manager/launchd.js";
21
20
  export interface DaemonCommandDeps {
22
21
  env: NodeJS.ProcessEnv;
@@ -39,8 +38,6 @@ export interface DaemonCommandDeps {
39
38
  userHome: (user: string) => string;
40
39
  /** The pid is a live `hq daemon run`. */
41
40
  daemonAlive: (pid: number) => boolean;
42
- /** Test seam for the company sync-mode commands. */
43
- syncModeClient?: () => Promise<SyncModeVaultClient>;
44
41
  windowsUser?: string;
45
42
  windowsHeadlessLauncher?: string;
46
43
  systemUnitDir?: string;