@openscout/scout 0.2.68 → 0.2.69
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/bin/openscout-runtime.mjs +11 -0
- package/dist/client/assets/addon-fit-DtSNdpy5.js +1 -0
- package/dist/client/assets/addon-webgl-YYNKPQUg.js +82 -0
- package/dist/client/assets/index-5-XOQrKH.js +186 -0
- package/dist/client/assets/index-BnA2HAbt.css +1 -0
- package/dist/client/assets/xterm-fBtFsYpq.js +34 -0
- package/dist/client/index.html +3 -3
- package/dist/main.mjs +2097 -504
- package/dist/openscout-terminal-relay.mjs +678 -0
- package/dist/pair-supervisor.mjs +1728 -183
- package/dist/runtime/base-daemon.mjs +19 -0
- package/dist/runtime/broker-daemon.mjs +2502 -382
- package/dist/runtime/broker-process-manager.mjs +11 -0
- package/dist/runtime/mesh-discover.mjs +11 -0
- package/dist/scout-control-plane-web.mjs +3220 -480
- package/dist/scout-web-server.mjs +3220 -480
- package/package.json +4 -2
- package/dist/client/assets/addon-fit_hudsonkit_false-DSvcGNZx.js +0 -1
- package/dist/client/assets/addon-webgl_hudsonkit_false-1rrLEmjL.js +0 -1
- package/dist/client/assets/index-R2y6GOWl.js +0 -184
- package/dist/client/assets/index-bOmc2x1_.css +0 -1
- package/dist/client/assets/xterm_hudsonkit_false-B2TbElXJ.js +0 -1
|
@@ -15491,7 +15491,13 @@ import { execFile } from "child_process";
|
|
|
15491
15491
|
import { promisify } from "util";
|
|
15492
15492
|
var execFileAsync = promisify(execFile);
|
|
15493
15493
|
var PARENT_HOP_LIMIT = 10;
|
|
15494
|
-
|
|
15494
|
+
var PROCESS_LIST_CACHE_MS = readNonNegativeIntEnv("OPENSCOUT_TAIL_PROCESS_CACHE_MS", 1000);
|
|
15495
|
+
var processListCache = null;
|
|
15496
|
+
function readNonNegativeIntEnv(name, fallback) {
|
|
15497
|
+
const raw = Number.parseInt(process.env[name] ?? "", 10);
|
|
15498
|
+
return Number.isFinite(raw) && raw >= 0 ? raw : fallback;
|
|
15499
|
+
}
|
|
15500
|
+
async function readProcessListUncached() {
|
|
15495
15501
|
const { stdout } = await execFileAsync("ps", ["-axww", "-o", "pid=,ppid=,etime=,command="], {
|
|
15496
15502
|
maxBuffer: 32 * 1024 * 1024
|
|
15497
15503
|
});
|
|
@@ -15513,6 +15519,24 @@ async function listProcesses() {
|
|
|
15513
15519
|
}
|
|
15514
15520
|
return out;
|
|
15515
15521
|
}
|
|
15522
|
+
async function listProcesses() {
|
|
15523
|
+
const now = Date.now();
|
|
15524
|
+
if (processListCache && now < processListCache.expiresAt) {
|
|
15525
|
+
return processListCache.promise;
|
|
15526
|
+
}
|
|
15527
|
+
let promise2 = readProcessListUncached();
|
|
15528
|
+
promise2 = promise2.catch((error48) => {
|
|
15529
|
+
if (processListCache?.promise === promise2) {
|
|
15530
|
+
processListCache = null;
|
|
15531
|
+
}
|
|
15532
|
+
throw error48;
|
|
15533
|
+
});
|
|
15534
|
+
processListCache = {
|
|
15535
|
+
expiresAt: now + PROCESS_LIST_CACHE_MS,
|
|
15536
|
+
promise: promise2
|
|
15537
|
+
};
|
|
15538
|
+
return promise2;
|
|
15539
|
+
}
|
|
15516
15540
|
function commandBasename(command) {
|
|
15517
15541
|
const firstToken = command.split(/\s+/)[0] ?? "";
|
|
15518
15542
|
const slashIdx = firstToken.lastIndexOf("/");
|
|
@@ -15608,6 +15632,19 @@ var DEFAULT_HOT_DISCOVERY_LIMIT = 64;
|
|
|
15608
15632
|
var DEFAULT_SHALLOW_DISCOVERY_LIMIT = 160;
|
|
15609
15633
|
var DEFAULT_DEEP_DISCOVERY_LIMIT = 160;
|
|
15610
15634
|
var HEAD_READ_BYTES = 256 * 1024;
|
|
15635
|
+
var METADATA_CACHE_LIMIT = 512;
|
|
15636
|
+
var metadataCache = new Map;
|
|
15637
|
+
function rememberMetadata(file2, metadata) {
|
|
15638
|
+
metadataCache.delete(file2.path);
|
|
15639
|
+
metadataCache.set(file2.path, { ...file2, ...metadata });
|
|
15640
|
+
while (metadataCache.size > METADATA_CACHE_LIMIT) {
|
|
15641
|
+
const oldest = metadataCache.keys().next().value;
|
|
15642
|
+
if (!oldest)
|
|
15643
|
+
break;
|
|
15644
|
+
metadataCache.delete(oldest);
|
|
15645
|
+
}
|
|
15646
|
+
return metadata;
|
|
15647
|
+
}
|
|
15611
15648
|
function projectsRoot() {
|
|
15612
15649
|
return process.env.OPENSCOUT_TAIL_CLAUDE_PROJECTS_ROOT ?? join(homedir(), ".claude", "projects");
|
|
15613
15650
|
}
|
|
@@ -15654,8 +15691,12 @@ function parseJsonRecord(line) {
|
|
|
15654
15691
|
return null;
|
|
15655
15692
|
}
|
|
15656
15693
|
}
|
|
15657
|
-
function readClaudeMetadata(
|
|
15658
|
-
const
|
|
15694
|
+
function readClaudeMetadata(file2) {
|
|
15695
|
+
const cached2 = metadataCache.get(file2.path);
|
|
15696
|
+
if (cached2 && cached2.mtimeMs === file2.mtimeMs && cached2.size === file2.size) {
|
|
15697
|
+
return { cwd: cached2.cwd, sessionId: cached2.sessionId };
|
|
15698
|
+
}
|
|
15699
|
+
const head = readFileHead(file2.path);
|
|
15659
15700
|
let cwd = null;
|
|
15660
15701
|
let sessionId = null;
|
|
15661
15702
|
for (const line of head.split(/\r?\n/)) {
|
|
@@ -15665,10 +15706,10 @@ function readClaudeMetadata(filePath) {
|
|
|
15665
15706
|
cwd ??= typeof record2.cwd === "string" && record2.cwd.trim() ? record2.cwd : null;
|
|
15666
15707
|
sessionId ??= typeof record2.sessionId === "string" && record2.sessionId.trim() ? record2.sessionId : typeof record2.session_id === "string" && record2.session_id.trim() ? record2.session_id : null;
|
|
15667
15708
|
if (cwd && sessionId) {
|
|
15668
|
-
return { cwd, sessionId };
|
|
15709
|
+
return rememberMetadata(file2, { cwd, sessionId });
|
|
15669
15710
|
}
|
|
15670
15711
|
}
|
|
15671
|
-
return { cwd, sessionId };
|
|
15712
|
+
return rememberMetadata(file2, { cwd, sessionId });
|
|
15672
15713
|
}
|
|
15673
15714
|
function decodeProjectDir(dirName) {
|
|
15674
15715
|
if (!dirName.startsWith("-"))
|
|
@@ -15875,7 +15916,7 @@ var ClaudeSource = {
|
|
|
15875
15916
|
if (!existsSync(root))
|
|
15876
15917
|
return [];
|
|
15877
15918
|
return walkRecentJsonlFiles(root, scope).map((file2) => {
|
|
15878
|
-
const meta3 = readClaudeMetadata(file2
|
|
15919
|
+
const meta3 = readClaudeMetadata(file2);
|
|
15879
15920
|
const cwd = meta3.cwd ?? fallbackCwdForPath(file2.path);
|
|
15880
15921
|
const sessionId = meta3.sessionId ?? basename(file2.path).replace(/\.jsonl$/, "");
|
|
15881
15922
|
return {
|
|
@@ -15908,6 +15949,19 @@ var DEFAULT_HOT_DISCOVERY_LIMIT2 = 64;
|
|
|
15908
15949
|
var DEFAULT_SHALLOW_DISCOVERY_LIMIT2 = 160;
|
|
15909
15950
|
var DEFAULT_DEEP_DISCOVERY_LIMIT2 = 160;
|
|
15910
15951
|
var HEAD_READ_BYTES2 = 512 * 1024;
|
|
15952
|
+
var METADATA_CACHE_LIMIT2 = 512;
|
|
15953
|
+
var metadataCache2 = new Map;
|
|
15954
|
+
function rememberMetadata2(file2, metadata) {
|
|
15955
|
+
metadataCache2.delete(file2.path);
|
|
15956
|
+
metadataCache2.set(file2.path, { ...file2, ...metadata });
|
|
15957
|
+
while (metadataCache2.size > METADATA_CACHE_LIMIT2) {
|
|
15958
|
+
const oldest = metadataCache2.keys().next().value;
|
|
15959
|
+
if (!oldest)
|
|
15960
|
+
break;
|
|
15961
|
+
metadataCache2.delete(oldest);
|
|
15962
|
+
}
|
|
15963
|
+
return metadata;
|
|
15964
|
+
}
|
|
15911
15965
|
function readPositiveIntEnv2(names, fallback) {
|
|
15912
15966
|
for (const name of names) {
|
|
15913
15967
|
const raw = Number.parseInt(process.env[name] ?? "", 10);
|
|
@@ -15991,8 +16045,12 @@ function parseJsonRecord2(line) {
|
|
|
15991
16045
|
function metadataRecord(value) {
|
|
15992
16046
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
15993
16047
|
}
|
|
15994
|
-
function readCodexMetadata(
|
|
15995
|
-
const
|
|
16048
|
+
function readCodexMetadata(file2) {
|
|
16049
|
+
const cached2 = metadataCache2.get(file2.path);
|
|
16050
|
+
if (cached2 && cached2.mtimeMs === file2.mtimeMs && cached2.size === file2.size) {
|
|
16051
|
+
return { cwd: cached2.cwd, sessionId: cached2.sessionId };
|
|
16052
|
+
}
|
|
16053
|
+
const head = readFileHead2(file2.path);
|
|
15996
16054
|
let cwd = null;
|
|
15997
16055
|
let sessionId = null;
|
|
15998
16056
|
for (const line of head.split(/\r?\n/)) {
|
|
@@ -16006,12 +16064,13 @@ function readCodexMetadata(filePath) {
|
|
|
16006
16064
|
cwd ??= typeof payload.cwd === "string" && payload.cwd.trim() ? payload.cwd : null;
|
|
16007
16065
|
sessionId ??= typeof payload.id === "string" && payload.id.trim() ? payload.id : null;
|
|
16008
16066
|
if (cwd || sessionId) {
|
|
16009
|
-
if (cwd && sessionId)
|
|
16010
|
-
return { cwd, sessionId };
|
|
16067
|
+
if (cwd && sessionId) {
|
|
16068
|
+
return rememberMetadata2(file2, { cwd, sessionId });
|
|
16069
|
+
}
|
|
16011
16070
|
}
|
|
16012
16071
|
}
|
|
16013
16072
|
}
|
|
16014
|
-
return { cwd, sessionId };
|
|
16073
|
+
return rememberMetadata2(file2, { cwd, sessionId });
|
|
16015
16074
|
}
|
|
16016
16075
|
function walkRecentJsonlFiles2(root, scope) {
|
|
16017
16076
|
const cutoff = Date.now() - discoveryWindowMs2(scope);
|
|
@@ -16054,7 +16113,7 @@ function discoverCodexTranscripts(scope) {
|
|
|
16054
16113
|
}
|
|
16055
16114
|
}
|
|
16056
16115
|
return [...byPath.values()].sort((a, b) => b.mtimeMs - a.mtimeMs).slice(0, discoveryLimit2(scope)).map((file2) => {
|
|
16057
|
-
const meta3 = readCodexMetadata(file2
|
|
16116
|
+
const meta3 = readCodexMetadata(file2);
|
|
16058
16117
|
const sessionId = meta3.sessionId ?? sessionIdFromCodexPath(file2.path);
|
|
16059
16118
|
return {
|
|
16060
16119
|
source: SOURCE_NAME2,
|
|
@@ -16261,6 +16320,7 @@ var RAW_MAX_STRING_LEN = 1000;
|
|
|
16261
16320
|
var RAW_MAX_ARRAY_ITEMS = 25;
|
|
16262
16321
|
var RAW_MAX_OBJECT_KEYS = 50;
|
|
16263
16322
|
var RECENT_TRANSCRIPT_READ_BYTES = 512 * 1024;
|
|
16323
|
+
var RECENT_TRANSCRIPT_MAX_FILES = readPositiveIntEnv3("OPENSCOUT_TAIL_RECENT_TRANSCRIPT_MAX_FILES", 24);
|
|
16264
16324
|
var sources = [ClaudeSource, CodexSource];
|
|
16265
16325
|
var watchers = new Map;
|
|
16266
16326
|
var aggregateBuffer = [];
|
|
@@ -16397,26 +16457,27 @@ function pushEvent(rawEvent) {
|
|
|
16397
16457
|
} catch {}
|
|
16398
16458
|
}
|
|
16399
16459
|
}
|
|
16400
|
-
async function readNew(handle, fromOffset) {
|
|
16401
|
-
|
|
16402
|
-
if (stats.size <= fromOffset) {
|
|
16460
|
+
async function readNew(handle, fromOffset, fileSize) {
|
|
16461
|
+
if (fileSize <= fromOffset) {
|
|
16403
16462
|
return { text: "", nextOffset: fromOffset };
|
|
16404
16463
|
}
|
|
16405
|
-
const length =
|
|
16464
|
+
const length = fileSize - fromOffset;
|
|
16406
16465
|
const buffer = Buffer.alloc(length);
|
|
16407
16466
|
await handle.read(buffer, 0, length, fromOffset);
|
|
16408
|
-
return { text: buffer.toString("utf8"), nextOffset:
|
|
16467
|
+
return { text: buffer.toString("utf8"), nextOffset: fileSize };
|
|
16409
16468
|
}
|
|
16410
16469
|
async function pumpWatcher(watcher) {
|
|
16411
16470
|
let handle = null;
|
|
16412
16471
|
try {
|
|
16413
|
-
|
|
16414
|
-
const stats = await handle.stat();
|
|
16472
|
+
const stats = await stat(watcher.transcriptPath);
|
|
16415
16473
|
if (stats.size < watcher.offset) {
|
|
16416
16474
|
watcher.offset = 0;
|
|
16417
16475
|
watcher.carry = "";
|
|
16418
16476
|
}
|
|
16419
|
-
|
|
16477
|
+
if (stats.size <= watcher.offset)
|
|
16478
|
+
return;
|
|
16479
|
+
handle = await open(watcher.transcriptPath, "r");
|
|
16480
|
+
const { text, nextOffset } = await readNew(handle, watcher.offset, stats.size);
|
|
16420
16481
|
watcher.offset = nextOffset;
|
|
16421
16482
|
if (!text)
|
|
16422
16483
|
return;
|
|
@@ -18633,6 +18694,276 @@ function assertValidUnblockRequestEvent(event, record2) {
|
|
|
18633
18694
|
throw new Error(errors3.join("; "));
|
|
18634
18695
|
}
|
|
18635
18696
|
}
|
|
18697
|
+
// packages/protocol/src/lifecycle.ts
|
|
18698
|
+
var TERMINAL_INVOCATION_STATES = new Set([
|
|
18699
|
+
"completed",
|
|
18700
|
+
"failed",
|
|
18701
|
+
"cancelled",
|
|
18702
|
+
"expired"
|
|
18703
|
+
]);
|
|
18704
|
+
var MAX_TERMINAL_SUMMARY_LENGTH = 256;
|
|
18705
|
+
function projectInvocationLifecycle(input) {
|
|
18706
|
+
const deliveries = (input.deliveries ?? []).map((delivery) => projectOutcomeDelivery(delivery, input.deliveryAttempts?.[delivery.id] ?? []));
|
|
18707
|
+
const peerDelivery = deliveries.find((delivery) => delivery.state === "dispatched_to_peer");
|
|
18708
|
+
const expiresAt = input.expiresAt ?? expiresAtForInvocation(input.invocation);
|
|
18709
|
+
const state = projectInvocationState({
|
|
18710
|
+
invocation: input.invocation,
|
|
18711
|
+
flight: input.flight,
|
|
18712
|
+
deliveries,
|
|
18713
|
+
now: input.now,
|
|
18714
|
+
expiresAt
|
|
18715
|
+
});
|
|
18716
|
+
const terminal = projectTerminalResult({
|
|
18717
|
+
state,
|
|
18718
|
+
flight: input.flight,
|
|
18719
|
+
now: input.now
|
|
18720
|
+
});
|
|
18721
|
+
const lifecycle = {
|
|
18722
|
+
invocationId: input.invocation.id,
|
|
18723
|
+
state
|
|
18724
|
+
};
|
|
18725
|
+
addOptional(lifecycle, "flightId", input.flight?.id);
|
|
18726
|
+
addOptional(lifecycle, "targetAgentId", input.flight?.targetAgentId ?? input.invocation.targetAgentId);
|
|
18727
|
+
addOptional(lifecycle, "targetEndpointId", stringMetadata(input.flight?.metadata, "targetEndpointId"));
|
|
18728
|
+
addOptional(lifecycle, "peerNodeId", peerDelivery?.peerNodeId ?? input.invocation.targetNodeId);
|
|
18729
|
+
addOptional(lifecycle, "peerFlightId", peerDelivery?.peerFlightId);
|
|
18730
|
+
addOptional(lifecycle, "workId", inferWorkId(input.invocation));
|
|
18731
|
+
addOptional(lifecycle, "actionId", stringMetadata(input.invocation.metadata, "actionId"));
|
|
18732
|
+
addOptional(lifecycle, "idempotencyKey", stringMetadata(input.invocation.metadata, "idempotencyKey"));
|
|
18733
|
+
addOptional(lifecycle, "acknowledgedAt", dispatchAcknowledgedAt(input.flight?.metadata) ?? peerDelivery?.deliveredAt);
|
|
18734
|
+
addOptional(lifecycle, "startedAt", input.flight?.startedAt);
|
|
18735
|
+
addOptional(lifecycle, "completedAt", input.flight?.completedAt ?? terminal?.completedAt);
|
|
18736
|
+
addOptional(lifecycle, "expiresAt", expiresAt);
|
|
18737
|
+
addOptional(lifecycle, "lastProgressAt", lastProgressAt(input.flight, deliveries));
|
|
18738
|
+
addOptional(lifecycle, "waitingOn", input.waitingOn ?? waitingOnFromMetadata(input.flight?.metadata));
|
|
18739
|
+
addOptional(lifecycle, "terminal", terminal);
|
|
18740
|
+
addOptional(lifecycle, "deliveries", deliveries.length > 0 ? deliveries : undefined);
|
|
18741
|
+
addOptional(lifecycle, "metadata", lifecycleMetadata(input.invocation, input.flight));
|
|
18742
|
+
return lifecycle;
|
|
18743
|
+
}
|
|
18744
|
+
function projectInvocationState(input) {
|
|
18745
|
+
const flightState = input.flight?.state;
|
|
18746
|
+
if (flightState === "completed" || flightState === "failed" || flightState === "cancelled") {
|
|
18747
|
+
return flightState;
|
|
18748
|
+
}
|
|
18749
|
+
if (input.expiresAt !== undefined && input.now !== undefined && input.expiresAt <= input.now) {
|
|
18750
|
+
return "expired";
|
|
18751
|
+
}
|
|
18752
|
+
if (input.deliveries?.some((delivery) => delivery.state === "dispatched_to_peer")) {
|
|
18753
|
+
return "acknowledged";
|
|
18754
|
+
}
|
|
18755
|
+
if (flightState === "waiting") {
|
|
18756
|
+
return "waiting";
|
|
18757
|
+
}
|
|
18758
|
+
if (flightState === "running") {
|
|
18759
|
+
return "working";
|
|
18760
|
+
}
|
|
18761
|
+
if (flightState === "waking") {
|
|
18762
|
+
return "dispatching";
|
|
18763
|
+
}
|
|
18764
|
+
if (flightState === "queued") {
|
|
18765
|
+
return "queued";
|
|
18766
|
+
}
|
|
18767
|
+
return input.invocation.ensureAwake ? "dispatching" : "queued";
|
|
18768
|
+
}
|
|
18769
|
+
function projectOutcomeDelivery(delivery, attempts = []) {
|
|
18770
|
+
const sortedAttempts = [...attempts].sort((left, right) => left.createdAt - right.createdAt);
|
|
18771
|
+
const lastAttempt = sortedAttempts[sortedAttempts.length - 1];
|
|
18772
|
+
const latestFailedAttempt = [...sortedAttempts].reverse().find((attempt) => attempt.status === "failed");
|
|
18773
|
+
const state = projectDeliveryState(delivery);
|
|
18774
|
+
const deliveredAt = deliveredAtForDelivery(delivery, sortedAttempts);
|
|
18775
|
+
const subject = deliverySubject(delivery);
|
|
18776
|
+
const outcome = {
|
|
18777
|
+
deliveryId: delivery.id,
|
|
18778
|
+
subjectKind: subject.kind,
|
|
18779
|
+
subjectId: subject.id,
|
|
18780
|
+
transport: delivery.transport,
|
|
18781
|
+
state,
|
|
18782
|
+
attemptCount: sortedAttempts.length
|
|
18783
|
+
};
|
|
18784
|
+
addOptional(outcome, "peerNodeId", peerNodeId(delivery));
|
|
18785
|
+
addOptional(outcome, "peerFlightId", stringMetadata(delivery.metadata, "peerFlightId"));
|
|
18786
|
+
addOptional(outcome, "nextAttemptAt", numberMetadata(delivery.metadata, "nextAttemptAt"));
|
|
18787
|
+
addOptional(outcome, "lastError", deliveryError(delivery, latestFailedAttempt));
|
|
18788
|
+
addOptional(outcome, "lastAttemptAt", lastAttempt?.createdAt);
|
|
18789
|
+
addOptional(outcome, "deliveredAt", deliveredAt);
|
|
18790
|
+
addOptional(outcome, "metadata", delivery.metadata);
|
|
18791
|
+
return outcome;
|
|
18792
|
+
}
|
|
18793
|
+
function projectDeliveryState(delivery) {
|
|
18794
|
+
switch (delivery.status) {
|
|
18795
|
+
case "accepted":
|
|
18796
|
+
case "pending":
|
|
18797
|
+
return "pending";
|
|
18798
|
+
case "leased":
|
|
18799
|
+
return "leased";
|
|
18800
|
+
case "peer_acked":
|
|
18801
|
+
return "dispatched_to_peer";
|
|
18802
|
+
case "sent":
|
|
18803
|
+
case "acknowledged":
|
|
18804
|
+
case "running":
|
|
18805
|
+
case "completed":
|
|
18806
|
+
return "sent";
|
|
18807
|
+
case "deferred":
|
|
18808
|
+
return "retrying";
|
|
18809
|
+
case "failed":
|
|
18810
|
+
return "dead_lettered";
|
|
18811
|
+
case "cancelled":
|
|
18812
|
+
return isSuppressedDelivery(delivery) ? "suppressed" : "cancelled";
|
|
18813
|
+
default:
|
|
18814
|
+
return "pending";
|
|
18815
|
+
}
|
|
18816
|
+
}
|
|
18817
|
+
function isTerminalInvocationState(state) {
|
|
18818
|
+
return TERMINAL_INVOCATION_STATES.has(state);
|
|
18819
|
+
}
|
|
18820
|
+
function projectTerminalResult(input) {
|
|
18821
|
+
if (!isTerminalInvocationState(input.state)) {
|
|
18822
|
+
return;
|
|
18823
|
+
}
|
|
18824
|
+
const state = input.state;
|
|
18825
|
+
const completedAt = input.flight?.completedAt ?? input.now;
|
|
18826
|
+
if (completedAt === undefined) {
|
|
18827
|
+
return;
|
|
18828
|
+
}
|
|
18829
|
+
const terminal = {
|
|
18830
|
+
state,
|
|
18831
|
+
completedAt
|
|
18832
|
+
};
|
|
18833
|
+
addOptional(terminal, "summary", compactTerminalSummary(input.flight));
|
|
18834
|
+
addOptional(terminal, "errorClass", stringMetadata(input.flight?.metadata, "errorClass"));
|
|
18835
|
+
addOptional(terminal, "exitCode", numberMetadata(input.flight?.metadata, "exitCode"));
|
|
18836
|
+
addOptional(terminal, "sourceRecordId", input.flight?.id);
|
|
18837
|
+
addOptional(terminal, "metadata", terminalMetadata(input.flight));
|
|
18838
|
+
return terminal;
|
|
18839
|
+
}
|
|
18840
|
+
function compactTerminalSummary(flight) {
|
|
18841
|
+
const summary = flight?.state === "failed" ? flight.error ?? flight.summary : flight?.summary;
|
|
18842
|
+
if (!summary?.trim()) {
|
|
18843
|
+
return;
|
|
18844
|
+
}
|
|
18845
|
+
const compacted = summary.replace(/\s+/g, " ").trim();
|
|
18846
|
+
return compacted.length <= MAX_TERMINAL_SUMMARY_LENGTH ? compacted : `${compacted.slice(0, MAX_TERMINAL_SUMMARY_LENGTH - 3).trimEnd()}...`;
|
|
18847
|
+
}
|
|
18848
|
+
function terminalMetadata(flight) {
|
|
18849
|
+
if (!flight?.metadata) {
|
|
18850
|
+
return;
|
|
18851
|
+
}
|
|
18852
|
+
const metadata = {};
|
|
18853
|
+
addOptional(metadata, "failureStage", stringMetadata(flight.metadata, "failureStage"));
|
|
18854
|
+
addOptional(metadata, "failureReason", stringMetadata(flight.metadata, "failureReason"));
|
|
18855
|
+
addOptional(metadata, "cancelledBy", stringMetadata(flight.metadata, "cancelledBy"));
|
|
18856
|
+
addOptional(metadata, "expiredAt", numberMetadata(flight.metadata, "expiredAt"));
|
|
18857
|
+
return Object.keys(metadata).length > 0 ? metadata : undefined;
|
|
18858
|
+
}
|
|
18859
|
+
function deliverySubject(delivery) {
|
|
18860
|
+
const workId = stringMetadata(delivery.metadata, "workId") ?? stringMetadata(delivery.metadata, "collaborationRecordId");
|
|
18861
|
+
if (workId) {
|
|
18862
|
+
return { kind: "work_item", id: workId };
|
|
18863
|
+
}
|
|
18864
|
+
if (delivery.invocationId) {
|
|
18865
|
+
return { kind: "invocation", id: delivery.invocationId };
|
|
18866
|
+
}
|
|
18867
|
+
if (delivery.messageId) {
|
|
18868
|
+
return { kind: "message", id: delivery.messageId };
|
|
18869
|
+
}
|
|
18870
|
+
return { kind: "message", id: delivery.id };
|
|
18871
|
+
}
|
|
18872
|
+
function deliveredAtForDelivery(delivery, attempts) {
|
|
18873
|
+
return numberMetadata(delivery.metadata, "deliveredAt") ?? numberMetadata(delivery.metadata, "peerAckedAt") ?? lastSuccessfulAttemptAt(attempts);
|
|
18874
|
+
}
|
|
18875
|
+
function lastSuccessfulAttemptAt(attempts) {
|
|
18876
|
+
for (let index = attempts.length - 1;index >= 0; index -= 1) {
|
|
18877
|
+
const attempt = attempts[index];
|
|
18878
|
+
if (attempt?.status === "acknowledged" || attempt?.status === "sent") {
|
|
18879
|
+
return attempt.createdAt;
|
|
18880
|
+
}
|
|
18881
|
+
}
|
|
18882
|
+
return;
|
|
18883
|
+
}
|
|
18884
|
+
function deliveryError(delivery, latestFailedAttempt) {
|
|
18885
|
+
const reason = stringMetadata(delivery.metadata, "failureReason");
|
|
18886
|
+
const detail = stringMetadata(delivery.metadata, "failureDetail") ?? stringMetadata(delivery.metadata, "lastError") ?? latestFailedAttempt?.error;
|
|
18887
|
+
const code = stringMetadata(delivery.metadata, "errorCode");
|
|
18888
|
+
const status = numberMetadata(delivery.metadata, "httpStatus");
|
|
18889
|
+
if (!reason && !detail && !code && status === undefined) {
|
|
18890
|
+
return;
|
|
18891
|
+
}
|
|
18892
|
+
const error48 = {};
|
|
18893
|
+
addOptional(error48, "reason", reason);
|
|
18894
|
+
addOptional(error48, "detail", detail);
|
|
18895
|
+
addOptional(error48, "retryable", booleanMetadata(delivery.metadata, "retryable"));
|
|
18896
|
+
addOptional(error48, "code", code);
|
|
18897
|
+
addOptional(error48, "status", status);
|
|
18898
|
+
return error48;
|
|
18899
|
+
}
|
|
18900
|
+
function isSuppressedDelivery(delivery) {
|
|
18901
|
+
return booleanMetadata(delivery.metadata, "suppressed") || booleanMetadata(delivery.metadata, "policySuppressed") || booleanMetadata(delivery.metadata, "suppressedByPolicy") || stringMetadata(delivery.metadata, "suppressionReason") !== undefined || stringMetadata(delivery.metadata, "failureReason") === "suppressed";
|
|
18902
|
+
}
|
|
18903
|
+
function peerNodeId(delivery) {
|
|
18904
|
+
return stringMetadata(delivery.metadata, "peerNodeId") ?? delivery.targetNodeId;
|
|
18905
|
+
}
|
|
18906
|
+
function dispatchAcknowledgedAt(metadata) {
|
|
18907
|
+
const dispatchAck = metadataObject(metadata, "dispatchAck");
|
|
18908
|
+
return numberMetadata(dispatchAck, "acknowledgedAt");
|
|
18909
|
+
}
|
|
18910
|
+
function lastProgressAt(flight, deliveries) {
|
|
18911
|
+
const deliveryAt = deliveries.map((delivery) => delivery.lastAttemptAt ?? delivery.deliveredAt).filter((value) => value !== undefined).sort((left, right) => right - left)[0];
|
|
18912
|
+
return Math.max(flight?.completedAt ?? 0, flight?.startedAt ?? 0, deliveryAt ?? 0) || undefined;
|
|
18913
|
+
}
|
|
18914
|
+
function lifecycleMetadata(invocation, flight) {
|
|
18915
|
+
const metadata = {};
|
|
18916
|
+
addOptional(metadata, "invocationMetadata", invocation.metadata);
|
|
18917
|
+
addOptional(metadata, "flightMetadata", flight?.metadata);
|
|
18918
|
+
return Object.keys(metadata).length > 0 ? metadata : undefined;
|
|
18919
|
+
}
|
|
18920
|
+
function waitingOnFromMetadata(metadata) {
|
|
18921
|
+
const waitingOn = metadataObject(metadata, "waitingOn");
|
|
18922
|
+
if (!waitingOn) {
|
|
18923
|
+
return;
|
|
18924
|
+
}
|
|
18925
|
+
const kind = stringMetadata(waitingOn, "kind");
|
|
18926
|
+
const projected = {
|
|
18927
|
+
kind: isWaitingOnKind(kind) ? kind : "unknown"
|
|
18928
|
+
};
|
|
18929
|
+
addOptional(projected, "label", stringMetadata(waitingOn, "label"));
|
|
18930
|
+
addOptional(projected, "targetId", stringMetadata(waitingOn, "targetId"));
|
|
18931
|
+
addOptional(projected, "metadata", metadataObject(waitingOn, "metadata"));
|
|
18932
|
+
return projected;
|
|
18933
|
+
}
|
|
18934
|
+
function isWaitingOnKind(value) {
|
|
18935
|
+
return value === "human" || value === "peer" || value === "approval" || value === "artifact" || value === "condition" || value === "agent" || value === "unknown";
|
|
18936
|
+
}
|
|
18937
|
+
function inferWorkId(invocation) {
|
|
18938
|
+
return stringMetadata(invocation.metadata, "workId") ?? stringMetadata(invocation.context, "workId") ?? stringMetadata(metadataObject(invocation.context, "collaboration"), "recordId");
|
|
18939
|
+
}
|
|
18940
|
+
function expiresAtForInvocation(invocation) {
|
|
18941
|
+
const metadataExpiresAt = numberMetadata(invocation.metadata, "expiresAt");
|
|
18942
|
+
if (metadataExpiresAt !== undefined) {
|
|
18943
|
+
return metadataExpiresAt;
|
|
18944
|
+
}
|
|
18945
|
+
return invocation.timeoutMs && Number.isFinite(invocation.timeoutMs) ? invocation.createdAt + invocation.timeoutMs : undefined;
|
|
18946
|
+
}
|
|
18947
|
+
function metadataObject(metadata, key) {
|
|
18948
|
+
const value = metadata?.[key];
|
|
18949
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
18950
|
+
}
|
|
18951
|
+
function stringMetadata(metadata, key) {
|
|
18952
|
+
const value = metadata?.[key];
|
|
18953
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
18954
|
+
}
|
|
18955
|
+
function numberMetadata(metadata, key) {
|
|
18956
|
+
const value = metadata?.[key];
|
|
18957
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
18958
|
+
}
|
|
18959
|
+
function booleanMetadata(metadata, key) {
|
|
18960
|
+
return metadata?.[key] === true;
|
|
18961
|
+
}
|
|
18962
|
+
function addOptional(target, key, value) {
|
|
18963
|
+
if (value !== undefined) {
|
|
18964
|
+
target[key] = value;
|
|
18965
|
+
}
|
|
18966
|
+
}
|
|
18636
18967
|
// packages/protocol/src/permission-policy.ts
|
|
18637
18968
|
var SCOUT_PERMISSION_PROFILES = [
|
|
18638
18969
|
"observe",
|
|
@@ -19628,6 +19959,14 @@ class FileBackedBrokerJournal {
|
|
|
19628
19959
|
getDurableAction(actionId) {
|
|
19629
19960
|
return this.state.durableActions.get(actionId) ?? null;
|
|
19630
19961
|
}
|
|
19962
|
+
getDurableActionByIdempotencyKey(input) {
|
|
19963
|
+
for (const action of this.state.durableActions.values()) {
|
|
19964
|
+
if (action.authorityCellId === input.authorityCellId && action.kind === input.kind && action.idempotencyKey === input.idempotencyKey) {
|
|
19965
|
+
return action;
|
|
19966
|
+
}
|
|
19967
|
+
}
|
|
19968
|
+
return null;
|
|
19969
|
+
}
|
|
19631
19970
|
async rewriteEntries(entries) {
|
|
19632
19971
|
await mkdir(dirname2(this.filePath), { recursive: true });
|
|
19633
19972
|
const payload = entries.length > 0 ? `${entries.map((entry) => JSON.stringify(entry)).join(`
|
|
@@ -19820,12 +20159,12 @@ function normalizedRouteTargetValue(target) {
|
|
|
19820
20159
|
if (!target) {
|
|
19821
20160
|
return;
|
|
19822
20161
|
}
|
|
19823
|
-
const direct = target.kind === "agent_id" ? target.agentId : target.kind === "agent_label" ? target.label : target.kind === "binding_ref" ? target.ref : target.kind === "project_path" ? target.projectPath : target.kind === "channel" ? target.channel : target.value;
|
|
20162
|
+
const direct = target.kind === "agent_id" ? target.agentId : target.kind === "agent_label" ? target.label : target.kind === "session_id" ? target.sessionId : target.kind === "binding_ref" ? target.ref : target.kind === "project_path" ? target.projectPath : target.kind === "channel" ? target.channel : target.value;
|
|
19824
20163
|
const trimmed = direct?.trim();
|
|
19825
20164
|
return trimmed && trimmed.length > 0 ? trimmed : undefined;
|
|
19826
20165
|
}
|
|
19827
20166
|
function askedLabelForRouteTarget(input) {
|
|
19828
|
-
return normalizedRouteTargetValue(input.target) ?? input.targetLabel?.trim() ?? input.targetAgentId?.trim() ?? "";
|
|
20167
|
+
return normalizedRouteTargetValue(input.target) ?? input.targetSessionId?.trim() ?? input.targetLabel?.trim() ?? input.targetAgentId?.trim() ?? "";
|
|
19829
20168
|
}
|
|
19830
20169
|
function routeChannelForTarget(input) {
|
|
19831
20170
|
const target = input.target;
|
|
@@ -19844,20 +20183,6 @@ function metadataStringValue(metadata, key) {
|
|
|
19844
20183
|
const value = metadata?.[key];
|
|
19845
20184
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
19846
20185
|
}
|
|
19847
|
-
function replacementForStaleAgent(snapshot, agent, helpers) {
|
|
19848
|
-
if (!helpers.isStale(agent)) {
|
|
19849
|
-
return;
|
|
19850
|
-
}
|
|
19851
|
-
const replacementAgentId = metadataStringValue(agent.metadata, "replacedByAgentId");
|
|
19852
|
-
if (!replacementAgentId || replacementAgentId === agent.id) {
|
|
19853
|
-
return;
|
|
19854
|
-
}
|
|
19855
|
-
const replacement = snapshot.agents[replacementAgentId];
|
|
19856
|
-
if (!replacement || helpers.isStale(replacement)) {
|
|
19857
|
-
return;
|
|
19858
|
-
}
|
|
19859
|
-
return replacement;
|
|
19860
|
-
}
|
|
19861
20186
|
function isReservedProductIdentity(definitionId) {
|
|
19862
20187
|
return definitionId === SCOUT_DISPATCHER_AGENT_ID || definitionId === OPENSCOUT_COORDINATOR_AGENT_ID;
|
|
19863
20188
|
}
|
|
@@ -19898,6 +20223,31 @@ function buildAgentLabelCandidate(snapshot, agent) {
|
|
|
19898
20223
|
aliases
|
|
19899
20224
|
};
|
|
19900
20225
|
}
|
|
20226
|
+
function stripHarnessQualifier(identity2) {
|
|
20227
|
+
if (!identity2.harness) {
|
|
20228
|
+
return null;
|
|
20229
|
+
}
|
|
20230
|
+
return constructAgentIdentity({
|
|
20231
|
+
definitionId: identity2.definitionId,
|
|
20232
|
+
workspaceQualifier: identity2.workspaceQualifier,
|
|
20233
|
+
profile: identity2.profile,
|
|
20234
|
+
model: identity2.model,
|
|
20235
|
+
nodeQualifier: identity2.nodeQualifier
|
|
20236
|
+
});
|
|
20237
|
+
}
|
|
20238
|
+
function resolutionFromDiagnosis(diagnosis, label) {
|
|
20239
|
+
if (diagnosis.kind === "resolved") {
|
|
20240
|
+
return { kind: "resolved", agent: diagnosis.match.agent };
|
|
20241
|
+
}
|
|
20242
|
+
if (diagnosis.kind === "ambiguous") {
|
|
20243
|
+
return {
|
|
20244
|
+
kind: "ambiguous",
|
|
20245
|
+
label,
|
|
20246
|
+
candidates: diagnosis.candidates.map((candidate) => candidate.agent)
|
|
20247
|
+
};
|
|
20248
|
+
}
|
|
20249
|
+
return null;
|
|
20250
|
+
}
|
|
19901
20251
|
function resolveAgentLabel(snapshot, label, options) {
|
|
19902
20252
|
const trimmed = label.trim();
|
|
19903
20253
|
if (!trimmed) {
|
|
@@ -19912,10 +20262,17 @@ function resolveAgentLabel(snapshot, label, options) {
|
|
|
19912
20262
|
}
|
|
19913
20263
|
const candidates = buildAgentLabelCandidates(snapshot, options.helpers);
|
|
19914
20264
|
const diagnosis = diagnoseAgentIdentity(identity2, candidates);
|
|
20265
|
+
const harnessAgnosticIdentity = stripHarnessQualifier(identity2);
|
|
19915
20266
|
if (diagnosis.kind === "resolved") {
|
|
19916
20267
|
return { kind: "resolved", agent: diagnosis.match.agent };
|
|
19917
20268
|
}
|
|
19918
20269
|
if (diagnosis.kind === "unknown") {
|
|
20270
|
+
if (harnessAgnosticIdentity) {
|
|
20271
|
+
const agnosticResolution = resolutionFromDiagnosis(diagnoseAgentIdentity(harnessAgnosticIdentity, candidates), identity2.label);
|
|
20272
|
+
if (agnosticResolution) {
|
|
20273
|
+
return agnosticResolution;
|
|
20274
|
+
}
|
|
20275
|
+
}
|
|
19919
20276
|
const fallbackCandidates = buildAgentLabelCandidates(snapshot, options.helpers, {
|
|
19920
20277
|
includeStale: true
|
|
19921
20278
|
});
|
|
@@ -19923,7 +20280,7 @@ function resolveAgentLabel(snapshot, label, options) {
|
|
|
19923
20280
|
if (fallbackDiagnosis.kind === "resolved") {
|
|
19924
20281
|
return {
|
|
19925
20282
|
kind: "resolved",
|
|
19926
|
-
agent:
|
|
20283
|
+
agent: fallbackDiagnosis.match.agent
|
|
19927
20284
|
};
|
|
19928
20285
|
}
|
|
19929
20286
|
if (fallbackDiagnosis.kind === "ambiguous") {
|
|
@@ -19933,6 +20290,12 @@ function resolveAgentLabel(snapshot, label, options) {
|
|
|
19933
20290
|
candidates: fallbackDiagnosis.candidates.map((candidate) => candidate.agent)
|
|
19934
20291
|
};
|
|
19935
20292
|
}
|
|
20293
|
+
if (harnessAgnosticIdentity) {
|
|
20294
|
+
const agnosticFallbackResolution = resolutionFromDiagnosis(diagnoseAgentIdentity(harnessAgnosticIdentity, fallbackCandidates), identity2.label);
|
|
20295
|
+
if (agnosticFallbackResolution) {
|
|
20296
|
+
return agnosticFallbackResolution;
|
|
20297
|
+
}
|
|
20298
|
+
}
|
|
19936
20299
|
return { kind: "unknown", label: identity2.label };
|
|
19937
20300
|
}
|
|
19938
20301
|
const preferLocal = options.preferLocalNodeId?.trim();
|
|
@@ -20002,19 +20365,37 @@ function resolveProjectPathTarget(snapshot, projectPath, options) {
|
|
|
20002
20365
|
candidates: candidates.filter((candidate) => candidate.rank === first.rank).map((candidate) => candidate.agent)
|
|
20003
20366
|
};
|
|
20004
20367
|
}
|
|
20368
|
+
function endpointMatchesSessionId(endpoint, sessionId) {
|
|
20369
|
+
return endpoint.sessionId?.trim() === sessionId || endpoint.id === sessionId;
|
|
20370
|
+
}
|
|
20371
|
+
function resolveSessionTarget(snapshot, sessionId, options) {
|
|
20372
|
+
const candidates = Object.values(snapshot.endpoints).filter((endpoint) => endpointMatchesSessionId(endpoint, sessionId)).map((endpoint) => snapshot.agents[endpoint.agentId]).filter((agent) => Boolean(agent)).map((agent) => agent);
|
|
20373
|
+
const unique2 = [...new Map(candidates.map((agent) => [agent.id, agent])).values()];
|
|
20374
|
+
if (unique2.length === 0) {
|
|
20375
|
+
return { kind: "unknown", label: `session:${sessionId}` };
|
|
20376
|
+
}
|
|
20377
|
+
if (unique2.length === 1) {
|
|
20378
|
+
return { kind: "resolved", agent: unique2[0] };
|
|
20379
|
+
}
|
|
20380
|
+
return {
|
|
20381
|
+
kind: "ambiguous",
|
|
20382
|
+
label: `session:${sessionId}`,
|
|
20383
|
+
candidates: unique2
|
|
20384
|
+
};
|
|
20385
|
+
}
|
|
20005
20386
|
function resolveBrokerRouteTarget(snapshot, input, options) {
|
|
20006
20387
|
const policy = input.routePolicy;
|
|
20007
20388
|
const routeTarget = input.target;
|
|
20008
20389
|
const preferLocalNodeId = policy?.preferLocalNodeId?.trim() || options.preferLocalNodeId;
|
|
20009
20390
|
const directId = routeTarget?.kind === "agent_id" ? normalizedRouteTargetValue(routeTarget) : input.targetAgentId?.trim();
|
|
20391
|
+
const directSessionId = routeTarget?.kind === "session_id" ? normalizedRouteTargetValue(routeTarget) : input.targetSessionId?.trim();
|
|
20392
|
+
if (directSessionId) {
|
|
20393
|
+
return resolveSessionTarget(snapshot, directSessionId, {
|
|
20394
|
+
helpers: options.helpers
|
|
20395
|
+
});
|
|
20396
|
+
}
|
|
20010
20397
|
if (directId) {
|
|
20011
20398
|
const agent = snapshot.agents[directId];
|
|
20012
|
-
if (agent) {
|
|
20013
|
-
const replacement = replacementForStaleAgent(snapshot, agent, options.helpers);
|
|
20014
|
-
if (replacement) {
|
|
20015
|
-
return { kind: "resolved", agent: replacement };
|
|
20016
|
-
}
|
|
20017
|
-
}
|
|
20018
20399
|
if (agent && (policy?.allowStaleDirectId ?? true)) {
|
|
20019
20400
|
return { kind: "resolved", agent };
|
|
20020
20401
|
}
|
|
@@ -21351,11 +21732,29 @@ function createPeerDeliveryWorker(deps, config2 = {}) {
|
|
|
21351
21732
|
// packages/runtime/src/local-agents.ts
|
|
21352
21733
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
21353
21734
|
import { execFileSync as execFileSync3, execSync } from "child_process";
|
|
21354
|
-
import { existsSync as
|
|
21735
|
+
import { existsSync as existsSync14, readFileSync as readFileSync7 } from "fs";
|
|
21355
21736
|
import { mkdir as mkdir7, rm as rm5, stat as stat4, writeFile as writeFile7 } from "fs/promises";
|
|
21356
|
-
import { basename as basename9, dirname as
|
|
21737
|
+
import { basename as basename9, dirname as dirname10, join as join19, resolve as resolve7 } from "path";
|
|
21357
21738
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
21358
21739
|
|
|
21740
|
+
// packages/runtime/src/dispatch-stalled.ts
|
|
21741
|
+
class DispatchStalledError extends Error {
|
|
21742
|
+
code = "DISPATCH_STALLED";
|
|
21743
|
+
sessionName;
|
|
21744
|
+
paneTail;
|
|
21745
|
+
retries;
|
|
21746
|
+
constructor(input) {
|
|
21747
|
+
super(`tmux dispatch for session ${input.sessionName} left the prompt in the composer after submit + ${input.retries} retr${input.retries === 1 ? "y" : "ies"}.`);
|
|
21748
|
+
this.name = "DispatchStalledError";
|
|
21749
|
+
this.sessionName = input.sessionName;
|
|
21750
|
+
this.paneTail = input.paneTail;
|
|
21751
|
+
this.retries = input.retries;
|
|
21752
|
+
}
|
|
21753
|
+
}
|
|
21754
|
+
function isDispatchStalledError(error48) {
|
|
21755
|
+
return error48 instanceof DispatchStalledError || Boolean(error48) && typeof error48 === "object" && error48.code === "DISPATCH_STALLED" && typeof error48.sessionName === "string";
|
|
21756
|
+
}
|
|
21757
|
+
|
|
21359
21758
|
// packages/runtime/src/claude-stream-json.ts
|
|
21360
21759
|
import { randomUUID } from "crypto";
|
|
21361
21760
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -26574,6 +26973,63 @@ function readCodexAppServerModelFromLaunchArgs(launchArgs) {
|
|
|
26574
26973
|
}
|
|
26575
26974
|
return null;
|
|
26576
26975
|
}
|
|
26976
|
+
function readCodexAppServerReasoningEffortFromLaunchArgs(launchArgs) {
|
|
26977
|
+
const normalized = normalizeCodexAppServerLaunchArgs(launchArgs);
|
|
26978
|
+
for (let index = 0;index < normalized.length; index += 1) {
|
|
26979
|
+
const current = normalized[index] ?? "";
|
|
26980
|
+
if (current === "-c" || current === "--config") {
|
|
26981
|
+
const reasoningEffort = parseCodexReasoningEffortConfig(normalized[index + 1]);
|
|
26982
|
+
if (reasoningEffort) {
|
|
26983
|
+
return reasoningEffort;
|
|
26984
|
+
}
|
|
26985
|
+
index += 1;
|
|
26986
|
+
continue;
|
|
26987
|
+
}
|
|
26988
|
+
if (current.startsWith("--config=")) {
|
|
26989
|
+
const reasoningEffort = parseCodexReasoningEffortConfig(current.slice("--config=".length));
|
|
26990
|
+
if (reasoningEffort) {
|
|
26991
|
+
return reasoningEffort;
|
|
26992
|
+
}
|
|
26993
|
+
}
|
|
26994
|
+
}
|
|
26995
|
+
return null;
|
|
26996
|
+
}
|
|
26997
|
+
|
|
26998
|
+
class CodexAppServerExitError extends Error {
|
|
26999
|
+
code = "CODEX_APP_SERVER_EXIT";
|
|
27000
|
+
exitKind;
|
|
27001
|
+
agentName;
|
|
27002
|
+
exitCode;
|
|
27003
|
+
signal;
|
|
27004
|
+
reason;
|
|
27005
|
+
noteworthy;
|
|
27006
|
+
constructor(input) {
|
|
27007
|
+
const exitKind = input.exitKind ?? (input.signal === "SIGTERM" ? "external_sigterm" : "unexpected_exit");
|
|
27008
|
+
super(codexAppServerExitMessage({
|
|
27009
|
+
...input,
|
|
27010
|
+
exitKind
|
|
27011
|
+
}));
|
|
27012
|
+
this.name = "CodexAppServerExitError";
|
|
27013
|
+
this.exitKind = exitKind;
|
|
27014
|
+
this.agentName = input.agentName;
|
|
27015
|
+
this.exitCode = input.exitCode;
|
|
27016
|
+
this.signal = input.signal;
|
|
27017
|
+
this.reason = input.reason ?? null;
|
|
27018
|
+
this.noteworthy = exitKind !== "unexpected_exit";
|
|
27019
|
+
}
|
|
27020
|
+
}
|
|
27021
|
+
function isCodexAppServerExitError(error48) {
|
|
27022
|
+
return error48 instanceof CodexAppServerExitError || Boolean(error48 && typeof error48 === "object" && error48.code === "CODEX_APP_SERVER_EXIT");
|
|
27023
|
+
}
|
|
27024
|
+
function codexAppServerExitMessage(input) {
|
|
27025
|
+
if (input.exitKind === "proactive_shutdown") {
|
|
27026
|
+
return `Codex app-server session for ${input.agentName} was stopped by OpenScout` + (input.reason ? `: ${input.reason}` : "") + ".";
|
|
27027
|
+
}
|
|
27028
|
+
if (input.exitKind === "external_sigterm") {
|
|
27029
|
+
return `Codex app-server for ${input.agentName} was interrupted by SIGTERM.`;
|
|
27030
|
+
}
|
|
27031
|
+
return `Codex app-server exited for ${input.agentName}` + (input.exitCode !== null ? ` with code ${input.exitCode}` : "") + (input.signal ? ` (${input.signal})` : "");
|
|
27032
|
+
}
|
|
26577
27033
|
function resolveRequesterTimeoutMs2(timeoutMs) {
|
|
26578
27034
|
if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0) {
|
|
26579
27035
|
return timeoutMs;
|
|
@@ -26748,6 +27204,7 @@ class CodexAppServerSession {
|
|
|
26748
27204
|
activeTurn = null;
|
|
26749
27205
|
threadId = null;
|
|
26750
27206
|
threadPath = null;
|
|
27207
|
+
proactiveShutdown = null;
|
|
26751
27208
|
lastConfigSignature;
|
|
26752
27209
|
constructor(options) {
|
|
26753
27210
|
this.options = options;
|
|
@@ -26878,13 +27335,23 @@ class CodexAppServerSession {
|
|
|
26878
27335
|
});
|
|
26879
27336
|
}
|
|
26880
27337
|
async shutdown(options = {}) {
|
|
27338
|
+
this.proactiveShutdown = {
|
|
27339
|
+
reason: options.reason ?? (options.resetThread ? "OpenScout reset the app-server session" : "OpenScout stopped the app-server session")
|
|
27340
|
+
};
|
|
27341
|
+
const stoppedError = new CodexAppServerExitError({
|
|
27342
|
+
agentName: this.options.agentName,
|
|
27343
|
+
exitKind: "proactive_shutdown",
|
|
27344
|
+
exitCode: null,
|
|
27345
|
+
signal: null,
|
|
27346
|
+
reason: this.proactiveShutdown.reason
|
|
27347
|
+
});
|
|
26881
27348
|
const activeTurn = this.activeTurn;
|
|
26882
27349
|
this.activeTurn = null;
|
|
26883
27350
|
if (activeTurn) {
|
|
26884
|
-
activeTurn.reject(
|
|
27351
|
+
activeTurn.reject(stoppedError);
|
|
26885
27352
|
}
|
|
26886
27353
|
for (const pending of this.pendingRequests.values()) {
|
|
26887
|
-
pending.reject(
|
|
27354
|
+
pending.reject(stoppedError);
|
|
26888
27355
|
}
|
|
26889
27356
|
this.pendingRequests.clear();
|
|
26890
27357
|
const child = this.process;
|
|
@@ -26894,7 +27361,7 @@ class CodexAppServerSession {
|
|
|
26894
27361
|
if (child && child.exitCode === null && !child.killed) {
|
|
26895
27362
|
child.kill("SIGTERM");
|
|
26896
27363
|
await new Promise((resolve4) => setTimeout(resolve4, 250));
|
|
26897
|
-
if (child.exitCode === null &&
|
|
27364
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
26898
27365
|
child.kill("SIGKILL");
|
|
26899
27366
|
}
|
|
26900
27367
|
}
|
|
@@ -26945,6 +27412,7 @@ class CodexAppServerSession {
|
|
|
26945
27412
|
await mkdir4(this.options.runtimeDirectory, { recursive: true });
|
|
26946
27413
|
await mkdir4(this.options.logsDirectory, { recursive: true });
|
|
26947
27414
|
await writeFile4(join13(this.options.runtimeDirectory, "prompt.txt"), this.options.systemPrompt);
|
|
27415
|
+
this.proactiveShutdown = null;
|
|
26948
27416
|
const codexExecutable = resolveCodexExecutable();
|
|
26949
27417
|
const launchArgs = normalizeCodexAppServerLaunchArgs(this.options.launchArgs);
|
|
26950
27418
|
const env = buildManagedAgentEnvironment({
|
|
@@ -26984,7 +27452,16 @@ class CodexAppServerSession {
|
|
|
26984
27452
|
this.failSession(new Error(`Codex app-server failed for ${this.options.agentName}: ${errorMessage3(error48)}`));
|
|
26985
27453
|
});
|
|
26986
27454
|
child.once("exit", (code, signal) => {
|
|
26987
|
-
|
|
27455
|
+
const proactiveShutdown = this.proactiveShutdown;
|
|
27456
|
+
if (proactiveShutdown) {
|
|
27457
|
+
this.handleProactiveProcessExit(child, proactiveShutdown, code, signal);
|
|
27458
|
+
return;
|
|
27459
|
+
}
|
|
27460
|
+
this.failSession(new CodexAppServerExitError({
|
|
27461
|
+
agentName: this.options.agentName,
|
|
27462
|
+
exitCode: code,
|
|
27463
|
+
signal
|
|
27464
|
+
}));
|
|
26988
27465
|
});
|
|
26989
27466
|
await this.request("initialize", {
|
|
26990
27467
|
clientInfo: {
|
|
@@ -27319,6 +27796,23 @@ class CodexAppServerSession {
|
|
|
27319
27796
|
}
|
|
27320
27797
|
this.pendingRequests.clear();
|
|
27321
27798
|
appendFile4(this.stderrLogPath, `[openscout] ${error48.message}
|
|
27799
|
+
`).catch(() => {
|
|
27800
|
+
return;
|
|
27801
|
+
});
|
|
27802
|
+
this.persistState();
|
|
27803
|
+
}
|
|
27804
|
+
handleProactiveProcessExit(child, shutdown, code, signal) {
|
|
27805
|
+
if (this.process === child) {
|
|
27806
|
+
this.process = null;
|
|
27807
|
+
}
|
|
27808
|
+
this.proactiveShutdown = null;
|
|
27809
|
+
this.starting = null;
|
|
27810
|
+
const exitDetail = [
|
|
27811
|
+
code !== null ? `code ${code}` : null,
|
|
27812
|
+
signal
|
|
27813
|
+
].filter(Boolean).join(", ");
|
|
27814
|
+
const detail = exitDetail ? ` (${exitDetail})` : "";
|
|
27815
|
+
appendFile4(this.stderrLogPath, `[openscout] Codex app-server stopped for ${this.options.agentName}: ${shutdown.reason}${detail}
|
|
27322
27816
|
`).catch(() => {
|
|
27323
27817
|
return;
|
|
27324
27818
|
});
|
|
@@ -27390,7 +27884,10 @@ function getOrCreateSession2(options) {
|
|
|
27390
27884
|
if (existing.matches(options)) {
|
|
27391
27885
|
return existing;
|
|
27392
27886
|
}
|
|
27393
|
-
existing.shutdown({
|
|
27887
|
+
existing.shutdown({
|
|
27888
|
+
resetThread: true,
|
|
27889
|
+
reason: "OpenScout replaced the app-server session after its launch options changed"
|
|
27890
|
+
});
|
|
27394
27891
|
sessions2.delete(key);
|
|
27395
27892
|
}
|
|
27396
27893
|
const session = new CodexAppServerSession(options);
|
|
@@ -31507,6 +32004,17 @@ async function fetchHealthSnapshot(config2) {
|
|
|
31507
32004
|
nodes: payload.counts.nodes ?? 0,
|
|
31508
32005
|
actors: payload.counts.actors ?? 0,
|
|
31509
32006
|
agents: payload.counts.agents ?? 0,
|
|
32007
|
+
agentRecords: payload.counts.agentRecords,
|
|
32008
|
+
rawAgentRecords: payload.counts.rawAgentRecords,
|
|
32009
|
+
configuredAgents: payload.counts.configuredAgents,
|
|
32010
|
+
scoutManagedAgents: payload.counts.scoutManagedAgents,
|
|
32011
|
+
currentAgentRegistrations: payload.counts.currentAgentRegistrations,
|
|
32012
|
+
localAgentRegistrations: payload.counts.localAgentRegistrations,
|
|
32013
|
+
remoteAgentRegistrations: payload.counts.remoteAgentRegistrations,
|
|
32014
|
+
staleAgentRegistrations: payload.counts.staleAgentRegistrations,
|
|
32015
|
+
retiredAgentRegistrations: payload.counts.retiredAgentRegistrations,
|
|
32016
|
+
oneTimeAgentCards: payload.counts.oneTimeAgentCards,
|
|
32017
|
+
persistentAgentCards: payload.counts.persistentAgentCards,
|
|
31510
32018
|
conversations: payload.counts.conversations ?? 0,
|
|
31511
32019
|
messages: payload.counts.messages ?? 0,
|
|
31512
32020
|
flights: payload.counts.flights ?? 0,
|
|
@@ -31731,11 +32239,42 @@ function compileCodexPermissionProfile(profileInput) {
|
|
|
31731
32239
|
}
|
|
31732
32240
|
}
|
|
31733
32241
|
|
|
32242
|
+
// packages/runtime/src/user-config.ts
|
|
32243
|
+
import { existsSync as existsSync13, readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
32244
|
+
import { homedir as homedir14 } from "os";
|
|
32245
|
+
import { dirname as dirname9, join as join18 } from "path";
|
|
32246
|
+
function userConfigPath() {
|
|
32247
|
+
return join18(process.env.OPENSCOUT_HOME ?? join18(homedir14(), ".openscout"), "user.json");
|
|
32248
|
+
}
|
|
32249
|
+
function loadUserConfig() {
|
|
32250
|
+
const configPath = userConfigPath();
|
|
32251
|
+
if (!existsSync13(configPath))
|
|
32252
|
+
return {};
|
|
32253
|
+
try {
|
|
32254
|
+
return JSON.parse(readFileSync6(configPath, "utf8"));
|
|
32255
|
+
} catch {
|
|
32256
|
+
return {};
|
|
32257
|
+
}
|
|
32258
|
+
}
|
|
32259
|
+
function resolveOperatorName() {
|
|
32260
|
+
const config2 = loadUserConfig();
|
|
32261
|
+
return config2.name?.trim() || process.env.OPENSCOUT_OPERATOR_NAME?.trim() || process.env.USER?.trim() || "operator";
|
|
32262
|
+
}
|
|
32263
|
+
function normalizeHandle(value) {
|
|
32264
|
+
return value?.trim().replace(/^@+/, "") ?? "";
|
|
32265
|
+
}
|
|
32266
|
+
function resolveOperatorHandle() {
|
|
32267
|
+
const config2 = loadUserConfig();
|
|
32268
|
+
return normalizeHandle(config2.handle) || normalizeHandle(process.env.OPENSCOUT_OPERATOR_HANDLE) || normalizeHandle(config2.name) || normalizeHandle(process.env.OPENSCOUT_OPERATOR_NAME) || normalizeHandle(process.env.USER) || "operator";
|
|
32269
|
+
}
|
|
32270
|
+
|
|
31734
32271
|
// packages/runtime/src/local-agents.ts
|
|
31735
|
-
var MODULE_DIRECTORY =
|
|
32272
|
+
var MODULE_DIRECTORY = dirname10(fileURLToPath5(import.meta.url));
|
|
31736
32273
|
var OPENSCOUT_REPO_ROOT = resolve7(MODULE_DIRECTORY, "..", "..", "..");
|
|
31737
32274
|
var DEFAULT_LOCAL_AGENT_CAPABILITIES = ["chat", "invoke", "deliver"];
|
|
31738
32275
|
var DEFAULT_LOCAL_AGENT_HARNESS = "claude";
|
|
32276
|
+
var DEFAULT_ONE_TIME_LOCAL_AGENT_CARD_TTL_MS = 24 * 60 * 60 * 1000;
|
|
32277
|
+
var DEFAULT_ONE_TIME_LOCAL_AGENT_CARD_RETAIN = 24;
|
|
31739
32278
|
function resolveRelayHub() {
|
|
31740
32279
|
return resolveOpenScoutSupportPaths().relayHubDirectory;
|
|
31741
32280
|
}
|
|
@@ -31745,14 +32284,14 @@ function resolveProjectsRoot(projectPath) {
|
|
|
31745
32284
|
}
|
|
31746
32285
|
try {
|
|
31747
32286
|
const supportPaths = resolveOpenScoutSupportPaths();
|
|
31748
|
-
if (!
|
|
31749
|
-
return
|
|
32287
|
+
if (!existsSync14(supportPaths.settingsPath)) {
|
|
32288
|
+
return dirname10(projectPath);
|
|
31750
32289
|
}
|
|
31751
|
-
const raw = JSON.parse(
|
|
32290
|
+
const raw = JSON.parse(readFileSync7(supportPaths.settingsPath, "utf8"));
|
|
31752
32291
|
const workspaceRoot = raw.discovery?.workspaceRoots?.find((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
31753
|
-
return workspaceRoot ? resolve7(workspaceRoot) :
|
|
32292
|
+
return workspaceRoot ? resolve7(workspaceRoot) : dirname10(projectPath);
|
|
31754
32293
|
} catch {
|
|
31755
|
-
return
|
|
32294
|
+
return dirname10(projectPath);
|
|
31756
32295
|
}
|
|
31757
32296
|
}
|
|
31758
32297
|
function resolveBrokerUrl() {
|
|
@@ -31765,7 +32304,7 @@ function normalizeBrokerTimestamp(value) {
|
|
|
31765
32304
|
return value > 10000000000 ? Math.floor(value / 1000) : value;
|
|
31766
32305
|
}
|
|
31767
32306
|
function scoutCliPath() {
|
|
31768
|
-
return
|
|
32307
|
+
return join19(OPENSCOUT_REPO_ROOT, "packages", "cli", "bin", "scout.mjs");
|
|
31769
32308
|
}
|
|
31770
32309
|
function legacyNodeBrokerRelayCommand() {
|
|
31771
32310
|
return `node ${JSON.stringify(scoutCliPath())}`;
|
|
@@ -31792,13 +32331,13 @@ var SUPPORTED_SCOUT_HARNESSES = [
|
|
|
31792
32331
|
];
|
|
31793
32332
|
function resolveScoutSkillPath() {
|
|
31794
32333
|
const candidatePaths = [
|
|
31795
|
-
|
|
31796
|
-
|
|
31797
|
-
|
|
31798
|
-
|
|
32334
|
+
join19(OPENSCOUT_REPO_ROOT, ".agents", "skills", "scout", "SKILL.md"),
|
|
32335
|
+
join19(process.env.HOME ?? "", ".agents", "skills", "scout", "SKILL.md"),
|
|
32336
|
+
join19(OPENSCOUT_REPO_ROOT, ".agents", "skills", "relay-agent-comms", "SKILL.md"),
|
|
32337
|
+
join19(process.env.HOME ?? "", ".agents", "skills", "relay-agent-comms", "SKILL.md")
|
|
31799
32338
|
];
|
|
31800
32339
|
for (const path of candidatePaths) {
|
|
31801
|
-
if (
|
|
32340
|
+
if (existsSync14(path)) {
|
|
31802
32341
|
return path;
|
|
31803
32342
|
}
|
|
31804
32343
|
}
|
|
@@ -31906,6 +32445,74 @@ function buildLocalAgentSystemPromptTemplate() {
|
|
|
31906
32445
|
].join(`
|
|
31907
32446
|
`);
|
|
31908
32447
|
}
|
|
32448
|
+
function normalizeOperatorHandleSegment(value) {
|
|
32449
|
+
return normalizeAgentSelectorSegment(value?.trim().replace(/^@+/, "") ?? "") || "operator";
|
|
32450
|
+
}
|
|
32451
|
+
function resolveOperatorAugmentAgentName() {
|
|
32452
|
+
return `${normalizeOperatorHandleSegment(resolveOperatorHandle())}-ai`;
|
|
32453
|
+
}
|
|
32454
|
+
function operatorAugmentAgentNameCandidates() {
|
|
32455
|
+
return new Set([
|
|
32456
|
+
resolveOperatorAugmentAgentName(),
|
|
32457
|
+
"operator-ai"
|
|
32458
|
+
]);
|
|
32459
|
+
}
|
|
32460
|
+
function buildOperatorAugmentSystemPromptTemplate(input = {}) {
|
|
32461
|
+
const operatorHandle = normalizeOperatorHandleSegment(input.operatorHandle ?? resolveOperatorHandle());
|
|
32462
|
+
const augmentHandle = normalizeOperatorHandleSegment(input.augmentHandle ?? `${operatorHandle}-ai`);
|
|
32463
|
+
const humanLabel = `@${operatorHandle}`;
|
|
32464
|
+
const augmentLabel = `@${augmentHandle}`;
|
|
32465
|
+
return [
|
|
32466
|
+
"{{base_prompt}}",
|
|
32467
|
+
"",
|
|
32468
|
+
`You are the augmented counterpart to the human Scout operator ${humanLabel}.`,
|
|
32469
|
+
`${humanLabel} is the human. ${augmentLabel} is the AI-augmented looper with a human in the loop.`,
|
|
32470
|
+
`Do not impersonate ${humanLabel}. Speak and act as ${augmentLabel}, and involve ${humanLabel} only when human judgment or approval is the real next dependency.`,
|
|
32471
|
+
"",
|
|
32472
|
+
"Operating loop:",
|
|
32473
|
+
" - Keep long-running conversations in the same DM or invocation thread whenever possible.",
|
|
32474
|
+
" - Maintain continuity across turns: track the goal, decisions made, open questions, blockers, and promised follow-ups.",
|
|
32475
|
+
" - For efforts that span many turns, many files, or more than one working session, create or update a durable note/checkpoint when you have write access, then point to it briefly.",
|
|
32476
|
+
" - Prefer continuing from a concise recap over resetting context. If context is aging, summarize the useful state and keep moving.",
|
|
32477
|
+
` - Be explicit about the next responsible owner: ${augmentLabel}, ${humanLabel}, or another named agent.`,
|
|
32478
|
+
"",
|
|
32479
|
+
`When to invoke ${humanLabel}:`,
|
|
32480
|
+
" - Approval is needed for destructive, irreversible, public, financial, security-sensitive, credential, privacy, or cross-project priority decisions.",
|
|
32481
|
+
` - The task depends on taste, intent, product direction, personal context, or a choice only ${humanLabel} can make.`,
|
|
32482
|
+
" - You are blocked after a reasonable local attempt and the unblock request can be stated as a short concrete question.",
|
|
32483
|
+
" - A result is materially uncertain and acting without human input could waste meaningful time or create cleanup work.",
|
|
32484
|
+
" - You need permission to interrupt, wake, or redirect other people or agents outside the current work venue.",
|
|
32485
|
+
"",
|
|
32486
|
+
`How to invoke ${humanLabel}:`,
|
|
32487
|
+
" - Keep the ask concise: context, the decision needed, the default you recommend, and the consequence of no answer.",
|
|
32488
|
+
" - Use the same DM/thread when it exists. Do not broadcast human-loop requests.",
|
|
32489
|
+
` - If a reply is required before work can proceed, say that ${humanLabel} owns the next move and stop claiming progress.`,
|
|
32490
|
+
" - If work can continue safely, state the assumption and continue without waiting.",
|
|
32491
|
+
"",
|
|
32492
|
+
`Do not invoke ${humanLabel} for:`,
|
|
32493
|
+
" - Routine status updates, obvious implementation details, command outputs, local orientation, or reversible low-risk cleanup.",
|
|
32494
|
+
" - Ambiguity that you can resolve by reading the repo, checking Scout state, or asking the correct specialist agent.",
|
|
32495
|
+
"",
|
|
32496
|
+
"{{project_context}}",
|
|
32497
|
+
"",
|
|
32498
|
+
"{{collaboration_prompt}}",
|
|
32499
|
+
"",
|
|
32500
|
+
"{{protocol_prompt}}"
|
|
32501
|
+
].join(`
|
|
32502
|
+
`);
|
|
32503
|
+
}
|
|
32504
|
+
function operatorAugmentDefaultsForDefinitionId(definitionId) {
|
|
32505
|
+
const normalizedDefinitionId = normalizeAgentSelectorSegment(definitionId);
|
|
32506
|
+
if (!normalizedDefinitionId || !operatorAugmentAgentNameCandidates().has(normalizedDefinitionId)) {
|
|
32507
|
+
return null;
|
|
32508
|
+
}
|
|
32509
|
+
return {
|
|
32510
|
+
displayName: titleCaseLocalAgentName(normalizedDefinitionId),
|
|
32511
|
+
systemPrompt: buildOperatorAugmentSystemPromptTemplate({
|
|
32512
|
+
augmentHandle: normalizedDefinitionId
|
|
32513
|
+
})
|
|
32514
|
+
};
|
|
32515
|
+
}
|
|
31909
32516
|
function renderLocalAgentSystemPromptTemplate(template, context, options = {}) {
|
|
31910
32517
|
const basePrompt = buildLocalAgentBasePrompt(context);
|
|
31911
32518
|
const projectContext = buildLocalAgentProjectContextPrompt(context);
|
|
@@ -32060,7 +32667,7 @@ function expandHomePath3(value) {
|
|
|
32060
32667
|
return process.env.HOME ?? process.cwd();
|
|
32061
32668
|
}
|
|
32062
32669
|
if (value.startsWith("~/")) {
|
|
32063
|
-
return
|
|
32670
|
+
return join19(process.env.HOME ?? process.cwd(), value.slice(2));
|
|
32064
32671
|
}
|
|
32065
32672
|
return value;
|
|
32066
32673
|
}
|
|
@@ -32125,8 +32732,8 @@ var DEFAULT_CLAUDE_SCOUT_ALLOWED_TOOLS = [
|
|
|
32125
32732
|
"mcp__scout__agents_search",
|
|
32126
32733
|
"mcp__scout__agents_resolve",
|
|
32127
32734
|
"mcp__scout__messages_reply",
|
|
32735
|
+
"mcp__scout__ask",
|
|
32128
32736
|
"mcp__scout__messages_send",
|
|
32129
|
-
"mcp__scout__invocations_ask",
|
|
32130
32737
|
"mcp__scout__invocations_get",
|
|
32131
32738
|
"mcp__scout__invocations_wait",
|
|
32132
32739
|
"mcp__scout__work_update",
|
|
@@ -32146,6 +32753,10 @@ function normalizeClaudeRuntimeLaunchArgs(value) {
|
|
|
32146
32753
|
DEFAULT_CLAUDE_SCOUT_ALLOWED_TOOLS.join(",")
|
|
32147
32754
|
];
|
|
32148
32755
|
}
|
|
32756
|
+
function normalizeRequestedModel(value) {
|
|
32757
|
+
const trimmed = value?.trim();
|
|
32758
|
+
return trimmed ? trimmed : undefined;
|
|
32759
|
+
}
|
|
32149
32760
|
function readClaudeLaunchModel(launchArgs) {
|
|
32150
32761
|
for (let index = 0;index < launchArgs.length; index += 1) {
|
|
32151
32762
|
const current = launchArgs[index] ?? "";
|
|
@@ -32193,37 +32804,199 @@ function readLaunchModelForHarness(harness, launchArgs) {
|
|
|
32193
32804
|
}
|
|
32194
32805
|
return;
|
|
32195
32806
|
}
|
|
32196
|
-
function
|
|
32197
|
-
|
|
32198
|
-
|
|
32199
|
-
|
|
32200
|
-
|
|
32201
|
-
|
|
32202
|
-
|
|
32203
|
-
|
|
32204
|
-
|
|
32205
|
-
|
|
32807
|
+
function stripLaunchModelForHarness(harness, launchArgs) {
|
|
32808
|
+
if (harness === "codex") {
|
|
32809
|
+
const next = [];
|
|
32810
|
+
const normalized = normalizeCodexAppServerLaunchArgs(launchArgs);
|
|
32811
|
+
for (let index = 0;index < normalized.length; index += 1) {
|
|
32812
|
+
const current = normalized[index] ?? "";
|
|
32813
|
+
if (current === "-c" || current === "--config") {
|
|
32814
|
+
const value = normalized[index + 1];
|
|
32815
|
+
if (readCodexAppServerModelFromLaunchArgs(value ? [current, value] : [current])) {
|
|
32816
|
+
index += 1;
|
|
32817
|
+
continue;
|
|
32818
|
+
}
|
|
32819
|
+
next.push(current);
|
|
32820
|
+
if (value) {
|
|
32821
|
+
next.push(value);
|
|
32822
|
+
index += 1;
|
|
32823
|
+
}
|
|
32824
|
+
continue;
|
|
32825
|
+
}
|
|
32826
|
+
if (current.startsWith("--config=")) {
|
|
32827
|
+
if (readCodexAppServerModelFromLaunchArgs([current])) {
|
|
32828
|
+
continue;
|
|
32829
|
+
}
|
|
32830
|
+
}
|
|
32831
|
+
next.push(current);
|
|
32206
32832
|
}
|
|
32207
|
-
|
|
32208
|
-
cwd: normalizeProjectPath2(profile.cwd || record2.cwd || process.cwd()),
|
|
32209
|
-
transport: normalizeLocalAgentTransport(profile.transport, harness),
|
|
32210
|
-
sessionId: normalizeTmuxSessionName2(profile.sessionId, `${agentId}-${harness}`),
|
|
32211
|
-
launchArgs: normalizeLaunchArgsForHarness(harness, profile.launchArgs),
|
|
32212
|
-
...profile.permissionProfile ? { permissionProfile: profile.permissionProfile } : {}
|
|
32213
|
-
};
|
|
32833
|
+
return next;
|
|
32214
32834
|
}
|
|
32215
|
-
|
|
32216
|
-
|
|
32217
|
-
|
|
32218
|
-
|
|
32219
|
-
|
|
32220
|
-
|
|
32221
|
-
|
|
32222
|
-
|
|
32223
|
-
|
|
32835
|
+
if (harness === "claude" || harness === "pi") {
|
|
32836
|
+
const next = [];
|
|
32837
|
+
const normalized = normalizeLocalAgentLaunchArgs(launchArgs);
|
|
32838
|
+
for (let index = 0;index < normalized.length; index += 1) {
|
|
32839
|
+
const current = normalized[index] ?? "";
|
|
32840
|
+
if (current === "--model") {
|
|
32841
|
+
index += 1;
|
|
32842
|
+
continue;
|
|
32843
|
+
}
|
|
32844
|
+
if (current.startsWith("--model=")) {
|
|
32845
|
+
continue;
|
|
32846
|
+
}
|
|
32847
|
+
next.push(current);
|
|
32848
|
+
}
|
|
32849
|
+
return next;
|
|
32224
32850
|
}
|
|
32225
|
-
|
|
32226
|
-
|
|
32851
|
+
return normalizeLocalAgentLaunchArgs(launchArgs);
|
|
32852
|
+
}
|
|
32853
|
+
function buildLaunchArgsForRequestedModel(harness, model) {
|
|
32854
|
+
if (harness === "codex") {
|
|
32855
|
+
return normalizeCodexAppServerLaunchArgs(["--model", model]);
|
|
32856
|
+
}
|
|
32857
|
+
if (harness === "claude") {
|
|
32858
|
+
return ["--model", model];
|
|
32859
|
+
}
|
|
32860
|
+
if (harness === "pi") {
|
|
32861
|
+
return ["--model", model];
|
|
32862
|
+
}
|
|
32863
|
+
return [];
|
|
32864
|
+
}
|
|
32865
|
+
function normalizeRequestedReasoningEffort(reasoningEffort) {
|
|
32866
|
+
const trimmed = reasoningEffort?.trim();
|
|
32867
|
+
return trimmed ? trimmed : undefined;
|
|
32868
|
+
}
|
|
32869
|
+
function stripLaunchReasoningEffortForHarness(harness, launchArgs) {
|
|
32870
|
+
if (harness === "pi") {
|
|
32871
|
+
const next2 = [];
|
|
32872
|
+
const normalized2 = normalizeLocalAgentLaunchArgs(launchArgs);
|
|
32873
|
+
for (let index = 0;index < normalized2.length; index += 1) {
|
|
32874
|
+
const current = normalized2[index] ?? "";
|
|
32875
|
+
if (current === "--thinking") {
|
|
32876
|
+
index += 1;
|
|
32877
|
+
continue;
|
|
32878
|
+
}
|
|
32879
|
+
if (current.startsWith("--thinking=")) {
|
|
32880
|
+
continue;
|
|
32881
|
+
}
|
|
32882
|
+
next2.push(current);
|
|
32883
|
+
}
|
|
32884
|
+
return next2;
|
|
32885
|
+
}
|
|
32886
|
+
if (harness !== "codex") {
|
|
32887
|
+
return normalizeLaunchArgsForHarness(harness, launchArgs);
|
|
32888
|
+
}
|
|
32889
|
+
const next = [];
|
|
32890
|
+
const normalized = normalizeCodexAppServerLaunchArgs(launchArgs);
|
|
32891
|
+
for (let index = 0;index < normalized.length; index += 1) {
|
|
32892
|
+
const current = normalized[index] ?? "";
|
|
32893
|
+
if (current === "-c" || current === "--config") {
|
|
32894
|
+
const value = normalized[index + 1];
|
|
32895
|
+
if (readCodexAppServerReasoningEffortFromLaunchArgs(value ? [current, value] : [current])) {
|
|
32896
|
+
index += 1;
|
|
32897
|
+
continue;
|
|
32898
|
+
}
|
|
32899
|
+
next.push(current);
|
|
32900
|
+
if (value) {
|
|
32901
|
+
next.push(value);
|
|
32902
|
+
index += 1;
|
|
32903
|
+
}
|
|
32904
|
+
continue;
|
|
32905
|
+
}
|
|
32906
|
+
if (current.startsWith("--config=")) {
|
|
32907
|
+
if (readCodexAppServerReasoningEffortFromLaunchArgs([current])) {
|
|
32908
|
+
continue;
|
|
32909
|
+
}
|
|
32910
|
+
}
|
|
32911
|
+
next.push(current);
|
|
32912
|
+
}
|
|
32913
|
+
return next;
|
|
32914
|
+
}
|
|
32915
|
+
function buildLaunchArgsForRequestedReasoningEffort(harness, reasoningEffort) {
|
|
32916
|
+
if (harness === "codex") {
|
|
32917
|
+
return normalizeCodexAppServerLaunchArgs(["--reasoning-effort", reasoningEffort]);
|
|
32918
|
+
}
|
|
32919
|
+
if (harness === "pi") {
|
|
32920
|
+
return ["--thinking", reasoningEffort];
|
|
32921
|
+
}
|
|
32922
|
+
return [];
|
|
32923
|
+
}
|
|
32924
|
+
function applyRequestedModelToLaunchArgs(harness, launchArgs, model) {
|
|
32925
|
+
const normalized = normalizeLaunchArgsForHarness(harness, launchArgs);
|
|
32926
|
+
const requestedModel = normalizeRequestedModel(model);
|
|
32927
|
+
if (!requestedModel) {
|
|
32928
|
+
return normalized;
|
|
32929
|
+
}
|
|
32930
|
+
return [
|
|
32931
|
+
...stripLaunchModelForHarness(harness, normalized),
|
|
32932
|
+
...buildLaunchArgsForRequestedModel(harness, requestedModel)
|
|
32933
|
+
];
|
|
32934
|
+
}
|
|
32935
|
+
function applyRequestedRuntimeOptionsToLaunchArgs(harness, launchArgs, options) {
|
|
32936
|
+
const withModel = applyRequestedModelToLaunchArgs(harness, launchArgs, options.model);
|
|
32937
|
+
const requestedReasoningEffort = normalizeRequestedReasoningEffort(options.reasoningEffort);
|
|
32938
|
+
if (!requestedReasoningEffort) {
|
|
32939
|
+
return withModel;
|
|
32940
|
+
}
|
|
32941
|
+
return [
|
|
32942
|
+
...stripLaunchReasoningEffortForHarness(harness, withModel),
|
|
32943
|
+
...buildLaunchArgsForRequestedReasoningEffort(harness, requestedReasoningEffort)
|
|
32944
|
+
];
|
|
32945
|
+
}
|
|
32946
|
+
function defaultHarnessForOverride(override, fallback = "claude") {
|
|
32947
|
+
return normalizeManagedHarness2(override.defaultHarness ?? override.runtime?.harness, fallback);
|
|
32948
|
+
}
|
|
32949
|
+
function launchArgsForOverrideHarness(override, harness) {
|
|
32950
|
+
const profileLaunchArgs = override.harnessProfiles?.[harness]?.launchArgs;
|
|
32951
|
+
if (profileLaunchArgs) {
|
|
32952
|
+
return normalizeLaunchArgsForHarness(harness, profileLaunchArgs);
|
|
32953
|
+
}
|
|
32954
|
+
if (harness === defaultHarnessForOverride(override, harness)) {
|
|
32955
|
+
return normalizeLaunchArgsForHarness(harness, override.launchArgs);
|
|
32956
|
+
}
|
|
32957
|
+
return [];
|
|
32958
|
+
}
|
|
32959
|
+
function overrideHarnessProfile(override, harness) {
|
|
32960
|
+
const profile = override.harnessProfiles?.[harness];
|
|
32961
|
+
return {
|
|
32962
|
+
cwd: normalizeProjectPath2(profile?.cwd || override.runtime?.cwd || override.projectRoot || process.cwd()),
|
|
32963
|
+
transport: normalizeLocalAgentTransport(profile?.transport ?? override.runtime?.transport, harness),
|
|
32964
|
+
sessionId: normalizeTmuxSessionName2(profile?.sessionId, `${override.agentId}-${harness}`),
|
|
32965
|
+
launchArgs: launchArgsForOverrideHarness(override, harness),
|
|
32966
|
+
...profile?.permissionProfile ? { permissionProfile: profile.permissionProfile } : {}
|
|
32967
|
+
};
|
|
32968
|
+
}
|
|
32969
|
+
function normalizeManagedHarness2(value, fallback) {
|
|
32970
|
+
return value === "codex" ? "codex" : value === "claude" ? "claude" : value === "cursor" ? "cursor" : value === "pi" ? "pi" : fallback;
|
|
32971
|
+
}
|
|
32972
|
+
function normalizeLocalHarnessProfiles(agentId, record2) {
|
|
32973
|
+
const defaultHarness = normalizeManagedHarness2(typeof record2.defaultHarness === "string" ? record2.defaultHarness : record2.harness, "claude");
|
|
32974
|
+
const nextProfiles = {};
|
|
32975
|
+
for (const harness of ["claude", "codex", "cursor", "pi"]) {
|
|
32976
|
+
const profile = record2.harnessProfiles?.[harness];
|
|
32977
|
+
if (!profile) {
|
|
32978
|
+
continue;
|
|
32979
|
+
}
|
|
32980
|
+
nextProfiles[harness] = {
|
|
32981
|
+
cwd: normalizeProjectPath2(profile.cwd || record2.cwd || process.cwd()),
|
|
32982
|
+
transport: normalizeLocalAgentTransport(profile.transport, harness),
|
|
32983
|
+
sessionId: normalizeTmuxSessionName2(profile.sessionId, `${agentId}-${harness}`),
|
|
32984
|
+
launchArgs: normalizeLaunchArgsForHarness(harness, profile.launchArgs),
|
|
32985
|
+
...profile.permissionProfile ? { permissionProfile: profile.permissionProfile } : {}
|
|
32986
|
+
};
|
|
32987
|
+
}
|
|
32988
|
+
const runtimeHarness = normalizeManagedHarness2(record2.harness, defaultHarness);
|
|
32989
|
+
if (!nextProfiles[runtimeHarness]) {
|
|
32990
|
+
nextProfiles[runtimeHarness] = {
|
|
32991
|
+
cwd: normalizeProjectPath2(record2.cwd || process.cwd()),
|
|
32992
|
+
transport: normalizeLocalAgentTransport(record2.transport, runtimeHarness),
|
|
32993
|
+
sessionId: normalizeTmuxSessionName2(record2.tmuxSession, `${agentId}-${runtimeHarness}`),
|
|
32994
|
+
launchArgs: normalizeLaunchArgsForHarness(runtimeHarness, record2.launchArgs),
|
|
32995
|
+
...record2.permissionProfile ? { permissionProfile: record2.permissionProfile } : {}
|
|
32996
|
+
};
|
|
32997
|
+
}
|
|
32998
|
+
if (!nextProfiles[defaultHarness]) {
|
|
32999
|
+
nextProfiles[defaultHarness] = {
|
|
32227
33000
|
cwd: normalizeProjectPath2(record2.cwd || process.cwd()),
|
|
32228
33001
|
transport: normalizeLocalAgentTransport(record2.transport, defaultHarness),
|
|
32229
33002
|
sessionId: normalizeTmuxSessionName2(record2.tmuxSession, `${agentId}-${defaultHarness}`),
|
|
@@ -32290,6 +33063,31 @@ function recordForHarness(record2, harnessOverride) {
|
|
|
32290
33063
|
permissionProfile: profile.permissionProfile
|
|
32291
33064
|
};
|
|
32292
33065
|
}
|
|
33066
|
+
function normalizeCardTimestamp(value) {
|
|
33067
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : undefined;
|
|
33068
|
+
}
|
|
33069
|
+
function normalizeLocalAgentCardLifecycle(value, now = Date.now()) {
|
|
33070
|
+
if (!value) {
|
|
33071
|
+
return;
|
|
33072
|
+
}
|
|
33073
|
+
const kind = value.kind === "one_time" ? "one_time" : value.kind === "persistent" ? "persistent" : undefined;
|
|
33074
|
+
if (!kind) {
|
|
33075
|
+
return;
|
|
33076
|
+
}
|
|
33077
|
+
const createdAt = normalizeCardTimestamp(value.createdAt) ?? now;
|
|
33078
|
+
const expiresAt = normalizeCardTimestamp(value.expiresAt);
|
|
33079
|
+
const maxUses = typeof value.maxUses === "number" && Number.isFinite(value.maxUses) && value.maxUses > 0 ? Math.floor(value.maxUses) : undefined;
|
|
33080
|
+
const createdById = value.createdById?.trim();
|
|
33081
|
+
const inboxConversationId = value.inboxConversationId?.trim();
|
|
33082
|
+
return {
|
|
33083
|
+
kind,
|
|
33084
|
+
createdAt,
|
|
33085
|
+
...createdById ? { createdById } : {},
|
|
33086
|
+
...expiresAt ? { expiresAt } : {},
|
|
33087
|
+
...maxUses ? { maxUses } : {},
|
|
33088
|
+
...inboxConversationId ? { inboxConversationId } : {}
|
|
33089
|
+
};
|
|
33090
|
+
}
|
|
32293
33091
|
function normalizeLocalAgentRecord(agentId, record2) {
|
|
32294
33092
|
const cwd = normalizeProjectPath2(record2.cwd || process.cwd());
|
|
32295
33093
|
const projectRoot = normalizeProjectPath2(record2.projectRoot || cwd);
|
|
@@ -32319,9 +33117,28 @@ function normalizeLocalAgentRecord(agentId, record2) {
|
|
|
32319
33117
|
capabilities: normalizeLocalAgentCapabilities(record2.capabilities),
|
|
32320
33118
|
launchArgs: activeProfile?.launchArgs ?? normalizeLaunchArgsForHarness(harness, record2.launchArgs),
|
|
32321
33119
|
permissionProfile: activeProfile?.permissionProfile ?? record2.permissionProfile,
|
|
32322
|
-
registrationSource: record2.registrationSource
|
|
33120
|
+
registrationSource: record2.registrationSource,
|
|
33121
|
+
card: normalizeLocalAgentCardLifecycle(record2.card)
|
|
33122
|
+
};
|
|
33123
|
+
}
|
|
33124
|
+
function localAgentStatusFromRecord(agentId, record2, source) {
|
|
33125
|
+
const normalizedRecord = normalizeLocalAgentRecord(agentId, record2);
|
|
33126
|
+
return {
|
|
33127
|
+
agentId,
|
|
33128
|
+
definitionId: normalizedRecord.definitionId ?? agentId,
|
|
33129
|
+
projectName: normalizedRecord.project,
|
|
33130
|
+
projectRoot: normalizedRecord.projectRoot ?? normalizedRecord.cwd,
|
|
33131
|
+
sessionId: normalizedRecord.tmuxSession,
|
|
33132
|
+
startedAt: normalizedRecord.startedAt,
|
|
33133
|
+
harness: normalizeLocalAgentHarness(normalizedRecord.harness),
|
|
33134
|
+
transport: normalizedRecord.transport,
|
|
33135
|
+
isOnline: isLocalAgentRecordOnline(agentId, normalizedRecord),
|
|
33136
|
+
source
|
|
32323
33137
|
};
|
|
32324
33138
|
}
|
|
33139
|
+
function localAgentStatusSource(agentId, overrides) {
|
|
33140
|
+
return overrides[agentId]?.source === "manual" ? "manual" : "configured";
|
|
33141
|
+
}
|
|
32325
33142
|
function localAgentRecordFromResolvedConfig(config2) {
|
|
32326
33143
|
return normalizeLocalAgentRecord(config2.agentId, {
|
|
32327
33144
|
definitionId: config2.definitionId,
|
|
@@ -32355,7 +33172,8 @@ function localAgentRecordFromRelayAgentOverride(agentId, override) {
|
|
|
32355
33172
|
harnessProfiles: override.harnessProfiles,
|
|
32356
33173
|
transport: normalizeLocalAgentTransport(override.runtime?.transport, normalizeLocalAgentHarness(override.runtime?.harness)),
|
|
32357
33174
|
capabilities: override.capabilities,
|
|
32358
|
-
launchArgs: override.launchArgs
|
|
33175
|
+
launchArgs: override.launchArgs,
|
|
33176
|
+
card: override.card
|
|
32359
33177
|
});
|
|
32360
33178
|
}
|
|
32361
33179
|
function relayAgentOverrideFromLocalAgentRecord(agentId, record2, existing) {
|
|
@@ -32376,6 +33194,7 @@ function relayAgentOverrideFromLocalAgentRecord(agentId, record2, existing) {
|
|
|
32376
33194
|
capabilities: normalizeLocalAgentCapabilities(normalizedRecord.capabilities),
|
|
32377
33195
|
defaultHarness: normalizeManagedHarness2(normalizedRecord.defaultHarness, "claude"),
|
|
32378
33196
|
harnessProfiles: normalizedRecord.harnessProfiles,
|
|
33197
|
+
...normalizedRecord.card ? { card: normalizedRecord.card } : {},
|
|
32379
33198
|
runtime: {
|
|
32380
33199
|
cwd: normalizeProjectPath2(normalizedRecord.cwd),
|
|
32381
33200
|
harness: normalizeLocalAgentHarness(normalizedRecord.harness),
|
|
@@ -32387,8 +33206,8 @@ function relayAgentOverrideFromLocalAgentRecord(agentId, record2, existing) {
|
|
|
32387
33206
|
}
|
|
32388
33207
|
async function ensureLocalSessionEndpointOnline(endpoint) {
|
|
32389
33208
|
if (endpoint.transport === "codex_app_server") {
|
|
32390
|
-
await ensureCodexAppServerAgentOnline(buildCodexEndpointSessionOptions(endpoint));
|
|
32391
|
-
return {};
|
|
33209
|
+
const result = await ensureCodexAppServerAgentOnline(buildCodexEndpointSessionOptions(endpoint));
|
|
33210
|
+
return { externalSessionId: result.threadId };
|
|
32392
33211
|
}
|
|
32393
33212
|
if (endpoint.transport === "claude_stream_json") {
|
|
32394
33213
|
const result = await ensureClaudeStreamJsonAgentOnline(buildClaudeEndpointSessionOptions(endpoint));
|
|
@@ -32405,6 +33224,118 @@ async function shutdownLocalSessionEndpoint(endpoint) {
|
|
|
32405
33224
|
await shutdownClaudeStreamJsonAgent(buildClaudeEndpointSessionOptions(endpoint));
|
|
32406
33225
|
}
|
|
32407
33226
|
}
|
|
33227
|
+
function oneTimeCardCreatedAt(lifecycle2) {
|
|
33228
|
+
return normalizeCardTimestamp(lifecycle2.createdAt) ?? 0;
|
|
33229
|
+
}
|
|
33230
|
+
function shouldPruneOneTimeCard(lifecycle2, now, maxAgeMs) {
|
|
33231
|
+
if (lifecycle2.kind !== "one_time") {
|
|
33232
|
+
return false;
|
|
33233
|
+
}
|
|
33234
|
+
if (lifecycle2.expiresAt !== undefined && lifecycle2.expiresAt <= now) {
|
|
33235
|
+
return true;
|
|
33236
|
+
}
|
|
33237
|
+
const createdAt = oneTimeCardCreatedAt(lifecycle2);
|
|
33238
|
+
return createdAt > 0 && createdAt + maxAgeMs <= now;
|
|
33239
|
+
}
|
|
33240
|
+
function oneTimeCardMatchesScope(agentId, override, input) {
|
|
33241
|
+
if (BUILT_IN_AGENT_DEFINITION_IDS.has(agentId)) {
|
|
33242
|
+
return false;
|
|
33243
|
+
}
|
|
33244
|
+
const lifecycle2 = normalizeLocalAgentCardLifecycle(override.card);
|
|
33245
|
+
if (lifecycle2?.kind !== "one_time") {
|
|
33246
|
+
return false;
|
|
33247
|
+
}
|
|
33248
|
+
if (input.createdById?.trim() && lifecycle2.createdById !== input.createdById.trim()) {
|
|
33249
|
+
return false;
|
|
33250
|
+
}
|
|
33251
|
+
if (input.projectRoot?.trim()) {
|
|
33252
|
+
const scopedRoot = normalizeProjectPath2(input.projectRoot);
|
|
33253
|
+
const cardRoot = normalizeProjectPath2(override.projectRoot || override.runtime?.cwd || ".");
|
|
33254
|
+
if (cardRoot !== scopedRoot) {
|
|
33255
|
+
return false;
|
|
33256
|
+
}
|
|
33257
|
+
}
|
|
33258
|
+
return true;
|
|
33259
|
+
}
|
|
33260
|
+
async function retireLocalAgentOverrides(overrides, agentIds) {
|
|
33261
|
+
const retired = [];
|
|
33262
|
+
for (const agentId of agentIds) {
|
|
33263
|
+
const override = overrides[agentId];
|
|
33264
|
+
if (!override) {
|
|
33265
|
+
continue;
|
|
33266
|
+
}
|
|
33267
|
+
const record2 = localAgentRecordFromRelayAgentOverride(agentId, override);
|
|
33268
|
+
const status = localAgentStatusFromRecord(agentId, record2, localAgentStatusSource(agentId, overrides));
|
|
33269
|
+
await stopLocalAgent(agentId).catch(() => null);
|
|
33270
|
+
retired.push({
|
|
33271
|
+
...status,
|
|
33272
|
+
isOnline: false
|
|
33273
|
+
});
|
|
33274
|
+
delete overrides[agentId];
|
|
33275
|
+
}
|
|
33276
|
+
if (retired.length > 0) {
|
|
33277
|
+
await writeRelayAgentOverrides(overrides);
|
|
33278
|
+
}
|
|
33279
|
+
return retired;
|
|
33280
|
+
}
|
|
33281
|
+
async function pruneOneTimeLocalAgentCards(input = {}) {
|
|
33282
|
+
const now = input.now ?? Date.now();
|
|
33283
|
+
const maxAgeMs = Math.max(0, input.maxAgeMs ?? DEFAULT_ONE_TIME_LOCAL_AGENT_CARD_TTL_MS);
|
|
33284
|
+
const maxCount = Math.max(0, input.maxCount ?? DEFAULT_ONE_TIME_LOCAL_AGENT_CARD_RETAIN);
|
|
33285
|
+
const excluded = new Set(input.excludeAgentIds ?? []);
|
|
33286
|
+
const overrides = await readRelayAgentOverrides();
|
|
33287
|
+
const candidates = Object.entries(overrides).filter(([agentId, override]) => !excluded.has(agentId) && oneTimeCardMatchesScope(agentId, override, input)).map(([agentId, override]) => ({
|
|
33288
|
+
agentId,
|
|
33289
|
+
override,
|
|
33290
|
+
lifecycle: normalizeLocalAgentCardLifecycle(override.card)
|
|
33291
|
+
})).sort((left, right) => oneTimeCardCreatedAt(right.lifecycle) - oneTimeCardCreatedAt(left.lifecycle) || left.agentId.localeCompare(right.agentId));
|
|
33292
|
+
const retireIds = new Set;
|
|
33293
|
+
for (const candidate of candidates) {
|
|
33294
|
+
if (shouldPruneOneTimeCard(candidate.lifecycle, now, maxAgeMs)) {
|
|
33295
|
+
retireIds.add(candidate.agentId);
|
|
33296
|
+
}
|
|
33297
|
+
}
|
|
33298
|
+
const retained = candidates.filter((candidate) => !retireIds.has(candidate.agentId));
|
|
33299
|
+
for (const candidate of retained.slice(maxCount)) {
|
|
33300
|
+
retireIds.add(candidate.agentId);
|
|
33301
|
+
}
|
|
33302
|
+
const retired = await retireLocalAgentOverrides({ ...overrides }, retireIds);
|
|
33303
|
+
return {
|
|
33304
|
+
inspected: candidates.length,
|
|
33305
|
+
remaining: Math.max(0, candidates.length - retired.length),
|
|
33306
|
+
retired
|
|
33307
|
+
};
|
|
33308
|
+
}
|
|
33309
|
+
async function retireConsumedOneTimeLocalAgentCards(input) {
|
|
33310
|
+
const conversationId = input.conversationId.trim();
|
|
33311
|
+
const actorId = input.actorId.trim();
|
|
33312
|
+
if (!conversationId || !actorId) {
|
|
33313
|
+
return [];
|
|
33314
|
+
}
|
|
33315
|
+
const participants = new Set(input.participantIds.map((entry) => entry.trim()).filter(Boolean));
|
|
33316
|
+
if (participants.size === 0) {
|
|
33317
|
+
return [];
|
|
33318
|
+
}
|
|
33319
|
+
const overrides = await readRelayAgentOverrides();
|
|
33320
|
+
const retireIds = new Set;
|
|
33321
|
+
for (const [agentId, override] of Object.entries(overrides)) {
|
|
33322
|
+
if (!participants.has(agentId)) {
|
|
33323
|
+
continue;
|
|
33324
|
+
}
|
|
33325
|
+
const lifecycle2 = normalizeLocalAgentCardLifecycle(override.card);
|
|
33326
|
+
if (lifecycle2?.kind !== "one_time") {
|
|
33327
|
+
continue;
|
|
33328
|
+
}
|
|
33329
|
+
if (lifecycle2.createdById && lifecycle2.createdById === actorId) {
|
|
33330
|
+
continue;
|
|
33331
|
+
}
|
|
33332
|
+
if (agentId === actorId) {
|
|
33333
|
+
continue;
|
|
33334
|
+
}
|
|
33335
|
+
retireIds.add(agentId);
|
|
33336
|
+
}
|
|
33337
|
+
return retireLocalAgentOverrides({ ...overrides }, retireIds);
|
|
33338
|
+
}
|
|
32408
33339
|
function buildCodexAgentSessionOptions(agentName, record2, systemPrompt) {
|
|
32409
33340
|
const permissionPosture = compileCodexPermissionProfile(record2.permissionProfile);
|
|
32410
33341
|
return {
|
|
@@ -32435,6 +33366,22 @@ function endpointMetadataString(endpoint, key) {
|
|
|
32435
33366
|
const value = endpoint.metadata?.[key];
|
|
32436
33367
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
32437
33368
|
}
|
|
33369
|
+
function endpointMetadataStringArray(endpoint, key) {
|
|
33370
|
+
const value = endpoint.metadata?.[key];
|
|
33371
|
+
if (Array.isArray(value)) {
|
|
33372
|
+
return value.map((entry) => String(entry).trim()).filter(Boolean);
|
|
33373
|
+
}
|
|
33374
|
+
if (typeof value === "string" && value.trim()) {
|
|
33375
|
+
return [value.trim()];
|
|
33376
|
+
}
|
|
33377
|
+
return [];
|
|
33378
|
+
}
|
|
33379
|
+
function attachedCodexEndpointLaunchArgs(endpoint) {
|
|
33380
|
+
return applyRequestedRuntimeOptionsToLaunchArgs("codex", endpointMetadataStringArray(endpoint, "launchArgs"), {
|
|
33381
|
+
model: endpointMetadataString(endpoint, "model"),
|
|
33382
|
+
reasoningEffort: endpointMetadataString(endpoint, "reasoningEffort")
|
|
33383
|
+
});
|
|
33384
|
+
}
|
|
32438
33385
|
function endpointInvocationPrompt(endpoint, agentName, invocation) {
|
|
32439
33386
|
const source = endpointMetadataString(endpoint, "source");
|
|
32440
33387
|
const externalSource = endpointMetadataString(endpoint, "externalSource");
|
|
@@ -32472,7 +33419,8 @@ function attachedLocalSessionSystemPrompt(endpoint) {
|
|
|
32472
33419
|
}
|
|
32473
33420
|
function buildCodexEndpointSessionOptions(endpoint) {
|
|
32474
33421
|
const agentName = endpointAgentName(endpoint);
|
|
32475
|
-
const
|
|
33422
|
+
const ownsSessionThread = endpoint.metadata?.source === "scoutbot";
|
|
33423
|
+
const threadId = ownsSessionThread ? undefined : endpointMetadataString(endpoint, "threadId") ?? endpointMetadataString(endpoint, "externalSessionId") ?? endpoint.sessionId ?? undefined;
|
|
32476
33424
|
return {
|
|
32477
33425
|
agentName,
|
|
32478
33426
|
sessionId: endpointRuntimeInstanceId(endpoint),
|
|
@@ -32480,9 +33428,9 @@ function buildCodexEndpointSessionOptions(endpoint) {
|
|
|
32480
33428
|
systemPrompt: attachedLocalSessionSystemPrompt(endpoint),
|
|
32481
33429
|
runtimeDirectory: relayAgentRuntimeDirectory(agentName),
|
|
32482
33430
|
logsDirectory: relayAgentLogsDirectory(agentName),
|
|
32483
|
-
launchArgs:
|
|
33431
|
+
launchArgs: attachedCodexEndpointLaunchArgs(endpoint),
|
|
32484
33432
|
threadId,
|
|
32485
|
-
requireExistingThread: Boolean(threadId)
|
|
33433
|
+
requireExistingThread: Boolean(threadId) && !ownsSessionThread
|
|
32486
33434
|
};
|
|
32487
33435
|
}
|
|
32488
33436
|
function buildClaudeEndpointSessionOptions(endpoint) {
|
|
@@ -32659,7 +33607,7 @@ function buildScoutReplyContextPrompt(context) {
|
|
|
32659
33607
|
] : [
|
|
32660
33608
|
"> Do not publish a separate acknowledgement or progress update through Scout for this request.",
|
|
32661
33609
|
"> Your final assistant message will be delivered back through the Scout broker.",
|
|
32662
|
-
"> Do not call `messages_reply`, `scout_reply`, `scout send`, `messages_send`, or `
|
|
33610
|
+
"> Do not call `messages_reply`, `scout_reply`, `scout send`, `messages_send`, or `ask` to answer this request."
|
|
32663
33611
|
];
|
|
32664
33612
|
const header = [
|
|
32665
33613
|
"<!-- SCOUT BROKER REPLY MODE -->",
|
|
@@ -32770,35 +33718,228 @@ function stripLocalAgentReplyMetadata(body, flightId, asker) {
|
|
|
32770
33718
|
async function sendLocalAgentPrompt(agentName, record2, prompt) {
|
|
32771
33719
|
const harness = normalizeLocalAgentHarness(record2.harness);
|
|
32772
33720
|
if (harness === "codex") {
|
|
32773
|
-
const promptPipe =
|
|
33721
|
+
const promptPipe = join19(relayAgentRuntimeDirectory(agentName), "prompt.pipe");
|
|
32774
33722
|
await writeFile7(promptPipe, prompt.trim() + "\x00");
|
|
32775
33723
|
return;
|
|
32776
33724
|
}
|
|
32777
|
-
sendTmuxPrompt(record2.tmuxSession, prompt,
|
|
33725
|
+
await sendTmuxPrompt(record2.tmuxSession, prompt, buildTmuxDispatchStrategy(harness, prompt));
|
|
33726
|
+
}
|
|
33727
|
+
var TMUX_PASTE_DRAIN_MS = 150;
|
|
33728
|
+
var TMUX_VERIFY_FIRST_SAMPLE_MS = 250;
|
|
33729
|
+
var TMUX_VERIFY_SECOND_SAMPLE_MS = 750;
|
|
33730
|
+
var TMUX_VERIFY_RETRY_SAMPLE_MS = 400;
|
|
33731
|
+
var TMUX_CAPTURE_TAIL_LINES = 20;
|
|
33732
|
+
var TMUX_READY_TIMEOUT_MS = 20000;
|
|
33733
|
+
var TMUX_READY_POLL_MS = 250;
|
|
33734
|
+
var TMUX_READY_TAIL_LINES = 80;
|
|
33735
|
+
function buildTmuxDispatchStrategy(harness, prompt) {
|
|
33736
|
+
const promptAbsentFromTail = (paneTail) => !tmuxPaneTailContainsPromptFragment(paneTail, prompt);
|
|
33737
|
+
if (harness === "pi") {
|
|
33738
|
+
return { submit: ["Enter"], verify: promptAbsentFromTail };
|
|
33739
|
+
}
|
|
33740
|
+
return { submit: ["Enter"], verify: promptAbsentFromTail };
|
|
32778
33741
|
}
|
|
32779
|
-
function sendTmuxPrompt(sessionName, prompt,
|
|
33742
|
+
async function sendTmuxPrompt(sessionName, prompt, strategy) {
|
|
33743
|
+
const effectiveStrategy = strategy ?? buildTmuxDispatchStrategy("claude", prompt);
|
|
32780
33744
|
const bufferName = `openscout-prompt-${randomUUID2()}`;
|
|
33745
|
+
let bufferOwned = true;
|
|
32781
33746
|
try {
|
|
33747
|
+
if (effectiveStrategy.pre && effectiveStrategy.pre.length > 0) {
|
|
33748
|
+
execFileSync3("tmux", ["send-keys", "-t", sessionName, ...effectiveStrategy.pre], { stdio: "pipe" });
|
|
33749
|
+
}
|
|
32782
33750
|
execFileSync3("tmux", ["load-buffer", "-b", bufferName, "-"], {
|
|
32783
33751
|
stdio: "pipe",
|
|
32784
33752
|
input: prompt
|
|
32785
33753
|
});
|
|
32786
|
-
execFileSync3("tmux",
|
|
33754
|
+
execFileSync3("tmux", buildTmuxPasteBufferArgs(bufferName, sessionName), {
|
|
32787
33755
|
stdio: "pipe"
|
|
32788
33756
|
});
|
|
32789
|
-
|
|
33757
|
+
bufferOwned = false;
|
|
33758
|
+
await tmuxDispatchSleep(TMUX_PASTE_DRAIN_MS);
|
|
33759
|
+
execFileSync3("tmux", ["send-keys", "-t", sessionName, ...effectiveStrategy.submit], { stdio: "pipe" });
|
|
33760
|
+
if (await dispatchVerifiedAfter(sessionName, effectiveStrategy, TMUX_VERIFY_FIRST_SAMPLE_MS)) {
|
|
33761
|
+
return { submitted: true, retries: 0 };
|
|
33762
|
+
}
|
|
33763
|
+
if (await dispatchVerifiedAfter(sessionName, effectiveStrategy, TMUX_VERIFY_SECOND_SAMPLE_MS)) {
|
|
33764
|
+
return { submitted: true, retries: 0 };
|
|
33765
|
+
}
|
|
33766
|
+
execFileSync3("tmux", ["send-keys", "-t", sessionName, "Enter"], { stdio: "pipe" });
|
|
33767
|
+
if (await dispatchVerifiedAfter(sessionName, effectiveStrategy, TMUX_VERIFY_RETRY_SAMPLE_MS)) {
|
|
33768
|
+
return { submitted: true, retries: 1 };
|
|
33769
|
+
}
|
|
33770
|
+
throw new DispatchStalledError({
|
|
33771
|
+
sessionName,
|
|
33772
|
+
paneTail: captureTmuxPaneTail(sessionName, TMUX_CAPTURE_TAIL_LINES).slice(0, 2000),
|
|
33773
|
+
retries: 1
|
|
33774
|
+
});
|
|
32790
33775
|
} catch (error48) {
|
|
32791
|
-
|
|
32792
|
-
|
|
32793
|
-
|
|
33776
|
+
if (bufferOwned) {
|
|
33777
|
+
try {
|
|
33778
|
+
execFileSync3("tmux", ["delete-buffer", "-b", bufferName], { stdio: "pipe" });
|
|
33779
|
+
} catch {}
|
|
33780
|
+
}
|
|
32794
33781
|
throw error48;
|
|
32795
33782
|
}
|
|
32796
33783
|
}
|
|
32797
|
-
function
|
|
32798
|
-
|
|
32799
|
-
|
|
33784
|
+
function buildTmuxPasteBufferArgs(bufferName, sessionName) {
|
|
33785
|
+
return ["paste-buffer", "-dpr", "-b", bufferName, "-t", sessionName];
|
|
33786
|
+
}
|
|
33787
|
+
function tmuxDispatchSleep(ms) {
|
|
33788
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
33789
|
+
}
|
|
33790
|
+
async function dispatchVerifiedAfter(sessionName, strategy, delayMs) {
|
|
33791
|
+
await tmuxDispatchSleep(delayMs);
|
|
33792
|
+
const paneTail = captureTmuxPaneTail(sessionName, TMUX_CAPTURE_TAIL_LINES);
|
|
33793
|
+
if (!paneTail) {
|
|
33794
|
+
return true;
|
|
32800
33795
|
}
|
|
32801
|
-
return
|
|
33796
|
+
return strategy.verify(paneTail);
|
|
33797
|
+
}
|
|
33798
|
+
function captureTmuxPaneTail(sessionName, lines) {
|
|
33799
|
+
try {
|
|
33800
|
+
return execFileSync3("tmux", ["capture-pane", "-p", "-t", sessionName, "-S", `-${lines}`, "-E", "-"], { stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" });
|
|
33801
|
+
} catch {
|
|
33802
|
+
return "";
|
|
33803
|
+
}
|
|
33804
|
+
}
|
|
33805
|
+
async function waitForTmuxHarnessReady(sessionName, harness) {
|
|
33806
|
+
if (harness !== "claude") {
|
|
33807
|
+
return;
|
|
33808
|
+
}
|
|
33809
|
+
const deadline = Date.now() + TMUX_READY_TIMEOUT_MS;
|
|
33810
|
+
let paneTail = "";
|
|
33811
|
+
while (Date.now() < deadline) {
|
|
33812
|
+
if (!isLocalAgentSessionAlive(sessionName)) {
|
|
33813
|
+
throw new Error(`tmux session ${sessionName} exited before Claude Code was ready.`);
|
|
33814
|
+
}
|
|
33815
|
+
paneTail = captureTmuxPaneTail(sessionName, TMUX_READY_TAIL_LINES);
|
|
33816
|
+
if (tmuxPaneTailShowsReadyComposer(paneTail)) {
|
|
33817
|
+
return;
|
|
33818
|
+
}
|
|
33819
|
+
await tmuxDispatchSleep(TMUX_READY_POLL_MS);
|
|
33820
|
+
}
|
|
33821
|
+
const tail = stripTerminalControlSequences(paneTail).trim().split(/\r?\n/).slice(-20).join(`
|
|
33822
|
+
`).trim();
|
|
33823
|
+
throw new Error(`tmux session ${sessionName} did not show a ready Claude Code composer within ${TMUX_READY_TIMEOUT_MS}ms.` + (tail ? `
|
|
33824
|
+
Recent pane tail:
|
|
33825
|
+
${tail}` : ""));
|
|
33826
|
+
}
|
|
33827
|
+
function tmuxPaneTailShowsReadyComposer(paneTail) {
|
|
33828
|
+
const cleanedTail = stripTerminalControlSequences(paneTail);
|
|
33829
|
+
const lines = cleanedTail.split(/\r?\n/);
|
|
33830
|
+
const anchor = findActiveTmuxComposerAnchor(lines);
|
|
33831
|
+
if (!anchor) {
|
|
33832
|
+
return false;
|
|
33833
|
+
}
|
|
33834
|
+
const afterComposerLines = [];
|
|
33835
|
+
for (const line of lines.slice(anchor.index + 1)) {
|
|
33836
|
+
if (isTmuxComposerBoundary(line)) {
|
|
33837
|
+
break;
|
|
33838
|
+
}
|
|
33839
|
+
afterComposerLines.push(line);
|
|
33840
|
+
}
|
|
33841
|
+
return !tmuxPaneTailShowsHarnessActivity(afterComposerLines.join(`
|
|
33842
|
+
`));
|
|
33843
|
+
}
|
|
33844
|
+
function tmuxPaneTailContainsPromptFragment(paneTail, prompt) {
|
|
33845
|
+
const cleanedTail = stripTerminalControlSequences(paneTail);
|
|
33846
|
+
const composerText = extractActiveTmuxComposerText(cleanedTail);
|
|
33847
|
+
if (composerText !== null) {
|
|
33848
|
+
return textContainsPromptFragment(composerText, prompt);
|
|
33849
|
+
}
|
|
33850
|
+
if (tmuxPaneTailShowsHarnessActivity(cleanedTail)) {
|
|
33851
|
+
return false;
|
|
33852
|
+
}
|
|
33853
|
+
return textContainsPromptFragment(cleanedTail, prompt);
|
|
33854
|
+
}
|
|
33855
|
+
function textContainsPromptFragment(haystack, prompt) {
|
|
33856
|
+
const normalizedTail = haystack.replace(/\s+/g, " ").trim();
|
|
33857
|
+
if (!normalizedTail)
|
|
33858
|
+
return false;
|
|
33859
|
+
const normalizedPrompt = prompt.replace(/\s+/g, " ").trim();
|
|
33860
|
+
if (normalizedPrompt.length < 24) {
|
|
33861
|
+
return normalizedPrompt.length > 0 && normalizedTail.includes(normalizedPrompt);
|
|
33862
|
+
}
|
|
33863
|
+
const midpoint = Math.floor(normalizedPrompt.length / 2);
|
|
33864
|
+
const windows = [
|
|
33865
|
+
normalizedPrompt.slice(0, 40),
|
|
33866
|
+
normalizedPrompt.slice(Math.max(0, midpoint - 20), midpoint + 20),
|
|
33867
|
+
normalizedPrompt.slice(Math.max(0, normalizedPrompt.length - 40))
|
|
33868
|
+
];
|
|
33869
|
+
return windows.some((w) => w.length >= 24 && normalizedTail.includes(w));
|
|
33870
|
+
}
|
|
33871
|
+
function stripTerminalControlSequences(value) {
|
|
33872
|
+
return value.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
33873
|
+
}
|
|
33874
|
+
function findActiveTmuxComposerAnchor(lines) {
|
|
33875
|
+
const inlineComposerIndex = findLastIndex(lines, (line) => /^\s*[\u276F\u203A]\s*/.test(line));
|
|
33876
|
+
const boxedComposerIndex = findLastIndex(lines, (line) => /^\s*[\u2502\u2503]\s*[>\u276F]\s*/.test(line));
|
|
33877
|
+
if (inlineComposerIndex < 0 && boxedComposerIndex < 0) {
|
|
33878
|
+
return null;
|
|
33879
|
+
}
|
|
33880
|
+
if (inlineComposerIndex > boxedComposerIndex) {
|
|
33881
|
+
return { index: inlineComposerIndex, kind: "inline" };
|
|
33882
|
+
}
|
|
33883
|
+
return { index: boxedComposerIndex, kind: "boxed" };
|
|
33884
|
+
}
|
|
33885
|
+
function extractActiveTmuxComposerText(paneTail) {
|
|
33886
|
+
const lines = paneTail.split(/\r?\n/);
|
|
33887
|
+
const anchor = findActiveTmuxComposerAnchor(lines);
|
|
33888
|
+
if (!anchor) {
|
|
33889
|
+
return null;
|
|
33890
|
+
}
|
|
33891
|
+
return anchor.kind === "inline" ? collectInlineComposerText(lines, anchor.index) : collectBoxedComposerText(lines, anchor.index);
|
|
33892
|
+
}
|
|
33893
|
+
function findLastIndex(items, predicate) {
|
|
33894
|
+
for (let index = items.length - 1;index >= 0; index -= 1) {
|
|
33895
|
+
if (predicate(items[index])) {
|
|
33896
|
+
return index;
|
|
33897
|
+
}
|
|
33898
|
+
}
|
|
33899
|
+
return -1;
|
|
33900
|
+
}
|
|
33901
|
+
function collectInlineComposerText(lines, startIndex) {
|
|
33902
|
+
const collected = [lines[startIndex].replace(/^\s*[\u276F\u203A]\s*/, "")];
|
|
33903
|
+
for (let index = startIndex + 1;index < lines.length; index += 1) {
|
|
33904
|
+
const line = lines[index];
|
|
33905
|
+
if (isTmuxComposerBoundary(line)) {
|
|
33906
|
+
break;
|
|
33907
|
+
}
|
|
33908
|
+
collected.push(line);
|
|
33909
|
+
}
|
|
33910
|
+
return collected.join(" ").trim();
|
|
33911
|
+
}
|
|
33912
|
+
function collectBoxedComposerText(lines, startIndex) {
|
|
33913
|
+
const collected = [];
|
|
33914
|
+
for (let index = startIndex;index < lines.length; index += 1) {
|
|
33915
|
+
const line = lines[index];
|
|
33916
|
+
if (index > startIndex && isTmuxComposerBoundary(line)) {
|
|
33917
|
+
break;
|
|
33918
|
+
}
|
|
33919
|
+
if (!/^\s*[\u2502\u2503]/.test(line)) {
|
|
33920
|
+
if (isTmuxComposerBoundary(line)) {
|
|
33921
|
+
break;
|
|
33922
|
+
}
|
|
33923
|
+
collected.push(line);
|
|
33924
|
+
continue;
|
|
33925
|
+
}
|
|
33926
|
+
const content = line.replace(/^\s*[\u2502\u2503]\s*/, "").replace(/\s*[\u2502\u2503]\s*$/, "").replace(index === startIndex ? /^[>\u276F]\s*/ : /^/, "");
|
|
33927
|
+
collected.push(content);
|
|
33928
|
+
}
|
|
33929
|
+
return collected.join(" ").trim();
|
|
33930
|
+
}
|
|
33931
|
+
function isTmuxComposerBoundary(line) {
|
|
33932
|
+
const trimmed = line.trim();
|
|
33933
|
+
if (!trimmed) {
|
|
33934
|
+
return false;
|
|
33935
|
+
}
|
|
33936
|
+
if (/^[\u2500\u2501\u2550\u256D\u256E\u2570\u256F\u250C\u2510\u2514\u2518\u2554\u2557\u255A\u255D\u255F\u2562\u2560\u2563\u256A\u256B\u256C\u2569\u2566\u2564\u2567\u254C\u254D\u254E\u254F\s]+$/.test(trimmed)) {
|
|
33937
|
+
return true;
|
|
33938
|
+
}
|
|
33939
|
+
return /^--\s*(?:INSERT|NORMAL)\s*--/.test(trimmed) || /^(?:Opus|Sonnet|Haiku|Claude|Codex|GPT)\b/.test(trimmed);
|
|
33940
|
+
}
|
|
33941
|
+
function tmuxPaneTailShowsHarnessActivity(paneTail) {
|
|
33942
|
+
return /(?:^|\n)\s*(?:[\u23FA\u25CF\u273D\u2722\u273B\u23BF]|Bash\(|Read\(|Edit\(|Write\(|Grep\(|Glob\(|TodoWrite\()/.test(paneTail);
|
|
32802
33943
|
}
|
|
32803
33944
|
function shellQuoteArguments(args) {
|
|
32804
33945
|
return args.map((arg) => JSON.stringify(arg)).join(" ");
|
|
@@ -32810,10 +33951,10 @@ function buildLocalAgentLaunchCommand(agentName, record2, projectPath, promptFil
|
|
|
32810
33951
|
const harness = normalizeLocalAgentHarness(record2.harness);
|
|
32811
33952
|
const extraArgs = shellQuoteArguments(harness === "claude" ? normalizeClaudeRuntimeLaunchArgs(record2.launchArgs) : normalizeLaunchArgsForHarness(harness, record2.launchArgs));
|
|
32812
33953
|
if (harness === "codex") {
|
|
32813
|
-
return `exec bash ${JSON.stringify(workerScript ??
|
|
33954
|
+
return `exec bash ${JSON.stringify(workerScript ?? join19(relayAgentRuntimeDirectory(agentName), "codex-worker.sh"))}`;
|
|
32814
33955
|
}
|
|
32815
33956
|
if (harness === "pi") {
|
|
32816
|
-
const sessionDir =
|
|
33957
|
+
const sessionDir = join19(relayAgentRuntimeDirectory(agentName), "pi-sessions");
|
|
32817
33958
|
return [
|
|
32818
33959
|
"pi",
|
|
32819
33960
|
`--append-system-prompt "$(cat ${JSON.stringify(promptFile)})"`,
|
|
@@ -32833,6 +33974,11 @@ function buildLocalAgentLaunchCommand(agentName, record2, projectPath, promptFil
|
|
|
32833
33974
|
function buildTmuxLaunchShellCommand(launchScript) {
|
|
32834
33975
|
return `exec bash ${JSON.stringify(launchScript)}`;
|
|
32835
33976
|
}
|
|
33977
|
+
function killAgentSession(sessionName) {
|
|
33978
|
+
try {
|
|
33979
|
+
execSync(`tmux kill-session -t ${JSON.stringify(sessionName)}`, { stdio: "pipe" });
|
|
33980
|
+
} catch {}
|
|
33981
|
+
}
|
|
32836
33982
|
function areHarnessBinariesAvailable(record2) {
|
|
32837
33983
|
const harness = normalizeLocalAgentHarness(record2.harness);
|
|
32838
33984
|
const binaries = new Set;
|
|
@@ -32878,7 +34024,7 @@ async function ensureLocalAgentOnline(agentName, record2) {
|
|
|
32878
34024
|
await mkdir7(agentRuntimeDir, { recursive: true });
|
|
32879
34025
|
await mkdir7(logsDir, { recursive: true });
|
|
32880
34026
|
if (normalizedRecord.transport === "codex_app_server") {
|
|
32881
|
-
await writeFile7(
|
|
34027
|
+
await writeFile7(join19(agentRuntimeDir, "prompt.txt"), systemPrompt);
|
|
32882
34028
|
await ensureCodexAppServerAgentOnline(buildCodexAgentSessionOptions(agentName, normalizedRecord, systemPrompt));
|
|
32883
34029
|
const registry3 = await readLocalAgentRegistry();
|
|
32884
34030
|
registry3[agentName] = {
|
|
@@ -32890,7 +34036,7 @@ async function ensureLocalAgentOnline(agentName, record2) {
|
|
|
32890
34036
|
return registry3[agentName];
|
|
32891
34037
|
}
|
|
32892
34038
|
if (normalizedRecord.transport === "claude_stream_json") {
|
|
32893
|
-
await writeFile7(
|
|
34039
|
+
await writeFile7(join19(agentRuntimeDir, "prompt.txt"), systemPrompt);
|
|
32894
34040
|
await ensureClaudeStreamJsonAgentOnline(buildClaudeAgentSessionOptions(agentName, normalizedRecord, systemPrompt));
|
|
32895
34041
|
const registry3 = await readLocalAgentRegistry();
|
|
32896
34042
|
registry3[agentName] = {
|
|
@@ -32903,17 +34049,17 @@ async function ensureLocalAgentOnline(agentName, record2) {
|
|
|
32903
34049
|
}
|
|
32904
34050
|
const initialMessage = buildLocalAgentInitialMessage(projectName, agentName);
|
|
32905
34051
|
const bootstrapPrompt = buildLocalAgentBootstrapPrompt(normalizeLocalAgentHarness(normalizedRecord.harness), systemPrompt, initialMessage);
|
|
32906
|
-
const queueDirectory =
|
|
32907
|
-
const processingDirectory =
|
|
32908
|
-
const processedDirectory =
|
|
32909
|
-
const promptFile =
|
|
32910
|
-
const initialFile =
|
|
32911
|
-
const launchScript =
|
|
32912
|
-
const workerScript =
|
|
32913
|
-
const codexSessionIdFile =
|
|
32914
|
-
const stateFile =
|
|
32915
|
-
const stdoutLogFile =
|
|
32916
|
-
const stderrLogFile =
|
|
34052
|
+
const queueDirectory = join19(agentRuntimeDir, "queue");
|
|
34053
|
+
const processingDirectory = join19(queueDirectory, "processing");
|
|
34054
|
+
const processedDirectory = join19(queueDirectory, "processed");
|
|
34055
|
+
const promptFile = join19(agentRuntimeDir, "prompt.txt");
|
|
34056
|
+
const initialFile = join19(agentRuntimeDir, "initial.txt");
|
|
34057
|
+
const launchScript = join19(agentRuntimeDir, "launch.sh");
|
|
34058
|
+
const workerScript = join19(agentRuntimeDir, "codex-worker.sh");
|
|
34059
|
+
const codexSessionIdFile = join19(agentRuntimeDir, "codex-session-id.txt");
|
|
34060
|
+
const stateFile = join19(agentRuntimeDir, "state.json");
|
|
34061
|
+
const stdoutLogFile = join19(logsDir, "stdout.log");
|
|
34062
|
+
const stderrLogFile = join19(logsDir, "stderr.log");
|
|
32917
34063
|
await writeFile7(promptFile, systemPrompt);
|
|
32918
34064
|
await writeFile7(initialFile, bootstrapPrompt);
|
|
32919
34065
|
await writeFile7(stderrLogFile, "");
|
|
@@ -32978,11 +34124,17 @@ async function ensureLocalAgentOnline(agentName, record2) {
|
|
|
32978
34124
|
await new Promise((resolve8) => setTimeout(resolve8, 100));
|
|
32979
34125
|
}
|
|
32980
34126
|
if (!isLocalAgentSessionAlive(normalizedRecord.tmuxSession)) {
|
|
32981
|
-
const stderrTail =
|
|
34127
|
+
const stderrTail = existsSync14(stderrLogFile) ? readFileSync7(stderrLogFile, "utf8").trim().split(/\r?\n/).slice(-10).join(`
|
|
32982
34128
|
`).trim() : "";
|
|
32983
34129
|
throw new Error(stderrTail ? `Relay agent ${agentName} failed to stay online:
|
|
32984
34130
|
${stderrTail}` : `Relay agent ${agentName} failed to stay online.`);
|
|
32985
34131
|
}
|
|
34132
|
+
try {
|
|
34133
|
+
await waitForTmuxHarnessReady(normalizedRecord.tmuxSession, normalizeLocalAgentHarness(normalizedRecord.harness));
|
|
34134
|
+
} catch (error48) {
|
|
34135
|
+
killAgentSession(normalizedRecord.tmuxSession);
|
|
34136
|
+
throw error48;
|
|
34137
|
+
}
|
|
32986
34138
|
const registry2 = await readLocalAgentRegistry();
|
|
32987
34139
|
registry2[agentName] = {
|
|
32988
34140
|
...normalizedRecord,
|
|
@@ -32992,12 +34144,249 @@ ${stderrTail}` : `Relay agent ${agentName} failed to stay online.`);
|
|
|
32992
34144
|
await writeLocalAgentRegistry(registry2);
|
|
32993
34145
|
return registry2[agentName];
|
|
32994
34146
|
}
|
|
34147
|
+
async function startLocalAgent(input) {
|
|
34148
|
+
const projectPath = normalizeProjectPath2(input.projectPath);
|
|
34149
|
+
const preferredHarness = input.harness ? normalizeLocalAgentHarness(input.harness) : undefined;
|
|
34150
|
+
const currentDirectory = input.currentDirectory ?? projectPath;
|
|
34151
|
+
const effectiveCwd = input.cwdOverride ? normalizeProjectPath2(input.cwdOverride) : undefined;
|
|
34152
|
+
const shouldEnsureOnline = input.ensureOnline !== false;
|
|
34153
|
+
const requestedPermissionProfile = parseScoutPermissionProfile(input.permissionProfile);
|
|
34154
|
+
const cardLifecycle = normalizeLocalAgentCardLifecycle(input.card);
|
|
34155
|
+
const requestedDefinitionId = input.agentName?.trim() ? normalizeAgentSelectorSegment(input.agentName.trim()) : "";
|
|
34156
|
+
if (input.agentName?.trim() && !requestedDefinitionId) {
|
|
34157
|
+
throw new Error(`Invalid agent name "${input.agentName}".`);
|
|
34158
|
+
}
|
|
34159
|
+
const overrides = await readRelayAgentOverrides();
|
|
34160
|
+
const findMatchForRoot = (root) => {
|
|
34161
|
+
let fallback = null;
|
|
34162
|
+
for (const [id, override] of Object.entries(overrides)) {
|
|
34163
|
+
if (BUILT_IN_AGENT_DEFINITION_IDS.has(id))
|
|
34164
|
+
continue;
|
|
34165
|
+
if (!override.projectRoot)
|
|
34166
|
+
continue;
|
|
34167
|
+
if (normalizeProjectPath2(override.projectRoot) !== root)
|
|
34168
|
+
continue;
|
|
34169
|
+
if (requestedDefinitionId && override.definitionId === requestedDefinitionId) {
|
|
34170
|
+
return { agentId: id, override };
|
|
34171
|
+
}
|
|
34172
|
+
if (!fallback)
|
|
34173
|
+
fallback = { agentId: id, override };
|
|
34174
|
+
}
|
|
34175
|
+
return fallback;
|
|
34176
|
+
};
|
|
34177
|
+
let matched = findMatchForRoot(projectPath);
|
|
34178
|
+
let projectRoot = projectPath;
|
|
34179
|
+
if (!matched) {
|
|
34180
|
+
const resolved = await findNearestProjectRoot(projectPath);
|
|
34181
|
+
if (resolved && resolved !== projectPath) {
|
|
34182
|
+
projectRoot = normalizeProjectPath2(resolved);
|
|
34183
|
+
matched = findMatchForRoot(projectRoot);
|
|
34184
|
+
}
|
|
34185
|
+
}
|
|
34186
|
+
let matchingAgentId = matched?.agentId;
|
|
34187
|
+
let matchingOverride = matched?.override;
|
|
34188
|
+
let coldProjectConfigPath = null;
|
|
34189
|
+
let targetAgentId;
|
|
34190
|
+
let coldProjectConfig = null;
|
|
34191
|
+
if (!matchingOverride) {
|
|
34192
|
+
const ensuredProject = await ensureProjectConfigForDirectory(projectPath);
|
|
34193
|
+
projectRoot = ensuredProject.projectRoot ?? projectPath;
|
|
34194
|
+
coldProjectConfigPath = ensuredProject.projectConfigPath ?? null;
|
|
34195
|
+
coldProjectConfig = ensuredProject.config ?? null;
|
|
34196
|
+
matched = findMatchForRoot(projectRoot);
|
|
34197
|
+
matchingAgentId = matched?.agentId;
|
|
34198
|
+
matchingOverride = matched?.override;
|
|
34199
|
+
}
|
|
34200
|
+
if (!matchingOverride) {
|
|
34201
|
+
const configDefinitionId = coldProjectConfig?.agent?.id?.trim() ? normalizeAgentSelectorSegment(coldProjectConfig.agent.id.trim()) : "";
|
|
34202
|
+
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename9(projectRoot)) || "agent";
|
|
34203
|
+
const configDisplayName = coldProjectConfig?.agent?.displayName?.trim() || "";
|
|
34204
|
+
const operatorAugmentDefaults = operatorAugmentDefaultsForDefinitionId(definitionId);
|
|
34205
|
+
const effectiveDisplayName = input.displayName || operatorAugmentDefaults?.displayName || configDisplayName || titleCaseLocalAgentName(definitionId);
|
|
34206
|
+
const instance = buildRelayAgentInstance(definitionId, projectRoot);
|
|
34207
|
+
const configDefaultHarness = coldProjectConfig?.agent?.runtime?.defaultHarness;
|
|
34208
|
+
const effectiveHarness = normalizeManagedHarness2(preferredHarness ?? configDefaultHarness, "claude");
|
|
34209
|
+
const transport = normalizeLocalAgentTransport(undefined, effectiveHarness);
|
|
34210
|
+
const sessionId = normalizeTmuxSessionName2(undefined, `${instance.id}-${effectiveHarness}`);
|
|
34211
|
+
const launchArgs = applyRequestedRuntimeOptionsToLaunchArgs(effectiveHarness, [], {
|
|
34212
|
+
model: input.model,
|
|
34213
|
+
reasoningEffort: input.reasoningEffort
|
|
34214
|
+
});
|
|
34215
|
+
const existingForInstance = overrides[instance.id];
|
|
34216
|
+
if (existingForInstance && normalizeProjectPath2(existingForInstance.projectRoot) !== projectRoot) {
|
|
34217
|
+
throw new Error(`Another agent is already registered as ${instance.id} at ${existingForInstance.projectRoot}. ` + `Two clones of the same project on the same branch cannot both register here; ` + `rename one of the checkouts or switch its branch before running scout up.`);
|
|
34218
|
+
}
|
|
34219
|
+
overrides[instance.id] = {
|
|
34220
|
+
agentId: instance.id,
|
|
34221
|
+
definitionId,
|
|
34222
|
+
displayName: effectiveDisplayName,
|
|
34223
|
+
projectName: basename9(projectRoot),
|
|
34224
|
+
projectRoot,
|
|
34225
|
+
projectConfigPath: coldProjectConfigPath,
|
|
34226
|
+
source: "manual",
|
|
34227
|
+
startedAt: nowSeconds2(),
|
|
34228
|
+
...operatorAugmentDefaults ? { systemPrompt: operatorAugmentDefaults.systemPrompt } : {},
|
|
34229
|
+
launchArgs,
|
|
34230
|
+
defaultHarness: effectiveHarness,
|
|
34231
|
+
...cardLifecycle ? { card: cardLifecycle } : {},
|
|
34232
|
+
harnessProfiles: {
|
|
34233
|
+
[effectiveHarness]: {
|
|
34234
|
+
cwd: effectiveCwd ?? projectRoot,
|
|
34235
|
+
transport,
|
|
34236
|
+
sessionId,
|
|
34237
|
+
launchArgs,
|
|
34238
|
+
...requestedPermissionProfile ? { permissionProfile: requestedPermissionProfile } : {}
|
|
34239
|
+
}
|
|
34240
|
+
},
|
|
34241
|
+
runtime: {
|
|
34242
|
+
cwd: effectiveCwd ?? projectRoot,
|
|
34243
|
+
harness: effectiveHarness,
|
|
34244
|
+
transport,
|
|
34245
|
+
sessionId,
|
|
34246
|
+
wakePolicy: "on_demand"
|
|
34247
|
+
}
|
|
34248
|
+
};
|
|
34249
|
+
await writeRelayAgentOverrides(overrides);
|
|
34250
|
+
targetAgentId = instance.id;
|
|
34251
|
+
} else if (requestedDefinitionId && requestedDefinitionId !== matchingOverride.definitionId) {
|
|
34252
|
+
const matchingProjectRoot = normalizeProjectPath2(matchingOverride.projectRoot);
|
|
34253
|
+
const instance = buildRelayAgentInstance(requestedDefinitionId, matchingProjectRoot);
|
|
34254
|
+
const existingForInstance = overrides[instance.id];
|
|
34255
|
+
if (existingForInstance && normalizeProjectPath2(existingForInstance.projectRoot) !== matchingProjectRoot) {
|
|
34256
|
+
throw new Error(`Another agent is already registered as ${instance.id} at ${existingForInstance.projectRoot}. ` + `Two clones of the same project on the same branch cannot both register here; ` + `rename one of the checkouts or switch its branch before running scout up.`);
|
|
34257
|
+
}
|
|
34258
|
+
const resolvedHarness = preferredHarness ?? matchingOverride.runtime?.harness;
|
|
34259
|
+
const nextHarness = normalizeManagedHarness2(resolvedHarness, "claude");
|
|
34260
|
+
const nextDefaultHarness = preferredHarness ? normalizeManagedHarness2(preferredHarness, "claude") : defaultHarnessForOverride(matchingOverride, "claude");
|
|
34261
|
+
const nextSessionId = normalizeTmuxSessionName2(undefined, `${instance.id}-${nextHarness}`);
|
|
34262
|
+
const nextLaunchArgs = applyRequestedRuntimeOptionsToLaunchArgs(nextHarness, launchArgsForOverrideHarness(matchingOverride, nextHarness), {
|
|
34263
|
+
model: input.model,
|
|
34264
|
+
reasoningEffort: input.reasoningEffort
|
|
34265
|
+
});
|
|
34266
|
+
const nextTransport = normalizeLocalAgentTransport(preferredHarness ? undefined : matchingOverride.runtime?.transport, nextHarness);
|
|
34267
|
+
const operatorAugmentDefaults = operatorAugmentDefaultsForDefinitionId(requestedDefinitionId);
|
|
34268
|
+
overrides[instance.id] = {
|
|
34269
|
+
agentId: instance.id,
|
|
34270
|
+
definitionId: requestedDefinitionId,
|
|
34271
|
+
displayName: input.displayName || operatorAugmentDefaults?.displayName || titleCaseLocalAgentName(requestedDefinitionId),
|
|
34272
|
+
projectName: matchingOverride.projectName ?? basename9(matchingProjectRoot),
|
|
34273
|
+
projectRoot: matchingProjectRoot,
|
|
34274
|
+
projectConfigPath: null,
|
|
34275
|
+
source: "manual",
|
|
34276
|
+
startedAt: matchingOverride.startedAt ?? nowSeconds2(),
|
|
34277
|
+
...operatorAugmentDefaults ? { systemPrompt: operatorAugmentDefaults.systemPrompt } : {},
|
|
34278
|
+
launchArgs: nextHarness === nextDefaultHarness ? nextLaunchArgs : matchingOverride.launchArgs,
|
|
34279
|
+
capabilities: matchingOverride.capabilities,
|
|
34280
|
+
defaultHarness: nextDefaultHarness,
|
|
34281
|
+
...cardLifecycle ? { card: cardLifecycle } : {},
|
|
34282
|
+
harnessProfiles: {
|
|
34283
|
+
...matchingOverride.harnessProfiles ?? {},
|
|
34284
|
+
[nextHarness]: {
|
|
34285
|
+
...overrideHarnessProfile(matchingOverride, nextHarness),
|
|
34286
|
+
transport: nextTransport,
|
|
34287
|
+
sessionId: nextSessionId,
|
|
34288
|
+
launchArgs: nextLaunchArgs,
|
|
34289
|
+
...requestedPermissionProfile ? { permissionProfile: requestedPermissionProfile } : {}
|
|
34290
|
+
}
|
|
34291
|
+
},
|
|
34292
|
+
runtime: {
|
|
34293
|
+
cwd: effectiveCwd ?? matchingOverride.runtime?.cwd ?? matchingProjectRoot,
|
|
34294
|
+
harness: nextHarness,
|
|
34295
|
+
transport: nextTransport,
|
|
34296
|
+
sessionId: nextSessionId,
|
|
34297
|
+
wakePolicy: "on_demand"
|
|
34298
|
+
}
|
|
34299
|
+
};
|
|
34300
|
+
await writeRelayAgentOverrides(overrides);
|
|
34301
|
+
targetAgentId = instance.id;
|
|
34302
|
+
} else {
|
|
34303
|
+
const operatorAugmentDefaults = operatorAugmentDefaultsForDefinitionId(matchingOverride.definitionId ?? requestedDefinitionId);
|
|
34304
|
+
const shouldApplyOperatorAugmentPrompt = Boolean(operatorAugmentDefaults && !matchingOverride.systemPrompt?.trim());
|
|
34305
|
+
if (input.model || input.reasoningEffort || requestedPermissionProfile || cardLifecycle || shouldApplyOperatorAugmentPrompt) {
|
|
34306
|
+
const existingHarness = normalizeManagedHarness2(preferredHarness ?? matchingOverride.defaultHarness ?? matchingOverride.runtime?.harness, "claude");
|
|
34307
|
+
const nextLaunchArgs = applyRequestedRuntimeOptionsToLaunchArgs(existingHarness, launchArgsForOverrideHarness(matchingOverride, existingHarness), {
|
|
34308
|
+
model: input.model,
|
|
34309
|
+
reasoningEffort: input.reasoningEffort
|
|
34310
|
+
});
|
|
34311
|
+
overrides[matchingAgentId] = {
|
|
34312
|
+
...matchingOverride,
|
|
34313
|
+
...cardLifecycle ? { card: cardLifecycle } : {},
|
|
34314
|
+
...shouldApplyOperatorAugmentPrompt ? { systemPrompt: operatorAugmentDefaults.systemPrompt } : {},
|
|
34315
|
+
launchArgs: existingHarness === defaultHarnessForOverride(matchingOverride, existingHarness) ? nextLaunchArgs : matchingOverride.launchArgs,
|
|
34316
|
+
harnessProfiles: {
|
|
34317
|
+
...matchingOverride.harnessProfiles ?? {},
|
|
34318
|
+
[existingHarness]: {
|
|
34319
|
+
...overrideHarnessProfile(matchingOverride, existingHarness),
|
|
34320
|
+
launchArgs: nextLaunchArgs,
|
|
34321
|
+
...requestedPermissionProfile ? { permissionProfile: requestedPermissionProfile } : {}
|
|
34322
|
+
}
|
|
34323
|
+
}
|
|
34324
|
+
};
|
|
34325
|
+
await writeRelayAgentOverrides(overrides);
|
|
34326
|
+
}
|
|
34327
|
+
targetAgentId = matchingAgentId;
|
|
34328
|
+
}
|
|
34329
|
+
if (shouldEnsureOnline) {
|
|
34330
|
+
await ensureLocalAgentBindingOnline(targetAgentId, process.env.OPENSCOUT_NODE_ID ?? "local", {
|
|
34331
|
+
includeDiscovered: false,
|
|
34332
|
+
currentDirectory,
|
|
34333
|
+
ensureCurrentProjectConfig: false,
|
|
34334
|
+
harness: preferredHarness
|
|
34335
|
+
});
|
|
34336
|
+
}
|
|
34337
|
+
const finalOverrides = await readRelayAgentOverrides();
|
|
34338
|
+
const finalOverride = finalOverrides[targetAgentId];
|
|
34339
|
+
if (!finalOverride) {
|
|
34340
|
+
throw new Error(`Agent ${targetAgentId} did not register successfully.`);
|
|
34341
|
+
}
|
|
34342
|
+
const record2 = localAgentRecordFromRelayAgentOverride(targetAgentId, finalOverride);
|
|
34343
|
+
return localAgentStatusFromRecord(targetAgentId, record2, localAgentStatusSource(targetAgentId, finalOverrides));
|
|
34344
|
+
}
|
|
34345
|
+
async function stopLocalAgent(agentId) {
|
|
34346
|
+
const [registry2, overrides] = await Promise.all([
|
|
34347
|
+
readLocalAgentRegistry(),
|
|
34348
|
+
readRelayAgentOverrides()
|
|
34349
|
+
]);
|
|
34350
|
+
const record2 = registry2[agentId];
|
|
34351
|
+
if (!record2) {
|
|
34352
|
+
return null;
|
|
34353
|
+
}
|
|
34354
|
+
const normalizedRecord = normalizeLocalAgentRecord(agentId, record2);
|
|
34355
|
+
const sessionsToStop = new Set([normalizedRecord.tmuxSession]);
|
|
34356
|
+
if (normalizedRecord.transport === "codex_app_server") {
|
|
34357
|
+
for (const sessionName of sessionsToStop) {
|
|
34358
|
+
await shutdownCodexAppServerAgent({
|
|
34359
|
+
...buildCodexAgentSessionOptions(agentId, normalizedRecord),
|
|
34360
|
+
sessionId: sessionName
|
|
34361
|
+
}, {
|
|
34362
|
+
resetThread: true
|
|
34363
|
+
});
|
|
34364
|
+
}
|
|
34365
|
+
} else if (normalizedRecord.transport === "claude_stream_json") {
|
|
34366
|
+
for (const sessionName of sessionsToStop) {
|
|
34367
|
+
await shutdownClaudeStreamJsonAgent({
|
|
34368
|
+
...buildClaudeAgentSessionOptions(agentId, normalizedRecord),
|
|
34369
|
+
sessionId: sessionName
|
|
34370
|
+
}, {
|
|
34371
|
+
resetSession: true
|
|
34372
|
+
});
|
|
34373
|
+
}
|
|
34374
|
+
} else {
|
|
34375
|
+
for (const sessionName of sessionsToStop) {
|
|
34376
|
+
killAgentSession(sessionName);
|
|
34377
|
+
}
|
|
34378
|
+
}
|
|
34379
|
+
return {
|
|
34380
|
+
...localAgentStatusFromRecord(agentId, normalizedRecord, localAgentStatusSource(agentId, overrides)),
|
|
34381
|
+
isOnline: false
|
|
34382
|
+
};
|
|
34383
|
+
}
|
|
32995
34384
|
function readPersistedClaudeSessionId(agentName) {
|
|
32996
34385
|
try {
|
|
32997
34386
|
const runtimeDir = relayAgentRuntimeDirectory(agentName);
|
|
32998
|
-
const catalogPath =
|
|
32999
|
-
if (
|
|
33000
|
-
const raw =
|
|
34387
|
+
const catalogPath = join19(runtimeDir, "session-catalog.json");
|
|
34388
|
+
if (existsSync14(catalogPath)) {
|
|
34389
|
+
const raw = readFileSync7(catalogPath, "utf8").trim();
|
|
33001
34390
|
if (raw) {
|
|
33002
34391
|
const catalog = JSON.parse(raw);
|
|
33003
34392
|
if (typeof catalog.activeSessionId === "string" && catalog.activeSessionId.trim()) {
|
|
@@ -33005,9 +34394,9 @@ function readPersistedClaudeSessionId(agentName) {
|
|
|
33005
34394
|
}
|
|
33006
34395
|
}
|
|
33007
34396
|
}
|
|
33008
|
-
const legacyPath =
|
|
33009
|
-
if (
|
|
33010
|
-
const value =
|
|
34397
|
+
const legacyPath = join19(runtimeDir, "claude-session-id.txt");
|
|
34398
|
+
if (existsSync14(legacyPath)) {
|
|
34399
|
+
const value = readFileSync7(legacyPath, "utf8").trim();
|
|
33011
34400
|
return value || null;
|
|
33012
34401
|
}
|
|
33013
34402
|
return null;
|
|
@@ -33019,6 +34408,7 @@ function buildLocalAgentBinding(agentId, record2, alive, nodeId, source) {
|
|
|
33019
34408
|
const normalizedRecord = normalizeLocalAgentRecord(agentId, record2);
|
|
33020
34409
|
const configuredModel = readLaunchModelForHarness(normalizeLocalAgentHarness(normalizedRecord.harness), normalizedRecord.launchArgs);
|
|
33021
34410
|
const codexPermissionPosture = normalizeLocalAgentHarness(normalizedRecord.harness) === "codex" ? compileCodexPermissionProfile(normalizedRecord.permissionProfile) : null;
|
|
34411
|
+
const cardLifecycle = normalizeLocalAgentCardLifecycle(normalizedRecord.card);
|
|
33022
34412
|
const definitionId = normalizedRecord.definitionId ?? agentId;
|
|
33023
34413
|
const displayName = titleCaseLocalAgentName(definitionId);
|
|
33024
34414
|
const projectRoot = normalizedRecord.projectRoot ?? normalizedRecord.cwd;
|
|
@@ -33046,6 +34436,7 @@ function buildLocalAgentBinding(agentId, record2, alive, nodeId, source) {
|
|
|
33046
34436
|
workspaceQualifier: instance.workspaceQualifier,
|
|
33047
34437
|
branch: instance.branch,
|
|
33048
34438
|
...configuredModel ? { model: configuredModel } : {},
|
|
34439
|
+
...cardLifecycle ? { cardLifecycle } : {},
|
|
33049
34440
|
...codexPermissionPosture ? {
|
|
33050
34441
|
permissionProfile: codexPermissionPosture.profile,
|
|
33051
34442
|
approvalPolicy: codexPermissionPosture.approvalPolicy,
|
|
@@ -33081,6 +34472,7 @@ function buildLocalAgentBinding(agentId, record2, alive, nodeId, source) {
|
|
|
33081
34472
|
workspaceQualifier: instance.workspaceQualifier,
|
|
33082
34473
|
branch: instance.branch,
|
|
33083
34474
|
...configuredModel ? { model: configuredModel } : {},
|
|
34475
|
+
...cardLifecycle ? { cardLifecycle } : {},
|
|
33084
34476
|
...codexPermissionPosture ? {
|
|
33085
34477
|
permissionProfile: codexPermissionPosture.profile,
|
|
33086
34478
|
approvalPolicy: codexPermissionPosture.approvalPolicy,
|
|
@@ -33121,6 +34513,7 @@ function buildLocalAgentBinding(agentId, record2, alive, nodeId, source) {
|
|
|
33121
34513
|
workspaceQualifier: instance.workspaceQualifier,
|
|
33122
34514
|
branch: instance.branch,
|
|
33123
34515
|
...configuredModel ? { model: configuredModel } : {},
|
|
34516
|
+
...cardLifecycle ? { cardLifecycle } : {},
|
|
33124
34517
|
...codexPermissionPosture ? {
|
|
33125
34518
|
permissionProfile: codexPermissionPosture.profile,
|
|
33126
34519
|
approvalPolicy: codexPermissionPosture.approvalPolicy,
|
|
@@ -33212,7 +34605,8 @@ async function invokeLocalAgentEndpoint(endpoint, invocation) {
|
|
|
33212
34605
|
replyContext
|
|
33213
34606
|
});
|
|
33214
34607
|
return {
|
|
33215
|
-
output: result.output
|
|
34608
|
+
output: result.output,
|
|
34609
|
+
externalSessionId: result.threadId
|
|
33216
34610
|
};
|
|
33217
34611
|
}
|
|
33218
34612
|
if (!existing && endpoint.transport === "claude_stream_json") {
|
|
@@ -33223,7 +34617,8 @@ async function invokeLocalAgentEndpoint(endpoint, invocation) {
|
|
|
33223
34617
|
timeoutMs: invocation.timeoutMs
|
|
33224
34618
|
});
|
|
33225
34619
|
return {
|
|
33226
|
-
output: result.output
|
|
34620
|
+
output: result.output,
|
|
34621
|
+
externalSessionId: result.sessionId
|
|
33227
34622
|
};
|
|
33228
34623
|
}
|
|
33229
34624
|
const projectRoot = endpoint.projectRoot ?? endpoint.cwd;
|
|
@@ -33262,7 +34657,8 @@ async function invokeLocalAgentEndpoint(endpoint, invocation) {
|
|
|
33262
34657
|
replyContext
|
|
33263
34658
|
});
|
|
33264
34659
|
return {
|
|
33265
|
-
output: result.output
|
|
34660
|
+
output: result.output,
|
|
34661
|
+
externalSessionId: result.threadId
|
|
33266
34662
|
};
|
|
33267
34663
|
}
|
|
33268
34664
|
if (onlineRecord.transport === "claude_stream_json") {
|
|
@@ -33272,7 +34668,8 @@ async function invokeLocalAgentEndpoint(endpoint, invocation) {
|
|
|
33272
34668
|
timeoutMs: invocation.timeoutMs
|
|
33273
34669
|
});
|
|
33274
34670
|
return {
|
|
33275
|
-
output: result.output
|
|
34671
|
+
output: result.output,
|
|
34672
|
+
externalSessionId: result.sessionId
|
|
33276
34673
|
};
|
|
33277
34674
|
}
|
|
33278
34675
|
const flightId = createLocalAgentFlightId();
|
|
@@ -33361,6 +34758,7 @@ function buildScoutAgentCard(binding, options = {}) {
|
|
|
33361
34758
|
const supportedInterfaces = metadataRecordArray(binding.agent.metadata, "supportedInterfaces");
|
|
33362
34759
|
const securitySchemes = metadataRecord3(binding.agent.metadata, "securitySchemes");
|
|
33363
34760
|
const securityRequirements = metadataStringMatrix(binding.agent.metadata, "securityRequirements");
|
|
34761
|
+
const lifecycle2 = options.lifecycle ?? metadataRecord3(binding.agent.metadata, "cardLifecycle");
|
|
33364
34762
|
return {
|
|
33365
34763
|
id: binding.agent.id,
|
|
33366
34764
|
agentId: binding.agent.id,
|
|
@@ -33390,6 +34788,7 @@ function buildScoutAgentCard(binding, options = {}) {
|
|
|
33390
34788
|
...options.createdById?.trim() ? { createdById: options.createdById.trim() } : {},
|
|
33391
34789
|
brokerRegistered: options.brokerRegistered ?? false,
|
|
33392
34790
|
...options.inboxConversationId?.trim() ? { inboxConversationId: options.inboxConversationId.trim() } : {},
|
|
34791
|
+
...lifecycle2 ? { lifecycle: lifecycle2 } : {},
|
|
33393
34792
|
returnAddress: buildScoutReturnAddress({
|
|
33394
34793
|
actorId: binding.agent.id,
|
|
33395
34794
|
handle,
|
|
@@ -33407,7 +34806,8 @@ function buildScoutAgentCard(binding, options = {}) {
|
|
|
33407
34806
|
actorId: binding.actor.id,
|
|
33408
34807
|
endpointId: binding.endpoint.id,
|
|
33409
34808
|
wakePolicy: binding.agent.wakePolicy,
|
|
33410
|
-
...model ? { model } : {}
|
|
34809
|
+
...model ? { model } : {},
|
|
34810
|
+
...lifecycle2 ? { cardLifecycle: lifecycle2 } : {}
|
|
33411
34811
|
}
|
|
33412
34812
|
};
|
|
33413
34813
|
}
|
|
@@ -33471,9 +34871,9 @@ function upsertScoutAgentCardFromInput(runtime, input) {
|
|
|
33471
34871
|
}
|
|
33472
34872
|
|
|
33473
34873
|
// packages/runtime/src/pairing-session-agents.ts
|
|
33474
|
-
import { existsSync as
|
|
33475
|
-
import { basename as basename10, join as
|
|
33476
|
-
import { homedir as
|
|
34874
|
+
import { existsSync as existsSync15, readFileSync as readFileSync8 } from "fs";
|
|
34875
|
+
import { basename as basename10, join as join20 } from "path";
|
|
34876
|
+
import { homedir as homedir15 } from "os";
|
|
33477
34877
|
var DEFAULT_PAIRING_PORT = 7888;
|
|
33478
34878
|
var PAIRING_CONNECT_TIMEOUT_MS = 1500;
|
|
33479
34879
|
var PAIRING_REQUEST_TIMEOUT_MS = 1e4;
|
|
@@ -33481,18 +34881,18 @@ var DEFAULT_PAIRING_POLL_INTERVAL_MS = 350;
|
|
|
33481
34881
|
var DEFAULT_PAIRING_INVOCATION_TIMEOUT_MS = 45000;
|
|
33482
34882
|
var MAX_SYNTHETIC_OUTPUT_CHARS = 1200;
|
|
33483
34883
|
function pairingPaths() {
|
|
33484
|
-
const rootDir =
|
|
34884
|
+
const rootDir = join20(homedir15(), ".scout", "pairing");
|
|
33485
34885
|
return {
|
|
33486
|
-
configPath:
|
|
33487
|
-
runtimeStatePath:
|
|
34886
|
+
configPath: join20(rootDir, "config.json"),
|
|
34887
|
+
runtimeStatePath: join20(rootDir, "runtime.json")
|
|
33488
34888
|
};
|
|
33489
34889
|
}
|
|
33490
34890
|
function readJsonFile2(filePath) {
|
|
33491
|
-
if (!
|
|
34891
|
+
if (!existsSync15(filePath)) {
|
|
33492
34892
|
return null;
|
|
33493
34893
|
}
|
|
33494
34894
|
try {
|
|
33495
|
-
return JSON.parse(
|
|
34895
|
+
return JSON.parse(readFileSync8(filePath, "utf8"));
|
|
33496
34896
|
} catch {
|
|
33497
34897
|
return null;
|
|
33498
34898
|
}
|
|
@@ -33502,7 +34902,7 @@ function resolvePairingBridgePort(options = {}) {
|
|
|
33502
34902
|
return options.port;
|
|
33503
34903
|
}
|
|
33504
34904
|
const { configPath, runtimeStatePath } = pairingPaths();
|
|
33505
|
-
const configExists =
|
|
34905
|
+
const configExists = existsSync15(configPath);
|
|
33506
34906
|
const runtimeSnapshot = readJsonFile2(runtimeStatePath);
|
|
33507
34907
|
if (!configExists && !runtimeSnapshot) {
|
|
33508
34908
|
return null;
|
|
@@ -34043,7 +35443,7 @@ import { mkdirSync as mkdirSync5 } from "fs";
|
|
|
34043
35443
|
import { dirname as dirname12 } from "path";
|
|
34044
35444
|
import { Database as Database2 } from "bun:sqlite";
|
|
34045
35445
|
|
|
34046
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35446
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/entity.js
|
|
34047
35447
|
var entityKind = Symbol.for("drizzle:entityKind");
|
|
34048
35448
|
var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
|
|
34049
35449
|
function is(value, type) {
|
|
@@ -34068,7 +35468,7 @@ function is(value, type) {
|
|
|
34068
35468
|
return false;
|
|
34069
35469
|
}
|
|
34070
35470
|
|
|
34071
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35471
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/column.js
|
|
34072
35472
|
class Column {
|
|
34073
35473
|
constructor(table, config2) {
|
|
34074
35474
|
this.table = table;
|
|
@@ -34118,7 +35518,7 @@ class Column {
|
|
|
34118
35518
|
}
|
|
34119
35519
|
}
|
|
34120
35520
|
|
|
34121
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35521
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/column-builder.js
|
|
34122
35522
|
class ColumnBuilder {
|
|
34123
35523
|
static [entityKind] = "ColumnBuilder";
|
|
34124
35524
|
config;
|
|
@@ -34174,20 +35574,20 @@ class ColumnBuilder {
|
|
|
34174
35574
|
}
|
|
34175
35575
|
}
|
|
34176
35576
|
|
|
34177
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35577
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/table.utils.js
|
|
34178
35578
|
var TableName = Symbol.for("drizzle:Name");
|
|
34179
35579
|
|
|
34180
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35580
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/tracing-utils.js
|
|
34181
35581
|
function iife(fn, ...args) {
|
|
34182
35582
|
return fn(...args);
|
|
34183
35583
|
}
|
|
34184
35584
|
|
|
34185
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35585
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/pg-core/unique-constraint.js
|
|
34186
35586
|
function uniqueKeyName(table, columns) {
|
|
34187
35587
|
return `${table[TableName]}_${columns.join("_")}_unique`;
|
|
34188
35588
|
}
|
|
34189
35589
|
|
|
34190
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35590
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/pg-core/columns/common.js
|
|
34191
35591
|
class PgColumn extends Column {
|
|
34192
35592
|
constructor(table, config2) {
|
|
34193
35593
|
if (!config2.uniqueName) {
|
|
@@ -34236,7 +35636,7 @@ class ExtraConfigColumn extends PgColumn {
|
|
|
34236
35636
|
}
|
|
34237
35637
|
}
|
|
34238
35638
|
|
|
34239
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35639
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/pg-core/columns/enum.js
|
|
34240
35640
|
class PgEnumObjectColumn extends PgColumn {
|
|
34241
35641
|
static [entityKind] = "PgEnumObjectColumn";
|
|
34242
35642
|
enum;
|
|
@@ -34266,7 +35666,7 @@ class PgEnumColumn extends PgColumn {
|
|
|
34266
35666
|
}
|
|
34267
35667
|
}
|
|
34268
35668
|
|
|
34269
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35669
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/subquery.js
|
|
34270
35670
|
class Subquery {
|
|
34271
35671
|
static [entityKind] = "Subquery";
|
|
34272
35672
|
constructor(sql, fields, alias, isWith = false, usedTables = []) {
|
|
@@ -34285,10 +35685,10 @@ class WithSubquery extends Subquery {
|
|
|
34285
35685
|
static [entityKind] = "WithSubquery";
|
|
34286
35686
|
}
|
|
34287
35687
|
|
|
34288
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35688
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/version.js
|
|
34289
35689
|
var version2 = "0.45.2";
|
|
34290
35690
|
|
|
34291
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35691
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/tracing.js
|
|
34292
35692
|
var otel;
|
|
34293
35693
|
var rawTracer;
|
|
34294
35694
|
var tracer = {
|
|
@@ -34315,10 +35715,10 @@ var tracer = {
|
|
|
34315
35715
|
}
|
|
34316
35716
|
};
|
|
34317
35717
|
|
|
34318
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35718
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/view-common.js
|
|
34319
35719
|
var ViewBaseConfig = Symbol.for("drizzle:ViewBaseConfig");
|
|
34320
35720
|
|
|
34321
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35721
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/table.js
|
|
34322
35722
|
var Schema = Symbol.for("drizzle:Schema");
|
|
34323
35723
|
var Columns = Symbol.for("drizzle:Columns");
|
|
34324
35724
|
var ExtraConfigColumns = Symbol.for("drizzle:ExtraConfigColumns");
|
|
@@ -34362,7 +35762,7 @@ function getTableUniqueName(table) {
|
|
|
34362
35762
|
return `${table[Schema] ?? "public"}.${table[TableName]}`;
|
|
34363
35763
|
}
|
|
34364
35764
|
|
|
34365
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
35765
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/sql.js
|
|
34366
35766
|
function isSQLWrapper(value) {
|
|
34367
35767
|
return value !== null && value !== undefined && typeof value.getSQL === "function";
|
|
34368
35768
|
}
|
|
@@ -34642,7 +36042,7 @@ function sql(strings, ...params) {
|
|
|
34642
36042
|
return new SQL([new StringChunk(str)]);
|
|
34643
36043
|
}
|
|
34644
36044
|
sql2.raw = raw;
|
|
34645
|
-
function
|
|
36045
|
+
function join21(chunks, separator) {
|
|
34646
36046
|
const result = [];
|
|
34647
36047
|
for (const [i, chunk] of chunks.entries()) {
|
|
34648
36048
|
if (i > 0 && separator !== undefined) {
|
|
@@ -34652,7 +36052,7 @@ function sql(strings, ...params) {
|
|
|
34652
36052
|
}
|
|
34653
36053
|
return new SQL(result);
|
|
34654
36054
|
}
|
|
34655
|
-
sql2.join =
|
|
36055
|
+
sql2.join = join21;
|
|
34656
36056
|
function identifier(value) {
|
|
34657
36057
|
return new Name(value);
|
|
34658
36058
|
}
|
|
@@ -34742,7 +36142,7 @@ Subquery.prototype.getSQL = function() {
|
|
|
34742
36142
|
return new SQL([this]);
|
|
34743
36143
|
};
|
|
34744
36144
|
|
|
34745
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36145
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/alias.js
|
|
34746
36146
|
class ColumnAliasProxyHandler {
|
|
34747
36147
|
constructor(table) {
|
|
34748
36148
|
this.table = table;
|
|
@@ -34821,7 +36221,7 @@ function mapColumnsInSQLToAlias(query, alias) {
|
|
|
34821
36221
|
}));
|
|
34822
36222
|
}
|
|
34823
36223
|
|
|
34824
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36224
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/errors.js
|
|
34825
36225
|
class DrizzleError extends Error {
|
|
34826
36226
|
static [entityKind] = "DrizzleError";
|
|
34827
36227
|
constructor({ message, cause }) {
|
|
@@ -34851,7 +36251,7 @@ class TransactionRollbackError extends DrizzleError {
|
|
|
34851
36251
|
}
|
|
34852
36252
|
}
|
|
34853
36253
|
|
|
34854
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36254
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/logger.js
|
|
34855
36255
|
class ConsoleLogWriter {
|
|
34856
36256
|
static [entityKind] = "ConsoleLogWriter";
|
|
34857
36257
|
write(message) {
|
|
@@ -34883,7 +36283,7 @@ class NoopLogger {
|
|
|
34883
36283
|
logQuery() {}
|
|
34884
36284
|
}
|
|
34885
36285
|
|
|
34886
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36286
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/query-promise.js
|
|
34887
36287
|
class QueryPromise {
|
|
34888
36288
|
static [entityKind] = "QueryPromise";
|
|
34889
36289
|
[Symbol.toStringTag] = "QueryPromise";
|
|
@@ -34904,7 +36304,7 @@ class QueryPromise {
|
|
|
34904
36304
|
}
|
|
34905
36305
|
}
|
|
34906
36306
|
|
|
34907
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36307
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/utils.js
|
|
34908
36308
|
function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
34909
36309
|
const nullifyMap = {};
|
|
34910
36310
|
const result = columns.reduce((result2, { path, field }, columnIndex) => {
|
|
@@ -35058,7 +36458,7 @@ function isConfig(data) {
|
|
|
35058
36458
|
}
|
|
35059
36459
|
var textDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder;
|
|
35060
36460
|
|
|
35061
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36461
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/pg-core/table.js
|
|
35062
36462
|
var InlineForeignKeys = Symbol.for("drizzle:PgInlineForeignKeys");
|
|
35063
36463
|
var EnableRLS = Symbol.for("drizzle:EnableRLS");
|
|
35064
36464
|
|
|
@@ -35074,7 +36474,7 @@ class PgTable extends Table {
|
|
|
35074
36474
|
[Table.Symbol.ExtraConfigColumns] = {};
|
|
35075
36475
|
}
|
|
35076
36476
|
|
|
35077
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36477
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/pg-core/primary-keys.js
|
|
35078
36478
|
class PrimaryKeyBuilder {
|
|
35079
36479
|
static [entityKind] = "PgPrimaryKeyBuilder";
|
|
35080
36480
|
columns;
|
|
@@ -35102,7 +36502,7 @@ class PrimaryKey {
|
|
|
35102
36502
|
}
|
|
35103
36503
|
}
|
|
35104
36504
|
|
|
35105
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36505
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/expressions/conditions.js
|
|
35106
36506
|
function bindIfParam(value, column) {
|
|
35107
36507
|
if (isDriverValueEncoder(column) && !isSQLWrapper(value) && !is(value, Param) && !is(value, Placeholder) && !is(value, Column) && !is(value, Table) && !is(value, View)) {
|
|
35108
36508
|
return new Param(value, column);
|
|
@@ -35207,7 +36607,7 @@ function notIlike(column, value) {
|
|
|
35207
36607
|
return sql`${column} not ilike ${value}`;
|
|
35208
36608
|
}
|
|
35209
36609
|
|
|
35210
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36610
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sql/expressions/select.js
|
|
35211
36611
|
function asc(column) {
|
|
35212
36612
|
return sql`${column} asc`;
|
|
35213
36613
|
}
|
|
@@ -35215,7 +36615,7 @@ function desc(column) {
|
|
|
35215
36615
|
return sql`${column} desc`;
|
|
35216
36616
|
}
|
|
35217
36617
|
|
|
35218
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36618
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/relations.js
|
|
35219
36619
|
class Relation {
|
|
35220
36620
|
constructor(sourceTable, referencedTable, relationName) {
|
|
35221
36621
|
this.sourceTable = sourceTable;
|
|
@@ -35435,10 +36835,10 @@ function mapRelationalRow(tablesConfig, tableConfig, row, buildQueryResultSelect
|
|
|
35435
36835
|
return result;
|
|
35436
36836
|
}
|
|
35437
36837
|
|
|
35438
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36838
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/bun-sqlite/driver.js
|
|
35439
36839
|
import { Database } from "bun:sqlite";
|
|
35440
36840
|
|
|
35441
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36841
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/selection-proxy.js
|
|
35442
36842
|
class SelectionProxyHandler {
|
|
35443
36843
|
static [entityKind] = "SelectionProxyHandler";
|
|
35444
36844
|
config;
|
|
@@ -35490,7 +36890,7 @@ class SelectionProxyHandler {
|
|
|
35490
36890
|
}
|
|
35491
36891
|
}
|
|
35492
36892
|
|
|
35493
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36893
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/foreign-keys.js
|
|
35494
36894
|
class ForeignKeyBuilder {
|
|
35495
36895
|
static [entityKind] = "SQLiteForeignKeyBuilder";
|
|
35496
36896
|
reference;
|
|
@@ -35544,12 +36944,12 @@ class ForeignKey {
|
|
|
35544
36944
|
}
|
|
35545
36945
|
}
|
|
35546
36946
|
|
|
35547
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36947
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/unique-constraint.js
|
|
35548
36948
|
function uniqueKeyName2(table, columns) {
|
|
35549
36949
|
return `${table[TableName]}_${columns.join("_")}_unique`;
|
|
35550
36950
|
}
|
|
35551
36951
|
|
|
35552
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
36952
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/common.js
|
|
35553
36953
|
class SQLiteColumnBuilder extends ColumnBuilder {
|
|
35554
36954
|
static [entityKind] = "SQLiteColumnBuilder";
|
|
35555
36955
|
foreignKeyConfigs = [];
|
|
@@ -35600,7 +37000,7 @@ class SQLiteColumn extends Column {
|
|
|
35600
37000
|
static [entityKind] = "SQLiteColumn";
|
|
35601
37001
|
}
|
|
35602
37002
|
|
|
35603
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37003
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/blob.js
|
|
35604
37004
|
class SQLiteBigIntBuilder extends SQLiteColumnBuilder {
|
|
35605
37005
|
static [entityKind] = "SQLiteBigIntBuilder";
|
|
35606
37006
|
constructor(name) {
|
|
@@ -35688,7 +37088,7 @@ function blob(a, b) {
|
|
|
35688
37088
|
return new SQLiteBlobBufferBuilder(name);
|
|
35689
37089
|
}
|
|
35690
37090
|
|
|
35691
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37091
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/custom.js
|
|
35692
37092
|
class SQLiteCustomColumnBuilder extends SQLiteColumnBuilder {
|
|
35693
37093
|
static [entityKind] = "SQLiteCustomColumnBuilder";
|
|
35694
37094
|
constructor(name, fieldConfig, customTypeParams) {
|
|
@@ -35729,7 +37129,7 @@ function customType(customTypeParams) {
|
|
|
35729
37129
|
};
|
|
35730
37130
|
}
|
|
35731
37131
|
|
|
35732
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37132
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/integer.js
|
|
35733
37133
|
class SQLiteBaseIntegerBuilder extends SQLiteColumnBuilder {
|
|
35734
37134
|
static [entityKind] = "SQLiteBaseIntegerBuilder";
|
|
35735
37135
|
constructor(name, dataType, columnType) {
|
|
@@ -35831,7 +37231,7 @@ function integer2(a, b) {
|
|
|
35831
37231
|
return new SQLiteIntegerBuilder(name);
|
|
35832
37232
|
}
|
|
35833
37233
|
|
|
35834
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37234
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/numeric.js
|
|
35835
37235
|
class SQLiteNumericBuilder extends SQLiteColumnBuilder {
|
|
35836
37236
|
static [entityKind] = "SQLiteNumericBuilder";
|
|
35837
37237
|
constructor(name) {
|
|
@@ -35901,7 +37301,7 @@ function numeric(a, b) {
|
|
|
35901
37301
|
return mode === "number" ? new SQLiteNumericNumberBuilder(name) : mode === "bigint" ? new SQLiteNumericBigIntBuilder(name) : new SQLiteNumericBuilder(name);
|
|
35902
37302
|
}
|
|
35903
37303
|
|
|
35904
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37304
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/real.js
|
|
35905
37305
|
class SQLiteRealBuilder extends SQLiteColumnBuilder {
|
|
35906
37306
|
static [entityKind] = "SQLiteRealBuilder";
|
|
35907
37307
|
constructor(name) {
|
|
@@ -35922,7 +37322,7 @@ function real(name) {
|
|
|
35922
37322
|
return new SQLiteRealBuilder(name ?? "");
|
|
35923
37323
|
}
|
|
35924
37324
|
|
|
35925
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37325
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/text.js
|
|
35926
37326
|
class SQLiteTextBuilder extends SQLiteColumnBuilder {
|
|
35927
37327
|
static [entityKind] = "SQLiteTextBuilder";
|
|
35928
37328
|
constructor(name, config2) {
|
|
@@ -35977,7 +37377,7 @@ function text(a, b = {}) {
|
|
|
35977
37377
|
return new SQLiteTextBuilder(name, config2);
|
|
35978
37378
|
}
|
|
35979
37379
|
|
|
35980
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37380
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/columns/all.js
|
|
35981
37381
|
function getSQLiteColumnBuilders() {
|
|
35982
37382
|
return {
|
|
35983
37383
|
blob,
|
|
@@ -35989,7 +37389,7 @@ function getSQLiteColumnBuilders() {
|
|
|
35989
37389
|
};
|
|
35990
37390
|
}
|
|
35991
37391
|
|
|
35992
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37392
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/table.js
|
|
35993
37393
|
var InlineForeignKeys2 = Symbol.for("drizzle:SQLiteInlineForeignKeys");
|
|
35994
37394
|
|
|
35995
37395
|
class SQLiteTable extends Table {
|
|
@@ -36023,7 +37423,7 @@ var sqliteTable = (name, columns, extraConfig) => {
|
|
|
36023
37423
|
return sqliteTableBase(name, columns, extraConfig);
|
|
36024
37424
|
};
|
|
36025
37425
|
|
|
36026
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37426
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/indexes.js
|
|
36027
37427
|
class IndexBuilderOn {
|
|
36028
37428
|
constructor(name, unique4) {
|
|
36029
37429
|
this.name = name;
|
|
@@ -36066,7 +37466,7 @@ function index(name) {
|
|
|
36066
37466
|
return new IndexBuilderOn(name, false);
|
|
36067
37467
|
}
|
|
36068
37468
|
|
|
36069
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37469
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/utils.js
|
|
36070
37470
|
function extractUsedTable(table) {
|
|
36071
37471
|
if (is(table, SQLiteTable)) {
|
|
36072
37472
|
return [`${table[Table.Symbol.BaseName]}`];
|
|
@@ -36080,7 +37480,7 @@ function extractUsedTable(table) {
|
|
|
36080
37480
|
return [];
|
|
36081
37481
|
}
|
|
36082
37482
|
|
|
36083
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37483
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/delete.js
|
|
36084
37484
|
class SQLiteDeleteBase extends QueryPromise {
|
|
36085
37485
|
constructor(table, session, dialect, withList) {
|
|
36086
37486
|
super();
|
|
@@ -36150,7 +37550,7 @@ class SQLiteDeleteBase extends QueryPromise {
|
|
|
36150
37550
|
}
|
|
36151
37551
|
}
|
|
36152
37552
|
|
|
36153
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37553
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/casing.js
|
|
36154
37554
|
function toSnakeCase(input) {
|
|
36155
37555
|
const words = input.replace(/['\u2019]/g, "").match(/[\da-z]+|[A-Z]+(?![a-z])|[A-Z][\da-z]+/g) ?? [];
|
|
36156
37556
|
return words.map((word) => word.toLowerCase()).join("_");
|
|
@@ -36203,12 +37603,12 @@ class CasingCache {
|
|
|
36203
37603
|
}
|
|
36204
37604
|
}
|
|
36205
37605
|
|
|
36206
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37606
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/view-base.js
|
|
36207
37607
|
class SQLiteViewBase extends View {
|
|
36208
37608
|
static [entityKind] = "SQLiteViewBase";
|
|
36209
37609
|
}
|
|
36210
37610
|
|
|
36211
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
37611
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/dialect.js
|
|
36212
37612
|
class SQLiteDialect {
|
|
36213
37613
|
static [entityKind] = "SQLiteDialect";
|
|
36214
37614
|
casing;
|
|
@@ -36791,7 +38191,7 @@ class SQLiteSyncDialect extends SQLiteDialect {
|
|
|
36791
38191
|
}
|
|
36792
38192
|
}
|
|
36793
38193
|
|
|
36794
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
38194
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/query-builders/query-builder.js
|
|
36795
38195
|
class TypedQueryBuilder {
|
|
36796
38196
|
static [entityKind] = "TypedQueryBuilder";
|
|
36797
38197
|
getSelectedFields() {
|
|
@@ -36799,7 +38199,7 @@ class TypedQueryBuilder {
|
|
|
36799
38199
|
}
|
|
36800
38200
|
}
|
|
36801
38201
|
|
|
36802
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
38202
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/select.js
|
|
36803
38203
|
class SQLiteSelectBuilder {
|
|
36804
38204
|
static [entityKind] = "SQLiteSelectBuilder";
|
|
36805
38205
|
fields;
|
|
@@ -36881,7 +38281,7 @@ class SQLiteSelectQueryBuilderBase extends TypedQueryBuilder {
|
|
|
36881
38281
|
const tableName = getTableLikeName(table);
|
|
36882
38282
|
for (const item of extractUsedTable(table))
|
|
36883
38283
|
this.usedTables.add(item);
|
|
36884
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
38284
|
+
if (typeof tableName === "string" && this.config.joins?.some((join21) => join21.alias === tableName)) {
|
|
36885
38285
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
36886
38286
|
}
|
|
36887
38287
|
if (!this.isPartialSelect) {
|
|
@@ -37097,7 +38497,7 @@ var unionAll = createSetOperator("union", true);
|
|
|
37097
38497
|
var intersect = createSetOperator("intersect", false);
|
|
37098
38498
|
var except = createSetOperator("except", false);
|
|
37099
38499
|
|
|
37100
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
38500
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/query-builder.js
|
|
37101
38501
|
class QueryBuilder {
|
|
37102
38502
|
static [entityKind] = "SQLiteQueryBuilder";
|
|
37103
38503
|
dialect;
|
|
@@ -37156,7 +38556,7 @@ class QueryBuilder {
|
|
|
37156
38556
|
}
|
|
37157
38557
|
}
|
|
37158
38558
|
|
|
37159
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
38559
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/insert.js
|
|
37160
38560
|
class SQLiteInsertBuilder {
|
|
37161
38561
|
constructor(table, session, dialect, withList) {
|
|
37162
38562
|
this.table = table;
|
|
@@ -37265,7 +38665,7 @@ class SQLiteInsertBase extends QueryPromise {
|
|
|
37265
38665
|
}
|
|
37266
38666
|
}
|
|
37267
38667
|
|
|
37268
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
38668
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/update.js
|
|
37269
38669
|
class SQLiteUpdateBuilder {
|
|
37270
38670
|
constructor(table, session, dialect, withList) {
|
|
37271
38671
|
this.table = table;
|
|
@@ -37295,7 +38695,7 @@ class SQLiteUpdateBase extends QueryPromise {
|
|
|
37295
38695
|
createJoin(joinType) {
|
|
37296
38696
|
return (table, on) => {
|
|
37297
38697
|
const tableName = getTableLikeName(table);
|
|
37298
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
38698
|
+
if (typeof tableName === "string" && this.config.joins.some((join21) => join21.alias === tableName)) {
|
|
37299
38699
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
37300
38700
|
}
|
|
37301
38701
|
if (typeof on === "function") {
|
|
@@ -37369,7 +38769,7 @@ class SQLiteUpdateBase extends QueryPromise {
|
|
|
37369
38769
|
}
|
|
37370
38770
|
}
|
|
37371
38771
|
|
|
37372
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
38772
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/count.js
|
|
37373
38773
|
class SQLiteCountBuilder extends SQL {
|
|
37374
38774
|
constructor(params) {
|
|
37375
38775
|
super(SQLiteCountBuilder.buildEmbeddedCount(params.source, params.filters).queryChunks);
|
|
@@ -37404,7 +38804,7 @@ class SQLiteCountBuilder extends SQL {
|
|
|
37404
38804
|
}
|
|
37405
38805
|
}
|
|
37406
38806
|
|
|
37407
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
38807
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/query.js
|
|
37408
38808
|
class RelationalQueryBuilder {
|
|
37409
38809
|
constructor(mode, fullSchema, schema, tableNamesMap, table, tableConfig, dialect, session) {
|
|
37410
38810
|
this.mode = mode;
|
|
@@ -37498,7 +38898,7 @@ class SQLiteSyncRelationalQuery extends SQLiteRelationalQuery {
|
|
|
37498
38898
|
}
|
|
37499
38899
|
}
|
|
37500
38900
|
|
|
37501
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
38901
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/query-builders/raw.js
|
|
37502
38902
|
class SQLiteRaw extends QueryPromise {
|
|
37503
38903
|
constructor(execute, getSQL, action, dialect, mapBatchResult) {
|
|
37504
38904
|
super();
|
|
@@ -37524,7 +38924,7 @@ class SQLiteRaw extends QueryPromise {
|
|
|
37524
38924
|
}
|
|
37525
38925
|
}
|
|
37526
38926
|
|
|
37527
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
38927
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/db.js
|
|
37528
38928
|
class BaseSQLiteDatabase {
|
|
37529
38929
|
constructor(resultKind, dialect, session, schema) {
|
|
37530
38930
|
this.resultKind = resultKind;
|
|
@@ -37647,7 +39047,7 @@ class BaseSQLiteDatabase {
|
|
|
37647
39047
|
}
|
|
37648
39048
|
}
|
|
37649
39049
|
|
|
37650
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
39050
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/cache/core/cache.js
|
|
37651
39051
|
class Cache {
|
|
37652
39052
|
static [entityKind] = "Cache";
|
|
37653
39053
|
}
|
|
@@ -37673,7 +39073,7 @@ async function hashQuery(sql2, params) {
|
|
|
37673
39073
|
return hashHex;
|
|
37674
39074
|
}
|
|
37675
39075
|
|
|
37676
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
39076
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/sqlite-core/session.js
|
|
37677
39077
|
class ExecuteResultSync extends QueryPromise {
|
|
37678
39078
|
constructor(resultCb) {
|
|
37679
39079
|
super();
|
|
@@ -37846,7 +39246,7 @@ class SQLiteTransaction extends BaseSQLiteDatabase {
|
|
|
37846
39246
|
}
|
|
37847
39247
|
}
|
|
37848
39248
|
|
|
37849
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
39249
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/bun-sqlite/session.js
|
|
37850
39250
|
class SQLiteBunSession extends SQLiteSession {
|
|
37851
39251
|
constructor(client, dialect, schema, options = {}) {
|
|
37852
39252
|
super(dialect);
|
|
@@ -37945,7 +39345,7 @@ class PreparedQuery extends SQLitePreparedQuery {
|
|
|
37945
39345
|
}
|
|
37946
39346
|
}
|
|
37947
39347
|
|
|
37948
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
39348
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/bun-sqlite/driver.js
|
|
37949
39349
|
class BunSQLiteDatabase extends BaseSQLiteDatabase {
|
|
37950
39350
|
static [entityKind] = "BunSQLiteDatabase";
|
|
37951
39351
|
}
|
|
@@ -37999,6 +39399,7 @@ function drizzle(...params) {
|
|
|
37999
39399
|
})(drizzle || (drizzle = {}));
|
|
38000
39400
|
|
|
38001
39401
|
// packages/runtime/src/drizzle-schema.ts
|
|
39402
|
+
var epochMsNow = sql`(CAST(strftime('%s','now') AS INTEGER) * 1000)`;
|
|
38002
39403
|
var deliveriesTable = sqliteTable("deliveries", {
|
|
38003
39404
|
id: text("id").primaryKey(),
|
|
38004
39405
|
messageId: text("message_id"),
|
|
@@ -38014,7 +39415,7 @@ var deliveriesTable = sqliteTable("deliveries", {
|
|
|
38014
39415
|
leaseOwner: text("lease_owner"),
|
|
38015
39416
|
leaseExpiresAt: integer2("lease_expires_at"),
|
|
38016
39417
|
metadataJson: text("metadata_json"),
|
|
38017
|
-
createdAt: integer2("created_at").notNull().default(
|
|
39418
|
+
createdAt: integer2("created_at").notNull().default(epochMsNow)
|
|
38018
39419
|
}, (table) => [
|
|
38019
39420
|
index("idx_deliveries_status_transport").on(table.status, table.transport)
|
|
38020
39421
|
]);
|
|
@@ -38041,7 +39442,7 @@ var briefingsTable = sqliteTable("briefings", {
|
|
|
38041
39442
|
snapshotJson: text("snapshot_json").notNull(),
|
|
38042
39443
|
callJson: text("call_json").notNull(),
|
|
38043
39444
|
markdown: text("markdown"),
|
|
38044
|
-
createdAt: integer2("created_at").notNull().default(
|
|
39445
|
+
createdAt: integer2("created_at").notNull().default(epochMsNow)
|
|
38045
39446
|
}, (table) => [
|
|
38046
39447
|
index("idx_briefings_created_at").on(table.createdAt),
|
|
38047
39448
|
index("idx_briefings_kind_created_at").on(table.kind, table.createdAt)
|
|
@@ -38058,11 +39459,11 @@ function openControlPlaneDrizzle(client) {
|
|
|
38058
39459
|
}
|
|
38059
39460
|
|
|
38060
39461
|
// packages/runtime/src/drizzle-migrate.ts
|
|
38061
|
-
import { existsSync as
|
|
38062
|
-
import { join as
|
|
39462
|
+
import { existsSync as existsSync16 } from "fs";
|
|
39463
|
+
import { join as join21 } from "path";
|
|
38063
39464
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
38064
39465
|
|
|
38065
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
39466
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/migrator.js
|
|
38066
39467
|
import crypto2 from "crypto";
|
|
38067
39468
|
import fs from "fs";
|
|
38068
39469
|
function readMigrationFiles(config2) {
|
|
@@ -38094,7 +39495,7 @@ function readMigrationFiles(config2) {
|
|
|
38094
39495
|
return migrationQueries;
|
|
38095
39496
|
}
|
|
38096
39497
|
|
|
38097
|
-
// node_modules/.bun/drizzle-orm@0.45.2+
|
|
39498
|
+
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/bun-sqlite/migrator.js
|
|
38098
39499
|
function migrate(db, config2) {
|
|
38099
39500
|
const migrations = readMigrationFiles(config2);
|
|
38100
39501
|
db.dialect.migrate(migrations, db.session, config2);
|
|
@@ -38128,7 +39529,7 @@ CREATE TABLE IF NOT EXISTS actors (
|
|
|
38128
39529
|
handle TEXT,
|
|
38129
39530
|
labels_json TEXT,
|
|
38130
39531
|
metadata_json TEXT,
|
|
38131
|
-
created_at INTEGER NOT NULL DEFAULT (
|
|
39532
|
+
created_at INTEGER NOT NULL DEFAULT (CAST(strftime('%s','now') AS INTEGER) * 1000)
|
|
38132
39533
|
);
|
|
38133
39534
|
|
|
38134
39535
|
CREATE TABLE IF NOT EXISTS agents (
|
|
@@ -38161,7 +39562,7 @@ CREATE TABLE IF NOT EXISTS agent_endpoints (
|
|
|
38161
39562
|
cwd TEXT,
|
|
38162
39563
|
project_root TEXT,
|
|
38163
39564
|
metadata_json TEXT,
|
|
38164
|
-
updated_at INTEGER NOT NULL DEFAULT (
|
|
39565
|
+
updated_at INTEGER NOT NULL DEFAULT (CAST(strftime('%s','now') AS INTEGER) * 1000)
|
|
38165
39566
|
);
|
|
38166
39567
|
|
|
38167
39568
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
@@ -38175,7 +39576,7 @@ CREATE TABLE IF NOT EXISTS conversations (
|
|
|
38175
39576
|
parent_conversation_id TEXT REFERENCES conversations(id) ON DELETE SET NULL,
|
|
38176
39577
|
message_id TEXT,
|
|
38177
39578
|
metadata_json TEXT,
|
|
38178
|
-
created_at INTEGER NOT NULL DEFAULT (
|
|
39579
|
+
created_at INTEGER NOT NULL DEFAULT (CAST(strftime('%s','now') AS INTEGER) * 1000)
|
|
38179
39580
|
);
|
|
38180
39581
|
|
|
38181
39582
|
CREATE TABLE IF NOT EXISTS conversation_members (
|
|
@@ -38292,7 +39693,7 @@ CREATE TABLE IF NOT EXISTS deliveries (
|
|
|
38292
39693
|
lease_owner TEXT,
|
|
38293
39694
|
lease_expires_at INTEGER,
|
|
38294
39695
|
metadata_json TEXT,
|
|
38295
|
-
created_at INTEGER NOT NULL DEFAULT (
|
|
39696
|
+
created_at INTEGER NOT NULL DEFAULT (CAST(strftime('%s','now') AS INTEGER) * 1000)
|
|
38296
39697
|
);
|
|
38297
39698
|
|
|
38298
39699
|
CREATE TABLE IF NOT EXISTS delivery_attempts (
|
|
@@ -38498,9 +39899,9 @@ CREATE TABLE IF NOT EXISTS mobile_push_registrations (
|
|
|
38498
39899
|
updated_at INTEGER NOT NULL
|
|
38499
39900
|
);
|
|
38500
39901
|
|
|
38501
|
-
-- Briefing Room: persistent archive of
|
|
39902
|
+
-- Briefing Room: persistent archive of Scoutbot-generated briefs.
|
|
38502
39903
|
-- Each row carries three layers \u2014 snapshot (Layer 1), observations (Layer 2),
|
|
38503
|
-
-- brief + call (Layer 3) \u2014 so an operator can audit not just what
|
|
39904
|
+
-- brief + call (Layer 3) \u2014 so an operator can audit not just what Scoutbot said
|
|
38504
39905
|
-- but what it read and how it asked. Rolling 100-cap is enforced in code.
|
|
38505
39906
|
CREATE TABLE IF NOT EXISTS briefings (
|
|
38506
39907
|
id TEXT PRIMARY KEY,
|
|
@@ -38518,7 +39919,7 @@ CREATE TABLE IF NOT EXISTS briefings (
|
|
|
38518
39919
|
-- markdown pipeline landed; rows persisted after step 3 of SCO-037 carry
|
|
38519
39920
|
-- the full markdown document the analyst emitted.
|
|
38520
39921
|
markdown TEXT,
|
|
38521
|
-
created_at INTEGER NOT NULL DEFAULT (
|
|
39922
|
+
created_at INTEGER NOT NULL DEFAULT (CAST(strftime('%s','now') AS INTEGER) * 1000)
|
|
38522
39923
|
);
|
|
38523
39924
|
|
|
38524
39925
|
CREATE INDEX IF NOT EXISTS idx_nodes_mesh_id
|
|
@@ -38629,8 +40030,8 @@ function resolveControlPlaneDrizzleMigrationsFolder() {
|
|
|
38629
40030
|
}
|
|
38630
40031
|
function applyControlPlaneDrizzleMigrations(database) {
|
|
38631
40032
|
const migrationsFolder = resolveControlPlaneDrizzleMigrationsFolder();
|
|
38632
|
-
const journalPath =
|
|
38633
|
-
if (!
|
|
40033
|
+
const journalPath = join21(migrationsFolder, "meta", "_journal.json");
|
|
40034
|
+
if (!existsSync16(journalPath)) {
|
|
38634
40035
|
return false;
|
|
38635
40036
|
}
|
|
38636
40037
|
migrate(openControlPlaneDrizzle(database), { migrationsFolder });
|
|
@@ -38641,35 +40042,14 @@ function stampControlPlaneSchemaVersion(database) {
|
|
|
38641
40042
|
}
|
|
38642
40043
|
if (false) {}
|
|
38643
40044
|
|
|
38644
|
-
// packages/runtime/src/user-config.ts
|
|
38645
|
-
import { existsSync as existsSync16, readFileSync as readFileSync8, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "fs";
|
|
38646
|
-
import { homedir as homedir15 } from "os";
|
|
38647
|
-
import { dirname as dirname11, join as join21 } from "path";
|
|
38648
|
-
function userConfigPath() {
|
|
38649
|
-
return join21(process.env.OPENSCOUT_HOME ?? join21(homedir15(), ".openscout"), "user.json");
|
|
38650
|
-
}
|
|
38651
|
-
function loadUserConfig() {
|
|
38652
|
-
const configPath = userConfigPath();
|
|
38653
|
-
if (!existsSync16(configPath))
|
|
38654
|
-
return {};
|
|
38655
|
-
try {
|
|
38656
|
-
return JSON.parse(readFileSync8(configPath, "utf8"));
|
|
38657
|
-
} catch {
|
|
38658
|
-
return {};
|
|
38659
|
-
}
|
|
38660
|
-
}
|
|
38661
|
-
function resolveOperatorName() {
|
|
38662
|
-
const config2 = loadUserConfig();
|
|
38663
|
-
return config2.name?.trim() || process.env.OPENSCOUT_OPERATOR_NAME?.trim() || process.env.USER?.trim() || "operator";
|
|
38664
|
-
}
|
|
38665
|
-
|
|
38666
40045
|
// packages/runtime/src/conversations/legacy-ids.ts
|
|
38667
40046
|
function conversationIdForAgent(agentId) {
|
|
38668
40047
|
return buildDirectConversationId("operator", agentId);
|
|
38669
40048
|
}
|
|
38670
40049
|
function configuredOperatorActorIds() {
|
|
38671
40050
|
const operatorName = resolveOperatorName().trim() || "operator";
|
|
38672
|
-
|
|
40051
|
+
const operatorHandle = resolveOperatorHandle().trim() || operatorName;
|
|
40052
|
+
return Array.from(new Set(["operator", operatorName, operatorHandle]));
|
|
38673
40053
|
}
|
|
38674
40054
|
function buildDirectConversationId(operatorId, agentId) {
|
|
38675
40055
|
return `dm.${operatorId}.${agentId}`;
|
|
@@ -39984,6 +41364,11 @@ class SQLiteControlPlaneStore {
|
|
|
39984
41364
|
const row = queryGet(this.readDb, "SELECT * FROM durable_actions WHERE id = ?1", actionId);
|
|
39985
41365
|
return row ? durableActionFromRow(row) : null;
|
|
39986
41366
|
}
|
|
41367
|
+
getDurableActionByIdempotencyKey(input) {
|
|
41368
|
+
const row = queryGet(this.readDb, `SELECT * FROM durable_actions
|
|
41369
|
+
WHERE authority_cell_id = ?1 AND kind = ?2 AND idempotency_key = ?3`, input.authorityCellId, input.kind, input.idempotencyKey);
|
|
41370
|
+
return row ? durableActionFromRow(row) : null;
|
|
41371
|
+
}
|
|
39987
41372
|
listDueDurableActions(input) {
|
|
39988
41373
|
const limit = Math.max(1, Math.min(500, Math.floor(input.limit ?? 50)));
|
|
39989
41374
|
const claimableAt = input.claimableAt ?? input.dueAtLte;
|
|
@@ -41431,6 +42816,52 @@ class ThreadEventPlane {
|
|
|
41431
42816
|
}
|
|
41432
42817
|
}
|
|
41433
42818
|
|
|
42819
|
+
// packages/runtime/src/invocation-lifecycle-read-model.ts
|
|
42820
|
+
function readInvocationLifecycle(input) {
|
|
42821
|
+
const invocationId = input.invocationId.trim();
|
|
42822
|
+
if (!invocationId) {
|
|
42823
|
+
return null;
|
|
42824
|
+
}
|
|
42825
|
+
const invocation = input.snapshot.invocations[invocationId];
|
|
42826
|
+
if (!invocation) {
|
|
42827
|
+
return null;
|
|
42828
|
+
}
|
|
42829
|
+
const deliveries2 = input.journal.listDeliveries({ limit: input.deliveryLimit ?? 5000 }).filter((delivery) => deliveryMatchesInvocation(delivery, invocation));
|
|
42830
|
+
const deliveryAttempts = Object.fromEntries(deliveries2.map((delivery) => [
|
|
42831
|
+
delivery.id,
|
|
42832
|
+
input.journal.listDeliveryAttempts(delivery.id)
|
|
42833
|
+
]));
|
|
42834
|
+
return projectInvocationLifecycle({
|
|
42835
|
+
invocation,
|
|
42836
|
+
flight: latestFlightForInvocation(input.snapshot, invocationId),
|
|
42837
|
+
deliveries: deliveries2,
|
|
42838
|
+
deliveryAttempts,
|
|
42839
|
+
now: input.now ?? Date.now()
|
|
42840
|
+
});
|
|
42841
|
+
}
|
|
42842
|
+
function latestFlightForInvocation(snapshot, invocationId) {
|
|
42843
|
+
let latest;
|
|
42844
|
+
for (const flight of Object.values(snapshot.flights)) {
|
|
42845
|
+
if (flight.invocationId !== invocationId) {
|
|
42846
|
+
continue;
|
|
42847
|
+
}
|
|
42848
|
+
if (!latest || flightSortTimestamp(flight) > flightSortTimestamp(latest)) {
|
|
42849
|
+
latest = flight;
|
|
42850
|
+
}
|
|
42851
|
+
}
|
|
42852
|
+
return latest;
|
|
42853
|
+
}
|
|
42854
|
+
function flightSortTimestamp(flight) {
|
|
42855
|
+
return flight.completedAt ?? flight.startedAt ?? 0;
|
|
42856
|
+
}
|
|
42857
|
+
function deliveryMatchesInvocation(delivery, invocation) {
|
|
42858
|
+
return delivery.invocationId === invocation.id || Boolean(invocation.messageId && delivery.messageId === invocation.messageId) || metadataString3(delivery.metadata, "invocationId") === invocation.id;
|
|
42859
|
+
}
|
|
42860
|
+
function metadataString3(metadata, key) {
|
|
42861
|
+
const value = metadata?.[key];
|
|
42862
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
42863
|
+
}
|
|
42864
|
+
|
|
41434
42865
|
// packages/runtime/src/broker-core-service.ts
|
|
41435
42866
|
function normalizeLimit(limit) {
|
|
41436
42867
|
return typeof limit === "number" && Number.isFinite(limit) && limit > 0 ? Math.min(limit, 500) : 100;
|
|
@@ -41453,7 +42884,13 @@ function listBrokerMessages(runtime, input = {}) {
|
|
|
41453
42884
|
}
|
|
41454
42885
|
return authored || addressed || participantConversation;
|
|
41455
42886
|
};
|
|
41456
|
-
return Object.values(snapshot.messages).filter((message) => !input.conversationId || message.conversationId === input.conversationId).filter(matchesParticipant).filter((message) => input.since === null || input.since === undefined ? true : message.createdAt >= input.since).sort((lhs, rhs) => rhs.createdAt - lhs.createdAt).slice(0, limit).reverse();
|
|
42887
|
+
return Object.values(snapshot.messages).filter((message) => !isBrokerRequesterWaitTimeoutStatusMessage(message)).filter((message) => !input.conversationId || message.conversationId === input.conversationId).filter(matchesParticipant).filter((message) => input.since === null || input.since === undefined ? true : message.createdAt >= input.since).sort((lhs, rhs) => rhs.createdAt - lhs.createdAt).slice(0, limit).reverse();
|
|
42888
|
+
}
|
|
42889
|
+
function isBrokerRequesterWaitTimeoutStatusMessage(message) {
|
|
42890
|
+
if (message.class !== "status" || metadataString4(message.metadata, "source") !== "broker") {
|
|
42891
|
+
return false;
|
|
42892
|
+
}
|
|
42893
|
+
return message.body.includes("Scout stopped waiting for a synchronous result") || message.body.includes("the requester stopped waiting after");
|
|
41457
42894
|
}
|
|
41458
42895
|
async function listBrokerActivity(projection, isReconciledStaleFlightActivityItem, input) {
|
|
41459
42896
|
const items = await projection.listActivityItems({
|
|
@@ -41506,7 +42943,7 @@ function compactText(value, fallback) {
|
|
|
41506
42943
|
}
|
|
41507
42944
|
return text2.length > 240 ? `${text2.slice(0, 237)}...` : text2;
|
|
41508
42945
|
}
|
|
41509
|
-
function
|
|
42946
|
+
function metadataString4(metadata, key) {
|
|
41510
42947
|
const value = metadata?.[key];
|
|
41511
42948
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
41512
42949
|
}
|
|
@@ -41514,6 +42951,82 @@ function metadataNumber(metadata, key) {
|
|
|
41514
42951
|
const value = metadata?.[key];
|
|
41515
42952
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
41516
42953
|
}
|
|
42954
|
+
function metadataBoolean(metadata, key) {
|
|
42955
|
+
return metadata?.[key] === true;
|
|
42956
|
+
}
|
|
42957
|
+
function metadataRecord4(metadata, key) {
|
|
42958
|
+
const value = metadata?.[key];
|
|
42959
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
42960
|
+
}
|
|
42961
|
+
function agentCardLifecycleKind(agent) {
|
|
42962
|
+
const lifecycle2 = metadataRecord4(agent.metadata, "cardLifecycle");
|
|
42963
|
+
const kind = metadataString4(lifecycle2, "kind");
|
|
42964
|
+
return kind === "persistent" || kind === "one_time" ? kind : null;
|
|
42965
|
+
}
|
|
42966
|
+
function summarizeBrokerAgentCounts(snapshot, localNodeId) {
|
|
42967
|
+
const counts = {
|
|
42968
|
+
agents: 0,
|
|
42969
|
+
agentRecords: 0,
|
|
42970
|
+
rawAgentRecords: 0,
|
|
42971
|
+
configuredAgents: 0,
|
|
42972
|
+
scoutManagedAgents: 0,
|
|
42973
|
+
currentAgentRegistrations: 0,
|
|
42974
|
+
localAgentRegistrations: 0,
|
|
42975
|
+
remoteAgentRegistrations: 0,
|
|
42976
|
+
staleAgentRegistrations: 0,
|
|
42977
|
+
retiredAgentRegistrations: 0,
|
|
42978
|
+
oneTimeAgentCards: 0,
|
|
42979
|
+
persistentAgentCards: 0
|
|
42980
|
+
};
|
|
42981
|
+
for (const agent of Object.values(snapshot.agents)) {
|
|
42982
|
+
counts.agentRecords += 1;
|
|
42983
|
+
counts.rawAgentRecords += 1;
|
|
42984
|
+
const retired = metadataBoolean(agent.metadata, "retiredFromFleet");
|
|
42985
|
+
const stale = metadataBoolean(agent.metadata, "staleLocalRegistration");
|
|
42986
|
+
const current = !retired && !stale;
|
|
42987
|
+
const local = agent.homeNodeId === localNodeId || agent.authorityNodeId === localNodeId;
|
|
42988
|
+
const lifecycleKind = agentCardLifecycleKind(agent);
|
|
42989
|
+
const oneTimeCard = lifecycleKind === "one_time";
|
|
42990
|
+
const persistentCard = lifecycleKind === "persistent";
|
|
42991
|
+
const source = metadataString4(agent.metadata, "source");
|
|
42992
|
+
const externalSource = metadataString4(agent.metadata, "externalSource");
|
|
42993
|
+
const registryBacked = source === undefined || source === "relay-agent-registry";
|
|
42994
|
+
const durableScoutManaged = source === "scout-managed" && externalSource !== "pairing-session";
|
|
42995
|
+
if (retired) {
|
|
42996
|
+
counts.retiredAgentRegistrations += 1;
|
|
42997
|
+
}
|
|
42998
|
+
if (stale) {
|
|
42999
|
+
counts.staleAgentRegistrations += 1;
|
|
43000
|
+
}
|
|
43001
|
+
if (!current) {
|
|
43002
|
+
continue;
|
|
43003
|
+
}
|
|
43004
|
+
counts.currentAgentRegistrations += 1;
|
|
43005
|
+
if (local) {
|
|
43006
|
+
counts.localAgentRegistrations += 1;
|
|
43007
|
+
} else {
|
|
43008
|
+
counts.remoteAgentRegistrations += 1;
|
|
43009
|
+
}
|
|
43010
|
+
if (oneTimeCard) {
|
|
43011
|
+
counts.oneTimeAgentCards += 1;
|
|
43012
|
+
}
|
|
43013
|
+
if (persistentCard) {
|
|
43014
|
+
counts.persistentAgentCards += 1;
|
|
43015
|
+
}
|
|
43016
|
+
if (!local || oneTimeCard) {
|
|
43017
|
+
continue;
|
|
43018
|
+
}
|
|
43019
|
+
if (registryBacked) {
|
|
43020
|
+
counts.configuredAgents += 1;
|
|
43021
|
+
continue;
|
|
43022
|
+
}
|
|
43023
|
+
if (durableScoutManaged) {
|
|
43024
|
+
counts.scoutManagedAgents += 1;
|
|
43025
|
+
}
|
|
43026
|
+
}
|
|
43027
|
+
counts.agents = counts.configuredAgents + counts.scoutManagedAgents;
|
|
43028
|
+
return counts;
|
|
43029
|
+
}
|
|
41517
43030
|
function messageMentionsAgent(message, agentId) {
|
|
41518
43031
|
return message.actorId === agentId || Boolean(message.mentions?.some((mention) => mention.actorId === agentId)) || Boolean(message.audience?.notify?.includes(agentId)) || Boolean(message.audience?.invoke?.includes(agentId)) || Boolean(message.audience?.visibleTo?.includes(agentId));
|
|
41519
43032
|
}
|
|
@@ -41683,7 +43196,7 @@ function deliveryToFeedItem(delivery, snapshot, attempts) {
|
|
|
41683
43196
|
severity: deliverySeverity(delivery.status),
|
|
41684
43197
|
at: deliveryAt(delivery, snapshot, attempts),
|
|
41685
43198
|
title: `Delivery ${delivery.status}`,
|
|
41686
|
-
summary: compactText(
|
|
43199
|
+
summary: compactText(metadataString4(delivery.metadata, "failureReason") ?? metadataString4(delivery.metadata, "lastError") ?? `${delivery.reason} via ${delivery.transport}`, delivery.status),
|
|
41687
43200
|
agentId: delivery.targetId,
|
|
41688
43201
|
targetAgentId: delivery.targetId,
|
|
41689
43202
|
conversationId: invocation?.conversationId,
|
|
@@ -41828,8 +43341,8 @@ function endpointStatus(endpoint) {
|
|
|
41828
43341
|
sessionId: endpoint.sessionId,
|
|
41829
43342
|
projectRoot: endpoint.projectRoot,
|
|
41830
43343
|
cwd: endpoint.cwd,
|
|
41831
|
-
lastError:
|
|
41832
|
-
lastFailureStage:
|
|
43344
|
+
lastError: metadataString4(endpoint.metadata, "lastError"),
|
|
43345
|
+
lastFailureStage: metadataString4(endpoint.metadata, "lastFailureStage"),
|
|
41833
43346
|
updatedAt: metadataNumber(endpoint.metadata, "lastFailedAt") ?? metadataNumber(endpoint.metadata, "lastSeenAt")
|
|
41834
43347
|
};
|
|
41835
43348
|
}
|
|
@@ -41933,6 +43446,7 @@ function createBrokerCoreService(deps) {
|
|
|
41933
43446
|
baseUrl: deps.baseUrl,
|
|
41934
43447
|
readHealth: async () => {
|
|
41935
43448
|
const snapshot = deps.runtime.snapshot();
|
|
43449
|
+
const agentCounts = summarizeBrokerAgentCounts(snapshot, deps.nodeId);
|
|
41936
43450
|
return {
|
|
41937
43451
|
ok: true,
|
|
41938
43452
|
nodeId: deps.nodeId,
|
|
@@ -41940,7 +43454,18 @@ function createBrokerCoreService(deps) {
|
|
|
41940
43454
|
counts: {
|
|
41941
43455
|
nodes: Object.keys(snapshot.nodes).length,
|
|
41942
43456
|
actors: Object.keys(snapshot.actors).length,
|
|
41943
|
-
agents:
|
|
43457
|
+
agents: agentCounts.agents,
|
|
43458
|
+
agentRecords: agentCounts.agentRecords,
|
|
43459
|
+
rawAgentRecords: agentCounts.rawAgentRecords,
|
|
43460
|
+
configuredAgents: agentCounts.configuredAgents,
|
|
43461
|
+
scoutManagedAgents: agentCounts.scoutManagedAgents,
|
|
43462
|
+
currentAgentRegistrations: agentCounts.currentAgentRegistrations,
|
|
43463
|
+
localAgentRegistrations: agentCounts.localAgentRegistrations,
|
|
43464
|
+
remoteAgentRegistrations: agentCounts.remoteAgentRegistrations,
|
|
43465
|
+
staleAgentRegistrations: agentCounts.staleAgentRegistrations,
|
|
43466
|
+
retiredAgentRegistrations: agentCounts.retiredAgentRegistrations,
|
|
43467
|
+
oneTimeAgentCards: agentCounts.oneTimeAgentCards,
|
|
43468
|
+
persistentAgentCards: agentCounts.persistentAgentCards,
|
|
41944
43469
|
conversations: Object.keys(snapshot.conversations).length,
|
|
41945
43470
|
messages: Object.keys(snapshot.messages).length,
|
|
41946
43471
|
flights: Object.keys(snapshot.flights).length,
|
|
@@ -41958,6 +43483,11 @@ function createBrokerCoreService(deps) {
|
|
|
41958
43483
|
readUnblockRequests: async (query) => listBrokerUnblockRequests(deps.journal, query),
|
|
41959
43484
|
readUnblockRequestEvents: async (query) => listBrokerUnblockRequestEvents(deps.journal, query),
|
|
41960
43485
|
readAgentBrokerFeed: async (query) => await readAgentBrokerFeed(deps, query),
|
|
43486
|
+
readInvocationLifecycle: async (query) => readInvocationLifecycle({
|
|
43487
|
+
snapshot: deps.runtime.snapshot(),
|
|
43488
|
+
journal: deps.journal,
|
|
43489
|
+
invocationId: query.invocationId
|
|
43490
|
+
}),
|
|
41961
43491
|
readThreadEvents: async (query) => await deps.threadEvents.replay({
|
|
41962
43492
|
conversationId: query.conversationId,
|
|
41963
43493
|
afterSeq: query.afterSeq ?? 0,
|
|
@@ -42652,6 +44182,9 @@ async function broadcastApnsAlertToActiveMobileDevices(alert) {
|
|
|
42652
44182
|
}
|
|
42653
44183
|
|
|
42654
44184
|
// packages/runtime/src/broker-daemon.ts
|
|
44185
|
+
var PROCESS_NAME = "scout-broker";
|
|
44186
|
+
var WEB_PROCESS_NAME = "scout-web";
|
|
44187
|
+
process.title = PROCESS_NAME;
|
|
42655
44188
|
function createRuntimeId2(prefix) {
|
|
42656
44189
|
return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
42657
44190
|
}
|
|
@@ -42728,6 +44261,7 @@ var parentPid = Number.parseInt(process.env.OPENSCOUT_PARENT_PID ?? "0", 10);
|
|
|
42728
44261
|
var localAgentSyncIntervalMs = Number.parseInt(process.env.OPENSCOUT_LOCAL_AGENT_SYNC_INTERVAL_MS ?? "5000", 10);
|
|
42729
44262
|
var registeredLocalAgentsRegistrySignature = null;
|
|
42730
44263
|
var registeredLocalAgentsSyncInFlight = null;
|
|
44264
|
+
var DEFAULT_IMPLICIT_PROJECT_CARD_TTL_MS = 24 * 60 * 60 * 1000;
|
|
42731
44265
|
ensureOpenScoutCleanSlateSync();
|
|
42732
44266
|
var existingBroker = await probeExistingBroker();
|
|
42733
44267
|
if (existingBroker) {
|
|
@@ -42824,6 +44358,7 @@ var DEFAULT_INBOX_STATUSES = new Set([
|
|
|
42824
44358
|
"deferred",
|
|
42825
44359
|
"leased"
|
|
42826
44360
|
]);
|
|
44361
|
+
var STALE_MESH_AUTHORITY_NODE_MS = 24 * 60 * 60 * 1000;
|
|
42827
44362
|
async function listInboxItems(options) {
|
|
42828
44363
|
const statuses = options.statuses ?? DEFAULT_INBOX_STATUSES;
|
|
42829
44364
|
const limit = Math.min(Math.max(options.limit ?? 100, 1), 500);
|
|
@@ -43231,18 +44766,47 @@ function spawnWebServer(context = {}) {
|
|
|
43231
44766
|
trustedHost: context.trustedHost
|
|
43232
44767
|
});
|
|
43233
44768
|
const child = spawn5(bun.path, entry.endsWith(".ts") ? ["run", "--hot", entry] : ["run", entry], {
|
|
44769
|
+
argv0: WEB_PROCESS_NAME,
|
|
43234
44770
|
detached: true,
|
|
43235
44771
|
env,
|
|
43236
44772
|
stdio: ["ignore", logFd, logFd]
|
|
43237
44773
|
});
|
|
43238
|
-
child.once("exit", () => {
|
|
43239
|
-
if (webServerProcess
|
|
43240
|
-
|
|
44774
|
+
child.once("exit", (code, signal) => {
|
|
44775
|
+
if (webServerProcess !== child) {
|
|
44776
|
+
return;
|
|
44777
|
+
}
|
|
44778
|
+
webServerProcess = null;
|
|
44779
|
+
if (shuttingDown) {
|
|
44780
|
+
return;
|
|
44781
|
+
}
|
|
44782
|
+
const now = Date.now();
|
|
44783
|
+
while (webRespawnFailures.length > 0 && now - webRespawnFailures[0] > WEB_RESPAWN_FAILURE_WINDOW_MS) {
|
|
44784
|
+
webRespawnFailures.shift();
|
|
43241
44785
|
}
|
|
44786
|
+
webRespawnFailures.push(now);
|
|
44787
|
+
if (webRespawnFailures.length > WEB_RESPAWN_MAX_FAILURES) {
|
|
44788
|
+
console.error(`[openscout-runtime] Scout web server has exited ${webRespawnFailures.length} times within ${WEB_RESPAWN_FAILURE_WINDOW_MS / 1000}s \u2014 pausing auto-respawn. Use 'scout server start' to retry.`);
|
|
44789
|
+
webRespawnFailures.length = 0;
|
|
44790
|
+
return;
|
|
44791
|
+
}
|
|
44792
|
+
const delay = Math.min(WEB_RESPAWN_BASE_DELAY_MS * webRespawnFailures.length, WEB_RESPAWN_MAX_DELAY_MS);
|
|
44793
|
+
console.warn(`[openscout-runtime] Scout web server exited unexpectedly (code=${code}, signal=${signal}) \u2014 respawning in ${delay}ms (failure ${webRespawnFailures.length}/${WEB_RESPAWN_MAX_FAILURES})`);
|
|
44794
|
+
setTimeout(() => {
|
|
44795
|
+
if (shuttingDown)
|
|
44796
|
+
return;
|
|
44797
|
+
startWebServerIfNeeded(context).catch((error48) => {
|
|
44798
|
+
console.error("[openscout-runtime] web server respawn failed:", error48);
|
|
44799
|
+
});
|
|
44800
|
+
}, delay).unref?.();
|
|
43242
44801
|
});
|
|
43243
44802
|
child.unref();
|
|
43244
44803
|
return child;
|
|
43245
44804
|
}
|
|
44805
|
+
var WEB_RESPAWN_BASE_DELAY_MS = 1000;
|
|
44806
|
+
var WEB_RESPAWN_MAX_DELAY_MS = 30000;
|
|
44807
|
+
var WEB_RESPAWN_MAX_FAILURES = 5;
|
|
44808
|
+
var WEB_RESPAWN_FAILURE_WINDOW_MS = 60000;
|
|
44809
|
+
var webRespawnFailures = [];
|
|
43246
44810
|
async function webSupervisorStatus(error48 = null) {
|
|
43247
44811
|
const running = await isWebServerHealthy();
|
|
43248
44812
|
return {
|
|
@@ -43468,12 +45032,21 @@ async function recordInvocationDurably(invocation, options = {}) {
|
|
|
43468
45032
|
});
|
|
43469
45033
|
}
|
|
43470
45034
|
async function recordFlightDurably(flight) {
|
|
45035
|
+
let recordedFlight = null;
|
|
43471
45036
|
await runDurableWrite(async () => {
|
|
45037
|
+
const previous = runtime.snapshot().flights[flight.id];
|
|
45038
|
+
if (previous && shouldIgnoreFlightUpdate(previous, flight)) {
|
|
45039
|
+
console.warn(`[openscout-runtime] ignored stale flight update ${flight.id}: ${previous.state} -> ${flight.state}`);
|
|
45040
|
+
return;
|
|
45041
|
+
}
|
|
43472
45042
|
const entries = await commitDurableEntries({ kind: "flight.record", flight }, async () => {
|
|
43473
45043
|
await runtime.upsertFlight(flight);
|
|
43474
45044
|
}, { enqueueProjection: false });
|
|
43475
45045
|
await applyProjectedEntries(entries);
|
|
45046
|
+
recordedFlight = flight;
|
|
43476
45047
|
});
|
|
45048
|
+
if (!recordedFlight)
|
|
45049
|
+
return;
|
|
43477
45050
|
const invocation = knownInvocations.get(flight.invocationId) ?? runtime.snapshot().invocations[flight.invocationId];
|
|
43478
45051
|
await reconcileMessageDeliveriesForFlight(flight, invocation);
|
|
43479
45052
|
if (invocation && isTerminalFlightState(flight.state)) {
|
|
@@ -43489,7 +45062,18 @@ async function recordFlightDurably(flight) {
|
|
|
43489
45062
|
console.warn(`[openscout-runtime] failed to forward flight ${flight.id} to conversation authority:`, error48 instanceof Error ? error48.message : String(error48));
|
|
43490
45063
|
}
|
|
43491
45064
|
}
|
|
45065
|
+
function shouldIgnoreFlightUpdate(previous, next) {
|
|
45066
|
+
return isTerminalFlightState(previous.state) && !isTerminalFlightState(next.state);
|
|
45067
|
+
}
|
|
43492
45068
|
var terminalDeliveryStatuses = new Set(["completed", "failed", "cancelled"]);
|
|
45069
|
+
var staleReconcileableDeliveryStatuses = new Set([
|
|
45070
|
+
"accepted",
|
|
45071
|
+
"deferred",
|
|
45072
|
+
"leased",
|
|
45073
|
+
"pending",
|
|
45074
|
+
"running",
|
|
45075
|
+
"sent"
|
|
45076
|
+
]);
|
|
43493
45077
|
function deliveryStatusForFlight(flight) {
|
|
43494
45078
|
if (flight.state === "running" || flight.state === "waiting") {
|
|
43495
45079
|
return "running";
|
|
@@ -43528,6 +45112,46 @@ async function reconcileMessageDeliveriesForFlight(flight, invocation) {
|
|
|
43528
45112
|
});
|
|
43529
45113
|
}
|
|
43530
45114
|
}
|
|
45115
|
+
function staleLocalDeliveryReason(snapshot, delivery) {
|
|
45116
|
+
if (delivery.targetKind !== "agent" || !staleReconcileableDeliveryStatuses.has(delivery.status)) {
|
|
45117
|
+
return null;
|
|
45118
|
+
}
|
|
45119
|
+
const endpoints = Object.values(snapshot.endpoints).filter((endpoint) => endpoint.agentId === delivery.targetId);
|
|
45120
|
+
if (endpoints.length === 0) {
|
|
45121
|
+
return null;
|
|
45122
|
+
}
|
|
45123
|
+
if (endpoints.some((endpoint) => staleLocalEndpointReason(endpoint) === null)) {
|
|
45124
|
+
return null;
|
|
45125
|
+
}
|
|
45126
|
+
const staleEndpoints = endpoints.filter((endpoint) => staleLocalEndpointReason(endpoint) !== null).sort((left, right) => endpointStartedAt(right) - endpointStartedAt(left));
|
|
45127
|
+
const transportMatch = staleEndpoints.find((endpoint) => endpoint.transport === delivery.transport);
|
|
45128
|
+
return staleLocalEndpointReason(transportMatch ?? staleEndpoints[0] ?? null);
|
|
45129
|
+
}
|
|
45130
|
+
async function reconcileStaleLocalDeliveries() {
|
|
45131
|
+
const snapshot = runtime.snapshot();
|
|
45132
|
+
const now = Date.now();
|
|
45133
|
+
for (const delivery of journal.listDeliveries({ limit: 5000 })) {
|
|
45134
|
+
const reason = staleLocalDeliveryReason(snapshot, delivery);
|
|
45135
|
+
if (!reason) {
|
|
45136
|
+
continue;
|
|
45137
|
+
}
|
|
45138
|
+
await updateDeliveryStatusDurably({
|
|
45139
|
+
deliveryId: delivery.id,
|
|
45140
|
+
status: "failed",
|
|
45141
|
+
metadata: {
|
|
45142
|
+
failureReason: "agent_offline",
|
|
45143
|
+
failureDetail: `Stale local delivery reconciled: ${reason}`,
|
|
45144
|
+
staleLocalRegistration: true,
|
|
45145
|
+
reconciledStaleDelivery: true,
|
|
45146
|
+
reconciledReason: reason,
|
|
45147
|
+
reconciledAt: now
|
|
45148
|
+
},
|
|
45149
|
+
leaseOwner: null,
|
|
45150
|
+
leaseExpiresAt: null
|
|
45151
|
+
});
|
|
45152
|
+
console.warn(`[openscout-runtime] reconciled stale local delivery ${delivery.id}: ${reason}`);
|
|
45153
|
+
}
|
|
45154
|
+
}
|
|
43531
45155
|
async function recordDeliveryDurably(delivery) {
|
|
43532
45156
|
await runDurableWrite(async () => {
|
|
43533
45157
|
await commitDurableEntries({ kind: "deliveries.record", deliveries: [delivery] }, async () => {});
|
|
@@ -43913,17 +45537,61 @@ function latestEndpointForAgent(snapshot, agentId) {
|
|
|
43913
45537
|
const candidates = Object.values(snapshot.endpoints).filter((endpoint) => endpoint.agentId === agentId);
|
|
43914
45538
|
return [...candidates].sort((left, right) => Math.max(endpointTerminalAt(right), endpointStartedAt(right)) - Math.max(endpointTerminalAt(left), endpointStartedAt(left)))[0] ?? null;
|
|
43915
45539
|
}
|
|
45540
|
+
function staleLocalEndpointReason(endpoint) {
|
|
45541
|
+
if (!endpoint || endpoint.metadata?.staleLocalRegistration !== true) {
|
|
45542
|
+
return null;
|
|
45543
|
+
}
|
|
45544
|
+
const replacementAgentId = endpoint.metadata.replacedByAgentId;
|
|
45545
|
+
const replacement = typeof replacementAgentId === "string" && replacementAgentId.trim().length > 0 ? `; replacement agent is ${replacementAgentId.trim()}` : "";
|
|
45546
|
+
return `endpoint ${endpoint.id} is a stale local registration superseded by current setup${replacement}`;
|
|
45547
|
+
}
|
|
45548
|
+
function flightDispatchEndpointId(flight) {
|
|
45549
|
+
const dispatchAck = flight.metadata?.dispatchAck;
|
|
45550
|
+
if (!dispatchAck || typeof dispatchAck !== "object" || Array.isArray(dispatchAck)) {
|
|
45551
|
+
return null;
|
|
45552
|
+
}
|
|
45553
|
+
const endpointId = dispatchAck.endpointId;
|
|
45554
|
+
return typeof endpointId === "string" && endpointId.trim().length > 0 ? endpointId.trim() : null;
|
|
45555
|
+
}
|
|
45556
|
+
function endpointForFlight(snapshot, flight) {
|
|
45557
|
+
const dispatchedEndpointId = flightDispatchEndpointId(flight);
|
|
45558
|
+
if (dispatchedEndpointId) {
|
|
45559
|
+
const endpoint = snapshot.endpoints[dispatchedEndpointId];
|
|
45560
|
+
if (endpoint?.agentId === flight.targetAgentId) {
|
|
45561
|
+
return endpoint;
|
|
45562
|
+
}
|
|
45563
|
+
return null;
|
|
45564
|
+
}
|
|
45565
|
+
return latestEndpointForAgent(snapshot, flight.targetAgentId);
|
|
45566
|
+
}
|
|
45567
|
+
function flightDispatchEndpointUnavailableReason(snapshot, flight) {
|
|
45568
|
+
const dispatchedEndpointId = flightDispatchEndpointId(flight);
|
|
45569
|
+
if (!dispatchedEndpointId) {
|
|
45570
|
+
return null;
|
|
45571
|
+
}
|
|
45572
|
+
const endpoint = snapshot.endpoints[dispatchedEndpointId];
|
|
45573
|
+
if (!endpoint) {
|
|
45574
|
+
return `dispatched endpoint ${dispatchedEndpointId} is no longer registered`;
|
|
45575
|
+
}
|
|
45576
|
+
if (endpoint.agentId !== flight.targetAgentId) {
|
|
45577
|
+
return `dispatched endpoint ${dispatchedEndpointId} no longer belongs to target agent ${flight.targetAgentId}`;
|
|
45578
|
+
}
|
|
45579
|
+
return null;
|
|
45580
|
+
}
|
|
43916
45581
|
function isReconciledStaleFlightActivityItem(item) {
|
|
43917
45582
|
return item.kind === "flight_updated" && typeof item.summary === "string" && item.summary.startsWith("Stale running flight reconciled:");
|
|
43918
45583
|
}
|
|
43919
|
-
function
|
|
43920
|
-
return agent?.metadata?.
|
|
45584
|
+
function isRetiredLocalAgent(agent) {
|
|
45585
|
+
return agent?.metadata?.retiredFromFleet === true;
|
|
45586
|
+
}
|
|
45587
|
+
function isInactiveLocalAgent(agent) {
|
|
45588
|
+
return isRetiredLocalAgent(agent) || agent?.metadata?.staleLocalRegistration === true;
|
|
43921
45589
|
}
|
|
43922
45590
|
function isStaleLocalEndpoint(snapshot, endpoint) {
|
|
43923
45591
|
if (!endpoint || endpoint.metadata?.staleLocalRegistration === true) {
|
|
43924
45592
|
return true;
|
|
43925
45593
|
}
|
|
43926
|
-
return
|
|
45594
|
+
return isInactiveLocalAgent(snapshot.agents[endpoint.agentId]);
|
|
43927
45595
|
}
|
|
43928
45596
|
function homeEndpointForAgent(snapshot, agentId) {
|
|
43929
45597
|
const candidates = Object.values(snapshot.endpoints).filter((endpoint) => endpoint.agentId === agentId && !isStaleLocalEndpoint(snapshot, endpoint));
|
|
@@ -43977,6 +45645,20 @@ function metadataStringValue2(metadata, key) {
|
|
|
43977
45645
|
const value = metadata?.[key];
|
|
43978
45646
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
43979
45647
|
}
|
|
45648
|
+
function scoutbotReplyProvenanceMetadata(invocation) {
|
|
45649
|
+
if (invocation.targetAgentId !== "scoutbot") {
|
|
45650
|
+
return {};
|
|
45651
|
+
}
|
|
45652
|
+
return {
|
|
45653
|
+
source: metadataStringValue2(invocation.metadata, "source") ?? "scoutbot",
|
|
45654
|
+
requestedBy: metadataStringValue2(invocation.metadata, "requestedBy") ?? invocation.requesterId,
|
|
45655
|
+
sourceMessageId: metadataStringValue2(invocation.metadata, "sourceMessageId") ?? invocation.messageId ?? null,
|
|
45656
|
+
parentScoutbotTurnId: metadataStringValue2(invocation.metadata, "parentScoutbotTurnId"),
|
|
45657
|
+
generatedBy: metadataStringValue2(invocation.metadata, "generatedBy") ?? "scoutbot",
|
|
45658
|
+
scoutbotThreadId: metadataStringValue2(invocation.metadata, "scoutbotThreadId"),
|
|
45659
|
+
targetSessionId: metadataStringValue2(invocation.metadata, "targetSessionId")
|
|
45660
|
+
};
|
|
45661
|
+
}
|
|
43980
45662
|
function brokerTargetProjectRoot(agent, endpoint) {
|
|
43981
45663
|
return endpoint?.projectRoot ?? endpoint?.cwd ?? metadataStringValue2(agent.metadata, "projectRoot");
|
|
43982
45664
|
}
|
|
@@ -44185,7 +45867,7 @@ function buildBrokerReturnAddressForActor(snapshot, actorId, options = {}) {
|
|
|
44185
45867
|
replyToMessageId: options.replyToMessageId,
|
|
44186
45868
|
nodeId: endpoint?.nodeId || agent?.authorityNodeId || agent?.homeNodeId,
|
|
44187
45869
|
projectRoot: endpoint?.projectRoot ?? endpoint?.cwd ?? metadataStringValue2(agent?.metadata, "projectRoot") ?? undefined,
|
|
44188
|
-
sessionId: endpoint?.sessionId
|
|
45870
|
+
sessionId: options.sessionId ?? endpoint?.sessionId
|
|
44189
45871
|
});
|
|
44190
45872
|
}
|
|
44191
45873
|
function describeUnavailableDeliveryTarget(snapshot, agent) {
|
|
@@ -44203,20 +45885,8 @@ function describeUnavailableDeliveryTarget(snapshot, agent) {
|
|
|
44203
45885
|
projectRoot
|
|
44204
45886
|
};
|
|
44205
45887
|
}
|
|
44206
|
-
if (agent.metadata?.staleLocalRegistration === true) {
|
|
44207
|
-
return {
|
|
44208
|
-
agentId: agent.id,
|
|
44209
|
-
displayName: agent.displayName ?? agent.id,
|
|
44210
|
-
reason: "stale_registration",
|
|
44211
|
-
detail: `${agent.displayName ?? agent.id} has a stale registration and needs operator follow-up before the broker can route to it again.`,
|
|
44212
|
-
wakePolicy: agent.wakePolicy,
|
|
44213
|
-
endpointState: endpoint?.state === "offline" ? "offline" : "unknown",
|
|
44214
|
-
transport: endpoint?.transport ?? null,
|
|
44215
|
-
projectRoot
|
|
44216
|
-
};
|
|
44217
|
-
}
|
|
44218
45888
|
if (agent.authorityNodeId && agent.authorityNodeId !== nodeId) {
|
|
44219
|
-
return
|
|
45889
|
+
return describeRemoteAuthorityIssue(agent, snapshot.nodes[agent.authorityNodeId]);
|
|
44220
45890
|
}
|
|
44221
45891
|
if (agent.wakePolicy !== "manual") {
|
|
44222
45892
|
return null;
|
|
@@ -44298,7 +45968,7 @@ function summarizeHomeAgent(endpoint) {
|
|
|
44298
45968
|
}
|
|
44299
45969
|
async function brokerHomePayload() {
|
|
44300
45970
|
const snapshot = runtime.snapshot();
|
|
44301
|
-
const agents = Object.values(snapshot.agents).filter((agent) => !
|
|
45971
|
+
const agents = Object.values(snapshot.agents).filter((agent) => !isInactiveLocalAgent(agent)).map((agent) => {
|
|
44302
45972
|
const endpoint = homeEndpointForAgent(snapshot, agent.id);
|
|
44303
45973
|
const status = summarizeHomeAgent(endpoint);
|
|
44304
45974
|
return {
|
|
@@ -44352,20 +46022,33 @@ function staleWorkingFlightReason(snapshot, flight) {
|
|
|
44352
46022
|
if (!isWorkingFlightState(flight.state)) {
|
|
44353
46023
|
return null;
|
|
44354
46024
|
}
|
|
46025
|
+
if (activeInvocationTasks.has(flight.invocationId)) {
|
|
46026
|
+
return null;
|
|
46027
|
+
}
|
|
44355
46028
|
const startedAt = flightTimestamp(flight);
|
|
44356
46029
|
const newerTerminalFlight = Object.values(snapshot.flights).filter((candidate) => candidate.targetAgentId === flight.targetAgentId && candidate.id !== flight.id && !isWorkingFlightState(candidate.state) && flightTimestamp(candidate) > startedAt).sort((left, right) => flightTimestamp(right) - flightTimestamp(left))[0] ?? null;
|
|
44357
46030
|
if (newerTerminalFlight) {
|
|
44358
46031
|
return `superseded by newer ${newerTerminalFlight.state} flight ${newerTerminalFlight.id}`;
|
|
44359
46032
|
}
|
|
44360
46033
|
const agent = snapshot.agents[flight.targetAgentId];
|
|
44361
|
-
if (
|
|
44362
|
-
|
|
44363
|
-
|
|
46034
|
+
if (isRetiredLocalAgent(agent)) {
|
|
46035
|
+
return `target agent ${flight.targetAgentId} was retired from the fleet`;
|
|
46036
|
+
}
|
|
46037
|
+
if (agent?.metadata?.staleLocalRegistration === true) {
|
|
46038
|
+
return staleLocalEndpointReason(latestEndpointForAgent(snapshot, flight.targetAgentId)) ?? `target agent ${flight.targetAgentId} is a stale local registration superseded by current setup`;
|
|
44364
46039
|
}
|
|
44365
|
-
const
|
|
46040
|
+
const dispatchEndpointReason = flightDispatchEndpointUnavailableReason(snapshot, flight);
|
|
46041
|
+
if (dispatchEndpointReason) {
|
|
46042
|
+
return dispatchEndpointReason;
|
|
46043
|
+
}
|
|
46044
|
+
const endpoint = endpointForFlight(snapshot, flight);
|
|
44366
46045
|
if (!endpoint) {
|
|
44367
46046
|
return null;
|
|
44368
46047
|
}
|
|
46048
|
+
const staleEndpointReason = staleLocalEndpointReason(endpoint);
|
|
46049
|
+
if (staleEndpointReason) {
|
|
46050
|
+
return staleEndpointReason;
|
|
46051
|
+
}
|
|
44369
46052
|
const terminalAt = endpointTerminalAt(endpoint);
|
|
44370
46053
|
if (endpoint.state !== "active" && terminalAt > startedAt) {
|
|
44371
46054
|
return `endpoint ${endpoint.id} moved to ${endpoint.state} at ${terminalAt}`;
|
|
@@ -44457,7 +46140,7 @@ function uniqueManagedAgentSelector(snapshot, requestedSelector, currentAgentId)
|
|
|
44457
46140
|
for (let counter = 2;counter <= 101; counter += 1) {
|
|
44458
46141
|
const resolution = resolveAgentLabel(snapshot, candidate, {
|
|
44459
46142
|
preferLocalNodeId: nodeId,
|
|
44460
|
-
helpers: { isStale:
|
|
46143
|
+
helpers: { isStale: isInactiveLocalAgent }
|
|
44461
46144
|
});
|
|
44462
46145
|
if (resolution.kind === "unknown") {
|
|
44463
46146
|
return candidate;
|
|
@@ -44610,7 +46293,7 @@ function resolveManagedSessionAttachTarget(snapshot, input) {
|
|
|
44610
46293
|
const directAgentId = input.agentId?.trim();
|
|
44611
46294
|
if (directAgentId) {
|
|
44612
46295
|
const agent = snapshot.agents[directAgentId];
|
|
44613
|
-
if (!agent ||
|
|
46296
|
+
if (!agent || isInactiveLocalAgent(agent)) {
|
|
44614
46297
|
throw new Error(`unknown Scout agent ${directAgentId}`);
|
|
44615
46298
|
}
|
|
44616
46299
|
if (agent.authorityNodeId !== nodeId) {
|
|
@@ -44624,7 +46307,7 @@ function resolveManagedSessionAttachTarget(snapshot, input) {
|
|
|
44624
46307
|
}
|
|
44625
46308
|
const resolution = resolveAgentLabel(snapshot, selector, {
|
|
44626
46309
|
preferLocalNodeId: nodeId,
|
|
44627
|
-
helpers: { isStale:
|
|
46310
|
+
helpers: { isStale: isInactiveLocalAgent }
|
|
44628
46311
|
});
|
|
44629
46312
|
switch (resolution.kind) {
|
|
44630
46313
|
case "resolved":
|
|
@@ -44663,6 +46346,41 @@ function staleLocalAgentReplacementId(definitionId, activeAgentIdsByDefinition)
|
|
|
44663
46346
|
}
|
|
44664
46347
|
return null;
|
|
44665
46348
|
}
|
|
46349
|
+
function staleRegistrationMetadataMatches(metadata, replacementAgentId) {
|
|
46350
|
+
if (metadata?.staleLocalRegistration !== true) {
|
|
46351
|
+
return false;
|
|
46352
|
+
}
|
|
46353
|
+
if (!replacementAgentId) {
|
|
46354
|
+
return true;
|
|
46355
|
+
}
|
|
46356
|
+
const existingReplacement = typeof metadata.replacedByAgentId === "string" ? metadata.replacedByAgentId.trim() : "";
|
|
46357
|
+
return existingReplacement === replacementAgentId;
|
|
46358
|
+
}
|
|
46359
|
+
function staleLocalRegistrationMetadata(metadata, staleAt, replacementAgentId) {
|
|
46360
|
+
const existingReplacement = typeof metadata?.replacedByAgentId === "string" ? metadata.replacedByAgentId.trim() : "";
|
|
46361
|
+
const next = {
|
|
46362
|
+
...metadata ?? {},
|
|
46363
|
+
staleLocalRegistration: true,
|
|
46364
|
+
staleAt
|
|
46365
|
+
};
|
|
46366
|
+
if (replacementAgentId) {
|
|
46367
|
+
next.replacedByAgentId = replacementAgentId;
|
|
46368
|
+
} else if (existingReplacement) {
|
|
46369
|
+
next.replacedByAgentId = existingReplacement;
|
|
46370
|
+
} else {
|
|
46371
|
+
delete next.replacedByAgentId;
|
|
46372
|
+
}
|
|
46373
|
+
return next;
|
|
46374
|
+
}
|
|
46375
|
+
function clearStaleLocalEndpointMetadata(metadata) {
|
|
46376
|
+
const {
|
|
46377
|
+
staleLocalRegistration,
|
|
46378
|
+
staleAt,
|
|
46379
|
+
replacedByAgentId,
|
|
46380
|
+
...rest
|
|
46381
|
+
} = metadata ?? {};
|
|
46382
|
+
return rest;
|
|
46383
|
+
}
|
|
44666
46384
|
async function archiveStaleRegisteredLocalAgents(bindings) {
|
|
44667
46385
|
const activeAgentIds = new Set(bindings.map((binding) => binding.agent.id));
|
|
44668
46386
|
const activeAgentIdsByDefinition = bindings.reduce((map2, binding) => {
|
|
@@ -44685,48 +46403,36 @@ async function archiveStaleRegisteredLocalAgents(bindings) {
|
|
|
44685
46403
|
if (agent?.authorityNodeId && agent.authorityNodeId !== nodeId) {
|
|
44686
46404
|
continue;
|
|
44687
46405
|
}
|
|
46406
|
+
if (isLocalAgentEndpointAlive(endpoint)) {
|
|
46407
|
+
if (endpoint.metadata?.staleLocalRegistration === true) {
|
|
46408
|
+
await persistEndpoint({
|
|
46409
|
+
...endpoint,
|
|
46410
|
+
metadata: clearStaleLocalEndpointMetadata(endpoint.metadata)
|
|
46411
|
+
});
|
|
46412
|
+
}
|
|
46413
|
+
continue;
|
|
46414
|
+
}
|
|
44688
46415
|
const replacementAgentId = staleLocalAgentReplacementId(typeof agent?.definitionId === "string" ? agent.definitionId : null, activeAgentIdsByDefinition);
|
|
44689
|
-
if (
|
|
46416
|
+
if (agent && !staleRegistrationMetadataMatches(agent.metadata, replacementAgentId)) {
|
|
46417
|
+
await upsertAgentDurably({
|
|
46418
|
+
...agent,
|
|
46419
|
+
metadata: staleLocalRegistrationMetadata(agent.metadata, staleAt, replacementAgentId)
|
|
46420
|
+
});
|
|
46421
|
+
}
|
|
46422
|
+
if (endpoint.state === "offline" && staleRegistrationMetadataMatches(endpoint.metadata, replacementAgentId)) {
|
|
44690
46423
|
continue;
|
|
44691
46424
|
}
|
|
44692
46425
|
await persistEndpoint({
|
|
44693
46426
|
...endpoint,
|
|
44694
46427
|
state: "offline",
|
|
44695
46428
|
metadata: {
|
|
44696
|
-
...endpoint.metadata
|
|
44697
|
-
staleLocalRegistration: true,
|
|
44698
|
-
staleAt,
|
|
44699
|
-
replacedByAgentId: replacementAgentId ?? endpoint.metadata?.replacedByAgentId,
|
|
46429
|
+
...staleLocalRegistrationMetadata(endpoint.metadata, staleAt, replacementAgentId),
|
|
44700
46430
|
lastError: "stale local agent registration superseded by current setup",
|
|
44701
46431
|
lastFailedAt: staleAt
|
|
44702
46432
|
}
|
|
44703
46433
|
});
|
|
44704
46434
|
console.log(`[openscout-runtime] archived stale local endpoint ${endpoint.id}`);
|
|
44705
46435
|
}
|
|
44706
|
-
for (const agent of Object.values(snapshot.agents)) {
|
|
44707
|
-
if (activeAgentIds.has(agent.id) || !isGeneratedLocalAgentMetadata(agent.metadata)) {
|
|
44708
|
-
continue;
|
|
44709
|
-
}
|
|
44710
|
-
if (agent.authorityNodeId && agent.authorityNodeId !== nodeId) {
|
|
44711
|
-
continue;
|
|
44712
|
-
}
|
|
44713
|
-
const replacementAgentId = staleLocalAgentReplacementId(agent.definitionId, activeAgentIdsByDefinition);
|
|
44714
|
-
const nextMetadata = {
|
|
44715
|
-
...agent.metadata ?? {},
|
|
44716
|
-
staleLocalRegistration: true,
|
|
44717
|
-
staleAt,
|
|
44718
|
-
replacedByAgentId: replacementAgentId ?? agent.metadata?.replacedByAgentId
|
|
44719
|
-
};
|
|
44720
|
-
if (agent.metadata?.staleLocalRegistration === true && nextMetadata.replacedByAgentId === agent.metadata?.replacedByAgentId) {
|
|
44721
|
-
continue;
|
|
44722
|
-
}
|
|
44723
|
-
const nextAgent = {
|
|
44724
|
-
...agent,
|
|
44725
|
-
metadata: nextMetadata
|
|
44726
|
-
};
|
|
44727
|
-
await upsertAgentDurably(nextAgent);
|
|
44728
|
-
console.log(`[openscout-runtime] archived stale local agent ${agent.id}`);
|
|
44729
|
-
}
|
|
44730
46436
|
}
|
|
44731
46437
|
async function syncRegisteredLocalAgents() {
|
|
44732
46438
|
const bindings = await loadRegisteredLocalAgentBindings(nodeId);
|
|
@@ -44741,6 +46447,7 @@ async function syncRegisteredLocalAgents() {
|
|
|
44741
46447
|
}
|
|
44742
46448
|
await archiveStaleRegisteredLocalAgents(bindings);
|
|
44743
46449
|
await reconcileStaleWorkingFlights();
|
|
46450
|
+
await reconcileStaleLocalDeliveries();
|
|
44744
46451
|
const snapshot = runtime.snapshot();
|
|
44745
46452
|
for (const endpoint of Object.values(snapshot.endpoints)) {
|
|
44746
46453
|
if (endpoint.transport === "tmux") {
|
|
@@ -45115,6 +46822,49 @@ function hasReachableMeshEntrypoint(node) {
|
|
|
45115
46822
|
function isReachableMeshNode(node) {
|
|
45116
46823
|
return Boolean(node?.brokerUrl || hasReachableMeshEntrypoint(node));
|
|
45117
46824
|
}
|
|
46825
|
+
function meshNodeLastSeenAt(node) {
|
|
46826
|
+
return typeof node?.lastSeenAt === "number" && Number.isFinite(node.lastSeenAt) ? node.lastSeenAt : typeof node?.registeredAt === "number" && Number.isFinite(node.registeredAt) ? node.registeredAt : 0;
|
|
46827
|
+
}
|
|
46828
|
+
function isStaleMeshAuthorityNode(node) {
|
|
46829
|
+
if (!node) {
|
|
46830
|
+
return false;
|
|
46831
|
+
}
|
|
46832
|
+
const lastSeenAt = meshNodeLastSeenAt(node);
|
|
46833
|
+
return lastSeenAt > 0 && Date.now() - lastSeenAt > STALE_MESH_AUTHORITY_NODE_MS;
|
|
46834
|
+
}
|
|
46835
|
+
function formatMeshNodeLastSeen(node) {
|
|
46836
|
+
const lastSeenAt = meshNodeLastSeenAt(node);
|
|
46837
|
+
if (!lastSeenAt) {
|
|
46838
|
+
return "with no recent heartbeat";
|
|
46839
|
+
}
|
|
46840
|
+
return `last seen ${new Date(lastSeenAt).toISOString()}`;
|
|
46841
|
+
}
|
|
46842
|
+
function describeRemoteAuthorityIssue(agent, authorityNode) {
|
|
46843
|
+
const displayName = agent.displayName ?? agent.id;
|
|
46844
|
+
const authorityNodeId = agent.authorityNodeId;
|
|
46845
|
+
if (!authorityNodeId || authorityNodeId === nodeId) {
|
|
46846
|
+
return null;
|
|
46847
|
+
}
|
|
46848
|
+
const nodeLabel = authorityNode?.name ? `${authorityNode.name} (${authorityNodeId})` : authorityNodeId;
|
|
46849
|
+
const unavailable = !authorityNode || !isReachableMeshNode(authorityNode);
|
|
46850
|
+
const stale = isStaleMeshAuthorityNode(authorityNode);
|
|
46851
|
+
if (!unavailable && !stale) {
|
|
46852
|
+
return null;
|
|
46853
|
+
}
|
|
46854
|
+
const endpoint = homeEndpointForAgent(runtime.snapshot(), agent.id);
|
|
46855
|
+
const projectRoot = brokerTargetProjectRoot(agent, endpoint);
|
|
46856
|
+
const detail = unavailable ? `${displayName} belongs to peer node ${nodeLabel}, but that peer has no reachable broker URL or mesh entrypoint.` : `${displayName} belongs to peer node ${nodeLabel}, but that peer is stale (${formatMeshNodeLastSeen(authorityNode)}).`;
|
|
46857
|
+
return {
|
|
46858
|
+
agentId: agent.id,
|
|
46859
|
+
displayName,
|
|
46860
|
+
reason: "unknown",
|
|
46861
|
+
detail,
|
|
46862
|
+
wakePolicy: agent.wakePolicy,
|
|
46863
|
+
endpointState: endpoint?.state === "active" || endpoint?.state === "idle" || endpoint?.state === "waiting" ? "online" : endpoint?.state === "offline" ? "offline" : "unknown",
|
|
46864
|
+
transport: endpoint?.transport ?? null,
|
|
46865
|
+
projectRoot
|
|
46866
|
+
};
|
|
46867
|
+
}
|
|
45118
46868
|
function authorityNodeForConversation(conversationId) {
|
|
45119
46869
|
const conversation = runtime.conversation(conversationId);
|
|
45120
46870
|
if (!conversation || conversation.authorityNodeId === nodeId) {
|
|
@@ -45189,6 +46939,30 @@ async function maybeForwardFlightToAuthority(flight) {
|
|
|
45189
46939
|
}
|
|
45190
46940
|
await brokerPostJson(authority.authorityNode.brokerUrl, "/v1/flights", flight);
|
|
45191
46941
|
}
|
|
46942
|
+
async function retireConsumedOneTimeCardsForMessage(message) {
|
|
46943
|
+
if (message.class !== "agent" || message.actorId === systemActor.id) {
|
|
46944
|
+
return;
|
|
46945
|
+
}
|
|
46946
|
+
const conversation = runtime.conversation(message.conversationId);
|
|
46947
|
+
if (!conversation || conversation.kind !== "direct") {
|
|
46948
|
+
return;
|
|
46949
|
+
}
|
|
46950
|
+
const retired = await retireConsumedOneTimeLocalAgentCards({
|
|
46951
|
+
conversationId: conversation.id,
|
|
46952
|
+
actorId: message.actorId,
|
|
46953
|
+
participantIds: conversation.participantIds
|
|
46954
|
+
}).catch((error48) => {
|
|
46955
|
+
console.warn(`[openscout-runtime] one-time card cleanup failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
46956
|
+
return [];
|
|
46957
|
+
});
|
|
46958
|
+
if (retired.length === 0) {
|
|
46959
|
+
return;
|
|
46960
|
+
}
|
|
46961
|
+
console.log(`[openscout-runtime] retired ${retired.length} consumed one-time card${retired.length === 1 ? "" : "s"}`);
|
|
46962
|
+
await syncRegisteredLocalAgentsIfChanged("one-time card consumed").catch((error48) => {
|
|
46963
|
+
console.warn(`[openscout-runtime] one-time card broker sync failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
46964
|
+
});
|
|
46965
|
+
}
|
|
45192
46966
|
async function postConversationMessage(message) {
|
|
45193
46967
|
const authority = authorityNodeForConversation(message.conversationId);
|
|
45194
46968
|
if (authority) {
|
|
@@ -45205,6 +46979,9 @@ async function postConversationMessage(message) {
|
|
|
45205
46979
|
});
|
|
45206
46980
|
await forwardPeerBrokerDeliveries(message, deliveries2);
|
|
45207
46981
|
await applyProjectedEntries(entries);
|
|
46982
|
+
await reconcileStaleLocalDeliveries();
|
|
46983
|
+
await retireConsumedOneTimeCardsForMessage(message);
|
|
46984
|
+
await completeInvocationsForBrokerReply(message);
|
|
45208
46985
|
return { ok: true, message, deliveries: deliveries2 };
|
|
45209
46986
|
}
|
|
45210
46987
|
async function postInvocationStatusMessage(invocation, flight) {
|
|
@@ -45250,10 +47027,69 @@ function existingBrokerReplyForInvocation(invocation, agentId, sinceMs) {
|
|
|
45250
47027
|
const replies = Object.values(runtime.peek().messages).filter((message) => message.conversationId === invocation.conversationId && message.replyToMessageId === invocation.messageId && message.actorId === agentId && message.class === "agent" && message.createdAt >= since).sort((lhs, rhs) => rhs.createdAt - lhs.createdAt);
|
|
45251
47028
|
return replies[0] ?? null;
|
|
45252
47029
|
}
|
|
45253
|
-
function
|
|
47030
|
+
function messageAnswersInvocation(message, invocation) {
|
|
47031
|
+
if (invocation.action === "wake") {
|
|
47032
|
+
return false;
|
|
47033
|
+
}
|
|
47034
|
+
if (!invocation.conversationId || !invocation.messageId) {
|
|
47035
|
+
return false;
|
|
47036
|
+
}
|
|
47037
|
+
return message.class === "agent" && message.actorId === invocation.targetAgentId && message.conversationId === invocation.conversationId && message.replyToMessageId === invocation.messageId && message.body.trim().length > 0;
|
|
47038
|
+
}
|
|
47039
|
+
function completedFlightFromBrokerReply(invocation, flight, reply) {
|
|
47040
|
+
const agent = runtime.agent(invocation.targetAgentId);
|
|
47041
|
+
const replySource = metadataStringValue2(reply.metadata, "source");
|
|
47042
|
+
return {
|
|
47043
|
+
...flight,
|
|
47044
|
+
state: "completed",
|
|
47045
|
+
summary: `${agent?.displayName ?? invocation.targetAgentId} replied.`,
|
|
47046
|
+
output: reply.body,
|
|
47047
|
+
error: undefined,
|
|
47048
|
+
completedAt: reply.createdAt,
|
|
47049
|
+
metadata: {
|
|
47050
|
+
...flight.metadata ?? {},
|
|
47051
|
+
completedByBrokerReply: true,
|
|
47052
|
+
replyMessageId: reply.id,
|
|
47053
|
+
...replySource ? { replySource } : {}
|
|
47054
|
+
}
|
|
47055
|
+
};
|
|
47056
|
+
}
|
|
47057
|
+
async function completeInvocationForBrokerReply(invocation, reply) {
|
|
47058
|
+
const flight = runtime.flightForInvocation(invocation.id);
|
|
47059
|
+
if (!flight || !isWorkingFlightState(flight.state)) {
|
|
47060
|
+
return false;
|
|
47061
|
+
}
|
|
47062
|
+
const startedAt = flight.startedAt ?? invocation.createdAt;
|
|
47063
|
+
if (reply.createdAt < Math.max(0, startedAt - 5000)) {
|
|
47064
|
+
return false;
|
|
47065
|
+
}
|
|
47066
|
+
await persistFlight(completedFlightFromBrokerReply(invocation, flight, reply));
|
|
47067
|
+
return true;
|
|
47068
|
+
}
|
|
47069
|
+
async function completeInvocationsForBrokerReply(message) {
|
|
47070
|
+
if (message.class !== "agent" || !message.replyToMessageId || !message.body.trim()) {
|
|
47071
|
+
return;
|
|
47072
|
+
}
|
|
47073
|
+
const invocations2 = Object.values(runtime.snapshot().invocations).filter((invocation) => messageAnswersInvocation(message, invocation));
|
|
47074
|
+
for (const invocation of invocations2) {
|
|
47075
|
+
await completeInvocationForBrokerReply(invocation, message);
|
|
47076
|
+
}
|
|
47077
|
+
}
|
|
47078
|
+
function endpointMatchesTargetSession(endpoint, sessionId) {
|
|
47079
|
+
return endpoint.sessionId?.trim() === sessionId || endpoint.id === sessionId;
|
|
47080
|
+
}
|
|
47081
|
+
function invocationTargetSessionId(invocation) {
|
|
47082
|
+
return invocation.execution?.targetSessionId?.trim() || metadataStringValue2(invocation.metadata, "targetSessionId") || undefined;
|
|
47083
|
+
}
|
|
47084
|
+
function activeLocalEndpointForAgent(agentId, harness, targetSessionId) {
|
|
45254
47085
|
const candidates = runtime.endpointsForAgent(agentId, {
|
|
45255
47086
|
nodeId,
|
|
45256
47087
|
harness
|
|
47088
|
+
}).filter((endpoint) => {
|
|
47089
|
+
if (endpoint.metadata?.staleLocalRegistration === true) {
|
|
47090
|
+
return false;
|
|
47091
|
+
}
|
|
47092
|
+
return targetSessionId ? endpointMatchesTargetSession(endpoint, targetSessionId) : true;
|
|
45257
47093
|
});
|
|
45258
47094
|
return candidates.find((endpoint) => endpoint.transport === "pairing_bridge" ? endpoint.state !== "offline" : isLocalAgentEndpointAlive(endpoint));
|
|
45259
47095
|
}
|
|
@@ -45284,17 +47120,64 @@ function onlineConversationNotifyTargets(conversation, requesterId) {
|
|
|
45284
47120
|
return Boolean(activeLocalEndpointForAgent(participantId));
|
|
45285
47121
|
});
|
|
45286
47122
|
}
|
|
47123
|
+
async function reviveManagedLocalSessionEndpoint(endpoint) {
|
|
47124
|
+
if (!isManagedLocalSessionMetadata(endpoint.metadata)) {
|
|
47125
|
+
return null;
|
|
47126
|
+
}
|
|
47127
|
+
const sessionResult = await ensureLocalSessionEndpointOnline(endpoint);
|
|
47128
|
+
const externalSessionId = sessionResult.externalSessionId?.trim();
|
|
47129
|
+
const { lastError: _lastError, lastFailedAt: _lastFailedAt, ...baseMetadata } = endpoint.metadata ?? {};
|
|
47130
|
+
const revivedEndpoint = {
|
|
47131
|
+
...endpoint,
|
|
47132
|
+
state: "idle",
|
|
47133
|
+
...externalSessionId ? { sessionId: externalSessionId } : {},
|
|
47134
|
+
metadata: {
|
|
47135
|
+
...baseMetadata,
|
|
47136
|
+
lastResumedAt: Date.now(),
|
|
47137
|
+
...externalSessionId ? {
|
|
47138
|
+
externalSessionId,
|
|
47139
|
+
...endpoint.transport === "codex_app_server" ? { threadId: externalSessionId } : {}
|
|
47140
|
+
} : {}
|
|
47141
|
+
}
|
|
47142
|
+
};
|
|
47143
|
+
await persistEndpoint(revivedEndpoint);
|
|
47144
|
+
return revivedEndpoint;
|
|
47145
|
+
}
|
|
45287
47146
|
async function resolveLocalEndpointForInvocation(invocation) {
|
|
45288
47147
|
const requestedHarness = invocation.execution?.harness;
|
|
47148
|
+
const targetSessionId = invocationTargetSessionId(invocation);
|
|
45289
47149
|
const sessionPreference = invocation.execution?.session ?? "new";
|
|
45290
|
-
const existing = activeLocalEndpointForAgent(invocation.targetAgentId, requestedHarness);
|
|
47150
|
+
const existing = activeLocalEndpointForAgent(invocation.targetAgentId, requestedHarness, targetSessionId);
|
|
45291
47151
|
if (existing && (sessionPreference !== "new" || existing.transport === "pairing_bridge")) {
|
|
45292
47152
|
return existing;
|
|
45293
47153
|
}
|
|
45294
47154
|
const staleEndpoints = runtime.endpointsForAgent(invocation.targetAgentId, {
|
|
45295
47155
|
nodeId,
|
|
45296
47156
|
harness: requestedHarness
|
|
45297
|
-
}).filter((endpoint) => endpoint.id !== existing?.id);
|
|
47157
|
+
}).filter((endpoint) => endpoint.id !== existing?.id && (targetSessionId ? endpointMatchesTargetSession(endpoint, targetSessionId) : true));
|
|
47158
|
+
const staleLocalReason = staleEndpoints.map((endpoint) => staleLocalEndpointReason(endpoint)).find((reason) => Boolean(reason));
|
|
47159
|
+
if (staleLocalReason) {
|
|
47160
|
+
throw new Error(staleLocalReason);
|
|
47161
|
+
}
|
|
47162
|
+
if (invocation.ensureAwake) {
|
|
47163
|
+
for (const endpoint of staleEndpoints) {
|
|
47164
|
+
try {
|
|
47165
|
+
const revived = await reviveManagedLocalSessionEndpoint(endpoint);
|
|
47166
|
+
if (revived)
|
|
47167
|
+
return revived;
|
|
47168
|
+
} catch (error48) {
|
|
47169
|
+
await persistEndpoint({
|
|
47170
|
+
...endpoint,
|
|
47171
|
+
state: "offline",
|
|
47172
|
+
metadata: {
|
|
47173
|
+
...endpoint.metadata ?? {},
|
|
47174
|
+
lastError: error48 instanceof Error ? error48.message : String(error48),
|
|
47175
|
+
lastFailedAt: Date.now()
|
|
47176
|
+
}
|
|
47177
|
+
});
|
|
47178
|
+
}
|
|
47179
|
+
}
|
|
47180
|
+
}
|
|
45298
47181
|
for (const endpoint of staleEndpoints) {
|
|
45299
47182
|
await persistEndpoint({
|
|
45300
47183
|
...endpoint,
|
|
@@ -45312,34 +47195,8 @@ async function resolveLocalEndpointForInvocation(invocation) {
|
|
|
45312
47195
|
if (sessionPreference === "existing") {
|
|
45313
47196
|
return;
|
|
45314
47197
|
}
|
|
45315
|
-
|
|
45316
|
-
|
|
45317
|
-
continue;
|
|
45318
|
-
}
|
|
45319
|
-
try {
|
|
45320
|
-
const sessionResult = await ensureLocalSessionEndpointOnline(endpoint);
|
|
45321
|
-
const revivedEndpoint = {
|
|
45322
|
-
...endpoint,
|
|
45323
|
-
state: "idle",
|
|
45324
|
-
metadata: {
|
|
45325
|
-
...endpoint.metadata ?? {},
|
|
45326
|
-
lastResumedAt: Date.now(),
|
|
45327
|
-
...sessionResult.externalSessionId ? { externalSessionId: sessionResult.externalSessionId } : {}
|
|
45328
|
-
}
|
|
45329
|
-
};
|
|
45330
|
-
await persistEndpoint(revivedEndpoint);
|
|
45331
|
-
return revivedEndpoint;
|
|
45332
|
-
} catch (error48) {
|
|
45333
|
-
await persistEndpoint({
|
|
45334
|
-
...endpoint,
|
|
45335
|
-
state: "offline",
|
|
45336
|
-
metadata: {
|
|
45337
|
-
...endpoint.metadata ?? {},
|
|
45338
|
-
lastError: error48 instanceof Error ? error48.message : String(error48),
|
|
45339
|
-
lastFailedAt: Date.now()
|
|
45340
|
-
}
|
|
45341
|
-
});
|
|
45342
|
-
}
|
|
47198
|
+
if (targetSessionId) {
|
|
47199
|
+
return;
|
|
45343
47200
|
}
|
|
45344
47201
|
const binding = await ensureLocalAgentBindingOnline(invocation.targetAgentId, nodeId, {
|
|
45345
47202
|
includeDiscovered: true,
|
|
@@ -45358,7 +47215,7 @@ async function resolveLocalEndpointForInvocation(invocation) {
|
|
|
45358
47215
|
async function executeLocalInvocation(invocation, initialFlight) {
|
|
45359
47216
|
const agent = runtime.agent(invocation.targetAgentId);
|
|
45360
47217
|
let endpoint;
|
|
45361
|
-
const previousEndpoint = activeLocalEndpointForAgent(invocation.targetAgentId, invocation.execution?.harness);
|
|
47218
|
+
const previousEndpoint = activeLocalEndpointForAgent(invocation.targetAgentId, invocation.execution?.harness, invocationTargetSessionId(invocation));
|
|
45362
47219
|
try {
|
|
45363
47220
|
endpoint = await resolveLocalEndpointForInvocation(invocation);
|
|
45364
47221
|
} catch (error48) {
|
|
@@ -45379,6 +47236,24 @@ async function executeLocalInvocation(invocation, initialFlight) {
|
|
|
45379
47236
|
return;
|
|
45380
47237
|
}
|
|
45381
47238
|
if (!agent || !endpoint) {
|
|
47239
|
+
const staleEndpointReason = staleLocalEndpointReason(latestEndpointForAgent(runtime.snapshot(), invocation.targetAgentId));
|
|
47240
|
+
if (staleEndpointReason) {
|
|
47241
|
+
const failedFlight = {
|
|
47242
|
+
...initialFlight,
|
|
47243
|
+
state: "failed",
|
|
47244
|
+
summary: `${agent?.displayName ?? invocation.targetAgentId} could not be prepared.`,
|
|
47245
|
+
error: `Endpoint resolution failed before execution: ${staleEndpointReason}`,
|
|
47246
|
+
completedAt: Date.now(),
|
|
47247
|
+
metadata: {
|
|
47248
|
+
...initialFlight.metadata ?? {},
|
|
47249
|
+
failureStage: "endpoint_resolution",
|
|
47250
|
+
staleLocalRegistration: true
|
|
47251
|
+
}
|
|
47252
|
+
};
|
|
47253
|
+
await persistFlight(failedFlight);
|
|
47254
|
+
await postInvocationStatusMessage(invocation, failedFlight);
|
|
47255
|
+
return;
|
|
47256
|
+
}
|
|
45382
47257
|
const queuedFlight = {
|
|
45383
47258
|
...initialFlight,
|
|
45384
47259
|
state: "queued",
|
|
@@ -45436,6 +47311,20 @@ async function executeLocalInvocation(invocation, initialFlight) {
|
|
|
45436
47311
|
await persistFlight(runningFlight);
|
|
45437
47312
|
try {
|
|
45438
47313
|
const result = endpoint.transport === "pairing_bridge" ? await invokePairingSessionEndpoint(runningEndpoint, invocation) : await invokeLocalAgentEndpoint(runningEndpoint, invocation);
|
|
47314
|
+
const rawResultExternalSessionId = "externalSessionId" in result ? result.externalSessionId : undefined;
|
|
47315
|
+
const resultExternalSessionId = typeof rawResultExternalSessionId === "string" && rawResultExternalSessionId.trim() ? rawResultExternalSessionId.trim() : undefined;
|
|
47316
|
+
const completedEndpoint = {
|
|
47317
|
+
...runningEndpoint,
|
|
47318
|
+
...resultExternalSessionId ? { sessionId: resultExternalSessionId } : {},
|
|
47319
|
+
metadata: {
|
|
47320
|
+
...runningEndpoint.metadata ?? {},
|
|
47321
|
+
lastCompletedAt: Date.now(),
|
|
47322
|
+
...resultExternalSessionId ? {
|
|
47323
|
+
externalSessionId: resultExternalSessionId,
|
|
47324
|
+
...runningEndpoint.transport === "codex_app_server" ? { threadId: resultExternalSessionId } : {}
|
|
47325
|
+
} : {}
|
|
47326
|
+
}
|
|
47327
|
+
};
|
|
45439
47328
|
if (invocation.action === "wake") {
|
|
45440
47329
|
const completedFlight2 = {
|
|
45441
47330
|
...runningFlight,
|
|
@@ -45446,12 +47335,16 @@ async function executeLocalInvocation(invocation, initialFlight) {
|
|
|
45446
47335
|
};
|
|
45447
47336
|
await persistFlight(completedFlight2);
|
|
45448
47337
|
await persistEndpoint({
|
|
45449
|
-
...
|
|
45450
|
-
state: "idle"
|
|
45451
|
-
|
|
45452
|
-
|
|
45453
|
-
|
|
45454
|
-
|
|
47338
|
+
...completedEndpoint,
|
|
47339
|
+
state: "idle"
|
|
47340
|
+
});
|
|
47341
|
+
return;
|
|
47342
|
+
}
|
|
47343
|
+
const currentFlight = runtime.flightForInvocation(invocation.id);
|
|
47344
|
+
if (currentFlight && isTerminalFlightState(currentFlight.state)) {
|
|
47345
|
+
await persistEndpoint({
|
|
47346
|
+
...completedEndpoint,
|
|
47347
|
+
state: "idle"
|
|
45455
47348
|
});
|
|
45456
47349
|
return;
|
|
45457
47350
|
}
|
|
@@ -45491,12 +47384,8 @@ async function executeLocalInvocation(invocation, initialFlight) {
|
|
|
45491
47384
|
};
|
|
45492
47385
|
await persistFlight(completedFlight);
|
|
45493
47386
|
await persistEndpoint({
|
|
45494
|
-
...
|
|
45495
|
-
state: "idle"
|
|
45496
|
-
metadata: {
|
|
45497
|
-
...runningEndpoint.metadata ?? {},
|
|
45498
|
-
lastCompletedAt: Date.now()
|
|
45499
|
-
}
|
|
47387
|
+
...completedEndpoint,
|
|
47388
|
+
state: "idle"
|
|
45500
47389
|
});
|
|
45501
47390
|
if (invocation.conversationId && !postedReply) {
|
|
45502
47391
|
const conversation = runtime.conversation(invocation.conversationId);
|
|
@@ -45519,6 +47408,7 @@ async function executeLocalInvocation(invocation, initialFlight) {
|
|
|
45519
47408
|
invocationId: invocation.id,
|
|
45520
47409
|
flightId: completedFlight.id,
|
|
45521
47410
|
source: "broker",
|
|
47411
|
+
...scoutbotReplyProvenanceMetadata(invocation),
|
|
45522
47412
|
returnAddress: buildScoutReturnAddress({
|
|
45523
47413
|
actorId: agent.id,
|
|
45524
47414
|
handle: agent.handle?.trim() || agent.definitionId,
|
|
@@ -45527,19 +47417,19 @@ async function executeLocalInvocation(invocation, initialFlight) {
|
|
|
45527
47417
|
defaultSelector: agent.defaultSelector,
|
|
45528
47418
|
conversationId: invocation.conversationId,
|
|
45529
47419
|
replyToMessageId: invocation.messageId,
|
|
45530
|
-
nodeId:
|
|
45531
|
-
projectRoot:
|
|
45532
|
-
sessionId:
|
|
47420
|
+
nodeId: completedEndpoint.nodeId,
|
|
47421
|
+
projectRoot: completedEndpoint.projectRoot ?? completedEndpoint.cwd,
|
|
47422
|
+
sessionId: completedEndpoint.sessionId
|
|
45533
47423
|
}),
|
|
45534
47424
|
requestedReturnAddress: invocation.metadata?.["returnAddress"],
|
|
45535
|
-
responderHarness:
|
|
45536
|
-
responderTransport:
|
|
45537
|
-
responderSessionId:
|
|
45538
|
-
responderCwd:
|
|
45539
|
-
responderProjectRoot:
|
|
45540
|
-
responderAgentName: String(
|
|
45541
|
-
responderStartedAt: String(
|
|
45542
|
-
responderNodeId:
|
|
47425
|
+
responderHarness: completedEndpoint.harness,
|
|
47426
|
+
responderTransport: completedEndpoint.transport,
|
|
47427
|
+
responderSessionId: completedEndpoint.sessionId ?? "",
|
|
47428
|
+
responderCwd: completedEndpoint.cwd ?? "",
|
|
47429
|
+
responderProjectRoot: completedEndpoint.projectRoot ?? "",
|
|
47430
|
+
responderAgentName: String(completedEndpoint.metadata?.agentName ?? agent.id),
|
|
47431
|
+
responderStartedAt: String(completedEndpoint.metadata?.startedAt ?? ""),
|
|
47432
|
+
responderNodeId: completedEndpoint.nodeId
|
|
45543
47433
|
}
|
|
45544
47434
|
});
|
|
45545
47435
|
}
|
|
@@ -45547,10 +47437,18 @@ async function executeLocalInvocation(invocation, initialFlight) {
|
|
|
45547
47437
|
} catch (error48) {
|
|
45548
47438
|
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
45549
47439
|
if (isRequesterWaitTimeoutError(error48)) {
|
|
47440
|
+
const currentFlight = runtime.flightForInvocation(invocation.id);
|
|
47441
|
+
if (currentFlight && isTerminalFlightState(currentFlight.state)) {
|
|
47442
|
+
return;
|
|
47443
|
+
}
|
|
47444
|
+
const postedReply = existingBrokerReplyForInvocation(invocation, agent.id, runningFlight.startedAt ?? Date.now());
|
|
47445
|
+
if (postedReply && await completeInvocationForBrokerReply(invocation, postedReply)) {
|
|
47446
|
+
return;
|
|
47447
|
+
}
|
|
45550
47448
|
const waitingFlight = {
|
|
45551
47449
|
...runningFlight,
|
|
45552
47450
|
state: "waiting",
|
|
45553
|
-
summary: `${agent.displayName} is still working;
|
|
47451
|
+
summary: `${agent.displayName} is still working; Scout stopped waiting for a synchronous result after ${error48.timeoutMs}ms.`,
|
|
45554
47452
|
error: undefined,
|
|
45555
47453
|
completedAt: undefined,
|
|
45556
47454
|
metadata: {
|
|
@@ -45561,7 +47459,71 @@ async function executeLocalInvocation(invocation, initialFlight) {
|
|
|
45561
47459
|
}
|
|
45562
47460
|
};
|
|
45563
47461
|
await persistFlight(waitingFlight);
|
|
45564
|
-
|
|
47462
|
+
console.warn(`[openscout-runtime] ${waitingFlight.summary}`);
|
|
47463
|
+
return;
|
|
47464
|
+
}
|
|
47465
|
+
if (isDispatchStalledError(error48)) {
|
|
47466
|
+
const stalledFlight = {
|
|
47467
|
+
...runningFlight,
|
|
47468
|
+
state: "failed",
|
|
47469
|
+
summary: `${agent.displayName} dispatch stalled \u2014 prompt left in composer after submit + retry.`,
|
|
47470
|
+
error: message,
|
|
47471
|
+
completedAt: Date.now(),
|
|
47472
|
+
metadata: {
|
|
47473
|
+
...runningFlight.metadata ?? {},
|
|
47474
|
+
failureStage: "dispatch_stalled",
|
|
47475
|
+
dispatchStalledSession: error48.sessionName,
|
|
47476
|
+
dispatchStalledRetries: error48.retries,
|
|
47477
|
+
dispatchStalledPaneTail: error48.paneTail.slice(0, 1000)
|
|
47478
|
+
}
|
|
47479
|
+
};
|
|
47480
|
+
await persistFlight(stalledFlight);
|
|
47481
|
+
await persistEndpoint({
|
|
47482
|
+
...runningEndpoint,
|
|
47483
|
+
state: "offline",
|
|
47484
|
+
metadata: {
|
|
47485
|
+
...runningEndpoint.metadata ?? {},
|
|
47486
|
+
lastError: message,
|
|
47487
|
+
lastFailedAt: Date.now(),
|
|
47488
|
+
lastFailureStage: "dispatch_stalled"
|
|
47489
|
+
}
|
|
47490
|
+
});
|
|
47491
|
+
await postInvocationStatusMessage(invocation, stalledFlight);
|
|
47492
|
+
return;
|
|
47493
|
+
}
|
|
47494
|
+
if (isCodexAppServerExitError(error48) && error48.noteworthy) {
|
|
47495
|
+
const interruptedAt = Date.now();
|
|
47496
|
+
const failureStage = error48.exitKind === "proactive_shutdown" ? "codex_app_server_proactive_shutdown" : "codex_app_server_sigterm";
|
|
47497
|
+
const summary = error48.exitKind === "proactive_shutdown" ? `${agent.displayName} was stopped by OpenScout before it could reply.` : `${agent.displayName} was interrupted by a local Codex app-server SIGTERM.`;
|
|
47498
|
+
const interruptedFlight = {
|
|
47499
|
+
...runningFlight,
|
|
47500
|
+
state: "failed",
|
|
47501
|
+
summary,
|
|
47502
|
+
error: undefined,
|
|
47503
|
+
completedAt: interruptedAt,
|
|
47504
|
+
metadata: {
|
|
47505
|
+
...runningFlight.metadata ?? {},
|
|
47506
|
+
failureStage,
|
|
47507
|
+
failureSeverity: "noteworthy",
|
|
47508
|
+
noteworthy: true,
|
|
47509
|
+
exitKind: error48.exitKind,
|
|
47510
|
+
exitSignal: error48.signal,
|
|
47511
|
+
exitCode: error48.exitCode,
|
|
47512
|
+
...error48.reason ? { shutdownReason: error48.reason } : {}
|
|
47513
|
+
}
|
|
47514
|
+
};
|
|
47515
|
+
await persistFlight(interruptedFlight);
|
|
47516
|
+
await persistEndpoint({
|
|
47517
|
+
...runningEndpoint,
|
|
47518
|
+
state: "offline",
|
|
47519
|
+
metadata: {
|
|
47520
|
+
...runningEndpoint.metadata ?? {},
|
|
47521
|
+
lastNotice: message,
|
|
47522
|
+
lastInterruptedAt: interruptedAt,
|
|
47523
|
+
lastInterruptionStage: failureStage
|
|
47524
|
+
}
|
|
47525
|
+
});
|
|
47526
|
+
await postInvocationStatusMessage(invocation, interruptedFlight);
|
|
45565
47527
|
return;
|
|
45566
47528
|
}
|
|
45567
47529
|
const failedFlight = {
|
|
@@ -45861,6 +47823,7 @@ async function handleCommand(command) {
|
|
|
45861
47823
|
});
|
|
45862
47824
|
const mesh2 = await forwardPeerBrokerDeliveries(command.message, deliveries2);
|
|
45863
47825
|
await applyProjectedEntries(entries);
|
|
47826
|
+
await reconcileStaleLocalDeliveries();
|
|
45864
47827
|
console.log(`[openscout-runtime] message ${command.message.id} posted by ${command.message.actorId} to ${command.message.conversationId} with ${deliveries2.length} deliveries`);
|
|
45865
47828
|
return { ok: true, message: command.message, deliveries: deliveries2, mesh: mesh2 };
|
|
45866
47829
|
}
|
|
@@ -45893,7 +47856,7 @@ async function handleCommand(command) {
|
|
|
45893
47856
|
}
|
|
45894
47857
|
async function handleInvocationRequest(payload) {
|
|
45895
47858
|
await syncRegisteredLocalAgentsIfChanged("invocation");
|
|
45896
|
-
const resolved = resolveInvocationTarget(payload);
|
|
47859
|
+
const resolved = await resolveInvocationTarget(payload);
|
|
45897
47860
|
if (resolved.kind !== "resolved") {
|
|
45898
47861
|
const envelope = buildDispatchEnvelope(resolved, askedLabelForRouteTarget(payload), nodeId, runtime.snapshot(), { homeEndpointFor: homeEndpointForAgent });
|
|
45899
47862
|
const { record: record2 } = await recordScoutDispatchDurably(envelope, {
|
|
@@ -45944,8 +47907,9 @@ async function dispatchAcceptedInvocation(invocation) {
|
|
|
45944
47907
|
}
|
|
45945
47908
|
if (targetAgent.authorityNodeId && targetAgent.authorityNodeId !== nodeId) {
|
|
45946
47909
|
const authorityNode = runtime.node(targetAgent.authorityNodeId);
|
|
45947
|
-
|
|
45948
|
-
|
|
47910
|
+
const authorityIssue = describeRemoteAuthorityIssue(targetAgent, authorityNode);
|
|
47911
|
+
if (authorityIssue) {
|
|
47912
|
+
await failAcceptedInvocation(invocation, authorityIssue.detail);
|
|
45949
47913
|
return;
|
|
45950
47914
|
}
|
|
45951
47915
|
await peerDelivery.enqueue(invocation, authorityNode);
|
|
@@ -46361,6 +48325,17 @@ async function routeRequest(request, response) {
|
|
|
46361
48325
|
json2(response, 200, journal.listDeliveryAttempts(deliveryId));
|
|
46362
48326
|
return;
|
|
46363
48327
|
}
|
|
48328
|
+
const invocationLifecycleMatch = method === "GET" ? url2.pathname.match(/^\/v1\/invocations\/([^/]+)\/lifecycle$/) : null;
|
|
48329
|
+
if (invocationLifecycleMatch) {
|
|
48330
|
+
const invocationId = decodeURIComponent(invocationLifecycleMatch[1] ?? "");
|
|
48331
|
+
const lifecycle2 = await brokerService.readInvocationLifecycle?.({ invocationId });
|
|
48332
|
+
if (!lifecycle2) {
|
|
48333
|
+
notFound(response);
|
|
48334
|
+
return;
|
|
48335
|
+
}
|
|
48336
|
+
json2(response, 200, lifecycle2);
|
|
48337
|
+
return;
|
|
48338
|
+
}
|
|
46364
48339
|
if (method === "GET" && url2.pathname === "/v1/mesh/nodes") {
|
|
46365
48340
|
json2(response, 200, runtime.snapshot().nodes);
|
|
46366
48341
|
return;
|
|
@@ -46713,6 +48688,39 @@ data: ${JSON.stringify({ nodeId, meshId })}
|
|
|
46713
48688
|
}
|
|
46714
48689
|
return;
|
|
46715
48690
|
}
|
|
48691
|
+
if (method === "POST" && url2.pathname === "/v1/local-sessions/ensure") {
|
|
48692
|
+
try {
|
|
48693
|
+
const input = await readRequestBody(request);
|
|
48694
|
+
const snapshot = runtime.snapshot();
|
|
48695
|
+
const endpoint = input.endpointId?.trim() ? snapshot.endpoints[input.endpointId.trim()] : Object.values(snapshot.endpoints).find((candidate) => candidate.agentId === input.agentId?.trim() && candidate.nodeId === nodeId && (candidate.transport === "codex_app_server" || candidate.transport === "claude_stream_json") && candidate.state !== "offline");
|
|
48696
|
+
if (!endpoint) {
|
|
48697
|
+
throw new Error("local session endpoint not found");
|
|
48698
|
+
}
|
|
48699
|
+
if (endpoint.transport !== "codex_app_server" && endpoint.transport !== "claude_stream_json") {
|
|
48700
|
+
throw new Error(`endpoint ${endpoint.id} does not use a local session transport`);
|
|
48701
|
+
}
|
|
48702
|
+
const sessionResult = await ensureLocalSessionEndpointOnline(endpoint);
|
|
48703
|
+
const externalSessionId = sessionResult.externalSessionId?.trim();
|
|
48704
|
+
const nextEndpoint = {
|
|
48705
|
+
...endpoint,
|
|
48706
|
+
state: endpoint.state === "offline" ? "waiting" : endpoint.state,
|
|
48707
|
+
...externalSessionId ? { sessionId: externalSessionId } : {},
|
|
48708
|
+
metadata: {
|
|
48709
|
+
...endpoint.metadata ?? {},
|
|
48710
|
+
...externalSessionId ? {
|
|
48711
|
+
externalSessionId,
|
|
48712
|
+
threadId: endpoint.transport === "codex_app_server" ? externalSessionId : endpoint.metadata?.threadId
|
|
48713
|
+
} : {},
|
|
48714
|
+
lastEnsuredAt: Date.now()
|
|
48715
|
+
}
|
|
48716
|
+
};
|
|
48717
|
+
await persistEndpoint(nextEndpoint);
|
|
48718
|
+
json2(response, 200, { ok: true, endpoint: nextEndpoint, externalSessionId: externalSessionId ?? null });
|
|
48719
|
+
} catch (error48) {
|
|
48720
|
+
badRequest(response, error48);
|
|
48721
|
+
}
|
|
48722
|
+
return;
|
|
48723
|
+
}
|
|
46716
48724
|
if (method === "POST" && url2.pathname === "/v1/local-sessions/detach") {
|
|
46717
48725
|
try {
|
|
46718
48726
|
const input = await readRequestBody(request);
|
|
@@ -47042,18 +49050,99 @@ function callerContextForDelivery(payload) {
|
|
|
47042
49050
|
requesterNodeId: payload.caller?.nodeId?.trim() || payload.requesterNodeId?.trim() || nodeId
|
|
47043
49051
|
};
|
|
47044
49052
|
}
|
|
49053
|
+
function agentLabelForRouteParams(payload) {
|
|
49054
|
+
if (payload.target?.kind === "agent_label") {
|
|
49055
|
+
return payload.target.label;
|
|
49056
|
+
}
|
|
49057
|
+
if (!payload.target && payload.targetLabel?.trim()) {
|
|
49058
|
+
return payload.targetLabel;
|
|
49059
|
+
}
|
|
49060
|
+
return;
|
|
49061
|
+
}
|
|
49062
|
+
function supportedRouteHarness(value) {
|
|
49063
|
+
const normalized = value?.trim();
|
|
49064
|
+
if (normalized && SUPPORTED_SCOUT_HARNESSES.includes(normalized)) {
|
|
49065
|
+
return normalized;
|
|
49066
|
+
}
|
|
49067
|
+
return;
|
|
49068
|
+
}
|
|
49069
|
+
function executionWithRouteParams(payload) {
|
|
49070
|
+
const label = agentLabelForRouteParams(payload);
|
|
49071
|
+
const identity2 = label ? parseAgentIdentity(label.startsWith("@") ? label : `@${label}`) : null;
|
|
49072
|
+
const harness = supportedRouteHarness(identity2?.harness);
|
|
49073
|
+
if (!harness || payload.execution?.harness) {
|
|
49074
|
+
return payload.execution;
|
|
49075
|
+
}
|
|
49076
|
+
return {
|
|
49077
|
+
...payload.execution ?? {},
|
|
49078
|
+
harness
|
|
49079
|
+
};
|
|
49080
|
+
}
|
|
47045
49081
|
function resolveBrokerDeliveryTarget(input) {
|
|
47046
49082
|
return resolveBrokerRouteTarget(runtime.snapshot(), input, {
|
|
47047
49083
|
preferLocalNodeId: nodeId,
|
|
47048
|
-
helpers: { isStale:
|
|
49084
|
+
helpers: { isStale: isInactiveLocalAgent }
|
|
47049
49085
|
});
|
|
47050
49086
|
}
|
|
47051
|
-
function
|
|
47052
|
-
return
|
|
49087
|
+
function projectPathRouteTarget(input) {
|
|
49088
|
+
return input.target?.kind === "project_path" ? input.target.projectPath.trim() || undefined : undefined;
|
|
49089
|
+
}
|
|
49090
|
+
function implicitProjectAgentName(projectPath) {
|
|
49091
|
+
const base = normalizeAgentSelectorSegment(basename11(projectPath)) || "agent";
|
|
49092
|
+
return `${base}-card-${createRuntimeId2("one").slice(-8)}`;
|
|
49093
|
+
}
|
|
49094
|
+
async function resolveBrokerDeliveryTargetWithImplicitProjectCard(input, options) {
|
|
49095
|
+
const resolved = resolveBrokerDeliveryTarget(input);
|
|
49096
|
+
const projectPath = projectPathRouteTarget(input);
|
|
49097
|
+
const shouldCreateImplicitProjectCard = projectPath && (resolved.kind === "unknown" || resolved.kind === "ambiguous" && (input.execution?.session ?? "new") === "new");
|
|
49098
|
+
if (!shouldCreateImplicitProjectCard) {
|
|
49099
|
+
return resolved;
|
|
49100
|
+
}
|
|
49101
|
+
const createdAt = Date.now();
|
|
49102
|
+
const requesterId = options.requesterId?.trim();
|
|
49103
|
+
const status = await startLocalAgent({
|
|
49104
|
+
projectPath,
|
|
49105
|
+
agentName: implicitProjectAgentName(projectPath),
|
|
49106
|
+
currentDirectory: options.currentDirectory ?? projectPath,
|
|
49107
|
+
harness: input.execution?.harness,
|
|
49108
|
+
ensureOnline: false,
|
|
49109
|
+
card: {
|
|
49110
|
+
kind: "one_time",
|
|
49111
|
+
createdAt,
|
|
49112
|
+
...requesterId ? { createdById: requesterId } : {},
|
|
49113
|
+
expiresAt: createdAt + DEFAULT_IMPLICIT_PROJECT_CARD_TTL_MS,
|
|
49114
|
+
maxUses: 1
|
|
49115
|
+
}
|
|
49116
|
+
}).catch((error48) => {
|
|
49117
|
+
const detail = error48 instanceof Error ? error48.message : String(error48);
|
|
49118
|
+
throw new Error(`could not create an agent card for project ${projectPath}: ${detail}`);
|
|
49119
|
+
});
|
|
49120
|
+
await pruneOneTimeLocalAgentCards({
|
|
49121
|
+
...requesterId ? { createdById: requesterId } : {},
|
|
49122
|
+
projectRoot: status.projectRoot,
|
|
49123
|
+
excludeAgentIds: [status.agentId]
|
|
49124
|
+
}).catch((error48) => {
|
|
49125
|
+
console.warn(`[openscout-runtime] implicit project card cleanup failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
49126
|
+
});
|
|
49127
|
+
await syncRegisteredLocalAgentsIfChanged(options.reason);
|
|
49128
|
+
const agent = runtime.snapshot().agents[status.agentId];
|
|
49129
|
+
if (agent && !isInactiveLocalAgent(agent)) {
|
|
49130
|
+
return { kind: "resolved", agent };
|
|
49131
|
+
}
|
|
49132
|
+
return resolveBrokerDeliveryTarget(input);
|
|
49133
|
+
}
|
|
49134
|
+
async function resolveInvocationTarget(payload) {
|
|
49135
|
+
return resolveBrokerDeliveryTargetWithImplicitProjectCard({
|
|
47053
49136
|
target: payload.target,
|
|
47054
49137
|
targetAgentId: payload.targetAgentId,
|
|
49138
|
+
targetSessionId: payload.targetSessionId,
|
|
47055
49139
|
targetLabel: payload.targetLabel,
|
|
47056
|
-
routePolicy: payload.routePolicy
|
|
49140
|
+
routePolicy: payload.routePolicy,
|
|
49141
|
+
execution: payload.execution
|
|
49142
|
+
}, {
|
|
49143
|
+
requesterId: payload.requesterId,
|
|
49144
|
+
currentDirectory: projectPathRouteTarget(payload),
|
|
49145
|
+
reason: "implicit project invocation card"
|
|
47057
49146
|
});
|
|
47058
49147
|
}
|
|
47059
49148
|
function remediationForDispatch(dispatch) {
|
|
@@ -47088,6 +49177,7 @@ function buildDeliveryReceipt(input) {
|
|
|
47088
49177
|
requesterId: input.requesterId,
|
|
47089
49178
|
requesterNodeId: input.requesterNodeId,
|
|
47090
49179
|
targetAgentId: input.targetAgentId,
|
|
49180
|
+
targetSessionId: input.targetSessionId,
|
|
47091
49181
|
targetLabel: input.targetLabel,
|
|
47092
49182
|
...input.bindingRef ? { bindingRef: input.bindingRef } : {},
|
|
47093
49183
|
conversationId: input.conversationId,
|
|
@@ -47402,10 +49492,13 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47402
49492
|
const createdAt = typeof payload.createdAt === "number" && Number.isFinite(payload.createdAt) ? payload.createdAt : Date.now();
|
|
47403
49493
|
const { requesterId, requesterNodeId } = callerContextForDelivery(payload);
|
|
47404
49494
|
const askedLabel = askedLabelForRouteTarget(payload);
|
|
49495
|
+
const execution = executionWithRouteParams(payload);
|
|
47405
49496
|
const deliveryChannel = routeChannelForTarget(payload) ?? payload.channel?.trim();
|
|
49497
|
+
const targetSessionId = payload.target?.kind === "session_id" ? payload.target.sessionId.trim() : payload.targetSessionId?.trim() || metadataStringValue2(payload.invocationMetadata, "targetSessionId") || metadataStringValue2(payload.messageMetadata, "targetSessionId") || undefined;
|
|
49498
|
+
const replyToSessionId = payload.replyToSessionId?.trim() || metadataStringValue2(payload.invocationMetadata, "replyToSessionId") || metadataStringValue2(payload.messageMetadata, "replyToSessionId") || undefined;
|
|
47406
49499
|
const labels = normalizeScoutLabels(payload.labels);
|
|
47407
49500
|
const typedChannelTarget = payload.target?.kind === "channel" || payload.target?.kind === "broadcast";
|
|
47408
|
-
const hasAgentTarget = Boolean(payload.target?.kind === "agent_id" || payload.target?.kind === "agent_label" || payload.target?.kind === "project_path") || !payload.target && Boolean(payload.targetAgentId?.trim() || payload.targetLabel?.trim());
|
|
49501
|
+
const hasAgentTarget = Boolean(payload.target?.kind === "agent_id" || payload.target?.kind === "agent_label" || payload.target?.kind === "session_id" || payload.target?.kind === "project_path") || !payload.target && Boolean(payload.targetSessionId?.trim() || payload.targetAgentId?.trim() || payload.targetLabel?.trim());
|
|
47409
49502
|
const messageRef = messageRefCandidateForRouteTarget(payload);
|
|
47410
49503
|
const replyTarget = messageRef ? resolveBrokerMessageRef(runtime.snapshot(), messageRef) : null;
|
|
47411
49504
|
if (replyTarget) {
|
|
@@ -47442,7 +49535,8 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47442
49535
|
relayTargetIds: notifyTargets,
|
|
47443
49536
|
returnAddress: buildBrokerReturnAddressForActor(snapshot2, requesterId, {
|
|
47444
49537
|
conversationId: conversation2.id,
|
|
47445
|
-
replyToMessageId: messageId2
|
|
49538
|
+
replyToMessageId: messageId2,
|
|
49539
|
+
sessionId: replyToSessionId
|
|
47446
49540
|
})
|
|
47447
49541
|
}
|
|
47448
49542
|
};
|
|
@@ -47503,7 +49597,8 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47503
49597
|
relayMessageId: messageId2,
|
|
47504
49598
|
returnAddress: buildBrokerReturnAddressForActor(snapshot2, requesterId, {
|
|
47505
49599
|
conversationId: conversation2.id,
|
|
47506
|
-
replyToMessageId: messageId2
|
|
49600
|
+
replyToMessageId: messageId2,
|
|
49601
|
+
sessionId: replyToSessionId
|
|
47507
49602
|
})
|
|
47508
49603
|
}
|
|
47509
49604
|
};
|
|
@@ -47564,7 +49659,8 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47564
49659
|
relayMessageId: messageId2,
|
|
47565
49660
|
returnAddress: buildBrokerReturnAddressForActor(snapshot2, requesterId, {
|
|
47566
49661
|
conversationId: conversation2.id,
|
|
47567
|
-
replyToMessageId: messageId2
|
|
49662
|
+
replyToMessageId: messageId2,
|
|
49663
|
+
sessionId: replyToSessionId
|
|
47568
49664
|
})
|
|
47569
49665
|
}
|
|
47570
49666
|
};
|
|
@@ -47629,7 +49725,8 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47629
49725
|
relayMessageId: messageId2,
|
|
47630
49726
|
returnAddress: buildBrokerReturnAddressForActor(snapshot2, requesterId, {
|
|
47631
49727
|
conversationId: conversation2.id,
|
|
47632
|
-
replyToMessageId: messageId2
|
|
49728
|
+
replyToMessageId: messageId2,
|
|
49729
|
+
sessionId: replyToSessionId
|
|
47633
49730
|
})
|
|
47634
49731
|
}
|
|
47635
49732
|
};
|
|
@@ -47651,7 +49748,14 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47651
49748
|
message: message2
|
|
47652
49749
|
};
|
|
47653
49750
|
}
|
|
47654
|
-
const resolved =
|
|
49751
|
+
const resolved = await resolveBrokerDeliveryTargetWithImplicitProjectCard({
|
|
49752
|
+
...payload,
|
|
49753
|
+
execution
|
|
49754
|
+
}, {
|
|
49755
|
+
requesterId,
|
|
49756
|
+
currentDirectory: projectPathRouteTarget(payload),
|
|
49757
|
+
reason: "implicit project delivery card"
|
|
49758
|
+
});
|
|
47655
49759
|
if (resolved.kind !== "resolved") {
|
|
47656
49760
|
const { record: record2 } = await recordScoutDispatchDurably(buildDispatchEnvelope(resolved, askedLabel, nodeId, runtime.snapshot(), { homeEndpointFor: homeEndpointForAgent }), {
|
|
47657
49761
|
requesterId
|
|
@@ -47732,6 +49836,7 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47732
49836
|
metadata: {
|
|
47733
49837
|
...payload.messageMetadata ?? {},
|
|
47734
49838
|
...labels.length ? { labels } : {},
|
|
49839
|
+
...targetSessionId ? { targetSessionId } : {},
|
|
47735
49840
|
relayChannel: deliveryChannel || (conversation.kind === "direct" ? "dm" : "shared"),
|
|
47736
49841
|
relayTarget: resolved.agent.id,
|
|
47737
49842
|
relayTargetIds: [resolved.agent.id],
|
|
@@ -47739,7 +49844,8 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47739
49844
|
...collaborationRecordId ? { collaborationRecordId, workId: collaborationRecordId } : {},
|
|
47740
49845
|
returnAddress: buildBrokerReturnAddressForActor(snapshot, requesterId, {
|
|
47741
49846
|
conversationId: conversation.id,
|
|
47742
|
-
replyToMessageId: messageId
|
|
49847
|
+
replyToMessageId: messageId,
|
|
49848
|
+
sessionId: replyToSessionId
|
|
47743
49849
|
})
|
|
47744
49850
|
}
|
|
47745
49851
|
};
|
|
@@ -47752,6 +49858,7 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47752
49858
|
requesterId,
|
|
47753
49859
|
requesterNodeId,
|
|
47754
49860
|
targetAgentId: resolved.agent.id,
|
|
49861
|
+
targetSessionId,
|
|
47755
49862
|
targetLabel,
|
|
47756
49863
|
conversationId: conversation.id,
|
|
47757
49864
|
messageId
|
|
@@ -47764,14 +49871,20 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47764
49871
|
conversation,
|
|
47765
49872
|
message,
|
|
47766
49873
|
targetAgentId: resolved.agent.id,
|
|
49874
|
+
...targetSessionId ? { targetSessionId } : {},
|
|
47767
49875
|
...workRecord?.kind === "work_item" ? { workItem: workRecord } : {}
|
|
47768
49876
|
};
|
|
47769
49877
|
}
|
|
47770
49878
|
const invocationMetadata = {
|
|
47771
49879
|
...typeof payload.messageMetadata?.source === "string" && payload.invocationMetadata?.source === undefined ? { source: payload.messageMetadata.source } : {},
|
|
47772
49880
|
...payload.invocationMetadata ?? {},
|
|
49881
|
+
...targetSessionId ? { targetSessionId } : {},
|
|
47773
49882
|
...payload.intent === "tell" && payload.invocationMetadata?.sourceIntent === undefined ? { sourceIntent: "direct_message" } : {}
|
|
47774
49883
|
};
|
|
49884
|
+
const invocationExecution = {
|
|
49885
|
+
...execution ?? (payload.intent === "tell" ? { session: "any" } : {}),
|
|
49886
|
+
...targetSessionId ? { session: "existing", targetSessionId } : {}
|
|
49887
|
+
};
|
|
47775
49888
|
const invocation = {
|
|
47776
49889
|
id: createRuntimeId2("inv"),
|
|
47777
49890
|
requesterId,
|
|
@@ -47782,7 +49895,7 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47782
49895
|
...collaborationRecordId ? { collaborationRecordId } : {},
|
|
47783
49896
|
conversationId: conversation.id,
|
|
47784
49897
|
messageId,
|
|
47785
|
-
|
|
49898
|
+
...Object.keys(invocationExecution).length > 0 ? { execution: invocationExecution } : {},
|
|
47786
49899
|
ensureAwake: payload.ensureAwake ?? true,
|
|
47787
49900
|
stream: false,
|
|
47788
49901
|
createdAt,
|
|
@@ -47790,12 +49903,14 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47790
49903
|
metadata: {
|
|
47791
49904
|
...invocationMetadata,
|
|
47792
49905
|
...labels.length ? { labels } : {},
|
|
49906
|
+
...targetSessionId ? { targetSessionId } : {},
|
|
47793
49907
|
relayChannel: deliveryChannel || (conversation.kind === "direct" ? "dm" : "shared"),
|
|
47794
49908
|
relayTarget: resolved.agent.id,
|
|
47795
49909
|
...collaborationRecordId ? { collaborationRecordId, workId: collaborationRecordId } : {},
|
|
47796
49910
|
returnAddress: buildBrokerReturnAddressForActor(snapshot, requesterId, {
|
|
47797
49911
|
conversationId: conversation.id,
|
|
47798
|
-
replyToMessageId: messageId
|
|
49912
|
+
replyToMessageId: messageId,
|
|
49913
|
+
sessionId: replyToSessionId
|
|
47799
49914
|
})
|
|
47800
49915
|
}
|
|
47801
49916
|
};
|
|
@@ -47814,6 +49929,7 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47814
49929
|
requesterId,
|
|
47815
49930
|
requesterNodeId,
|
|
47816
49931
|
targetAgentId: resolved.agent.id,
|
|
49932
|
+
targetSessionId,
|
|
47817
49933
|
targetLabel,
|
|
47818
49934
|
bindingRef,
|
|
47819
49935
|
conversationId: conversation.id,
|
|
@@ -47823,6 +49939,7 @@ async function acceptBrokerDelivery(payload) {
|
|
|
47823
49939
|
conversation,
|
|
47824
49940
|
message,
|
|
47825
49941
|
targetAgentId: resolved.agent.id,
|
|
49942
|
+
...targetSessionId ? { targetSessionId } : {},
|
|
47826
49943
|
bindingRef,
|
|
47827
49944
|
flight,
|
|
47828
49945
|
...workRecord?.kind === "work_item" ? { workItem: workRecord } : {}
|
|
@@ -47906,6 +50023,9 @@ setTimeout(() => {
|
|
|
47906
50023
|
reconcileStaleWorkingFlights().catch((error48) => {
|
|
47907
50024
|
console.error("[openscout-runtime] stale flight reconciliation failed:", error48);
|
|
47908
50025
|
});
|
|
50026
|
+
reconcileStaleLocalDeliveries().catch((error48) => {
|
|
50027
|
+
console.error("[openscout-runtime] stale delivery reconciliation failed:", error48);
|
|
50028
|
+
});
|
|
47909
50029
|
}, 0).unref();
|
|
47910
50030
|
discoverPeers().catch((error48) => {
|
|
47911
50031
|
console.error("[openscout-runtime] initial mesh discovery failed:", error48);
|