@indigoai-us/hq-cli 5.125.0 → 5.127.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 (108) hide show
  1. package/CHANGELOG.md +329 -0
  2. package/assets/bot-workers/setup/skills/joining-a-team.md +125 -0
  3. package/assets/bot-workers/setup/skills/your-business.md +270 -0
  4. package/assets/bot-workers/setup/worker.yaml +189 -58
  5. package/assets/lanes-hooks/hq-lanes-drain.json +15 -0
  6. package/assets/lanes-hooks/hq-lanes-drain.mjs +254 -0
  7. package/assets/lanes-hooks/hq-lanes-drain.sh +21 -0
  8. package/assets/lanes-reconcile/hq-lanes-reconcile.service +11 -0
  9. package/assets/lanes-reconcile/hq-lanes-reconcile.timer +12 -0
  10. package/dist/command-catalog.generated.d.ts +643 -6
  11. package/dist/command-catalog.generated.js +836 -6
  12. package/dist/command-registration-plan.d.ts +7 -0
  13. package/dist/command-registration-plan.js +11 -1
  14. package/dist/commands/agents.d.ts +12 -0
  15. package/dist/commands/agents.js +46 -2
  16. package/dist/commands/bot.d.ts +10 -0
  17. package/dist/commands/bot.js +6 -0
  18. package/dist/commands/lanes.d.ts +114 -0
  19. package/dist/commands/lanes.js +2969 -0
  20. package/dist/commands/mesh.js +287 -24
  21. package/dist/commands/onboard-create-identity.d.ts +26 -0
  22. package/dist/commands/onboard-create-identity.js +23 -0
  23. package/dist/commands/onboard.js +13 -4
  24. package/dist/lib/bot/progress.d.ts +6 -0
  25. package/dist/lib/bot/progress.js +16 -0
  26. package/dist/lib/bot/runtime/grok.d.ts +30 -7
  27. package/dist/lib/bot/runtime/grok.js +86 -8
  28. package/dist/lib/bot/runtime/index.js +15 -8
  29. package/dist/lib/bot/runtime/messages-stream.d.ts +12 -3
  30. package/dist/lib/bot/runtime/messages-stream.js +49 -3
  31. package/dist/lib/lanes/accounts.d.ts +103 -0
  32. package/dist/lib/lanes/accounts.js +318 -0
  33. package/dist/lib/lanes/compaction.d.ts +96 -0
  34. package/dist/lib/lanes/compaction.js +197 -0
  35. package/dist/lib/lanes/config.d.ts +71 -0
  36. package/dist/lib/lanes/config.js +408 -0
  37. package/dist/lib/lanes/delivery.d.ts +151 -0
  38. package/dist/lib/lanes/delivery.js +354 -0
  39. package/dist/lib/lanes/dropbox.d.ts +96 -0
  40. package/dist/lib/lanes/dropbox.js +408 -0
  41. package/dist/lib/lanes/effort.d.ts +50 -0
  42. package/dist/lib/lanes/effort.js +109 -0
  43. package/dist/lib/lanes/errors.d.ts +39 -0
  44. package/dist/lib/lanes/errors.js +72 -0
  45. package/dist/lib/lanes/hooks-install.d.ts +81 -0
  46. package/dist/lib/lanes/hooks-install.js +326 -0
  47. package/dist/lib/lanes/hq-root.d.ts +19 -0
  48. package/dist/lib/lanes/hq-root.js +28 -0
  49. package/dist/lib/lanes/index.d.ts +49 -0
  50. package/dist/lib/lanes/index.js +27 -0
  51. package/dist/lib/lanes/liveness.d.ts +95 -0
  52. package/dist/lib/lanes/liveness.js +332 -0
  53. package/dist/lib/lanes/machine-identity.d.ts +34 -0
  54. package/dist/lib/lanes/machine-identity.js +92 -0
  55. package/dist/lib/lanes/mesh-events.d.ts +109 -0
  56. package/dist/lib/lanes/mesh-events.js +275 -0
  57. package/dist/lib/lanes/outpost-dispatch.d.ts +65 -0
  58. package/dist/lib/lanes/outpost-dispatch.js +90 -0
  59. package/dist/lib/lanes/questions.d.ts +75 -0
  60. package/dist/lib/lanes/questions.js +243 -0
  61. package/dist/lib/lanes/quota.d.ts +95 -0
  62. package/dist/lib/lanes/quota.js +320 -0
  63. package/dist/lib/lanes/reconcile-install.d.ts +69 -0
  64. package/dist/lib/lanes/reconcile-install.js +221 -0
  65. package/dist/lib/lanes/reconcile.d.ts +102 -0
  66. package/dist/lib/lanes/reconcile.js +985 -0
  67. package/dist/lib/lanes/registry.d.ts +116 -0
  68. package/dist/lib/lanes/registry.js +521 -0
  69. package/dist/lib/lanes/spawn.d.ts +274 -0
  70. package/dist/lib/lanes/spawn.js +1363 -0
  71. package/dist/lib/lanes/store.d.ts +68 -0
  72. package/dist/lib/lanes/store.js +745 -0
  73. package/dist/lib/lanes/throttle.d.ts +89 -0
  74. package/dist/lib/lanes/throttle.js +297 -0
  75. package/dist/lib/lanes/types.d.ts +535 -0
  76. package/dist/lib/lanes/types.js +350 -0
  77. package/dist/lib/lanes/watcher-main.d.ts +9 -0
  78. package/dist/lib/lanes/watcher-main.js +22 -0
  79. package/dist/lib/lanes/watcher.d.ts +216 -0
  80. package/dist/lib/lanes/watcher.js +859 -0
  81. package/dist/lib/mesh/api.d.ts +71 -7
  82. package/dist/lib/mesh/api.js +167 -28
  83. package/dist/lib/mesh/live/backfill-held.d.ts +18 -7
  84. package/dist/lib/mesh/live/backfill-held.js +66 -21
  85. package/dist/lib/mesh/live/daemon/config.d.ts +27 -0
  86. package/dist/lib/mesh/live/daemon/config.js +75 -0
  87. package/dist/lib/mesh/live/daemon/index.d.ts +4 -3
  88. package/dist/lib/mesh/live/daemon/index.js +3 -3
  89. package/dist/lib/mesh/live/daemon/install.d.ts +143 -1
  90. package/dist/lib/mesh/live/daemon/install.js +444 -2
  91. package/dist/lib/mesh/live/daemon/paths.d.ts +2 -0
  92. package/dist/lib/mesh/live/daemon/paths.js +2 -0
  93. package/dist/lib/mesh/live/daemon/run.d.ts +2 -0
  94. package/dist/lib/mesh/live/daemon/run.js +111 -54
  95. package/dist/lib/mesh/live/daemon/state.d.ts +2 -0
  96. package/dist/lib/mesh/live/daemon/transcript-watch.d.ts +3 -0
  97. package/dist/lib/mesh/live/daemon/transcript-watch.js +31 -8
  98. package/dist/lib/scan-packages/index.d.ts +2 -0
  99. package/dist/lib/scan-packages/index.js +18 -13
  100. package/dist/lib/work-context/config.d.ts +20 -0
  101. package/dist/lib/work-context/config.js +26 -5
  102. package/dist/lib/work-context/reconcile.js +28 -7
  103. package/dist/lib/work-context/state.d.ts +12 -0
  104. package/dist/lib/work-context/state.js +131 -3
  105. package/dist/lib/work-context/windows-acl.d.ts +123 -0
  106. package/dist/lib/work-context/windows-acl.js +425 -0
  107. package/dist/utils/pack-contributions.js +5 -4
  108. package/package.json +3 -1
@@ -400,6 +400,13 @@ export declare const REGISTRATION_PLAN: readonly [{
400
400
  readonly parent: "program";
401
401
  readonly module: "./commands/mesh.js";
402
402
  readonly exportName: "registerMeshCommand";
403
+ }, {
404
+ readonly type: "registrar";
405
+ readonly root: "lanes";
406
+ readonly parent: "program";
407
+ readonly module: "./commands/lanes.js";
408
+ readonly exportName: "registerLanesCommand";
409
+ readonly hidden: true;
403
410
  }, {
404
411
  readonly type: "registrar";
405
412
  readonly root: "bot";
@@ -69,13 +69,15 @@ export const REGISTRATION_PLAN = [
69
69
  { type: "registrar", root: "index", parent: "program", module: "./commands/index-cmd.js", exportName: "registerIndexCommand" },
70
70
  { type: "registrar", root: "doctor", parent: "program", module: "./commands/doctor.js", exportName: "registerDoctorCommand" },
71
71
  { type: "registrar", root: "mesh", parent: "program", module: "./commands/mesh.js", exportName: "registerMeshCommand" },
72
+ { type: "registrar", root: "lanes", parent: "program", module: "./commands/lanes.js", exportName: "registerLanesCommand", hidden: true },
72
73
  { type: "registrar", root: "bot", parent: "program", module: "./commands/bot.js", exportName: "registerBotCommand" },
73
74
  ];
74
75
  async function executePlan(program, steps) {
75
76
  const parents = new Map([["program", program]]);
76
77
  for (const step of steps) {
77
78
  if (step.type === "group") {
78
- parents.set(step.id, program.command(step.name).description(step.description));
79
+ const group = program.command(step.name, step.hidden ? { hidden: true } : {});
80
+ parents.set(step.id, group.description(step.description));
79
81
  continue;
80
82
  }
81
83
  const parent = parents.get(step.parent);
@@ -86,6 +88,14 @@ async function executePlan(program, steps) {
86
88
  if (!register)
87
89
  throw new Error(`Missing command registrar '${step.exportName}' from '${step.module}'`);
88
90
  const result = register(parent);
91
+ if (step.hidden) {
92
+ const command = result ??
93
+ parent.commands.find((candidate) => candidate.name() === step.root);
94
+ if (!command) {
95
+ throw new Error(`Command registrar '${step.exportName}' did not register hidden command '${step.root}'`);
96
+ }
97
+ command._hidden = true;
98
+ }
89
99
  if (step.result) {
90
100
  if (!result)
91
101
  throw new Error(`Command registrar '${step.exportName}' did not return '${step.result}'`);
@@ -130,6 +130,18 @@ export interface CompanyAgentView {
130
130
  };
131
131
  [key: string]: unknown;
132
132
  }
133
+ /**
134
+ * STATUS column for `hq agents list`.
135
+ *
136
+ * `agentStatus` is the agent's own stored runtime status and is NOT rewritten
137
+ * when a teardown starts — an agent that never finished provisioning and is
138
+ * now being removed keeps reading `provisioning` until the teardown completes
139
+ * and archives it. Observed live on liverecover/sean 2026-09-21: a removal that
140
+ * stalled on an object-locked vault bucket sat in the roster as `provisioning`,
141
+ * so the operator believed the removal had never been accepted. The roster
142
+ * already carries `setupPhase`, so prefer it whenever a teardown is in flight.
143
+ */
144
+ export declare function rosterStatusLabel(agent: CompanyAgentView): string;
133
145
  export interface ProfilePatch {
134
146
  displayName?: string;
135
147
  title?: string;
@@ -216,6 +216,24 @@ export class AgentsHttpError extends Error {
216
216
  this.agentCreatePlanLimit = agentCreatePlanLimit;
217
217
  }
218
218
  }
219
+ /**
220
+ * STATUS column for `hq agents list`.
221
+ *
222
+ * `agentStatus` is the agent's own stored runtime status and is NOT rewritten
223
+ * when a teardown starts — an agent that never finished provisioning and is
224
+ * now being removed keeps reading `provisioning` until the teardown completes
225
+ * and archives it. Observed live on liverecover/sean 2026-09-21: a removal that
226
+ * stalled on an object-locked vault bucket sat in the roster as `provisioning`,
227
+ * so the operator believed the removal had never been accepted. The roster
228
+ * already carries `setupPhase`, so prefer it whenever a teardown is in flight.
229
+ */
230
+ export function rosterStatusLabel(agent) {
231
+ if (agent.setupPhase === "deprovisioning")
232
+ return "removing";
233
+ if (agent.setupPhase === "deprovisioned")
234
+ return "removed";
235
+ return agent.agentStatus ?? "";
236
+ }
219
237
  /**
220
238
  * Authenticated JSON round-trip against the agents control plane. Throws
221
239
  * `AgentsHttpError` on any non-2xx (never swallows — hq-never-swallow-errors),
@@ -466,11 +484,37 @@ function signInProviderName(url) {
466
484
  return "Claude";
467
485
  return "your provider";
468
486
  }
487
+ /**
488
+ * Brain slot a device sign-in URL belongs to, or null when the provider has no
489
+ * per-brain slot (Claude) or the host is unknown.
490
+ */
491
+ function signInBrainSlot(url) {
492
+ const provider = signInProviderName(url);
493
+ if (provider === "Grok")
494
+ return "grok";
495
+ if (provider === "Codex")
496
+ return "codex";
497
+ return null;
498
+ }
499
+ /**
500
+ * True when the box probe already reports that brain as signed in. A device
501
+ * pairing file can outlive the sign-in it started, so the probe — not the
502
+ * leftover code — decides whether a human still has work to do.
503
+ */
504
+ function brainAlreadySignedIn(status, url) {
505
+ const slot = signInBrainSlot(url);
506
+ if (!slot)
507
+ return false;
508
+ const brains = recordValue(recordValue(status.agent)?.brains);
509
+ return brains?.[slot] === "signed-in";
510
+ }
469
511
  function currentDeviceSignInAction(status) {
470
512
  const pairing = recordValue(status.pairing);
471
513
  const url = safeActionUrl(pairing?.url);
472
514
  if (!url)
473
515
  return null;
516
+ if (brainAlreadySignedIn(status, url))
517
+ return null;
474
518
  const rawCode = nonEmptyString(pairing?.code);
475
519
  const code = rawCode && /^[A-Z0-9]{4,8}-[A-Z0-9]{4,8}$/i.test(rawCode)
476
520
  ? rawCode
@@ -1370,7 +1414,7 @@ export function registerAgentsCommand(program) {
1370
1414
  }
1371
1415
  const nameW = Math.max(4, ...roster.map((a) => (a.name ?? "").length));
1372
1416
  const slugW = Math.max(4, ...roster.map((a) => (a.slug ?? "").length));
1373
- const statusW = Math.max(6, ...roster.map((a) => (a.agentStatus ?? "").length));
1417
+ const statusW = Math.max(6, ...roster.map((a) => rosterStatusLabel(a).length));
1374
1418
  const modelW = Math.max(5, ...roster.map((a) => (a.codexModel ?? "").length));
1375
1419
  console.log(chalk.bold([
1376
1420
  "NAME".padEnd(nameW),
@@ -1383,7 +1427,7 @@ export function registerAgentsCommand(program) {
1383
1427
  console.log([
1384
1428
  (a.name ?? "").padEnd(nameW),
1385
1429
  (a.slug ?? "").padEnd(slugW),
1386
- (a.agentStatus ?? "").padEnd(statusW),
1430
+ rosterStatusLabel(a).padEnd(statusW),
1387
1431
  (a.codexModel ?? "").padEnd(modelW),
1388
1432
  a.uid,
1389
1433
  ].join(" "));
@@ -27,6 +27,16 @@ export interface BotRow {
27
27
  lastHeartbeatOk: boolean | null;
28
28
  lastInboxPollAt: string | null;
29
29
  lastInboxPollOk: boolean | null;
30
+ /**
31
+ * The bot is mid-turn right now: it has taken a message and has not finished
32
+ * answering. Read from the bot's own in-flight marker on this machine, so it
33
+ * is true even while the model is still thinking and nothing has been posted
34
+ * yet. Surfaces are what show "thinking"; a progress post in the middle of a
35
+ * turn does not end it.
36
+ */
37
+ busy: boolean;
38
+ /** When the oldest turn still in flight started (ISO), else null. */
39
+ busySince: string | null;
30
40
  /** Present while the coding tool needs a new sign-in before the bot can work. */
31
41
  runtimeSignIn: RuntimeSignInIssue | null;
32
42
  daemonInstalled: boolean;
@@ -1,5 +1,6 @@
1
1
  import { OwnerContextCache, lookupOwnerContext } from "../lib/bot/owner-context.js";
2
2
  import { hasActivePromotion } from "../lib/bot/promotion-receipt.js";
3
+ import { readInflightTurns } from "../lib/bot/inflight.js";
3
4
  import { hasPromotionHold, promotionHoldSummary } from "../lib/bot/promotion-hold.js";
4
5
  /**
5
6
  * `hq bot` — personal local bots (local-bots US-003/US-004/US-005).
@@ -117,6 +118,8 @@ function rowFor(name, opts = {}) {
117
118
  const status = readBotStatus(dir);
118
119
  const pid = status?.pid ?? null;
119
120
  const processAlive = pid !== null && isPidAlive(pid) && status?.state === "running";
121
+ // Turns this bot has taken and not finished: what "thinking" means.
122
+ const inflightTurns = readInflightTurns(dir);
120
123
  let daemonInstalled = false;
121
124
  let daemonLoaded = false;
122
125
  if (opts.withDaemon !== false) {
@@ -147,6 +150,8 @@ function rowFor(name, opts = {}) {
147
150
  lastHeartbeatOk: status?.lastHeartbeatOk ?? null,
148
151
  lastInboxPollAt: status?.lastInboxPollAt ?? null,
149
152
  lastInboxPollOk: status?.lastInboxPollOk ?? null,
153
+ busy: processAlive && inflightTurns.length > 0,
154
+ busySince: processAlive ? (inflightTurns[0]?.startedAt ?? null) : null,
150
155
  runtimeSignIn: status?.runtimeSignIn ?? null,
151
156
  daemonInstalled,
152
157
  daemonLoaded,
@@ -723,6 +728,7 @@ async function runBotStatus(nameArg, opts) {
723
728
  else if (status?.lastInboxPollAt) {
724
729
  console.log(` inbox: last poll ${status.lastInboxPollAt}`);
725
730
  }
731
+ console.log(` answering: ${row.busy ? chalk.green(`yes${row.busySince ? `, since ${row.busySince}` : ""}`) : chalk.gray("no")}`);
726
732
  console.log(` launchd: ${row.daemonInstalled ? (row.daemonLoaded ? "installed, loaded" : "installed, not loaded") : "not installed"}`);
727
733
  console.log(` creds: ${creds ? `present for ${creds.entityUid}` : chalk.red("missing")}`);
728
734
  if (status) {
@@ -0,0 +1,114 @@
1
+ /**
2
+ * `hq lanes` — worker lane management and decision queue (spec §5–§7, §10–§11).
3
+ *
4
+ * Every command prints JSON on stdout and takes no interactive input, except
5
+ * `accounts login`, which hands the terminal to the vendor's own sign-in.
6
+ */
7
+ import { Command } from "commander";
8
+ import { type OutpostDispatchResult } from "../lib/lanes/outpost-dispatch.js";
9
+ import { emitLaneDecisionEvents, type LaneMesh } from "../lib/lanes/mesh-events.js";
10
+ import { type LaneCompanyRef, type LaneRecord, type QuestionRecord, type ResolvedLaneWorker, type SeniorRef, type LivenessDeps, type MachineIdentity, type RunCommand, type ThrottleDeps } from "../lib/lanes/index.js";
11
+ import { questionBodyAbsPath } from "../lib/lanes/questions.js";
12
+ import { type RunCompactionFn } from "../lib/lanes/compaction.js";
13
+ import { spawnLaneWorker, type KillProcessFn, type ProveDetachedFn, type SpawnProcessFn } from "../lib/lanes/spawn.js";
14
+ export { spawnLaneWorker };
15
+ export { questionBodyAbsPath };
16
+ export declare const MAX_LANE_DEPTH = 2;
17
+ export declare const OUTPOST_ID_PATH = "/etc/outpost/outpost-id";
18
+ export declare const OUTPOST_DIR = "/etc/outpost";
19
+ export declare const LANES_RUNS_REL: string;
20
+ export type OutpostIdentity = {
21
+ kind: "id";
22
+ id: string;
23
+ } | {
24
+ kind: "unknown";
25
+ } | {
26
+ kind: "not_outpost";
27
+ };
28
+ export interface SpawnLoginResult {
29
+ status: number;
30
+ }
31
+ /** The lane → mesh seam. Defined in lib/lanes/mesh-events.ts; the watcher shares it. */
32
+ export type LanesMesh = LaneMesh;
33
+ export { emitLaneDecisionEvents };
34
+ export interface LanesCommandDeps {
35
+ hqRoot?: () => string;
36
+ /** Start HQ-root walk here instead of process.cwd(). Tests only. */
37
+ cwd?: () => string;
38
+ env?: NodeJS.ProcessEnv;
39
+ now?: () => Date;
40
+ hostname?: () => string;
41
+ resolveCompany?: (company?: string) => Promise<LaneCompanyRef>;
42
+ listOutpostIds?: () => Promise<string[]>;
43
+ readOutpostIdentity?: () => OutpostIdentity;
44
+ spawnLogin?: (opts: {
45
+ command: string;
46
+ args: string[];
47
+ env: NodeJS.ProcessEnv;
48
+ cwd?: string;
49
+ }) => Promise<SpawnLoginResult>;
50
+ throttleDeps?: ThrottleDeps;
51
+ existsSync?: (p: string) => boolean;
52
+ readFileSync?: (p: string, encoding: "utf8") => string;
53
+ homedir?: () => string;
54
+ mesh?: LanesMesh;
55
+ sleep?: (ms: number) => Promise<void>;
56
+ spawnProcess?: SpawnProcessFn;
57
+ proveDetached?: ProveDetachedFn;
58
+ killProcess?: KillProcessFn;
59
+ isAlive?: (pid: number) => boolean;
60
+ stopSleepMs?: (ms: number) => void;
61
+ livenessDeps?: LivenessDeps;
62
+ presenceConnected?: boolean;
63
+ systemdRoot?: string;
64
+ runSystemctl?: RunCommand;
65
+ resolveMachineIdentity?: () => MachineIdentity;
66
+ stageOutpostPayload?: (outpostId: string, bytes: Uint8Array) => Promise<{
67
+ getUrl: string;
68
+ }>;
69
+ dispatchOutpostExec?: (input: {
70
+ outpostId: string;
71
+ command: string;
72
+ }) => Promise<OutpostDispatchResult>;
73
+ fetchText?: (url: string) => Promise<string>;
74
+ runCompaction?: RunCompactionFn;
75
+ locateTranscript?: (home: string, sessionId: string) => string | null;
76
+ }
77
+ export declare function readOutpostIdentity(existsSync?: (p: string) => boolean, readFileSync?: (p: string) => string): OutpostIdentity;
78
+ export declare function parseSeniorRef(raw: string): SeniorRef;
79
+ export declare function resolveAnswerChoice(choice: string, options: string[], freeform: boolean): string;
80
+ /**
81
+ * Spec §5.1: `hq lanes ask` from inside a lane can hit a binary or dist
82
+ * being replaced mid-call (ENOENT / ETXTBSY / a module that no longer
83
+ * resolves) or a record written by a newer CLI. Three attempts, waits of
84
+ * 5 s then 15 s, 20 s of backoff in total, inside the 30 s bound.
85
+ */
86
+ export declare const ASK_BACKOFF_MS: readonly [5000, 15000];
87
+ export declare const ASK_ATTEMPTS: number;
88
+ export declare function casUpdateQuestion(hqRoot: string, questionId: string, updater: (current: QuestionRecord) => QuestionRecord): QuestionRecord;
89
+ export declare function casUpdateLane(hqRoot: string, laneId: string, updater: (current: LaneRecord) => LaneRecord): LaneRecord;
90
+ /**
91
+ * Spec §5.3: an approval gate ends the run. The lane stops at each
92
+ * checkpoint with a `decision: ask` envelope whose question names it; the
93
+ * reconcile pass resumes the lane once every question is answered.
94
+ */
95
+ export declare function checkpointInstruction(worker: Pick<ResolvedLaneWorker, "approvalRequired" | "humanCheckpoints">): string;
96
+ export declare function composeWorkerBrief(worker: ResolvedLaneWorker, taskBrief: string): string;
97
+ /**
98
+ * A lane with no worker still carries the standing authorization paragraph
99
+ * and the foreground-only rule.
100
+ */
101
+ export declare function composeGeneralBrief(taskBrief: string): string;
102
+ export declare function parseMaxRuntimeSeconds(raw: unknown, workerId: string): number | undefined;
103
+ export declare const PICKUP_TERMINAL_REASONS: readonly ["account_not_logged_in", "unknown_account", "account_disabled"];
104
+ export declare const DISPATCH_TERMINAL_REASON: "outpost_dispatch_failed";
105
+ export type PickupTerminalReason = (typeof PICKUP_TERMINAL_REASONS)[number];
106
+ /**
107
+ * Outpost-side account bind (spec §5.2). Writes a named terminal reason,
108
+ * never a plain `failed`.
109
+ */
110
+ export declare function applyOutpostAccountPickup(hqRoot: string, laneId: string): LaneRecord;
111
+ export declare function cancelPendingQuestionsForLane(hqRoot: string, laneId: string, nowIso: string, operatorReason?: string): QuestionRecord[];
112
+ export declare function stopCommittedState(state: LaneRecord["state"]): "cancelled" | "killed";
113
+ export declare function registerLanesCommand(parent: Command, deps?: LanesCommandDeps): Command;
114
+ //# sourceMappingURL=lanes.d.ts.map