@indigoai-us/hq-cli 5.345.77 → 5.345.78
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 +7 -0
- package/dist/lib/lanes/spawn.js +1 -0
- package/dist/lib/lanes/store.js +41 -25
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.345.78] — 2026-10-10
|
|
6
|
+
- `hq lanes` no longer fails every list, message, or admission command when
|
|
7
|
+
one lane still has leftover queue details from an older worker-profile wait.
|
|
8
|
+
Those leftover details are dropped on read, cleared when the queue reason
|
|
9
|
+
changes, and one unreadable lane is skipped so the rest of the host stays
|
|
10
|
+
usable.
|
|
11
|
+
|
|
5
12
|
## [5.345.77] — 2026-10-10
|
|
6
13
|
- Local bots no longer fail a turn when the installed Codex is too old for the
|
|
7
14
|
model it was asked to use (often the model a newer Codex app set in your own
|
package/dist/lib/lanes/spawn.js
CHANGED
|
@@ -677,6 +677,7 @@ export async function retryLaneOnAlternateAccount(hqRoot, lane, reason, writer =
|
|
|
677
677
|
...lane,
|
|
678
678
|
state: "queued",
|
|
679
679
|
queued_reason: "account_retry",
|
|
680
|
+
queued_details: undefined,
|
|
680
681
|
queued_at: at,
|
|
681
682
|
terminal_reason: undefined,
|
|
682
683
|
terminal_details: undefined,
|
package/dist/lib/lanes/store.js
CHANGED
|
@@ -386,6 +386,28 @@ function parseLaneStories(raw, filePath) {
|
|
|
386
386
|
}
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
|
+
/** Profile, disk, and admit details are only valid for their matching queue reason. */
|
|
390
|
+
function queuedDetailsAreStale(state, queuedReason, detailsReason) {
|
|
391
|
+
if (detailsReason === "worker_profile_changed") {
|
|
392
|
+
return queuedReason !== "worker_profile_changed";
|
|
393
|
+
}
|
|
394
|
+
if (detailsReason === "low_disk") {
|
|
395
|
+
return state !== "queued" || queuedReason !== "low_disk";
|
|
396
|
+
}
|
|
397
|
+
if (detailsReason === "admit_failed") {
|
|
398
|
+
return state !== "queued" || queuedReason !== "admit_failed";
|
|
399
|
+
}
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
function withoutStaleQueuedDetails(record) {
|
|
403
|
+
const details = record.queued_details;
|
|
404
|
+
if (details === undefined)
|
|
405
|
+
return record;
|
|
406
|
+
if (!queuedDetailsAreStale(record.state, record.queued_reason, details.reason)) {
|
|
407
|
+
return record;
|
|
408
|
+
}
|
|
409
|
+
return { ...record, queued_details: undefined };
|
|
410
|
+
}
|
|
389
411
|
export function parseLaneRecord(raw, filePath) {
|
|
390
412
|
if (!isPlainObject(raw)) {
|
|
391
413
|
throw new LaneSchemaError("Lane record must be a JSON object", {
|
|
@@ -638,7 +660,11 @@ export function parseLaneRecord(raw, filePath) {
|
|
|
638
660
|
});
|
|
639
661
|
}
|
|
640
662
|
const detailsRecord = details;
|
|
641
|
-
if (detailsRecord.reason
|
|
663
|
+
if (queuedDetailsAreStale(raw.state, raw.queued_reason, detailsRecord.reason)) {
|
|
664
|
+
normalized = { ...raw };
|
|
665
|
+
delete normalized.queued_details;
|
|
666
|
+
}
|
|
667
|
+
else if (detailsRecord.reason === "worker_profile_changed") {
|
|
642
668
|
if ((detailsRecord.expected_hash !== null && typeof detailsRecord.expected_hash !== "string") ||
|
|
643
669
|
typeof detailsRecord.actual_hash !== "string" || detailsRecord.actual_hash === "" ||
|
|
644
670
|
typeof detailsRecord.recovery_command !== "string" || detailsRecord.recovery_command.trim() === "") {
|
|
@@ -647,17 +673,6 @@ export function parseLaneRecord(raw, filePath) {
|
|
|
647
673
|
field: "queued_details",
|
|
648
674
|
});
|
|
649
675
|
}
|
|
650
|
-
if (raw.queued_reason !== "worker_profile_changed") {
|
|
651
|
-
if (raw.queued_reason === undefined) {
|
|
652
|
-
throw new LaneSchemaError("queued_details requires queued_reason worker_profile_changed", {
|
|
653
|
-
path: filePath,
|
|
654
|
-
field: "queued_details",
|
|
655
|
-
queued_reason: raw.queued_reason,
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
normalized = { ...raw };
|
|
659
|
-
delete normalized.queued_details;
|
|
660
|
-
}
|
|
661
676
|
}
|
|
662
677
|
else if (detailsRecord.reason === "outpost_dispatch_unknown") {
|
|
663
678
|
if (raw.state !== "queued" ||
|
|
@@ -1505,10 +1520,10 @@ export function readAllLanes(hqRoot, deps = defaultStoreDeps()) {
|
|
|
1505
1520
|
const identity = indexedDeps.outpostIdentity();
|
|
1506
1521
|
const isRemoteMirror = outpostId !== undefined && (identity.kind === "not_outpost" ||
|
|
1507
1522
|
(identity.kind === "id" && identity.id !== outpostId));
|
|
1508
|
-
if (!isRemoteMirror)
|
|
1509
|
-
throw err;
|
|
1510
1523
|
const field = typeof err.details.field === "string" ? err.details.field : "unknown_field";
|
|
1511
|
-
process.stderr.write(
|
|
1524
|
+
process.stderr.write(isRemoteMirror
|
|
1525
|
+
? `lanes store: skipping malformed mirrored lane ${laneId} field ${field}: ${err.message}\n`
|
|
1526
|
+
: `lanes store: skipping unreadable lane ${laneId} field ${field}: ${err.message}\n`);
|
|
1512
1527
|
}
|
|
1513
1528
|
}
|
|
1514
1529
|
return records.sort((a, b) => Date.parse(a.created_at) - Date.parse(b.created_at) ||
|
|
@@ -1631,13 +1646,14 @@ export function createLane(hqRoot, init, deps = defaultStoreDeps()) {
|
|
|
1631
1646
|
senior_history: init.senior_history ?? [],
|
|
1632
1647
|
attribution_history: init.attribution_history ?? [],
|
|
1633
1648
|
};
|
|
1634
|
-
|
|
1649
|
+
const createdRecord = withoutStaleQueuedDetails(record);
|
|
1650
|
+
parseLaneRecord(createdRecord, filePath);
|
|
1635
1651
|
const created = withRecordLock(filePath, deps, () => {
|
|
1636
1652
|
if (deps.existsSync(filePath)) {
|
|
1637
1653
|
throw new LanesError("lane_exists", `Lane ${lane_id} already exists`, { lane_id });
|
|
1638
1654
|
}
|
|
1639
|
-
atomicWriteJson(filePath,
|
|
1640
|
-
return
|
|
1655
|
+
atomicWriteJson(filePath, createdRecord, deps);
|
|
1656
|
+
return createdRecord;
|
|
1641
1657
|
});
|
|
1642
1658
|
return syncStoryLedgerForLane(hqRoot, created, deps);
|
|
1643
1659
|
}
|
|
@@ -1689,30 +1705,30 @@ export function updateLane(hqRoot, laneId, expectedVersion, writer, updater, dep
|
|
|
1689
1705
|
}
|
|
1690
1706
|
if (!isTerminalLaneState(current.state) && isTerminalLaneState(updated.state)) {
|
|
1691
1707
|
const releasedGrant = updated.hire_grant ?? current.hire_grant ?? 0;
|
|
1692
|
-
return {
|
|
1708
|
+
return withoutStaleQueuedDetails({
|
|
1693
1709
|
...updated,
|
|
1694
1710
|
released_hire_grant: releasedGrant,
|
|
1695
1711
|
hire_grant: 0,
|
|
1696
|
-
};
|
|
1712
|
+
});
|
|
1697
1713
|
}
|
|
1698
1714
|
if (isTerminalLaneState(current.state) && !isTerminalLaneState(updated.state) &&
|
|
1699
1715
|
current.released_hire_grant !== undefined) {
|
|
1700
|
-
return {
|
|
1716
|
+
return withoutStaleQueuedDetails({
|
|
1701
1717
|
...updated,
|
|
1702
1718
|
hire_grant: current.released_hire_grant,
|
|
1703
1719
|
released_hire_grant: undefined,
|
|
1704
|
-
};
|
|
1720
|
+
});
|
|
1705
1721
|
}
|
|
1706
1722
|
if (isTerminalLaneState(updated.state) &&
|
|
1707
1723
|
(updated.hire_grant !== current.hire_grant ||
|
|
1708
1724
|
updated.released_hire_grant !== current.released_hire_grant)) {
|
|
1709
|
-
return {
|
|
1725
|
+
return withoutStaleQueuedDetails({
|
|
1710
1726
|
...updated,
|
|
1711
1727
|
hire_grant: 0,
|
|
1712
1728
|
released_hire_grant: updated.released_hire_grant ?? updated.hire_grant ?? 0,
|
|
1713
|
-
};
|
|
1729
|
+
});
|
|
1714
1730
|
}
|
|
1715
|
-
return updated;
|
|
1731
|
+
return withoutStaleQueuedDetails(updated);
|
|
1716
1732
|
}, deps, {
|
|
1717
1733
|
beforeWrite: (current) => assertLaneStoreWriteAllowed(current, laneId, writer),
|
|
1718
1734
|
stamp: (current) => ({ written_by_version: newestLaneStoreVersion(current.written_by_version) }),
|