@indigoai-us/hq-cli 5.345.155 → 5.345.159
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 +289 -0
- package/assets/scaffold/core/scripts/rebuild-company-knowledge-index.sh +110 -2
- package/assets/scaffold/core/scripts/rebuild-projects-index.sh +101 -5
- package/assets/scaffold/core/scripts/worktree.sh +4 -0
- package/dist/command-catalog.generated.d.ts +536 -7
- package/dist/command-catalog.generated.js +676 -24
- package/dist/command-registration-plan.d.ts +18 -0
- package/dist/command-registration-plan.js +4 -0
- package/dist/commands/_patterns.d.ts +17 -0
- package/dist/commands/_patterns.js +22 -0
- package/dist/commands/agent-inbox.js +2 -2
- package/dist/commands/agent-kit.js +8 -6
- package/dist/commands/bot.js +7 -4
- package/dist/commands/channel-suggest.d.ts +56 -0
- package/dist/commands/channel-suggest.js +170 -0
- package/dist/commands/channels.js +7 -1
- package/dist/commands/cloud.d.ts +45 -0
- package/dist/commands/cloud.js +150 -10
- package/dist/commands/company.js +4 -3
- package/dist/commands/core-checkpoint-native.d.ts +18 -0
- package/dist/commands/core-checkpoint-native.js +67 -2
- package/dist/commands/core-pipeline-driver-native.d.ts +12 -1
- package/dist/commands/core-pipeline-driver-native.js +131 -5
- package/dist/commands/core.js +13 -1
- package/dist/commands/crm.js +83 -6
- package/dist/commands/deploy-access.d.ts +33 -0
- package/dist/commands/deploy-access.js +322 -0
- package/dist/commands/dm-attach.d.ts +106 -0
- package/dist/commands/dm-attach.js +184 -0
- package/dist/commands/dm.d.ts +37 -0
- package/dist/commands/dm.js +172 -10
- package/dist/commands/feedback-show.d.ts +40 -0
- package/dist/commands/feedback-show.js +261 -0
- package/dist/commands/feedback.d.ts +21 -0
- package/dist/commands/feedback.js +152 -2
- package/dist/commands/files-browse.d.ts +16 -0
- package/dist/commands/files-browse.js +52 -1
- package/dist/commands/files.d.ts +24 -0
- package/dist/commands/files.js +52 -1
- package/dist/commands/integrations-connect.js +7 -3
- package/dist/commands/integrations-core.d.ts +13 -1
- package/dist/commands/integrations-core.js +49 -4
- package/dist/commands/integrations.js +4 -2
- package/dist/commands/lanes-accounts.js +16 -1
- package/dist/commands/lanes-loop.js +14 -4
- package/dist/commands/lanes-message.js +6 -4
- package/dist/commands/lanes-resume.js +36 -13
- package/dist/commands/lanes-shared.d.ts +5 -0
- package/dist/commands/lanes-shared.js +13 -3
- package/dist/commands/lanes-watch.js +1 -0
- package/dist/commands/lanes.d.ts +20 -1
- package/dist/commands/lanes.js +201 -51
- package/dist/commands/mesh.js +149 -1
- package/dist/commands/monitor.d.ts +1 -0
- package/dist/commands/monitor.js +4 -1
- package/dist/commands/repo.d.ts +41 -0
- package/dist/commands/repo.js +331 -0
- package/dist/commands/scan.d.ts +3 -1
- package/dist/commands/scan.js +7 -3
- package/dist/commands/secrets.d.ts +37 -0
- package/dist/commands/secrets.js +185 -16
- package/dist/commands/signals.js +17 -5
- package/dist/commands/staff/listings.d.ts +41 -0
- package/dist/commands/staff/listings.js +160 -0
- package/dist/commands/staff/reset-test-account.d.ts +3 -2
- package/dist/commands/staff/reset-test-account.js +4 -3
- package/dist/hq-cloud-sync-runner/bin/sync-runner.js +2629 -1036
- package/dist/hq-cloud-sync-runner/package.json +1 -1
- package/dist/lib/agent-kit/inbox-state.d.ts +7 -0
- package/dist/lib/agent-kit/inbox-state.js +5 -1
- package/dist/lib/agent-kit/mcp/tools.js +2 -1
- package/dist/lib/agent-kit/run/inbox.js +2 -1
- package/dist/lib/agent-kit/wake-secrets.d.ts +7 -0
- package/dist/lib/agent-kit/wake-secrets.js +32 -0
- package/dist/lib/agent-kit/wake.d.ts +4 -0
- package/dist/lib/agent-kit/wake.js +49 -3
- package/dist/lib/bot/inflight.d.ts +7 -1
- package/dist/lib/bot/inflight.js +10 -2
- package/dist/lib/bot/prompt.js +3 -0
- package/dist/lib/bot/run.js +72 -20
- package/dist/lib/bot/session.d.ts +14 -0
- package/dist/lib/bot/session.js +70 -0
- package/dist/lib/capacity/collectors/claude-oauth.d.ts +6 -0
- package/dist/lib/capacity/collectors/claude-oauth.js +12 -0
- package/dist/lib/capacity/lane-login.d.ts +6 -0
- package/dist/lib/capacity/lane-login.js +5 -0
- package/dist/lib/core-utils/worktree.js +2 -0
- package/dist/lib/daemon/exit-cause.d.ts +43 -0
- package/dist/lib/daemon/exit-cause.js +88 -0
- package/dist/lib/daemon/handoff.d.ts +2 -0
- package/dist/lib/daemon/handoff.js +6 -1
- package/dist/lib/daemon/hq-child-bootstrap.mjs +20 -3
- package/dist/lib/daemon/paths.d.ts +2 -0
- package/dist/lib/daemon/paths.js +1 -0
- package/dist/lib/daemon/run.js +13 -0
- package/dist/lib/daemon/supervisor.d.ts +54 -1
- package/dist/lib/daemon/supervisor.js +297 -21
- package/dist/lib/daemon/unit-holds.d.ts +22 -0
- package/dist/lib/daemon/unit-holds.js +86 -0
- package/dist/lib/doctor/checks/sync-health.d.ts +9 -0
- package/dist/lib/doctor/checks/sync-health.js +66 -1
- package/dist/lib/doctor/company-resolution-state.d.ts +30 -0
- package/dist/lib/doctor/company-resolution-state.js +89 -0
- package/dist/lib/doctor/fix/apply.d.ts +36 -6
- package/dist/lib/doctor/fix/apply.js +128 -12
- package/dist/lib/doctor/types.d.ts +1 -1
- package/dist/lib/doctor/types.js +1 -0
- package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
- package/dist/lib/flag-registry-worker-source.generated.js +1 -1
- package/dist/lib/hook-engine/resolve.js +6 -2
- package/dist/lib/index-render/company-knowledge.d.ts +1 -1
- package/dist/lib/index-render/company-knowledge.js +4 -5
- package/dist/lib/index-render/index.js +44 -3
- package/dist/lib/index-render/projects.d.ts +1 -1
- package/dist/lib/index-render/projects.js +5 -5
- package/dist/lib/lanes/account-company.d.ts +28 -0
- package/dist/lib/lanes/account-company.js +53 -0
- package/dist/lib/lanes/accounts.d.ts +22 -3
- package/dist/lib/lanes/accounts.js +38 -2
- package/dist/lib/lanes/claude-balance.d.ts +6 -1
- package/dist/lib/lanes/claude-balance.js +6 -1
- package/dist/lib/lanes/claude-credential.d.ts +78 -0
- package/dist/lib/lanes/claude-credential.js +163 -0
- package/dist/lib/lanes/compaction.d.ts +2 -0
- package/dist/lib/lanes/compaction.js +9 -0
- package/dist/lib/lanes/config.js +6 -0
- package/dist/lib/lanes/envelope-repair-dispatch.js +2 -1
- package/dist/lib/lanes/hooks-install.js +2 -1
- package/dist/lib/lanes/host-capacity.d.ts +2 -0
- package/dist/lib/lanes/host-capacity.js +1 -0
- package/dist/lib/lanes/keep-alive.d.ts +1 -1
- package/dist/lib/lanes/keep-alive.js +3 -1
- package/dist/lib/lanes/links.js +10 -4
- package/dist/lib/lanes/loop.js +16 -1
- package/dist/lib/lanes/node-binary.d.ts +17 -0
- package/dist/lib/lanes/node-binary.js +30 -0
- package/dist/lib/lanes/outpost-dispatch.d.ts +2 -1
- package/dist/lib/lanes/outpost-dispatch.js +1 -0
- package/dist/lib/lanes/reconcile.js +4 -0
- package/dist/lib/lanes/remote-control-lane.js +2 -0
- package/dist/lib/lanes/spawn.d.ts +3 -0
- package/dist/lib/lanes/spawn.js +119 -9
- package/dist/lib/lanes/store.d.ts +6 -0
- package/dist/lib/lanes/store.js +107 -18
- package/dist/lib/lanes/types.d.ts +2 -0
- package/dist/lib/lanes/watch.js +28 -5
- package/dist/lib/lanes/watcher-main.js +4 -3
- package/dist/lib/lanes/watcher.d.ts +4 -0
- package/dist/lib/lanes/watcher.js +110 -21
- package/dist/lib/mesh/api.d.ts +32 -0
- package/dist/lib/mesh/api.js +75 -0
- package/dist/lib/secret-scan/detect.js +9 -0
- package/dist/lib/secret-scan/repo-config.d.ts +41 -0
- package/dist/lib/secret-scan/repo-config.js +237 -0
- package/dist/lib/secret-scan/rules.d.ts +7 -1
- package/dist/lib/secret-scan/rules.js +3 -1
- package/dist/lib/secret-scan/staged.d.ts +5 -0
- package/dist/lib/secret-scan/staged.js +19 -2
- package/dist/lib/secret-scan/types.d.ts +2 -0
- package/dist/lib/sync/server-owned-local-only.d.ts +29 -0
- package/dist/lib/sync/server-owned-local-only.js +75 -0
- package/dist/sentry-before-send.js +1 -0
- package/dist/utils/access-denied-hint.js +6 -0
- package/dist/utils/client-health.d.ts +34 -0
- package/dist/utils/client-health.js +96 -3
- package/dist/utils/package-use-lease.js +27 -9
- package/dist/utils/version-gate.d.ts +7 -0
- package/dist/utils/version-gate.js +66 -0
- package/package.json +8 -8
package/dist/commands/lanes.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* `accounts login`, which hands the terminal to the vendor's own sign-in.
|
|
6
6
|
* `watch` and the monitor reminder are the line-oriented text surfaces.
|
|
7
7
|
*/
|
|
8
|
+
import { accountMatchesCompany, accountMayRetainLane, companyMismatchError } from "../lib/lanes/account-company.js";
|
|
8
9
|
import { spawn, spawnSync } from "node:child_process";
|
|
9
10
|
import { randomBytes } from "node:crypto";
|
|
10
11
|
import * as fs from "node:fs";
|
|
@@ -104,6 +105,7 @@ import { blockerFreshnessFingerprint, resolveBlockerFreshnessForLane, } from "..
|
|
|
104
105
|
import { resolveKrFreshnessForShow } from "../lib/lanes/kr-freshness.js";
|
|
105
106
|
import { ensureSessionHome } from "../lib/lanes/session-relink.js";
|
|
106
107
|
import { defaultProbe, validateProfileLaneModel, validateLaneModel, } from "../lib/lanes/models.js";
|
|
108
|
+
import { readLaneClaudeCredential } from "../lib/lanes/claude-credential.js";
|
|
107
109
|
import { parseCliModel, refuseOutpostSelfTarget, resolveLaneModel, FOREGROUND_ONLY_RULE, STANDING_AUTHORIZATION, tempHomeRule, spawnLaneWorker, spawnEnvelopeRepairRequest, laneRunDir, readSpawnManifest, stopLaneProcesses, } from "../lib/lanes/spawn.js";
|
|
108
110
|
import { handOffInstallHere } from "../lib/daemon/handoff.js";
|
|
109
111
|
export { spawnLaneWorker };
|
|
@@ -439,6 +441,7 @@ function resolveDeps(deps = {}) {
|
|
|
439
441
|
mesh: deps.mesh ?? createDefaultMesh(),
|
|
440
442
|
sleep: deps.sleep ?? defaultSleep,
|
|
441
443
|
spawnProcess: deps.spawnProcess,
|
|
444
|
+
statfs: deps.statfs,
|
|
442
445
|
proveDetached: deps.proveDetached,
|
|
443
446
|
killProcess: deps.killProcess,
|
|
444
447
|
isAlive: deps.isAlive,
|
|
@@ -460,6 +463,8 @@ function resolveDeps(deps = {}) {
|
|
|
460
463
|
}),
|
|
461
464
|
resolveMachineIdentity: deps.resolveMachineIdentity ?? lookupMachineIdentity,
|
|
462
465
|
probeProvider: deps.probeProvider ?? defaultProbe,
|
|
466
|
+
readClaudeCredential: deps.readClaudeCredential ??
|
|
467
|
+
(deps.probeProvider === undefined ? readLaneClaudeCredential : undefined),
|
|
463
468
|
runCompaction: deps.runCompaction,
|
|
464
469
|
locateTranscript: deps.locateTranscript,
|
|
465
470
|
monitorEvidence: deps.monitorEvidence ??
|
|
@@ -511,9 +516,11 @@ function startAdmittedLane(ctx, root, candidate) {
|
|
|
511
516
|
env: ctx.env,
|
|
512
517
|
hostname: admissionHost.hostname,
|
|
513
518
|
admissionHost,
|
|
519
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
514
520
|
modelDeps: { readFileSync: ctx.readFileSync, probe: ctx.probeProvider, env: ctx.env },
|
|
515
521
|
existsSync: ctx.existsSync,
|
|
516
522
|
spawnProcess: ctx.spawnProcess,
|
|
523
|
+
statfs: ctx.statfs,
|
|
517
524
|
proveDetached: ctx.proveDetached,
|
|
518
525
|
killProcess: ctx.killProcess,
|
|
519
526
|
now: ctx.now,
|
|
@@ -2161,6 +2168,7 @@ async function loadClaudeBalanceHostSnapshots(ctx, hqRoot, config, options = {})
|
|
|
2161
2168
|
config,
|
|
2162
2169
|
existsSync: ctx.existsSync,
|
|
2163
2170
|
probe: ctx.probeProvider,
|
|
2171
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
2164
2172
|
env: ctx.env,
|
|
2165
2173
|
hostname: ctx.hostname(),
|
|
2166
2174
|
now: ctx.now(),
|
|
@@ -2184,6 +2192,7 @@ async function loadClaudeBalanceHostSnapshots(ctx, hqRoot, config, options = {})
|
|
|
2184
2192
|
config,
|
|
2185
2193
|
existsSync: ctx.existsSync,
|
|
2186
2194
|
probe: ctx.probeProvider,
|
|
2195
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
2187
2196
|
env: ctx.env,
|
|
2188
2197
|
hostname: ctx.hostname(),
|
|
2189
2198
|
now: ctx.now(),
|
|
@@ -4012,6 +4021,7 @@ async function runCreate(ctx, opts) {
|
|
|
4012
4021
|
existsSync: ctx.existsSync,
|
|
4013
4022
|
hostname: ctx.hostname(),
|
|
4014
4023
|
probe: ctx.probeProvider,
|
|
4024
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
4015
4025
|
env: ctx.env,
|
|
4016
4026
|
}).logged_in === true)
|
|
4017
4027
|
.sort(),
|
|
@@ -4083,7 +4093,25 @@ async function runCreate(ctx, opts) {
|
|
|
4083
4093
|
});
|
|
4084
4094
|
}
|
|
4085
4095
|
}
|
|
4086
|
-
const
|
|
4096
|
+
const candidateAccounts = validatedAccounts.size > 0 ? [...validatedAccounts] : profileAccounts;
|
|
4097
|
+
const accountCompany = resolveLaneCompany(hqRoot, { lane_id: "pending-create", company, mesh_company: meshCompany ?? undefined, project_id: project }).company;
|
|
4098
|
+
const allowedAccounts = Object.keys(config.providers[provider].accounts).filter((id) => (candidateAccounts === undefined || candidateAccounts.includes(id)) &&
|
|
4099
|
+
accountMatchesCompany(config.providers[provider].accounts[id], accountCompany, config.providers[provider].accounts));
|
|
4100
|
+
if (pinnedAccount !== undefined && !accountMatchesCompany(config.providers[provider].accounts[pinnedAccount], accountCompany, config.providers[provider].accounts)) {
|
|
4101
|
+
throw new LanesError("account_company_mismatch", `Account ${pinnedAccount} does not belong to the lane company`, { provider, account: pinnedAccount });
|
|
4102
|
+
}
|
|
4103
|
+
// Local creates and Claude balancing select an account here; other Outpost
|
|
4104
|
+
// creates pick theirs on the Outpost, so they are not refused locally.
|
|
4105
|
+
if (pinnedAccount === undefined && (outpostId === undefined || provider === "claude")) {
|
|
4106
|
+
const mismatch = companyMismatchError({
|
|
4107
|
+
provider,
|
|
4108
|
+
providerAccounts: config.providers[provider].accounts,
|
|
4109
|
+
candidates: candidateAccounts ?? Object.keys(config.providers[provider].accounts),
|
|
4110
|
+
company: accountCompany,
|
|
4111
|
+
});
|
|
4112
|
+
if (mismatch !== undefined)
|
|
4113
|
+
throw mismatch;
|
|
4114
|
+
}
|
|
4087
4115
|
let accountSelection;
|
|
4088
4116
|
if (provider === "claude") {
|
|
4089
4117
|
const persistedLocalHost = outpostId === undefined && placementHostOverride === undefined
|
|
@@ -4101,6 +4129,7 @@ async function runCreate(ctx, opts) {
|
|
|
4101
4129
|
balanceTargetHost = targetHost;
|
|
4102
4130
|
balanceHostLoad = await loadClaudeBalanceHostSnapshots(ctx, hqRoot, config);
|
|
4103
4131
|
const selected = selectClaudeAccount({
|
|
4132
|
+
company: accountCompany,
|
|
4104
4133
|
hosts: balanceHostLoad.snapshots,
|
|
4105
4134
|
targetHost,
|
|
4106
4135
|
actualTargetHost,
|
|
@@ -4119,11 +4148,7 @@ async function runCreate(ctx, opts) {
|
|
|
4119
4148
|
accountSelection = { ...selected, selected_at: ctx.now().toISOString() };
|
|
4120
4149
|
}
|
|
4121
4150
|
const balancedAdmissionAccounts = !outpostId && pinnedAccount === undefined
|
|
4122
|
-
?
|
|
4123
|
-
Object.entries(config.providers[provider].accounts)
|
|
4124
|
-
.filter(([id, account]) => account.enabled &&
|
|
4125
|
-
(profileAccounts === undefined || profileAccounts.includes(id)))
|
|
4126
|
-
.map(([id]) => id))]
|
|
4151
|
+
? allowedAccounts.filter((id) => config.providers[provider].accounts[id]?.enabled)
|
|
4127
4152
|
: undefined;
|
|
4128
4153
|
// The lane id is created in `persist`; its Work Mesh thread is ensured
|
|
4129
4154
|
// immediately afterward from that stable identity.
|
|
@@ -4167,6 +4192,7 @@ async function runCreate(ctx, opts) {
|
|
|
4167
4192
|
config,
|
|
4168
4193
|
existsSync: ctx.existsSync,
|
|
4169
4194
|
probe: ctx.probeProvider,
|
|
4195
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
4170
4196
|
env: ctx.env,
|
|
4171
4197
|
hostname: ctx.hostname(),
|
|
4172
4198
|
now: ctx.now(),
|
|
@@ -4181,6 +4207,7 @@ async function runCreate(ctx, opts) {
|
|
|
4181
4207
|
? { kind: "outpost", id: outpostId }
|
|
4182
4208
|
: localStableHost(ctx));
|
|
4183
4209
|
const selected = selectClaudeAccount({
|
|
4210
|
+
company: accountCompany,
|
|
4184
4211
|
hosts,
|
|
4185
4212
|
targetHost: balanceTargetHost,
|
|
4186
4213
|
actualTargetHost: actualTargetHostForPersist,
|
|
@@ -4521,6 +4548,7 @@ async function runCreate(ctx, opts) {
|
|
|
4521
4548
|
else if (admission.action === "start") {
|
|
4522
4549
|
started = spawnLaneWorker(hqRoot, lane, {
|
|
4523
4550
|
env: ctx.env,
|
|
4551
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
4524
4552
|
modelDeps: {
|
|
4525
4553
|
readFileSync: ctx.readFileSync,
|
|
4526
4554
|
probe: ctx.probeProvider,
|
|
@@ -4850,6 +4878,10 @@ function outpostRejectedGrantContextOption(result) {
|
|
|
4850
4878
|
return result.exitCode !== 0 &&
|
|
4851
4879
|
/unknown option\s+(?:['"])?--grant-context(?:['"])?(?:\s|$)/i.test(`${result.stderr}\n${result.stdout}`);
|
|
4852
4880
|
}
|
|
4881
|
+
function outpostRejectedSetTargetCommand(result) {
|
|
4882
|
+
return result.exitCode !== 0 &&
|
|
4883
|
+
/unknown command\s+(?:['"])?set-target(?:['"])?(?:\s|$)/i.test(`${result.stderr}\n${result.stdout}`);
|
|
4884
|
+
}
|
|
4853
4885
|
function outpostRejectedFailedResumeOption(result) {
|
|
4854
4886
|
return result.exitCode !== 0 &&
|
|
4855
4887
|
/unknown option\s+(?:['"])?--(?:from-failed|failed-resume-context)(?:['"])?(?:\s|$)/i.test(`${result.stderr}\n${result.stdout}`);
|
|
@@ -5230,9 +5262,11 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options, behavior =
|
|
|
5230
5262
|
? "approve-target"
|
|
5231
5263
|
: action === "repair-company"
|
|
5232
5264
|
? "repair-company-target"
|
|
5233
|
-
: action
|
|
5265
|
+
: action === "set"
|
|
5266
|
+
? "set-target"
|
|
5267
|
+
: action,
|
|
5234
5268
|
laneId: lane.lane_id,
|
|
5235
|
-
hqBinary: action === "grant" || action === "reparent" || action === "repair-company"
|
|
5269
|
+
hqBinary: action === "grant" || action === "reparent" || action === "repair-company" || action === "set"
|
|
5236
5270
|
? outpostCliOverride(ctx, outpostId)
|
|
5237
5271
|
: undefined,
|
|
5238
5272
|
text: options.text,
|
|
@@ -5247,6 +5281,7 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options, behavior =
|
|
|
5247
5281
|
fromFailed: options.fromFailed,
|
|
5248
5282
|
hire: options.hire,
|
|
5249
5283
|
senior: options.senior,
|
|
5284
|
+
actor: options.actor,
|
|
5250
5285
|
reason: options.reason,
|
|
5251
5286
|
company: options.company,
|
|
5252
5287
|
grantContext: contexts.grantContext,
|
|
@@ -5297,6 +5332,14 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options, behavior =
|
|
|
5297
5332
|
required_option: "--from-failed",
|
|
5298
5333
|
});
|
|
5299
5334
|
}
|
|
5335
|
+
if (action === "set" && outpostRejectedSetTargetCommand(dispatched)) {
|
|
5336
|
+
throw new LanesError("outpost_cli_upgrade_required", `Outpost ${outpostId} needs an hq-cli release containing remote lane settings before hq lanes set can change lane ${lane.lane_id}`, {
|
|
5337
|
+
lane_id: lane.lane_id,
|
|
5338
|
+
outpost_id: outpostId,
|
|
5339
|
+
command_id: dispatched.commandId,
|
|
5340
|
+
required_command: "set-target",
|
|
5341
|
+
});
|
|
5342
|
+
}
|
|
5300
5343
|
const ownerError = ownerErrorFromOutput(dispatched.stdout);
|
|
5301
5344
|
if (options.effort !== undefined && outpostRejectedEffortOption(dispatched)) {
|
|
5302
5345
|
throw new LanesError("outpost_effort_unsupported", `Outpost ${outpostId} rejected --effort; update hq-cli on that Outpost before changing a lane's effort remotely`, {
|
|
@@ -5372,23 +5415,25 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options, behavior =
|
|
|
5372
5415
|
remote.lane.company !== null &&
|
|
5373
5416
|
remote.lane.company !== undefined &&
|
|
5374
5417
|
remote.lane.company.slug === options.company
|
|
5375
|
-
: action === "
|
|
5376
|
-
? remote.lane !== null && typeof remote.lane === "object" &&
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
remote.
|
|
5381
|
-
|
|
5382
|
-
remote.lane !==
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5418
|
+
: action === "set"
|
|
5419
|
+
? remote.lane !== null && typeof remote.lane === "object" && !Array.isArray(remote.lane)
|
|
5420
|
+
: action === "reparent"
|
|
5421
|
+
? remote.lane !== null && typeof remote.lane === "object" &&
|
|
5422
|
+
Array.isArray(remote.changed_descendant_ids)
|
|
5423
|
+
: (((remote.delivery_status === "worker_spawned" ||
|
|
5424
|
+
remote.delivery_status === "queued_on_target_account") &&
|
|
5425
|
+
remote.lane !== undefined) ||
|
|
5426
|
+
(remote.delivery_status === "queued_on_admission" &&
|
|
5427
|
+
remote.lane !== null &&
|
|
5428
|
+
typeof remote.lane === "object" &&
|
|
5429
|
+
!Array.isArray(remote.lane) &&
|
|
5430
|
+
remote.lane.state === "queued") ||
|
|
5431
|
+
(remote.delivery_status === "queued_for_reconcile" &&
|
|
5432
|
+
remote.lane !== null &&
|
|
5433
|
+
typeof remote.lane === "object" &&
|
|
5434
|
+
!Array.isArray(remote.lane) &&
|
|
5435
|
+
remote.lane.state === "queued" &&
|
|
5436
|
+
remote.lane.queued_reason !== "worker_profile_changed")));
|
|
5392
5437
|
if (!resultConfirmed) {
|
|
5393
5438
|
throw new LanesError("outpost_delivery_unconfirmed", `Outpost ${outpostId} completed exec without a confirmed ${action} result for lane ${lane.lane_id}`, {
|
|
5394
5439
|
lane_id: lane.lane_id,
|
|
@@ -5447,7 +5492,11 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options, behavior =
|
|
|
5447
5492
|
printJson(response);
|
|
5448
5493
|
return response;
|
|
5449
5494
|
}
|
|
5450
|
-
if (action === "approve" ||
|
|
5495
|
+
if (action === "approve" ||
|
|
5496
|
+
action === "reparent" ||
|
|
5497
|
+
action === "resume" ||
|
|
5498
|
+
action === "repair-company" ||
|
|
5499
|
+
action === "set") {
|
|
5451
5500
|
const ownerLane = dispatchedOwnerLane(ctx, lane.lane_id, outpostId, remote.lane, behavior);
|
|
5452
5501
|
const descendants = [];
|
|
5453
5502
|
if (action === "reparent") {
|
|
@@ -5777,6 +5826,7 @@ async function runPickup(ctx, opts) {
|
|
|
5777
5826
|
try {
|
|
5778
5827
|
return spawnLaneWorker(hqRoot, current, {
|
|
5779
5828
|
env: ctx.env,
|
|
5829
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
5780
5830
|
modelDeps: {
|
|
5781
5831
|
readFileSync: ctx.readFileSync,
|
|
5782
5832
|
probe: ctx.probeProvider,
|
|
@@ -6173,6 +6223,7 @@ async function runCapacity(ctx) {
|
|
|
6173
6223
|
config: loadLanesConfig(hqRoot),
|
|
6174
6224
|
existsSync: ctx.existsSync,
|
|
6175
6225
|
probe: ctx.probeProvider,
|
|
6226
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
6176
6227
|
env: ctx.env,
|
|
6177
6228
|
hostname: ctx.hostname(),
|
|
6178
6229
|
now: ctx.now(),
|
|
@@ -6717,6 +6768,10 @@ async function printGrantResult(ctx, hqRoot, updated, hierarchy) {
|
|
|
6717
6768
|
* resume. The running turn keeps its values. Both are stored as explicit
|
|
6718
6769
|
* (`cli`) choices, so keep-alive and `hq lanes resume` keep them until the
|
|
6719
6770
|
* next `set` or an explicit resume `--effort`/`--worker`.
|
|
6771
|
+
*
|
|
6772
|
+
* A lane whose state lives on another Outpost is resolved the same way
|
|
6773
|
+
* `hq lanes grant` resolves it, and the change is forwarded to the owning
|
|
6774
|
+
* Outpost after the caller is checked against the owner's senior.
|
|
6720
6775
|
*/
|
|
6721
6776
|
async function runSet(ctx, laneId, opts) {
|
|
6722
6777
|
if (opts.company !== undefined) {
|
|
@@ -6726,6 +6781,60 @@ async function runSet(ctx, laneId, opts) {
|
|
|
6726
6781
|
await runRepairCompany(ctx, laneId, { company: opts.company });
|
|
6727
6782
|
return;
|
|
6728
6783
|
}
|
|
6784
|
+
const request = parseLaneSetRequest(laneId, opts);
|
|
6785
|
+
const target = await resolveCommandLaneTarget(ctx, laneId);
|
|
6786
|
+
const lane = target.lane;
|
|
6787
|
+
const callerLaneId = ctx.env.HQ_LANE_ID?.trim() || undefined;
|
|
6788
|
+
const authorization = callerLaneId === lane.lane_id
|
|
6789
|
+
? { authorized: true }
|
|
6790
|
+
: callerSeniorAuthorization(ctx, lane.senior);
|
|
6791
|
+
if (!authorization.authorized) {
|
|
6792
|
+
throw new LanesError("lane_set_unauthorized", appendCallerSeniorReason(`Only lane ${lane.lane_id} or its senior ${seniorKey(lane.senior)} may change its model or effort`, authorization), { lane_id: lane.lane_id, senior: lane.senior, reason: authorization.reason });
|
|
6793
|
+
}
|
|
6794
|
+
const actor = callerLaneId !== undefined
|
|
6795
|
+
? `lane:${callerLaneId}`
|
|
6796
|
+
: `session:${sessionIdFromEnv(ctx.env) ?? "unknown"}`;
|
|
6797
|
+
if (target.remoteOnly || (lane.host.kind === "outpost" && !laneRunsHereForOperatorMutation(ctx, lane))) {
|
|
6798
|
+
assertLaneSetResumable(lane);
|
|
6799
|
+
// Reject a bad effort here so the owner round trip is not spent on it.
|
|
6800
|
+
parseCliEffort(lane.provider, request.effort);
|
|
6801
|
+
await dispatchOutpostLaneCommand(ctx, lane, "set", {
|
|
6802
|
+
model: request.model,
|
|
6803
|
+
effort: request.effort,
|
|
6804
|
+
reason: request.reason,
|
|
6805
|
+
senior: seniorKey(lane.senior),
|
|
6806
|
+
actor,
|
|
6807
|
+
}, target.remoteOnly
|
|
6808
|
+
? { syncPrimary: false, expectedOwnerHost: target.ownerHost }
|
|
6809
|
+
: {});
|
|
6810
|
+
return;
|
|
6811
|
+
}
|
|
6812
|
+
const updated = applyLaneSettings(ctx, lane.lane_id, request, { actor });
|
|
6813
|
+
printLaneSetResult(updated);
|
|
6814
|
+
}
|
|
6815
|
+
/**
|
|
6816
|
+
* Owner side of a forwarded `hq lanes set`. The primary has already checked
|
|
6817
|
+
* the caller against the lane's senior; this side accepts only an SSM Run
|
|
6818
|
+
* Command dispatch for a lane hosted here whose senior is still the one the
|
|
6819
|
+
* primary checked.
|
|
6820
|
+
*/
|
|
6821
|
+
async function runSetOwnerTarget(ctx, laneId, opts) {
|
|
6822
|
+
if (!ctx.isSsmOwnerDispatch()) {
|
|
6823
|
+
throw new LanesError("lane_set_dispatch_unauthorized", "The Outpost set target is available only to an SSM Run Command dispatch", { lane_id: laneId });
|
|
6824
|
+
}
|
|
6825
|
+
const request = parseLaneSetRequest(laneId, opts);
|
|
6826
|
+
if (opts.senior === undefined) {
|
|
6827
|
+
throw new LanesError("lane_set_senior_required", "--senior is required", { lane_id: laneId });
|
|
6828
|
+
}
|
|
6829
|
+
const expectedSenior = parseSeniorRef(opts.senior);
|
|
6830
|
+
const actor = opts.actor?.trim();
|
|
6831
|
+
if (!actor || !/^(?:lane|session):\S+$/.test(actor)) {
|
|
6832
|
+
throw new LanesError("lane_set_actor_invalid", "--actor must be lane:<id> or session:<id>", { lane_id: laneId });
|
|
6833
|
+
}
|
|
6834
|
+
const updated = applyLaneSettings(ctx, laneId, request, { actor, expectedSenior });
|
|
6835
|
+
printLaneSetResult(updated);
|
|
6836
|
+
}
|
|
6837
|
+
function parseLaneSetRequest(laneId, opts) {
|
|
6729
6838
|
if (opts.model === undefined && opts.effort === undefined) {
|
|
6730
6839
|
throw new LanesError("lane_set_empty", "hq lanes set needs --company, --model, or --effort", { lane_id: laneId });
|
|
6731
6840
|
}
|
|
@@ -6735,26 +6844,37 @@ async function runSet(ctx, laneId, opts) {
|
|
|
6735
6844
|
}
|
|
6736
6845
|
if (reason !== undefined)
|
|
6737
6846
|
assertNoSecretText("set reason", reason);
|
|
6847
|
+
const model = opts.model?.trim();
|
|
6848
|
+
if (opts.model !== undefined && !model) {
|
|
6849
|
+
throw new LanesError("empty_model", "--model is empty or whitespace-only", { value: opts.model });
|
|
6850
|
+
}
|
|
6851
|
+
return {
|
|
6852
|
+
...(model !== undefined ? { model } : {}),
|
|
6853
|
+
...(opts.effort !== undefined ? { effort: opts.effort } : {}),
|
|
6854
|
+
...(reason !== undefined ? { reason } : {}),
|
|
6855
|
+
};
|
|
6856
|
+
}
|
|
6857
|
+
function assertLaneSetResumable(lane) {
|
|
6858
|
+
if (lane.state === "killed" || lane.state === "cancelled") {
|
|
6859
|
+
throw new LanesError("lane_not_resumable", `Lane ${lane.lane_id} is ${lane.state} and will not run again`, { lane_id: lane.lane_id, state: lane.state });
|
|
6860
|
+
}
|
|
6861
|
+
}
|
|
6862
|
+
function assertLaneSetSenior(lane, expectedSenior) {
|
|
6863
|
+
if (expectedSenior === undefined || seniorKey(lane.senior) === seniorKey(expectedSenior))
|
|
6864
|
+
return;
|
|
6865
|
+
throw new LanesError("lane_set_senior_changed", `Lane ${lane.lane_id}'s senior changed after the primary authorized its settings change`, { lane_id: lane.lane_id, expected_senior: expectedSenior, current_senior: lane.senior });
|
|
6866
|
+
}
|
|
6867
|
+
/** Apply a validated set request to a lane whose state lives on this host. */
|
|
6868
|
+
function applyLaneSettings(ctx, laneId, request, options) {
|
|
6738
6869
|
const hqRoot = ctx.hqRoot();
|
|
6739
6870
|
const lane = readLane(hqRoot, laneId);
|
|
6740
|
-
const callerLaneId = ctx.env.HQ_LANE_ID?.trim() || undefined;
|
|
6741
|
-
const authorization = callerLaneId === laneId
|
|
6742
|
-
? { authorized: true }
|
|
6743
|
-
: callerSeniorAuthorization(ctx, lane.senior);
|
|
6744
|
-
if (!authorization.authorized) {
|
|
6745
|
-
throw new LanesError("lane_set_unauthorized", appendCallerSeniorReason(`Only lane ${laneId} or its senior ${seniorKey(lane.senior)} may change its model or effort`, authorization), { lane_id: laneId, senior: lane.senior, reason: authorization.reason });
|
|
6746
|
-
}
|
|
6747
6871
|
if (lane.host.kind === "outpost" && !laneRunsHereForOperatorMutation(ctx, lane)) {
|
|
6748
6872
|
throw new LanesError("set_remote_unsupported", `Lane ${laneId} runs on Outpost ${lane.host.id}; run hq lanes set on that Outpost`, { lane_id: laneId, outpost_id: lane.host.id });
|
|
6749
6873
|
}
|
|
6750
6874
|
assertLaneRunsHereForOperatorMutation(ctx, lane, "set");
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
}
|
|
6754
|
-
const model = opts.model?.trim();
|
|
6755
|
-
if (opts.model !== undefined && !model) {
|
|
6756
|
-
throw new LanesError("empty_model", "--model is empty or whitespace-only", { value: opts.model });
|
|
6757
|
-
}
|
|
6875
|
+
assertLaneSetSenior(lane, options.expectedSenior);
|
|
6876
|
+
assertLaneSetResumable(lane);
|
|
6877
|
+
const { model, reason } = request;
|
|
6758
6878
|
if (model !== undefined) {
|
|
6759
6879
|
const config = loadLanesConfig(hqRoot);
|
|
6760
6880
|
const account = lane.account === undefined
|
|
@@ -6769,16 +6889,13 @@ async function runSet(ctx, laneId, opts) {
|
|
|
6769
6889
|
env: ctx.env,
|
|
6770
6890
|
});
|
|
6771
6891
|
}
|
|
6772
|
-
const effort = parseCliEffort(lane.provider,
|
|
6892
|
+
const effort = parseCliEffort(lane.provider, request.effort);
|
|
6773
6893
|
const at = ctx.now().toISOString();
|
|
6774
|
-
|
|
6775
|
-
? `lane:${callerLaneId}`
|
|
6776
|
-
: `session:${sessionIdFromEnv(ctx.env) ?? "unknown"}`;
|
|
6777
|
-
const updated = casUpdateLane(hqRoot, laneId, (current) => {
|
|
6894
|
+
return casUpdateLane(hqRoot, laneId, (current) => {
|
|
6778
6895
|
if (current.version !== lane.version) {
|
|
6779
6896
|
throw new LanesError("lane_set_conflict", `Lane ${laneId} changed while the settings were checked; run hq lanes set again`, { lane_id: laneId, prepared_version: lane.version, version: current.version });
|
|
6780
6897
|
}
|
|
6781
|
-
const entry = { at, actor, ...(reason !== undefined ? { reason } : {}) };
|
|
6898
|
+
const entry = { at, actor: options.actor, ...(reason !== undefined ? { reason } : {}) };
|
|
6782
6899
|
const next = { ...current };
|
|
6783
6900
|
const pending = { ...(current.pending_settings ?? {}) };
|
|
6784
6901
|
// A running turn keeps the model and effort it launched with, because the
|
|
@@ -6810,9 +6927,12 @@ async function runSet(ctx, laneId, opts) {
|
|
|
6810
6927
|
next.settings_history = appendCappedHistory(current.settings_history ?? [], entry);
|
|
6811
6928
|
return next;
|
|
6812
6929
|
});
|
|
6930
|
+
}
|
|
6931
|
+
function printLaneSetResult(updated) {
|
|
6813
6932
|
printJson({
|
|
6814
6933
|
ok: true,
|
|
6815
6934
|
action: "set",
|
|
6935
|
+
lane_id: updated.lane_id,
|
|
6816
6936
|
lane: updated,
|
|
6817
6937
|
model: updated.pending_settings?.model ?? updated.model ?? null,
|
|
6818
6938
|
effort: updated.pending_settings?.effort ?? updated.effort ?? null,
|
|
@@ -7331,7 +7451,8 @@ function validateResumeProfileModel(ctx, lane, profile) {
|
|
|
7331
7451
|
env: ctx.env,
|
|
7332
7452
|
});
|
|
7333
7453
|
}
|
|
7334
|
-
|
|
7454
|
+
/** @internal Exported for regression tests of the profile-refresh company check. */
|
|
7455
|
+
export function applyResumeProfileAndEffort(hqRoot, current, next, input) {
|
|
7335
7456
|
if (input.profile !== undefined) {
|
|
7336
7457
|
const profile = input.profile.profile;
|
|
7337
7458
|
next.worker = input.profile.id;
|
|
@@ -7387,6 +7508,12 @@ function applyResumeProfileAndEffort(current, next, input) {
|
|
|
7387
7508
|
next.provider = targetProvider;
|
|
7388
7509
|
next.provider_source = providerPinned ? current.provider_source : "profile";
|
|
7389
7510
|
if (!accountPinned && profileMatchesProvider) {
|
|
7511
|
+
if (profileAccount !== undefined && profileAccount !== current.account &&
|
|
7512
|
+
!accountMatchesCompany(loadLanesConfig(hqRoot).providers[targetProvider].accounts[profileAccount], resolveLaneCompany(hqRoot, current).company, loadLanesConfig(hqRoot).providers[targetProvider].accounts)) {
|
|
7513
|
+
throw new LanesError("account_company_mismatch", "Worker profile account does not belong to the lane company", {
|
|
7514
|
+
lane_id: current.lane_id, account: profileAccount,
|
|
7515
|
+
});
|
|
7516
|
+
}
|
|
7390
7517
|
next.account = profileAccount;
|
|
7391
7518
|
next.account_source = profileAccount === undefined ? "balanced" : "profile";
|
|
7392
7519
|
next.account_selection = undefined;
|
|
@@ -7496,7 +7623,7 @@ function recordResumeSetup(ctx, lane, input) {
|
|
|
7496
7623
|
next.keep_alive_blocked_reason = undefined;
|
|
7497
7624
|
if (input.accountSource !== undefined)
|
|
7498
7625
|
next.account_source = input.accountSource;
|
|
7499
|
-
applyResumeProfileAndEffort(current, next, { ...input, at: ctx.now().toISOString() });
|
|
7626
|
+
applyResumeProfileAndEffort(ctx.hqRoot(), current, next, { ...input, at: ctx.now().toISOString() });
|
|
7500
7627
|
if (input.accountSource !== undefined)
|
|
7501
7628
|
next.account_source = input.accountSource;
|
|
7502
7629
|
if (input.clearWorkerProfileChangedQueue === true) {
|
|
@@ -7576,6 +7703,11 @@ async function prepareAccountMove(ctx, lane, input) {
|
|
|
7576
7703
|
if (targetCfg === undefined) {
|
|
7577
7704
|
throw new AccountResolutionError("unknown_account", `Unknown account ${JSON.stringify(target)} for ${lane.provider}. Configured: ${Object.keys(providerCfg.accounts).join(", ") || "(none)"}`, { provider: lane.provider, account: target, enabled: Object.keys(providerCfg.accounts).filter((id) => providerCfg.accounts[id]?.enabled) });
|
|
7578
7705
|
}
|
|
7706
|
+
if (!accountMatchesCompany(targetCfg, resolveLaneCompany(hqRoot, lane).company, providerCfg.accounts)) {
|
|
7707
|
+
throw new LanesError("account_company_mismatch", "Lane moves require an account assigned to the lane's company", {
|
|
7708
|
+
provider: lane.provider, account: target, company: lane.company,
|
|
7709
|
+
});
|
|
7710
|
+
}
|
|
7579
7711
|
const targetHome = lane.remote_control === true
|
|
7580
7712
|
? remoteControlSessionHome(config, ctx.hostname())
|
|
7581
7713
|
: effectiveAccountHome(targetCfg, ctx.hostname()).home;
|
|
@@ -7586,6 +7718,7 @@ async function prepareAccountMove(ctx, lane, input) {
|
|
|
7586
7718
|
existsSync: ctx.existsSync,
|
|
7587
7719
|
hostname: ctx.hostname(),
|
|
7588
7720
|
probe: ctx.probeProvider,
|
|
7721
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
7589
7722
|
env: ctx.env,
|
|
7590
7723
|
}).logged_in !== true) {
|
|
7591
7724
|
throw new LanesError("account_not_logged_in", `Account ${target} for ${lane.provider} is not logged in (no credential file)`, { provider: lane.provider, account: target, lane_id: laneId });
|
|
@@ -7705,7 +7838,7 @@ async function prepareAccountMove(ctx, lane, input) {
|
|
|
7705
7838
|
...input.pending,
|
|
7706
7839
|
},
|
|
7707
7840
|
};
|
|
7708
|
-
applyResumeProfileAndEffort(current, next, {
|
|
7841
|
+
applyResumeProfileAndEffort(ctx.hqRoot(), current, next, {
|
|
7709
7842
|
...(input.workerProfile !== undefined ? { profile: input.workerProfile } : {}),
|
|
7710
7843
|
...(input.profileRepin !== undefined ? { profileRepin: input.profileRepin } : {}),
|
|
7711
7844
|
...(input.effort !== undefined ? { effort: input.effort } : {}),
|
|
@@ -7752,10 +7885,12 @@ async function selectAutomaticClaudeResumeAccount(ctx, lane, workerProfile, opti
|
|
|
7752
7885
|
existsSync: ctx.existsSync,
|
|
7753
7886
|
hostname: ctx.hostname(),
|
|
7754
7887
|
probe: ctx.probeProvider,
|
|
7888
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
7755
7889
|
env: ctx.env,
|
|
7756
7890
|
}).logged_in;
|
|
7757
7891
|
const recordedAccountUnavailable = lane.account !== undefined &&
|
|
7758
|
-
(currentConfig?.enabled !== true || currentLogin === false
|
|
7892
|
+
(currentConfig?.enabled !== true || currentLogin === false ||
|
|
7893
|
+
!accountMayRetainLane(currentConfig, resolveLaneCompany(hqRoot, lane).company, config.providers[lane.provider].accounts));
|
|
7759
7894
|
const profile = workerProfile?.profile ?? (lane.worker_profile !== undefined
|
|
7760
7895
|
? loadWorkerProfile(hqRoot, lane.worker_profile)
|
|
7761
7896
|
: undefined);
|
|
@@ -7817,7 +7952,7 @@ async function selectAutomaticClaudeResumeAccount(ctx, lane, workerProfile, opti
|
|
|
7817
7952
|
const currentTargetAccount = lane.account === undefined
|
|
7818
7953
|
? undefined
|
|
7819
7954
|
: targetHost?.capacity.providers.claude.accounts[lane.account];
|
|
7820
|
-
if (!
|
|
7955
|
+
if (!accountNeedsRepair &&
|
|
7821
7956
|
profilePin !== undefined &&
|
|
7822
7957
|
lane.account !== undefined &&
|
|
7823
7958
|
allowedAccounts?.includes(lane.account) &&
|
|
@@ -7826,6 +7961,8 @@ async function selectAutomaticClaudeResumeAccount(ctx, lane, workerProfile, opti
|
|
|
7826
7961
|
currentTargetAccount.logged_in === true)
|
|
7827
7962
|
return undefined;
|
|
7828
7963
|
const selectionInput = {
|
|
7964
|
+
company: resolveLaneCompany(hqRoot, lane).company,
|
|
7965
|
+
retainedAccount: lane.account,
|
|
7829
7966
|
hosts: balanceHosts.snapshots,
|
|
7830
7967
|
targetHost: lane.host,
|
|
7831
7968
|
actualTargetHost: lane.host,
|
|
@@ -7990,6 +8127,7 @@ function automaticBalanceMoveHistoryReason(ctx, lane) {
|
|
|
7990
8127
|
existsSync: ctx.existsSync,
|
|
7991
8128
|
hostname: ctx.hostname(),
|
|
7992
8129
|
probe: ctx.probeProvider,
|
|
8130
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
7993
8131
|
env: ctx.env,
|
|
7994
8132
|
}).logged_in;
|
|
7995
8133
|
if (login === false)
|
|
@@ -9693,6 +9831,7 @@ async function runReconcile(ctx, opts, recoverQueuedMessages) {
|
|
|
9693
9831
|
dryRun: Boolean(opts.dryRun),
|
|
9694
9832
|
spawnLaneDeps: {
|
|
9695
9833
|
env: ctx.env,
|
|
9834
|
+
readClaudeCredential: ctx.readClaudeCredential,
|
|
9696
9835
|
modelDeps: {
|
|
9697
9836
|
readFileSync: ctx.readFileSync,
|
|
9698
9837
|
probe: ctx.probeProvider,
|
|
@@ -10404,6 +10543,17 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
10404
10543
|
.action(wrap(async (laneId, opts) => {
|
|
10405
10544
|
await runGrantOwnerTarget(ctx, laneId, opts);
|
|
10406
10545
|
}));
|
|
10546
|
+
lanes
|
|
10547
|
+
.command("set-target", { hidden: true })
|
|
10548
|
+
.argument("<lane-id>", "Lane id")
|
|
10549
|
+
.option("--model <name>", "Model for the next resume")
|
|
10550
|
+
.option("--effort <level>", "Effort for the next resume")
|
|
10551
|
+
.option("--reason <text>", "Reason recorded in the lane's settings history")
|
|
10552
|
+
.option("--senior <ref>", "Senior the primary authorized the change against")
|
|
10553
|
+
.option("--actor <ref>", "lane:<id> or session:<id> that requested the change")
|
|
10554
|
+
.action(wrap(async (laneId, opts) => {
|
|
10555
|
+
await runSetOwnerTarget(ctx, laneId, opts);
|
|
10556
|
+
}));
|
|
10407
10557
|
lanes
|
|
10408
10558
|
.command("keep-alive")
|
|
10409
10559
|
.description("Opt a lane into or out of automatic lead-lane resumes")
|