@indigoai-us/hq-cli 5.254.0 → 5.256.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.
- package/CHANGELOG.md +12 -0
- package/dist/commands/integrations-import.js +3 -1
- package/dist/commands/lanes-shared.d.ts +27 -0
- package/dist/commands/lanes-watch.d.ts +7 -0
- package/dist/commands/lanes-watch.js +215 -0
- package/dist/commands/lanes.js +14 -211
- package/dist/commands/pack-install.js +3 -1
- package/dist/commands/run.js +10 -2
- package/dist/commands/secrets.d.ts +4 -1
- package/dist/commands/secrets.js +56 -19
- package/dist/run/hq-plugin.d.ts +4 -0
- package/dist/run/hq-plugin.js +30 -3
- package/dist/utils/cognito-session.d.ts +2 -0
- package/dist/utils/cognito-session.js +5 -0
- package/dist/utils/secret-load-availability.d.ts +8 -0
- package/dist/utils/secret-load-availability.js +54 -0
- package/dist/utils/secrets-cache.d.ts +7 -3
- package/dist/utils/secrets-cache.js +162 -14
- package/dist/utils/vault-api.d.ts +5 -1
- package/dist/utils/vault-api.js +82 -23
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.256.0] — 2026-09-28
|
|
6
|
+
|
|
7
|
+
## [5.255.0] — 2026-09-28
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Internal: moved watch, monitor-check, and wait handlers to src/commands/lanes-watch.ts; behavior is unchanged.
|
|
12
|
+
|
|
5
13
|
## [5.254.0] — 2026-09-28
|
|
6
14
|
|
|
7
15
|
### Added
|
|
@@ -14,9 +22,13 @@
|
|
|
14
22
|
### Fixed
|
|
15
23
|
|
|
16
24
|
- The end-of-session work report is no longer dropped when the background
|
|
25
|
+
transcript watcher polls late or adopts a session after a restart. A
|
|
26
|
+
synthesized `turn_end` now carries the transcript time, capped at now, and
|
|
27
|
+
is never earlier than the last event sent for the session.
|
|
17
28
|
- `hq db sql --remote` is hidden because remote SQL is not available in this
|
|
18
29
|
CLI build. Existing scripts get a clear error, and local SQL remains
|
|
19
30
|
available without `--remote`.
|
|
31
|
+
- `hq secrets` and `hq run` now use cached secrets during a temporary server outage, up to each secret’s configured cache lifetime. The default is three hours; revoked and high-security secrets still fail closed.
|
|
20
32
|
|
|
21
33
|
## [5.253.0] — 2026-09-27
|
|
22
34
|
|
|
@@ -350,7 +350,9 @@ export function registerImportCommands(integrations) {
|
|
|
350
350
|
}
|
|
351
351
|
const secretNames = [...Object.values({ ...(manifest.env ?? {}), ...(manifest.headers ?? {}) }), ...(manifest.args ?? [])]
|
|
352
352
|
.flatMap((value) => [...value.matchAll(/\$\{secret:([A-Z][A-Z0-9_]*(?:\/[A-Z][A-Z0-9_]*)*)\}/g)].map((match) => match[1]));
|
|
353
|
-
const secrets = await loadRevealedSecrets(token, companyUid, secretNames
|
|
353
|
+
const secrets = await loadRevealedSecrets(token, companyUid, secretNames, undefined, {
|
|
354
|
+
allowOfflineFallback: false,
|
|
355
|
+
});
|
|
354
356
|
const result = registerServer({
|
|
355
357
|
name: safeName,
|
|
356
358
|
manifest,
|
|
@@ -7,6 +7,7 @@ import type { WatcherLoopDeps } from "../lib/lanes/watcher.js";
|
|
|
7
7
|
import type { RunCompactionFn } from "../lib/lanes/compaction.js";
|
|
8
8
|
import type { LaneMesh, LaneMeshEvent } from "../lib/lanes/mesh-events.js";
|
|
9
9
|
import type { BalanceHostGap, BalanceHostSnapshot } from "../lib/lanes/claude-balance.js";
|
|
10
|
+
import type { HostCapacitySnapshot } from "../lib/lanes/host-capacity.js";
|
|
10
11
|
import { type ResolvedEffort } from "../lib/lanes/effort.js";
|
|
11
12
|
import type { SessionCopyResult } from "../lib/lanes/move-account.js";
|
|
12
13
|
import type { WorkerProfile } from "../lib/lanes/profile.js";
|
|
@@ -223,6 +224,32 @@ export interface Ctx {
|
|
|
223
224
|
laneTrackerEnabled: (company: LaneCompanyRef) => boolean | Promise<boolean>;
|
|
224
225
|
trackerActor: () => string | null;
|
|
225
226
|
}
|
|
227
|
+
export interface LaneWaitCommandOptions {
|
|
228
|
+
any?: string[];
|
|
229
|
+
for?: string[];
|
|
230
|
+
timeout?: string;
|
|
231
|
+
json?: boolean;
|
|
232
|
+
}
|
|
233
|
+
export interface MonitorCheckOptions {
|
|
234
|
+
session?: string;
|
|
235
|
+
engine?: string;
|
|
236
|
+
json?: boolean;
|
|
237
|
+
reminder?: boolean;
|
|
238
|
+
}
|
|
239
|
+
export interface LaneWatchOptions {
|
|
240
|
+
intervalMs?: string;
|
|
241
|
+
json?: boolean;
|
|
242
|
+
}
|
|
243
|
+
export interface LaneWatchHandlerDeps {
|
|
244
|
+
laneHostFromCtx(ctx: Ctx): LaneRecord["host"];
|
|
245
|
+
loadAllLanes(hqRoot: string): LaneRecord[];
|
|
246
|
+
loadClaudeBalanceHostSnapshots(ctx: Ctx, hqRoot: string, config: LanesConfig): Promise<{
|
|
247
|
+
snapshots: BalanceHostSnapshot[];
|
|
248
|
+
unavailableHosts: BalanceHostGap[];
|
|
249
|
+
}>;
|
|
250
|
+
printJson(value: unknown): void;
|
|
251
|
+
readOutpostCapacity(ctx: Ctx, outpostId: string): Promise<HostCapacitySnapshot>;
|
|
252
|
+
}
|
|
226
253
|
export interface PrimaryOwnedOutpostQuestion {
|
|
227
254
|
question: QuestionRecord;
|
|
228
255
|
lane: LaneRecord;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Ctx, MonitorCheckOptions, LaneWaitCommandOptions, LaneWatchHandlerDeps, LaneWatchOptions } from "./lanes-shared.js";
|
|
2
|
+
export declare function createLaneWatchHandlers(deps: LaneWatchHandlerDeps): {
|
|
3
|
+
runWatch: (ctx: Ctx, laneIds: string[], opts: LaneWatchOptions) => Promise<number>;
|
|
4
|
+
runMonitorCheck: (ctx: Ctx, opts: MonitorCheckOptions) => Promise<number>;
|
|
5
|
+
runWait: (ctx: Ctx, opts: LaneWaitCommandOptions) => Promise<number>;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=lanes-watch.d.ts.map
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { accountStatus, coveredLaneIds, loadLanesConfig, MAX_WATCHED_LANES, MONITOR_ENGINES, MONITOR_MAX_TIMEOUT_MS, MONITOR_UNCOVERED_EXIT_CODE, monitorReminderText, runLaneWatch, } from "../lib/lanes/index.js";
|
|
2
|
+
import { LEAD_LANE_KEEP_ALIVE_FLAG } from "../lib/lanes/keep-alive.js";
|
|
3
|
+
import { readLanesRegistryFlag } from "../lib/lanes/registry-flag.js";
|
|
4
|
+
import { isLanesError, LanesError } from "../lib/lanes/errors.js";
|
|
5
|
+
import { LANE_WAIT_INVALID_INPUT_EXIT_CODE, LANE_WAIT_TIMEOUT_EXIT_CODE, runLaneWait, } from "../lib/lanes/wait.js";
|
|
6
|
+
const MONITOR_ACTIVE_LANE_STATES = new Set([
|
|
7
|
+
"running",
|
|
8
|
+
"queued",
|
|
9
|
+
"awaiting_input",
|
|
10
|
+
"blocked",
|
|
11
|
+
]);
|
|
12
|
+
function resolveMonitorEngine(requested, env) {
|
|
13
|
+
const value = requested?.trim().toLowerCase() ||
|
|
14
|
+
env.HQ_CONDUCT_ENGINE?.trim().toLowerCase() ||
|
|
15
|
+
"claude";
|
|
16
|
+
if (!MONITOR_ENGINES.includes(value)) {
|
|
17
|
+
throw new LanesError("monitor_invalid_engine", `Unknown monitor-check engine ${JSON.stringify(value)}. Accepted: ${MONITOR_ENGINES.join(", ")}`, { accepted: [...MONITOR_ENGINES], value });
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
function monitorCallsForLaneIds(laneIds) {
|
|
22
|
+
const calls = [];
|
|
23
|
+
for (let offset = 0; offset < laneIds.length; offset += MAX_WATCHED_LANES) {
|
|
24
|
+
const chunk = laneIds.slice(offset, offset + MAX_WATCHED_LANES);
|
|
25
|
+
calls.push({
|
|
26
|
+
command: `hq lanes watch ${chunk.join(" ")}`,
|
|
27
|
+
timeout_ms: MONITOR_MAX_TIMEOUT_MS,
|
|
28
|
+
persistent: true,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return calls;
|
|
32
|
+
}
|
|
33
|
+
function laneWaitHumanLine(result) {
|
|
34
|
+
const details = Object.entries(result.change)
|
|
35
|
+
.filter(([key]) => key !== "type")
|
|
36
|
+
.map(([key, value]) => `${key}=${String(value)}`)
|
|
37
|
+
.join(" ");
|
|
38
|
+
return `lane=${result.lane_id} change=${result.change.type}${details ? ` ${details}` : ""} at=${result.at}`;
|
|
39
|
+
}
|
|
40
|
+
export function createLaneWatchHandlers(deps) {
|
|
41
|
+
const { laneHostFromCtx, loadAllLanes, loadClaudeBalanceHostSnapshots, printJson, readOutpostCapacity, } = deps;
|
|
42
|
+
async function runWatch(ctx, laneIds, opts) {
|
|
43
|
+
const rawInterval = opts.intervalMs === undefined ? undefined : Number(opts.intervalMs);
|
|
44
|
+
const hqRoot = ctx.hqRoot();
|
|
45
|
+
await runLaneWatch(hqRoot, laneIds, {
|
|
46
|
+
intervalMs: rawInterval,
|
|
47
|
+
sleep: ctx.sleep,
|
|
48
|
+
keepAliveEnabled: (lane) => readLanesRegistryFlag(LEAD_LANE_KEEP_ALIVE_FLAG, {
|
|
49
|
+
company: lane.company,
|
|
50
|
+
env: ctx.env,
|
|
51
|
+
}),
|
|
52
|
+
readAccountStatuses: async (lanes) => {
|
|
53
|
+
if (lanes.length === 0)
|
|
54
|
+
return [];
|
|
55
|
+
const config = loadLanesConfig(hqRoot);
|
|
56
|
+
const currentHost = laneHostFromCtx(ctx);
|
|
57
|
+
const currentHostname = ctx.hostname().trim();
|
|
58
|
+
const isCurrentHost = (host) => (host.kind === currentHost.kind && host.id === currentHost.id) ||
|
|
59
|
+
(host.kind === "local" && host.id === currentHostname);
|
|
60
|
+
const remoteOutpostIds = [...new Set(lanes
|
|
61
|
+
.filter((lane) => lane.host.kind === "outpost" && !isCurrentHost(lane.host))
|
|
62
|
+
.map((lane) => lane.host.id))];
|
|
63
|
+
const remoteOutposts = await Promise.all(remoteOutpostIds.map(async (id) => [id, await readOutpostCapacity(ctx, id)]));
|
|
64
|
+
const outpostSnapshots = new Map(remoteOutposts);
|
|
65
|
+
const remoteLocalLanes = lanes.filter((lane) => lane.host.kind === "local" && !isCurrentHost(lane.host));
|
|
66
|
+
const remoteLocalHosts = remoteLocalLanes.length > 0
|
|
67
|
+
? await loadClaudeBalanceHostSnapshots(ctx, hqRoot, config)
|
|
68
|
+
: undefined;
|
|
69
|
+
const localStatusCache = new Map();
|
|
70
|
+
return lanes.map((lane) => {
|
|
71
|
+
if (config.providers[lane.provider].accounts[lane.account] === undefined) {
|
|
72
|
+
throw new LanesError("watch_account_unconfigured", `Lane ${lane.lane_id} records unconfigured ${lane.provider} account ${lane.account}`, { lane_id: lane.lane_id, provider: lane.provider, account: lane.account, host: lane.host });
|
|
73
|
+
}
|
|
74
|
+
let loggedIn;
|
|
75
|
+
if (isCurrentHost(lane.host)) {
|
|
76
|
+
const key = JSON.stringify([lane.provider, lane.account, currentHost.kind, currentHost.id]);
|
|
77
|
+
if (!localStatusCache.has(key)) {
|
|
78
|
+
localStatusCache.set(key, accountStatus(lane.provider, lane.account, config, {
|
|
79
|
+
existsSync: ctx.existsSync,
|
|
80
|
+
probe: ctx.probeProvider,
|
|
81
|
+
env: ctx.env,
|
|
82
|
+
hostname: currentHostname,
|
|
83
|
+
}).logged_in);
|
|
84
|
+
}
|
|
85
|
+
loggedIn = localStatusCache.get(key);
|
|
86
|
+
}
|
|
87
|
+
else if (lane.host.kind === "outpost") {
|
|
88
|
+
loggedIn = outpostSnapshots.get(lane.host.id)?.providers[lane.provider].accounts[lane.account]?.logged_in;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const snapshot = remoteLocalHosts?.snapshots.find((candidate) => candidate.capacity.host.kind === lane.host.kind &&
|
|
92
|
+
candidate.capacity.host.id === lane.host.id);
|
|
93
|
+
if (!snapshot) {
|
|
94
|
+
const gap = remoteLocalHosts?.unavailableHosts.find((candidate) => candidate.host.kind === lane.host.kind && candidate.host.id === lane.host.id);
|
|
95
|
+
throw new LanesError("watch_account_host_unavailable", `Cannot check ${lane.provider} account ${lane.account} on ${lane.host.kind}:${lane.host.id}${gap ? `: ${gap.reason}` : ""}`, { lane_id: lane.lane_id, provider: lane.provider, account: lane.account, host: lane.host });
|
|
96
|
+
}
|
|
97
|
+
loggedIn = snapshot.capacity.providers[lane.provider].accounts[lane.account]?.logged_in;
|
|
98
|
+
}
|
|
99
|
+
if (loggedIn === undefined) {
|
|
100
|
+
throw new LanesError("watch_account_unconfigured", `Lane ${lane.lane_id} records unconfigured ${lane.provider} account ${lane.account} on ${lane.host.kind}:${lane.host.id}`, { lane_id: lane.lane_id, provider: lane.provider, account: lane.account, host: lane.host });
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
lane_id: lane.lane_id,
|
|
104
|
+
provider: lane.provider,
|
|
105
|
+
account: lane.account,
|
|
106
|
+
host: lane.host,
|
|
107
|
+
logged_in: loggedIn,
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
writeLine: (line) => console.log(opts.json ? JSON.stringify({ event: line }) : line),
|
|
112
|
+
writeAccountEvent: (event) => console.log(opts.json ? JSON.stringify(event) : `account_logged_out provider=${event.provider} account=${event.account} host=${event.host.kind}:${event.host.id} lane_ids=${event.lane_ids.join(",")}`),
|
|
113
|
+
writeError: (line) => process.stderr.write(`${line}\n`),
|
|
114
|
+
});
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
async function runMonitorCheck(ctx, opts) {
|
|
118
|
+
if (opts.reminder) {
|
|
119
|
+
console.log(monitorReminderText());
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
const sessionId = opts.session?.trim();
|
|
123
|
+
if (!sessionId) {
|
|
124
|
+
throw new LanesError("monitor_session_required", "hq lanes monitor-check requires --session <id> unless --reminder is used");
|
|
125
|
+
}
|
|
126
|
+
const engine = resolveMonitorEngine(opts.engine, ctx.env);
|
|
127
|
+
const activeLanes = loadAllLanes(ctx.hqRoot()).filter((lane) => lane.senior.kind === "session" &&
|
|
128
|
+
lane.senior.id === sessionId &&
|
|
129
|
+
MONITOR_ACTIVE_LANE_STATES.has(lane.state));
|
|
130
|
+
if (engine !== "claude") {
|
|
131
|
+
if (opts.json) {
|
|
132
|
+
printJson({
|
|
133
|
+
ok: true,
|
|
134
|
+
action: "monitor-check",
|
|
135
|
+
session_id: sessionId,
|
|
136
|
+
engine,
|
|
137
|
+
active_lane_ids: activeLanes.map((lane) => lane.lane_id),
|
|
138
|
+
covered_lane_ids: [],
|
|
139
|
+
uncovered_lane_ids: [],
|
|
140
|
+
skipped: "engine_has_no_claude_monitor",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
if (activeLanes.length === 0) {
|
|
146
|
+
if (opts.json) {
|
|
147
|
+
printJson({
|
|
148
|
+
ok: true,
|
|
149
|
+
action: "monitor-check",
|
|
150
|
+
session_id: sessionId,
|
|
151
|
+
engine,
|
|
152
|
+
active_lane_ids: [],
|
|
153
|
+
covered_lane_ids: [],
|
|
154
|
+
uncovered_lane_ids: [],
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
const evidence = await ctx.monitorEvidence(sessionId);
|
|
160
|
+
if (evidence.sessionId !== sessionId) {
|
|
161
|
+
throw new LanesError("monitor_evidence_session_mismatch", `Monitor evidence was for ${JSON.stringify(evidence.sessionId)}, expected ${JSON.stringify(sessionId)}`);
|
|
162
|
+
}
|
|
163
|
+
const covered = coveredLaneIds(evidence, ctx.now());
|
|
164
|
+
const activeIds = activeLanes.map((lane) => lane.lane_id);
|
|
165
|
+
const uncovered = activeIds.filter((laneId) => !covered.has(laneId));
|
|
166
|
+
const monitorCalls = monitorCallsForLaneIds(uncovered);
|
|
167
|
+
if (opts.json) {
|
|
168
|
+
printJson({
|
|
169
|
+
ok: uncovered.length === 0,
|
|
170
|
+
action: "monitor-check",
|
|
171
|
+
session_id: sessionId,
|
|
172
|
+
engine,
|
|
173
|
+
active_lane_ids: activeIds,
|
|
174
|
+
covered_lane_ids: activeIds.filter((laneId) => covered.has(laneId)),
|
|
175
|
+
uncovered_lane_ids: uncovered,
|
|
176
|
+
monitor_call: monitorCalls.length === 1 ? monitorCalls[0] : null,
|
|
177
|
+
monitor_calls: monitorCalls,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else if (uncovered.length > 0) {
|
|
181
|
+
for (const laneId of uncovered)
|
|
182
|
+
console.log(`uncovered lane: ${laneId}`);
|
|
183
|
+
for (const monitorCall of monitorCalls) {
|
|
184
|
+
console.log(`Monitor(command=${JSON.stringify(monitorCall.command)}, timeout_ms=${monitorCall.timeout_ms}, persistent=true)`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return uncovered.length > 0 ? MONITOR_UNCOVERED_EXIT_CODE : 0;
|
|
188
|
+
}
|
|
189
|
+
async function runWait(ctx, opts) {
|
|
190
|
+
const timeoutSeconds = opts.timeout === undefined ? Number.NaN : Number(opts.timeout);
|
|
191
|
+
try {
|
|
192
|
+
const result = await runLaneWait(ctx.hqRoot(), opts.any ?? [], opts.for ?? [], timeoutSeconds * 1000, { now: ctx.now, sleep: ctx.sleep });
|
|
193
|
+
if (result) {
|
|
194
|
+
console.log(opts.json ? JSON.stringify(result) : laneWaitHumanLine(result));
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
console.log(opts.json
|
|
198
|
+
? JSON.stringify({ ok: false, error: "wait_timeout" })
|
|
199
|
+
: "wait_timeout");
|
|
200
|
+
return LANE_WAIT_TIMEOUT_EXIT_CODE;
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
if (!isLanesError(err) || err.error !== "wait_invalid_input")
|
|
204
|
+
throw err;
|
|
205
|
+
const output = { ok: false, error: err.error, message: err.message };
|
|
206
|
+
if (opts.json)
|
|
207
|
+
console.log(JSON.stringify(output));
|
|
208
|
+
else
|
|
209
|
+
process.stderr.write(`${err.message}\n`);
|
|
210
|
+
return LANE_WAIT_INVALID_INPUT_EXIT_CODE;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return { runWatch, runMonitorCheck, runWait };
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=lanes-watch.js.map
|
package/dist/commands/lanes.js
CHANGED
|
@@ -15,6 +15,7 @@ import { createLaneAccountsHandlers } from "./lanes-accounts.js";
|
|
|
15
15
|
import { createLaneMessageHandlers } from "./lanes-message.js";
|
|
16
16
|
import { createLaneQuestionsHandlers } from "./lanes-questions.js";
|
|
17
17
|
import { createLaneResumeHandlers } from "./lanes-resume.js";
|
|
18
|
+
import { createLaneWatchHandlers } from "./lanes-watch.js";
|
|
18
19
|
export { resolveAnswerChoice } from "./lanes-questions.js";
|
|
19
20
|
import { registerOutpostPrunerCommand } from "./outpost-pruner.js";
|
|
20
21
|
import { registerLaneChecksCommand } from "./lanes-checks.js";
|
|
@@ -45,16 +46,15 @@ import { assertNoSecretText } from "../lib/lanes/text-scan.js";
|
|
|
45
46
|
import { createLaneMesh, emitLaneDecisionEvents, emitLaneTerminalStateEvent, laneMeshEventIdentity, } from "../lib/lanes/mesh-events.js";
|
|
46
47
|
import { sessionIdFromEnv } from "../lib/mesh/live/session-identity.js";
|
|
47
48
|
import { effectiveAccountHome } from "../lib/lanes/account-home.js";
|
|
48
|
-
import { AccountResolutionError, compareLaneQueueOrder,
|
|
49
|
+
import { AccountResolutionError, compareLaneQueueOrder, LANE_PROVIDERS, LANE_STATES, QUESTION_STATUSES, SENIOR_KINDS, accountStatus, appendCappedHistory, canonicalizeHome, createLane, decideAdmission, defaultLivenessDeps, defaultSystemdUserDir, defaultThrottleDeps, installReconcileTimer, providerPathEnv, probeDrainHookRegistration, isLanesError, isLaneVersionConflict, isTerminalLaneState, aliveDirectChildren, assignedChildHireGrants, hireGrantCapacityError, planHireGrantBackfill, terminalChildResumeHireGrantError, withHireGrantAdmission, laneStoryLedgerEnabled, validateProjectStories, buildLaneStatusSnapshot, formatLaneStatusHuman, listLaneIds, listQuestionIds, loadLanesConfig, laneRunsHere, MAX_LANE_DEPTH, MONITOR_ERROR_EXIT_CODE, readLiveMonitorEvidence, resolveMachineIdentity as lookupMachineIdentity, loadLivenessIndex, parseLaneProvider, parseLaneRecord, parseLaneState, parseQuestionRecord, parseSeniorKind, readLane, retryUpdateLane, syncLaneRecordFromOwner, readQuestion, resolveAccount, resolveLaneWorker, ignoredWorkerProfileFields, loadWorkerProfile, loadWorkerProfileWithRegistry, registryWorkerRecord, runReconcilePass, sessionLiveness, tryReadLane, uninstallReconcileTimer, updateLane, updateQuestion, dropboxDir, laneDeliveryMechanism, hasActiveAdmissionReservation, hasActivePendingResume, hasRecordedSessionId, hasEarlierEligibleQueuedLane, laneAdmissionCapReason, providerSupportsSessionResume, providerSessionPortable, sessionNotPortableMessage, withLaneAdmissionLock, withAllLaneAdmissionLocks, withLaneHireLocks, raiseLaneQuestion, sha256Text, } from "../lib/lanes/index.js";
|
|
49
50
|
import { activeLaneStories, laneStories, laneStory, storyWarning, } from "../lib/lanes/stories.js";
|
|
50
51
|
import { resolveLaneKeepAlive } from "../lib/lanes/profile.js";
|
|
51
|
-
import { keepAliveExclusion,
|
|
52
|
+
import { keepAliveExclusion, LANE_SUPERSESSION_LINEAGE_AWARE_FLAG, loadRetiredLaneIds, } from "../lib/lanes/keep-alive.js";
|
|
52
53
|
import { questionBodyAbsPath, resolveQuestionCompanyWithFallback, resolveProjectQuestionCompany, } from "../lib/lanes/questions.js";
|
|
53
54
|
import { assertQuestionBodySecretSafe } from "../lib/lanes/questions.js";
|
|
54
55
|
import { compactionAfterUsage, } from "../lib/lanes/compaction.js";
|
|
55
56
|
import { parseCliEffort, resolveLaneEffort, } from "../lib/lanes/effort.js";
|
|
56
57
|
import { LanesError } from "../lib/lanes/errors.js";
|
|
57
|
-
import { LANE_WAIT_INVALID_INPUT_EXIT_CODE, LANE_WAIT_TIMEOUT_EXIT_CODE, runLaneWait, } from "../lib/lanes/wait.js";
|
|
58
58
|
import { loadQuotaState, quotaBlockFor } from "../lib/lanes/quota.js";
|
|
59
59
|
import { SESSION_MOVE_REASON } from "../lib/lanes/move-account.js";
|
|
60
60
|
import { managerStatusGateEnabledForLane, resolveManagerStatusGateForLane, } from "../lib/lanes/manager-status-gate.js";
|
|
@@ -1196,180 +1196,6 @@ function assertPlacementEnabled(ctx) {
|
|
|
1196
1196
|
function loadAllQuestions(hqRoot) {
|
|
1197
1197
|
return listQuestionIds(hqRoot).map((id) => readQuestion(hqRoot, id));
|
|
1198
1198
|
}
|
|
1199
|
-
const MONITOR_ACTIVE_LANE_STATES = new Set([
|
|
1200
|
-
"running",
|
|
1201
|
-
"queued",
|
|
1202
|
-
"awaiting_input",
|
|
1203
|
-
"blocked",
|
|
1204
|
-
]);
|
|
1205
|
-
function resolveMonitorEngine(requested, env) {
|
|
1206
|
-
const value = requested?.trim().toLowerCase() ||
|
|
1207
|
-
env.HQ_CONDUCT_ENGINE?.trim().toLowerCase() ||
|
|
1208
|
-
"claude";
|
|
1209
|
-
if (!MONITOR_ENGINES.includes(value)) {
|
|
1210
|
-
throw new LanesError("monitor_invalid_engine", `Unknown monitor-check engine ${JSON.stringify(value)}. Accepted: ${MONITOR_ENGINES.join(", ")}`, { accepted: [...MONITOR_ENGINES], value });
|
|
1211
|
-
}
|
|
1212
|
-
return value;
|
|
1213
|
-
}
|
|
1214
|
-
async function runWatch(ctx, laneIds, opts) {
|
|
1215
|
-
const rawInterval = opts.intervalMs === undefined ? undefined : Number(opts.intervalMs);
|
|
1216
|
-
const hqRoot = ctx.hqRoot();
|
|
1217
|
-
await runLaneWatch(hqRoot, laneIds, {
|
|
1218
|
-
intervalMs: rawInterval,
|
|
1219
|
-
sleep: ctx.sleep,
|
|
1220
|
-
keepAliveEnabled: (lane) => readLanesRegistryFlag(LEAD_LANE_KEEP_ALIVE_FLAG, {
|
|
1221
|
-
company: lane.company,
|
|
1222
|
-
env: ctx.env,
|
|
1223
|
-
}),
|
|
1224
|
-
readAccountStatuses: async (lanes) => {
|
|
1225
|
-
if (lanes.length === 0)
|
|
1226
|
-
return [];
|
|
1227
|
-
const config = loadLanesConfig(hqRoot);
|
|
1228
|
-
const currentHost = laneHostFromCtx(ctx);
|
|
1229
|
-
const currentHostname = ctx.hostname().trim();
|
|
1230
|
-
const isCurrentHost = (host) => (host.kind === currentHost.kind && host.id === currentHost.id) ||
|
|
1231
|
-
(host.kind === "local" && host.id === currentHostname);
|
|
1232
|
-
const remoteOutpostIds = [...new Set(lanes
|
|
1233
|
-
.filter((lane) => lane.host.kind === "outpost" && !isCurrentHost(lane.host))
|
|
1234
|
-
.map((lane) => lane.host.id))];
|
|
1235
|
-
const remoteOutposts = await Promise.all(remoteOutpostIds.map(async (id) => [id, await readOutpostCapacity(ctx, id)]));
|
|
1236
|
-
const outpostSnapshots = new Map(remoteOutposts);
|
|
1237
|
-
const remoteLocalLanes = lanes.filter((lane) => lane.host.kind === "local" && !isCurrentHost(lane.host));
|
|
1238
|
-
const remoteLocalHosts = remoteLocalLanes.length > 0
|
|
1239
|
-
? await loadClaudeBalanceHostSnapshots(ctx, hqRoot, config)
|
|
1240
|
-
: undefined;
|
|
1241
|
-
const localStatusCache = new Map();
|
|
1242
|
-
return lanes.map((lane) => {
|
|
1243
|
-
if (config.providers[lane.provider].accounts[lane.account] === undefined) {
|
|
1244
|
-
throw new LanesError("watch_account_unconfigured", `Lane ${lane.lane_id} records unconfigured ${lane.provider} account ${lane.account}`, { lane_id: lane.lane_id, provider: lane.provider, account: lane.account, host: lane.host });
|
|
1245
|
-
}
|
|
1246
|
-
let loggedIn;
|
|
1247
|
-
if (isCurrentHost(lane.host)) {
|
|
1248
|
-
const key = JSON.stringify([lane.provider, lane.account, currentHost.kind, currentHost.id]);
|
|
1249
|
-
if (!localStatusCache.has(key)) {
|
|
1250
|
-
localStatusCache.set(key, accountStatus(lane.provider, lane.account, config, {
|
|
1251
|
-
existsSync: ctx.existsSync,
|
|
1252
|
-
probe: ctx.probeProvider,
|
|
1253
|
-
env: ctx.env,
|
|
1254
|
-
hostname: currentHostname,
|
|
1255
|
-
}).logged_in);
|
|
1256
|
-
}
|
|
1257
|
-
loggedIn = localStatusCache.get(key);
|
|
1258
|
-
}
|
|
1259
|
-
else if (lane.host.kind === "outpost") {
|
|
1260
|
-
loggedIn = outpostSnapshots.get(lane.host.id)?.providers[lane.provider].accounts[lane.account]?.logged_in;
|
|
1261
|
-
}
|
|
1262
|
-
else {
|
|
1263
|
-
const snapshot = remoteLocalHosts?.snapshots.find((candidate) => candidate.capacity.host.kind === lane.host.kind &&
|
|
1264
|
-
candidate.capacity.host.id === lane.host.id);
|
|
1265
|
-
if (!snapshot) {
|
|
1266
|
-
const gap = remoteLocalHosts?.unavailableHosts.find((candidate) => candidate.host.kind === lane.host.kind && candidate.host.id === lane.host.id);
|
|
1267
|
-
throw new LanesError("watch_account_host_unavailable", `Cannot check ${lane.provider} account ${lane.account} on ${lane.host.kind}:${lane.host.id}${gap ? `: ${gap.reason}` : ""}`, { lane_id: lane.lane_id, provider: lane.provider, account: lane.account, host: lane.host });
|
|
1268
|
-
}
|
|
1269
|
-
loggedIn = snapshot.capacity.providers[lane.provider].accounts[lane.account]?.logged_in;
|
|
1270
|
-
}
|
|
1271
|
-
if (loggedIn === undefined) {
|
|
1272
|
-
throw new LanesError("watch_account_unconfigured", `Lane ${lane.lane_id} records unconfigured ${lane.provider} account ${lane.account} on ${lane.host.kind}:${lane.host.id}`, { lane_id: lane.lane_id, provider: lane.provider, account: lane.account, host: lane.host });
|
|
1273
|
-
}
|
|
1274
|
-
return {
|
|
1275
|
-
lane_id: lane.lane_id,
|
|
1276
|
-
provider: lane.provider,
|
|
1277
|
-
account: lane.account,
|
|
1278
|
-
host: lane.host,
|
|
1279
|
-
logged_in: loggedIn,
|
|
1280
|
-
};
|
|
1281
|
-
});
|
|
1282
|
-
},
|
|
1283
|
-
writeLine: (line) => console.log(opts.json ? JSON.stringify({ event: line }) : line),
|
|
1284
|
-
writeAccountEvent: (event) => console.log(opts.json ? JSON.stringify(event) : `account_logged_out provider=${event.provider} account=${event.account} host=${event.host.kind}:${event.host.id} lane_ids=${event.lane_ids.join(",")}`),
|
|
1285
|
-
writeError: (line) => process.stderr.write(`${line}\n`),
|
|
1286
|
-
});
|
|
1287
|
-
return 0;
|
|
1288
|
-
}
|
|
1289
|
-
function monitorCallsForLaneIds(laneIds) {
|
|
1290
|
-
const calls = [];
|
|
1291
|
-
for (let offset = 0; offset < laneIds.length; offset += MAX_WATCHED_LANES) {
|
|
1292
|
-
const chunk = laneIds.slice(offset, offset + MAX_WATCHED_LANES);
|
|
1293
|
-
calls.push({
|
|
1294
|
-
command: `hq lanes watch ${chunk.join(" ")}`,
|
|
1295
|
-
timeout_ms: MONITOR_MAX_TIMEOUT_MS,
|
|
1296
|
-
persistent: true,
|
|
1297
|
-
});
|
|
1298
|
-
}
|
|
1299
|
-
return calls;
|
|
1300
|
-
}
|
|
1301
|
-
async function runMonitorCheck(ctx, opts) {
|
|
1302
|
-
if (opts.reminder) {
|
|
1303
|
-
console.log(monitorReminderText());
|
|
1304
|
-
return 0;
|
|
1305
|
-
}
|
|
1306
|
-
const sessionId = opts.session?.trim();
|
|
1307
|
-
if (!sessionId) {
|
|
1308
|
-
throw new LanesError("monitor_session_required", "hq lanes monitor-check requires --session <id> unless --reminder is used");
|
|
1309
|
-
}
|
|
1310
|
-
const engine = resolveMonitorEngine(opts.engine, ctx.env);
|
|
1311
|
-
const activeLanes = loadAllLanes(ctx.hqRoot()).filter((lane) => lane.senior.kind === "session" &&
|
|
1312
|
-
lane.senior.id === sessionId &&
|
|
1313
|
-
MONITOR_ACTIVE_LANE_STATES.has(lane.state));
|
|
1314
|
-
if (engine !== "claude") {
|
|
1315
|
-
if (opts.json) {
|
|
1316
|
-
printJson({
|
|
1317
|
-
ok: true,
|
|
1318
|
-
action: "monitor-check",
|
|
1319
|
-
session_id: sessionId,
|
|
1320
|
-
engine,
|
|
1321
|
-
active_lane_ids: activeLanes.map((lane) => lane.lane_id),
|
|
1322
|
-
covered_lane_ids: [],
|
|
1323
|
-
uncovered_lane_ids: [],
|
|
1324
|
-
skipped: "engine_has_no_claude_monitor",
|
|
1325
|
-
});
|
|
1326
|
-
}
|
|
1327
|
-
return 0;
|
|
1328
|
-
}
|
|
1329
|
-
if (activeLanes.length === 0) {
|
|
1330
|
-
if (opts.json) {
|
|
1331
|
-
printJson({
|
|
1332
|
-
ok: true,
|
|
1333
|
-
action: "monitor-check",
|
|
1334
|
-
session_id: sessionId,
|
|
1335
|
-
engine,
|
|
1336
|
-
active_lane_ids: [],
|
|
1337
|
-
covered_lane_ids: [],
|
|
1338
|
-
uncovered_lane_ids: [],
|
|
1339
|
-
});
|
|
1340
|
-
}
|
|
1341
|
-
return 0;
|
|
1342
|
-
}
|
|
1343
|
-
const evidence = await ctx.monitorEvidence(sessionId);
|
|
1344
|
-
if (evidence.sessionId !== sessionId) {
|
|
1345
|
-
throw new LanesError("monitor_evidence_session_mismatch", `Monitor evidence was for ${JSON.stringify(evidence.sessionId)}, expected ${JSON.stringify(sessionId)}`);
|
|
1346
|
-
}
|
|
1347
|
-
const covered = coveredLaneIds(evidence, ctx.now());
|
|
1348
|
-
const activeIds = activeLanes.map((lane) => lane.lane_id);
|
|
1349
|
-
const uncovered = activeIds.filter((laneId) => !covered.has(laneId));
|
|
1350
|
-
const monitorCalls = monitorCallsForLaneIds(uncovered);
|
|
1351
|
-
if (opts.json) {
|
|
1352
|
-
printJson({
|
|
1353
|
-
ok: uncovered.length === 0,
|
|
1354
|
-
action: "monitor-check",
|
|
1355
|
-
session_id: sessionId,
|
|
1356
|
-
engine,
|
|
1357
|
-
active_lane_ids: activeIds,
|
|
1358
|
-
covered_lane_ids: activeIds.filter((laneId) => covered.has(laneId)),
|
|
1359
|
-
uncovered_lane_ids: uncovered,
|
|
1360
|
-
monitor_call: monitorCalls.length === 1 ? monitorCalls[0] : null,
|
|
1361
|
-
monitor_calls: monitorCalls,
|
|
1362
|
-
});
|
|
1363
|
-
}
|
|
1364
|
-
else if (uncovered.length > 0) {
|
|
1365
|
-
for (const laneId of uncovered)
|
|
1366
|
-
console.log(`uncovered lane: ${laneId}`);
|
|
1367
|
-
for (const monitorCall of monitorCalls) {
|
|
1368
|
-
console.log(`Monitor(command=${JSON.stringify(monitorCall.command)}, timeout_ms=${monitorCall.timeout_ms}, persistent=true)`);
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
return uncovered.length > 0 ? MONITOR_UNCOVERED_EXIT_CODE : 0;
|
|
1372
|
-
}
|
|
1373
1199
|
function sessionMetaPath(hqRoot, sessionId) {
|
|
1374
1200
|
return path.join(hqRoot, "workspace", "sessions", sessionId, "meta.yaml");
|
|
1375
1201
|
}
|
|
@@ -1858,37 +1684,6 @@ function assertKnownOutpost(requested, known) {
|
|
|
1858
1684
|
*/
|
|
1859
1685
|
export const ASK_BACKOFF_MS = [5_000, 15_000];
|
|
1860
1686
|
export const ASK_ATTEMPTS = ASK_BACKOFF_MS.length + 1;
|
|
1861
|
-
function laneWaitHumanLine(result) {
|
|
1862
|
-
const details = Object.entries(result.change)
|
|
1863
|
-
.filter(([key]) => key !== "type")
|
|
1864
|
-
.map(([key, value]) => `${key}=${String(value)}`)
|
|
1865
|
-
.join(" ");
|
|
1866
|
-
return `lane=${result.lane_id} change=${result.change.type}${details ? ` ${details}` : ""} at=${result.at}`;
|
|
1867
|
-
}
|
|
1868
|
-
async function runWait(ctx, opts) {
|
|
1869
|
-
const timeoutSeconds = opts.timeout === undefined ? Number.NaN : Number(opts.timeout);
|
|
1870
|
-
try {
|
|
1871
|
-
const result = await runLaneWait(ctx.hqRoot(), opts.any ?? [], opts.for ?? [], timeoutSeconds * 1000, { now: ctx.now, sleep: ctx.sleep });
|
|
1872
|
-
if (result) {
|
|
1873
|
-
console.log(opts.json ? JSON.stringify(result) : laneWaitHumanLine(result));
|
|
1874
|
-
return 0;
|
|
1875
|
-
}
|
|
1876
|
-
console.log(opts.json
|
|
1877
|
-
? JSON.stringify({ ok: false, error: "wait_timeout" })
|
|
1878
|
-
: "wait_timeout");
|
|
1879
|
-
return LANE_WAIT_TIMEOUT_EXIT_CODE;
|
|
1880
|
-
}
|
|
1881
|
-
catch (err) {
|
|
1882
|
-
if (!isLanesError(err) || err.error !== "wait_invalid_input")
|
|
1883
|
-
throw err;
|
|
1884
|
-
const output = { ok: false, error: err.error, message: err.message };
|
|
1885
|
-
if (opts.json)
|
|
1886
|
-
console.log(JSON.stringify(output));
|
|
1887
|
-
else
|
|
1888
|
-
process.stderr.write(`${err.message}\n`);
|
|
1889
|
-
return LANE_WAIT_INVALID_INPUT_EXIT_CODE;
|
|
1890
|
-
}
|
|
1891
|
-
}
|
|
1892
1687
|
function withCasRetry(fn, attempts = 5) {
|
|
1893
1688
|
let last;
|
|
1894
1689
|
for (let i = 0; i < attempts; i += 1) {
|
|
@@ -7050,6 +6845,14 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
7050
6845
|
validateResumeProfileModel,
|
|
7051
6846
|
withResumeHireAdmission,
|
|
7052
6847
|
});
|
|
6848
|
+
const watchHandlerDeps = {
|
|
6849
|
+
laneHostFromCtx,
|
|
6850
|
+
loadAllLanes,
|
|
6851
|
+
loadClaudeBalanceHostSnapshots,
|
|
6852
|
+
printJson,
|
|
6853
|
+
readOutpostCapacity,
|
|
6854
|
+
};
|
|
6855
|
+
const watchHandlers = createLaneWatchHandlers(watchHandlerDeps);
|
|
7053
6856
|
const lanes = parent
|
|
7054
6857
|
.command("lanes", { hidden: true })
|
|
7055
6858
|
.description("Create, supervise, and steer worker lanes; routed decision queue");
|
|
@@ -7253,13 +7056,13 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
7253
7056
|
.option("--for <change-type>", "envelope | question | state", collectRepeatable, [])
|
|
7254
7057
|
.option("--timeout <seconds>", "Positive timeout in seconds")
|
|
7255
7058
|
.option("--json", "JSON output")
|
|
7256
|
-
.action(wrapText(async (opts) => runWait(ctx, opts)));
|
|
7059
|
+
.action(wrapText(async (opts) => watchHandlers.runWait(ctx, opts)));
|
|
7257
7060
|
lanes
|
|
7258
7061
|
.command("watch")
|
|
7259
7062
|
.description("Watch lane state and question changes until all lanes are terminal")
|
|
7260
7063
|
.argument("<lane-id...>", "Lane ids to watch")
|
|
7261
7064
|
.option("--interval-ms <ms>", "Polling interval, bounded to 100ms–30s", "5000")
|
|
7262
|
-
.action(wrapText(async (laneIds, opts) => runWatch(ctx, laneIds, opts)));
|
|
7065
|
+
.action(wrapText(async (laneIds, opts) => watchHandlers.runWatch(ctx, laneIds, opts)));
|
|
7263
7066
|
lanes
|
|
7264
7067
|
.command("monitor-check")
|
|
7265
7068
|
.description("Check that active Claude senior lanes have live Monitor watch tasks")
|
|
@@ -7267,7 +7070,7 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
7267
7070
|
.option("--engine <engine>", "claude | codex | grok; defaults to HQ_CONDUCT_ENGINE or claude")
|
|
7268
7071
|
.option("--reminder", "Print the senior Monitor reminder text")
|
|
7269
7072
|
.option("--json", "JSON on stdout")
|
|
7270
|
-
.action(wrapText(async (opts) => runMonitorCheck(ctx, opts)));
|
|
7073
|
+
.action(wrapText(async (opts) => watchHandlers.runMonitorCheck(ctx, opts)));
|
|
7271
7074
|
lanes
|
|
7272
7075
|
.command("show")
|
|
7273
7076
|
.description("Show one lane")
|
|
@@ -1421,7 +1421,9 @@ export async function makeInstallSecretResolver(secretNames, company) {
|
|
|
1421
1421
|
return () => null;
|
|
1422
1422
|
[scopeUid] = scopes;
|
|
1423
1423
|
}
|
|
1424
|
-
const authorized = await loadRevealedSecrets(token, scopeUid, names
|
|
1424
|
+
const authorized = await loadRevealedSecrets(token, scopeUid, names, undefined, {
|
|
1425
|
+
allowOfflineFallback: false,
|
|
1426
|
+
});
|
|
1425
1427
|
return (name) => authorized.get(name) ?? null;
|
|
1426
1428
|
}
|
|
1427
1429
|
catch {
|
package/dist/commands/run.js
CHANGED
|
@@ -2,9 +2,10 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import * as fs from 'node:fs';
|
|
4
4
|
import { internal } from 'varlock';
|
|
5
|
-
import { ensureCognitoToken } from '../utils/cognito-session.js';
|
|
5
|
+
import { cognitoCachePrincipalUid, ensureCognitoToken } from '../utils/cognito-session.js';
|
|
6
6
|
import { apiKeyCapabilityGateMessage, peekHqApiKey, } from '../utils/resolve-vault-credential.js';
|
|
7
7
|
import { computeSha256 } from '../utils/integrity.js';
|
|
8
|
+
import { isUnavailableSecretLoadHttpStatus, SecretLoadUnavailableError, } from '../utils/secret-load-availability.js';
|
|
8
9
|
import { vaultApiFetch, getCompanyUid } from '../utils/vault-api.js';
|
|
9
10
|
import { discoverSchemas } from '../run/discover-schemas.js';
|
|
10
11
|
import { installHqPlugin, prewarmHqSecrets } from '../run/hq-plugin.js';
|
|
@@ -82,7 +83,9 @@ export function registerRunCommand(program) {
|
|
|
82
83
|
throw new Error('company slug not set. Add # @hqCompany("slug") to your .env.schema or pass --company <slug>.');
|
|
83
84
|
}
|
|
84
85
|
const token = await ensureCognitoToken();
|
|
85
|
-
const uid = await getCompanyUid(token, slug
|
|
86
|
+
const uid = await getCompanyUid(token, slug, undefined, {
|
|
87
|
+
allowOfflineScopeFallback: true,
|
|
88
|
+
});
|
|
86
89
|
const usage = await buildRunUsage(opts.script, opts.scriptId);
|
|
87
90
|
const fetchBatch = async (companyUid, names, requestUsage) => {
|
|
88
91
|
const res = await vaultApiFetch({
|
|
@@ -99,6 +102,9 @@ export function registerRunCommand(program) {
|
|
|
99
102
|
: typeof body.error === 'string'
|
|
100
103
|
? body.error
|
|
101
104
|
: res.statusText;
|
|
105
|
+
if (isUnavailableSecretLoadHttpStatus(res.status)) {
|
|
106
|
+
throw new SecretLoadUnavailableError(`Failed to batch-load secrets: ${message}`);
|
|
107
|
+
}
|
|
102
108
|
if (res.status >= 400 &&
|
|
103
109
|
res.status < 500 &&
|
|
104
110
|
typeof body.code === 'string') {
|
|
@@ -110,6 +116,8 @@ export function registerRunCommand(program) {
|
|
|
110
116
|
};
|
|
111
117
|
const pluginOpts = {
|
|
112
118
|
companyOverride: opts.company,
|
|
119
|
+
principalUid: cognitoCachePrincipalUid(token) ?? undefined,
|
|
120
|
+
allowOfflineFallback: true,
|
|
113
121
|
resolveCompanyUid: async () => uid,
|
|
114
122
|
usage,
|
|
115
123
|
fetchBatch,
|