@indigoai-us/hq-cli 5.134.0 → 5.136.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 (38) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/command-catalog.generated.d.ts +71 -0
  3. package/dist/command-catalog.generated.js +93 -0
  4. package/dist/commands/bot-jobs.d.ts +127 -0
  5. package/dist/commands/bot-jobs.js +445 -0
  6. package/dist/commands/bot.js +3 -0
  7. package/dist/commands/lanes.d.ts +4 -2
  8. package/dist/commands/lanes.js +150 -2
  9. package/dist/lib/bot/api.d.ts +66 -0
  10. package/dist/lib/bot/api.js +38 -0
  11. package/dist/lib/bot/index.d.ts +3 -0
  12. package/dist/lib/bot/index.js +3 -0
  13. package/dist/lib/bot/inflight.d.ts +42 -0
  14. package/dist/lib/bot/job-completions.d.ts +91 -0
  15. package/dist/lib/bot/job-completions.js +132 -0
  16. package/dist/lib/bot/job-run.d.ts +109 -0
  17. package/dist/lib/bot/job-run.js +246 -0
  18. package/dist/lib/bot/paths.d.ts +9 -1
  19. package/dist/lib/bot/paths.js +14 -0
  20. package/dist/lib/bot/prompt.d.ts +12 -0
  21. package/dist/lib/bot/prompt.js +31 -0
  22. package/dist/lib/bot/room-policy.d.ts +18 -1
  23. package/dist/lib/bot/room-policy.js +20 -2
  24. package/dist/lib/bot/run.d.ts +23 -1
  25. package/dist/lib/bot/run.js +404 -7
  26. package/dist/lib/lanes/config.d.ts +7 -0
  27. package/dist/lib/lanes/config.js +28 -1
  28. package/dist/lib/lanes/index.d.ts +5 -1
  29. package/dist/lib/lanes/index.js +3 -1
  30. package/dist/lib/lanes/monitor.d.ts +48 -0
  31. package/dist/lib/lanes/monitor.js +409 -0
  32. package/dist/lib/lanes/spawn.d.ts +10 -1
  33. package/dist/lib/lanes/spawn.js +60 -5
  34. package/dist/lib/lanes/types.d.ts +6 -0
  35. package/dist/lib/lanes/types.js +1 -1
  36. package/dist/lib/lanes/watch.d.ts +22 -0
  37. package/dist/lib/lanes/watch.js +122 -0
  38. package/package.json +1 -1
@@ -5,7 +5,7 @@ export { AccountResolutionError, LaneNotFoundError, LaneSchemaError, LaneVersion
5
5
  export { MAX_LANE_DEPTH } from "./constants.js";
6
6
  export { CONFIG_SCHEMA_VERSION, ENVELOPE_DECISIONS, ENVELOPE_SCHEMA_VERSION, HISTORY_CAP, HOST_KINDS, LANE_PROVIDERS, LANE_SCHEMA_VERSION, LANE_STATES, LIVENESS_STATES, QUESTION_BODY_STORES, QUESTION_SCHEMA_VERSION, QUESTION_STATUSES, QUEUED_REASONS, RAISED_VIA, ROUTING_REASONS, SENIOR_KINDS, STORY_STATUSES, TERMINAL_LANE_STATES, isEnvelopeDecision, isHostKind, isLaneProvider, isLaneState, isLivenessState, isQuestionStatus, isSeniorKind, isTerminalLaneState, parseLaneEnvelope, parseLaneProvider, parseLaneState, parseLivenessState, parseMajorSchema, parseQuestionStatus, parseSeniorKind, } from "./types.js";
7
7
  export type { AccountConfig, AttributionHistoryEntry, EnvelopeDecision, EnvelopeQuestion, HostKind, LaneCompanyRef, LaneEnvelope, LaneHost, LaneProvider, LaneRecord, PendingResume, AccountHistoryEntry, LaneState, LanesConfig, LastEnvelopeRef, LivenessState, LivenessWindows, ProviderConfig, QuestionAnswer, QuestionBodyRef, QuestionRecord, QuestionStatus, QueuedReason, RaisedVia, RoutingHistoryEntry, RoutingReason, SeniorHistoryEntry, SeniorKind, SeniorRef, StoryStatus, TerminalLaneState, ThrottleConfig, } from "./types.js";
8
- export { DEFAULT_ACCOUNT_HOMES, DEFAULT_COMPACT_AFTER_MS, DEFAULT_CPU_BUSY_PAUSE, DEFAULT_CPU_BUSY_RESUME, DEFAULT_LIVE_WITHIN_MS, DEFAULT_LIVENESS_WINDOWS, DEFAULT_MAX_QUEUED, DEFAULT_MIN_AVAILABLE_MEM_MB, DEFAULT_PROVIDER_MAX_RUNNING, DEFAULT_SILENT_LOST_MS, DEFAULT_TURN_START_LOST_MS, LANES_CONFIG_REL, accountMaxRunning, canonicalizeHome, documentedDefaultConfig, expandHome, lanesConfigPath, loadLanesConfig, parseLanesConfig, providerCompactAfterMs, providerQuotaDefaultHoldMs, DEFAULT_QUOTA_HOLD_MS, writeLanesConfig, } from "./config.js";
8
+ export { DEFAULT_ACCOUNT_HOMES, DEFAULT_AUTO_COMPACT_TOKENS, DEFAULT_COMPACT_AFTER_MS, DEFAULT_CPU_BUSY_PAUSE, DEFAULT_CPU_BUSY_RESUME, DEFAULT_LIVE_WITHIN_MS, DEFAULT_LIVENESS_WINDOWS, DEFAULT_MAX_QUEUED, DEFAULT_MIN_AVAILABLE_MEM_MB, DEFAULT_PROVIDER_MAX_RUNNING, DEFAULT_SILENT_LOST_MS, DEFAULT_TURN_START_LOST_MS, LANES_CONFIG_REL, accountMaxRunning, canonicalizeHome, documentedDefaultConfig, expandHome, lanesConfigPath, loadLanesConfig, parseLanesConfig, providerCompactAfterMs, providerAutoCompactTokens, providerQuotaDefaultHoldMs, DEFAULT_QUOTA_HOLD_MS, writeLanesConfig, } from "./config.js";
9
9
  export type { ConfigLoadDeps, ConfigWriteDeps } from "./config.js";
10
10
  export { resolveLanesHqRoot } from "./hq-root.js";
11
11
  export type { LanesHqRootOpts } from "./hq-root.js";
@@ -13,6 +13,10 @@ export { buildOutpostPickupCommand, parseOutpostPickupPayload, } from "./outpost
13
13
  export type { OutpostDispatchResult, OutpostPickupPayload, } from "./outpost-dispatch.js";
14
14
  export { LANES_STORE_REL, LANE_RECORDS_DIR, PENDING_INDEX_DIR, QUESTION_RECORDS_DIR, appendCappedHistory, appendLaneAttribution, appendLaneSeniorHistory, appendQuestionRouting, createLane, createQuestion, isConflictSidecarName, laneRecordPath, lanesStoreRoot, listLaneIds, listQuestionIds, mergeLaneRecords, mergeQuestionRecords, mintLaneId, mintQuestionId, parseLaneRecord, parseQuestionRecord, pendingMarkerPath, questionRecordPath, readLane, readQuestion, resolveStoreHqRoot, sanitizeHostComponent, tryReadLane, tryReadQuestion, retryUpdateLane, retryUpdateQuestion, updateLane, updateQuestion, } from "./store.js";
15
15
  export type { StoreDeps } from "./store.js";
16
+ export { DEFAULT_LANE_WATCH_INTERVAL_MS, MAX_LANE_WATCH_INTERVAL_MS, MAX_WATCHED_LANES, MAX_WATCH_OUTPUT_LINES, runLaneWatch, } from "./watch.js";
17
+ export type { LaneWatchDeps, LaneWatchResult } from "./watch.js";
18
+ export { MONITOR_ERROR_EXIT_CODE, MONITOR_ENGINES, MONITOR_MAX_TIMEOUT_MS, MONITOR_TASK_OUTPUT_MAX_BYTES, MONITOR_TRANSCRIPT_MAX_BYTES, MONITOR_UNCOVERED_EXIT_CODE, coveredLaneIds, isMonitorTaskLive, monitorReminderText, parseCanonicalWatchCommand, parseMonitorTranscript, readLiveMonitorEvidence, } from "./monitor.js";
19
+ export type { LiveMonitorEvidenceOptions, MonitorEngine, MonitorEvidence, MonitorEvidenceReader, MonitorTaskEvidence, } from "./monitor.js";
16
20
  export { IMDS_HOST, IMDS_INSTANCE_ID_URL, IMDS_TIMEOUT_MS, IMDS_TOKEN_URL, defaultReadImdsInstanceId, resolveMachineIdentity, } from "./machine-identity.js";
17
21
  export type { MachineIdentity, MachineIdentityDeps } from "./machine-identity.js";
18
22
  export { LANES_RUNS_REL as SPAWN_LANES_RUNS_REL, PID_LIVENESS_DECISIONS, PROVIDER_COMMAND, PROVIDER_MODEL_FLAG, SPAWN_TERMINAL_REASONS, ANSWERED_QUESTIONS_FILE, appendModelFlag, armLaneWatcher, buildProviderCommand, parseCliModel, resolveLaneModel, defaultProveDetached, isPidRecordAlive, laneRunDir, missingPidProbe, nextEnvelopePath, markSpawnFailure, parsePidRecord, parseProcStat, parseSpawnTerminalReason, probePidRecord, readPidRecord, readProcStarttime, readProcStarttimeDetailed, readSpawnManifest, resumePrompt, envelopeInstruction, spawnLaneWorker, stopLaneProcesses, watcherMainPath, workerEnv, } from "./spawn.js";
@@ -4,10 +4,12 @@
4
4
  export { AccountResolutionError, LaneNotFoundError, LaneSchemaError, LaneVersionConflict, LanesConfigError, LanesError, WorkerResolutionError, isLaneVersionConflict, isLanesError, } from "./errors.js";
5
5
  export { MAX_LANE_DEPTH } from "./constants.js";
6
6
  export { CONFIG_SCHEMA_VERSION, ENVELOPE_DECISIONS, ENVELOPE_SCHEMA_VERSION, HISTORY_CAP, HOST_KINDS, LANE_PROVIDERS, LANE_SCHEMA_VERSION, LANE_STATES, LIVENESS_STATES, QUESTION_BODY_STORES, QUESTION_SCHEMA_VERSION, QUESTION_STATUSES, QUEUED_REASONS, RAISED_VIA, ROUTING_REASONS, SENIOR_KINDS, STORY_STATUSES, TERMINAL_LANE_STATES, isEnvelopeDecision, isHostKind, isLaneProvider, isLaneState, isLivenessState, isQuestionStatus, isSeniorKind, isTerminalLaneState, parseLaneEnvelope, parseLaneProvider, parseLaneState, parseLivenessState, parseMajorSchema, parseQuestionStatus, parseSeniorKind, } from "./types.js";
7
- export { DEFAULT_ACCOUNT_HOMES, DEFAULT_COMPACT_AFTER_MS, DEFAULT_CPU_BUSY_PAUSE, DEFAULT_CPU_BUSY_RESUME, DEFAULT_LIVE_WITHIN_MS, DEFAULT_LIVENESS_WINDOWS, DEFAULT_MAX_QUEUED, DEFAULT_MIN_AVAILABLE_MEM_MB, DEFAULT_PROVIDER_MAX_RUNNING, DEFAULT_SILENT_LOST_MS, DEFAULT_TURN_START_LOST_MS, LANES_CONFIG_REL, accountMaxRunning, canonicalizeHome, documentedDefaultConfig, expandHome, lanesConfigPath, loadLanesConfig, parseLanesConfig, providerCompactAfterMs, providerQuotaDefaultHoldMs, DEFAULT_QUOTA_HOLD_MS, writeLanesConfig, } from "./config.js";
7
+ export { DEFAULT_ACCOUNT_HOMES, DEFAULT_AUTO_COMPACT_TOKENS, DEFAULT_COMPACT_AFTER_MS, DEFAULT_CPU_BUSY_PAUSE, DEFAULT_CPU_BUSY_RESUME, DEFAULT_LIVE_WITHIN_MS, DEFAULT_LIVENESS_WINDOWS, DEFAULT_MAX_QUEUED, DEFAULT_MIN_AVAILABLE_MEM_MB, DEFAULT_PROVIDER_MAX_RUNNING, DEFAULT_SILENT_LOST_MS, DEFAULT_TURN_START_LOST_MS, LANES_CONFIG_REL, accountMaxRunning, canonicalizeHome, documentedDefaultConfig, expandHome, lanesConfigPath, loadLanesConfig, parseLanesConfig, providerCompactAfterMs, providerAutoCompactTokens, providerQuotaDefaultHoldMs, DEFAULT_QUOTA_HOLD_MS, writeLanesConfig, } from "./config.js";
8
8
  export { resolveLanesHqRoot } from "./hq-root.js";
9
9
  export { buildOutpostPickupCommand, parseOutpostPickupPayload, } from "./outpost-dispatch.js";
10
10
  export { LANES_STORE_REL, LANE_RECORDS_DIR, PENDING_INDEX_DIR, QUESTION_RECORDS_DIR, appendCappedHistory, appendLaneAttribution, appendLaneSeniorHistory, appendQuestionRouting, createLane, createQuestion, isConflictSidecarName, laneRecordPath, lanesStoreRoot, listLaneIds, listQuestionIds, mergeLaneRecords, mergeQuestionRecords, mintLaneId, mintQuestionId, parseLaneRecord, parseQuestionRecord, pendingMarkerPath, questionRecordPath, readLane, readQuestion, resolveStoreHqRoot, sanitizeHostComponent, tryReadLane, tryReadQuestion, retryUpdateLane, retryUpdateQuestion, updateLane, updateQuestion, } from "./store.js";
11
+ export { DEFAULT_LANE_WATCH_INTERVAL_MS, MAX_LANE_WATCH_INTERVAL_MS, MAX_WATCHED_LANES, MAX_WATCH_OUTPUT_LINES, runLaneWatch, } from "./watch.js";
12
+ export { MONITOR_ERROR_EXIT_CODE, MONITOR_ENGINES, MONITOR_MAX_TIMEOUT_MS, MONITOR_TASK_OUTPUT_MAX_BYTES, MONITOR_TRANSCRIPT_MAX_BYTES, MONITOR_UNCOVERED_EXIT_CODE, coveredLaneIds, isMonitorTaskLive, monitorReminderText, parseCanonicalWatchCommand, parseMonitorTranscript, readLiveMonitorEvidence, } from "./monitor.js";
11
13
  export { IMDS_HOST, IMDS_INSTANCE_ID_URL, IMDS_TIMEOUT_MS, IMDS_TOKEN_URL, defaultReadImdsInstanceId, resolveMachineIdentity, } from "./machine-identity.js";
12
14
  export { LANES_RUNS_REL as SPAWN_LANES_RUNS_REL, PID_LIVENESS_DECISIONS, PROVIDER_COMMAND, PROVIDER_MODEL_FLAG, SPAWN_TERMINAL_REASONS, ANSWERED_QUESTIONS_FILE, appendModelFlag, armLaneWatcher, buildProviderCommand, parseCliModel, resolveLaneModel, defaultProveDetached, isPidRecordAlive, laneRunDir, missingPidProbe, nextEnvelopePath, markSpawnFailure, parsePidRecord, parseProcStat, parseSpawnTerminalReason, probePidRecord, readPidRecord, readProcStarttime, readProcStarttimeDetailed, readSpawnManifest, resumePrompt, envelopeInstruction, spawnLaneWorker, stopLaneProcesses, watcherMainPath, workerEnv, } from "./spawn.js";
13
15
  export { SILENCE_MS, WATCHER_DECISION_EVENTS, WATCHER_OUT_MAX_BYTES, WATCHER_POLL_MS, WATCHER_SIGNAL_KINDS, appendCappedLog, appendWatcherSignal, applyTerminalToLane, classifyLaneExit, clearLaneStalled, isPidAlive, laneIdentityFromRecord, markLaneStalled, notifySlotFreed, parseWatcherSignalKind, readLatestEnvelope, runWatcherLoop, stalledReason, tickWatcher, watcherEventsPath, watcherLastSignalPath, watcherOutLogPath, writeWatcherDecision, } from "./watcher.js";
@@ -0,0 +1,48 @@
1
+ export declare const MONITOR_MAX_TIMEOUT_MS = 1800000;
2
+ export declare const MONITOR_UNCOVERED_EXIT_CODE = 2;
3
+ export declare const MONITOR_ERROR_EXIT_CODE = 3;
4
+ export declare const MONITOR_TRANSCRIPT_MAX_BYTES: number;
5
+ export declare const MONITOR_TASK_OUTPUT_MAX_BYTES: number;
6
+ export type MonitorEngine = "claude" | "codex" | "grok";
7
+ export declare const MONITOR_ENGINES: readonly MonitorEngine[];
8
+ export interface MonitorTaskEvidence {
9
+ taskId: string;
10
+ command: string;
11
+ startedAt: string;
12
+ timeoutMs: number;
13
+ persistent?: boolean;
14
+ stopped?: boolean;
15
+ outputPresent: boolean;
16
+ outputText?: string;
17
+ processAlive?: boolean;
18
+ outputPath?: string;
19
+ }
20
+ export interface MonitorEvidence {
21
+ sessionId: string;
22
+ tasks: readonly MonitorTaskEvidence[];
23
+ transcriptPaths?: readonly string[];
24
+ taskOutputPaths?: readonly string[];
25
+ processCommands?: readonly string[];
26
+ }
27
+ export interface LiveMonitorEvidenceOptions {
28
+ homedir?: () => string;
29
+ env?: NodeJS.ProcessEnv;
30
+ now?: () => Date;
31
+ transcriptMaxBytes?: number;
32
+ taskOutputMaxBytes?: number;
33
+ readProcessCommands?: () => readonly string[];
34
+ }
35
+ /**
36
+ * Parse only the JSONL shape emitted by Claude Code's Monitor tool. The
37
+ * caller supplies a bounded tail; malformed or partial lines are ignored so a
38
+ * torn final write cannot turn into positive liveness evidence.
39
+ */
40
+ export declare function parseMonitorTranscript(text: string): MonitorTaskEvidence[];
41
+ /** Return argv only for the exact command form the gate arms. */
42
+ export declare function parseCanonicalWatchCommand(command: string): string[] | null;
43
+ export declare function isMonitorTaskLive(task: MonitorTaskEvidence, now: Date): boolean;
44
+ export declare function coveredLaneIds(evidence: MonitorEvidence, now: Date): Set<string>;
45
+ export declare function readLiveMonitorEvidence(sessionId: string, options?: LiveMonitorEvidenceOptions): MonitorEvidence;
46
+ export type MonitorEvidenceReader = (sessionId: string) => MonitorEvidence | Promise<MonitorEvidence>;
47
+ export declare function monitorReminderText(): string;
48
+ //# sourceMappingURL=monitor.d.ts.map
@@ -0,0 +1,409 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import * as fs from "node:fs";
3
+ import * as os from "node:os";
4
+ import * as path from "node:path";
5
+ import { LanesError } from "./errors.js";
6
+ export const MONITOR_MAX_TIMEOUT_MS = 1_800_000;
7
+ export const MONITOR_UNCOVERED_EXIT_CODE = 2;
8
+ export const MONITOR_ERROR_EXIT_CODE = 3;
9
+ export const MONITOR_TRANSCRIPT_MAX_BYTES = 512 * 1024;
10
+ export const MONITOR_TASK_OUTPUT_MAX_BYTES = 64 * 1024;
11
+ const SESSION_ID_PATTERN = /^[A-Za-z0-9._-]+$/;
12
+ const LANE_ID_PATTERN = /^[A-Za-z0-9_][A-Za-z0-9._-]*$/;
13
+ const TERMINAL_TASK_OUTPUT = /(?:\[(?:exited|killed|terminated|stopped)(?:\b|\])|task\s+(?:stopped|killed)|monitor\s+(?:stopped|expired))/i;
14
+ export const MONITOR_ENGINES = [
15
+ "claude",
16
+ "codex",
17
+ "grok",
18
+ ];
19
+ function stringValue(value) {
20
+ return typeof value === "string" && value.length > 0 ? value : undefined;
21
+ }
22
+ function numberValue(value) {
23
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
24
+ }
25
+ function contentText(content) {
26
+ if (typeof content === "string")
27
+ return content;
28
+ if (!Array.isArray(content))
29
+ return "";
30
+ return content
31
+ .map((item) => {
32
+ if (typeof item === "string")
33
+ return item;
34
+ if (item && typeof item === "object") {
35
+ const text = item.text;
36
+ const contentValue = item.content;
37
+ return typeof text === "string"
38
+ ? text
39
+ : typeof contentValue === "string"
40
+ ? contentValue
41
+ : "";
42
+ }
43
+ return "";
44
+ })
45
+ .join("\n");
46
+ }
47
+ function toolUseBlocks(row) {
48
+ const message = row.message;
49
+ if (!message || typeof message !== "object")
50
+ return [];
51
+ const content = message.content;
52
+ if (!Array.isArray(content))
53
+ return [];
54
+ return content.filter((item) => Boolean(item && typeof item === "object" && item.type === "tool_use"));
55
+ }
56
+ function toolResultText(row) {
57
+ const message = row.message;
58
+ if (!message || typeof message !== "object")
59
+ return "";
60
+ return contentText(message.content);
61
+ }
62
+ function toolResultUseId(row) {
63
+ const message = row.message;
64
+ if (!message || typeof message !== "object")
65
+ return undefined;
66
+ const content = message.content;
67
+ if (!Array.isArray(content))
68
+ return undefined;
69
+ for (const item of content) {
70
+ if (!item || typeof item !== "object")
71
+ continue;
72
+ const block = item;
73
+ if (block.type === "tool_result") {
74
+ return stringValue(block.tool_use_id) ?? stringValue(block.toolUseId);
75
+ }
76
+ }
77
+ return undefined;
78
+ }
79
+ function monitorTaskId(text) {
80
+ const match = /\btask\s+([A-Za-z0-9_-]+)\b/i.exec(text);
81
+ return match?.[1];
82
+ }
83
+ function isMissingFilesystemEntry(err) {
84
+ if (!err || typeof err !== "object")
85
+ return false;
86
+ const code = err.code;
87
+ return code === "ENOENT" || code === "ENOTDIR";
88
+ }
89
+ function monitorEvidenceUnreadable(filePath, err) {
90
+ const cause = err instanceof Error ? err.message : String(err);
91
+ return new LanesError("monitor_evidence_unreadable", `Unable to read monitor evidence ${filePath}: ${cause}`, { path: filePath, cause });
92
+ }
93
+ /**
94
+ * Parse only the JSONL shape emitted by Claude Code's Monitor tool. The
95
+ * caller supplies a bounded tail; malformed or partial lines are ignored so a
96
+ * torn final write cannot turn into positive liveness evidence.
97
+ */
98
+ export function parseMonitorTranscript(text) {
99
+ const pending = [];
100
+ const stoppedIds = new Set();
101
+ for (const line of text.split("\n")) {
102
+ if (line.length === 0)
103
+ continue;
104
+ let row;
105
+ try {
106
+ const parsed = JSON.parse(line);
107
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
108
+ continue;
109
+ row = parsed;
110
+ }
111
+ catch {
112
+ continue;
113
+ }
114
+ for (const block of toolUseBlocks(row)) {
115
+ const name = stringValue(block.name);
116
+ const input = block.input;
117
+ const inputObject = input && typeof input === "object" && !Array.isArray(input)
118
+ ? input
119
+ : {};
120
+ if (name === "Monitor") {
121
+ const command = stringValue(inputObject.command);
122
+ const startedAt = stringValue(row.timestamp);
123
+ const timeoutMs = numberValue(inputObject.timeout_ms);
124
+ if (command && startedAt && timeoutMs && timeoutMs > 0) {
125
+ pending.push({
126
+ command,
127
+ startedAt,
128
+ timeoutMs,
129
+ toolUseId: stringValue(block.id),
130
+ persistent: typeof inputObject.persistent === "boolean"
131
+ ? inputObject.persistent
132
+ : undefined,
133
+ });
134
+ }
135
+ }
136
+ else if (name === "TaskStop") {
137
+ const taskId = stringValue(inputObject.task_id) ?? stringValue(inputObject.taskId);
138
+ if (taskId)
139
+ stoppedIds.add(taskId);
140
+ }
141
+ }
142
+ const toolUseResult = row.toolUseResult;
143
+ if (toolUseResult &&
144
+ typeof toolUseResult === "object" &&
145
+ !Array.isArray(toolUseResult)) {
146
+ const result = toolUseResult;
147
+ const taskId = stringValue(result.taskId) ??
148
+ stringValue(result.task_id) ??
149
+ monitorTaskId(toolResultText(row));
150
+ const resultUseId = toolResultUseId(row);
151
+ const candidate = resultUseId
152
+ ? pending.find((item) => item.taskId === undefined && item.toolUseId === resultUseId)
153
+ : pending.find((item) => item.taskId === undefined);
154
+ if (taskId && candidate) {
155
+ candidate.taskId = taskId;
156
+ candidate.timeoutMs =
157
+ numberValue(result.timeoutMs) ?? candidate.timeoutMs;
158
+ if (typeof result.persistent === "boolean") {
159
+ candidate.persistent = result.persistent;
160
+ }
161
+ const file = result.file;
162
+ if (file && typeof file === "object" && !Array.isArray(file)) {
163
+ candidate.outputPath = stringValue(file.filePath);
164
+ }
165
+ }
166
+ }
167
+ else {
168
+ const taskId = monitorTaskId(toolResultText(row));
169
+ const resultUseId = toolResultUseId(row);
170
+ const candidate = resultUseId
171
+ ? pending.find((item) => item.taskId === undefined && item.toolUseId === resultUseId)
172
+ : pending.find((item) => item.taskId === undefined);
173
+ if (taskId && candidate)
174
+ candidate.taskId = taskId;
175
+ }
176
+ }
177
+ return pending
178
+ .filter((item) => Boolean(item.taskId))
179
+ .map((item) => ({
180
+ taskId: item.taskId,
181
+ command: item.command,
182
+ startedAt: item.startedAt,
183
+ timeoutMs: item.timeoutMs,
184
+ persistent: item.persistent,
185
+ stopped: item.stopped || stoppedIds.has(item.taskId),
186
+ outputPresent: false,
187
+ outputPath: item.outputPath,
188
+ }));
189
+ }
190
+ /** Return argv only for the exact command form the gate arms. */
191
+ export function parseCanonicalWatchCommand(command) {
192
+ const tokens = command.trim().split(/\s+/u);
193
+ if (tokens.length < 4)
194
+ return null;
195
+ const executable = path.basename(tokens[0]);
196
+ if (executable !== "hq" || tokens[1] !== "lanes" || tokens[2] !== "watch") {
197
+ return null;
198
+ }
199
+ const laneIds = tokens.slice(3);
200
+ if (laneIds.some((laneId) => !LANE_ID_PATTERN.test(laneId)))
201
+ return null;
202
+ return laneIds;
203
+ }
204
+ function taskOutputIsTerminal(outputText) {
205
+ return outputText ? TERMINAL_TASK_OUTPUT.test(outputText) : false;
206
+ }
207
+ export function isMonitorTaskLive(task, now) {
208
+ if (task.stopped || task.processAlive !== true)
209
+ return false;
210
+ if (taskOutputIsTerminal(task.outputText))
211
+ return false;
212
+ const startedAt = Date.parse(task.startedAt);
213
+ if (!Number.isFinite(startedAt) || !Number.isFinite(task.timeoutMs) || task.timeoutMs <= 0) {
214
+ return false;
215
+ }
216
+ const deadline = startedAt + Math.min(task.timeoutMs, MONITOR_MAX_TIMEOUT_MS);
217
+ return now.getTime() < deadline;
218
+ }
219
+ export function coveredLaneIds(evidence, now) {
220
+ const covered = new Set();
221
+ for (const task of evidence.tasks) {
222
+ if (!isMonitorTaskLive(task, now))
223
+ continue;
224
+ const laneIds = parseCanonicalWatchCommand(task.command);
225
+ if (!laneIds)
226
+ continue;
227
+ for (const laneId of laneIds)
228
+ covered.add(laneId);
229
+ }
230
+ return covered;
231
+ }
232
+ function boundedTail(filePath, maxBytes) {
233
+ let fd;
234
+ let content = null;
235
+ let failure;
236
+ try {
237
+ const stat = fs.statSync(filePath);
238
+ const size = Math.min(stat.size, maxBytes);
239
+ fd = fs.openSync(filePath, "r");
240
+ const buffer = Buffer.alloc(size);
241
+ fs.readSync(fd, buffer, 0, size, Math.max(0, stat.size - size));
242
+ content = buffer.toString("utf8");
243
+ }
244
+ catch (err) {
245
+ if (!isMissingFilesystemEntry(err))
246
+ failure = monitorEvidenceUnreadable(filePath, err);
247
+ }
248
+ if (fd !== undefined) {
249
+ try {
250
+ fs.closeSync(fd);
251
+ }
252
+ catch (err) {
253
+ if (!isMissingFilesystemEntry(err) && !failure) {
254
+ failure = monitorEvidenceUnreadable(filePath, err);
255
+ }
256
+ }
257
+ }
258
+ if (failure)
259
+ throw failure;
260
+ return content;
261
+ }
262
+ function configDirs(home, env) {
263
+ const found = new Set();
264
+ const configured = env.CLAUDE_CONFIG_DIR?.trim() || path.join(home, ".claude");
265
+ found.add(configured);
266
+ try {
267
+ for (const name of fs.readdirSync(home)) {
268
+ if (name === ".claude" || name.startsWith(".claude-")) {
269
+ found.add(path.join(home, name));
270
+ found.add(path.join(home, name, ".claude"));
271
+ }
272
+ }
273
+ }
274
+ catch (err) {
275
+ if (!isMissingFilesystemEntry(err))
276
+ throw monitorEvidenceUnreadable(home, err);
277
+ }
278
+ const accountRoot = path.join(home, ".claude-accounts");
279
+ try {
280
+ for (const account of fs.readdirSync(accountRoot)) {
281
+ found.add(path.join(accountRoot, account, ".claude"));
282
+ }
283
+ }
284
+ catch (err) {
285
+ if (!isMissingFilesystemEntry(err))
286
+ throw monitorEvidenceUnreadable(accountRoot, err);
287
+ }
288
+ return [...found];
289
+ }
290
+ function transcriptPathsFor(home, env, sessionId) {
291
+ const paths = [];
292
+ for (const configDir of configDirs(home, env)) {
293
+ const projectsDir = path.join(configDir, "projects");
294
+ let projectDirs;
295
+ try {
296
+ projectDirs = fs.readdirSync(projectsDir);
297
+ }
298
+ catch (err) {
299
+ if (!isMissingFilesystemEntry(err))
300
+ throw monitorEvidenceUnreadable(projectsDir, err);
301
+ continue;
302
+ }
303
+ for (const projectDir of projectDirs) {
304
+ const candidate = path.join(projectsDir, projectDir, `${sessionId}.jsonl`);
305
+ try {
306
+ if (fs.statSync(candidate).isFile())
307
+ paths.push(candidate);
308
+ }
309
+ catch (err) {
310
+ if (!isMissingFilesystemEntry(err))
311
+ throw monitorEvidenceUnreadable(candidate, err);
312
+ }
313
+ }
314
+ }
315
+ return [...new Set(paths)];
316
+ }
317
+ function taskOutputCandidates(transcriptPath, sessionId, task) {
318
+ const candidates = [];
319
+ if (task.outputPath)
320
+ candidates.push(task.outputPath);
321
+ const projectDir = path.basename(path.dirname(transcriptPath));
322
+ try {
323
+ for (const tempName of fs.readdirSync(os.tmpdir())) {
324
+ if (!tempName.startsWith("claude-"))
325
+ continue;
326
+ candidates.push(path.join(os.tmpdir(), tempName, projectDir, sessionId, "tasks", `${task.taskId}.output`));
327
+ }
328
+ }
329
+ catch (err) {
330
+ if (!isMissingFilesystemEntry(err))
331
+ throw monitorEvidenceUnreadable(os.tmpdir(), err);
332
+ }
333
+ return [...new Set(candidates)];
334
+ }
335
+ function defaultProcessCommands() {
336
+ try {
337
+ const output = execFileSync("ps", ["-eww", "-o", "args="], {
338
+ encoding: "utf8",
339
+ stdio: ["ignore", "pipe", "ignore"],
340
+ });
341
+ return output
342
+ .split("\n")
343
+ .map((line) => line.trim())
344
+ .filter((line) => line.length > 0);
345
+ }
346
+ catch {
347
+ return [];
348
+ }
349
+ }
350
+ function processHasExactCommand(processCommands, command) {
351
+ return processCommands.some((line) => line.trim() === command);
352
+ }
353
+ export function readLiveMonitorEvidence(sessionId, options = {}) {
354
+ if (!SESSION_ID_PATTERN.test(sessionId)) {
355
+ throw new LanesError("monitor_invalid_session", `Invalid senior session id ${JSON.stringify(sessionId)}`);
356
+ }
357
+ const home = options.homedir?.() ?? os.homedir();
358
+ const env = options.env ?? process.env;
359
+ const transcriptMaxBytes = options.transcriptMaxBytes ?? MONITOR_TRANSCRIPT_MAX_BYTES;
360
+ const taskOutputMaxBytes = options.taskOutputMaxBytes ?? MONITOR_TASK_OUTPUT_MAX_BYTES;
361
+ const processCommands = options.readProcessCommands?.() ?? defaultProcessCommands();
362
+ const tasks = new Map();
363
+ const transcriptPaths = transcriptPathsFor(home, env, sessionId);
364
+ const taskOutputPaths = [];
365
+ for (const transcriptPath of transcriptPaths) {
366
+ const transcript = boundedTail(transcriptPath, transcriptMaxBytes);
367
+ if (transcript === null)
368
+ continue;
369
+ for (const parsed of parseMonitorTranscript(transcript)) {
370
+ const outputCandidates = taskOutputCandidates(transcriptPath, sessionId, parsed);
371
+ let outputPath;
372
+ let outputText;
373
+ for (const candidate of outputCandidates) {
374
+ const content = boundedTail(candidate, taskOutputMaxBytes);
375
+ if (content === null)
376
+ continue;
377
+ outputPath = candidate;
378
+ outputText = content;
379
+ taskOutputPaths.push(candidate);
380
+ break;
381
+ }
382
+ tasks.set(parsed.taskId, {
383
+ ...parsed,
384
+ outputPresent: outputPath !== undefined,
385
+ outputPath: outputPath ?? parsed.outputPath,
386
+ outputText,
387
+ processAlive: processHasExactCommand(processCommands, parsed.command)
388
+ ? true
389
+ : undefined,
390
+ });
391
+ }
392
+ }
393
+ return {
394
+ sessionId,
395
+ tasks: [...tasks.values()],
396
+ transcriptPaths,
397
+ taskOutputPaths: [...new Set(taskOutputPaths)],
398
+ processCommands,
399
+ };
400
+ }
401
+ export function monitorReminderText() {
402
+ return [
403
+ "For active Claude senior lanes, arm one live Claude Code Monitor task per uncovered lane:",
404
+ 'Monitor(command="hq lanes watch <lane-id>...", timeout_ms=1800000, persistent=true)',
405
+ "Use `hq lanes monitor-check --session <id>` to verify coverage. `persistent=true` is requested where the installed Monitor tool honors it; Claude Code caps Monitor tasks at 30 minutes, so re-arm after expiry.",
406
+ "The caller must pass `--engine codex` or `--engine grok` (or set HQ_CONDUCT_ENGINE) for sessions whose engine has no Claude Monitor tool; those engines are never required to provide one.",
407
+ ].join("\n");
408
+ }
409
+ //# sourceMappingURL=monitor.js.map
@@ -21,6 +21,9 @@ declare const PROVIDER_COMMAND: Record<LaneProvider, string>;
21
21
  export declare function providerCommandOnPath(command: string, pathEnv: string | undefined): boolean;
22
22
  /** Per-provider model flag. A missing entry means --model is refused. */
23
23
  export declare const PROVIDER_MODEL_FLAG: Record<LaneProvider, string>;
24
+ export declare const CLAUDE_AUTO_COMPACT_ENV = "CLAUDE_CODE_AUTO_COMPACT_WINDOW";
25
+ /** Codex CLI overrides required for its ChatGPT fast service tier. */
26
+ export declare const CODEX_FAST_MODE_FLAGS: readonly ["-c", "service_tier=\"fast\"", "--enable", "fast_mode"];
24
27
  export declare function parseCliModel(raw: string | undefined): string | undefined;
25
28
  export declare function resolveLaneModel(input: {
26
29
  cliModel?: string;
@@ -28,6 +31,8 @@ export declare function resolveLaneModel(input: {
28
31
  providerModel?: string;
29
32
  }): string | undefined;
30
33
  export declare function appendModelFlag(provider: LaneProvider, args: string[], model: string | undefined): string[];
34
+ /** Add Codex fast-mode flags before the prompt/positional separator. */
35
+ export declare function appendFastModeFlags(provider: LaneProvider, args: string[], enabled: boolean | undefined): string[];
31
36
  export type DetachedStdio = ["ignore", number, number];
32
37
  export interface DetachedSpawnOptions {
33
38
  detached: true;
@@ -190,6 +195,8 @@ export declare function buildProviderCommand(provider: LaneProvider, input: {
190
195
  model?: string;
191
196
  /** Validated against the provider's own value set by appendEffortFlag. */
192
197
  effort?: string;
198
+ /** Enable Codex's fast service tier for this resolved model. */
199
+ fastMode?: boolean;
193
200
  /** Continue a recorded session. Only providers in PROVIDER_SESSION_RESUME accept this. */
194
201
  resume?: ProviderResumeInput;
195
202
  /**
@@ -202,7 +209,7 @@ export declare function buildProviderCommand(provider: LaneProvider, input: {
202
209
  export declare function workerEnv(base: NodeJS.ProcessEnv, resolved: {
203
210
  envVar: string;
204
211
  home: string;
205
- }, laneId: string, hqRoot: string): NodeJS.ProcessEnv;
212
+ }, laneId: string, hqRoot: string, autoCompactTokens?: number): NodeJS.ProcessEnv;
206
213
  export declare function markSpawnFailure(hqRoot: string, laneId: string, reasonRaw: string, details: Record<string, unknown>): LaneRecord;
207
214
  /**
208
215
  * Spec §5.2 executing-side check. Compares this machine's identity to
@@ -219,6 +226,7 @@ export interface SpawnManifestFile {
219
226
  } | null;
220
227
  /** Byte length of logs/worker.out before this run started; its result is after this. */
221
228
  worker_out_offset?: number;
229
+ fast_mode?: boolean;
222
230
  }
223
231
  /** Read the per-run manifest. Missing file or field reads as absent. */
224
232
  export declare function readSpawnManifest(runDir: string): SpawnManifestFile;
@@ -268,6 +276,7 @@ export declare function envelopeRepairMode(provider: LaneProvider): EnvelopeRepa
268
276
  * prompt as a fresh single turn on the same account (`fresh_turn` mode). It
269
277
  * replaces `worker.pid` and rewrites `spawn.json` so the watcher's next tick
270
278
  * follows the new process. The account is the one already bound on the record.
279
+ * Fast-mode evidence is updated after the replacement is proven detached.
271
280
  */
272
281
  export declare function spawnEnvelopeRepair(hqRoot: string, lane: LaneRecord, input: EnvelopeRepairSpawnInput, deps?: SpawnLaneDeps): number;
273
282
  export { PROVIDER_HOME_ENV, PROVIDER_COMMAND };