@indigoai-us/hq-cli 5.345.11 → 5.345.13
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.
- package/CHANGELOG.md +10 -0
- package/assets/scaffold/core/scripts/hq-delegate-grant.sh +16 -16
- package/assets/scaffold/core/scripts/register-project.sh +5 -5
- package/assets/scaffold/core/scripts/repo-run-registry.sh +8 -8
- package/assets/scaffold/core/scripts/resume-thread-lock.sh +4 -4
- package/assets/scaffold/core/scripts/verify-story-deliverables.sh +1 -1
- package/assets/scaffold/core/scripts/worktree-gc.sh +1 -1
- package/dist/commands/core-delegate-w1b.js +14 -9
- package/dist/commands/core-delegate.d.ts +1 -0
- package/dist/commands/core-delegate.js +10 -2
- package/dist/commands/core-handoff.js +69 -34
- package/dist/commands/core-hq-session-native.js +26 -5
- package/dist/commands/core-job-notify-fast.d.ts +2 -0
- package/dist/commands/core-job-notify-fast.js +6 -0
- package/dist/commands/core-job-probe-fast.d.ts +2 -0
- package/dist/commands/core-job-probe-fast.js +11 -0
- package/dist/commands/core-job-probe-native.js +1 -1
- package/dist/commands/core-job-remediate-fast.d.ts +2 -0
- package/dist/commands/core-job-remediate-fast.js +6 -0
- package/dist/commands/core-job-run-fast.d.ts +2 -0
- package/dist/commands/core-job-run-fast.js +6 -0
- package/dist/commands/core-pin-fast.d.ts +2 -0
- package/dist/commands/core-pin-fast.js +15 -0
- package/dist/commands/core-rebuild-index-fast.d.ts +6 -0
- package/dist/commands/core-rebuild-index-fast.js +39 -0
- package/dist/commands/core-register-project-native.js +11 -2
- package/dist/commands/core-repo-run-registry-native.js +47 -4
- package/dist/commands/core-session-journal-native.d.ts +1 -1
- package/dist/commands/core-session-journal-native.js +2 -2
- package/dist/commands/core-share-suggestion-state-native.js +6 -2
- package/dist/commands/core-work-mesh-live-rebind-native.js +5 -2
- package/dist/commands/core-worker-lint-fast.d.ts +2 -0
- package/dist/commands/core-worker-lint-fast.js +11 -0
- package/dist/commands/core.js +9 -6
- package/dist/fast-scaffold.js +49 -0
- package/dist/lib/core-utils/worktree-resume.d.ts +1 -0
- package/dist/lib/core-utils/worktree-resume.js +68 -31
- package/dist/lib/daemon/catalog.d.ts +10 -0
- package/dist/lib/daemon/catalog.js +8 -0
- package/dist/lib/daemon/lanes-reconcile-guard.d.ts +43 -0
- package/dist/lib/daemon/lanes-reconcile-guard.js +115 -0
- package/dist/lib/daemon/run.js +2 -0
- package/dist/lib/daemon/supervisor.d.ts +2 -0
- package/dist/lib/daemon/supervisor.js +28 -0
- package/dist/lib/lanes/autopilot-registry.d.ts +2 -5
- package/dist/lib/lanes/autopilot-registry.js +4 -4
- package/dist/lib/lanes/compaction.d.ts +2 -2
- package/dist/lib/lanes/compaction.js +221 -54
- package/dist/lib/lanes/move-account.js +24 -1
- package/dist/lib/lanes/reconcile.d.ts +0 -5
- package/dist/lib/lanes/reconcile.js +4 -4
- package/dist/lib/lanes/types.d.ts +6 -5
- package/dist/utils/run-bundled-script.js +1 -1
- package/package.json +1 -1
|
@@ -49,10 +49,116 @@ export function compactionDue(lane, nowMs, thresholdMs) {
|
|
|
49
49
|
threshold_ms: thresholdMs,
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
function
|
|
52
|
+
function readJsonStringAt(input, start) {
|
|
53
|
+
if (input[start] !== '"')
|
|
54
|
+
return null;
|
|
55
|
+
let index = start + 1;
|
|
56
|
+
while (index < input.length) {
|
|
57
|
+
if (input[index] === "\\") {
|
|
58
|
+
index += 2;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (input[index] === '"') {
|
|
62
|
+
try {
|
|
63
|
+
return { value: JSON.parse(input.slice(start, index + 1)), end: index + 1 };
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
index += 1;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
function skipJsonWhitespace(input, start) {
|
|
74
|
+
let index = start;
|
|
75
|
+
while (/\s/.test(input[index] ?? ""))
|
|
76
|
+
index += 1;
|
|
77
|
+
return index;
|
|
78
|
+
}
|
|
79
|
+
function skipJsonValue(input, start) {
|
|
80
|
+
const first = input[start];
|
|
81
|
+
if (first === '"')
|
|
82
|
+
return readJsonStringAt(input, start)?.end ?? null;
|
|
83
|
+
if (first !== "{" && first !== "[") {
|
|
84
|
+
let index = start;
|
|
85
|
+
while (index < input.length && input[index] !== "," && input[index] !== "}" && input[index] !== "]")
|
|
86
|
+
index += 1;
|
|
87
|
+
return index < input.length ? index : null;
|
|
88
|
+
}
|
|
89
|
+
const stack = [first === "{" ? "}" : "]"];
|
|
90
|
+
let index = start + 1;
|
|
91
|
+
while (index < input.length) {
|
|
92
|
+
const char = input[index];
|
|
93
|
+
if (char === '"') {
|
|
94
|
+
const parsed = readJsonStringAt(input, index);
|
|
95
|
+
if (!parsed)
|
|
96
|
+
return null;
|
|
97
|
+
index = parsed.end;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (char === "{" || char === "[")
|
|
101
|
+
stack.push(char === "{" ? "}" : "]");
|
|
102
|
+
else if (char === "}" || char === "]") {
|
|
103
|
+
if (stack.pop() !== char)
|
|
104
|
+
return null;
|
|
105
|
+
if (stack.length === 0)
|
|
106
|
+
return index + 1;
|
|
107
|
+
}
|
|
108
|
+
index += 1;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
/** Extract a top-level JSON value from a bounded prefix, even if its tail is truncated. */
|
|
113
|
+
function topLevelJsonValue(input, targetKey) {
|
|
114
|
+
let index = skipJsonWhitespace(input, 0);
|
|
115
|
+
if (input[index++] !== "{")
|
|
116
|
+
return null;
|
|
117
|
+
while (index < input.length) {
|
|
118
|
+
index = skipJsonWhitespace(input, index);
|
|
119
|
+
if (input[index] === "}")
|
|
120
|
+
return null;
|
|
121
|
+
const key = readJsonStringAt(input, index);
|
|
122
|
+
if (!key)
|
|
123
|
+
return null;
|
|
124
|
+
index = skipJsonWhitespace(input, key.end);
|
|
125
|
+
if (input[index++] !== ":")
|
|
126
|
+
return null;
|
|
127
|
+
index = skipJsonWhitespace(input, index);
|
|
128
|
+
const end = skipJsonValue(input, index);
|
|
129
|
+
if (key.value === targetKey)
|
|
130
|
+
return end === null ? null : input.slice(index, end);
|
|
131
|
+
if (end === null)
|
|
132
|
+
return null;
|
|
133
|
+
index = skipJsonWhitespace(input, end);
|
|
134
|
+
if (input[index] === ",")
|
|
135
|
+
index += 1;
|
|
136
|
+
else
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
function topLevelString(input, targetKey) {
|
|
142
|
+
const raw = topLevelJsonValue(input, targetKey);
|
|
143
|
+
if (!raw?.startsWith('"'))
|
|
144
|
+
return null;
|
|
145
|
+
try {
|
|
146
|
+
return JSON.parse(raw);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function isProviderMarkerLine(line, lineNumber, transcriptPath, provider, oversized = false) {
|
|
53
153
|
const needle = provider === "claude" ? "compact_boundary" : "compacted";
|
|
54
154
|
if (!line.includes(needle))
|
|
55
155
|
return false;
|
|
156
|
+
if (oversized) {
|
|
157
|
+
const type = topLevelString(line, "type");
|
|
158
|
+
const subtype = topLevelString(line, "subtype");
|
|
159
|
+
return (provider === "claude" && type === "system" && subtype === "compact_boundary") ||
|
|
160
|
+
(provider === "codex" && type === "compacted");
|
|
161
|
+
}
|
|
56
162
|
let record;
|
|
57
163
|
try {
|
|
58
164
|
const parsed = JSON.parse(line);
|
|
@@ -67,25 +173,61 @@ function isProviderMarkerLine(line, lineNumber, transcriptPath, provider) {
|
|
|
67
173
|
return ((provider === "claude" && record.type === "system" && record.subtype === "compact_boundary") ||
|
|
68
174
|
(provider === "codex" && record.type === "compacted"));
|
|
69
175
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
176
|
+
const TRANSCRIPT_READ_CHUNK_BYTES = 1024 * 1024;
|
|
177
|
+
const TRANSCRIPT_MAX_LINE_BYTES = 64 * 1024 * 1024;
|
|
178
|
+
const TRANSCRIPT_OVERSIZED_PREFIX_BYTES = 64 * 1024;
|
|
179
|
+
/** Read JSONL incrementally, retaining at most one bounded line plus one chunk. */
|
|
180
|
+
function scanTranscriptLines(transcriptPath, startOffset, includeUnterminatedLast, onLine, maxLineBytes = TRANSCRIPT_MAX_LINE_BYTES) {
|
|
74
181
|
const fd = fs.openSync(transcriptPath, "r");
|
|
75
182
|
try {
|
|
76
|
-
const
|
|
77
|
-
if (startOffset >
|
|
78
|
-
return {
|
|
79
|
-
|
|
80
|
-
return { count: 0, next_offset: size, replaced: false };
|
|
81
|
-
const chunkSize = 1024 * 1024;
|
|
82
|
-
const lineParts = [];
|
|
83
|
-
let count = 0;
|
|
183
|
+
const fileSize = fs.fstatSync(fd).size;
|
|
184
|
+
if (startOffset > fileSize) {
|
|
185
|
+
return { file_size: fileSize, next_offset: fileSize, replaced: true };
|
|
186
|
+
}
|
|
84
187
|
let position = startOffset;
|
|
85
|
-
let nextOffset = startOffset;
|
|
86
188
|
let lineNumber = 0;
|
|
87
|
-
|
|
88
|
-
|
|
189
|
+
let lineParts = [];
|
|
190
|
+
let lineBytes = 0;
|
|
191
|
+
let skipLongLine = false;
|
|
192
|
+
let nextOffset = startOffset;
|
|
193
|
+
const appendPart = (part) => {
|
|
194
|
+
if (part.length === 0 || skipLongLine)
|
|
195
|
+
return;
|
|
196
|
+
lineBytes += part.length;
|
|
197
|
+
if (lineBytes > maxLineBytes) {
|
|
198
|
+
skipLongLine = true;
|
|
199
|
+
const prefix = Buffer.alloc(Math.min(TRANSCRIPT_OVERSIZED_PREFIX_BYTES, lineBytes));
|
|
200
|
+
let copied = 0;
|
|
201
|
+
for (const previous of lineParts) {
|
|
202
|
+
const length = Math.min(previous.length, prefix.length - copied);
|
|
203
|
+
if (length <= 0)
|
|
204
|
+
break;
|
|
205
|
+
previous.copy(prefix, copied, 0, length);
|
|
206
|
+
copied += length;
|
|
207
|
+
}
|
|
208
|
+
const partLength = Math.min(part.length, prefix.length - copied);
|
|
209
|
+
if (partLength > 0)
|
|
210
|
+
part.copy(prefix, copied, 0, partLength);
|
|
211
|
+
lineParts = prefix.length > 0 ? [prefix] : [];
|
|
212
|
+
lineBytes = prefix.length;
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
lineParts.push(part);
|
|
216
|
+
};
|
|
217
|
+
const finishLine = (endOffset) => {
|
|
218
|
+
lineNumber += 1;
|
|
219
|
+
const recognizedMarker = onLine(Buffer.concat(lineParts, lineBytes).toString("utf8"), lineNumber, skipLongLine);
|
|
220
|
+
if (skipLongLine && recognizedMarker !== true) {
|
|
221
|
+
process.stderr.write(`hq lanes: skipped oversized transcript line ${lineNumber} in ${transcriptPath} (over ${maxLineBytes} bytes)\n`);
|
|
222
|
+
}
|
|
223
|
+
lineParts = [];
|
|
224
|
+
lineBytes = 0;
|
|
225
|
+
skipLongLine = false;
|
|
226
|
+
nextOffset = endOffset;
|
|
227
|
+
};
|
|
228
|
+
while (position < fileSize) {
|
|
229
|
+
const chunk = Buffer.allocUnsafe(Math.min(TRANSCRIPT_READ_CHUNK_BYTES, fileSize - position));
|
|
230
|
+
const chunkStart = position;
|
|
89
231
|
const read = fs.readSync(fd, chunk, 0, chunk.length, position);
|
|
90
232
|
if (read === 0)
|
|
91
233
|
break;
|
|
@@ -94,28 +236,34 @@ export function probeProviderCompactionsSince(transcriptPath, provider, startOff
|
|
|
94
236
|
for (let index = 0; index < read; index += 1) {
|
|
95
237
|
if (chunk[index] !== 0x0a)
|
|
96
238
|
continue;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
lineParts.length = 0;
|
|
100
|
-
lineNumber += 1;
|
|
101
|
-
if (isProviderMarkerLine(line, lineNumber, transcriptPath, provider))
|
|
102
|
-
count += 1;
|
|
239
|
+
appendPart(chunk.subarray(lineStart, index));
|
|
240
|
+
finishLine(chunkStart + index + 1);
|
|
103
241
|
lineStart = index + 1;
|
|
104
|
-
nextOffset = position - (read - lineStart);
|
|
105
242
|
}
|
|
106
243
|
if (lineStart < read)
|
|
107
|
-
|
|
244
|
+
appendPart(chunk.subarray(lineStart, read));
|
|
108
245
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
replaced: false,
|
|
113
|
-
};
|
|
246
|
+
if (includeUnterminatedLast && (lineBytes > 0 || skipLongLine))
|
|
247
|
+
finishLine(fileSize);
|
|
248
|
+
return { file_size: fileSize, next_offset: nextOffset, replaced: false };
|
|
114
249
|
}
|
|
115
250
|
finally {
|
|
116
251
|
fs.closeSync(fd);
|
|
117
252
|
}
|
|
118
253
|
}
|
|
254
|
+
/** Read newly appended, newline-complete marker records after a saved byte offset. */
|
|
255
|
+
export function probeProviderCompactionsSince(transcriptPath, provider, startOffset, maxLineBytes = TRANSCRIPT_MAX_LINE_BYTES) {
|
|
256
|
+
if (provider === "grok")
|
|
257
|
+
return { count: 0, next_offset: startOffset, replaced: false };
|
|
258
|
+
let count = 0;
|
|
259
|
+
const scan = scanTranscriptLines(transcriptPath, startOffset, false, (line, lineNumber, oversized) => {
|
|
260
|
+
const marker = isProviderMarkerLine(line, lineNumber, transcriptPath, provider, oversized);
|
|
261
|
+
if (marker)
|
|
262
|
+
count += 1;
|
|
263
|
+
return marker;
|
|
264
|
+
}, maxLineBytes);
|
|
265
|
+
return { count, next_offset: scan.next_offset, replaced: scan.replaced };
|
|
266
|
+
}
|
|
119
267
|
export function providerTranscriptSize(transcriptPath) {
|
|
120
268
|
try {
|
|
121
269
|
return fs.statSync(transcriptPath).size;
|
|
@@ -166,39 +314,58 @@ export function findSessionTranscript(home, sessionId) {
|
|
|
166
314
|
return null;
|
|
167
315
|
}
|
|
168
316
|
/** Count compact boundaries in a transcript. Other lines are never parsed. */
|
|
169
|
-
export function probeCompactBoundaries(transcriptPath) {
|
|
317
|
+
export function probeCompactBoundaries(transcriptPath, maxLineBytes = TRANSCRIPT_MAX_LINE_BYTES) {
|
|
170
318
|
if (transcriptPath === null)
|
|
171
319
|
return { count: 0, last_pre_tokens: null };
|
|
172
|
-
let
|
|
320
|
+
let count = 0;
|
|
321
|
+
let last = null;
|
|
173
322
|
try {
|
|
174
|
-
|
|
323
|
+
scanTranscriptLines(transcriptPath, 0, true, (line, lineNumber, oversized) => {
|
|
324
|
+
if (oversized) {
|
|
325
|
+
const marker = topLevelString(line, "type") === "system" && topLevelString(line, "subtype") === "compact_boundary";
|
|
326
|
+
if (!marker)
|
|
327
|
+
return false;
|
|
328
|
+
count += 1;
|
|
329
|
+
const rawMetadata = topLevelJsonValue(line, "compactMetadata");
|
|
330
|
+
if (rawMetadata) {
|
|
331
|
+
try {
|
|
332
|
+
const meta = JSON.parse(rawMetadata);
|
|
333
|
+
const pre = meta.preTokens;
|
|
334
|
+
last = typeof pre === "number" && Number.isFinite(pre) ? pre : null;
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
last = null;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
last = null;
|
|
342
|
+
}
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
if (!line.includes('"compact_boundary"'))
|
|
346
|
+
return;
|
|
347
|
+
let rec;
|
|
348
|
+
try {
|
|
349
|
+
rec = JSON.parse(line);
|
|
350
|
+
}
|
|
351
|
+
catch (err) {
|
|
352
|
+
process.stderr.write(`hq lanes: skipped an unparseable line in ${transcriptPath}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
if (rec.type !== "system" || rec.subtype !== "compact_boundary")
|
|
356
|
+
return false;
|
|
357
|
+
count += 1;
|
|
358
|
+
const meta = rec.compactMetadata;
|
|
359
|
+
const pre = meta?.preTokens;
|
|
360
|
+
last = typeof pre === "number" && Number.isFinite(pre) ? pre : null;
|
|
361
|
+
return true;
|
|
362
|
+
}, maxLineBytes);
|
|
175
363
|
}
|
|
176
364
|
catch (err) {
|
|
177
|
-
|
|
178
|
-
if (code === "ENOENT")
|
|
365
|
+
if (err.code === "ENOENT")
|
|
179
366
|
return { count: 0, last_pre_tokens: null };
|
|
180
367
|
throw err;
|
|
181
368
|
}
|
|
182
|
-
let count = 0;
|
|
183
|
-
let last = null;
|
|
184
|
-
for (const line of text.split("\n")) {
|
|
185
|
-
if (!line.includes('"compact_boundary"'))
|
|
186
|
-
continue;
|
|
187
|
-
let rec;
|
|
188
|
-
try {
|
|
189
|
-
rec = JSON.parse(line);
|
|
190
|
-
}
|
|
191
|
-
catch (err) {
|
|
192
|
-
process.stderr.write(`hq lanes: skipped an unparseable line in ${transcriptPath}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
if (rec.type !== "system" || rec.subtype !== "compact_boundary")
|
|
196
|
-
continue;
|
|
197
|
-
count += 1;
|
|
198
|
-
const meta = rec.compactMetadata;
|
|
199
|
-
const pre = meta?.preTokens;
|
|
200
|
-
last = typeof pre === "number" && Number.isFinite(pre) ? pre : null;
|
|
201
|
-
}
|
|
202
369
|
return { count, last_pre_tokens: last };
|
|
203
370
|
}
|
|
204
371
|
/** Synchronous `/compact`. stdout is discarded; stderr goes to the run dir. */
|
|
@@ -123,16 +123,39 @@ function refuseCredential(provider, file) {
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
function sameContent(a, b) {
|
|
126
|
+
const chunkBytes = 1024 * 1024;
|
|
127
|
+
let aFd;
|
|
128
|
+
let bFd;
|
|
126
129
|
try {
|
|
127
130
|
const sa = fs.statSync(a);
|
|
128
131
|
const sb = fs.statSync(b);
|
|
129
132
|
if (sa.size !== sb.size)
|
|
130
133
|
return false;
|
|
131
|
-
|
|
134
|
+
aFd = fs.openSync(a, "r");
|
|
135
|
+
bFd = fs.openSync(b, "r");
|
|
136
|
+
const aChunk = Buffer.allocUnsafe(chunkBytes);
|
|
137
|
+
const bChunk = Buffer.allocUnsafe(chunkBytes);
|
|
138
|
+
let position = 0;
|
|
139
|
+
while (position < sa.size) {
|
|
140
|
+
const requested = Math.min(chunkBytes, sa.size - position);
|
|
141
|
+
const aRead = fs.readSync(aFd, aChunk, 0, requested, position);
|
|
142
|
+
const bRead = fs.readSync(bFd, bChunk, 0, requested, position);
|
|
143
|
+
if (aRead !== requested || bRead !== requested || !aChunk.subarray(0, aRead).equals(bChunk.subarray(0, bRead))) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
position += requested;
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
132
149
|
}
|
|
133
150
|
catch {
|
|
134
151
|
return false;
|
|
135
152
|
}
|
|
153
|
+
finally {
|
|
154
|
+
if (aFd !== undefined)
|
|
155
|
+
fs.closeSync(aFd);
|
|
156
|
+
if (bFd !== undefined)
|
|
157
|
+
fs.closeSync(bFd);
|
|
158
|
+
}
|
|
136
159
|
}
|
|
137
160
|
/**
|
|
138
161
|
* Copy one file via a temp name and rename, so a partial copy is never a
|
|
@@ -19,11 +19,6 @@ export declare const QUESTION_AGE_MS: number;
|
|
|
19
19
|
export declare const MAX_AGED_ADVANCES: number;
|
|
20
20
|
/** Aligns with watcher silence: a host that has not reported for this long is dead. */
|
|
21
21
|
export declare const DEAD_HOST_MS: number;
|
|
22
|
-
export declare const RECONCILE_LOCK_STALE_MS = 30000;
|
|
23
|
-
export declare const RECONCILE_LOCK_TIMEOUT_MS = 5000;
|
|
24
|
-
/** A pickup probe that has not cleared its marker within this window is abandoned. */
|
|
25
|
-
export declare const PICKUP_VALIDATION_MAX_AGE_MS: number;
|
|
26
|
-
export declare const PICKUP_VALIDATION_TIMEOUT_REASON: "pickup_validation_timeout";
|
|
27
22
|
export declare const CLOSE_INTERRUPTED_DONE_STORY_WORKERS_FLAG = "lanes.close-interrupted-done-story-workers";
|
|
28
23
|
export declare const RECONCILE_UNIT_NAME = "hq-lanes-reconcile.service";
|
|
29
24
|
export declare const RECONCILE_TIMER_NAME = "hq-lanes-reconcile.timer";
|
|
@@ -45,11 +45,11 @@ export const QUESTION_AGE_MS = 60 * 60 * 1000;
|
|
|
45
45
|
export const MAX_AGED_ADVANCES = MAX_LANE_DEPTH - 1;
|
|
46
46
|
/** Aligns with watcher silence: a host that has not reported for this long is dead. */
|
|
47
47
|
export const DEAD_HOST_MS = SILENCE_MS;
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
const RECONCILE_LOCK_STALE_MS = 30_000;
|
|
49
|
+
const RECONCILE_LOCK_TIMEOUT_MS = 5_000;
|
|
50
50
|
/** A pickup probe that has not cleared its marker within this window is abandoned. */
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
const PICKUP_VALIDATION_MAX_AGE_MS = 15 * 60 * 1000;
|
|
52
|
+
const PICKUP_VALIDATION_TIMEOUT_REASON = "pickup_validation_timeout";
|
|
53
53
|
export const CLOSE_INTERRUPTED_DONE_STORY_WORKERS_FLAG = "lanes.close-interrupted-done-story-workers";
|
|
54
54
|
const INTERRUPTED_DONE_STORY_MIN_AGE_MS = 24 * 60 * 60 * 1000;
|
|
55
55
|
export const RECONCILE_UNIT_NAME = "hq-lanes-reconcile.service";
|
|
@@ -179,7 +179,7 @@ export declare const LANE_PROVIDERS: readonly ["claude", "codex", "grok"];
|
|
|
179
179
|
export type LaneProvider = (typeof LANE_PROVIDERS)[number];
|
|
180
180
|
export declare const QUEUED_REASONS: readonly ["cap", "provider_cap", "account_cap", "profile_cap", "queue_position", "throttle", "provider_binary_missing", "account_retry", "lead_reserve", "worker_profile_changed", "low_disk", "admit_failed"];
|
|
181
181
|
export type QueuedReason = (typeof QUEUED_REASONS)[number];
|
|
182
|
-
|
|
182
|
+
type QueuedDetails = {
|
|
183
183
|
reason: "worker_profile_changed";
|
|
184
184
|
expected_hash: string | null;
|
|
185
185
|
actual_hash: string;
|
|
@@ -308,7 +308,7 @@ export interface SeniorHistoryEntry {
|
|
|
308
308
|
by: string;
|
|
309
309
|
reason: string;
|
|
310
310
|
}
|
|
311
|
-
|
|
311
|
+
interface LaneStopHistoryEntry {
|
|
312
312
|
at: string;
|
|
313
313
|
reason: string;
|
|
314
314
|
}
|
|
@@ -370,7 +370,7 @@ export interface AttributionHistoryEntry {
|
|
|
370
370
|
at: string;
|
|
371
371
|
story_switch_unacknowledged?: StorySwitchUnacknowledgedNote;
|
|
372
372
|
}
|
|
373
|
-
|
|
373
|
+
interface StorySwitchPending {
|
|
374
374
|
previous_project_id: string;
|
|
375
375
|
previous_story_id: string;
|
|
376
376
|
project_id: string;
|
|
@@ -416,7 +416,7 @@ export interface ManagerStatusGateHistoryEntry {
|
|
|
416
416
|
resume_queued?: boolean;
|
|
417
417
|
resume_skipped_reason?: "open_question" | "blocked" | "miss_limit" | "no_provider_session";
|
|
418
418
|
}
|
|
419
|
-
|
|
419
|
+
interface BlockerFreshnessState {
|
|
420
420
|
/** Stable hashes of the stale blocker labels seen at the last completed turn. */
|
|
421
421
|
stale_keys: string[];
|
|
422
422
|
stale_labels: string[];
|
|
@@ -440,7 +440,7 @@ export interface BlockerFreshnessHistoryEntry {
|
|
|
440
440
|
reason?: string;
|
|
441
441
|
delivery_recovered?: true;
|
|
442
442
|
}
|
|
443
|
-
|
|
443
|
+
interface KrFreshnessState {
|
|
444
444
|
/** Stable fingerprint of the last stalled KPI set, which is resumed once. */
|
|
445
445
|
stalled_fingerprint?: string;
|
|
446
446
|
}
|
|
@@ -1044,4 +1044,5 @@ export interface LanesConfig {
|
|
|
1044
1044
|
export declare function isIsoDateTime(value: string): boolean;
|
|
1045
1045
|
export declare function parseMajorSchema(schemaVersion: string, expectedPrefix: string, expectedMajor: number): void;
|
|
1046
1046
|
export declare function parseLaneEnvelope(raw: unknown): LaneEnvelope;
|
|
1047
|
+
export {};
|
|
1047
1048
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -33,7 +33,7 @@ import { spawnSync } from "child_process";
|
|
|
33
33
|
import * as fs from "node:fs";
|
|
34
34
|
import * as os from "node:os";
|
|
35
35
|
import * as path from "path";
|
|
36
|
-
import { resolveBundledAsset } from "./hq-roots.js";
|
|
36
|
+
import { resolveBundledAsset } from "./hq-roots-core.js";
|
|
37
37
|
/**
|
|
38
38
|
* Which interpreter runs a bundled asset, chosen by extension.
|
|
39
39
|
*
|