@indigoai-us/hq-cli 5.187.0 → 5.188.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 +25 -0
- package/dist/command-catalog.generated.d.ts +65 -0
- package/dist/command-catalog.generated.js +85 -0
- package/dist/commands/lanes.d.ts +7 -1
- package/dist/commands/lanes.js +894 -45
- package/dist/lib/lanes/claude-account-balance.d.ts +82 -0
- package/dist/lib/lanes/claude-account-balance.js +253 -0
- package/dist/lib/lanes/hire-grant-dispatch.d.ts +21 -0
- package/dist/lib/lanes/hire-grant-dispatch.js +167 -0
- package/dist/lib/lanes/hire-grants.d.ts +3 -2
- package/dist/lib/lanes/host-capacity.d.ts +19 -0
- package/dist/lib/lanes/host-capacity.js +68 -0
- package/dist/lib/lanes/index.d.ts +1 -1
- package/dist/lib/lanes/outpost-dispatch.d.ts +11 -1
- package/dist/lib/lanes/outpost-dispatch.js +20 -0
- package/dist/lib/lanes/ssm-command-context.d.ts +12 -0
- package/dist/lib/lanes/ssm-command-context.js +52 -0
- package/dist/lib/lanes/store.js +86 -0
- package/dist/lib/lanes/types.d.ts +48 -0
- package/dist/lib/lanes/types.js +1 -1
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ export type { AdmissionCapReason, AdmissionHost } from "./admission.js";
|
|
|
10
10
|
export { buildHostCapacitySnapshot, chooseHostForLane, parseHostCapacitySnapshot, } from "./host-capacity.js";
|
|
11
11
|
export type { HostCapacityAccount, HostCapacityProvider, HostCapacitySnapshot, HostPlacementChoice, } from "./host-capacity.js";
|
|
12
12
|
export { CONFIG_SCHEMA_VERSION, ENVELOPE_DECISIONS, ENVELOPE_SCHEMA_VERSION, HISTORY_CAP, HOST_KINDS, LANE_PROVIDERS, LANE_SCHEMA_VERSION, LANE_STORY_STATUSES, 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";
|
|
13
|
-
export type { AccountConfig, AttributionHistoryEntry, EnvelopeDecision, EnvelopeQuestion, HostKind, LaneCompanyRef, LaneEnvelope, LaneHost, LaneProvider, LanePlacementPolicy, LaneRecord, LaneStory, LaneStoryStatus, 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";
|
|
13
|
+
export type { AccountConfig, AttributionHistoryEntry, EnvelopeDecision, EnvelopeQuestion, HostKind, LaneCompanyRef, LaneAccountSelection, LaneAccountSelectionConsidered, LaneAccountSelectionHostCount, LaneEnvelope, LaneHost, LaneProvider, LanePlacementPolicy, LaneRecord, LaneStory, LaneStoryStatus, 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";
|
|
14
14
|
export { ACTIVE_LANE_STORY_STATUSES, activeLaneStories, laneStories, laneStory, storyKey, storyStatusForEnvelope, storyWarning, withCurrentStory, withLaneStories, } from "./stories.js";
|
|
15
15
|
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";
|
|
16
16
|
export type { ConfigLoadDeps, ConfigWriteDeps } from "./config.js";
|
|
@@ -27,7 +27,7 @@ export interface OutpostDispatchResult {
|
|
|
27
27
|
stderr: string;
|
|
28
28
|
}
|
|
29
29
|
export interface OutpostLaneCommand {
|
|
30
|
-
action: "message" | "resume" | "stop" | "show" | "grant";
|
|
30
|
+
action: "message" | "resume" | "stop" | "show" | "grant" | "grant-target";
|
|
31
31
|
laneId: string;
|
|
32
32
|
hqBinary?: string;
|
|
33
33
|
text?: string;
|
|
@@ -36,6 +36,7 @@ export interface OutpostLaneCommand {
|
|
|
36
36
|
account?: string;
|
|
37
37
|
model?: string;
|
|
38
38
|
hire?: string;
|
|
39
|
+
grantContext?: string;
|
|
39
40
|
compact?: boolean;
|
|
40
41
|
}
|
|
41
42
|
export interface OutpostExecPort {
|
|
@@ -61,12 +62,21 @@ export declare function parseOutpostPickupPayload(raw: unknown): OutpostPickupPa
|
|
|
61
62
|
export declare function buildOutpostPickupCommand(payloadUrl: string): string;
|
|
62
63
|
/** Bounded, read-only capacity query executed by the target Outpost CLI. */
|
|
63
64
|
export declare function buildOutpostCapacityCommand(): string;
|
|
65
|
+
/** Read the lane records owned by an Outpost for exact per-account state counts. */
|
|
66
|
+
export declare function buildOutpostLaneListCommand(): string;
|
|
64
67
|
/** Commit a queued lane move on the host that currently owns its state. */
|
|
65
68
|
export declare function buildOutpostMoveTargetCommand(input: {
|
|
66
69
|
laneId: string;
|
|
67
70
|
host: LaneHost;
|
|
68
71
|
account: string;
|
|
69
72
|
}): string;
|
|
73
|
+
/** Move an owned Claude session between accounts while leaving its turn parked. */
|
|
74
|
+
export declare function buildOutpostBalanceMoveCommand(input: {
|
|
75
|
+
laneId: string;
|
|
76
|
+
account: string;
|
|
77
|
+
fromAccount: string;
|
|
78
|
+
expectedState: LaneRecord["state"];
|
|
79
|
+
}): string;
|
|
70
80
|
/** Idempotently backfill the marker on the selected Outpost. */
|
|
71
81
|
export declare function buildOutpostIdentityBackfillCommand(expectedId: string): string;
|
|
72
82
|
/** Build the same `hq outposts exec` remote command used by lane pickup. */
|
|
@@ -46,6 +46,10 @@ export function buildOutpostPickupCommand(payloadUrl) {
|
|
|
46
46
|
export function buildOutpostCapacityCommand() {
|
|
47
47
|
return withRemoteHqDir(joinCommandParts(["hq", "lanes", "capacity", "--json"]));
|
|
48
48
|
}
|
|
49
|
+
/** Read the lane records owned by an Outpost for exact per-account state counts. */
|
|
50
|
+
export function buildOutpostLaneListCommand() {
|
|
51
|
+
return withRemoteHqDir(joinCommandParts(["hq", "lanes", "list", "--json"]));
|
|
52
|
+
}
|
|
49
53
|
/** Commit a queued lane move on the host that currently owns its state. */
|
|
50
54
|
export function buildOutpostMoveTargetCommand(input) {
|
|
51
55
|
return withRemoteHqDir(joinCommandParts([
|
|
@@ -61,6 +65,21 @@ export function buildOutpostMoveTargetCommand(input) {
|
|
|
61
65
|
input.account,
|
|
62
66
|
]));
|
|
63
67
|
}
|
|
68
|
+
/** Move an owned Claude session between accounts while leaving its turn parked. */
|
|
69
|
+
export function buildOutpostBalanceMoveCommand(input) {
|
|
70
|
+
return withRemoteHqDir(joinCommandParts([
|
|
71
|
+
"hq",
|
|
72
|
+
"lanes",
|
|
73
|
+
"balance-move-target",
|
|
74
|
+
input.laneId,
|
|
75
|
+
"--account",
|
|
76
|
+
input.account,
|
|
77
|
+
"--from-account",
|
|
78
|
+
input.fromAccount,
|
|
79
|
+
"--expected-state",
|
|
80
|
+
input.expectedState,
|
|
81
|
+
]));
|
|
82
|
+
}
|
|
64
83
|
/** Idempotently backfill the marker on the selected Outpost. */
|
|
65
84
|
export function buildOutpostIdentityBackfillCommand(expectedId) {
|
|
66
85
|
return withRemoteHqDir(joinCommandParts([
|
|
@@ -86,6 +105,7 @@ export function buildOutpostLaneCommand(input) {
|
|
|
86
105
|
["--account", input.account],
|
|
87
106
|
["--model", input.model],
|
|
88
107
|
["--hire", input.hire],
|
|
108
|
+
["--grant-context", input.grantContext],
|
|
89
109
|
]) {
|
|
90
110
|
if (value !== undefined)
|
|
91
111
|
args.push(flag, value);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface SsmRunCommandContextDeps {
|
|
2
|
+
platform?: string;
|
|
3
|
+
parentPid?: number;
|
|
4
|
+
readFileSync?: (path: string, encoding: "utf8") => string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* True only for a Linux process descended from the root-owned SSM Run Command
|
|
8
|
+
* worker chain. Outpost owner-only lane mutations use this to distinguish an
|
|
9
|
+
* SSM dispatch from a normal local CLI invocation.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isSsmRunCommandProcess(deps?: SsmRunCommandContextDeps): boolean;
|
|
12
|
+
//# sourceMappingURL=ssm-command-context.d.ts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
const SSM_WORKER_CHAIN = [
|
|
3
|
+
"ssm-document-wo",
|
|
4
|
+
"ssm-agent-worke",
|
|
5
|
+
"amazon-ssm-agen",
|
|
6
|
+
];
|
|
7
|
+
/**
|
|
8
|
+
* True only for a Linux process descended from the root-owned SSM Run Command
|
|
9
|
+
* worker chain. Outpost owner-only lane mutations use this to distinguish an
|
|
10
|
+
* SSM dispatch from a normal local CLI invocation.
|
|
11
|
+
*/
|
|
12
|
+
export function isSsmRunCommandProcess(deps = {}) {
|
|
13
|
+
if ((deps.platform ?? process.platform) !== "linux")
|
|
14
|
+
return false;
|
|
15
|
+
const readFileSync = deps.readFileSync ?? ((filePath, encoding) => fs.readFileSync(filePath, encoding));
|
|
16
|
+
let pid = deps.parentPid ?? process.ppid;
|
|
17
|
+
const lineage = [];
|
|
18
|
+
for (let depth = 0; depth < 32 && pid > 1; depth += 1) {
|
|
19
|
+
let status;
|
|
20
|
+
let command;
|
|
21
|
+
try {
|
|
22
|
+
status = readFileSync(`/proc/${pid}/status`, "utf8");
|
|
23
|
+
command = readFileSync(`/proc/${pid}/comm`, "utf8").trim();
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const code = err !== null && typeof err === "object" && "code" in err
|
|
27
|
+
? err.code
|
|
28
|
+
: undefined;
|
|
29
|
+
if (code === "ENOENT" || code === "EACCES" || code === "EPERM")
|
|
30
|
+
return false;
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
const parentMatch = /^PPid:\s*(\d+)\s*$/m.exec(status);
|
|
34
|
+
const uidMatch = /^Uid:\s*\d+\s+(\d+)\s+\d+\s+\d+\s*$/m.exec(status);
|
|
35
|
+
if (!parentMatch || !uidMatch || !command)
|
|
36
|
+
return false;
|
|
37
|
+
const parentPid = Number(parentMatch[1]);
|
|
38
|
+
const effectiveUid = Number(uidMatch[1]);
|
|
39
|
+
if (!Number.isSafeInteger(parentPid) || !Number.isSafeInteger(effectiveUid))
|
|
40
|
+
return false;
|
|
41
|
+
lineage.push({ pid, parentPid, command, effectiveUid });
|
|
42
|
+
pid = parentPid;
|
|
43
|
+
}
|
|
44
|
+
for (let start = 0; start <= lineage.length - SSM_WORKER_CHAIN.length; start += 1) {
|
|
45
|
+
const chain = lineage.slice(start, start + SSM_WORKER_CHAIN.length);
|
|
46
|
+
if (chain.every((entry, index) => entry.effectiveUid === 0 && entry.command.startsWith(SSM_WORKER_CHAIN[index]))) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=ssm-command-context.js.map
|
package/dist/lib/lanes/store.js
CHANGED
|
@@ -473,6 +473,9 @@ export function parseLaneRecord(raw, filePath) {
|
|
|
473
473
|
path: filePath,
|
|
474
474
|
});
|
|
475
475
|
}
|
|
476
|
+
if (raw.account_selection !== undefined) {
|
|
477
|
+
parseLaneAccountSelection(raw.account_selection, filePath);
|
|
478
|
+
}
|
|
476
479
|
if (raw.placement_default !== undefined) {
|
|
477
480
|
const placement = raw.placement_default;
|
|
478
481
|
if (!isPlainObject(placement) ||
|
|
@@ -494,6 +497,89 @@ export function parseLaneRecord(raw, filePath) {
|
|
|
494
497
|
// a parse/rewrite cycle (spec §5.1 field-preservation).
|
|
495
498
|
return raw;
|
|
496
499
|
}
|
|
500
|
+
function parseLaneAccountSelection(value, filePath) {
|
|
501
|
+
const failure = (field) => new LaneSchemaError(`Invalid account_selection.${field}`, {
|
|
502
|
+
path: filePath,
|
|
503
|
+
field: `account_selection.${field}`,
|
|
504
|
+
});
|
|
505
|
+
if (!isPlainObject(value))
|
|
506
|
+
throw failure("must be an object");
|
|
507
|
+
const selection = value;
|
|
508
|
+
if (typeof selection.account !== "string" || selection.account.trim() === "")
|
|
509
|
+
throw failure("account");
|
|
510
|
+
if (selection.signal !== "usage" && selection.signal !== "lane_count" && selection.signal !== "explicit")
|
|
511
|
+
throw failure("signal");
|
|
512
|
+
if (selection.reason !== "least_loaded" && selection.reason !== "explicit")
|
|
513
|
+
throw failure("reason");
|
|
514
|
+
if (typeof selection.selected_at !== "string" || !Number.isFinite(Date.parse(selection.selected_at)))
|
|
515
|
+
throw failure("selected_at");
|
|
516
|
+
const parseHost = (host, field) => {
|
|
517
|
+
if (!isPlainObject(host) || !isHostKind(host.kind) || typeof host.id !== "string" || host.id.trim() === "")
|
|
518
|
+
throw failure(field);
|
|
519
|
+
};
|
|
520
|
+
parseHost(selection.target_host, "target_host");
|
|
521
|
+
if (!Array.isArray(selection.considered) || !Array.isArray(selection.skipped_accounts) || !Array.isArray(selection.unavailable_hosts)) {
|
|
522
|
+
throw failure("arrays");
|
|
523
|
+
}
|
|
524
|
+
for (const [index, rowValue] of selection.considered.entries()) {
|
|
525
|
+
if (!isPlainObject(rowValue))
|
|
526
|
+
throw failure(`considered.${index}`);
|
|
527
|
+
const row = rowValue;
|
|
528
|
+
if (typeof row.account !== "string" || row.account.trim() === "" || typeof row.eligible !== "boolean" || typeof row.live_lanes !== "number" || !Number.isInteger(row.live_lanes) || row.live_lanes < 0 || typeof row.counts_complete !== "boolean" || !Array.isArray(row.hosts))
|
|
529
|
+
throw failure(`considered.${index}`);
|
|
530
|
+
if (row.ineligible_reason !== undefined && typeof row.ineligible_reason !== "string")
|
|
531
|
+
throw failure(`considered.${index}.ineligible_reason`);
|
|
532
|
+
if (row.usage !== null) {
|
|
533
|
+
if (!isPlainObject(row.usage))
|
|
534
|
+
throw failure(`considered.${index}.usage`);
|
|
535
|
+
for (const key of ["five_hour_percent", "weekly_percent"]) {
|
|
536
|
+
const percent = row.usage[key];
|
|
537
|
+
if (percent !== undefined && (typeof percent !== "number" || !Number.isFinite(percent) || percent < 0 || percent > 100))
|
|
538
|
+
throw failure(`considered.${index}.usage.${key}`);
|
|
539
|
+
}
|
|
540
|
+
if (row.usage.sampled_at !== undefined && (typeof row.usage.sampled_at !== "string" || !Number.isFinite(Date.parse(row.usage.sampled_at))))
|
|
541
|
+
throw failure(`considered.${index}.usage.sampled_at`);
|
|
542
|
+
}
|
|
543
|
+
for (const [hostIndex, hostValue] of row.hosts.entries()) {
|
|
544
|
+
if (!isPlainObject(hostValue))
|
|
545
|
+
throw failure(`considered.${index}.hosts.${hostIndex}`);
|
|
546
|
+
const host = hostValue;
|
|
547
|
+
parseHost(host.host, `considered.${index}.hosts.${hostIndex}.host`);
|
|
548
|
+
if (typeof host.enabled !== "boolean" || !(host.logged_in === null || typeof host.logged_in === "boolean"))
|
|
549
|
+
throw failure(`considered.${index}.hosts.${hostIndex}.status`);
|
|
550
|
+
if (!(host.live_lanes === null || (typeof host.live_lanes === "number" && Number.isInteger(host.live_lanes) && host.live_lanes >= 0)))
|
|
551
|
+
throw failure(`considered.${index}.hosts.${hostIndex}.live_lanes`);
|
|
552
|
+
if (!isPlainObject(host.lane_counts))
|
|
553
|
+
throw failure(`considered.${index}.hosts.${hostIndex}.lane_counts`);
|
|
554
|
+
for (const key of ["running", "queued", "awaiting_input"]) {
|
|
555
|
+
const count = host.lane_counts[key];
|
|
556
|
+
if (!(count === null || (typeof count === "number" && Number.isInteger(count) && count >= 0)))
|
|
557
|
+
throw failure(`considered.${index}.hosts.${hostIndex}.lane_counts.${key}`);
|
|
558
|
+
}
|
|
559
|
+
if (!["lane_list", "capacity", "capacity_partial", "unavailable"].includes(String(host.count_source)))
|
|
560
|
+
throw failure(`considered.${index}.hosts.${hostIndex}.count_source`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
for (const [index, rowValue] of selection.skipped_accounts.entries()) {
|
|
564
|
+
if (!isPlainObject(rowValue))
|
|
565
|
+
throw failure(`skipped_accounts.${index}`);
|
|
566
|
+
const row = rowValue;
|
|
567
|
+
if (typeof row.account !== "string" || row.account.trim() === "" || typeof row.reason !== "string" || row.reason.trim() === "")
|
|
568
|
+
throw failure(`skipped_accounts.${index}`);
|
|
569
|
+
parseHost(row.host, `skipped_accounts.${index}.host`);
|
|
570
|
+
}
|
|
571
|
+
for (const [index, rowValue] of selection.unavailable_hosts.entries()) {
|
|
572
|
+
if (!isPlainObject(rowValue))
|
|
573
|
+
throw failure(`unavailable_hosts.${index}`);
|
|
574
|
+
const row = rowValue;
|
|
575
|
+
if (typeof row.reason !== "string" || row.reason.trim() === "")
|
|
576
|
+
throw failure(`unavailable_hosts.${index}`);
|
|
577
|
+
if (isPlainObject(row.host) && row.host.kind === "unknown" && row.host.id === "unknown")
|
|
578
|
+
continue;
|
|
579
|
+
parseHost(row.host, `unavailable_hosts.${index}.host`);
|
|
580
|
+
}
|
|
581
|
+
return selection;
|
|
582
|
+
}
|
|
497
583
|
export function parseQuestionRecord(raw, filePath) {
|
|
498
584
|
if (!isPlainObject(raw)) {
|
|
499
585
|
throw new LaneSchemaError("Question record must be a JSON object", {
|
|
@@ -230,6 +230,52 @@ export interface LaneHost {
|
|
|
230
230
|
kind: HostKind;
|
|
231
231
|
id: string;
|
|
232
232
|
}
|
|
233
|
+
export interface LaneAccountSelectionHostCount {
|
|
234
|
+
host: LaneHost;
|
|
235
|
+
enabled: boolean;
|
|
236
|
+
logged_in: boolean | null;
|
|
237
|
+
live_lanes: number | null;
|
|
238
|
+
lane_counts: {
|
|
239
|
+
running: number | null;
|
|
240
|
+
queued: number | null;
|
|
241
|
+
awaiting_input: number | null;
|
|
242
|
+
};
|
|
243
|
+
count_source: "lane_list" | "capacity" | "capacity_partial" | "unavailable";
|
|
244
|
+
}
|
|
245
|
+
export interface LaneAccountSelectionConsidered {
|
|
246
|
+
account: string;
|
|
247
|
+
eligible: boolean;
|
|
248
|
+
ineligible_reason?: string;
|
|
249
|
+
live_lanes: number;
|
|
250
|
+
counts_complete: boolean;
|
|
251
|
+
usage: {
|
|
252
|
+
five_hour_percent?: number;
|
|
253
|
+
weekly_percent?: number;
|
|
254
|
+
sampled_at?: string;
|
|
255
|
+
} | null;
|
|
256
|
+
hosts: LaneAccountSelectionHostCount[];
|
|
257
|
+
}
|
|
258
|
+
/** Decision evidence saved with a Claude lane when account balancing is active. */
|
|
259
|
+
export interface LaneAccountSelection {
|
|
260
|
+
account: string;
|
|
261
|
+
signal: "usage" | "lane_count" | "explicit";
|
|
262
|
+
reason: "least_loaded" | "explicit";
|
|
263
|
+
target_host: LaneHost;
|
|
264
|
+
selected_at: string;
|
|
265
|
+
considered: LaneAccountSelectionConsidered[];
|
|
266
|
+
skipped_accounts: Array<{
|
|
267
|
+
account: string;
|
|
268
|
+
host: LaneHost;
|
|
269
|
+
reason: string;
|
|
270
|
+
}>;
|
|
271
|
+
unavailable_hosts: Array<{
|
|
272
|
+
host: LaneHost | {
|
|
273
|
+
kind: "unknown";
|
|
274
|
+
id: "unknown";
|
|
275
|
+
};
|
|
276
|
+
reason: string;
|
|
277
|
+
}>;
|
|
278
|
+
}
|
|
233
279
|
export interface SeniorHistoryEntry {
|
|
234
280
|
from: SeniorRef;
|
|
235
281
|
to: SeniorRef;
|
|
@@ -309,6 +355,8 @@ export interface LaneRecord {
|
|
|
309
355
|
worker_policy_delivery?: "hook" | "prompt";
|
|
310
356
|
provider: LaneProvider;
|
|
311
357
|
account?: string;
|
|
358
|
+
/** Recent Claude account-selection evidence for a create or automatic resume move. */
|
|
359
|
+
account_selection?: LaneAccountSelection;
|
|
312
360
|
/** Eligible accounts for a queue entry created without an explicit account. */
|
|
313
361
|
admission_accounts?: string[];
|
|
314
362
|
/**
|
package/dist/lib/lanes/types.js
CHANGED
|
@@ -224,7 +224,7 @@ export const LANE_FIELD_WRITERS = {
|
|
|
224
224
|
pickup_validation_pending: ["creator", "command", "spawn", "reconcile"],
|
|
225
225
|
pickup_validation_pending_since: ["creator", "command", "spawn", "reconcile"],
|
|
226
226
|
priority: ["command"], worker: ["creator", "command"], worker_path: ["creator", "command"], worker_pack: ["creator", "command"], worker_profile: ["creator", "command"], worker_profile_hash: ["creator", "command", "spawn"], worker_profile_ignored: ["creator", "command", "spawn"], worker_policy_delivery: ["command", "spawn"],
|
|
227
|
-
provider: ["creator"], account: ["creator", "spawn", "command", "watcher", "reconcile"], admission_accounts: ["creator", "command"], account_history: ["command", "spawn", "watcher", "reconcile"], pending_resume: ["command", "spawn", "watcher", "reconcile"], placement_default: ["creator"], host: ["creator", "command"], origin_host: ["creator"], origin_host_source: ["creator"],
|
|
227
|
+
provider: ["creator"], account: ["creator", "spawn", "command", "watcher", "reconcile"], account_selection: ["creator", "command"], admission_accounts: ["creator", "command"], account_history: ["command", "spawn", "watcher", "reconcile"], pending_resume: ["command", "spawn", "watcher", "reconcile"], placement_default: ["creator"], host: ["creator", "command"], origin_host: ["creator"], origin_host_source: ["creator"],
|
|
228
228
|
version: ["creator"], created_at: ["creator"], updated_at: ["creator"], attribution_history: ["command"],
|
|
229
229
|
last_envelope: ["watcher", "reconcile"], model: ["creator", "spawn", "command"], model_source: ["creator", "spawn", "command"], effort: ["creator", "spawn"], effort_source: ["creator", "spawn"], fast_mode: ["spawn"],
|
|
230
230
|
last_message_at: ["command"], last_compaction: ["spawn"], story_complete: ["watcher", "reconcile"], story_complete_reason: ["watcher", "reconcile"], story_status: ["watcher", "reconcile"],
|