@indigoai-us/hq-cli 5.293.0 → 5.295.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 (97) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/assets/scaffold/core/scripts/outpost-jobs-reconcile.sh +5 -1
  3. package/dist/command-catalog.generated.d.ts +54 -33
  4. package/dist/command-catalog.generated.js +68 -42
  5. package/dist/commands/auth.d.ts +1 -0
  6. package/dist/commands/auth.js +76 -1
  7. package/dist/commands/core-command-catalog.js +3 -2
  8. package/dist/commands/core-delegate-w1b.d.ts +2 -0
  9. package/dist/commands/core-delegate-w1b.js +28 -2
  10. package/dist/commands/core-delegate.d.ts +3 -1
  11. package/dist/commands/core-delegate.js +35 -5
  12. package/dist/commands/core-handoff-fast.d.ts +18 -0
  13. package/dist/commands/core-handoff-fast.js +103 -0
  14. package/dist/commands/core-handoff-open-steps.d.ts +21 -0
  15. package/dist/commands/core-handoff-open-steps.js +264 -0
  16. package/dist/commands/core-handoff.d.ts +4 -2
  17. package/dist/commands/core-handoff.js +22 -249
  18. package/dist/commands/core-jobs-native.d.ts +2 -0
  19. package/dist/commands/core-jobs-native.js +22 -11
  20. package/dist/commands/core-knowledge-prefs.d.ts +2 -0
  21. package/dist/commands/core-knowledge-prefs.js +13 -1
  22. package/dist/commands/core-ontology-native.d.ts +2 -0
  23. package/dist/commands/core-ontology-native.js +22 -2
  24. package/dist/commands/core-policy.d.ts +2 -0
  25. package/dist/commands/core-policy.js +18 -1
  26. package/dist/commands/core.js +2 -1
  27. package/dist/commands/daemon.d.ts +2 -1
  28. package/dist/commands/daemon.js +22 -7
  29. package/dist/commands/doctor.js +0 -74
  30. package/dist/commands/lanes-autopilot.d.ts +11 -0
  31. package/dist/commands/lanes-autopilot.js +336 -0
  32. package/dist/commands/lanes-message.js +23 -5
  33. package/dist/commands/lanes-questions.js +8 -5
  34. package/dist/commands/lanes-resume.js +0 -3
  35. package/dist/commands/lanes-shared.d.ts +18 -2
  36. package/dist/commands/lanes-stories.d.ts +14 -0
  37. package/dist/commands/lanes-stories.js +308 -0
  38. package/dist/commands/lanes.d.ts +1 -9
  39. package/dist/commands/lanes.js +216 -481
  40. package/dist/fast-core.js +53 -25
  41. package/dist/fast-scaffold.d.ts +15 -7
  42. package/dist/fast-scaffold.js +167 -17
  43. package/dist/index.js +1 -10
  44. package/dist/lib/core-utils/sentry-report.d.ts +0 -19
  45. package/dist/lib/core-utils/sentry-report.js +8 -61
  46. package/dist/lib/core-utils/worktree-resume.d.ts +2 -0
  47. package/dist/lib/core-utils/worktree-resume.js +16 -0
  48. package/dist/lib/daemon/migrate.d.ts +8 -1
  49. package/dist/lib/daemon/migrate.js +19 -7
  50. package/dist/lib/doctor/checks/claude-wiring.js +9 -0
  51. package/dist/lib/lanes/autopilot-metrics.d.ts +99 -0
  52. package/dist/lib/lanes/autopilot-metrics.js +301 -0
  53. package/dist/lib/lanes/flag-keys.d.ts +2 -0
  54. package/dist/lib/lanes/flag-keys.js +2 -0
  55. package/dist/lib/lanes/manager-status-gate.d.ts +0 -17
  56. package/dist/lib/lanes/manager-status-gate.js +2 -43
  57. package/dist/lib/lanes/outpost-dispatch.d.ts +2 -0
  58. package/dist/lib/lanes/outpost-dispatch.js +7 -1
  59. package/dist/lib/lanes/outpost-hire-cache.d.ts +0 -1
  60. package/dist/lib/lanes/outpost-hire-cache.js +0 -1
  61. package/dist/lib/lanes/outpost-snapshot-memo.d.ts +6 -0
  62. package/dist/lib/lanes/outpost-snapshot-memo.js +14 -0
  63. package/dist/lib/lanes/reconcile.d.ts +2 -3
  64. package/dist/lib/lanes/reconcile.js +44 -38
  65. package/dist/lib/lanes/spawn.d.ts +0 -2
  66. package/dist/lib/lanes/spawn.js +18 -5
  67. package/dist/lib/lanes/store.d.ts +2 -0
  68. package/dist/lib/lanes/store.js +54 -3
  69. package/dist/lib/lanes/types.d.ts +18 -1
  70. package/dist/lib/lanes/types.js +1 -1
  71. package/dist/lib/lanes/watcher.d.ts +4 -3
  72. package/dist/lib/lanes/watcher.js +102 -34
  73. package/dist/lib/mesh/live/daemon/run.js +18 -1
  74. package/dist/native-fast-route.d.ts +3 -1
  75. package/dist/native-fast-route.js +10 -8
  76. package/dist/utils/cognito-session.d.ts +6 -0
  77. package/dist/utils/cognito-session.js +9 -0
  78. package/dist/utils/contribution-table.d.ts +1 -1
  79. package/dist/utils/fast-stream-errors.d.ts +12 -0
  80. package/dist/utils/fast-stream-errors.js +18 -0
  81. package/dist/utils/scaffold-fast-import-guard.d.ts +2 -2
  82. package/dist/utils/scaffold-fast-import-guard.js +6 -3
  83. package/dist/utils/self-update.js +31 -0
  84. package/dist/utils/version-gate.js +22 -3
  85. package/package.json +1 -1
  86. package/dist/fast-lanes-list-route.d.ts +0 -8
  87. package/dist/fast-lanes-list-route.js +0 -32
  88. package/dist/fast-lanes-list.d.ts +0 -3
  89. package/dist/fast-lanes-list.js +0 -224
  90. package/dist/lib/doctor/client-health-sentry-flag.d.ts +0 -23
  91. package/dist/lib/doctor/client-health-sentry-flag.js +0 -99
  92. package/dist/lib/doctor/client-health-sentry.d.ts +0 -71
  93. package/dist/lib/doctor/client-health-sentry.js +0 -286
  94. package/dist/lib/lanes/outpost-snapshot-cache.d.ts +0 -26
  95. package/dist/lib/lanes/outpost-snapshot-cache.js +0 -215
  96. package/dist/lib/lanes/outpost-snapshot-refresh.d.ts +0 -21
  97. package/dist/lib/lanes/outpost-snapshot-refresh.js +0 -329
@@ -5,7 +5,6 @@ import * as os from "node:os";
5
5
  import * as path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { archiveOldThreads } from "../lib/core-utils/archive-old-threads.js";
8
- import { serializeJqJson } from "../lib/core-utils/jq-json-serializer.js";
9
8
  import { summarizeHqStatus } from "../lib/core-utils/hq-status-summary.js";
10
9
  import { enqueueSessionEvent } from "../lib/mesh/live/enqueue.js";
11
10
  import { renderIndexTarget } from "../lib/index-render/index.js";
@@ -13,7 +12,8 @@ import { defaultBackgroundDependencies, runBackgroundLauncher, } from "../lib/se
13
12
  import { resolveLiveRoot } from "../utils/hq-roots.js";
14
13
  import { runBundledScript } from "../utils/run-bundled-script.js";
15
14
  import { describeCoreCommand } from "./core-command-catalog.js";
16
- import { coreNativeHandoffEnabled } from "./core-native-handoff-flag.js";
15
+ import { compactJson, isRecord, jqTruthy, prettyJson, runHandoffOpenSteps, shellDate, } from "./core-handoff-open-steps.js";
16
+ export { runHandoffOpenSteps };
17
17
  const ASSETS = {
18
18
  finalize: "core/scripts/handoff-finalize.sh",
19
19
  post: "core/scripts/handoff-post.sh",
@@ -24,28 +24,6 @@ const DESCRIPTIONS = {
24
24
  post: "Run best-effort post-handoff maintenance",
25
25
  openSteps: "List and update open handoff steps",
26
26
  };
27
- const OPEN_STEPS_UNKNOWN_USAGE = `# hq-core: public
28
- # handoff-open-steps.sh — list and close next steps across handoff threads
29
- # (2026-09-07).
30
- #
31
- # Handoff threads record next_steps; since 2026-09-07 each carries an \x60id\x60
32
- # (\x60<thread_id>#<n>\x60) and a \x60status\x60 (open|done|dropped). This script is the
33
- # closure side: /startwork and /resumework list what is still open instead of
34
- # re-copying it forward, and a session closes a step when it is actually done.
35
- #
36
- # Usage:
37
- # handoff-open-steps.sh list [--limit N] [--company <slug>] [--json]
38
- # handoff-open-steps.sh close <step-id> [--as done|dropped] [--note "<why>"]
39
- # handoff-open-steps.sh reopen <step-id>
40
- #
41
- # Threads live in workspace/threads/T-*.json (and archive/**). Closing edits
42
- # the step in place inside its thread file (only \x60status\x60, \x60closed_at\x60,
43
- # \x60closed_by\x60, \x60note\x60) and bumps \x60updated_at\x60; nothing else in the thread is
44
- # touched. Legacy steps without an id are listed with a synthetic id and can be
45
- # closed the same way (the id is written on first close).
46
- set -uo pipefail
47
- HQ_ROOT="\${HQ_ROOT:-\${CLAUDE_PROJECT_DIR:-$(cd "$(dirname "\${BASH_SOURCE[0]}")/../.." && pwd)}}"
48
- `;
49
27
  const SESSION_ID_ENV_KEYS = [
50
28
  "HQ_SESSION_ID",
51
29
  "CLAUDE_CODE_SESSION_ID",
@@ -173,18 +151,6 @@ function copyClipboardText(value, cwd) {
173
151
  return false;
174
152
  }
175
153
  }
176
- function prettyJson(value) {
177
- return serializeJqJson(value, "pretty");
178
- }
179
- function compactJson(value) {
180
- return serializeJqJson(value, "compact");
181
- }
182
- function isRecord(value) {
183
- return value !== null && typeof value === "object" && !Array.isArray(value);
184
- }
185
- function jqTruthy(value) {
186
- return value !== undefined && value !== null && value !== false;
187
- }
188
154
  function mkdirParent(file) {
189
155
  fs.mkdirSync(path.dirname(file), { recursive: true });
190
156
  }
@@ -194,219 +160,6 @@ function writeAtomic(file, text, mode) {
194
160
  fs.writeFileSync(temporary, text, mode === undefined ? undefined : { mode });
195
161
  fs.renameSync(temporary, file);
196
162
  }
197
- function listFiles(root, predicate) {
198
- const found = [];
199
- const visit = (directory) => {
200
- let entries;
201
- try {
202
- entries = fs.readdirSync(directory, { withFileTypes: true });
203
- }
204
- catch {
205
- return;
206
- }
207
- for (const entry of entries) {
208
- const file = path.join(directory, entry.name);
209
- if (entry.isDirectory())
210
- visit(file);
211
- else if (entry.isFile() && predicate(file, entry))
212
- found.push(file);
213
- }
214
- };
215
- visit(root);
216
- return found;
217
- }
218
- function sortThreadFilesNewest(files) {
219
- return files.sort((left, right) => {
220
- const leftMtime = Math.floor(fs.statSync(left).mtimeMs / 1000);
221
- const rightMtime = Math.floor(fs.statSync(right).mtimeMs / 1000);
222
- if (leftMtime !== rightMtime)
223
- return rightMtime - leftMtime;
224
- // GNU sort -rn falls back to reverse lexical order for equal numeric keys.
225
- return right.localeCompare(left);
226
- });
227
- }
228
- function normalizedSteps(file, value) {
229
- if (!isRecord(value))
230
- return undefined;
231
- const steps = value.next_steps ?? [];
232
- if (!Array.isArray(steps))
233
- return undefined;
234
- const basename = path.basename(file).replace(/\.json$/, "");
235
- const normalized = [];
236
- for (let index = 0; index < steps.length; index += 1) {
237
- const raw = steps[index];
238
- if (typeof raw !== "string" && !isRecord(raw))
239
- return undefined;
240
- const step = typeof raw === "string" ? { step: raw } : { ...raw };
241
- if (!jqTruthy(step.id))
242
- step.id = `${basename}#${index + 1}`;
243
- if (!jqTruthy(step.status))
244
- step.status = "open";
245
- delete step.key;
246
- normalized.push(step);
247
- }
248
- return normalized;
249
- }
250
- function parseJson(file) {
251
- return JSON.parse(fs.readFileSync(file, "utf8"));
252
- }
253
- function shellDate(date) {
254
- return date.toISOString().replace(/\.\d{3}Z$/, "Z");
255
- }
256
- export function runHandoffOpenSteps(args, context) {
257
- const root = context.root;
258
- const threads = path.join(root, "workspace/threads");
259
- const argv = [...args];
260
- const command = argv[0] || "list";
261
- if (argv.length > 0)
262
- argv.shift();
263
- if (command === "list") {
264
- let limitText = "20";
265
- let company = "";
266
- let json = false;
267
- for (let index = 0; index < argv.length;) {
268
- const token = argv[index];
269
- if (token === "--limit") {
270
- limitText = argv[index + 1] ?? "";
271
- index += 2;
272
- }
273
- else if (token === "--company") {
274
- company = argv[index + 1] ?? "";
275
- index += 2;
276
- }
277
- else if (token === "--json") {
278
- json = true;
279
- index += 1;
280
- }
281
- else
282
- index += 1;
283
- }
284
- const numericLimit = /^-?\d+$/.test(limitText) ? Number(limitText) : Number.NaN;
285
- const candidates = sortThreadFilesNewest(listFiles(threads, (file) => {
286
- const name = path.basename(file);
287
- return /^T-.*\.json$/.test(name) && !name.endsWith(".changeset.json") && !file.split(path.sep).includes("resume-locks");
288
- }));
289
- let count = 0;
290
- const rows = [];
291
- for (const file of candidates) {
292
- if (!Number.isNaN(numericLimit) && count >= numericLimit)
293
- break;
294
- count += 1;
295
- let thread;
296
- let nextSteps;
297
- try {
298
- thread = parseJson(file);
299
- nextSteps = normalizedSteps(file, thread);
300
- }
301
- catch {
302
- continue;
303
- }
304
- if (!nextSteps || !isRecord(thread))
305
- continue;
306
- if (company) {
307
- const companies = (isRecord(thread.metadata) ? thread.metadata.company : undefined) ?? [];
308
- const contains = Array.isArray(companies)
309
- ? companies.includes(company)
310
- : typeof companies === "string" && companies.includes(company);
311
- if (!contains)
312
- continue;
313
- }
314
- for (const step of nextSteps) {
315
- if (step.status !== "open")
316
- continue;
317
- rows.push({
318
- thread: thread.thread_id,
319
- title: (isRecord(thread.metadata) ? thread.metadata.title : undefined) ?? "",
320
- created: thread.created_at,
321
- id: step.id,
322
- step: step.step ?? null,
323
- });
324
- }
325
- }
326
- if (json)
327
- return { code: 0, stdout: prettyJson(rows), stderr: "" };
328
- if (rows.length === 0)
329
- return { code: 0, stdout: `No open handoff steps in the last ${count} thread(s).\n`, stderr: "" };
330
- const jqString = (value) => value === null || value === undefined
331
- ? "null"
332
- : typeof value === "string" ? value : compactJson(value).trimEnd();
333
- const output = rows.map((row) => `${jqString(row.id)} ${jqString(row.step)} [${jqString(row.title)}]\n`).join("");
334
- return { code: 0, stdout: output, stderr: "" };
335
- }
336
- if (command === "close" || command === "reopen") {
337
- const id = argv[0] ?? "";
338
- const rest = argv.slice(1);
339
- if (!id)
340
- return { code: 2, stdout: "", stderr: `usage: ${command} <step-id>\n` };
341
- let as = "done";
342
- let note = "";
343
- for (let index = 0; index < rest.length;) {
344
- if (rest[index] === "--as") {
345
- as = rest[index + 1] ?? "";
346
- index += 2;
347
- }
348
- else if (rest[index] === "--note") {
349
- note = rest[index + 1] ?? "";
350
- index += 2;
351
- }
352
- else
353
- index += 1;
354
- }
355
- if (command === "reopen")
356
- as = "open";
357
- if (!new Set(["done", "dropped", "open"]).has(as))
358
- return { code: 2, stdout: "", stderr: "--as must be done|dropped\n" };
359
- const threadId = id.split("#", 1)[0] ?? "";
360
- const candidates = listFiles(threads, (file) => path.basename(file) === `${threadId}.json` && !file.split(path.sep).includes("resume-locks"));
361
- const file = candidates[0];
362
- if (!file)
363
- return { code: 3, stdout: "", stderr: `handoff-open-steps: thread ${threadId} not found under ${threads}\n` };
364
- const now = shellDate(nowFor(context));
365
- const by = process.env.HQ_SESSION_ID || process.env.CLAUDE_SESSION_ID || "unknown-session";
366
- let text;
367
- try {
368
- const thread = parseJson(file);
369
- const steps = normalizedSteps(file, thread);
370
- if (!steps || !isRecord(thread))
371
- throw new Error("Cannot iterate over null (null)");
372
- if (!steps.some((step) => step.id === id))
373
- throw new Error(`step ${id} not in thread`);
374
- const updated = steps.map((step) => {
375
- if (step.id !== id)
376
- return step;
377
- if (as === "open") {
378
- delete step.closed_at;
379
- delete step.closed_by;
380
- step.status = "open";
381
- }
382
- else {
383
- step.status = as;
384
- step.closed_at = now;
385
- step.closed_by = by;
386
- if (note !== "")
387
- step.note = note;
388
- }
389
- return step;
390
- });
391
- thread.next_steps = updated;
392
- thread.updated_at = now;
393
- text = prettyJson(thread);
394
- }
395
- catch (error) {
396
- const message = error instanceof Error ? error.message : String(error);
397
- const jqMessage = message.startsWith("step ")
398
- ? `jq: error (at <stdin>:1): ${message}`
399
- : `jq: error: ${message}`;
400
- return { code: 3, stdout: "", stderr: `${jqMessage}\n` };
401
- }
402
- // jq > file.tmp followed by mv uses the caller's umask for this new inode.
403
- const temporary = `${file}.tmp`;
404
- fs.writeFileSync(temporary, text);
405
- fs.renameSync(temporary, file);
406
- return { code: 0, stdout: `handoff-open-steps: ${id} -> ${as}\n`, stderr: "" };
407
- }
408
- return { code: 2, stdout: OPEN_STEPS_UNKNOWN_USAGE, stderr: "" };
409
- }
410
163
  function isSensitivePath(value) {
411
164
  const exceptions = new Set(["core/settings/.gitkeep", "core/settings/pure-ralph.json"]);
412
165
  if (exceptions.has(value))
@@ -1331,6 +1084,25 @@ function emitResult(result) {
1331
1084
  if (result.code !== 0)
1332
1085
  process.exit(result.code);
1333
1086
  }
1087
+ /** Fast-entry adapter; the shared family flag is resolved before this module loads. */
1088
+ export async function runHandoffFast(args, _stdin, _cwd, hqRoot, commandName) {
1089
+ const liveRoot = hqRoot ?? resolveLiveRoot();
1090
+ const context = { root: liveRoot, cwd: liveRoot };
1091
+ const result = await withRootEnvironment(liveRoot, () => {
1092
+ if (commandName === "finalize")
1093
+ return runHandoffFinalize([...args], context);
1094
+ if (commandName === "post")
1095
+ return runHandoffPost([...args], context);
1096
+ return runHandoffOpenSteps([...args], context);
1097
+ });
1098
+ if (result.stdout)
1099
+ process.stdout.write(result.stdout);
1100
+ if (result.stderr)
1101
+ process.stderr.write(result.stderr);
1102
+ if (result.code !== 0)
1103
+ process.exitCode = result.code;
1104
+ return result.code;
1105
+ }
1334
1106
  /** Register native handoff commands behind the shared default-off flag. */
1335
1107
  export function registerCoreHandoffCommand(core) {
1336
1108
  const handoff = core.command("handoff").description("Handoff session helpers");
@@ -1346,6 +1118,7 @@ export function registerCoreHandoffCommand(core) {
1346
1118
  const scope = core.opts();
1347
1119
  const root = resolveLiveRoot({ hqRoot: scope.hqRoot });
1348
1120
  const operands = cmd.args.length > 0 ? cmd.args : args;
1121
+ const { coreNativeHandoffEnabled } = await import("./core-native-handoff-flag.js");
1349
1122
  if (!await coreNativeHandoffEnabled()) {
1350
1123
  const bundled = runBundledScript({ asset: ASSETS[name === "open-steps" ? "openSteps" : name], args: operands, cwd: root, hqRoot: root });
1351
1124
  if (bundled.code !== 0)
@@ -19,5 +19,7 @@ export type ReconcileOptions = {
19
19
  export declare function runReconcile(argv: string[], rootArg?: string, options?: ReconcileOptions): Promise<number>;
20
20
  export declare function registerCoreJobsNativeCommand(core: Command): void;
21
21
  export declare function rawArgumentsForCommand(command: Command, fallback: string[], raw?: string[]): string[];
22
+ /** Fast-entry adapter; the shared family flag is resolved before this module loads. */
23
+ export declare function runJobsFast(args: readonly string[], _stdin: string, _cwd: string, _liveRoot: string | undefined, commandName: string, hqRootArg: string | undefined): Promise<number>;
22
24
  export {};
23
25
  //# sourceMappingURL=core-jobs-native.d.ts.map
@@ -7,7 +7,6 @@ import { serializeJqJson } from "../lib/core-utils/jq-json-serializer.js";
7
7
  import { resolveLiveRoot } from "../utils/hq-roots.js";
8
8
  import { runBundledScript } from "../utils/run-bundled-script.js";
9
9
  import { describeCoreCommand } from "./core-command-catalog.js";
10
- import { coreNativeJobsEnabled } from "./core-native-jobs-flag.js";
11
10
  const SCHEDULE_PARSE_ASSET = "core/scripts/jobs-schedule-parse.sh";
12
11
  const VALIDATE_ASSET = "core/scripts/jobs-validate.sh";
13
12
  const RECONCILE_ASSET = "core/scripts/outpost-jobs-reconcile.sh";
@@ -518,23 +517,26 @@ function collectJobFiles(args, emit) {
518
517
  const stat = fs.statSync(argument);
519
518
  if (stat.isFile()) {
520
519
  if (/\.(yaml|yml)$/.test(argument))
521
- files.push(argument);
520
+ files.push({ diskPath: argument, displayPath: argument });
522
521
  else
523
522
  emit(argument, "path", "not a .yaml/.yml job file");
524
523
  return;
525
524
  }
526
525
  if (stat.isDirectory()) {
527
- const walk = (directory) => {
526
+ const strippedArgument = argument.replace(/\/+$/, "") || path.parse(argument).root;
527
+ const walk = (directory, displayDirectory) => {
528
528
  const entries = fs.readdirSync(directory, { withFileTypes: true });
529
529
  for (const entry of entries) {
530
530
  const file = path.join(directory, entry.name);
531
+ const displayFile = `${displayDirectory.replace(/\/$/, "")}/${entry.name}`;
531
532
  if (entry.isDirectory())
532
- walk(file);
533
- else if (entry.isFile() && /\.(yaml|yml)$/.test(entry.name))
534
- files.push(file);
533
+ walk(file, displayFile);
534
+ else if (entry.isFile() && /\.(yaml|yml)$/.test(entry.name)) {
535
+ files.push({ diskPath: file, displayPath: displayFile });
536
+ }
535
537
  }
536
538
  };
537
- walk(argument);
539
+ walk(argument, strippedArgument);
538
540
  return;
539
541
  }
540
542
  emit(argument, "path", "file or directory not found");
@@ -559,19 +561,19 @@ export function validateJobs(args) {
559
561
  errors.push(`jobs-validate: ${file}: ${field}: ${message}`);
560
562
  };
561
563
  const seenIds = [];
562
- const files = collectJobFiles(args, emit).sort(comparePathsLikeSort);
564
+ const files = collectJobFiles(args, emit).sort((left, right) => comparePathsLikeSort(left.diskPath, right.diskPath));
563
565
  if (!files.length) {
564
566
  for (const error of errors)
565
567
  process.stderr.write(`${error}\n`);
566
568
  process.stderr.write("jobs-validate: no job YAML files found\n");
567
569
  return 1;
568
570
  }
569
- for (const file of files) {
571
+ for (const { diskPath, displayPath } of files) {
570
572
  try {
571
- validateJob(file, parseJobFile(fs.readFileSync(file, "utf8")), seenIds, emit);
573
+ validateJob(displayPath, parseJobFile(fs.readFileSync(diskPath, "utf8")), seenIds, emit);
572
574
  }
573
575
  catch {
574
- emit(file, "yaml", "failed to parse YAML");
576
+ emit(displayPath, "yaml", "failed to parse YAML");
575
577
  }
576
578
  }
577
579
  for (const error of errors)
@@ -1292,6 +1294,7 @@ export function registerCoreJobsNativeCommand(core) {
1292
1294
  .action(async (args, _options, current) => {
1293
1295
  const argv = rawArgumentsForCommand(current, args);
1294
1296
  const groupHqRoot = core.opts().hqRoot;
1297
+ const { coreNativeJobsEnabled } = await import("./core-native-jobs-flag.js");
1295
1298
  if (!await coreNativeJobsEnabled()) {
1296
1299
  const hqRoot = asset === RECONCILE_ASSET && !argv.includes("--hq-root")
1297
1300
  && !argv.includes("--help") && !argv.includes("-h")
@@ -1328,4 +1331,12 @@ export function rawArgumentsForCommand(command, fallback, raw = process.argv) {
1328
1331
  }
1329
1332
  return start >= 0 ? raw.slice(start) : (command.args.length ? command.args : fallback);
1330
1333
  }
1334
+ /** Fast-entry adapter; the shared family flag is resolved before this module loads. */
1335
+ export async function runJobsFast(args, _stdin, _cwd, _liveRoot, commandName, hqRootArg) {
1336
+ if (commandName === "schedule-parse")
1337
+ return runScheduleParse([...args]);
1338
+ if (commandName === "validate")
1339
+ return validateJobs([...args]);
1340
+ return runReconcile([...args], hqRootArg ?? process.env.HQ_ROOT);
1341
+ }
1331
1342
  //# sourceMappingURL=core-jobs-native.js.map
@@ -6,5 +6,7 @@ export type CoreCommandResult = {
6
6
  stderr: string;
7
7
  };
8
8
  export declare function runKnowledgePrefs(args: readonly string[], root: string): CoreCommandResult;
9
+ /** Fast-entry adapter; family gating and shell fallback happen before import. */
10
+ export declare function runKnowledgePrefsFast(args: readonly string[], _stdin: string, _cwd: string, hqRoot: string | undefined): number;
9
11
  export declare function registerCoreKnowledgePrefsCommand(core: Command): void;
10
12
  //# sourceMappingURL=core-knowledge-prefs.d.ts.map
@@ -9,7 +9,6 @@ import * as path from 'node:path';
9
9
  import { resolveLiveRoot } from '../utils/hq-roots.js';
10
10
  import { runBundledScript } from '../utils/run-bundled-script.js';
11
11
  import { describeCoreCommand } from './core-command-catalog.js';
12
- import { coreNativePolicyEnabled } from './core-native-policy-flag.js';
13
12
  export const KNOWLEDGE_PREFS_ASSET = 'core/scripts/knowledge-prefs.sh';
14
13
  const DEFAULTS = {
15
14
  signals_enabled: 'true',
@@ -84,6 +83,18 @@ export function runKnowledgePrefs(args, root) {
84
83
  stderr: '',
85
84
  };
86
85
  }
86
+ /** Fast-entry adapter; family gating and shell fallback happen before import. */
87
+ export function runKnowledgePrefsFast(args, _stdin, _cwd, hqRoot) {
88
+ const root = hqRoot ?? resolveLiveRoot();
89
+ const result = runKnowledgePrefs(args, root);
90
+ if (result.stdout)
91
+ process.stdout.write(result.stdout);
92
+ if (result.stderr)
93
+ process.stderr.write(result.stderr);
94
+ if (result.code !== 0)
95
+ process.exitCode = result.code;
96
+ return result.code;
97
+ }
87
98
  export function registerCoreKnowledgePrefsCommand(core) {
88
99
  const command = core
89
100
  .command('knowledge-prefs')
@@ -97,6 +108,7 @@ export function registerCoreKnowledgePrefsCommand(core) {
97
108
  const hqRoot = resolveLiveRoot({
98
109
  hqRoot: core.opts().hqRoot,
99
110
  });
111
+ const { coreNativePolicyEnabled } = await import('./core-native-policy-flag.js');
100
112
  if (!await coreNativePolicyEnabled()) {
101
113
  const result = runBundledScript({
102
114
  asset: KNOWLEDGE_PREFS_ASSET,
@@ -5,6 +5,8 @@ export interface ScriptResult {
5
5
  stdout: string;
6
6
  stderr: string;
7
7
  }
8
+ /** Fast-entry adapter; family gating and shell fallback happen before import. */
9
+ export declare function runOntologyNativeFast(args: readonly string[], _stdin: string, cwd: string, hqRoot: string | undefined, commandName: string): number;
8
10
  export declare function sourceYamlValidate(file: string | undefined): ScriptResult;
9
11
  export declare function candidateCommand(args: string[], root: string): ScriptResult;
10
12
  export declare function briefCommand(args: string[], defaultRoot: string): ScriptResult;
@@ -3,7 +3,6 @@ import { createHash } from "node:crypto";
3
3
  import { spawnSync } from "node:child_process";
4
4
  import * as fs from "node:fs";
5
5
  import * as path from "node:path";
6
- import { resolveProcessFlagGate } from "../lib/flag-registry.js";
7
6
  import { runBundledScript } from "../utils/run-bundled-script.js";
8
7
  import { resolveBundledAsset } from "../utils/hq-roots.js";
9
8
  import { describeCoreCommand } from "./core-command-catalog.js";
@@ -34,6 +33,26 @@ function writeResult(result) {
34
33
  process.stderr.write(result.stderr);
35
34
  process.exitCode = result.code;
36
35
  }
36
+ /** Fast-entry adapter; family gating and shell fallback happen before import. */
37
+ export function runOntologyNativeFast(args, _stdin, cwd, hqRoot, commandName) {
38
+ const operands = [...args];
39
+ const root = commandName === "source-yaml-validate" ? cwd : hqRoot ?? cwd;
40
+ let result;
41
+ if (commandName === "audience-grant")
42
+ result = audienceGrant(operands, root);
43
+ else if (commandName === "brief")
44
+ result = briefCommand(operands, root);
45
+ else if (commandName === "candidate")
46
+ result = candidateCommand(operands, root);
47
+ else if (commandName === "garden")
48
+ result = gardenCommand(operands, root);
49
+ else if (commandName === "source-worklist")
50
+ result = worklistCommand(operands, root);
51
+ else
52
+ result = sourceYamlValidate(operands[0]);
53
+ writeResult(result);
54
+ return result.code;
55
+ }
37
56
  function runHq(args, output = "capture") {
38
57
  const executable = process.env.HQ_BIN || "hq";
39
58
  const result = spawnSync(executable, args, {
@@ -869,7 +888,7 @@ export function registerCoreOntologyNativeCommands(ontology, rootFor) {
869
888
  .allowExcessArguments()
870
889
  .helpOption(false)
871
890
  .argument("[args...]", "arguments accepted for shell ABI compatibility")
872
- .action((args = [], _options, commandContext) => {
891
+ .action(async (args = [], _options, commandContext) => {
873
892
  const argv = process.argv.slice(2);
874
893
  const coreIndex = argv.indexOf("core");
875
894
  const ontologyIndex = argv.indexOf("ontology", coreIndex + 1);
@@ -877,6 +896,7 @@ export function registerCoreOntologyNativeCommands(ontology, rootFor) {
877
896
  const forwarded = commandIndex >= 0 ? argv.slice(commandIndex + 1)
878
897
  : commandContext.args.length > 0 ? commandContext.args : args;
879
898
  const liveRoot = entry.root === "live" ? rootFor() : process.cwd();
899
+ const { resolveProcessFlagGate } = await import("../lib/flag-registry.js");
880
900
  if (!resolveProcessFlagGate(FLAG, { fallback: false }, () => false)) {
881
901
  const result = runBundledScript({
882
902
  asset: `${ASSET}${entry.asset}`,
@@ -11,5 +11,7 @@ export type CorePolicyResult = {
11
11
  export declare function runPolicyAgeReport(args: readonly string[], root: string, env?: NodeJS.ProcessEnv, nowEpoch?: number): CorePolicyResult;
12
12
  export declare function runPolicyFrontmatter(args: readonly string[], cwd: string): FrontmatterResult;
13
13
  export declare function runPolicyRetire(args: readonly string[], root: string, cwd: string, env?: NodeJS.ProcessEnv, now?: Date): CorePolicyResult;
14
+ /** Fast-entry adapter; family gating and shell fallback happen before import. */
15
+ export declare function runPolicyFast(args: readonly string[], _stdin: string, cwd: string, hqRoot: string | undefined, commandName: string): number;
14
16
  export declare function registerCorePolicyCommand(core: Command): void;
15
17
  //# sourceMappingURL=core-policy.d.ts.map
@@ -7,7 +7,6 @@ import { policyValidatorDiagnostic } from '../lib/policy-validator.js';
7
7
  import { resolveLiveRoot, resolveBundledAsset } from '../utils/hq-roots.js';
8
8
  import { runBundledScript } from '../utils/run-bundled-script.js';
9
9
  import { describeCoreCommand } from './core-command-catalog.js';
10
- import { coreNativePolicyEnabled } from './core-native-policy-flag.js';
11
10
  import { runPolicyFrontmatter as runPolicyFrontmatterImpl } from './core-policy-frontmatter.js';
12
11
  export const POLICY_AGE_REPORT_ASSET = 'core/scripts/policy-age-report.sh';
13
12
  export const POLICY_RETIRE_ASSET = 'core/scripts/policy-retire.sh';
@@ -947,6 +946,21 @@ function writeResult(result) {
947
946
  if (result.code !== 0)
948
947
  process.exitCode = result.code;
949
948
  }
949
+ /** Fast-entry adapter; family gating and shell fallback happen before import. */
950
+ export function runPolicyFast(args, _stdin, cwd, hqRoot, commandName) {
951
+ let result;
952
+ if (commandName === "frontmatter") {
953
+ result = runPolicyFrontmatter(args, cwd);
954
+ }
955
+ else {
956
+ const root = hqRoot ?? resolveLiveRoot();
957
+ result = commandName === "age-report"
958
+ ? runPolicyAgeReport(args, root)
959
+ : runPolicyRetire(args, root, cwd);
960
+ }
961
+ writeResult(result);
962
+ return result.code;
963
+ }
950
964
  export function registerCorePolicyCommand(core) {
951
965
  const group = core.command('policy').description('Policy maintenance commands');
952
966
  const register = (name, asset, summary, rootKind) => {
@@ -963,6 +977,7 @@ export function registerCorePolicyCommand(core) {
963
977
  const ageReport = register('age-report', POLICY_AGE_REPORT_ASSET, 'Report policy usage and retirement candidates', 'live');
964
978
  ageReport.action(async (args = [], _options, command) => {
965
979
  const operands = command.args.length > 0 ? command.args : args;
980
+ const { coreNativePolicyEnabled } = await import('./core-native-policy-flag.js');
966
981
  if (!await coreNativePolicyEnabled()) {
967
982
  const root = resolveLiveRoot({ hqRoot: core.opts().hqRoot });
968
983
  const result = runBundledScript({ asset: POLICY_AGE_REPORT_ASSET, args: operands, cwd: process.cwd(), hqRoot: root });
@@ -976,6 +991,7 @@ export function registerCorePolicyCommand(core) {
976
991
  const retire = register('retire', POLICY_RETIRE_ASSET, 'Retire or restore a policy', 'live');
977
992
  retire.action(async (args = [], _options, command) => {
978
993
  const operands = command.args.length > 0 ? command.args : args;
994
+ const { coreNativePolicyEnabled } = await import('./core-native-policy-flag.js');
979
995
  if (!await coreNativePolicyEnabled()) {
980
996
  const root = resolveLiveRoot({ hqRoot: core.opts().hqRoot });
981
997
  const result = runBundledScript({ asset: POLICY_RETIRE_ASSET, args: operands, cwd: process.cwd(), hqRoot: root });
@@ -989,6 +1005,7 @@ export function registerCorePolicyCommand(core) {
989
1005
  const frontmatter = register('frontmatter', POLICY_FRONTMATTER_ASSET, 'Extract policy frontmatter', 'cwd');
990
1006
  frontmatter.action(async (args = [], _options, command) => {
991
1007
  const operands = command.args.length > 0 ? command.args : args;
1008
+ const { coreNativePolicyEnabled } = await import('./core-native-policy-flag.js');
992
1009
  if (!await coreNativePolicyEnabled()) {
993
1010
  const result = runBundledScript({ asset: POLICY_FRONTMATTER_ASSET, args: operands, cwd: process.cwd() });
994
1011
  if (result.code !== 0)
@@ -31,6 +31,7 @@
31
31
  import { Option } from "commander";
32
32
  import { registerCoreCheckpointCommand } from "./core-checkpoint.js";
33
33
  import { registerCoreDelegateCommand } from "./core-delegate.js";
34
+ import { registerCoreDelegateW1b } from "./core-delegate-w1b.js";
34
35
  import { registerCoreHandoffCommand } from "./core-handoff.js";
35
36
  import { registerCoreOntologyCommand } from "./core-ontology.js";
36
37
  import { registerCoreKnowledgePrefsCommand } from "./core-knowledge-prefs.js";
@@ -347,7 +348,7 @@ export function registerCoreCommands(program) {
347
348
  registerCoreCheckpointCommand(core);
348
349
  registerCoreOntologyCommand(core);
349
350
  registerCoreCheckpointGateSettingCommand(core);
350
- registerCoreDelegateCommand(core);
351
+ registerCoreDelegateCommand(core, registerCoreDelegateW1b);
351
352
  registerCoreHandoffCommand(core);
352
353
  registerCoreKnowledgePrefsCommand(core);
353
354
  registerCorePolicyCommand(core);
@@ -33,7 +33,8 @@ export interface DaemonCommandDeps {
33
33
  readFile: (p: string) => string;
34
34
  /** Writes a root-owned file such as /etc/hq/machine-type, creating its folder. */
35
35
  writeFile: (p: string, text: string) => void;
36
- legacyUnits: () => LegacyUnit[];
36
+ /** Older units in `home` (default: this user's home). */
37
+ legacyUnits: (home?: string) => LegacyUnit[];
37
38
  resolveHqRoot: (flag: string | undefined) => string | undefined;
38
39
  /** Home folder of the login user a box's system unit runs as. */
39
40
  userHome: (user: string) => string;