@indigoai-us/hq-cli 5.202.0 → 5.203.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 +15 -0
- package/README.md +24 -0
- package/assets/lanes-hooks/hq-lanes-drain.mjs +36 -15
- package/dist/command-catalog.generated.d.ts +168 -0
- package/dist/command-catalog.generated.js +214 -0
- package/dist/command-registration-plan.d.ts +6 -0
- package/dist/command-registration-plan.js +1 -0
- package/dist/commands/integrations-connect.d.ts +38 -0
- package/dist/commands/integrations-connect.js +39 -38
- package/dist/commands/integrations-core.d.ts +4 -6
- package/dist/commands/integrations-core.js +15 -12
- package/dist/commands/integrations-import.js +8 -6
- package/dist/commands/integrations-manage.js +8 -6
- package/dist/commands/integrations.js +9 -5
- package/dist/commands/lanes.d.ts +1 -0
- package/dist/commands/lanes.js +150 -83
- package/dist/commands/monitor.d.ts +58 -0
- package/dist/commands/monitor.js +965 -0
- package/dist/lib/doctor/checks/integrations.js +11 -0
- package/dist/lib/lanes/delivery-core.d.ts +15 -0
- package/dist/lib/lanes/delivery-core.js +21 -0
- package/dist/lib/lanes/delivery.d.ts +21 -5
- package/dist/lib/lanes/delivery.js +71 -7
- package/dist/lib/lanes/dropbox.d.ts +13 -1
- package/dist/lib/lanes/dropbox.js +61 -5
- package/dist/lib/lanes/index.d.ts +1 -1
- package/dist/lib/lanes/index.js +1 -1
- package/dist/lib/lanes/move-account.js +1 -1
- package/dist/lib/lanes/spawn.d.ts +6 -3
- package/dist/lib/lanes/spawn.js +41 -8
- package/dist/lib/lanes/types.d.ts +3 -0
- package/dist/lib/monitor.d.ts +153 -0
- package/dist/lib/monitor.js +519 -0
- package/dist/main.js +40 -28
- package/dist/utils/cli-network-lifecycle.d.ts +4 -0
- package/dist/utils/cli-network-lifecycle.js +11 -0
- package/dist/utils/redact-error-text.js +2 -1
- package/dist/utils/redact-url.d.ts +14 -0
- package/dist/utils/redact-url.js +218 -0
- package/package.json +1 -1
package/dist/commands/lanes.js
CHANGED
|
@@ -32,13 +32,15 @@ import { vaultApiFetch } from "../utils/vault-api.js";
|
|
|
32
32
|
import { openMeshTransport } from "../lib/mesh/client.js";
|
|
33
33
|
import { createLaneMesh, emitLaneDecisionEvents, emitLaneTerminalStateEvent, laneMeshEventIdentity, } from "../lib/lanes/mesh-events.js";
|
|
34
34
|
import { sessionIdFromEnv } from "../lib/mesh/live/session-identity.js";
|
|
35
|
-
import { AccountResolutionError, compareLaneQueueOrder, coveredLaneIds, DEFAULT_ACCOUNT_HOMES, LANE_PROVIDERS, LANE_STATES, PROVIDER_HOME_ENV, QUESTION_STATUSES, SENIOR_KINDS, accountStatus, appendCappedHistory, canonicalizeHome, createLane, createQuestion, decideAdmission, defaultLivenessDeps, defaultSystemdUserDir, defaultThrottleDeps, installDrainHook, installReconcileTimer, providerPathEnv, probeDrainHookRegistration, isLanesError, isLaneVersionConflict, isTerminalLaneState, aliveDirectChildren, assignedChildHireGrants, LANE_HIRE_GRANTS_FLAG, planHireGrantBackfill, withHireGrantAdmission, laneStoryLedgerEnabled, validateProjectStories, buildLaneStatusSnapshot, formatLaneStatusHuman, listAccountStatuses, listLaneIds, listQuestionIds, listSessionLiveness, loadLanesConfig, laneRunsHere, MAX_LANE_DEPTH, MONITOR_ERROR_EXIT_CODE, MONITOR_ENGINES, MONITOR_MAX_TIMEOUT_MS, MONITOR_UNCOVERED_EXIT_CODE, MAX_WATCHED_LANES, monitorReminderText, readLiveMonitorEvidence, resolveMachineIdentity as lookupMachineIdentity, loadLivenessIndex, parseLaneProvider, parseLaneRecord, parseLaneState, parseLivenessState, parseQuestionRecord, parseQuestionStatus, parseSeniorKind, readDaemonPresenceConnected, readLane, retryUpdateLane, syncLaneRecordFromOwner, readQuestion, resolveAccount, resolveLaneWorker, ignoredWorkerProfileFields, loadWorkerProfile, runReconcilePass, wakeAnsweredLaneNow, runLaneWatch, sessionLiveness, tryReadLane, uninstallReconcileTimer, updateLane, updateQuestion, writeLanesConfig, appendDropboxMessage, answerDropboxMessage, deliveryRefusalReason, resumeCommandRefusal, dropboxDir, dropboxInboxPath, laneAcceptsDropboxDelivery, laneAcceptsOperatorMessage, laneDeliveryMechanism, hasActiveAdmissionReservation, hasActivePendingResume, hasRecordedSessionId, hasEarlierEligibleQueuedLane, laneAdmissionCapReason, providerSupportsSessionResume, withLaneAdmissionLock, withLaneHireLocks, laneIdForAnswerDelivery, operatorMessageRefusalReason, raiseLaneQuestion, sha256Text, writeQuestionBody, } from "../lib/lanes/index.js";
|
|
35
|
+
import { AccountResolutionError, compareLaneQueueOrder, coveredLaneIds, DEFAULT_ACCOUNT_HOMES, LANE_PROVIDERS, LANE_STATES, PROVIDER_HOME_ENV, QUESTION_STATUSES, SENIOR_KINDS, accountStatus, appendCappedHistory, canonicalizeHome, createLane, createQuestion, decideAdmission, defaultLivenessDeps, defaultSystemdUserDir, defaultThrottleDeps, installDrainHook, installReconcileTimer, providerPathEnv, probeDrainHookRegistration, isLanesError, isLaneVersionConflict, isTerminalLaneState, aliveDirectChildren, assignedChildHireGrants, LANE_HIRE_GRANTS_FLAG, planHireGrantBackfill, withHireGrantAdmission, laneStoryLedgerEnabled, validateProjectStories, buildLaneStatusSnapshot, formatLaneStatusHuman, listAccountStatuses, listLaneIds, listQuestionIds, listSessionLiveness, loadLanesConfig, laneRunsHere, MAX_LANE_DEPTH, MONITOR_ERROR_EXIT_CODE, MONITOR_ENGINES, MONITOR_MAX_TIMEOUT_MS, MONITOR_UNCOVERED_EXIT_CODE, MAX_WATCHED_LANES, monitorReminderText, readLiveMonitorEvidence, resolveMachineIdentity as lookupMachineIdentity, loadLivenessIndex, parseLaneProvider, parseLaneRecord, parseLaneState, parseLivenessState, parseQuestionRecord, parseQuestionStatus, parseSeniorKind, readDaemonPresenceConnected, readLane, retryUpdateLane, syncLaneRecordFromOwner, readQuestion, resolveAccount, resolveLaneWorker, ignoredWorkerProfileFields, loadWorkerProfile, runReconcilePass, wakeAnsweredLaneNow, runLaneWatch, sessionLiveness, tryReadLane, uninstallReconcileTimer, updateLane, updateQuestion, writeLanesConfig, appendDropboxMessage, answerDropboxMessage, deliveryRefusalReason, resumeCommandRefusal, dropboxDir, dropboxInboxPath, laneAcceptsDropboxDelivery, laneAcceptsOperatorMessage, laneDeliveryMechanism, hasActiveAdmissionReservation, hasActivePendingResume, hasRecordedSessionId, hasEarlierEligibleQueuedLane, laneAdmissionCapReason, providerSupportsSessionResume, providerSessionPortable, sessionNotPortableMessage, withLaneAdmissionLock, withLaneHireLocks, laneIdForAnswerDelivery, operatorMessageRefusalReason, raiseLaneQuestion, sha256Text, writeQuestionBody, } from "../lib/lanes/index.js";
|
|
36
36
|
import { activeLaneStories, laneStories, laneStory, storyWarning, } from "../lib/lanes/stories.js";
|
|
37
37
|
import { questionBodyAbsPath } from "../lib/lanes/questions.js";
|
|
38
38
|
import { compactionAfterUsage, } from "../lib/lanes/compaction.js";
|
|
39
39
|
import { providerCompactAfterMs } from "../lib/lanes/config.js";
|
|
40
40
|
import { parseCliEffort, resolveLaneEffort, } from "../lib/lanes/effort.js";
|
|
41
41
|
import { LanesError } from "../lib/lanes/errors.js";
|
|
42
|
+
import { dispatchLaneDelivery } from "../lib/lanes/delivery-core.js";
|
|
43
|
+
import { formatMonitorEvent } from "../lib/lanes/dropbox.js";
|
|
42
44
|
import { accountQuotaView, loadQuotaState, quotaBlockFor } from "../lib/lanes/quota.js";
|
|
43
45
|
import { SESSION_MOVE_REASON } from "../lib/lanes/move-account.js";
|
|
44
46
|
import { ensureSessionHome } from "../lib/lanes/session-relink.js";
|
|
@@ -235,6 +237,7 @@ function resolveDeps(deps = {}) {
|
|
|
235
237
|
throttleDeps: deps.throttleDeps ?? defaultThrottleDeps(env),
|
|
236
238
|
existsSync: deps.existsSync ?? ((p) => fs.existsSync(p)),
|
|
237
239
|
readFileSync: deps.readFileSync ?? ((p, encoding) => fs.readFileSync(p, encoding)),
|
|
240
|
+
readStdin: deps.readStdin ?? (() => fs.readFileSync(0, "utf8")),
|
|
238
241
|
homedir: deps.homedir ?? (() => os.homedir()),
|
|
239
242
|
mesh: deps.mesh ?? createDefaultMesh(),
|
|
240
243
|
sleep: deps.sleep ?? defaultSleep,
|
|
@@ -5021,11 +5024,10 @@ async function prepareAccountMove(ctx, lane, input) {
|
|
|
5021
5024
|
account: target,
|
|
5022
5025
|
});
|
|
5023
5026
|
}
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
throw new LanesError("provider_session_not_portable", `Provider ${lane.provider} has no session resume, so a lane cannot move between its accounts`, { lane_id: laneId, provider: lane.provider });
|
|
5027
|
+
// The grok comparison repeats PROVIDER_SESSION_PORTABLE so TypeScript narrows
|
|
5028
|
+
// the provider for ensureSessionHome below.
|
|
5029
|
+
if (!providerSessionPortable(lane.provider) || lane.provider === "grok") {
|
|
5030
|
+
throw new LanesError("provider_session_not_portable", sessionNotPortableMessage(lane.provider), { lane_id: laneId, provider: lane.provider });
|
|
5029
5031
|
}
|
|
5030
5032
|
if (!hasRecordedSessionId(lane)) {
|
|
5031
5033
|
throw new LanesError("no_provider_session", `Lane ${laneId} has no recorded provider session id, so there is no session to move`, { lane_id: laneId, provider: lane.provider });
|
|
@@ -5310,8 +5312,8 @@ async function runMessage(ctx, laneId, opts) {
|
|
|
5310
5312
|
state: lane.state,
|
|
5311
5313
|
});
|
|
5312
5314
|
}
|
|
5313
|
-
if (opts.account !== undefined && !keepCurrentAccount && !
|
|
5314
|
-
throw new LanesError("provider_session_not_portable",
|
|
5315
|
+
if (opts.account !== undefined && !keepCurrentAccount && !providerSessionPortable(lane.provider)) {
|
|
5316
|
+
throw new LanesError("provider_session_not_portable", sessionNotPortableMessage(lane.provider), { lane_id: laneId, provider: lane.provider });
|
|
5315
5317
|
}
|
|
5316
5318
|
// One decision point for how a follow-up reaches this lane (delivery.ts).
|
|
5317
5319
|
// `none` refuses before anything is written: no inbox append, no spawn.
|
|
@@ -5359,12 +5361,27 @@ async function runMessage(ctx, laneId, opts) {
|
|
|
5359
5361
|
if ((opts.project !== undefined || opts.story !== undefined) && ctx.storyLedgerEnabled()) {
|
|
5360
5362
|
validateProjectStories(hqRoot, projectId, [storyId], lane.company?.slug);
|
|
5361
5363
|
}
|
|
5364
|
+
const framedMonitorEvent = opts.monitorEvent === undefined
|
|
5365
|
+
? undefined
|
|
5366
|
+
: formatMonitorEvent({
|
|
5367
|
+
monitorId: opts.monitorEvent.monitor_id,
|
|
5368
|
+
description: opts.monitorEvent.description,
|
|
5369
|
+
sequence: opts.monitorEvent.sequence,
|
|
5370
|
+
text,
|
|
5371
|
+
});
|
|
5372
|
+
const deliveryText = framedMonitorEvent ?? text;
|
|
5362
5373
|
const dropboxMessage = {
|
|
5363
5374
|
at,
|
|
5364
5375
|
message_id: messageId,
|
|
5365
5376
|
text,
|
|
5366
5377
|
project_id: projectId,
|
|
5367
5378
|
story_id: storyId,
|
|
5379
|
+
...(opts.monitorEvent === undefined ? {} : {
|
|
5380
|
+
kind: "monitor_event",
|
|
5381
|
+
monitor_id: opts.monitorEvent.monitor_id,
|
|
5382
|
+
description: opts.monitorEvent.description,
|
|
5383
|
+
sequence: opts.monitorEvent.sequence,
|
|
5384
|
+
}),
|
|
5368
5385
|
};
|
|
5369
5386
|
let resumed = null;
|
|
5370
5387
|
let move = null;
|
|
@@ -5377,7 +5394,13 @@ async function runMessage(ctx, laneId, opts) {
|
|
|
5377
5394
|
cliModel: opts.model?.trim() || undefined,
|
|
5378
5395
|
...(resumeProfile !== undefined ? { workerProfile: resumeProfile } : {}),
|
|
5379
5396
|
...(resumeEffort !== undefined ? { effort: resumeEffort } : {}),
|
|
5380
|
-
pending: {
|
|
5397
|
+
pending: {
|
|
5398
|
+
trigger: "message",
|
|
5399
|
+
text: deliveryText,
|
|
5400
|
+
...(opts.monitorEvent === undefined ? {} : { monitor_event: true }),
|
|
5401
|
+
message_id: messageId,
|
|
5402
|
+
compact: opts.compact !== false,
|
|
5403
|
+
},
|
|
5381
5404
|
});
|
|
5382
5405
|
lane = move.lane;
|
|
5383
5406
|
if (move.queued) {
|
|
@@ -5395,7 +5418,8 @@ async function runMessage(ctx, laneId, opts) {
|
|
|
5395
5418
|
...(resumeEffort !== undefined ? { effort: resumeEffort } : {}),
|
|
5396
5419
|
pending: {
|
|
5397
5420
|
trigger: "message",
|
|
5398
|
-
text,
|
|
5421
|
+
text: deliveryText,
|
|
5422
|
+
...(opts.monitorEvent === undefined ? {} : { monitor_event: true }),
|
|
5399
5423
|
message_id: messageId,
|
|
5400
5424
|
compact: opts.compact !== false,
|
|
5401
5425
|
},
|
|
@@ -5423,81 +5447,94 @@ async function runMessage(ctx, laneId, opts) {
|
|
|
5423
5447
|
if (move?.queued) {
|
|
5424
5448
|
// Parked at the target's cap: reconcile resumes the session there.
|
|
5425
5449
|
}
|
|
5426
|
-
else if (mechanism === "dropbox") {
|
|
5427
|
-
// Live (or about-to-be-live) process: the PreToolUse drain delivers it.
|
|
5428
|
-
if (!laneAcceptsOperatorMessage(lane)) {
|
|
5429
|
-
throw new LanesError("lane_not_accepting_messages", operatorMessageRefusalReason(lane.state), { lane_id: laneId, state: lane.state });
|
|
5430
|
-
}
|
|
5431
|
-
appendDropboxMessage(hqRoot, laneId, dropboxMessage);
|
|
5432
|
-
}
|
|
5433
5450
|
else {
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5451
|
+
const dispatched = await dispatchLaneDelivery(lane, {
|
|
5452
|
+
dropbox: () => {
|
|
5453
|
+
// Live (or about-to-be-live) process: the PreToolUse drain delivers it.
|
|
5454
|
+
if (!laneAcceptsOperatorMessage(lane)) {
|
|
5455
|
+
throw new LanesError("lane_not_accepting_messages", operatorMessageRefusalReason(lane.state), { lane_id: laneId, state: lane.state });
|
|
5456
|
+
}
|
|
5457
|
+
appendDropboxMessage(hqRoot, laneId, dropboxMessage);
|
|
5458
|
+
return null;
|
|
5459
|
+
},
|
|
5460
|
+
resume: async () => {
|
|
5461
|
+
// Exited worker with a recorded session: queue the message when capacity
|
|
5462
|
+
// is occupied, otherwise start its next turn under the shared admission lock.
|
|
5463
|
+
assertLaneRunsHereForAdmission(ctx, lane);
|
|
5464
|
+
return withLaneAdmissionLock(hqRoot, lane.provider, async () => {
|
|
5465
|
+
const admission = await assessLaneAdmission(ctx, lane, { queueAt: at });
|
|
5466
|
+
if (admission.action === "refuse" && admission.error)
|
|
5467
|
+
throw admission.error;
|
|
5468
|
+
return withResumeHireAdmission(ctx, lane, () => {
|
|
5469
|
+
if (admission.action === "queue") {
|
|
5470
|
+
const sessionId = lane.provider_session_id;
|
|
5471
|
+
if (!sessionId) {
|
|
5472
|
+
throw new LanesError("no_provider_session", `Lane ${laneId} has no provider session id to queue this message resume`, {
|
|
5473
|
+
lane_id: laneId,
|
|
5474
|
+
provider: lane.provider,
|
|
5475
|
+
});
|
|
5476
|
+
}
|
|
5477
|
+
archiveResumeMessage(hqRoot, laneId, dropboxMessage);
|
|
5478
|
+
queuedOnAdmission = true;
|
|
5479
|
+
return casUpdateLane(hqRoot, laneId, (current) => {
|
|
5480
|
+
if (current.version !== lane.version || current.state !== lane.state) {
|
|
5481
|
+
throw new LanesError("lane_admission_conflict", `Lane ${laneId} changed while message admission was checked`, {
|
|
5482
|
+
lane_id: laneId,
|
|
5483
|
+
prepared_version: lane.version,
|
|
5484
|
+
version: current.version,
|
|
5485
|
+
state: current.state,
|
|
5486
|
+
});
|
|
5487
|
+
}
|
|
5488
|
+
return {
|
|
5489
|
+
...current,
|
|
5490
|
+
state: "queued",
|
|
5491
|
+
queued_reason: admission.reason ?? "throttle",
|
|
5492
|
+
queued_at: at,
|
|
5493
|
+
pending_resume: {
|
|
5494
|
+
session_id: sessionId,
|
|
5495
|
+
trigger: "message",
|
|
5496
|
+
text: deliveryText,
|
|
5497
|
+
...(opts.monitorEvent === undefined ? {} : { monitor_event: true }),
|
|
5498
|
+
message_id: messageId,
|
|
5499
|
+
compact: opts.compact !== false,
|
|
5500
|
+
at,
|
|
5501
|
+
},
|
|
5502
|
+
};
|
|
5459
5503
|
});
|
|
5460
5504
|
}
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5505
|
+
const started = spawnLaneWorker(hqRoot, lane, {
|
|
5506
|
+
env: ctx.env,
|
|
5507
|
+
modelDeps: {
|
|
5508
|
+
readFileSync: ctx.readFileSync,
|
|
5509
|
+
probe: ctx.probeProvider,
|
|
5510
|
+
env: ctx.env,
|
|
5511
|
+
},
|
|
5512
|
+
existsSync: ctx.existsSync,
|
|
5513
|
+
spawnProcess: ctx.spawnProcess,
|
|
5514
|
+
proveDetached: ctx.proveDetached,
|
|
5515
|
+
killProcess: ctx.killProcess,
|
|
5516
|
+
now: ctx.now,
|
|
5517
|
+
resolveMachineIdentity: ctx.resolveMachineIdentity,
|
|
5518
|
+
runCompaction: ctx.runCompaction,
|
|
5519
|
+
locateTranscript: ctx.locateTranscript,
|
|
5520
|
+
}, {
|
|
5521
|
+
trigger: {
|
|
5522
|
+
kind: "message",
|
|
5523
|
+
text: deliveryText,
|
|
5470
5524
|
message_id: messageId,
|
|
5471
|
-
|
|
5472
|
-
at,
|
|
5525
|
+
...(opts.monitorEvent === undefined ? {} : { monitor_event: true }),
|
|
5473
5526
|
},
|
|
5474
|
-
|
|
5527
|
+
compact: opts.compact !== false,
|
|
5528
|
+
effort: resumeEffort ?? recordedResumeEffort(lane),
|
|
5529
|
+
});
|
|
5530
|
+
archiveResumeMessage(hqRoot, laneId, dropboxMessage);
|
|
5531
|
+
return started;
|
|
5475
5532
|
});
|
|
5476
|
-
}
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
probe: ctx.probeProvider,
|
|
5482
|
-
env: ctx.env,
|
|
5483
|
-
},
|
|
5484
|
-
existsSync: ctx.existsSync,
|
|
5485
|
-
spawnProcess: ctx.spawnProcess,
|
|
5486
|
-
proveDetached: ctx.proveDetached,
|
|
5487
|
-
killProcess: ctx.killProcess,
|
|
5488
|
-
now: ctx.now,
|
|
5489
|
-
resolveMachineIdentity: ctx.resolveMachineIdentity,
|
|
5490
|
-
runCompaction: ctx.runCompaction,
|
|
5491
|
-
locateTranscript: ctx.locateTranscript,
|
|
5492
|
-
}, {
|
|
5493
|
-
trigger: { kind: "message", text, message_id: messageId },
|
|
5494
|
-
compact: opts.compact !== false,
|
|
5495
|
-
effort: resumeEffort ?? recordedResumeEffort(lane),
|
|
5496
|
-
});
|
|
5497
|
-
archiveResumeMessage(hqRoot, laneId, dropboxMessage);
|
|
5498
|
-
return started;
|
|
5499
|
-
});
|
|
5500
|
-
}, ctx.sleep);
|
|
5533
|
+
}, ctx.sleep);
|
|
5534
|
+
},
|
|
5535
|
+
}, mechanism);
|
|
5536
|
+
if (dispatched.mechanism === "resume")
|
|
5537
|
+
resumed = dispatched.value;
|
|
5501
5538
|
}
|
|
5502
5539
|
// Every accepted message moves the compaction reference forward.
|
|
5503
5540
|
let next = casUpdateLane(hqRoot, laneId, (current) => ({
|
|
@@ -5736,8 +5773,6 @@ async function runClaudeBalanceMoveTarget(ctx, laneId, opts) {
|
|
|
5736
5773
|
});
|
|
5737
5774
|
}
|
|
5738
5775
|
function laneWithRecoveredProviderSession(hqRoot, lane) {
|
|
5739
|
-
if (lane.provider === "grok")
|
|
5740
|
-
return lane;
|
|
5741
5776
|
const manifest = readSpawnManifest(laneRunDir(hqRoot, lane.lane_id));
|
|
5742
5777
|
const sessionId = (typeof lane.provider_session_id === "string" && lane.provider_session_id.trim()
|
|
5743
5778
|
? lane.provider_session_id
|
|
@@ -5795,8 +5830,8 @@ async function runResume(ctx, laneId, opts) {
|
|
|
5795
5830
|
state: lane.state,
|
|
5796
5831
|
});
|
|
5797
5832
|
}
|
|
5798
|
-
if (opts.account !== undefined && !
|
|
5799
|
-
throw new LanesError("provider_session_not_portable",
|
|
5833
|
+
if (opts.account !== undefined && !providerSessionPortable(lane.provider)) {
|
|
5834
|
+
throw new LanesError("provider_session_not_portable", sessionNotPortableMessage(lane.provider), { lane_id: laneId, provider: lane.provider });
|
|
5800
5835
|
}
|
|
5801
5836
|
if (lane.state === "queued") {
|
|
5802
5837
|
throw new LanesError("lane_not_resumable", `Lane ${laneId} is queued; use hq lanes admit ${laneId} to request admission`, { lane_id: laneId, state: lane.state, admission_command: `hq lanes admit ${laneId}` });
|
|
@@ -8304,6 +8339,38 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
8304
8339
|
.action(wrap(async (laneId, opts) => {
|
|
8305
8340
|
await runMessage(ctx, laneId, opts);
|
|
8306
8341
|
}));
|
|
8342
|
+
lanes
|
|
8343
|
+
.command("_monitor-message", { hidden: true })
|
|
8344
|
+
.argument("<lane-id>", "Lane id")
|
|
8345
|
+
.action(wrap(async (laneId) => {
|
|
8346
|
+
const input = ctx.readStdin();
|
|
8347
|
+
let payload;
|
|
8348
|
+
try {
|
|
8349
|
+
payload = JSON.parse(input);
|
|
8350
|
+
}
|
|
8351
|
+
catch (err) {
|
|
8352
|
+
throw new LanesError("monitor_lane_payload_invalid", `Monitor lane delivery payload is invalid JSON: ${err instanceof Error ? err.message : String(err)}.`, {});
|
|
8353
|
+
}
|
|
8354
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
8355
|
+
throw new LanesError("monitor_lane_payload_invalid", "Monitor lane delivery payload must be an object.", {});
|
|
8356
|
+
}
|
|
8357
|
+
const value = payload;
|
|
8358
|
+
if (typeof value.text !== "string" ||
|
|
8359
|
+
typeof value.monitor_id !== "string" ||
|
|
8360
|
+
typeof value.description !== "string" ||
|
|
8361
|
+
!Number.isInteger(value.sequence) ||
|
|
8362
|
+
Number(value.sequence) < 1) {
|
|
8363
|
+
throw new LanesError("monitor_lane_payload_invalid", "Monitor lane delivery payload is missing text, monitor metadata, or sequence.", {});
|
|
8364
|
+
}
|
|
8365
|
+
await runMessage(ctx, laneId, {
|
|
8366
|
+
text: value.text,
|
|
8367
|
+
monitorEvent: {
|
|
8368
|
+
monitor_id: value.monitor_id,
|
|
8369
|
+
description: value.description,
|
|
8370
|
+
sequence: Number(value.sequence),
|
|
8371
|
+
},
|
|
8372
|
+
});
|
|
8373
|
+
}));
|
|
8307
8374
|
lanes
|
|
8308
8375
|
.command("resume")
|
|
8309
8376
|
.description("Resume an interrupted, done or blocked lane on its recorded provider session")
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { drainDropboxAtPath } from "../lib/lanes/dropbox.js";
|
|
4
|
+
import { recordMonitorTargetActivity, type MonitorMetadata, type MonitorState, type MonitorTarget, type MonitorProcessEntry, type MonitorRuntimeIdentity } from "../lib/monitor.js";
|
|
5
|
+
import type { LaneCompanyRef, LaneProvider } from "../lib/lanes/types.js";
|
|
6
|
+
export declare function findSessionOwner(target: MonitorTarget, deps?: {
|
|
7
|
+
env?: NodeJS.ProcessEnv;
|
|
8
|
+
parentPid?: number;
|
|
9
|
+
readProcess?: (pid: number) => MonitorProcessEntry | null;
|
|
10
|
+
readStarttime?: (pid: number) => number | null;
|
|
11
|
+
}): {
|
|
12
|
+
pid: number;
|
|
13
|
+
starttime: number | null;
|
|
14
|
+
} | null;
|
|
15
|
+
export declare function sessionOwnerTarget(discovered: MonitorTarget, resolved: MonitorTarget): MonitorTarget;
|
|
16
|
+
declare function monitorEnabled(company?: LaneCompanyRef | null): Promise<boolean>;
|
|
17
|
+
export declare function runMonitorEnabledCommand(deps?: {
|
|
18
|
+
readFlag?: (company: LaneCompanyRef | null) => Promise<boolean>;
|
|
19
|
+
writeOut?: (text: string) => void;
|
|
20
|
+
writeError?: (text: string) => void;
|
|
21
|
+
}): Promise<number>;
|
|
22
|
+
export declare function armText(meta: MonitorMetadata): string;
|
|
23
|
+
export declare function resolveMonitorStartTarget(hqRoot: string, discovered: MonitorTarget, explicitlyProvided: boolean, runtime?: MonitorRuntimeIdentity): MonitorTarget;
|
|
24
|
+
export declare function deliverNormalEvent(hqRoot: string, meta: MonitorMetadata, state: MonitorState, rawText: string): Promise<MonitorState>;
|
|
25
|
+
export interface RunSupervisorDeps {
|
|
26
|
+
resolveRoot?: () => string;
|
|
27
|
+
monitorEnabled?: typeof monitorEnabled;
|
|
28
|
+
deliver?: typeof deliverNormalEvent;
|
|
29
|
+
spawn?: typeof spawn;
|
|
30
|
+
}
|
|
31
|
+
export declare function runSupervisor(id: string, deps?: RunSupervisorDeps): Promise<void>;
|
|
32
|
+
interface MonitorHookResult {
|
|
33
|
+
stdout: string;
|
|
34
|
+
exitCode: 0 | 2;
|
|
35
|
+
}
|
|
36
|
+
export interface WaitForSessionDeps {
|
|
37
|
+
monitorEnabled?: () => Promise<boolean>;
|
|
38
|
+
resolveRoot?: () => string;
|
|
39
|
+
readStdin?: () => Promise<string>;
|
|
40
|
+
recordActivity?: typeof recordMonitorTargetActivity;
|
|
41
|
+
drainDropbox?: typeof drainDropboxAtPath;
|
|
42
|
+
sleep?: (milliseconds: number) => Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
export declare function runMonitorHookSafely(kind: "drain" | "wait", operation: () => Promise<MonitorHookResult>, writeError?: (text: string) => void): Promise<MonitorHookResult>;
|
|
45
|
+
export interface DrainSessionDeps {
|
|
46
|
+
monitorEnabled?: () => Promise<boolean>;
|
|
47
|
+
resolveRoot?: () => string;
|
|
48
|
+
readStdin?: () => Promise<string>;
|
|
49
|
+
sessionEnvironmentId?: (provider: LaneProvider) => string | undefined;
|
|
50
|
+
nearestRuntimeIdentity?: () => MonitorRuntimeIdentity | undefined;
|
|
51
|
+
recordActivity?: typeof recordMonitorTargetActivity;
|
|
52
|
+
drainDropbox?: typeof drainDropboxAtPath;
|
|
53
|
+
}
|
|
54
|
+
export declare function drainSession(provider: LaneProvider, event: "PreToolUse" | "UserPromptSubmit", deps?: DrainSessionDeps): Promise<MonitorHookResult>;
|
|
55
|
+
export declare function waitForSession(provider: LaneProvider, deps?: WaitForSessionDeps): Promise<MonitorHookResult>;
|
|
56
|
+
export declare function registerMonitorCommand(parent: Command): Command;
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=monitor.d.ts.map
|