@indigoai-us/hq-cli 5.308.0 → 5.309.1

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 (95) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/command-catalog.generated.d.ts +4 -1
  3. package/dist/command-catalog.generated.js +5 -1
  4. package/dist/commands/agents.js +6 -0
  5. package/dist/commands/core-checkpoint-gate-setting.d.ts +0 -10
  6. package/dist/commands/core-checkpoint-gate-setting.js +3 -3
  7. package/dist/commands/core-ontology.d.ts +1 -9
  8. package/dist/commands/core-ontology.js +4 -4
  9. package/dist/commands/core-policy.d.ts +0 -3
  10. package/dist/commands/core-policy.js +3 -3
  11. package/dist/commands/files.js +1 -1
  12. package/dist/commands/index-cmd.js +1 -1
  13. package/dist/commands/integrations-api.d.ts +9 -4
  14. package/dist/commands/integrations-api.js +9 -6
  15. package/dist/commands/integrations-manage.js +11 -3
  16. package/dist/commands/integrations.d.ts +8 -0
  17. package/dist/commands/integrations.js +83 -0
  18. package/dist/commands/lanes-checks.d.ts +6 -2
  19. package/dist/commands/lanes-checks.js +69 -19
  20. package/dist/commands/lanes-report.js +5 -2
  21. package/dist/commands/lanes.d.ts +0 -11
  22. package/dist/commands/lanes.js +6 -6
  23. package/dist/commands/mcp-registration.d.ts +5 -11
  24. package/dist/commands/mcp-registration.js +2 -6
  25. package/dist/lib/core-utils/sentry-report.d.ts +5 -11
  26. package/dist/lib/core-utils/sentry-report.js +2 -2
  27. package/dist/lib/db/local.d.ts +0 -5
  28. package/dist/lib/db/local.js +1 -1
  29. package/dist/lib/db/migrate.d.ts +0 -12
  30. package/dist/lib/db/migrate.js +5 -5
  31. package/dist/lib/db/sql.d.ts +0 -10
  32. package/dist/lib/db/sql.js +4 -8
  33. package/dist/lib/doctor/checks/codex-wiring.d.ts +0 -4
  34. package/dist/lib/doctor/checks/codex-wiring.js +3 -35
  35. package/dist/lib/doctor/checks/grok-wiring.js +1 -34
  36. package/dist/lib/doctor/checks/runtime-health.d.ts +0 -17
  37. package/dist/lib/doctor/checks/runtime-health.js +4 -4
  38. package/dist/lib/doctor/checks/scaffold-cli-floor.d.ts +0 -1
  39. package/dist/lib/doctor/checks/scaffold-cli-floor.js +1 -1
  40. package/dist/lib/doctor/compat.d.ts +0 -16
  41. package/dist/lib/doctor/compat.js +3 -3
  42. package/dist/lib/doctor/deep/effects.js +1 -3
  43. package/dist/lib/doctor/deep/sandbox.js +1 -3
  44. package/dist/lib/doctor/fixtures/schema.js +1 -3
  45. package/dist/lib/doctor/platform.d.ts +0 -26
  46. package/dist/lib/doctor/platform.js +5 -5
  47. package/dist/lib/doctor/shared.d.ts +8 -0
  48. package/dist/lib/doctor/shared.js +38 -0
  49. package/dist/lib/lanes/autopilot.js +125 -103
  50. package/dist/lib/monitor.d.ts +2 -6
  51. package/dist/lib/monitor.js +5 -5
  52. package/dist/lib/onboarding/errors.d.ts +2 -1
  53. package/dist/lib/onboarding/errors.js +1 -1
  54. package/dist/lib/onboarding/index.d.ts +2 -6
  55. package/dist/lib/onboarding/index.js +2 -5
  56. package/dist/lib/report-publish.d.ts +1 -10
  57. package/dist/lib/report-publish.js +3 -9
  58. package/dist/lib/search-index/embed-lock.d.ts +0 -7
  59. package/dist/lib/search-index/embed-lock.js +1 -1
  60. package/dist/lib/search-index/index.d.ts +7 -0
  61. package/dist/lib/search-index/index.js +21 -2
  62. package/dist/lib/search-index/load-gate.d.ts +0 -8
  63. package/dist/lib/search-index/load-gate.js +3 -3
  64. package/dist/lib/search-index/max-doc-bytes.d.ts +2 -3
  65. package/dist/lib/search-index/max-doc-bytes.js +1 -1
  66. package/dist/lib/search-index/qmd-exit-diagnostics.d.ts +5 -0
  67. package/dist/lib/search-index/qmd-exit-diagnostics.js +40 -0
  68. package/dist/lib/service-manager/launchd.d.ts +0 -7
  69. package/dist/lib/service-manager/launchd.js +2 -2
  70. package/dist/main.js +7 -2
  71. package/dist/startup-registration.js +9 -1
  72. package/dist/utils/client-health.d.ts +0 -4
  73. package/dist/utils/client-health.js +2 -2
  74. package/dist/utils/feedback-diagnostics.d.ts +2 -1
  75. package/dist/utils/feedback-log-bundle.d.ts +0 -25
  76. package/dist/utils/feedback-log-bundle.js +5 -5
  77. package/dist/utils/feedback-logs.d.ts +4 -38
  78. package/dist/utils/feedback-logs.js +7 -7
  79. package/dist/utils/feedback-screenshots.d.ts +0 -1
  80. package/dist/utils/feedback-screenshots.js +1 -1
  81. package/dist/utils/install-tree-torn.d.ts +19 -13
  82. package/dist/utils/install-tree-torn.js +77 -2
  83. package/dist/utils/local-files-overview.d.ts +0 -6
  84. package/dist/utils/local-files-overview.js +1 -1
  85. package/dist/utils/qmd-model-download-error.d.ts +0 -8
  86. package/dist/utils/qmd-model-download-error.js +1 -1
  87. package/dist/utils/qmd-query-document-error.d.ts +0 -6
  88. package/dist/utils/qmd-query-document-error.js +1 -1
  89. package/dist/utils/scaffold-fast-import-guard.d.ts +0 -1
  90. package/dist/utils/scaffold-fast-import-guard.js +1 -1
  91. package/dist/utils/scaffold-sibling-references.d.ts +3 -2
  92. package/dist/utils/sentry-fingerprint.js +17 -0
  93. package/dist/utils/version-gate.d.ts +4 -0
  94. package/dist/utils/version-gate.js +13 -0
  95. package/package.json +1 -1
@@ -1,7 +1,9 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
+ import { laneRunsOnHost } from "./admission.js";
3
4
  import { appendDropboxMessage } from "./dropbox.js";
4
5
  import { LanesError } from "./errors.js";
6
+ import { resolveLaneCompany } from "./lane-company.js";
5
7
  import { readLanesRegistryFlag } from "./registry-flag.js";
6
8
  import { readAllLanes } from "./store.js";
7
9
  export const LEAD_AUTOPILOT_FLAG = "lanes.lead-autopilot";
@@ -406,7 +408,7 @@ function recordOperatorEscalation(hqRoot, record) {
406
408
  async function runLeadAutopilotPassUnlocked(input) {
407
409
  const { hqRoot, host, now } = input;
408
410
  const result = { ok: true, host, evaluated: 0, sent: [], started: [], escalated: [], skipped: [] };
409
- const leads = parseRegistry(hqRoot).filter((lead) => lead.host === host || (host === "local" && lead.host === input.hostname));
411
+ const leads = parseRegistry(hqRoot);
410
412
  const lanes = readAllLanes(hqRoot);
411
413
  const byId = new Map(lanes.map((lane) => [lane.lane_id, lane]));
412
414
  const stateFile = path.join(hqRoot, "workspace", "lane-briefs", "autopilot-state.json");
@@ -417,136 +419,156 @@ async function runLeadAutopilotPassUnlocked(input) {
417
419
  result.skipped.push({ lead_lane: registered.lane, reason: "lead_lane_missing" });
418
420
  continue;
419
421
  }
420
- if (lead.company === null) {
422
+ const company = resolveLaneCompany(hqRoot, lead).company;
423
+ if (!company) {
421
424
  result.skipped.push({ lead_lane: lead.lane_id, reason: "lead_company_unresolved" });
422
425
  continue;
423
426
  }
424
427
  const registeredLocalHost = registered.host === "local" || registered.host === input.hostname;
425
- if ((registeredLocalHost && (lead.host.kind !== "local" || lead.host.id !== input.hostname)) ||
426
- (!registeredLocalHost && (lead.host.kind !== "outpost" || lead.host.id !== registered.host || input.outpostId !== registered.host))) {
428
+ const hostMatchesRegistry = registeredLocalHost
429
+ ? lead.host.kind === "local"
430
+ : lead.host.kind === "outpost" && lead.host.id === registered.host && input.outpostId === registered.host;
431
+ if (!hostMatchesRegistry ||
432
+ !laneRunsOnHost(lead, { hostname: input.hostname, outpostId: input.outpostId })) {
427
433
  result.skipped.push({ lead_lane: lead.lane_id, reason: "lead_host_mismatch" });
428
434
  continue;
429
435
  }
430
- const enabled = await (input.readFlag ?? readLanesRegistryFlag)(LEAD_AUTOPILOT_FLAG, { company: lead.company });
431
- if (!enabled) {
432
- result.skipped.push({ lead_lane: lead.lane_id, reason: "flag_off" });
433
- continue;
434
- }
435
- const status = readStatus(hqRoot, registered.status, lead.company.slug);
436
- const statusUpdatedAt = typeof status.updated_at === "string" && Number.isFinite(Date.parse(status.updated_at))
437
- ? new Date(Date.parse(status.updated_at)).toISOString()
438
- : undefined;
439
- result.evaluated += 1;
440
- const stories = projectStories(hqRoot, registered.prd, lead.company.slug, lead.project_id);
441
- const children = lanes.filter((lane) => lane.senior.kind === "lane" && lane.senior.id === lead.lane_id);
442
- const planned = planLeadAutopilotWakes({
443
- lead,
444
- children,
445
- stories,
446
- now,
447
- managerStatus: status,
448
- keepAliveResumed: input.keepAliveResumedLeads?.has(lead.lane_id) === true,
449
- });
450
436
  let stateChanged = false;
451
- const activeKeys = new Set(planned.map((wake) => `${lead.lane_id}:${wake.condition}`));
452
- for (const key of Object.keys(state.sent)) {
453
- if (key.startsWith(`${lead.lane_id}:`) && !activeKeys.has(key)) {
454
- delete state.sent[key];
455
- stateChanged = true;
437
+ try {
438
+ const enabled = await (input.readFlag ?? readLanesRegistryFlag)(LEAD_AUTOPILOT_FLAG, { company });
439
+ if (!enabled) {
440
+ result.skipped.push({ lead_lane: lead.lane_id, reason: "flag_off" });
441
+ continue;
456
442
  }
457
- }
458
- for (const wake of planned) {
459
- const key = `${lead.lane_id}:${wake.condition}`;
460
- const prior = state.sent[key];
461
- if (prior?.fingerprint === wake.fingerprint) {
462
- if (input.dryRun)
463
- continue;
464
- let current = prior;
465
- const lastWakeAt = Date.parse(prior.last_wake_at ?? prior.at);
466
- if (!Number.isFinite(lastWakeAt)) {
467
- throw new LanesError("lead_autopilot_state_invalid", `Invalid wake time for ${lead.lane_id}`, { lead_lane: lead.lane_id, story_id: wake.story_id });
468
- }
469
- if (statusUpdatedAt === undefined || prior.status_updated_at === undefined) {
470
- throw new LanesError("lead_autopilot_status_activity_unverifiable", `Cannot verify whether lead ${lead.lane_id} acted after its autopilot wake`, { lead_lane: lead.lane_id, story_id: wake.story_id });
471
- }
472
- if (!prior.acted && Date.parse(statusUpdatedAt) > Date.parse(prior.status_updated_at)) {
473
- current = { ...prior, acted: true };
474
- state.sent[key] = current;
443
+ const status = readStatus(hqRoot, registered.status, company.slug);
444
+ const statusUpdatedAt = typeof status.updated_at === "string" && Number.isFinite(Date.parse(status.updated_at))
445
+ ? new Date(Date.parse(status.updated_at)).toISOString()
446
+ : undefined;
447
+ const stories = projectStories(hqRoot, registered.prd, company.slug, lead.project_id);
448
+ const children = lanes.filter((lane) => lane.senior.kind === "lane" && lane.senior.id === lead.lane_id);
449
+ const planned = planLeadAutopilotWakes({
450
+ lead,
451
+ children,
452
+ stories,
453
+ now,
454
+ managerStatus: status,
455
+ keepAliveResumed: input.keepAliveResumedLeads?.has(lead.lane_id) === true,
456
+ });
457
+ const activeKeys = new Set(planned.map((wake) => `${lead.lane_id}:${wake.condition}`));
458
+ for (const key of Object.keys(state.sent)) {
459
+ if (key.startsWith(`${lead.lane_id}:`) && !activeKeys.has(key)) {
460
+ delete state.sent[key];
475
461
  stateChanged = true;
476
462
  }
477
- if (wake.condition === "fill_grant" && input.startWorker && !current.acted && !current.auto_started) {
478
- const firstWakeAt = Date.parse(current.at);
479
- if (!Number.isFinite(firstWakeAt)) {
480
- throw new LanesError("lead_autopilot_state_invalid", `Invalid fill-grant wake time for ${lead.lane_id}`, { lead_lane: lead.lane_id, story_id: wake.story_id });
463
+ }
464
+ for (const wake of planned) {
465
+ const key = `${lead.lane_id}:${wake.condition}`;
466
+ const prior = state.sent[key];
467
+ if (prior?.fingerprint === wake.fingerprint) {
468
+ if (input.dryRun)
469
+ continue;
470
+ let current = prior;
471
+ const lastWakeAt = Date.parse(prior.last_wake_at ?? prior.at);
472
+ if (!Number.isFinite(lastWakeAt)) {
473
+ throw new LanesError("lead_autopilot_state_invalid", `Invalid wake time for ${lead.lane_id}`, { lead_lane: lead.lane_id, story_id: wake.story_id });
474
+ }
475
+ if (statusUpdatedAt === undefined || prior.status_updated_at === undefined) {
476
+ throw new LanesError("lead_autopilot_status_activity_unverifiable", `Cannot verify whether lead ${lead.lane_id} acted after its autopilot wake`, { lead_lane: lead.lane_id, story_id: wake.story_id });
477
+ }
478
+ if (!prior.acted && Date.parse(statusUpdatedAt) > Date.parse(prior.status_updated_at)) {
479
+ current = { ...prior, acted: true };
480
+ state.sent[key] = current;
481
+ stateChanged = true;
481
482
  }
482
- if (now.getTime() - firstWakeAt >= LEAD_AUTOPILOT_FILL_DELAY_MS) {
483
- const story = stories.find((candidate) => candidate.id === wake.story_id && candidate.status === "todo");
484
- if (!story?.briefPath) {
485
- throw new LanesError("lead_autopilot_story_brief_missing", `Cannot auto-start story ${wake.story_id}: its project record has no valid brief path`, { lead_lane: lead.lane_id, story_id: wake.story_id, project_id: lead.project_id });
483
+ if (wake.condition === "fill_grant" && input.startWorker && !current.acted && !current.auto_started) {
484
+ const firstWakeAt = Date.parse(current.at);
485
+ if (!Number.isFinite(firstWakeAt)) {
486
+ throw new LanesError("lead_autopilot_state_invalid", `Invalid fill-grant wake time for ${lead.lane_id}`, { lead_lane: lead.lane_id, story_id: wake.story_id });
486
487
  }
487
- if (lead.state !== "running" && lead.state !== "queued") {
488
- current = { ...current, acted: true };
488
+ if (now.getTime() - firstWakeAt >= LEAD_AUTOPILOT_FILL_DELAY_MS) {
489
+ const story = stories.find((candidate) => candidate.id === wake.story_id && candidate.status === "todo");
490
+ if (!story?.briefPath) {
491
+ throw new LanesError("lead_autopilot_story_brief_missing", `Cannot auto-start story ${wake.story_id}: its project record has no valid brief path`, { lead_lane: lead.lane_id, story_id: wake.story_id, project_id: lead.project_id });
492
+ }
493
+ if (lead.state !== "running" && lead.state !== "queued") {
494
+ current = { ...current, acted: true };
495
+ state.sent[key] = current;
496
+ stateChanged = true;
497
+ result.skipped.push({ lead_lane: lead.lane_id, reason: "auto_start_lead_not_active" });
498
+ }
499
+ else {
500
+ const started = await input.startWorker({ lead, story });
501
+ current = { ...current, auto_started: true, worker_lane: started.lane_id };
502
+ state.sent[key] = current;
503
+ stateChanged = true;
504
+ result.started.push({ lead_lane: lead.lane_id, story_id: story.id, worker_lane: started.lane_id });
505
+ }
506
+ }
507
+ }
508
+ if (!current.acted && !current.auto_started && current.escalated_at === undefined && now.getTime() - lastWakeAt >= LEAD_AUTOPILOT_FILL_DELAY_MS) {
509
+ const wakeCount = current.wake_count ?? 1;
510
+ if (wakeCount < 2) {
511
+ appendDropboxMessage(hqRoot, lead.lane_id, {
512
+ at: now.toISOString(),
513
+ message_id: `lead-autopilot:${wake.fingerprint}:wake-2`,
514
+ kind: "system_notice",
515
+ text: wake.prompt,
516
+ });
517
+ current = { ...current, wake_count: 2, last_wake_at: now.toISOString() };
489
518
  state.sent[key] = current;
490
519
  stateChanged = true;
491
- result.skipped.push({ lead_lane: lead.lane_id, reason: "auto_start_lead_not_active" });
520
+ result.sent.push(wake);
492
521
  }
493
522
  else {
494
- const started = await input.startWorker({ lead, story });
495
- current = { ...current, auto_started: true, worker_lane: started.lane_id };
523
+ const escalation = { team: registered.team, lead_lane: lead.lane_id, condition: wake.condition, story_id: wake.story_id, at: now.toISOString(), fingerprint: wake.fingerprint };
524
+ recordOperatorEscalation(hqRoot, escalation);
525
+ current = { ...current, escalated_at: now.toISOString() };
496
526
  state.sent[key] = current;
497
527
  stateChanged = true;
498
- result.started.push({ lead_lane: lead.lane_id, story_id: story.id, worker_lane: started.lane_id });
528
+ result.escalated.push(escalation);
499
529
  }
500
530
  }
531
+ continue;
501
532
  }
502
- if (!current.acted && !current.auto_started && current.escalated_at === undefined && now.getTime() - lastWakeAt >= LEAD_AUTOPILOT_FILL_DELAY_MS) {
503
- const wakeCount = current.wake_count ?? 1;
504
- if (wakeCount < 2) {
505
- appendDropboxMessage(hqRoot, lead.lane_id, {
506
- at: now.toISOString(),
507
- message_id: `lead-autopilot:${wake.fingerprint}:wake-2`,
508
- kind: "system_notice",
509
- text: wake.prompt,
510
- });
511
- current = { ...current, wake_count: 2, last_wake_at: now.toISOString() };
512
- state.sent[key] = current;
513
- stateChanged = true;
514
- result.sent.push(wake);
515
- }
516
- else {
517
- const escalation = { team: registered.team, lead_lane: lead.lane_id, condition: wake.condition, story_id: wake.story_id, at: now.toISOString(), fingerprint: wake.fingerprint };
518
- recordOperatorEscalation(hqRoot, escalation);
519
- current = { ...current, escalated_at: now.toISOString() };
520
- state.sent[key] = current;
521
- stateChanged = true;
522
- result.escalated.push(escalation);
523
- }
533
+ if (!input.dryRun) {
534
+ appendDropboxMessage(hqRoot, lead.lane_id, {
535
+ at: now.toISOString(),
536
+ message_id: `lead-autopilot:${wake.fingerprint}`,
537
+ kind: "system_notice",
538
+ text: wake.prompt,
539
+ });
540
+ state.sent[key] = {
541
+ fingerprint: wake.fingerprint,
542
+ at: now.toISOString(),
543
+ ...(statusUpdatedAt ? { status_updated_at: statusUpdatedAt } : {}),
544
+ wake_count: 1,
545
+ last_wake_at: now.toISOString(),
546
+ };
547
+ stateChanged = true;
524
548
  }
525
- continue;
549
+ result.sent.push(wake);
526
550
  }
527
- if (!input.dryRun) {
528
- appendDropboxMessage(hqRoot, lead.lane_id, {
529
- at: now.toISOString(),
530
- message_id: `lead-autopilot:${wake.fingerprint}`,
531
- kind: "system_notice",
532
- text: wake.prompt,
533
- });
534
- state.sent[key] = {
535
- fingerprint: wake.fingerprint,
536
- at: now.toISOString(),
537
- ...(statusUpdatedAt ? { status_updated_at: statusUpdatedAt } : {}),
538
- wake_count: 1,
539
- last_wake_at: now.toISOString(),
540
- };
541
- stateChanged = true;
542
- }
543
- result.sent.push(wake);
551
+ if (!input.dryRun && stateChanged)
552
+ writeState(stateFile, state);
553
+ result.evaluated += 1;
554
+ }
555
+ catch (error) {
556
+ if (!input.dryRun && stateChanged)
557
+ writeState(stateFile, state);
558
+ if (!(error instanceof LanesError) || LEAD_AUTOPILOT_PASS_FATAL_ERRORS.has(error.error))
559
+ throw error;
560
+ result.skipped.push({ lead_lane: lead.lane_id, reason: error.error });
544
561
  }
545
- if (!input.dryRun && stateChanged)
546
- writeState(stateFile, state);
547
562
  }
548
563
  return result;
549
564
  }
565
+ // Tenant-boundary and path-safety failures stop the whole pass; other per-lead
566
+ // data errors skip only that lead.
567
+ const LEAD_AUTOPILOT_PASS_FATAL_ERRORS = new Set([
568
+ "lead_autopilot_tenant_mismatch",
569
+ "lead_autopilot_status_path_invalid",
570
+ "lead_autopilot_escalation_record_invalid",
571
+ ]);
550
572
  const LEAD_AUTOPILOT_STALE_LOCK_MAX_AGE_MS = 60 * 60_000;
551
573
  function processStartIdentity(pid) {
552
574
  try {
@@ -4,15 +4,12 @@ export declare const MONITOR_FLAG = "monitor.enabled";
4
4
  export declare const MONITOR_FLAG_DEFAULT = false;
5
5
  export declare const MONITOR_DEFAULT_TIMEOUT_MS: number;
6
6
  export declare const MONITOR_DEFAULT_CHECKIN_MS: number;
7
- export declare const MONITOR_PROMPT_CACHE_TTL_MS: number;
8
7
  export declare const MONITOR_BATCH_WINDOW_MS = 200;
9
8
  export declare const MONITOR_POLL_INTERVAL_MS = 1000;
10
9
  export declare const MONITOR_RATE_WINDOW_MS = 10000;
11
10
  /** Sustained stdout floods stop after 3 windows; the per-window cap can be overridden with HQ_MONITOR_MAX_EVENTS_PER_WINDOW. */
12
11
  export declare const MONITOR_MAX_EVENTS_PER_WINDOW = 60;
13
12
  export declare const MONITOR_MAX_FLOOD_WINDOWS = 3;
14
- export declare const MONITOR_LOCK_STALE_MS = 30000;
15
- export declare const MONITOR_MAX_TIMER_DELAY_MS = 2147000000;
16
13
  export type MonitorTarget = {
17
14
  kind: "lane";
18
15
  laneId: string;
@@ -38,7 +35,7 @@ export interface NearestMonitorRuntime {
38
35
  export interface MonitorRuntimeIdentity extends NearestMonitorRuntime {
39
36
  starttime: number;
40
37
  }
41
- export interface MonitorSessionOwner {
38
+ interface MonitorSessionOwner {
42
39
  pid: number;
43
40
  starttime: number | null;
44
41
  }
@@ -107,7 +104,6 @@ export interface MonitorCheckinResult {
107
104
  /** This guard is first in monitor start so a conflicting invocation has no side effects. */
108
105
  export declare function assertMonitorTimeoutCompatibility(persistent: boolean, timeoutProvided: boolean): void;
109
106
  export declare function parseMonitorDuration(value: string, kind: "timeout" | "checkin"): number;
110
- export declare function assertMonitorSessionId(sessionId: string): void;
111
107
  export declare function parseMonitorTarget(value: string): MonitorTarget;
112
108
  export declare function monitorTargetKey(target: MonitorTarget): string;
113
109
  export declare function detectMonitorTarget(options: DetectMonitorTargetOptions): MonitorTarget;
@@ -119,7 +115,6 @@ export declare function findNearestMonitorRuntime(options: {
119
115
  export declare function monitorSessionDir(hqRoot: string, provider: LaneProvider, sessionId: string): string;
120
116
  export declare function monitorSessionHasActiveMarkers(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
121
117
  export declare function monitorSessionHasActiveMarkerForOwner(hqRoot: string, provider: LaneProvider, sessionId: string, owner: MonitorRuntimeIdentity): boolean;
122
- export declare function monitorSessionHasInboxFile(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
123
118
  export declare function monitorSessionInboxHasEvents(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
124
119
  export declare function monitorSessionHasWork(hqRoot: string, provider: LaneProvider, sessionId: string): boolean;
125
120
  export declare function monitorDir(hqRoot: string, monitorId: string): string;
@@ -150,4 +145,5 @@ export declare function recordMonitorTargetDeliveryAtPath(activityPath: string,
150
145
  export declare function formatElapsed(ms: number): string;
151
146
  export declare function runMonitorCheckinTick(hqRoot: string, targetKey: string, deps: MonitorCheckinDeps): Promise<MonitorCheckinResult>;
152
147
  export declare function readMonitorPidLiveness(pid: number | null, starttime: number | null, readStarttime?: (pid: number) => number | null): boolean;
148
+ export {};
153
149
  //# sourceMappingURL=monitor.d.ts.map
@@ -9,15 +9,15 @@ export const MONITOR_FLAG = "monitor.enabled";
9
9
  export const MONITOR_FLAG_DEFAULT = false;
10
10
  export const MONITOR_DEFAULT_TIMEOUT_MS = 5 * 60_000;
11
11
  export const MONITOR_DEFAULT_CHECKIN_MS = 55 * 60_000;
12
- export const MONITOR_PROMPT_CACHE_TTL_MS = 60 * 60_000;
12
+ const MONITOR_PROMPT_CACHE_TTL_MS = 60 * 60_000;
13
13
  export const MONITOR_BATCH_WINDOW_MS = 200;
14
14
  export const MONITOR_POLL_INTERVAL_MS = 1_000;
15
15
  export const MONITOR_RATE_WINDOW_MS = 10_000;
16
16
  /** Sustained stdout floods stop after 3 windows; the per-window cap can be overridden with HQ_MONITOR_MAX_EVENTS_PER_WINDOW. */
17
17
  export const MONITOR_MAX_EVENTS_PER_WINDOW = 60;
18
18
  export const MONITOR_MAX_FLOOD_WINDOWS = 3;
19
- export const MONITOR_LOCK_STALE_MS = 30_000;
20
- export const MONITOR_MAX_TIMER_DELAY_MS = 2_147_000_000;
19
+ const MONITOR_LOCK_STALE_MS = 30_000;
20
+ const MONITOR_MAX_TIMER_DELAY_MS = 2_147_000_000;
21
21
  const SESSION_ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
22
22
  const SAFE_LANE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
23
23
  const RUNTIME_ENV = {
@@ -59,7 +59,7 @@ function assertLaneTargetId(laneId) {
59
59
  throw monitorError("monitor_target_invalid", `Invalid lane target ${JSON.stringify(laneId)}.`, { lane_id: laneId });
60
60
  }
61
61
  }
62
- export function assertMonitorSessionId(sessionId) {
62
+ function assertMonitorSessionId(sessionId) {
63
63
  if (!SESSION_ID_RE.test(sessionId)) {
64
64
  throw monitorError("monitor_session_id_invalid", "Session ids must contain only letters, numbers, underscores, or hyphens and be 1–128 characters long.", { session_id: sessionId });
65
65
  }
@@ -154,7 +154,7 @@ export function monitorSessionHasActiveMarkerForOwner(hqRoot, provider, sessionI
154
154
  && markerOwner.starttime === owner.starttime;
155
155
  });
156
156
  }
157
- export function monitorSessionHasInboxFile(hqRoot, provider, sessionId) {
157
+ function monitorSessionHasInboxFile(hqRoot, provider, sessionId) {
158
158
  return fs.existsSync(path.join(monitorSessionDir(hqRoot, provider, sessionId), "dropbox", "inbox.jsonl"));
159
159
  }
160
160
  export function monitorSessionInboxHasEvents(hqRoot, provider, sessionId) {
@@ -4,7 +4,7 @@
4
4
  * Each failure class maps to a distinct step in the onboarding flow,
5
5
  * making it easy for the installer to show targeted recovery hints.
6
6
  */
7
- export declare class OnboardingError extends Error {
7
+ declare class OnboardingError extends Error {
8
8
  readonly step: string;
9
9
  readonly cause?: Error | undefined;
10
10
  constructor(message: string, step: string, cause?: Error | undefined);
@@ -30,4 +30,5 @@ export declare class InviteAcceptError extends OnboardingError {
30
30
  export declare class StsVerifyError extends OnboardingError {
31
31
  constructor(message: string, cause?: Error);
32
32
  }
33
+ export {};
33
34
  //# sourceMappingURL=errors.d.ts.map
@@ -4,7 +4,7 @@
4
4
  * Each failure class maps to a distinct step in the onboarding flow,
5
5
  * making it easy for the installer to show targeted recovery hints.
6
6
  */
7
- export class OnboardingError extends Error {
7
+ class OnboardingError extends Error {
8
8
  step;
9
9
  cause;
10
10
  constructor(message, step, cause) {
@@ -7,11 +7,7 @@
7
7
  * invite/accept into create-company and join-company flows with
8
8
  * checkpoint/resume.
9
9
  */
10
- export { createCompanyFlow, joinCompanyFlow, resumeOnboarding, onboardingContract, } from "./orchestrator.js";
11
- export { readCheckpoint, writeCheckpoint, deleteCheckpoint, getCheckpointPath, isStepComplete, } from "./checkpoint.js";
12
- export { OnboardingError, PersonCreationError, CompanyCreationError, ProvisioningError, MembershipBootstrapError, FirstSyncError, InviteAcceptError, StsVerifyError, } from "./errors.js";
13
- export type { OnboardingInput, CreateCompanyInput, JoinCompanyInput, OnboardingConfig, OnboardingResult, OnboardingProgress, OnboardingStep, StepStatus, ProgressCallback, OnboardingCheckpoint, DesktopInstallerContract, HqConfig, } from "./types.js";
10
+ export { readCheckpoint } from "./checkpoint.js";
11
+ export type { OnboardingCheckpoint } from "./types.js";
14
12
  export { runOnboardCli } from "./cli/onboard.js";
15
- export type { OnboardCliOptions, OnboardCliResult } from "./cli/onboard.js";
16
- export { formatProgress, formatSummary, formatError, validateSlug, validateEmail } from "./cli/prompts.js";
17
13
  //# sourceMappingURL=index.d.ts.map
@@ -7,10 +7,7 @@
7
7
  * invite/accept into create-company and join-company flows with
8
8
  * checkpoint/resume.
9
9
  */
10
- export { createCompanyFlow, joinCompanyFlow, resumeOnboarding, onboardingContract, } from "./orchestrator.js";
11
- export { readCheckpoint, writeCheckpoint, deleteCheckpoint, getCheckpointPath, isStepComplete, } from "./checkpoint.js";
12
- export { OnboardingError, PersonCreationError, CompanyCreationError, ProvisioningError, MembershipBootstrapError, FirstSyncError, InviteAcceptError, StsVerifyError, } from "./errors.js";
13
- // CLI
10
+ // The CLI command and identity guard are the only consumers of this barrel.
11
+ export { readCheckpoint } from "./checkpoint.js";
14
12
  export { runOnboardCli } from "./cli/onboard.js";
15
- export { formatProgress, formatSummary, formatError, validateSlug, validateEmail } from "./cli/prompts.js";
16
13
  //# sourceMappingURL=index.js.map
@@ -1,9 +1,5 @@
1
- /** Mirrors the deploy skill's static-report guardrails. */
2
- export declare const REPORT_SOURCE_MAX_BYTES: number;
3
- export declare const REPORT_BUNDLE_MAX_BYTES: number;
4
- export declare const REPORT_SOURCE_MAX_FILES = 100;
5
1
  export declare const REPORT_CSP = "default-src 'none'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'none'; frame-src 'none'; form-action 'none'";
6
- export type ReportLastRun = {
2
+ type ReportLastRun = {
7
3
  at: string;
8
4
  status: "running" | "succeeded" | "failed";
9
5
  reason?: string;
@@ -175,10 +171,5 @@ type BuiltTarball = {
175
171
  };
176
172
  /** hq-deploy static payload format: index.html stays at the archive root. */
177
173
  export declare function buildReportTarball(files: StaticFile[]): BuiltTarball;
178
- /** Isolated test helper for creating a compliant report source. */
179
- export declare function makeReportFixture(html: string): {
180
- directory: string;
181
- cleanup: () => void;
182
- };
183
174
  export {};
184
175
  //# sourceMappingURL=report-publish.d.ts.map
@@ -13,9 +13,9 @@ import { gzipSync } from "node:zlib";
13
13
  import { REPORT_PREVIEW_FILE } from "./report-snapshot.js";
14
14
  import { loadUpdateReportRunbook } from "./report-templates.js";
15
15
  /** Mirrors the deploy skill's static-report guardrails. */
16
- export const REPORT_SOURCE_MAX_BYTES = 25 * 1024 * 1024;
17
- export const REPORT_BUNDLE_MAX_BYTES = 10 * 1024 * 1024;
18
- export const REPORT_SOURCE_MAX_FILES = 100;
16
+ const REPORT_SOURCE_MAX_BYTES = 25 * 1024 * 1024;
17
+ const REPORT_BUNDLE_MAX_BYTES = 10 * 1024 * 1024;
18
+ const REPORT_SOURCE_MAX_FILES = 100;
19
19
  export const REPORT_CSP = "default-src 'none'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'none'; frame-src 'none'; form-action 'none'";
20
20
  /**
21
21
  * Write the files exactly as they will be published, protected index.html
@@ -418,10 +418,4 @@ function writeOctal(buffer, value, offset, length) {
418
418
  buffer.write(value.toString(8).padStart(length - 1, "0").slice(-length + 1), offset, length - 1, "ascii");
419
419
  buffer[offset + length - 1] = 0;
420
420
  }
421
- /** Isolated test helper for creating a compliant report source. */
422
- export function makeReportFixture(html) {
423
- const directory = fs.mkdtempSync(path.join(os.tmpdir(), "hq-report-test-"));
424
- fs.writeFileSync(path.join(directory, "index.html"), html);
425
- return { directory, cleanup: () => fs.rmSync(directory, { recursive: true, force: true }) };
426
- }
427
421
  //# sourceMappingURL=report-publish.js.map
@@ -11,13 +11,6 @@ export type EmbedLockProcessEvents = Pick<NodeJS.Process, 'once'> & {
11
11
  removeListener?: NodeJS.Process['removeListener'];
12
12
  };
13
13
  export type EmbedLockRunResult = 'ran' | 'skipped' | 'busy' | 'unavailable';
14
- /**
15
- * Serializes QMD writes started through HQ-managed hq-cli paths. A bare `qmd
16
- * update` / `qmd embed` (or another tool that does not call this module) cannot
17
- * participate, because qmd is a third-party package and does not know about
18
- * HQ's lock protocol.
19
- */
20
- export declare const EMBED_LOCK_NAME = "qmd-reindex-bg.lock";
21
14
  export declare function defaultEmbedLockDependencies(env?: NodeJS.ProcessEnv): EmbedLockDependencies;
22
15
  export declare function lockRoot(home: string): string;
23
16
  export declare function lockPath(home: string): string;
@@ -6,7 +6,7 @@ import * as path from 'node:path';
6
6
  * participate, because qmd is a third-party package and does not know about
7
7
  * HQ's lock protocol.
8
8
  */
9
- export const EMBED_LOCK_NAME = 'qmd-reindex-bg.lock';
9
+ const EMBED_LOCK_NAME = 'qmd-reindex-bg.lock';
10
10
  export function defaultEmbedLockDependencies(env = process.env) {
11
11
  return {
12
12
  env,
@@ -11,6 +11,7 @@ export type QmdProcessResult = {
11
11
  */
12
12
  signal?: NodeJS.Signals | string | null;
13
13
  };
14
+ export type QmdUpdateEntryPath = 'index-sync';
14
15
  export type QmdProcessRunner = (bin: string, args: string[], options: {
15
16
  cwd?: string;
16
17
  env?: NodeJS.ProcessEnv;
@@ -113,6 +114,10 @@ export declare class QmdExitError extends Error {
113
114
  readonly stdout: string;
114
115
  readonly stderr: string;
115
116
  name: string;
117
+ /** Safe route labels for telemetry; raw qmd streams remain local to the error. */
118
+ entryPath?: QmdUpdateEntryPath;
119
+ /** Present only when the invoked executable is the bundled qmd. */
120
+ qmdVersion?: string;
116
121
  constructor(message: string, args: string[], status: number | null, stdout: string, stderr: string);
117
122
  }
118
123
  export declare class QmdCollectionMissingError extends QmdExitError {
@@ -507,6 +512,8 @@ export type ResolveQmdInvocationOptions = {
507
512
  export declare function resolveQmdInvocation(options?: ResolveQmdInvocationOptions): QmdInvocation;
508
513
  export type RunQmdOptions = {
509
514
  bin?: string;
515
+ /** Source of an update failure, used only for bounded Sentry tags. */
516
+ entryPath?: QmdUpdateEntryPath;
510
517
  cwd?: string;
511
518
  env?: NodeJS.ProcessEnv;
512
519
  runner?: QmdProcessRunner;
@@ -76,6 +76,10 @@ export class QmdExitError extends Error {
76
76
  stdout;
77
77
  stderr;
78
78
  name = 'QmdExitError';
79
+ /** Safe route labels for telemetry; raw qmd streams remain local to the error. */
80
+ entryPath;
81
+ /** Present only when the invoked executable is the bundled qmd. */
82
+ qmdVersion;
79
83
  constructor(message, args, status, stdout, stderr) {
80
84
  super(message);
81
85
  this.args = args;
@@ -1239,6 +1243,21 @@ function finishRunQmd(result, bin, args, attribution) {
1239
1243
  }
1240
1244
  throw exitError;
1241
1245
  }
1246
+ function finishRunQmdWithDiagnostics(result, bin, args, options, attribution) {
1247
+ try {
1248
+ return finishRunQmd(result, bin, args, attribution);
1249
+ }
1250
+ catch (error) {
1251
+ if (error instanceof QmdExitError) {
1252
+ if (args[0] === 'update' && options.entryPath)
1253
+ error.entryPath = options.entryPath;
1254
+ const bundledBins = [packageLocalBin(), packageLocalNodeEntry()].filter((candidate) => Boolean(candidate));
1255
+ if (bundledBins.includes(bin))
1256
+ error.qmdVersion = resolveQmdVersion();
1257
+ }
1258
+ throw error;
1259
+ }
1260
+ }
1242
1261
  /** Run qmd with captured output and typed failures. */
1243
1262
  export function runQmd(args, options = {}) {
1244
1263
  // Legacy string-bin runner seam (tests and callers that inject a fake process):
@@ -1246,7 +1265,7 @@ export function runQmd(args, options = {}) {
1246
1265
  if (options.runner) {
1247
1266
  const bin = options.bin ?? resolveQmdBin({ env: options.env });
1248
1267
  const result = options.runner(bin, args, { cwd: options.cwd, env: options.env });
1249
- return finishRunQmd(result, bin, args);
1268
+ return finishRunQmdWithDiagnostics(result, bin, args, options);
1250
1269
  }
1251
1270
  // Default path: resolve the full invocation (shell-free Node launcher preferred)
1252
1271
  // and spawn it through the shared Windows-aware plan. An explicit string bin is
@@ -1279,7 +1298,7 @@ export function runQmd(args, options = {}) {
1279
1298
  // genuinely missing qmd — instead of blaming the launcher for all three
1280
1299
  // (HQ-CLI-1A). `command` is the process actually spawned; `launcher` is qmd's
1281
1300
  // file identity.
1282
- return finishRunQmd(result, launcher, args, {
1301
+ return finishRunQmdWithDiagnostics(result, launcher, args, options, {
1283
1302
  command: invocation.command,
1284
1303
  launcher,
1285
1304
  cwd: options.cwd,
@@ -22,10 +22,6 @@ export type LoadGateDependencies = {
22
22
  freemem: () => number;
23
23
  totalmem: () => number;
24
24
  };
25
- type CpuCounters = {
26
- total: number;
27
- idle: number;
28
- };
29
25
  export type EmbedLoadDecision = {
30
26
  action: 'embed';
31
27
  forced: false;
@@ -44,11 +40,8 @@ export declare class LoadGateConfigurationError extends Error {
44
40
  constructor(value: string);
45
41
  }
46
42
  export declare function defaultLoadGateDependencies(env?: NodeJS.ProcessEnv): LoadGateDependencies;
47
- export declare function parseProcStatAggregate(contents: string): CpuCounters | undefined;
48
- export declare function cpuBusyPercent(before: CpuCounters, after: CpuCounters): number | undefined;
49
43
  /** Sample aggregate CPU busy time over 200 ms, falling back only without /proc/stat. */
50
44
  export declare function measureCpuPercent(dependencies: LoadGateDependencies): number;
51
- export declare function memAvailableFraction(contents: string): number | undefined;
52
45
  /** Prefer Linux MemAvailable, because MemFree alone treats reclaimable cache as used memory. */
53
46
  export declare function measureMemoryPercent(dependencies: LoadGateDependencies): number;
54
47
  export declare function parseLoadThreshold(env: NodeJS.ProcessEnv): number | undefined;
@@ -61,5 +54,4 @@ export declare function loadGateStatePath(home: string): string;
61
54
  export declare function checkEmbedLoad(home: string, dependencies: LoadGateDependencies): EmbedLoadDecision;
62
55
  /** Reset the starvation counter only after qmd embed has actually returned successfully. */
63
56
  export declare function recordSuccessfulEmbed(home: string, dependencies: LoadGateDependencies): void;
64
- export {};
65
57
  //# sourceMappingURL=load-gate.d.ts.map
@@ -46,7 +46,7 @@ function errorCode(error) {
46
46
  function missing(error) {
47
47
  return errorCode(error) === 'ENOENT';
48
48
  }
49
- export function parseProcStatAggregate(contents) {
49
+ function parseProcStatAggregate(contents) {
50
50
  const line = contents.split('\n').find((candidate) => /^cpu\s+/.test(candidate));
51
51
  if (!line)
52
52
  return undefined;
@@ -58,7 +58,7 @@ export function parseProcStatAggregate(contents) {
58
58
  const idle = values[3] + values[4];
59
59
  return total > 0 && Number.isFinite(idle) ? { total, idle } : undefined;
60
60
  }
61
- export function cpuBusyPercent(before, after) {
61
+ function cpuBusyPercent(before, after) {
62
62
  const totalDelta = after.total - before.total;
63
63
  const idleDelta = after.idle - before.idle;
64
64
  if (totalDelta <= 0 || idleDelta < 0)
@@ -117,7 +117,7 @@ export function measureCpuPercent(dependencies) {
117
117
  throw new Error('Cannot determine CPU busy time from /proc/stat.');
118
118
  return busy;
119
119
  }
120
- export function memAvailableFraction(contents) {
120
+ function memAvailableFraction(contents) {
121
121
  const fields = new Map();
122
122
  for (const line of contents.split('\n')) {
123
123
  const match = /^(MemTotal|MemAvailable):\s+(\d+)\s+kB$/.exec(line.trim());