@indigoai-us/hq-cli 5.201.0 → 5.201.1
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
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.201.1] — 2026-09-25
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Outpost grant checks now include child lanes from the owning Outpost. Owner
|
|
10
|
+
records take precedence over duplicate primary records, and each grant
|
|
11
|
+
command reads the owner lane list once.
|
|
12
|
+
- Outpost grant checks re-read owner lanes under the hire lock and use the
|
|
13
|
+
validated Outpost CLI override for the lane-list probe.
|
|
14
|
+
|
|
5
15
|
## [5.201.0] — 2026-09-25
|
|
6
16
|
|
|
7
17
|
### Added
|
package/dist/commands/lanes.js
CHANGED
|
@@ -479,6 +479,14 @@ function laneHireFields(lane, lanes) {
|
|
|
479
479
|
hire_summary: hireSummary,
|
|
480
480
|
};
|
|
481
481
|
}
|
|
482
|
+
function mergeOwnerLaneHierarchy(supplied, ownerLanes) {
|
|
483
|
+
const byId = new Map();
|
|
484
|
+
for (const lane of supplied)
|
|
485
|
+
byId.set(lane.lane_id, lane);
|
|
486
|
+
for (const lane of ownerLanes)
|
|
487
|
+
byId.set(lane.lane_id, lane);
|
|
488
|
+
return [...byId.values()];
|
|
489
|
+
}
|
|
482
490
|
function outpostCliOverride(ctx, outpostId) {
|
|
483
491
|
const envKey = `HQ_LANES_OUTPOST_CLI_${outpostId.toUpperCase().replace(/[^A-Z0-9_]/g, "_")}`;
|
|
484
492
|
const configured = ctx.env[envKey];
|
|
@@ -1031,11 +1039,12 @@ async function loadHostCapacitySnapshots(ctx, hqRoot, config = loadLanesConfig(h
|
|
|
1031
1039
|
};
|
|
1032
1040
|
}
|
|
1033
1041
|
async function readOutpostLaneRecords(ctx, outpostId) {
|
|
1042
|
+
const hqBinary = outpostCliOverride(ctx, outpostId);
|
|
1034
1043
|
let result;
|
|
1035
1044
|
try {
|
|
1036
1045
|
result = await ctx.dispatchOutpostExec({
|
|
1037
1046
|
outpostId,
|
|
1038
|
-
command: buildOutpostLaneListCommand(),
|
|
1047
|
+
command: buildOutpostLaneListCommand({ hqBinary }),
|
|
1039
1048
|
timeoutSeconds: CAPACITY_PROBE_TIMEOUT_MS / 1000,
|
|
1040
1049
|
waitMs: CAPACITY_PROBE_TIMEOUT_MS,
|
|
1041
1050
|
});
|
|
@@ -3312,9 +3321,20 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options) {
|
|
|
3312
3321
|
throw new LanesError("outpost_dispatch_failed", `Lane ${lane.lane_id} has no Outpost host to dispatch to`, { lane_id: lane.lane_id });
|
|
3313
3322
|
}
|
|
3314
3323
|
const outpostId = lane.host.id;
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3324
|
+
let grantContext;
|
|
3325
|
+
let grantHierarchy;
|
|
3326
|
+
if (action === "grant") {
|
|
3327
|
+
const enforcementEnabled = await ctx.laneHireGrantsEnabled(lane.company);
|
|
3328
|
+
let hierarchy = loadAllLanes(ctx.hqRoot());
|
|
3329
|
+
const ownerLanes = await readOutpostLaneRecords(ctx, outpostId);
|
|
3330
|
+
const byId = new Map(hierarchy.map((record) => [record.lane_id, record]));
|
|
3331
|
+
for (const ownerLane of ownerLanes) {
|
|
3332
|
+
byId.set(ownerLane.lane_id, ownerLane);
|
|
3333
|
+
}
|
|
3334
|
+
hierarchy = [...byId.values()];
|
|
3335
|
+
grantHierarchy = hierarchy;
|
|
3336
|
+
grantContext = createOutpostHireGrantContext(lane, hierarchy, enforcementEnabled);
|
|
3337
|
+
}
|
|
3318
3338
|
let dispatched;
|
|
3319
3339
|
try {
|
|
3320
3340
|
dispatched = await ctx.dispatchOutpostExec({
|
|
@@ -3407,6 +3427,7 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options) {
|
|
|
3407
3427
|
...remote,
|
|
3408
3428
|
lane_id: ownerLane.lane_id,
|
|
3409
3429
|
lane: ownerLane,
|
|
3430
|
+
...laneHireFields(ownerLane, grantHierarchy ?? []),
|
|
3410
3431
|
outpost_id: outpostId,
|
|
3411
3432
|
outpost_command_id: dispatched.commandId,
|
|
3412
3433
|
outpost_transport: "outposts_exec",
|
|
@@ -4518,7 +4539,11 @@ async function applyHireGrant(ctx, laneId, hireGrant, authorization, grantContex
|
|
|
4518
4539
|
(!grantContext || !sameHireGrantSenior(current.senior, grantContext.expected_senior))) {
|
|
4519
4540
|
throw new LanesError("hire_grant_senior_changed", `Lane ${laneId}'s senior changed before the Outpost applied the grant update`, { lane_id: laneId, current_senior: current.senior });
|
|
4520
4541
|
}
|
|
4521
|
-
const hierarchy = grantContext
|
|
4542
|
+
const hierarchy = grantContext
|
|
4543
|
+
? authorization === "ssm-owner-dispatch"
|
|
4544
|
+
? mergeOwnerLaneHierarchy(grantContext.hierarchy, loadAllLanes(hqRoot))
|
|
4545
|
+
: grantContext.hierarchy
|
|
4546
|
+
: loadAllLanes(hqRoot);
|
|
4522
4547
|
if (enforce && current.senior.kind === "lane") {
|
|
4523
4548
|
if (!current.senior.id) {
|
|
4524
4549
|
throw new LanesError("hire_grant_senior_invalid", `Lane ${laneId} has a lane senior without an id`, {
|
|
@@ -4604,7 +4629,8 @@ async function runGrantOwnerTarget(ctx, laneId, opts) {
|
|
|
4604
4629
|
const hireGrant = parseHireGrant(opts.hire);
|
|
4605
4630
|
const grantContext = parseOutpostHireGrantContext(opts.grantContext, laneId);
|
|
4606
4631
|
const hqRoot = ctx.hqRoot();
|
|
4607
|
-
|
|
4632
|
+
const updated = await applyHireGrant(ctx, laneId, hireGrant, "ssm-owner-dispatch", grantContext);
|
|
4633
|
+
printGrantResult(hqRoot, updated, mergeOwnerLaneHierarchy(grantContext.hierarchy, loadAllLanes(hqRoot)));
|
|
4608
4634
|
}
|
|
4609
4635
|
async function runBackfillGrants(ctx, opts) {
|
|
4610
4636
|
if (opts.apply && opts.dryRun) {
|
|
@@ -72,7 +72,7 @@ export declare function parseOutpostPickupPayload(raw: unknown): OutpostPickupPa
|
|
|
72
72
|
export declare function buildOutpostPickupCommand(payloadUrl: string): string;
|
|
73
73
|
/** Bounded, read-only capacity query executed by the target Outpost CLI. */
|
|
74
74
|
export declare function buildOutpostCapacityCommand(): string;
|
|
75
|
-
/** Read
|
|
75
|
+
/** Read lane records owned by an Outpost, using its configured HQ binary when set. */
|
|
76
76
|
export declare function buildOutpostLaneListCommand(input?: {
|
|
77
77
|
hqBinary?: string;
|
|
78
78
|
}): string;
|
|
@@ -65,7 +65,7 @@ export function buildOutpostPickupCommand(payloadUrl) {
|
|
|
65
65
|
export function buildOutpostCapacityCommand() {
|
|
66
66
|
return withRemoteHqDir(joinCommandParts(["hq", "lanes", "capacity", "--json"]));
|
|
67
67
|
}
|
|
68
|
-
/** Read
|
|
68
|
+
/** Read lane records owned by an Outpost, using its configured HQ binary when set. */
|
|
69
69
|
export function buildOutpostLaneListCommand(input = {}) {
|
|
70
70
|
return withRemoteHqDir(joinCommandParts([
|
|
71
71
|
input.hqBinary?.trim() || "hq",
|