@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
@@ -1,16 +1,39 @@
1
1
  /**
2
2
  * Grok CLI headless adapter.
3
3
  *
4
- * grok -p <prompt> --output-format streaming-messages-json --always-approve
4
+ * grok -p <prompt> --output-format <streaming format> --always-approve
5
5
  * --no-subagents --cwd <cwd> [-m m] [-r <sessionId>]
6
6
  *
7
- * stdout is NDJSON in the Anthropic Messages shape (see messages-stream.ts).
8
- * The plain `json` format glued every interim sentence into one reply; the
9
- * streaming format lets each message be posted as it is written.
10
- * Verified against grok (grok-4.6) on 2026-09-12 (fixtures/grok-stream.ndjson);
11
- * the older `{ text, sessionId }` envelope is still accepted.
7
+ * stdout is NDJSON. Older grok (before 0.2.56) wrote Anthropic Messages
8
+ * shapes under `--output-format streaming-messages-json` (see
9
+ * messages-stream.ts). grok 0.2.56 dropped that value and emits token
10
+ * events under `streaming-json`:
11
+ *
12
+ * {"type":"thought","data":…}
13
+ * {"type":"text","data":"Hi"}
14
+ * {"type":"end","stopReason":"EndTurn","sessionId":…}
15
+ *
16
+ * The format is probed from `grok --help` once per process (and cached).
17
+ * If an older grok still lists `streaming-messages-json`, that is used.
18
+ * If the probe misses and grok rejects the old value, the turn retries
19
+ * with `streaming-json`. The older `{ text, sessionId }` envelope is
20
+ * still accepted.
12
21
  */
13
22
  import { type BotRuntime, type RuntimeTurnInput } from "./types.js";
23
+ export declare const GROK_OUTPUT_FORMAT_LEGACY = "streaming-messages-json";
24
+ export declare const GROK_OUTPUT_FORMAT_STREAMING_JSON = "streaming-json";
25
+ export declare function resetGrokOutputFormatCache(): void;
26
+ /** Pick the streaming `--output-format` grok's `--help` says it accepts. */
27
+ export declare function grokOutputFormatFromHelp(helpText: string): string;
28
+ /** Probe `grok --help` once and cache the streaming format. */
29
+ export declare function probeGrokOutputFormat(readHelp?: () => string): string;
30
+ /**
31
+ * When grok 0.2.56 rejects the pre-0.2.56 flag, rewrite argv to
32
+ * `streaming-json` and remember that for later turns.
33
+ */
34
+ export declare function grokRetryArgsAfterInvalidOutputFormat(args: string[], stderr: string): string[] | undefined;
14
35
  export declare function grokPrompt(input: RuntimeTurnInput): string;
15
- export declare function createGrokRuntime(): BotRuntime;
36
+ export declare function createGrokRuntime(opts?: {
37
+ grokHelp?: string;
38
+ }): BotRuntime;
16
39
  //# sourceMappingURL=grok.d.ts.map
@@ -1,23 +1,101 @@
1
1
  /**
2
2
  * Grok CLI headless adapter.
3
3
  *
4
- * grok -p <prompt> --output-format streaming-messages-json --always-approve
4
+ * grok -p <prompt> --output-format <streaming format> --always-approve
5
5
  * --no-subagents --cwd <cwd> [-m m] [-r <sessionId>]
6
6
  *
7
- * stdout is NDJSON in the Anthropic Messages shape (see messages-stream.ts).
8
- * The plain `json` format glued every interim sentence into one reply; the
9
- * streaming format lets each message be posted as it is written.
10
- * Verified against grok (grok-4.6) on 2026-09-12 (fixtures/grok-stream.ndjson);
11
- * the older `{ text, sessionId }` envelope is still accepted.
7
+ * stdout is NDJSON. Older grok (before 0.2.56) wrote Anthropic Messages
8
+ * shapes under `--output-format streaming-messages-json` (see
9
+ * messages-stream.ts). grok 0.2.56 dropped that value and emits token
10
+ * events under `streaming-json`:
11
+ *
12
+ * {"type":"thought","data":…}
13
+ * {"type":"text","data":"Hi"}
14
+ * {"type":"end","stopReason":"EndTurn","sessionId":…}
15
+ *
16
+ * The format is probed from `grok --help` once per process (and cached).
17
+ * If an older grok still lists `streaming-messages-json`, that is used.
18
+ * If the probe misses and grok rejects the old value, the turn retries
19
+ * with `streaming-json`. The older `{ text, sessionId }` envelope is
20
+ * still accepted.
12
21
  */
22
+ import { execFileSync } from "node:child_process";
13
23
  import { messagesStreamEvents, messagesStreamFailure, messagesStreamResult } from "./messages-stream.js";
14
24
  import { parseJsonLine, RuntimeError } from "./types.js";
25
+ export const GROK_OUTPUT_FORMAT_LEGACY = "streaming-messages-json";
26
+ export const GROK_OUTPUT_FORMAT_STREAMING_JSON = "streaming-json";
27
+ let cachedOutputFormat;
28
+ export function resetGrokOutputFormatCache() {
29
+ cachedOutputFormat = undefined;
30
+ }
31
+ /** Pick the streaming `--output-format` grok's `--help` says it accepts. */
32
+ export function grokOutputFormatFromHelp(helpText) {
33
+ const section = /--output-format\s*<OUTPUT_FORMAT>[\s\S]*?\[possible values:\s*([^\]]+)\]/i.exec(helpText);
34
+ const values = (section?.[1] ?? "")
35
+ .split(",")
36
+ .map((s) => s.trim())
37
+ .filter(Boolean);
38
+ if (values.includes(GROK_OUTPUT_FORMAT_LEGACY))
39
+ return GROK_OUTPUT_FORMAT_LEGACY;
40
+ if (values.includes(GROK_OUTPUT_FORMAT_STREAMING_JSON))
41
+ return GROK_OUTPUT_FORMAT_STREAMING_JSON;
42
+ if (helpText.includes(GROK_OUTPUT_FORMAT_LEGACY))
43
+ return GROK_OUTPUT_FORMAT_LEGACY;
44
+ if (/\bstreaming-json\b/.test(helpText))
45
+ return GROK_OUTPUT_FORMAT_STREAMING_JSON;
46
+ return GROK_OUTPUT_FORMAT_LEGACY;
47
+ }
48
+ function defaultGrokHelp() {
49
+ try {
50
+ return execFileSync("grok", ["--help"], {
51
+ encoding: "utf8",
52
+ timeout: 5_000,
53
+ stdio: ["ignore", "pipe", "pipe"],
54
+ });
55
+ }
56
+ catch (err) {
57
+ const e = err;
58
+ return `${e.stdout ?? ""}\n${e.stderr ?? ""}`;
59
+ }
60
+ }
61
+ /** Probe `grok --help` once and cache the streaming format. */
62
+ export function probeGrokOutputFormat(readHelp = defaultGrokHelp) {
63
+ if (cachedOutputFormat)
64
+ return cachedOutputFormat;
65
+ let help;
66
+ try {
67
+ help = readHelp();
68
+ }
69
+ catch {
70
+ help = "";
71
+ }
72
+ cachedOutputFormat = grokOutputFormatFromHelp(help);
73
+ return cachedOutputFormat;
74
+ }
75
+ /**
76
+ * When grok 0.2.56 rejects the pre-0.2.56 flag, rewrite argv to
77
+ * `streaming-json` and remember that for later turns.
78
+ */
79
+ export function grokRetryArgsAfterInvalidOutputFormat(args, stderr) {
80
+ if (!/invalid value ['"]streaming-messages-json['"]/.test(stderr))
81
+ return undefined;
82
+ const i = args.indexOf("--output-format");
83
+ if (i < 0 || args[i + 1] === GROK_OUTPUT_FORMAT_STREAMING_JSON)
84
+ return undefined;
85
+ const next = args.slice();
86
+ next[i + 1] = GROK_OUTPUT_FORMAT_STREAMING_JSON;
87
+ cachedOutputFormat = GROK_OUTPUT_FORMAT_STREAMING_JSON;
88
+ return next;
89
+ }
15
90
  export function grokPrompt(input) {
16
91
  if (input.sessionId)
17
92
  return input.prompt;
18
93
  return `${input.systemPrompt}\n\n---\n\nMessage from your owner:\n\n${input.prompt}`;
19
94
  }
20
- export function createGrokRuntime() {
95
+ export function createGrokRuntime(opts = {}) {
96
+ const format = opts.grokHelp !== undefined
97
+ ? grokOutputFormatFromHelp(opts.grokHelp)
98
+ : (cachedOutputFormat ?? GROK_OUTPUT_FORMAT_LEGACY);
21
99
  return {
22
100
  id: "grok",
23
101
  binary: "grok",
@@ -26,7 +104,7 @@ export function createGrokRuntime() {
26
104
  "-p",
27
105
  grokPrompt(input),
28
106
  "--output-format",
29
- "streaming-messages-json",
107
+ format,
30
108
  "--always-approve",
31
109
  "--no-subagents",
32
110
  "--cwd",
@@ -5,7 +5,7 @@ import * as os from "node:os";
5
5
  import * as path from "node:path";
6
6
  import { createClaudeRuntime } from "./claude.js";
7
7
  import { createCodexRuntime } from "./codex.js";
8
- import { createGrokRuntime } from "./grok.js";
8
+ import { createGrokRuntime, grokRetryArgsAfterInvalidOutputFormat, probeGrokOutputFormat } from "./grok.js";
9
9
  import { parseJsonLine, RuntimeError, turnTimeoutMs, stderrExcerpt, } from "./types.js";
10
10
  export * from "./types.js";
11
11
  export { createClaudeRuntime, claudePermissionMode } from "./claude.js";
@@ -16,6 +16,7 @@ export function runtimeFor(id, env = process.env) {
16
16
  return createClaudeRuntime(env);
17
17
  if (id === "codex")
18
18
  return createCodexRuntime();
19
+ probeGrokOutputFormat();
19
20
  return createGrokRuntime();
20
21
  }
21
22
  /**
@@ -220,15 +221,21 @@ export async function runRuntimeTurn(runtime, input, deps = {}) {
220
221
  }
221
222
  : undefined;
222
223
  const timeoutMs = deps.timeoutMs ?? turnTimeoutMs(env);
224
+ const spawnOptions = {
225
+ cwd: input.cwd,
226
+ env,
227
+ ...(timeoutMs !== undefined ? { timeoutMs } : {}),
228
+ ...(onStdoutLine ? { onStdoutLine } : {}),
229
+ ...(input.signal ? { signal: input.signal } : {}),
230
+ };
223
231
  let result;
224
232
  try {
225
- result = await spawnImpl(binary, args, {
226
- cwd: input.cwd,
227
- env,
228
- ...(timeoutMs !== undefined ? { timeoutMs } : {}),
229
- ...(onStdoutLine ? { onStdoutLine } : {}),
230
- ...(input.signal ? { signal: input.signal } : {}),
231
- });
233
+ result = await spawnImpl(binary, args, spawnOptions);
234
+ if (runtime.id === "grok" && result.code !== 0 && !input.signal?.aborted) {
235
+ const retryArgs = grokRetryArgsAfterInvalidOutputFormat(args, result.stderr);
236
+ if (retryArgs)
237
+ result = await spawnImpl(binary, retryArgs, spawnOptions);
238
+ }
232
239
  }
233
240
  catch (err) {
234
241
  const code = err.code;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The NDJSON stream Claude Code (`--output-format stream-json --verbose`) and
3
- * Grok (`--output-format streaming-messages-json`) both write: Anthropic
3
+ * older Grok (`--output-format streaming-messages-json`) both write: Anthropic
4
4
  * Messages wire shapes, one event per line.
5
5
  *
6
6
  * {"type":"system","subtype":"init","session_id":…}
@@ -9,9 +9,18 @@
9
9
  * {"type":"user","message":{"content":[{"type":"tool_result",…}]}}
10
10
  * {"type":"result","subtype":"success","is_error":false,"result":"<last message>","session_id":…}
11
11
  *
12
- * Recorded from Claude Code 2.1.258 and grok (model grok-4.6) on 2026-09-12;
12
+ * grok 0.2.56 dropped `streaming-messages-json` for `streaming-json`, which
13
+ * is token deltas rather than whole messages:
14
+ *
15
+ * {"type":"thought","data":…}
16
+ * {"type":"text","data":"Hi"}
17
+ * {"type":"end","stopReason":"EndTurn","sessionId":…}
18
+ *
19
+ * Text `data` chunks are concatenated for the final reply and never emitted
20
+ * as progress (they are token deltas). Recorded from Claude Code 2.1.258 and
21
+ * grok (model grok-4.6) on 2026-09-12, plus grok 0.2.56 on 2026-09-21;
13
22
  * fixtures in runtime/fixtures/. Claude sends one content block per assistant
14
- * event; Grok sends a whole message (thinking + text + tool_use) per event.
23
+ * event; older Grok sends a whole message (thinking + text + tool_use) per event.
15
24
  */
16
25
  import { type RuntimeStreamEvent, type RuntimeTurnResult } from "./types.js";
17
26
  /** Progress events in one stream line: top-level assistant text and tool starts only. */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The NDJSON stream Claude Code (`--output-format stream-json --verbose`) and
3
- * Grok (`--output-format streaming-messages-json`) both write: Anthropic
3
+ * older Grok (`--output-format streaming-messages-json`) both write: Anthropic
4
4
  * Messages wire shapes, one event per line.
5
5
  *
6
6
  * {"type":"system","subtype":"init","session_id":…}
@@ -9,9 +9,18 @@
9
9
  * {"type":"user","message":{"content":[{"type":"tool_result",…}]}}
10
10
  * {"type":"result","subtype":"success","is_error":false,"result":"<last message>","session_id":…}
11
11
  *
12
- * Recorded from Claude Code 2.1.258 and grok (model grok-4.6) on 2026-09-12;
12
+ * grok 0.2.56 dropped `streaming-messages-json` for `streaming-json`, which
13
+ * is token deltas rather than whole messages:
14
+ *
15
+ * {"type":"thought","data":…}
16
+ * {"type":"text","data":"Hi"}
17
+ * {"type":"end","stopReason":"EndTurn","sessionId":…}
18
+ *
19
+ * Text `data` chunks are concatenated for the final reply and never emitted
20
+ * as progress (they are token deltas). Recorded from Claude Code 2.1.258 and
21
+ * grok (model grok-4.6) on 2026-09-12, plus grok 0.2.56 on 2026-09-21;
13
22
  * fixtures in runtime/fixtures/. Claude sends one content block per assistant
14
- * event; Grok sends a whole message (thinking + text + tool_use) per event.
23
+ * event; older Grok sends a whole message (thinking + text + tool_use) per event.
15
24
  */
16
25
  import { parseJsonLine, RuntimeError } from "./types.js";
17
26
  /** Progress events in one stream line: top-level assistant text and tool starts only. */
@@ -48,6 +57,9 @@ export function messagesStreamEvents(line) {
48
57
  * RuntimeError for an error result, or when there is nothing usable.
49
58
  */
50
59
  export function messagesStreamResult(stdout, runtimeName) {
60
+ const token = grokTokenStreamResult(stdout, runtimeName);
61
+ if (token)
62
+ return token;
51
63
  let result = null;
52
64
  let sessionId;
53
65
  let lastText;
@@ -78,6 +90,38 @@ export function messagesStreamResult(stdout, runtimeName) {
78
90
  sessionId = result.session_id;
79
91
  return { text, sessionId };
80
92
  }
93
+ /**
94
+ * grok 0.2.56 `--output-format streaming-json`: concatenate text deltas and
95
+ * take sessionId from the terminal `end` event. Throws on `error`. Null when
96
+ * the stream is not this shape (so the Anthropic Messages parser can run).
97
+ */
98
+ function grokTokenStreamResult(stdout, runtimeName) {
99
+ let text = "";
100
+ let sessionId;
101
+ let saw = false;
102
+ for (const line of stdout.split("\n")) {
103
+ const ev = parseJsonLine(line);
104
+ if (!ev)
105
+ continue;
106
+ if (ev.type === "text" && typeof ev.data === "string") {
107
+ saw = true;
108
+ text += ev.data;
109
+ }
110
+ else if (ev.type === "thought") {
111
+ saw = true;
112
+ }
113
+ else if (ev.type === "end") {
114
+ saw = true;
115
+ if (typeof ev.sessionId === "string")
116
+ sessionId = ev.sessionId;
117
+ }
118
+ else if (ev.type === "error" && typeof ev.message === "string") {
119
+ const detail = ev.message;
120
+ throw new RuntimeError(`${runtimeName} reported an error: ${detail.slice(0, 200)}`, detail.slice(0, 400), null);
121
+ }
122
+ }
123
+ return saw ? { text, sessionId } : null;
124
+ }
81
125
  /** The error text of an `is_error` result event, if the stream has one. */
82
126
  export function messagesStreamFailure(stdout) {
83
127
  let reason;
@@ -85,6 +129,8 @@ export function messagesStreamFailure(stdout) {
85
129
  const ev = parseJsonLine(line);
86
130
  if (ev?.type === "result" && ev.is_error === true && typeof ev.result === "string" && ev.result.trim())
87
131
  reason = ev.result.trim();
132
+ if (ev?.type === "error" && typeof ev.message === "string" && ev.message.trim())
133
+ reason = ev.message.trim();
88
134
  }
89
135
  return reason;
90
136
  }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Provider account resolution (spec §5.5).
3
+ *
4
+ * Naming an account and omitting one mean different things: an explicit
5
+ * disabled id is refused; omitting picks the least-loaded eligible account.
6
+ * Status reports `configured` and `logged_in` separately. logged_in is
7
+ * derived from whether a provider credential file EXISTS — this module
8
+ * never reads, prints, copies, or hashes that file.
9
+ */
10
+ import { type LaneRecord, type LaneProvider } from "./types.js";
11
+ import type { LanesConfig } from "./types.js";
12
+ export declare const PROVIDER_HOME_ENV: Record<LaneProvider, string>;
13
+ export declare const AUTH_JSON_NAME = "auth.json";
14
+ export declare const CLAUDE_CREDENTIALS_NAME = ".credentials.json";
15
+ /**
16
+ * Credential filenames are a property of the provider. Codex and Grok write
17
+ * auth.json. Claude Code writes .credentials.json (never auth.json) inside
18
+ * the config dir, and can also authenticate via the OS keychain with no
19
+ * file here at all.
20
+ */
21
+ export declare const PROVIDER_CREDENTIAL_FILES: Record<LaneProvider, readonly string[]>;
22
+ export type AuthState = "file" | "absent" | "unknown";
23
+ export interface AccountDeps {
24
+ existsSync: (p: string) => boolean;
25
+ }
26
+ export interface AccountResolveContext {
27
+ hqRoot?: string;
28
+ existsSync?: (p: string) => boolean;
29
+ loadLanes?: (hqRoot: string) => LaneRecord[];
30
+ /** Already-resolved model for this lane. Beats cliModel and account defaults. */
31
+ model?: string;
32
+ /** `--model` from create, applied to every candidate account. */
33
+ cliModel?: string;
34
+ now?: Date;
35
+ }
36
+ export interface ResolvedAccount {
37
+ provider: LaneProvider;
38
+ id: string;
39
+ home: string;
40
+ enabled: true;
41
+ envVar: string;
42
+ }
43
+ export interface AccountStatus {
44
+ provider: LaneProvider;
45
+ id: string;
46
+ home: string;
47
+ enabled: boolean;
48
+ disabled_reason?: string;
49
+ /** Present in personal/lanes/config.json. */
50
+ configured: boolean;
51
+ /**
52
+ * True when a provider credential file exists. False only when every
53
+ * candidate is absent AND absence is conclusive for that provider
54
+ * (Codex, Grok). Null for Claude when no candidate exists: Claude can
55
+ * authenticate via keychain, so a missing file is not logged-out.
56
+ * Never inspects file contents.
57
+ */
58
+ logged_in: boolean | null;
59
+ auth_state: AuthState;
60
+ envVar: string;
61
+ }
62
+ export declare function credentialPaths(provider: LaneProvider, home: string): string[];
63
+ /**
64
+ * Existence-only probe. Callers must not read the files this returns paths to.
65
+ */
66
+ export declare function hasCredentialFile(provider: LaneProvider, home: string, existsSync: (p: string) => boolean): boolean;
67
+ /**
68
+ * Claude with no file in the config dir is unknown, not logged out: the
69
+ * credential may live in the OS keychain or an API-key helper. Codex and
70
+ * Grok write auth.json when logged in, so absence is logged out.
71
+ */
72
+ export declare function authStateFor(provider: LaneProvider, present: boolean): AuthState;
73
+ export declare function loggedInFromAuthState(state: AuthState): boolean | null;
74
+ /** Admission and listing share this: refuse only a conclusive logged-out. */
75
+ export declare function isLoggedOut(status: Pick<AccountStatus, "logged_in">): boolean;
76
+ /** Auto-select requires a proven credential file, not Claude-unknown. */
77
+ export declare function isCredentialProven(status: Pick<AccountStatus, "logged_in">): boolean;
78
+ /**
79
+ * Occupying states hold a slot: running / awaiting_input / blocked have a
80
+ * live (or paused-live) worker; queued holds a queue slot that will take a
81
+ * running slot. Terminal states do not count.
82
+ */
83
+ export declare function isOccupyingLaneState(state: LaneRecord["state"]): boolean;
84
+ export declare function occupyingLaneCount(lanes: readonly LaneRecord[], provider: LaneProvider, accountId: string): number;
85
+ export declare function runningLaneCount(lanes: readonly LaneRecord[], provider: LaneProvider, accountId: string): number;
86
+ /** Most recent created_at on this account+provider, any state. Null if none. */
87
+ export declare function lastStartedAt(lanes: readonly LaneRecord[], provider: LaneProvider, accountId: string): string | null;
88
+ /**
89
+ * Pick among enabled, credential-proven accounts by occupying count
90
+ * (lowest wins). Ties break to least-recently-started (oldest created_at),
91
+ * then account id ascending. Accounts at max_running are excluded from
92
+ * start-eligible; if every proven account is at cap the pick still returns
93
+ * one so admission can queue rather than overflow.
94
+ */
95
+ export declare function selectBalancedAccount(provider: LaneProvider, config: LanesConfig, ctx?: AccountResolveContext): ResolvedAccount;
96
+ export declare function resolveAccount(provider: LaneProvider, requestedId: string | undefined, config: LanesConfig, ctx?: AccountResolveContext): ResolvedAccount;
97
+ /** Codex/Grok path. Kept for callers that still name auth.json. */
98
+ export declare function authJsonPath(home: string): string;
99
+ export declare function accountStatus(provider: LaneProvider, accountId: string, config: LanesConfig, deps?: AccountDeps): AccountStatus;
100
+ export declare function listAccountStatuses(provider: LaneProvider, config: LanesConfig, deps?: AccountDeps): AccountStatus[];
101
+ /** Environment assignment the worker process should receive. */
102
+ export declare function accountEnv(resolved: ResolvedAccount): Record<string, string>;
103
+ //# sourceMappingURL=accounts.d.ts.map