@openscout/scout 0.2.69 → 0.2.70
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/dist/client/assets/{addon-fit-DtSNdpy5.js → addon-fit-BNV7JPhj.js} +1 -1
- package/dist/client/assets/{addon-webgl-YYNKPQUg.js → addon-webgl-B-_Y5L3F.js} +1 -1
- package/dist/client/assets/index-BJri_z5a.css +1 -0
- package/dist/client/assets/index-Ccjo5BZz.js +199 -0
- package/dist/client/assets/{xterm-fBtFsYpq.js → xterm-Cx1oABPt.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/main.mjs +13252 -12118
- package/dist/openscout-terminal-relay.mjs +17 -94
- package/dist/pair-supervisor.mjs +600 -19
- package/dist/runtime/broker-daemon.mjs +1075 -153
- package/dist/scout-control-plane-web.mjs +988 -187
- package/dist/scout-web-server.mjs +988 -187
- package/package.json +1 -1
- package/dist/client/assets/index-5-XOQrKH.js +0 -186
- package/dist/client/assets/index-BnA2HAbt.css +0 -1
|
@@ -16,12 +16,13 @@ var __export = (target, all) => {
|
|
|
16
16
|
|
|
17
17
|
// packages/runtime/src/broker-daemon.ts
|
|
18
18
|
import { spawn as spawn5 } from "child_process";
|
|
19
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
19
20
|
import { createServer } from "http";
|
|
20
21
|
import { existsSync as existsSync19, mkdirSync as mkdirSync8, openSync as openSync3 } from "fs";
|
|
21
22
|
import { lstat, mkdir as mkdir8, stat as stat5, unlink } from "fs/promises";
|
|
22
23
|
import { createRequire } from "module";
|
|
23
24
|
import { hostname as hostname4 } from "os";
|
|
24
|
-
import { basename as
|
|
25
|
+
import { basename as basename12, dirname as dirname16, join as join25, resolve as resolve8 } from "path";
|
|
25
26
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
26
27
|
|
|
27
28
|
// node_modules/.bun/@trpc+server@11.16.0+1fb4c65d43e298b9/node_modules/@trpc/server/dist/codes-DagpWZLc.mjs
|
|
@@ -16320,6 +16321,7 @@ var RAW_MAX_STRING_LEN = 1000;
|
|
|
16320
16321
|
var RAW_MAX_ARRAY_ITEMS = 25;
|
|
16321
16322
|
var RAW_MAX_OBJECT_KEYS = 50;
|
|
16322
16323
|
var RECENT_TRANSCRIPT_READ_BYTES = 512 * 1024;
|
|
16324
|
+
var RECENT_TRANSCRIPT_LINES_PER_FILE = 200;
|
|
16323
16325
|
var RECENT_TRANSCRIPT_MAX_FILES = readPositiveIntEnv3("OPENSCOUT_TAIL_RECENT_TRANSCRIPT_MAX_FILES", 24);
|
|
16324
16326
|
var sources = [ClaudeSource, CodexSource];
|
|
16325
16327
|
var watchers = new Map;
|
|
@@ -16646,6 +16648,15 @@ function stopLoopIfIdle() {
|
|
|
16646
16648
|
}
|
|
16647
16649
|
watchers.clear();
|
|
16648
16650
|
}
|
|
16651
|
+
async function getTailDiscovery(force = false) {
|
|
16652
|
+
if (force) {
|
|
16653
|
+
return runDiscovery("deep", { pruneMissing: true });
|
|
16654
|
+
}
|
|
16655
|
+
if (lastDiscovery && Date.now() - lastDiscovery.generatedAt <= DISCOVERY_CACHE_MAX_AGE_MS) {
|
|
16656
|
+
return lastDiscovery;
|
|
16657
|
+
}
|
|
16658
|
+
return runDiscovery("shallow", { pruneMissing: true });
|
|
16659
|
+
}
|
|
16649
16660
|
function subscribeTail(handler) {
|
|
16650
16661
|
subscribers2.add(handler);
|
|
16651
16662
|
ensureLoopRunning();
|
|
@@ -16664,6 +16675,78 @@ function subscribeTail(handler) {
|
|
|
16664
16675
|
function snapshotRecentEvents(limit = 500) {
|
|
16665
16676
|
return aggregateBuffer.slice(-limit);
|
|
16666
16677
|
}
|
|
16678
|
+
async function readRecentLiveEvents(limit = 500) {
|
|
16679
|
+
if (watchers.size === 0) {
|
|
16680
|
+
await runDiscovery("shallow", { pruneMissing: true });
|
|
16681
|
+
} else if (!lastDiscovery || Date.now() - lastDiscovery.generatedAt > DISCOVERY_CACHE_MAX_AGE_MS) {
|
|
16682
|
+
await runDiscovery("hot", { pruneMissing: false });
|
|
16683
|
+
}
|
|
16684
|
+
await pumpAllWatchers();
|
|
16685
|
+
return snapshotRecentEvents(limit);
|
|
16686
|
+
}
|
|
16687
|
+
async function readRecentTranscriptLines(path, maxLines = RECENT_TRANSCRIPT_LINES_PER_FILE) {
|
|
16688
|
+
let handle = null;
|
|
16689
|
+
try {
|
|
16690
|
+
const stats = await stat(path);
|
|
16691
|
+
if (stats.size <= 0)
|
|
16692
|
+
return [];
|
|
16693
|
+
const start = Math.max(0, stats.size - RECENT_TRANSCRIPT_READ_BYTES);
|
|
16694
|
+
const length = stats.size - start;
|
|
16695
|
+
const buffer = Buffer.alloc(length);
|
|
16696
|
+
handle = await open(path, "r");
|
|
16697
|
+
await handle.read(buffer, 0, length, start);
|
|
16698
|
+
const lines = buffer.toString("utf8").split(`
|
|
16699
|
+
`);
|
|
16700
|
+
if (start > 0) {
|
|
16701
|
+
lines.shift();
|
|
16702
|
+
}
|
|
16703
|
+
return lines.filter(Boolean).slice(-maxLines);
|
|
16704
|
+
} catch {
|
|
16705
|
+
return [];
|
|
16706
|
+
} finally {
|
|
16707
|
+
await handle?.close().catch(() => {});
|
|
16708
|
+
}
|
|
16709
|
+
}
|
|
16710
|
+
async function readRecentTranscriptEvents(limit = 50, options) {
|
|
16711
|
+
const discovery = options?.discovery ?? await getTailDiscovery();
|
|
16712
|
+
const events = [];
|
|
16713
|
+
const seenTranscripts = new Set;
|
|
16714
|
+
const seenEvents = new Set;
|
|
16715
|
+
const transcriptReadLimit = Math.min(RECENT_TRANSCRIPT_MAX_FILES, Math.max(12, limit));
|
|
16716
|
+
for (const transcript of discovery.transcripts.slice(0, transcriptReadLimit)) {
|
|
16717
|
+
const key = transcriptKey(transcript);
|
|
16718
|
+
if (seenTranscripts.has(key))
|
|
16719
|
+
continue;
|
|
16720
|
+
seenTranscripts.add(key);
|
|
16721
|
+
const source = sources.find((candidate) => candidate.name === transcript.source);
|
|
16722
|
+
if (!source)
|
|
16723
|
+
continue;
|
|
16724
|
+
const process3 = processForTranscript(transcript, discovery.processes);
|
|
16725
|
+
const lines = await readRecentTranscriptLines(transcript.transcriptPath, options?.perTranscriptLineLimit);
|
|
16726
|
+
lines.forEach((line, index) => {
|
|
16727
|
+
const event = source.parseLine(line, {
|
|
16728
|
+
process: process3,
|
|
16729
|
+
transcript,
|
|
16730
|
+
transcriptPath: transcript.transcriptPath,
|
|
16731
|
+
lineOffset: index
|
|
16732
|
+
});
|
|
16733
|
+
if (event) {
|
|
16734
|
+
const compacted = compactEvent(event);
|
|
16735
|
+
const eventKey = [
|
|
16736
|
+
compacted.source,
|
|
16737
|
+
compacted.sessionId,
|
|
16738
|
+
compacted.kind,
|
|
16739
|
+
compacted.summary
|
|
16740
|
+
].join("\x00");
|
|
16741
|
+
if (!seenEvents.has(eventKey)) {
|
|
16742
|
+
seenEvents.add(eventKey);
|
|
16743
|
+
events.push(compacted);
|
|
16744
|
+
}
|
|
16745
|
+
}
|
|
16746
|
+
});
|
|
16747
|
+
}
|
|
16748
|
+
return events.sort((left, right) => right.ts - left.ts).slice(0, limit);
|
|
16749
|
+
}
|
|
16667
16750
|
// packages/runtime/src/harness-topology/service.ts
|
|
16668
16751
|
import { createHash } from "crypto";
|
|
16669
16752
|
import { homedir as homedir5 } from "os";
|
|
@@ -17798,6 +17881,16 @@ var tailEventsInput = exports_external.object({
|
|
|
17798
17881
|
since: exports_external.string().optional(),
|
|
17799
17882
|
sources: exports_external.array(exports_external.string()).optional()
|
|
17800
17883
|
}).optional();
|
|
17884
|
+
var tailRecentInput = exports_external.object({
|
|
17885
|
+
limit: exports_external.number().int().min(1).max(1000).optional(),
|
|
17886
|
+
sources: exports_external.array(exports_external.string()).optional(),
|
|
17887
|
+
kinds: exports_external.array(exports_external.string()).optional(),
|
|
17888
|
+
sessionId: exports_external.string().optional(),
|
|
17889
|
+
project: exports_external.string().optional(),
|
|
17890
|
+
cwd: exports_external.string().optional(),
|
|
17891
|
+
query: exports_external.string().optional(),
|
|
17892
|
+
transcripts: exports_external.boolean().optional()
|
|
17893
|
+
}).optional();
|
|
17801
17894
|
var topologyEventsInput = exports_external.object({
|
|
17802
17895
|
since: exports_external.string().optional(),
|
|
17803
17896
|
sources: exports_external.array(exports_external.string()).optional()
|
|
@@ -17946,6 +18039,48 @@ function topologyEventIterable(sources2, signal) {
|
|
|
17946
18039
|
}
|
|
17947
18040
|
};
|
|
17948
18041
|
}
|
|
18042
|
+
function normalizedFilterSet(values) {
|
|
18043
|
+
const normalized = values?.map((value) => value.trim().toLowerCase()).filter(Boolean);
|
|
18044
|
+
return normalized && normalized.length > 0 ? new Set(normalized) : null;
|
|
18045
|
+
}
|
|
18046
|
+
function textMatches(value, query) {
|
|
18047
|
+
if (!query)
|
|
18048
|
+
return true;
|
|
18049
|
+
return (value ?? "").toLowerCase().includes(query);
|
|
18050
|
+
}
|
|
18051
|
+
function tailEventMatches(event, input) {
|
|
18052
|
+
const sources2 = normalizedFilterSet(input?.sources);
|
|
18053
|
+
if (sources2 && !sources2.has(event.source.toLowerCase()))
|
|
18054
|
+
return false;
|
|
18055
|
+
const kinds = normalizedFilterSet(input?.kinds);
|
|
18056
|
+
if (kinds && !kinds.has(event.kind.toLowerCase()))
|
|
18057
|
+
return false;
|
|
18058
|
+
const sessionId = input?.sessionId?.trim();
|
|
18059
|
+
if (sessionId && event.sessionId !== sessionId)
|
|
18060
|
+
return false;
|
|
18061
|
+
const project = input?.project?.trim().toLowerCase();
|
|
18062
|
+
if (project && !textMatches(event.project, project))
|
|
18063
|
+
return false;
|
|
18064
|
+
const cwd = input?.cwd?.trim().toLowerCase();
|
|
18065
|
+
if (cwd && !textMatches(event.cwd, cwd))
|
|
18066
|
+
return false;
|
|
18067
|
+
const query = input?.query?.trim().toLowerCase();
|
|
18068
|
+
if (query) {
|
|
18069
|
+
const haystack = [
|
|
18070
|
+
event.source,
|
|
18071
|
+
event.kind,
|
|
18072
|
+
event.sessionId,
|
|
18073
|
+
event.project,
|
|
18074
|
+
event.cwd,
|
|
18075
|
+
event.harness,
|
|
18076
|
+
event.summary
|
|
18077
|
+
].join(`
|
|
18078
|
+
`).toLowerCase();
|
|
18079
|
+
if (!haystack.includes(query))
|
|
18080
|
+
return false;
|
|
18081
|
+
}
|
|
18082
|
+
return true;
|
|
18083
|
+
}
|
|
17949
18084
|
var controlRouter = t.router({
|
|
17950
18085
|
events: t.procedure.input(controlEventsInput).subscription(async function* ({ input, signal }) {
|
|
17951
18086
|
const kinds = input?.kinds;
|
|
@@ -17971,6 +18106,33 @@ var controlRouter = t.router({
|
|
|
17971
18106
|
})
|
|
17972
18107
|
});
|
|
17973
18108
|
var tailRouter = t.router({
|
|
18109
|
+
recent: t.procedure.input(tailRecentInput).query(async ({ input }) => {
|
|
18110
|
+
const limit = input?.limit ?? TAIL_BACKLOG_LIMIT;
|
|
18111
|
+
const bufferedEvents = await readRecentLiveEvents(limit);
|
|
18112
|
+
const eventsById = new Map;
|
|
18113
|
+
if (input?.transcripts) {
|
|
18114
|
+
const transcriptEvents = await readRecentTranscriptEvents(limit, {
|
|
18115
|
+
perTranscriptLineLimit: Math.min(200, Math.max(50, limit))
|
|
18116
|
+
});
|
|
18117
|
+
for (const event of transcriptEvents) {
|
|
18118
|
+
eventsById.set(event.id, event);
|
|
18119
|
+
}
|
|
18120
|
+
}
|
|
18121
|
+
for (const event of bufferedEvents) {
|
|
18122
|
+
eventsById.set(event.id, event);
|
|
18123
|
+
}
|
|
18124
|
+
const events = [...eventsById.values()].filter((event) => tailEventMatches(event, input)).sort((left, right) => {
|
|
18125
|
+
if (left.ts === right.ts)
|
|
18126
|
+
return left.id.localeCompare(right.id);
|
|
18127
|
+
return left.ts - right.ts;
|
|
18128
|
+
}).slice(-limit);
|
|
18129
|
+
return {
|
|
18130
|
+
generatedAt: Date.now(),
|
|
18131
|
+
limit,
|
|
18132
|
+
cursor: events.at(-1)?.id ?? null,
|
|
18133
|
+
events
|
|
18134
|
+
};
|
|
18135
|
+
}),
|
|
17974
18136
|
events: t.procedure.input(tailEventsInput).subscription(async function* ({ input, signal }) {
|
|
17975
18137
|
const sources2 = input?.sources;
|
|
17976
18138
|
const filter = sources2 && sources2.length > 0 ? new Set(sources2) : null;
|
|
@@ -18512,6 +18674,31 @@ function buildUnsignedMeshPresence(input) {
|
|
|
18512
18674
|
...input.metadata ? { metadata: input.metadata } : {}
|
|
18513
18675
|
};
|
|
18514
18676
|
}
|
|
18677
|
+
// packages/protocol/src/channel-identity.ts
|
|
18678
|
+
var CHANNEL_ID_PREFIX = "c.";
|
|
18679
|
+
var CHANNEL_NATURAL_KEY_METADATA = "naturalKey";
|
|
18680
|
+
function mintChannelId(randomUuid) {
|
|
18681
|
+
return `${CHANNEL_ID_PREFIX}${randomUuid().toLowerCase()}`;
|
|
18682
|
+
}
|
|
18683
|
+
function directChannelNaturalKey(participantIds) {
|
|
18684
|
+
return `direct:${stableIdentityParts(participantIds).join(",")}`;
|
|
18685
|
+
}
|
|
18686
|
+
function namedChannelNaturalKey(channel) {
|
|
18687
|
+
return `channel:${encodeIdentityPart(channel.trim().toLowerCase() || "shared")}`;
|
|
18688
|
+
}
|
|
18689
|
+
function systemChannelNaturalKey(name) {
|
|
18690
|
+
return `system:${encodeIdentityPart(name.trim().toLowerCase() || "system")}`;
|
|
18691
|
+
}
|
|
18692
|
+
function channelNaturalKeyFromMetadata(metadata) {
|
|
18693
|
+
const value = metadata?.[CHANNEL_NATURAL_KEY_METADATA];
|
|
18694
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
18695
|
+
}
|
|
18696
|
+
function stableIdentityParts(values) {
|
|
18697
|
+
return Array.from(new Set(values.map((value) => value.trim()).filter(Boolean))).sort().map(encodeIdentityPart);
|
|
18698
|
+
}
|
|
18699
|
+
function encodeIdentityPart(value) {
|
|
18700
|
+
return encodeURIComponent(value).replace(/[!'()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
18701
|
+
}
|
|
18515
18702
|
// packages/protocol/src/collaboration.ts
|
|
18516
18703
|
function isQuestionTerminalState(state) {
|
|
18517
18704
|
return state === "closed" || state === "declined";
|
|
@@ -20273,29 +20460,6 @@ function resolveAgentLabel(snapshot, label, options) {
|
|
|
20273
20460
|
return agnosticResolution;
|
|
20274
20461
|
}
|
|
20275
20462
|
}
|
|
20276
|
-
const fallbackCandidates = buildAgentLabelCandidates(snapshot, options.helpers, {
|
|
20277
|
-
includeStale: true
|
|
20278
|
-
});
|
|
20279
|
-
const fallbackDiagnosis = diagnoseAgentIdentity(identity2, fallbackCandidates);
|
|
20280
|
-
if (fallbackDiagnosis.kind === "resolved") {
|
|
20281
|
-
return {
|
|
20282
|
-
kind: "resolved",
|
|
20283
|
-
agent: fallbackDiagnosis.match.agent
|
|
20284
|
-
};
|
|
20285
|
-
}
|
|
20286
|
-
if (fallbackDiagnosis.kind === "ambiguous") {
|
|
20287
|
-
return {
|
|
20288
|
-
kind: "ambiguous",
|
|
20289
|
-
label: identity2.label,
|
|
20290
|
-
candidates: fallbackDiagnosis.candidates.map((candidate) => candidate.agent)
|
|
20291
|
-
};
|
|
20292
|
-
}
|
|
20293
|
-
if (harnessAgnosticIdentity) {
|
|
20294
|
-
const agnosticFallbackResolution = resolutionFromDiagnosis(diagnoseAgentIdentity(harnessAgnosticIdentity, fallbackCandidates), identity2.label);
|
|
20295
|
-
if (agnosticFallbackResolution) {
|
|
20296
|
-
return agnosticFallbackResolution;
|
|
20297
|
-
}
|
|
20298
|
-
}
|
|
20299
20463
|
return { kind: "unknown", label: identity2.label };
|
|
20300
20464
|
}
|
|
20301
20465
|
const preferLocal = options.preferLocalNodeId?.trim();
|
|
@@ -21734,7 +21898,7 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
21734
21898
|
import { execFileSync as execFileSync3, execSync } from "child_process";
|
|
21735
21899
|
import { existsSync as existsSync14, readFileSync as readFileSync7 } from "fs";
|
|
21736
21900
|
import { mkdir as mkdir7, rm as rm5, stat as stat4, writeFile as writeFile7 } from "fs/promises";
|
|
21737
|
-
import { basename as
|
|
21901
|
+
import { basename as basename10, dirname as dirname11, join as join19, resolve as resolve7 } from "path";
|
|
21738
21902
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
21739
21903
|
|
|
21740
21904
|
// packages/runtime/src/dispatch-stalled.ts
|
|
@@ -22945,6 +23109,7 @@ class SessionRegistry {
|
|
|
22945
23109
|
}
|
|
22946
23110
|
}
|
|
22947
23111
|
// packages/agent-sessions/src/history.ts
|
|
23112
|
+
import { basename as basename6, dirname as dirname4 } from "path";
|
|
22948
23113
|
function normalizeTimestamp(value) {
|
|
22949
23114
|
if (typeof value === "number") {
|
|
22950
23115
|
if (!Number.isFinite(value)) {
|
|
@@ -23033,6 +23198,59 @@ function renderToolResultContent(content) {
|
|
|
23033
23198
|
}
|
|
23034
23199
|
return stringifyUnknown(content);
|
|
23035
23200
|
}
|
|
23201
|
+
function renderContentPartsText(content) {
|
|
23202
|
+
if (typeof content === "string") {
|
|
23203
|
+
return content;
|
|
23204
|
+
}
|
|
23205
|
+
if (!Array.isArray(content)) {
|
|
23206
|
+
return "";
|
|
23207
|
+
}
|
|
23208
|
+
return content.map((entry) => {
|
|
23209
|
+
if (typeof entry === "string") {
|
|
23210
|
+
return entry;
|
|
23211
|
+
}
|
|
23212
|
+
if (!isRecord(entry)) {
|
|
23213
|
+
return "";
|
|
23214
|
+
}
|
|
23215
|
+
if (typeof entry.text === "string") {
|
|
23216
|
+
return entry.text;
|
|
23217
|
+
}
|
|
23218
|
+
if (typeof entry.content === "string") {
|
|
23219
|
+
return entry.content;
|
|
23220
|
+
}
|
|
23221
|
+
return "";
|
|
23222
|
+
}).filter(Boolean).join(`
|
|
23223
|
+
`);
|
|
23224
|
+
}
|
|
23225
|
+
function extractReasoningText(item) {
|
|
23226
|
+
const summary = Array.isArray(item.summary) ? item.summary : [];
|
|
23227
|
+
const content = Array.isArray(item.content) ? item.content : [];
|
|
23228
|
+
const summaryText = summary.map((entry) => {
|
|
23229
|
+
if (typeof entry === "string") {
|
|
23230
|
+
return entry;
|
|
23231
|
+
}
|
|
23232
|
+
const record2 = entry;
|
|
23233
|
+
if (typeof record2.text === "string") {
|
|
23234
|
+
return record2.text;
|
|
23235
|
+
}
|
|
23236
|
+
if (typeof record2.summary === "string") {
|
|
23237
|
+
return record2.summary;
|
|
23238
|
+
}
|
|
23239
|
+
return "";
|
|
23240
|
+
}).filter(Boolean).join(`
|
|
23241
|
+
`);
|
|
23242
|
+
const contentText = content.map((entry) => {
|
|
23243
|
+
if (typeof entry === "string") {
|
|
23244
|
+
return entry;
|
|
23245
|
+
}
|
|
23246
|
+
const record2 = entry;
|
|
23247
|
+
return typeof record2.text === "string" ? record2.text : "";
|
|
23248
|
+
}).filter(Boolean).join(`
|
|
23249
|
+
`);
|
|
23250
|
+
return [summaryText, contentText].filter(Boolean).join(`
|
|
23251
|
+
|
|
23252
|
+
`).trim();
|
|
23253
|
+
}
|
|
23036
23254
|
function extractQuestionOptions(firstQuestion) {
|
|
23037
23255
|
const options = Array.isArray(firstQuestion.options) ? firstQuestion.options : [];
|
|
23038
23256
|
return options.map((option) => {
|
|
@@ -23709,6 +23927,505 @@ class ClaudeCodeHistoryParser {
|
|
|
23709
23927
|
});
|
|
23710
23928
|
}
|
|
23711
23929
|
}
|
|
23930
|
+
|
|
23931
|
+
class CodexHistoryParser {
|
|
23932
|
+
session;
|
|
23933
|
+
baseTimestampMs;
|
|
23934
|
+
events = [];
|
|
23935
|
+
currentTurn = null;
|
|
23936
|
+
turnCounter = 0;
|
|
23937
|
+
blockIndex = 0;
|
|
23938
|
+
blockById = new Map;
|
|
23939
|
+
toolBlockMap = new Map;
|
|
23940
|
+
assistantMessageTextThisTurn = new Set;
|
|
23941
|
+
inputTokens = 0;
|
|
23942
|
+
outputTokens = 0;
|
|
23943
|
+
reasoningOutputTokens = 0;
|
|
23944
|
+
cachedInputTokens = 0;
|
|
23945
|
+
tokenEventCount = 0;
|
|
23946
|
+
constructor(session, baseTimestampMs) {
|
|
23947
|
+
this.session = session;
|
|
23948
|
+
this.baseTimestampMs = baseTimestampMs;
|
|
23949
|
+
}
|
|
23950
|
+
parse(content) {
|
|
23951
|
+
const lines = content.split(/\r?\n/u);
|
|
23952
|
+
let parsedLineCount = 0;
|
|
23953
|
+
let skippedLineCount = 0;
|
|
23954
|
+
let lineCount = 0;
|
|
23955
|
+
let lastCapturedAt = this.baseTimestampMs;
|
|
23956
|
+
for (let index = 0;index < lines.length; index += 1) {
|
|
23957
|
+
const rawLine = lines[index];
|
|
23958
|
+
const trimmed = rawLine.trim();
|
|
23959
|
+
if (!trimmed) {
|
|
23960
|
+
continue;
|
|
23961
|
+
}
|
|
23962
|
+
lineCount += 1;
|
|
23963
|
+
let record2;
|
|
23964
|
+
try {
|
|
23965
|
+
const parsed = JSON.parse(trimmed);
|
|
23966
|
+
if (!isRecord(parsed)) {
|
|
23967
|
+
skippedLineCount += 1;
|
|
23968
|
+
continue;
|
|
23969
|
+
}
|
|
23970
|
+
record2 = parsed;
|
|
23971
|
+
} catch {
|
|
23972
|
+
skippedLineCount += 1;
|
|
23973
|
+
continue;
|
|
23974
|
+
}
|
|
23975
|
+
const capturedAt = extractRecordTimestamp(record2) ?? this.baseTimestampMs + index;
|
|
23976
|
+
lastCapturedAt = capturedAt;
|
|
23977
|
+
if (this.handleRecord(record2, capturedAt)) {
|
|
23978
|
+
parsedLineCount += 1;
|
|
23979
|
+
} else {
|
|
23980
|
+
skippedLineCount += 1;
|
|
23981
|
+
}
|
|
23982
|
+
}
|
|
23983
|
+
if (this.persistUsageMetadata()) {
|
|
23984
|
+
this.emitSessionUpdate(lastCapturedAt);
|
|
23985
|
+
}
|
|
23986
|
+
return {
|
|
23987
|
+
events: this.events,
|
|
23988
|
+
lineCount,
|
|
23989
|
+
parsedLineCount,
|
|
23990
|
+
skippedLineCount
|
|
23991
|
+
};
|
|
23992
|
+
}
|
|
23993
|
+
handleRecord(record2, capturedAt) {
|
|
23994
|
+
const type = maybeString(record2.type);
|
|
23995
|
+
if (!type) {
|
|
23996
|
+
return false;
|
|
23997
|
+
}
|
|
23998
|
+
switch (type) {
|
|
23999
|
+
case "session_meta":
|
|
24000
|
+
this.handleSessionMeta(record2, capturedAt);
|
|
24001
|
+
return true;
|
|
24002
|
+
case "turn_context":
|
|
24003
|
+
this.handleTurnContext(record2, capturedAt);
|
|
24004
|
+
return true;
|
|
24005
|
+
case "event_msg":
|
|
24006
|
+
this.handleEventMessage(record2, capturedAt);
|
|
24007
|
+
return true;
|
|
24008
|
+
case "response_item":
|
|
24009
|
+
this.handleResponseItem(record2, capturedAt);
|
|
24010
|
+
return true;
|
|
24011
|
+
case "compacted":
|
|
24012
|
+
return true;
|
|
24013
|
+
default:
|
|
24014
|
+
return false;
|
|
24015
|
+
}
|
|
24016
|
+
}
|
|
24017
|
+
handleSessionMeta(record2, capturedAt) {
|
|
24018
|
+
const payload = isRecord(record2.payload) ? record2.payload : {};
|
|
24019
|
+
let changed = false;
|
|
24020
|
+
const providerMeta = this.ensureProviderMeta();
|
|
24021
|
+
const externalSessionId = maybeString(payload.id);
|
|
24022
|
+
if (externalSessionId && providerMeta.externalSessionId !== externalSessionId) {
|
|
24023
|
+
providerMeta.externalSessionId = externalSessionId;
|
|
24024
|
+
changed = true;
|
|
24025
|
+
}
|
|
24026
|
+
const cwd = maybeString(payload.cwd);
|
|
24027
|
+
if (cwd && this.session.cwd !== cwd) {
|
|
24028
|
+
this.session.cwd = cwd;
|
|
24029
|
+
if (!this.session.name || /^\d+$/u.test(this.session.name)) {
|
|
24030
|
+
this.session.name = basename6(cwd) || "Codex Session";
|
|
24031
|
+
}
|
|
24032
|
+
changed = true;
|
|
24033
|
+
}
|
|
24034
|
+
const git = isRecord(payload.git) ? payload.git : null;
|
|
24035
|
+
const runtime = this.ensureObserveMetaRecord("observeRuntime");
|
|
24036
|
+
changed = this.assignObserveString(runtime, "originator", payload.originator) || changed;
|
|
24037
|
+
changed = this.assignObserveString(runtime, "cliVersion", payload.cli_version) || changed;
|
|
24038
|
+
changed = this.assignObserveString(runtime, "source", payload.source) || changed;
|
|
24039
|
+
changed = this.assignObserveString(runtime, "threadSource", payload.thread_source) || changed;
|
|
24040
|
+
changed = this.assignObserveString(runtime, "modelProvider", payload.model_provider) || changed;
|
|
24041
|
+
changed = this.assignObserveString(runtime, "gitBranch", git?.branch) || changed;
|
|
24042
|
+
changed = this.assignObserveString(runtime, "gitCommitHash", git?.commit_hash) || changed;
|
|
24043
|
+
changed = this.assignObserveString(runtime, "repositoryUrl", git?.repository_url) || changed;
|
|
24044
|
+
if (changed) {
|
|
24045
|
+
this.emitSessionUpdate(capturedAt);
|
|
24046
|
+
}
|
|
24047
|
+
}
|
|
24048
|
+
handleTurnContext(record2, capturedAt) {
|
|
24049
|
+
const payload = isRecord(record2.payload) ? record2.payload : {};
|
|
24050
|
+
let changed = false;
|
|
24051
|
+
const cwd = maybeString(payload.cwd);
|
|
24052
|
+
if (cwd && this.session.cwd !== cwd) {
|
|
24053
|
+
this.session.cwd = cwd;
|
|
24054
|
+
changed = true;
|
|
24055
|
+
}
|
|
24056
|
+
const model = maybeString(payload.model);
|
|
24057
|
+
if (model && this.session.model !== model) {
|
|
24058
|
+
this.session.model = model;
|
|
24059
|
+
changed = true;
|
|
24060
|
+
}
|
|
24061
|
+
const runtime = this.ensureObserveMetaRecord("observeRuntime");
|
|
24062
|
+
changed = this.assignObserveString(runtime, "approvalPolicy", payload.approval_policy) || changed;
|
|
24063
|
+
changed = this.assignObserveString(runtime, "currentDate", payload.current_date) || changed;
|
|
24064
|
+
changed = this.assignObserveString(runtime, "timezone", payload.timezone) || changed;
|
|
24065
|
+
changed = this.assignObserveString(runtime, "effort", payload.effort) || changed;
|
|
24066
|
+
changed = this.assignObserveString(runtime, "personality", payload.personality) || changed;
|
|
24067
|
+
if (isRecord(payload.sandbox_policy) && runtime.sandboxPolicy !== payload.sandbox_policy) {
|
|
24068
|
+
runtime.sandboxPolicy = payload.sandbox_policy;
|
|
24069
|
+
changed = true;
|
|
24070
|
+
}
|
|
24071
|
+
if (changed) {
|
|
24072
|
+
this.emitSessionUpdate(capturedAt);
|
|
24073
|
+
}
|
|
24074
|
+
}
|
|
24075
|
+
handleEventMessage(record2, capturedAt) {
|
|
24076
|
+
const payload = isRecord(record2.payload) ? record2.payload : {};
|
|
24077
|
+
const eventType = maybeString(payload.type);
|
|
24078
|
+
if (!eventType) {
|
|
24079
|
+
return;
|
|
24080
|
+
}
|
|
24081
|
+
switch (eventType) {
|
|
24082
|
+
case "task_started": {
|
|
24083
|
+
const startedAt = normalizeTimestamp(payload.started_at) ?? capturedAt;
|
|
24084
|
+
this.startTurn(startedAt, maybeString(payload.turn_id));
|
|
24085
|
+
break;
|
|
24086
|
+
}
|
|
24087
|
+
case "user_message":
|
|
24088
|
+
this.ensureTurn(capturedAt);
|
|
24089
|
+
break;
|
|
24090
|
+
case "agent_message": {
|
|
24091
|
+
const message = maybeString(payload.message);
|
|
24092
|
+
if (message) {
|
|
24093
|
+
this.appendCompletedText(capturedAt, message);
|
|
24094
|
+
this.assistantMessageTextThisTurn.add(message);
|
|
24095
|
+
}
|
|
24096
|
+
break;
|
|
24097
|
+
}
|
|
24098
|
+
case "patch_apply_end":
|
|
24099
|
+
this.handleToolOutput(capturedAt, maybeString(payload.call_id), [maybeString(payload.stdout), maybeString(payload.stderr)].filter(Boolean).join(`
|
|
24100
|
+
`), payload.success === false);
|
|
24101
|
+
break;
|
|
24102
|
+
case "token_count":
|
|
24103
|
+
this.captureTokenUsage(payload.info);
|
|
24104
|
+
break;
|
|
24105
|
+
case "task_complete":
|
|
24106
|
+
this.endTurn("completed", normalizeTimestamp(payload.completed_at) ?? capturedAt);
|
|
24107
|
+
break;
|
|
24108
|
+
case "context_compacted":
|
|
24109
|
+
case "web_search_end":
|
|
24110
|
+
break;
|
|
24111
|
+
default:
|
|
24112
|
+
break;
|
|
24113
|
+
}
|
|
24114
|
+
}
|
|
24115
|
+
handleResponseItem(record2, capturedAt) {
|
|
24116
|
+
const payload = isRecord(record2.payload) ? record2.payload : {};
|
|
24117
|
+
const itemType = maybeString(payload.type);
|
|
24118
|
+
if (!itemType) {
|
|
24119
|
+
return;
|
|
24120
|
+
}
|
|
24121
|
+
switch (itemType) {
|
|
24122
|
+
case "message":
|
|
24123
|
+
this.handleResponseMessage(payload, capturedAt);
|
|
24124
|
+
break;
|
|
24125
|
+
case "reasoning":
|
|
24126
|
+
this.handleReasoning(payload, capturedAt);
|
|
24127
|
+
break;
|
|
24128
|
+
case "function_call":
|
|
24129
|
+
case "custom_tool_call":
|
|
24130
|
+
this.handleToolCall(payload, capturedAt);
|
|
24131
|
+
break;
|
|
24132
|
+
case "function_call_output":
|
|
24133
|
+
case "custom_tool_call_output":
|
|
24134
|
+
this.handleToolOutput(capturedAt, maybeString(payload.call_id), renderToolResultContent(payload.output), false);
|
|
24135
|
+
break;
|
|
24136
|
+
case "web_search_call":
|
|
24137
|
+
this.handleWebSearchCall(payload, capturedAt);
|
|
24138
|
+
break;
|
|
24139
|
+
default:
|
|
24140
|
+
break;
|
|
24141
|
+
}
|
|
24142
|
+
}
|
|
24143
|
+
handleResponseMessage(payload, capturedAt) {
|
|
24144
|
+
const role = maybeString(payload.role);
|
|
24145
|
+
if (role !== "assistant") {
|
|
24146
|
+
return;
|
|
24147
|
+
}
|
|
24148
|
+
const text = renderContentPartsText(payload.content).trim();
|
|
24149
|
+
if (!text || this.assistantMessageTextThisTurn.has(text)) {
|
|
24150
|
+
return;
|
|
24151
|
+
}
|
|
24152
|
+
this.appendCompletedText(capturedAt, text);
|
|
24153
|
+
this.assistantMessageTextThisTurn.add(text);
|
|
24154
|
+
}
|
|
24155
|
+
handleReasoning(payload, capturedAt) {
|
|
24156
|
+
const text = extractReasoningText(payload);
|
|
24157
|
+
if (!text) {
|
|
24158
|
+
return;
|
|
24159
|
+
}
|
|
24160
|
+
const turn = this.ensureTurn(capturedAt);
|
|
24161
|
+
const block = this.startBlock(turn, capturedAt, {
|
|
24162
|
+
type: "reasoning",
|
|
24163
|
+
text,
|
|
24164
|
+
status: "completed"
|
|
24165
|
+
});
|
|
24166
|
+
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
24167
|
+
}
|
|
24168
|
+
handleToolCall(payload, capturedAt) {
|
|
24169
|
+
const turn = this.ensureTurn(capturedAt);
|
|
24170
|
+
const toolName = maybeString(payload.name) ?? "unknown";
|
|
24171
|
+
const toolCallId = maybeString(payload.call_id) ?? `${turn.id}:tool:${this.blockIndex}`;
|
|
24172
|
+
const input = this.parseToolInput(payload.arguments ?? payload.input);
|
|
24173
|
+
const action = this.buildAction(toolName, toolCallId, input);
|
|
24174
|
+
const block = this.startBlock(turn, capturedAt, {
|
|
24175
|
+
id: `${turn.id}:action:${toolCallId}`,
|
|
24176
|
+
type: "action",
|
|
24177
|
+
action,
|
|
24178
|
+
status: "streaming"
|
|
24179
|
+
});
|
|
24180
|
+
this.toolBlockMap.set(toolCallId, block.id);
|
|
24181
|
+
}
|
|
24182
|
+
handleWebSearchCall(payload, capturedAt) {
|
|
24183
|
+
const turn = this.ensureTurn(capturedAt);
|
|
24184
|
+
const toolCallId = `${turn.id}:web-search:${this.blockIndex}`;
|
|
24185
|
+
const action = {
|
|
24186
|
+
kind: "tool_call",
|
|
24187
|
+
toolName: "web_search",
|
|
24188
|
+
toolCallId,
|
|
24189
|
+
input: payload.action,
|
|
24190
|
+
result: payload.status,
|
|
24191
|
+
status: maybeString(payload.status) === "failed" ? "failed" : "completed",
|
|
24192
|
+
output: ""
|
|
24193
|
+
};
|
|
24194
|
+
const block = this.startBlock(turn, capturedAt, {
|
|
24195
|
+
id: `${turn.id}:action:${toolCallId}`,
|
|
24196
|
+
type: "action",
|
|
24197
|
+
action,
|
|
24198
|
+
status: "completed"
|
|
24199
|
+
});
|
|
24200
|
+
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
24201
|
+
}
|
|
24202
|
+
parseToolInput(value) {
|
|
24203
|
+
if (typeof value !== "string") {
|
|
24204
|
+
return value;
|
|
24205
|
+
}
|
|
24206
|
+
const trimmed = value.trim();
|
|
24207
|
+
if (!trimmed) {
|
|
24208
|
+
return "";
|
|
24209
|
+
}
|
|
24210
|
+
try {
|
|
24211
|
+
return JSON.parse(trimmed);
|
|
24212
|
+
} catch {
|
|
24213
|
+
return value;
|
|
24214
|
+
}
|
|
24215
|
+
}
|
|
24216
|
+
buildAction(toolName, toolCallId, input) {
|
|
24217
|
+
const inputRecord = isRecord(input) ? input : {};
|
|
24218
|
+
if (toolName === "exec_command") {
|
|
24219
|
+
return {
|
|
24220
|
+
kind: "command",
|
|
24221
|
+
command: maybeString(inputRecord.cmd) ?? "",
|
|
24222
|
+
status: "running",
|
|
24223
|
+
output: ""
|
|
24224
|
+
};
|
|
24225
|
+
}
|
|
24226
|
+
return {
|
|
24227
|
+
kind: "tool_call",
|
|
24228
|
+
toolName,
|
|
24229
|
+
toolCallId,
|
|
24230
|
+
input,
|
|
24231
|
+
status: "running",
|
|
24232
|
+
output: ""
|
|
24233
|
+
};
|
|
24234
|
+
}
|
|
24235
|
+
handleToolOutput(capturedAt, toolCallId, output, isError) {
|
|
24236
|
+
if (!toolCallId) {
|
|
24237
|
+
return;
|
|
24238
|
+
}
|
|
24239
|
+
const blockId = this.toolBlockMap.get(toolCallId);
|
|
24240
|
+
const turn = this.currentTurn;
|
|
24241
|
+
if (!blockId || !turn) {
|
|
24242
|
+
return;
|
|
24243
|
+
}
|
|
24244
|
+
if (output) {
|
|
24245
|
+
this.emitEvent(capturedAt, {
|
|
24246
|
+
event: "block:action:output",
|
|
24247
|
+
sessionId: this.session.id,
|
|
24248
|
+
turnId: turn.id,
|
|
24249
|
+
blockId,
|
|
24250
|
+
output
|
|
24251
|
+
});
|
|
24252
|
+
}
|
|
24253
|
+
const exitCode = this.extractExitCode(output);
|
|
24254
|
+
const status = isError || exitCode != null && exitCode !== 0 ? "failed" : "completed";
|
|
24255
|
+
this.emitEvent(capturedAt, {
|
|
24256
|
+
event: "block:action:status",
|
|
24257
|
+
sessionId: this.session.id,
|
|
24258
|
+
turnId: turn.id,
|
|
24259
|
+
blockId,
|
|
24260
|
+
status,
|
|
24261
|
+
...exitCode != null ? { meta: { exitCode } } : {}
|
|
24262
|
+
});
|
|
24263
|
+
const block = this.blockById.get(blockId);
|
|
24264
|
+
if (block) {
|
|
24265
|
+
this.emitBlockEnd(capturedAt, turn, block, status === "failed" ? "failed" : "completed");
|
|
24266
|
+
}
|
|
24267
|
+
this.toolBlockMap.delete(toolCallId);
|
|
24268
|
+
}
|
|
24269
|
+
extractExitCode(output) {
|
|
24270
|
+
const match = output.match(/(?:exit code|exited with code):\s*(-?\d+)/iu);
|
|
24271
|
+
if (!match) {
|
|
24272
|
+
return null;
|
|
24273
|
+
}
|
|
24274
|
+
const exitCode = Number(match[1]);
|
|
24275
|
+
return Number.isFinite(exitCode) ? exitCode : null;
|
|
24276
|
+
}
|
|
24277
|
+
captureTokenUsage(info) {
|
|
24278
|
+
if (!isRecord(info)) {
|
|
24279
|
+
return;
|
|
24280
|
+
}
|
|
24281
|
+
const total = isRecord(info.total_token_usage) ? info.total_token_usage : {};
|
|
24282
|
+
this.inputTokens = maybeNumber(total.input_tokens) ?? this.inputTokens;
|
|
24283
|
+
this.outputTokens = maybeNumber(total.output_tokens) ?? this.outputTokens;
|
|
24284
|
+
this.reasoningOutputTokens = maybeNumber(total.reasoning_output_tokens) ?? this.reasoningOutputTokens;
|
|
24285
|
+
this.cachedInputTokens = maybeNumber(total.cached_input_tokens) ?? this.cachedInputTokens;
|
|
24286
|
+
this.tokenEventCount += 1;
|
|
24287
|
+
}
|
|
24288
|
+
persistUsageMetadata() {
|
|
24289
|
+
if (this.tokenEventCount === 0) {
|
|
24290
|
+
return false;
|
|
24291
|
+
}
|
|
24292
|
+
const usage = this.ensureObserveMetaRecord("observeUsage");
|
|
24293
|
+
let changed = false;
|
|
24294
|
+
const assignNumber = (key, value) => {
|
|
24295
|
+
if (value > 0 && usage[key] !== value) {
|
|
24296
|
+
usage[key] = value;
|
|
24297
|
+
changed = true;
|
|
24298
|
+
}
|
|
24299
|
+
};
|
|
24300
|
+
assignNumber("inputTokens", this.inputTokens);
|
|
24301
|
+
assignNumber("outputTokens", this.outputTokens);
|
|
24302
|
+
assignNumber("reasoningOutputTokens", this.reasoningOutputTokens);
|
|
24303
|
+
assignNumber("cacheReadInputTokens", this.cachedInputTokens);
|
|
24304
|
+
assignNumber("tokenEvents", this.tokenEventCount);
|
|
24305
|
+
return changed;
|
|
24306
|
+
}
|
|
24307
|
+
startTurn(capturedAt, turnId) {
|
|
24308
|
+
if (this.currentTurn) {
|
|
24309
|
+
this.endTurn("stopped", capturedAt);
|
|
24310
|
+
}
|
|
24311
|
+
this.turnCounter += 1;
|
|
24312
|
+
this.blockIndex = 0;
|
|
24313
|
+
this.blockById.clear();
|
|
24314
|
+
this.toolBlockMap.clear();
|
|
24315
|
+
this.assistantMessageTextThisTurn.clear();
|
|
24316
|
+
this.session.status = "active";
|
|
24317
|
+
this.emitSessionUpdate(capturedAt);
|
|
24318
|
+
const turn = {
|
|
24319
|
+
id: turnId || `history-turn-${this.turnCounter}`,
|
|
24320
|
+
sessionId: this.session.id,
|
|
24321
|
+
status: "started",
|
|
24322
|
+
startedAt: new Date(capturedAt).toISOString(),
|
|
24323
|
+
blocks: []
|
|
24324
|
+
};
|
|
24325
|
+
this.currentTurn = turn;
|
|
24326
|
+
this.emitEvent(capturedAt, {
|
|
24327
|
+
event: "turn:start",
|
|
24328
|
+
sessionId: this.session.id,
|
|
24329
|
+
turn
|
|
24330
|
+
});
|
|
24331
|
+
return turn;
|
|
24332
|
+
}
|
|
24333
|
+
ensureTurn(capturedAt) {
|
|
24334
|
+
return this.currentTurn ?? this.startTurn(capturedAt);
|
|
24335
|
+
}
|
|
24336
|
+
endTurn(status, capturedAt) {
|
|
24337
|
+
const turn = this.currentTurn;
|
|
24338
|
+
if (!turn) {
|
|
24339
|
+
return;
|
|
24340
|
+
}
|
|
24341
|
+
turn.status = status;
|
|
24342
|
+
turn.endedAt = new Date(capturedAt).toISOString();
|
|
24343
|
+
this.emitEvent(capturedAt, {
|
|
24344
|
+
event: "turn:end",
|
|
24345
|
+
sessionId: this.session.id,
|
|
24346
|
+
turnId: turn.id,
|
|
24347
|
+
status
|
|
24348
|
+
});
|
|
24349
|
+
this.currentTurn = null;
|
|
24350
|
+
this.blockById.clear();
|
|
24351
|
+
this.toolBlockMap.clear();
|
|
24352
|
+
this.assistantMessageTextThisTurn.clear();
|
|
24353
|
+
this.session.status = "idle";
|
|
24354
|
+
this.emitSessionUpdate(capturedAt);
|
|
24355
|
+
}
|
|
24356
|
+
appendCompletedText(capturedAt, text) {
|
|
24357
|
+
const turn = this.ensureTurn(capturedAt);
|
|
24358
|
+
const block = this.startBlock(turn, capturedAt, {
|
|
24359
|
+
type: "text",
|
|
24360
|
+
text,
|
|
24361
|
+
status: "completed"
|
|
24362
|
+
});
|
|
24363
|
+
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
24364
|
+
}
|
|
24365
|
+
startBlock(turn, capturedAt, partial2) {
|
|
24366
|
+
const block = {
|
|
24367
|
+
...partial2,
|
|
24368
|
+
id: partial2.id || `${turn.id}:block:${this.blockIndex}`,
|
|
24369
|
+
turnId: turn.id,
|
|
24370
|
+
index: this.blockIndex
|
|
24371
|
+
};
|
|
24372
|
+
this.blockIndex += 1;
|
|
24373
|
+
turn.blocks.push(block);
|
|
24374
|
+
this.blockById.set(block.id, block);
|
|
24375
|
+
this.emitEvent(capturedAt, {
|
|
24376
|
+
event: "block:start",
|
|
24377
|
+
sessionId: this.session.id,
|
|
24378
|
+
turnId: turn.id,
|
|
24379
|
+
block
|
|
24380
|
+
});
|
|
24381
|
+
return block;
|
|
24382
|
+
}
|
|
24383
|
+
emitBlockEnd(capturedAt, turn, block, status) {
|
|
24384
|
+
block.status = status;
|
|
24385
|
+
this.emitEvent(capturedAt, {
|
|
24386
|
+
event: "block:end",
|
|
24387
|
+
sessionId: this.session.id,
|
|
24388
|
+
turnId: turn.id,
|
|
24389
|
+
blockId: block.id,
|
|
24390
|
+
status
|
|
24391
|
+
});
|
|
24392
|
+
}
|
|
24393
|
+
ensureProviderMeta() {
|
|
24394
|
+
const providerMeta = isRecord(this.session.providerMeta) ? this.session.providerMeta : {};
|
|
24395
|
+
this.session.providerMeta = providerMeta;
|
|
24396
|
+
return providerMeta;
|
|
24397
|
+
}
|
|
24398
|
+
ensureObserveMetaRecord(key) {
|
|
24399
|
+
const providerMeta = this.ensureProviderMeta();
|
|
24400
|
+
const existing = providerMeta[key];
|
|
24401
|
+
if (isRecord(existing)) {
|
|
24402
|
+
return existing;
|
|
24403
|
+
}
|
|
24404
|
+
const next = {};
|
|
24405
|
+
providerMeta[key] = next;
|
|
24406
|
+
return next;
|
|
24407
|
+
}
|
|
24408
|
+
assignObserveString(target, key, value) {
|
|
24409
|
+
const next = maybeString(value);
|
|
24410
|
+
if (!next || target[key] === next) {
|
|
24411
|
+
return false;
|
|
24412
|
+
}
|
|
24413
|
+
target[key] = next;
|
|
24414
|
+
return true;
|
|
24415
|
+
}
|
|
24416
|
+
emitSessionUpdate(capturedAt) {
|
|
24417
|
+
this.emitEvent(capturedAt, {
|
|
24418
|
+
event: "session:update",
|
|
24419
|
+
session: { ...this.session }
|
|
24420
|
+
});
|
|
24421
|
+
}
|
|
24422
|
+
emitEvent(capturedAt, event) {
|
|
24423
|
+
this.events.push({
|
|
24424
|
+
capturedAt,
|
|
24425
|
+
event: structuredClone(event)
|
|
24426
|
+
});
|
|
24427
|
+
}
|
|
24428
|
+
}
|
|
23712
24429
|
// packages/agent-sessions/src/adapters/claude-code.ts
|
|
23713
24430
|
import { existsSync as existsSync8, readdirSync as readdirSync5, statSync as statSync5 } from "fs";
|
|
23714
24431
|
import { homedir as homedir8 } from "os";
|
|
@@ -24316,7 +25033,7 @@ import { homedir as homedir10 } from "os";
|
|
|
24316
25033
|
// packages/agent-sessions/src/codex-launch-config.ts
|
|
24317
25034
|
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync9 } from "fs";
|
|
24318
25035
|
import { homedir as homedir9 } from "os";
|
|
24319
|
-
import { basename as
|
|
25036
|
+
import { basename as basename7, delimiter as delimiter2, dirname as dirname5, join as join10, resolve as resolve3 } from "path";
|
|
24320
25037
|
import { fileURLToPath } from "url";
|
|
24321
25038
|
function isExecutable(filePath) {
|
|
24322
25039
|
if (!filePath) {
|
|
@@ -24337,7 +25054,7 @@ function ancestorChain(start) {
|
|
|
24337
25054
|
let current = resolve3(start);
|
|
24338
25055
|
while (true) {
|
|
24339
25056
|
chain.push(current);
|
|
24340
|
-
const parent =
|
|
25057
|
+
const parent = dirname5(current);
|
|
24341
25058
|
if (parent === current) {
|
|
24342
25059
|
return chain;
|
|
24343
25060
|
}
|
|
@@ -24373,7 +25090,7 @@ function resolveBunExecutable2(env) {
|
|
|
24373
25090
|
return candidate;
|
|
24374
25091
|
}
|
|
24375
25092
|
}
|
|
24376
|
-
if (
|
|
25093
|
+
if (basename7(process.execPath).startsWith("bun") && isExecutable(process.execPath)) {
|
|
24377
25094
|
return process.execPath;
|
|
24378
25095
|
}
|
|
24379
25096
|
return resolveExecutableFromSearchPath(["bun"], env);
|
|
@@ -24393,7 +25110,7 @@ function resolveScoutExecutable(env) {
|
|
|
24393
25110
|
return resolveExecutableFromSearchPath(["scout"], env);
|
|
24394
25111
|
}
|
|
24395
25112
|
function resolveRepoScoutScript(currentDirectory) {
|
|
24396
|
-
const moduleDirectory =
|
|
25113
|
+
const moduleDirectory = dirname5(fileURLToPath(import.meta.url));
|
|
24397
25114
|
const starts = uniquePaths([currentDirectory, moduleDirectory]);
|
|
24398
25115
|
for (const start of starts) {
|
|
24399
25116
|
for (const candidate of ancestorChain(start)) {
|
|
@@ -24681,7 +25398,7 @@ function stringifyValue2(value) {
|
|
|
24681
25398
|
return String(value);
|
|
24682
25399
|
}
|
|
24683
25400
|
}
|
|
24684
|
-
function
|
|
25401
|
+
function extractReasoningText2(item) {
|
|
24685
25402
|
const summary = Array.isArray(item.summary) ? item.summary : [];
|
|
24686
25403
|
const content = Array.isArray(item.content) ? item.content : [];
|
|
24687
25404
|
const summaryText = summary.map((entry) => {
|
|
@@ -25153,7 +25870,7 @@ class CodexAdapter extends BaseAdapter {
|
|
|
25153
25870
|
this.ensureTextBlock(turnState, itemId, typeof item.text === "string" ? item.text : "");
|
|
25154
25871
|
return;
|
|
25155
25872
|
case "reasoning": {
|
|
25156
|
-
const text =
|
|
25873
|
+
const text = extractReasoningText2(item);
|
|
25157
25874
|
if (text) {
|
|
25158
25875
|
this.ensureReasoningBlock(turnState, itemId, text);
|
|
25159
25876
|
}
|
|
@@ -25232,7 +25949,7 @@ class CodexAdapter extends BaseAdapter {
|
|
|
25232
25949
|
return;
|
|
25233
25950
|
}
|
|
25234
25951
|
case "reasoning": {
|
|
25235
|
-
const finalText =
|
|
25952
|
+
const finalText = extractReasoningText2(item);
|
|
25236
25953
|
if (!finalText && !turnState.blocksByItemId.has(itemId)) {
|
|
25237
25954
|
return;
|
|
25238
25955
|
}
|
|
@@ -28038,7 +28755,7 @@ import { execFileSync as execFileSync2 } from "child_process";
|
|
|
28038
28755
|
import { existsSync as existsSync11, readFileSync as readFileSync4 } from "fs";
|
|
28039
28756
|
import { access, mkdir as mkdir6, readdir as readdir2, readFile as readFile8, realpath, rm as rm4, stat as stat3, writeFile as writeFile6 } from "fs/promises";
|
|
28040
28757
|
import { homedir as homedir12, hostname as hostname3, userInfo } from "os";
|
|
28041
|
-
import { basename as
|
|
28758
|
+
import { basename as basename8, dirname as dirname8, isAbsolute, join as join16, relative as relative3, resolve as resolve5 } from "path";
|
|
28042
28759
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
28043
28760
|
|
|
28044
28761
|
// node_modules/.bun/smol-toml@1.6.1/node_modules/smol-toml/dist/error.js
|
|
@@ -28990,7 +29707,7 @@ function parse5(toml, { maxDepth = 1000, integersAsBigInt } = {}) {
|
|
|
28990
29707
|
// packages/runtime/src/harness-catalog.ts
|
|
28991
29708
|
import { existsSync as existsSync10, statSync as statSync6 } from "fs";
|
|
28992
29709
|
import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
28993
|
-
import { dirname as
|
|
29710
|
+
import { dirname as dirname6, join as join14 } from "path";
|
|
28994
29711
|
var HARNESS_CATALOG_VERSION = 1;
|
|
28995
29712
|
var DEFAULT_SUPPORT = {
|
|
28996
29713
|
install: true,
|
|
@@ -29183,7 +29900,7 @@ var BUILT_IN_HARNESS_CATALOG = [
|
|
|
29183
29900
|
}
|
|
29184
29901
|
];
|
|
29185
29902
|
async function writeHarnessCatalogOverrides(overrides, overridePath = resolveOpenScoutSupportPaths().harnessCatalogPath) {
|
|
29186
|
-
await mkdir5(
|
|
29903
|
+
await mkdir5(dirname6(overridePath), { recursive: true });
|
|
29187
29904
|
const payload = {
|
|
29188
29905
|
version: HARNESS_CATALOG_VERSION,
|
|
29189
29906
|
entries: overrides,
|
|
@@ -29201,7 +29918,7 @@ async function ensureHarnessCatalogOverrideFile(overridePath = resolveOpenScoutS
|
|
|
29201
29918
|
// packages/runtime/src/user-project-hints.ts
|
|
29202
29919
|
import { readdir, readFile as readFile7, stat as stat2 } from "fs/promises";
|
|
29203
29920
|
import { homedir as homedir11 } from "os";
|
|
29204
|
-
import { dirname as
|
|
29921
|
+
import { dirname as dirname7, join as join15, resolve as resolve4 } from "path";
|
|
29205
29922
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
29206
29923
|
var PROJECT_HINT_MARKERS = [
|
|
29207
29924
|
".git",
|
|
@@ -29238,7 +29955,7 @@ async function resolveExistingDirectoryHint(pathLike) {
|
|
|
29238
29955
|
return absolutePath;
|
|
29239
29956
|
}
|
|
29240
29957
|
if (info.isFile()) {
|
|
29241
|
-
return
|
|
29958
|
+
return dirname7(absolutePath);
|
|
29242
29959
|
}
|
|
29243
29960
|
} catch {
|
|
29244
29961
|
return null;
|
|
@@ -29265,7 +29982,7 @@ async function findLikelyProjectRoot(absolutePath) {
|
|
|
29265
29982
|
}
|
|
29266
29983
|
}
|
|
29267
29984
|
}
|
|
29268
|
-
const parent =
|
|
29985
|
+
const parent = dirname7(current);
|
|
29269
29986
|
if (parent === current) {
|
|
29270
29987
|
return lastCandidate ?? absolutePath;
|
|
29271
29988
|
}
|
|
@@ -29406,7 +30123,7 @@ async function appendCursorWorkspacePaths(home, roots) {
|
|
|
29406
30123
|
}
|
|
29407
30124
|
const wsRaw = await readFile7(wsFile, "utf8");
|
|
29408
30125
|
const wsDoc = JSON.parse(wsRaw);
|
|
29409
|
-
const wsDir =
|
|
30126
|
+
const wsDir = dirname7(wsFile);
|
|
29410
30127
|
for (const f of wsDoc.folders ?? []) {
|
|
29411
30128
|
if (typeof f.path !== "string" || !f.path) {
|
|
29412
30129
|
continue;
|
|
@@ -30115,7 +30832,7 @@ async function readJsonFile(filePath) {
|
|
|
30115
30832
|
}
|
|
30116
30833
|
}
|
|
30117
30834
|
async function writeJsonFile(filePath, value) {
|
|
30118
|
-
await mkdir6(
|
|
30835
|
+
await mkdir6(dirname8(filePath), { recursive: true });
|
|
30119
30836
|
await writeFile6(filePath, JSON.stringify(value, null, 2) + `
|
|
30120
30837
|
`, "utf8");
|
|
30121
30838
|
}
|
|
@@ -30360,7 +31077,7 @@ function applyImportedEnvironmentSeeds(config2, codexImport, projectRoot) {
|
|
|
30360
31077
|
...(config2.environment?.actions?.length ?? 0) === 0 && importedEnvironment.actions ? { actions: importedEnvironment.actions } : {}
|
|
30361
31078
|
};
|
|
30362
31079
|
}
|
|
30363
|
-
const defaultProjectName = titleCase2(
|
|
31080
|
+
const defaultProjectName = titleCase2(basename8(projectRoot));
|
|
30364
31081
|
if (codexImport?.name?.trim() && (!config2.project.name?.trim() || config2.project.name === defaultProjectName)) {
|
|
30365
31082
|
next.project = {
|
|
30366
31083
|
...config2.project,
|
|
@@ -30570,7 +31287,7 @@ async function seedWorkspaceRoots(options) {
|
|
|
30570
31287
|
const roots = new Set;
|
|
30571
31288
|
const currentProjectRoot = options.currentDirectory ? await findNearestProjectRoot(options.currentDirectory) : null;
|
|
30572
31289
|
if (currentProjectRoot) {
|
|
30573
|
-
roots.add(
|
|
31290
|
+
roots.add(dirname8(currentProjectRoot));
|
|
30574
31291
|
}
|
|
30575
31292
|
const legacyRoot = options.legacyRelayConfig?.projectRoot?.trim();
|
|
30576
31293
|
if (legacyRoot) {
|
|
@@ -30578,7 +31295,7 @@ async function seedWorkspaceRoots(options) {
|
|
|
30578
31295
|
}
|
|
30579
31296
|
for (const record2 of Object.values(options.legacyAgents ?? {})) {
|
|
30580
31297
|
if (record2.cwd?.trim()) {
|
|
30581
|
-
roots.add(
|
|
31298
|
+
roots.add(dirname8(normalizePath(record2.cwd)));
|
|
30582
31299
|
}
|
|
30583
31300
|
}
|
|
30584
31301
|
if (roots.size === 0) {
|
|
@@ -30599,7 +31316,7 @@ async function readOpenScoutSettings(options = {}) {
|
|
|
30599
31316
|
});
|
|
30600
31317
|
}
|
|
30601
31318
|
var SCOUT_SKILL_FILE_NAME = "SKILL.md";
|
|
30602
|
-
var SETUP_MODULE_DIRECTORY =
|
|
31319
|
+
var SETUP_MODULE_DIRECTORY = dirname8(fileURLToPath3(import.meta.url));
|
|
30603
31320
|
var SCOUT_SKILL_REPO_ROOT = resolve5(SETUP_MODULE_DIRECTORY, "..", "..", "..");
|
|
30604
31321
|
var SCOUT_SKILL_INSTALL_PATHS = {
|
|
30605
31322
|
claude: join16(homedir12(), ".claude", "skills", "scout", SCOUT_SKILL_FILE_NAME),
|
|
@@ -30693,7 +31410,7 @@ async function findNearestProjectRoot(startDirectory) {
|
|
|
30693
31410
|
if (await pathExists2(projectConfigPath(current)) || await pathExists2(join16(current, "package.json")) || await pathExists2(join16(current, "AGENTS.md")) || await pathExists2(join16(current, "CLAUDE.md"))) {
|
|
30694
31411
|
lastCandidate = current;
|
|
30695
31412
|
}
|
|
30696
|
-
const parent =
|
|
31413
|
+
const parent = dirname8(current);
|
|
30697
31414
|
if (parent === current) {
|
|
30698
31415
|
return lastCandidate;
|
|
30699
31416
|
}
|
|
@@ -30701,7 +31418,7 @@ async function findNearestProjectRoot(startDirectory) {
|
|
|
30701
31418
|
}
|
|
30702
31419
|
}
|
|
30703
31420
|
function defaultProjectConfig(projectRoot, settings, preferredHarness) {
|
|
30704
|
-
const projectName =
|
|
31421
|
+
const projectName = basename8(projectRoot);
|
|
30705
31422
|
const definitionId = normalizeAgentId(projectName);
|
|
30706
31423
|
const relativeRoot = relative3(projectRoot, projectRoot) || ".";
|
|
30707
31424
|
return {
|
|
@@ -30992,7 +31709,7 @@ function relayAgentOverrideFromResolvedConfig(config2) {
|
|
|
30992
31709
|
}
|
|
30993
31710
|
function projectDefaultDefinitionIds(config2) {
|
|
30994
31711
|
return new Set([
|
|
30995
|
-
|
|
31712
|
+
basename8(config2.projectRoot),
|
|
30996
31713
|
config2.projectName
|
|
30997
31714
|
].map((value) => normalizeAgentId(value)).filter(Boolean));
|
|
30998
31715
|
}
|
|
@@ -31033,8 +31750,8 @@ function selectorFromInput(value) {
|
|
|
31033
31750
|
}
|
|
31034
31751
|
async function resolveManifestBackedAgent(projectRoot, config2, settings, override) {
|
|
31035
31752
|
const resolvedProjectRoot = resolveProjectRootFromConfig(projectRoot, config2);
|
|
31036
|
-
const projectName = config2.project.name?.trim() || titleCase2(config2.project.id ||
|
|
31037
|
-
const fallbackDefinitionId = normalizeAgentId(config2.project.id ||
|
|
31753
|
+
const projectName = config2.project.name?.trim() || titleCase2(config2.project.id || basename8(resolvedProjectRoot));
|
|
31754
|
+
const fallbackDefinitionId = normalizeAgentId(config2.project.id || basename8(resolvedProjectRoot));
|
|
31038
31755
|
const definitionId = normalizeAgentId(config2.agent?.id || override?.definitionId || fallbackDefinitionId);
|
|
31039
31756
|
const detectedHarness = await detectPreferredHarness(resolvedProjectRoot, settings.agents.defaultHarness);
|
|
31040
31757
|
const runtimeDefaults = config2.agent?.runtime?.defaults;
|
|
@@ -31072,7 +31789,7 @@ async function resolveManifestBackedAgent(projectRoot, config2, settings, overri
|
|
|
31072
31789
|
return mergeResolvedAgentConfig(base, override, settings);
|
|
31073
31790
|
}
|
|
31074
31791
|
async function resolveInferredAgent(projectRoot, settings, override) {
|
|
31075
|
-
const projectName =
|
|
31792
|
+
const projectName = basename8(projectRoot);
|
|
31076
31793
|
const definitionId = normalizeAgentId(override?.definitionId?.trim() || projectName);
|
|
31077
31794
|
const detectedHarness = await detectPreferredHarness(projectRoot, settings.agents.defaultHarness);
|
|
31078
31795
|
const defaultHarness = normalizeManagedHarness(override?.defaultHarness ?? override?.runtime?.harness, normalizeManagedHarness(detectedHarness, "claude"));
|
|
@@ -31108,7 +31825,7 @@ async function resolveInferredAgent(projectRoot, settings, override) {
|
|
|
31108
31825
|
return mergeResolvedAgentConfig(base, override, settings);
|
|
31109
31826
|
}
|
|
31110
31827
|
async function buildProjectInventoryEntry(agent, sourceRoot) {
|
|
31111
|
-
const manifestRoot = agent.projectConfigPath ? normalizePath(join16(
|
|
31828
|
+
const manifestRoot = agent.projectConfigPath ? normalizePath(join16(dirname8(agent.projectConfigPath), "..")) : null;
|
|
31112
31829
|
const manifest = manifestRoot ? await readProjectConfig(manifestRoot) : null;
|
|
31113
31830
|
const markers = await detectHarnessMarkers(agent.projectRoot);
|
|
31114
31831
|
const harnesses = new Map;
|
|
@@ -31373,7 +32090,7 @@ async function ensureRelayAgentConfigured(value, options = {}) {
|
|
|
31373
32090
|
import { spawnSync } from "child_process";
|
|
31374
32091
|
import { chmodSync, existsSync as existsSync12, mkdirSync as mkdirSync2, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
31375
32092
|
import { homedir as homedir13 } from "os";
|
|
31376
|
-
import { dirname as
|
|
32093
|
+
import { dirname as dirname9, join as join17, resolve as resolve6 } from "path";
|
|
31377
32094
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
31378
32095
|
|
|
31379
32096
|
// packages/runtime/src/broker-api.ts
|
|
@@ -31624,7 +32341,7 @@ function runtimePackageDir() {
|
|
|
31624
32341
|
const fromGlobal = findGlobalRuntimeDir();
|
|
31625
32342
|
if (fromGlobal)
|
|
31626
32343
|
return fromGlobal;
|
|
31627
|
-
const moduleDir =
|
|
32344
|
+
const moduleDir = dirname9(fileURLToPath4(import.meta.url));
|
|
31628
32345
|
return resolve6(moduleDir, "..");
|
|
31629
32346
|
}
|
|
31630
32347
|
function isInstalledRuntimePackageDir(candidate) {
|
|
@@ -31658,7 +32375,7 @@ function findGlobalRuntimeDir() {
|
|
|
31658
32375
|
return null;
|
|
31659
32376
|
}
|
|
31660
32377
|
function findBundledRuntimeDir() {
|
|
31661
|
-
const moduleDir =
|
|
32378
|
+
const moduleDir = dirname9(fileURLToPath4(import.meta.url));
|
|
31662
32379
|
const candidate = resolve6(moduleDir, "..");
|
|
31663
32380
|
return isInstalledRuntimePackageDir(candidate) ? candidate : null;
|
|
31664
32381
|
}
|
|
@@ -31669,7 +32386,7 @@ function findWorkspaceRuntimeDir(startDir) {
|
|
|
31669
32386
|
if (existsSync12(join17(candidate, "package.json")) && existsSync12(join17(candidate, "src"))) {
|
|
31670
32387
|
return candidate;
|
|
31671
32388
|
}
|
|
31672
|
-
const parent =
|
|
32389
|
+
const parent = dirname9(current);
|
|
31673
32390
|
if (parent === current)
|
|
31674
32391
|
return null;
|
|
31675
32392
|
current = parent;
|
|
@@ -31868,7 +32585,7 @@ function xmlEscape(value) {
|
|
|
31868
32585
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31869
32586
|
}
|
|
31870
32587
|
function ensureParentDirectory(filePath) {
|
|
31871
|
-
mkdirSync2(
|
|
32588
|
+
mkdirSync2(dirname9(filePath), { recursive: true });
|
|
31872
32589
|
}
|
|
31873
32590
|
function ensureServiceDirectories(config2) {
|
|
31874
32591
|
ensureOpenScoutCleanSlateSync();
|
|
@@ -32242,7 +32959,7 @@ function compileCodexPermissionProfile(profileInput) {
|
|
|
32242
32959
|
// packages/runtime/src/user-config.ts
|
|
32243
32960
|
import { existsSync as existsSync13, readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
32244
32961
|
import { homedir as homedir14 } from "os";
|
|
32245
|
-
import { dirname as
|
|
32962
|
+
import { dirname as dirname10, join as join18 } from "path";
|
|
32246
32963
|
function userConfigPath() {
|
|
32247
32964
|
return join18(process.env.OPENSCOUT_HOME ?? join18(homedir14(), ".openscout"), "user.json");
|
|
32248
32965
|
}
|
|
@@ -32269,7 +32986,7 @@ function resolveOperatorHandle() {
|
|
|
32269
32986
|
}
|
|
32270
32987
|
|
|
32271
32988
|
// packages/runtime/src/local-agents.ts
|
|
32272
|
-
var MODULE_DIRECTORY =
|
|
32989
|
+
var MODULE_DIRECTORY = dirname11(fileURLToPath5(import.meta.url));
|
|
32273
32990
|
var OPENSCOUT_REPO_ROOT = resolve7(MODULE_DIRECTORY, "..", "..", "..");
|
|
32274
32991
|
var DEFAULT_LOCAL_AGENT_CAPABILITIES = ["chat", "invoke", "deliver"];
|
|
32275
32992
|
var DEFAULT_LOCAL_AGENT_HARNESS = "claude";
|
|
@@ -32285,13 +33002,13 @@ function resolveProjectsRoot(projectPath) {
|
|
|
32285
33002
|
try {
|
|
32286
33003
|
const supportPaths = resolveOpenScoutSupportPaths();
|
|
32287
33004
|
if (!existsSync14(supportPaths.settingsPath)) {
|
|
32288
|
-
return
|
|
33005
|
+
return dirname11(projectPath);
|
|
32289
33006
|
}
|
|
32290
33007
|
const raw = JSON.parse(readFileSync7(supportPaths.settingsPath, "utf8"));
|
|
32291
33008
|
const workspaceRoot = raw.discovery?.workspaceRoots?.find((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
32292
|
-
return workspaceRoot ? resolve7(workspaceRoot) :
|
|
33009
|
+
return workspaceRoot ? resolve7(workspaceRoot) : dirname11(projectPath);
|
|
32293
33010
|
} catch {
|
|
32294
|
-
return
|
|
33011
|
+
return dirname11(projectPath);
|
|
32295
33012
|
}
|
|
32296
33013
|
}
|
|
32297
33014
|
function resolveBrokerUrl() {
|
|
@@ -32729,6 +33446,7 @@ var DEFAULT_CLAUDE_SCOUT_ALLOWED_TOOLS = [
|
|
|
32729
33446
|
"mcp__scout__messages_inbox",
|
|
32730
33447
|
"mcp__scout__messages_channel",
|
|
32731
33448
|
"mcp__scout__broker_feed",
|
|
33449
|
+
"mcp__scout__tail_events",
|
|
32732
33450
|
"mcp__scout__agents_search",
|
|
32733
33451
|
"mcp__scout__agents_resolve",
|
|
32734
33452
|
"mcp__scout__messages_reply",
|
|
@@ -33091,7 +33809,7 @@ function normalizeLocalAgentCardLifecycle(value, now = Date.now()) {
|
|
|
33091
33809
|
function normalizeLocalAgentRecord(agentId, record2) {
|
|
33092
33810
|
const cwd = normalizeProjectPath2(record2.cwd || process.cwd());
|
|
33093
33811
|
const projectRoot = normalizeProjectPath2(record2.projectRoot || cwd);
|
|
33094
|
-
const project = record2.project?.trim() ||
|
|
33812
|
+
const project = record2.project?.trim() || basename10(projectRoot);
|
|
33095
33813
|
const definitionId = record2.definitionId?.trim() || agentId;
|
|
33096
33814
|
const defaultHarness = activeLocalHarness(record2);
|
|
33097
33815
|
const harnessProfiles = normalizeLocalHarnessProfiles(agentId, {
|
|
@@ -33161,7 +33879,7 @@ function localAgentRecordFromRelayAgentOverride(agentId, override) {
|
|
|
33161
33879
|
return normalizeLocalAgentRecord(agentId, {
|
|
33162
33880
|
definitionId: override.definitionId ?? agentId,
|
|
33163
33881
|
registrationSource: override.source,
|
|
33164
|
-
project: override.projectName ??
|
|
33882
|
+
project: override.projectName ?? basename10(override.projectRoot || override.runtime?.cwd || agentId),
|
|
33165
33883
|
projectRoot: override.projectRoot ?? override.runtime?.cwd,
|
|
33166
33884
|
tmuxSession: override.runtime?.sessionId ?? `relay-${agentId}`,
|
|
33167
33885
|
cwd: override.runtime?.cwd ?? override.projectRoot,
|
|
@@ -33215,6 +33933,13 @@ async function ensureLocalSessionEndpointOnline(endpoint) {
|
|
|
33215
33933
|
}
|
|
33216
33934
|
return {};
|
|
33217
33935
|
}
|
|
33936
|
+
function clearEndpointFailureMetadata(metadata) {
|
|
33937
|
+
const { lastError: _lastError, lastFailedAt: _lastFailedAt, ...baseMetadata } = metadata ?? {};
|
|
33938
|
+
return baseMetadata;
|
|
33939
|
+
}
|
|
33940
|
+
function endpointStateAfterSuccessfulSessionWarmup(state) {
|
|
33941
|
+
return state === "active" ? "active" : "idle";
|
|
33942
|
+
}
|
|
33218
33943
|
async function shutdownLocalSessionEndpoint(endpoint) {
|
|
33219
33944
|
if (endpoint.transport === "codex_app_server") {
|
|
33220
33945
|
await shutdownCodexAppServerAgent(buildCodexEndpointSessionOptions(endpoint));
|
|
@@ -33547,7 +34272,7 @@ function invocationSessionFreshness(invocation) {
|
|
|
33547
34272
|
case "existing":
|
|
33548
34273
|
return "continuing session";
|
|
33549
34274
|
case "any":
|
|
33550
|
-
return "
|
|
34275
|
+
return invocation.execution?.targetSessionId ? "continuing session" : "fresh session";
|
|
33551
34276
|
default:
|
|
33552
34277
|
return "session unspecified";
|
|
33553
34278
|
}
|
|
@@ -34016,7 +34741,7 @@ async function ensureLocalAgentOnline(agentName, record2) {
|
|
|
34016
34741
|
return normalizedRecord;
|
|
34017
34742
|
}
|
|
34018
34743
|
const projectPath = normalizedRecord.cwd;
|
|
34019
|
-
const projectName = normalizedRecord.project ||
|
|
34744
|
+
const projectName = normalizedRecord.project || basename10(projectPath);
|
|
34020
34745
|
const systemPromptTemplate = normalizedRecord.systemPrompt || buildLocalAgentSystemPromptTemplate();
|
|
34021
34746
|
const systemPrompt = renderLocalAgentSystemPromptTemplate(systemPromptTemplate, buildLocalAgentTemplateContext(agentName, projectName, projectPath), { transport: normalizedRecord.transport });
|
|
34022
34747
|
const agentRuntimeDir = relayAgentRuntimeDirectory(agentName);
|
|
@@ -34199,7 +34924,7 @@ async function startLocalAgent(input) {
|
|
|
34199
34924
|
}
|
|
34200
34925
|
if (!matchingOverride) {
|
|
34201
34926
|
const configDefinitionId = coldProjectConfig?.agent?.id?.trim() ? normalizeAgentSelectorSegment(coldProjectConfig.agent.id.trim()) : "";
|
|
34202
|
-
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(
|
|
34927
|
+
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename10(projectRoot)) || "agent";
|
|
34203
34928
|
const configDisplayName = coldProjectConfig?.agent?.displayName?.trim() || "";
|
|
34204
34929
|
const operatorAugmentDefaults = operatorAugmentDefaultsForDefinitionId(definitionId);
|
|
34205
34930
|
const effectiveDisplayName = input.displayName || operatorAugmentDefaults?.displayName || configDisplayName || titleCaseLocalAgentName(definitionId);
|
|
@@ -34220,7 +34945,7 @@ async function startLocalAgent(input) {
|
|
|
34220
34945
|
agentId: instance.id,
|
|
34221
34946
|
definitionId,
|
|
34222
34947
|
displayName: effectiveDisplayName,
|
|
34223
|
-
projectName:
|
|
34948
|
+
projectName: basename10(projectRoot),
|
|
34224
34949
|
projectRoot,
|
|
34225
34950
|
projectConfigPath: coldProjectConfigPath,
|
|
34226
34951
|
source: "manual",
|
|
@@ -34269,7 +34994,7 @@ async function startLocalAgent(input) {
|
|
|
34269
34994
|
agentId: instance.id,
|
|
34270
34995
|
definitionId: requestedDefinitionId,
|
|
34271
34996
|
displayName: input.displayName || operatorAugmentDefaults?.displayName || titleCaseLocalAgentName(requestedDefinitionId),
|
|
34272
|
-
projectName: matchingOverride.projectName ??
|
|
34997
|
+
projectName: matchingOverride.projectName ?? basename10(matchingProjectRoot),
|
|
34273
34998
|
projectRoot: matchingProjectRoot,
|
|
34274
34999
|
projectConfigPath: null,
|
|
34275
35000
|
source: "manual",
|
|
@@ -34625,7 +35350,7 @@ async function invokeLocalAgentEndpoint(endpoint, invocation) {
|
|
|
34625
35350
|
const requestedHarness = invocation.execution?.harness;
|
|
34626
35351
|
const record2 = existing ?? (projectRoot ? {
|
|
34627
35352
|
definitionId,
|
|
34628
|
-
project:
|
|
35353
|
+
project: basename10(projectRoot),
|
|
34629
35354
|
projectRoot,
|
|
34630
35355
|
tmuxSession: String(endpoint.metadata?.tmuxSession ?? `relay-${agentRuntimeId}`),
|
|
34631
35356
|
cwd: projectRoot,
|
|
@@ -34872,7 +35597,7 @@ function upsertScoutAgentCardFromInput(runtime, input) {
|
|
|
34872
35597
|
|
|
34873
35598
|
// packages/runtime/src/pairing-session-agents.ts
|
|
34874
35599
|
import { existsSync as existsSync15, readFileSync as readFileSync8 } from "fs";
|
|
34875
|
-
import { basename as
|
|
35600
|
+
import { basename as basename11, join as join20 } from "path";
|
|
34876
35601
|
import { homedir as homedir15 } from "os";
|
|
34877
35602
|
var DEFAULT_PAIRING_PORT = 7888;
|
|
34878
35603
|
var PAIRING_CONNECT_TIMEOUT_MS = 1500;
|
|
@@ -35059,7 +35784,7 @@ function shortPairingSessionId(sessionId) {
|
|
|
35059
35784
|
}
|
|
35060
35785
|
function pairingProjectLabel(session) {
|
|
35061
35786
|
const cwd = session.cwd?.trim();
|
|
35062
|
-
return cwd ?
|
|
35787
|
+
return cwd ? basename11(cwd) : null;
|
|
35063
35788
|
}
|
|
35064
35789
|
function pairingDisplayName(session, shortId) {
|
|
35065
35790
|
const explicit = session.name?.trim();
|
|
@@ -35440,7 +36165,7 @@ async function invokePairingSessionEndpoint(endpoint, invocation, options = {})
|
|
|
35440
36165
|
|
|
35441
36166
|
// packages/runtime/src/sqlite-store.ts
|
|
35442
36167
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
35443
|
-
import { dirname as
|
|
36168
|
+
import { dirname as dirname13 } from "path";
|
|
35444
36169
|
import { Database as Database2 } from "bun:sqlite";
|
|
35445
36170
|
|
|
35446
36171
|
// node_modules/.bun/drizzle-orm@0.45.2+e80f9ee8788b3855/node_modules/drizzle-orm/entity.js
|
|
@@ -40042,6 +40767,9 @@ function stampControlPlaneSchemaVersion(database) {
|
|
|
40042
40767
|
}
|
|
40043
40768
|
if (false) {}
|
|
40044
40769
|
|
|
40770
|
+
// packages/runtime/src/conversations/api.ts
|
|
40771
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
40772
|
+
|
|
40045
40773
|
// packages/runtime/src/conversations/legacy-ids.ts
|
|
40046
40774
|
function conversationIdForAgent(agentId) {
|
|
40047
40775
|
return buildDirectConversationId("operator", agentId);
|
|
@@ -40107,11 +40835,22 @@ class Conversations {
|
|
|
40107
40835
|
findById(id) {
|
|
40108
40836
|
return this.store.getConversation(id);
|
|
40109
40837
|
}
|
|
40110
|
-
findByNaturalKey(
|
|
40838
|
+
findByNaturalKey(key) {
|
|
40839
|
+
const normalizedKey = key.trim();
|
|
40840
|
+
if (!normalizedKey) {
|
|
40841
|
+
return null;
|
|
40842
|
+
}
|
|
40843
|
+
const rows = this.readDb.query("SELECT id FROM conversations ORDER BY created_at ASC").all();
|
|
40844
|
+
for (const row of rows) {
|
|
40845
|
+
const conversation = this.findById(row.id);
|
|
40846
|
+
if (conversation && channelNaturalKeyFromMetadata(conversation.metadata) === normalizedKey) {
|
|
40847
|
+
return conversation;
|
|
40848
|
+
}
|
|
40849
|
+
}
|
|
40111
40850
|
return null;
|
|
40112
40851
|
}
|
|
40113
40852
|
findByAgent(agentId) {
|
|
40114
|
-
return this.findById(conversationIdForAgent(agentId));
|
|
40853
|
+
return this.findById(conversationIdForAgent(agentId)) ?? this.findByNaturalKey(directChannelNaturalKey(["operator", agentId]));
|
|
40115
40854
|
}
|
|
40116
40855
|
findByParent(parentId) {
|
|
40117
40856
|
const rows = this.readDb.query("SELECT id FROM conversations WHERE parent_conversation_id = ?1 ORDER BY created_at ASC").all(parentId);
|
|
@@ -40155,7 +40894,7 @@ class Conversations {
|
|
|
40155
40894
|
return existing;
|
|
40156
40895
|
}
|
|
40157
40896
|
const conversation = {
|
|
40158
|
-
id:
|
|
40897
|
+
id: mintChannelId(randomUUID3),
|
|
40159
40898
|
kind: input.kind,
|
|
40160
40899
|
title: input.title,
|
|
40161
40900
|
visibility: input.visibility,
|
|
@@ -40164,7 +40903,10 @@ class Conversations {
|
|
|
40164
40903
|
participantIds: input.participantIds,
|
|
40165
40904
|
parentConversationId: input.parentConversationId,
|
|
40166
40905
|
topic: input.topic,
|
|
40167
|
-
metadata:
|
|
40906
|
+
metadata: {
|
|
40907
|
+
...input.metadata ?? {},
|
|
40908
|
+
naturalKey: input.naturalKey
|
|
40909
|
+
}
|
|
40168
40910
|
};
|
|
40169
40911
|
this.upsert(conversation);
|
|
40170
40912
|
return conversation;
|
|
@@ -40182,6 +40924,10 @@ class Conversations {
|
|
|
40182
40924
|
}
|
|
40183
40925
|
const parsedDirect = parseDirectConversationId(rawId);
|
|
40184
40926
|
if (parsedDirect) {
|
|
40927
|
+
const byNaturalKey = this.findByNaturalKey(directChannelNaturalKey([parsedDirect.operatorId, parsedDirect.agentId]));
|
|
40928
|
+
if (byNaturalKey) {
|
|
40929
|
+
return byNaturalKey;
|
|
40930
|
+
}
|
|
40185
40931
|
for (const candidate of directConversationIdCandidates(parsedDirect.agentId)) {
|
|
40186
40932
|
const hit = this.findById(candidate);
|
|
40187
40933
|
if (hit) {
|
|
@@ -40191,6 +40937,10 @@ class Conversations {
|
|
|
40191
40937
|
}
|
|
40192
40938
|
const legacyScoutAgentId = parseLegacyScoutSessionConversationId(rawId);
|
|
40193
40939
|
if (legacyScoutAgentId) {
|
|
40940
|
+
const byNaturalKey = this.findByNaturalKey(directChannelNaturalKey(["operator", legacyScoutAgentId]));
|
|
40941
|
+
if (byNaturalKey) {
|
|
40942
|
+
return byNaturalKey;
|
|
40943
|
+
}
|
|
40194
40944
|
for (const candidate of directConversationIdCandidates(legacyScoutAgentId)) {
|
|
40195
40945
|
const hit = this.findById(candidate);
|
|
40196
40946
|
if (hit) {
|
|
@@ -40415,7 +41165,7 @@ class SQLiteControlPlaneStore {
|
|
|
40415
41165
|
flushPendingEventsTimer = null;
|
|
40416
41166
|
conversationsApi = null;
|
|
40417
41167
|
constructor(dbPath) {
|
|
40418
|
-
mkdirSync5(
|
|
41168
|
+
mkdirSync5(dirname13(dbPath), { recursive: true });
|
|
40419
41169
|
this.db = new SQLiteDatabase(dbPath, { create: true });
|
|
40420
41170
|
this.db.exec("PRAGMA busy_timeout = 5000;");
|
|
40421
41171
|
this.db.exec("PRAGMA journal_mode = WAL;");
|
|
@@ -41658,7 +42408,7 @@ class SQLiteControlPlaneStore {
|
|
|
41658
42408
|
if (message.replyToMessageId && this.isKnownAgentId(message.actorId)) {
|
|
41659
42409
|
return "ask_replied";
|
|
41660
42410
|
}
|
|
41661
|
-
if (agentId && message.actorId !== agentId) {
|
|
42411
|
+
if (agentId && message.actorId !== agentId && this.isDirectConversation(message.conversationId)) {
|
|
41662
42412
|
return "ask_opened";
|
|
41663
42413
|
}
|
|
41664
42414
|
if (this.isKnownAgentId(message.actorId)) {
|
|
@@ -41666,6 +42416,13 @@ class SQLiteControlPlaneStore {
|
|
|
41666
42416
|
}
|
|
41667
42417
|
return "message_posted";
|
|
41668
42418
|
}
|
|
42419
|
+
isDirectConversation(conversationId, db = this.readDb) {
|
|
42420
|
+
if (!conversationId) {
|
|
42421
|
+
return false;
|
|
42422
|
+
}
|
|
42423
|
+
const row = queryGet(db, "SELECT kind FROM conversations WHERE id = ?1 LIMIT 1", conversationId);
|
|
42424
|
+
return row?.kind === "direct";
|
|
42425
|
+
}
|
|
41669
42426
|
resolveActivityAgentIdForMessage(message) {
|
|
41670
42427
|
if (message.class === "status" && typeof message.metadata?.targetAgentId === "string" && this.isKnownAgentId(message.metadata.targetAgentId)) {
|
|
41671
42428
|
return message.metadata.targetAgentId;
|
|
@@ -43516,7 +44273,7 @@ import {
|
|
|
43516
44273
|
writeFileSync as writeFileSync4
|
|
43517
44274
|
} from "fs";
|
|
43518
44275
|
import { homedir as homedir16, hostname as osHostname } from "os";
|
|
43519
|
-
import { dirname as
|
|
44276
|
+
import { dirname as dirname14, join as join22 } from "path";
|
|
43520
44277
|
var LOCAL_CONFIG_VERSION = 1;
|
|
43521
44278
|
var DEFAULT_LOCAL_CONFIG = {
|
|
43522
44279
|
version: LOCAL_CONFIG_VERSION,
|
|
@@ -43771,7 +44528,7 @@ import { Database as Database3 } from "bun:sqlite";
|
|
|
43771
44528
|
import { mkdirSync as mkdirSync7, readFileSync as readFileSync11 } from "fs";
|
|
43772
44529
|
import { connect as connectHttp2 } from "http2";
|
|
43773
44530
|
import { createPrivateKey, sign as signWithKey } from "crypto";
|
|
43774
|
-
import { dirname as
|
|
44531
|
+
import { dirname as dirname15, join as join24 } from "path";
|
|
43775
44532
|
var MOBILE_PUSH_SCHEMA = `
|
|
43776
44533
|
CREATE TABLE IF NOT EXISTS mobile_push_registrations (
|
|
43777
44534
|
id TEXT PRIMARY KEY,
|
|
@@ -43813,7 +44570,7 @@ function writeDb() {
|
|
|
43813
44570
|
dbHandle = null;
|
|
43814
44571
|
}
|
|
43815
44572
|
if (!dbHandle) {
|
|
43816
|
-
mkdirSync7(
|
|
44573
|
+
mkdirSync7(dirname15(nextPath), { recursive: true });
|
|
43817
44574
|
dbHandle = new Database3(nextPath, { create: true });
|
|
43818
44575
|
dbPath = nextPath;
|
|
43819
44576
|
ensureMobilePushSchema(dbHandle);
|
|
@@ -44254,6 +45011,11 @@ var tailnetName = process.env.TAILSCALE_TAILNET ?? undefined;
|
|
|
44254
45011
|
var brokerUrl = process.env.OPENSCOUT_BROKER_URL ?? buildDefaultBrokerUrl(host, port);
|
|
44255
45012
|
var brokerSocketPath = process.env.OPENSCOUT_BROKER_SOCKET_PATH ?? resolveBrokerServiceConfig().brokerSocketPath;
|
|
44256
45013
|
var nodeId = process.env.OPENSCOUT_NODE_ID ?? `${nodeName}-${meshId}`.toLowerCase().replace(/[^a-z0-9-]+/g, "-");
|
|
45014
|
+
var nodeLocalProductAgentIds = new Set([
|
|
45015
|
+
SCOUT_DISPATCHER_AGENT_ID,
|
|
45016
|
+
OPENSCOUT_COORDINATOR_AGENT_ID,
|
|
45017
|
+
"scoutbot"
|
|
45018
|
+
]);
|
|
44257
45019
|
var seedUrls = (process.env.OPENSCOUT_MESH_SEEDS ?? "").split(",").map((value) => value.trim()).filter(Boolean);
|
|
44258
45020
|
var configuredCoreAgentIds = (process.env.OPENSCOUT_CORE_AGENTS ?? "").split(",").map((value) => value.trim().toLowerCase()).filter(Boolean);
|
|
44259
45021
|
var discoveryIntervalMs = Number.parseInt(process.env.OPENSCOUT_MESH_DISCOVERY_INTERVAL_MS ?? "60000", 10);
|
|
@@ -44288,8 +45050,6 @@ var shuttingDown = false;
|
|
|
44288
45050
|
var sseKeepAliveIntervalMs = Number.parseInt(process.env.OPENSCOUT_SSE_KEEPALIVE_MS ?? "15000", 10);
|
|
44289
45051
|
var operatorActorId = "operator";
|
|
44290
45052
|
var BROKER_SHARED_CHANNEL_ID = "channel.shared";
|
|
44291
|
-
var BROKER_VOICE_CHANNEL_ID = "channel.voice";
|
|
44292
|
-
var BROKER_SYSTEM_CHANNEL_ID = "channel.system";
|
|
44293
45053
|
var WEB_START_POLL_TIMEOUT_MS = 15000;
|
|
44294
45054
|
var WEB_START_POLL_INTERVAL_MS = 250;
|
|
44295
45055
|
var webServerProcess = null;
|
|
@@ -44551,6 +45311,11 @@ async function discoverPeers(seeds = []) {
|
|
|
44551
45311
|
continue;
|
|
44552
45312
|
if (agent.homeNodeId === nodeId)
|
|
44553
45313
|
continue;
|
|
45314
|
+
if (isNodeLocalProductAgentId(agent.id))
|
|
45315
|
+
continue;
|
|
45316
|
+
const existingAgent = runtime.agent(agent.id);
|
|
45317
|
+
if (existingAgent && isLocalAgentAuthority(existingAgent))
|
|
45318
|
+
continue;
|
|
44554
45319
|
const agentHome = agent.homeNodeId || node.id;
|
|
44555
45320
|
if (agentHome !== node.id)
|
|
44556
45321
|
continue;
|
|
@@ -44572,6 +45337,12 @@ async function discoverPeers(seeds = []) {
|
|
|
44572
45337
|
probes: result.probes
|
|
44573
45338
|
};
|
|
44574
45339
|
}
|
|
45340
|
+
function isNodeLocalProductAgentId(agentId) {
|
|
45341
|
+
return nodeLocalProductAgentIds.has(agentId.trim().toLowerCase());
|
|
45342
|
+
}
|
|
45343
|
+
function isLocalAgentAuthority(agent) {
|
|
45344
|
+
return agent.homeNodeId === nodeId || agent.authorityNodeId === nodeId;
|
|
45345
|
+
}
|
|
44575
45346
|
function currentLocalNode() {
|
|
44576
45347
|
return runtime.node(nodeId) ?? localNode;
|
|
44577
45348
|
}
|
|
@@ -44671,7 +45442,7 @@ function resolveWebServerEntry() {
|
|
|
44671
45442
|
if (repoEntry) {
|
|
44672
45443
|
return repoEntry;
|
|
44673
45444
|
}
|
|
44674
|
-
const moduleDir =
|
|
45445
|
+
const moduleDir = dirname16(fileURLToPath7(import.meta.url));
|
|
44675
45446
|
const candidates = [
|
|
44676
45447
|
resolve8(moduleDir, "..", "scout-control-plane-web.mjs"),
|
|
44677
45448
|
resolve8(moduleDir, "..", "scout-web-server.mjs"),
|
|
@@ -44681,7 +45452,7 @@ function resolveWebServerEntry() {
|
|
|
44681
45452
|
return candidates.find((candidate) => existsSync19(candidate)) ?? null;
|
|
44682
45453
|
}
|
|
44683
45454
|
function resolveWebServerRepoRoot() {
|
|
44684
|
-
const moduleDir =
|
|
45455
|
+
const moduleDir = dirname16(fileURLToPath7(import.meta.url));
|
|
44685
45456
|
return resolveOpenScoutRepoRoot({
|
|
44686
45457
|
startDirectories: [
|
|
44687
45458
|
process.env.OPENSCOUT_SETUP_CWD,
|
|
@@ -45545,6 +46316,23 @@ function staleLocalEndpointReason(endpoint) {
|
|
|
45545
46316
|
const replacement = typeof replacementAgentId === "string" && replacementAgentId.trim().length > 0 ? `; replacement agent is ${replacementAgentId.trim()}` : "";
|
|
45546
46317
|
return `endpoint ${endpoint.id} is a stale local registration superseded by current setup${replacement}`;
|
|
45547
46318
|
}
|
|
46319
|
+
function staleLocalAgentReason(snapshot, agent) {
|
|
46320
|
+
const endpoints = Object.values(snapshot.endpoints).filter((endpoint) => endpoint.agentId === agent.id);
|
|
46321
|
+
const staleEndpointReasons = endpoints.map((endpoint) => staleLocalEndpointReason(endpoint)).filter((reason) => Boolean(reason));
|
|
46322
|
+
if (endpoints.length > 0 && staleEndpointReasons.length === endpoints.length) {
|
|
46323
|
+
return staleLocalEndpointReason(latestEndpointForAgent(snapshot, agent.id)) ?? staleEndpointReasons[0] ?? null;
|
|
46324
|
+
}
|
|
46325
|
+
if (agent.metadata?.staleLocalRegistration !== true) {
|
|
46326
|
+
return null;
|
|
46327
|
+
}
|
|
46328
|
+
const endpointReason = staleLocalEndpointReason(latestEndpointForAgent(snapshot, agent.id));
|
|
46329
|
+
if (endpointReason) {
|
|
46330
|
+
return endpointReason;
|
|
46331
|
+
}
|
|
46332
|
+
const replacementAgentId = metadataStringValue2(agent.metadata, "replacedByAgentId");
|
|
46333
|
+
const replacement = replacementAgentId ? `; replacement agent is ${replacementAgentId}` : "";
|
|
46334
|
+
return `agent ${agent.id} is a stale local registration superseded by current setup${replacement}`;
|
|
46335
|
+
}
|
|
45548
46336
|
function flightDispatchEndpointId(flight) {
|
|
45549
46337
|
const dispatchAck = flight.metadata?.dispatchAck;
|
|
45550
46338
|
if (!dispatchAck || typeof dispatchAck !== "object" || Array.isArray(dispatchAck)) {
|
|
@@ -45633,14 +46421,14 @@ function brokerConversationChannel(snapshot, conversationId) {
|
|
|
45633
46421
|
if (!conversation) {
|
|
45634
46422
|
return null;
|
|
45635
46423
|
}
|
|
46424
|
+
if (typeof conversation.metadata?.channel === "string") {
|
|
46425
|
+
return conversation.metadata.channel;
|
|
46426
|
+
}
|
|
45636
46427
|
return conversation.id.startsWith("channel.") ? conversation.id.replace(/^channel\./, "") : null;
|
|
45637
46428
|
}
|
|
45638
46429
|
function titleCaseName(value) {
|
|
45639
46430
|
return value.split(/[-_.\s]+/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
|
|
45640
46431
|
}
|
|
45641
|
-
function sanitizeConversationSegment(value) {
|
|
45642
|
-
return value.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-") || "shared";
|
|
45643
|
-
}
|
|
45644
46432
|
function metadataStringValue2(metadata, key) {
|
|
45645
46433
|
const value = metadata?.[key];
|
|
45646
46434
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
@@ -45674,7 +46462,7 @@ function brokerRouteKind(conversation) {
|
|
|
45674
46462
|
if (conversation.kind === "direct") {
|
|
45675
46463
|
return "dm";
|
|
45676
46464
|
}
|
|
45677
|
-
return conversation.id === BROKER_SHARED_CHANNEL_ID ? "broadcast" : "channel";
|
|
46465
|
+
return conversation.id === BROKER_SHARED_CHANNEL_ID || conversation.metadata?.channel === "shared" ? "broadcast" : "channel";
|
|
45678
46466
|
}
|
|
45679
46467
|
function normalizeBrokerProductTarget(value) {
|
|
45680
46468
|
return value.trim().toLowerCase().replace(/^@+/, "");
|
|
@@ -45733,15 +46521,8 @@ function resolveConversationShareMode(snapshot, participantIds, fallback) {
|
|
|
45733
46521
|
});
|
|
45734
46522
|
return hasRemoteParticipant ? "shared" : fallback;
|
|
45735
46523
|
}
|
|
45736
|
-
function
|
|
45737
|
-
|
|
45738
|
-
return `dm.${sourceId}.${targetId}`;
|
|
45739
|
-
}
|
|
45740
|
-
if (sourceId === operatorActorId || targetId === operatorActorId) {
|
|
45741
|
-
const peerId = sourceId === operatorActorId ? targetId : sourceId;
|
|
45742
|
-
return `dm.${operatorActorId}.${peerId}`;
|
|
45743
|
-
}
|
|
45744
|
-
return `dm.${[sourceId, targetId].sort().join(".")}`;
|
|
46524
|
+
function findConversationByIdentity(snapshot, naturalKey) {
|
|
46525
|
+
return Object.values(snapshot.conversations).find((conversation) => channelNaturalKeyFromMetadata(conversation.metadata) === naturalKey);
|
|
45745
46526
|
}
|
|
45746
46527
|
async function ensureBrokerActorForDelivery(actorId) {
|
|
45747
46528
|
const snapshot = runtime.snapshot();
|
|
@@ -45762,10 +46543,11 @@ async function ensureBrokerDeliveryConversation(input) {
|
|
|
45762
46543
|
const normalizedChannel = input.channel?.trim();
|
|
45763
46544
|
const targetAgentId = input.targetAgentId?.trim();
|
|
45764
46545
|
if (!normalizedChannel && targetAgentId) {
|
|
45765
|
-
const conversationId = targetAgentId === SCOUT_DISPATCHER_AGENT_ID && input.requesterId === operatorActorId ? BROKER_SHARED_CHANNEL_ID : directConversationIdForActors(input.requesterId, targetAgentId);
|
|
45766
46546
|
const participantIds = [...new Set([input.requesterId, targetAgentId])].sort();
|
|
45767
46547
|
const shareMode = resolveConversationShareMode(snapshot, participantIds, "local");
|
|
45768
|
-
const
|
|
46548
|
+
const naturalKey = directChannelNaturalKey(participantIds);
|
|
46549
|
+
const existing2 = findConversationByIdentity(snapshot, naturalKey);
|
|
46550
|
+
const conversationId = existing2?.id ?? mintChannelId(randomUUID4);
|
|
45769
46551
|
const alreadyMatches = existing2 && existing2.kind === "direct" && existing2.visibility === "private" && existing2.shareMode === shareMode && existing2.participantIds.join("\x00") === participantIds.join("\x00");
|
|
45770
46552
|
if (alreadyMatches) {
|
|
45771
46553
|
return existing2;
|
|
@@ -45782,6 +46564,7 @@ async function ensureBrokerDeliveryConversation(input) {
|
|
|
45782
46564
|
participantIds,
|
|
45783
46565
|
metadata: {
|
|
45784
46566
|
surface: "broker",
|
|
46567
|
+
naturalKey,
|
|
45785
46568
|
...targetAgentId === SCOUT_DISPATCHER_AGENT_ID && input.requesterId === operatorActorId ? { role: "partner" } : {}
|
|
45786
46569
|
}
|
|
45787
46570
|
};
|
|
@@ -45797,48 +46580,72 @@ async function ensureBrokerDeliveryConversation(input) {
|
|
|
45797
46580
|
])].sort();
|
|
45798
46581
|
let definition;
|
|
45799
46582
|
if (channel === "voice") {
|
|
46583
|
+
const naturalKey = namedChannelNaturalKey("voice");
|
|
46584
|
+
const existing2 = findConversationByIdentity(snapshot, naturalKey);
|
|
45800
46585
|
definition = {
|
|
45801
|
-
id:
|
|
46586
|
+
id: existing2?.id ?? mintChannelId(randomUUID4),
|
|
45802
46587
|
kind: "channel",
|
|
45803
46588
|
title: "voice",
|
|
45804
46589
|
visibility: "workspace",
|
|
45805
46590
|
shareMode: resolveConversationShareMode(snapshot, scopedParticipants, "local"),
|
|
45806
46591
|
authorityNodeId: nodeId,
|
|
45807
46592
|
participantIds: scopedParticipants,
|
|
45808
|
-
metadata: {
|
|
46593
|
+
metadata: {
|
|
46594
|
+
surface: "broker",
|
|
46595
|
+
channel: "voice",
|
|
46596
|
+
naturalKey
|
|
46597
|
+
}
|
|
45809
46598
|
};
|
|
45810
46599
|
} else if (channel === "system") {
|
|
46600
|
+
const naturalKey = systemChannelNaturalKey("system");
|
|
46601
|
+
const existing2 = findConversationByIdentity(snapshot, naturalKey);
|
|
45811
46602
|
definition = {
|
|
45812
|
-
id:
|
|
46603
|
+
id: existing2?.id ?? mintChannelId(randomUUID4),
|
|
45813
46604
|
kind: "system",
|
|
45814
46605
|
title: "system",
|
|
45815
46606
|
visibility: "system",
|
|
45816
46607
|
shareMode: "local",
|
|
45817
46608
|
authorityNodeId: nodeId,
|
|
45818
46609
|
participantIds: [operatorActorId, input.requesterId].sort(),
|
|
45819
|
-
metadata: {
|
|
46610
|
+
metadata: {
|
|
46611
|
+
surface: "broker",
|
|
46612
|
+
channel: "system",
|
|
46613
|
+
naturalKey
|
|
46614
|
+
}
|
|
45820
46615
|
};
|
|
45821
46616
|
} else if (channel === "shared") {
|
|
46617
|
+
const naturalKey = namedChannelNaturalKey("shared");
|
|
46618
|
+
const existing2 = findConversationByIdentity(snapshot, naturalKey);
|
|
45822
46619
|
definition = {
|
|
45823
|
-
id:
|
|
46620
|
+
id: existing2?.id ?? mintChannelId(randomUUID4),
|
|
45824
46621
|
kind: "channel",
|
|
45825
46622
|
title: "shared-channel",
|
|
45826
46623
|
visibility: "workspace",
|
|
45827
46624
|
shareMode: "shared",
|
|
45828
46625
|
authorityNodeId: nodeId,
|
|
45829
46626
|
participantIds: sharedParticipants,
|
|
45830
|
-
metadata: {
|
|
46627
|
+
metadata: {
|
|
46628
|
+
surface: "broker",
|
|
46629
|
+
channel: "shared",
|
|
46630
|
+
naturalKey
|
|
46631
|
+
}
|
|
45831
46632
|
};
|
|
45832
46633
|
} else {
|
|
46634
|
+
const naturalKey = namedChannelNaturalKey(channel);
|
|
46635
|
+
const existing2 = findConversationByIdentity(snapshot, naturalKey);
|
|
45833
46636
|
definition = {
|
|
45834
|
-
id:
|
|
46637
|
+
id: existing2?.id ?? mintChannelId(randomUUID4),
|
|
45835
46638
|
kind: "channel",
|
|
45836
46639
|
title: channel,
|
|
45837
46640
|
visibility: "workspace",
|
|
45838
46641
|
shareMode: resolveConversationShareMode(snapshot, scopedParticipants, "local"),
|
|
45839
46642
|
authorityNodeId: nodeId,
|
|
45840
46643
|
participantIds: scopedParticipants,
|
|
45841
|
-
metadata: {
|
|
46644
|
+
metadata: {
|
|
46645
|
+
surface: "broker",
|
|
46646
|
+
channel,
|
|
46647
|
+
naturalKey
|
|
46648
|
+
}
|
|
45842
46649
|
};
|
|
45843
46650
|
}
|
|
45844
46651
|
const existing = snapshot.conversations[definition.id];
|
|
@@ -45870,7 +46677,22 @@ function buildBrokerReturnAddressForActor(snapshot, actorId, options = {}) {
|
|
|
45870
46677
|
sessionId: options.sessionId ?? endpoint?.sessionId
|
|
45871
46678
|
});
|
|
45872
46679
|
}
|
|
45873
|
-
function describeUnavailableDeliveryTarget(snapshot, agent) {
|
|
46680
|
+
function describeUnavailableDeliveryTarget(snapshot, agent, targetSessionId) {
|
|
46681
|
+
const staleReason = targetSessionId ? staleLocalAgentReason(snapshot, agent) : agent.metadata?.staleLocalRegistration === true ? staleLocalAgentReason(snapshot, agent) : null;
|
|
46682
|
+
if (staleReason) {
|
|
46683
|
+
const endpoint2 = latestEndpointForAgent(snapshot, agent.id);
|
|
46684
|
+
const projectRoot2 = brokerTargetProjectRoot(agent, endpoint2);
|
|
46685
|
+
return {
|
|
46686
|
+
agentId: agent.id,
|
|
46687
|
+
displayName: agent.displayName ?? agent.id,
|
|
46688
|
+
reason: "stale_registration",
|
|
46689
|
+
detail: staleReason,
|
|
46690
|
+
wakePolicy: agent.wakePolicy,
|
|
46691
|
+
endpointState: endpoint2?.state === "active" || endpoint2?.state === "idle" || endpoint2?.state === "waiting" ? "online" : endpoint2?.state === "offline" ? "offline" : "unknown",
|
|
46692
|
+
transport: endpoint2?.transport ?? null,
|
|
46693
|
+
projectRoot: projectRoot2
|
|
46694
|
+
};
|
|
46695
|
+
}
|
|
45874
46696
|
const endpoint = homeEndpointForAgent(snapshot, agent.id);
|
|
45875
46697
|
const projectRoot = brokerTargetProjectRoot(agent, endpoint);
|
|
45876
46698
|
if (agent.metadata?.retiredFromFleet === true) {
|
|
@@ -46204,11 +47026,11 @@ function updateManagedSessionAgent(agent, input) {
|
|
|
46204
47026
|
};
|
|
46205
47027
|
}
|
|
46206
47028
|
function managedLocalSessionDefaultDisplayName(input) {
|
|
46207
|
-
const projectName =
|
|
47029
|
+
const projectName = basename12(input.projectRoot ?? input.cwd) || input.cwd;
|
|
46208
47030
|
return input.transport === "codex_app_server" ? `Codex (${projectName})` : `Claude (${projectName})`;
|
|
46209
47031
|
}
|
|
46210
47032
|
function suggestedManagedLocalSessionSelector(input) {
|
|
46211
|
-
const projectName = normalizeAgentSelectorSegment(
|
|
47033
|
+
const projectName = normalizeAgentSelectorSegment(basename12(input.projectRoot ?? input.cwd) || "session") || "session";
|
|
46212
47034
|
const prefix = input.transport === "codex_app_server" ? "codex" : "claude";
|
|
46213
47035
|
return `@${prefix}-${projectName}`;
|
|
46214
47036
|
}
|
|
@@ -46246,7 +47068,7 @@ function buildManagedLocalSessionAgent(input) {
|
|
|
46246
47068
|
function buildManagedLocalSessionPairingEndpointBinding(input) {
|
|
46247
47069
|
const projectRoot = resolve8(input.projectRoot ?? input.cwd);
|
|
46248
47070
|
const cwd = resolve8(input.cwd);
|
|
46249
|
-
const projectName =
|
|
47071
|
+
const projectName = basename12(projectRoot) || projectRoot;
|
|
46250
47072
|
const definitionId = input.definitionId?.trim() || selectorHandle(input.selector ?? input.agentId);
|
|
46251
47073
|
const base = buildManagedPairingEndpointBinding({
|
|
46252
47074
|
agentId: input.agentId,
|
|
@@ -47126,7 +47948,7 @@ async function reviveManagedLocalSessionEndpoint(endpoint) {
|
|
|
47126
47948
|
}
|
|
47127
47949
|
const sessionResult = await ensureLocalSessionEndpointOnline(endpoint);
|
|
47128
47950
|
const externalSessionId = sessionResult.externalSessionId?.trim();
|
|
47129
|
-
const
|
|
47951
|
+
const baseMetadata = clearEndpointFailureMetadata(endpoint.metadata);
|
|
47130
47952
|
const revivedEndpoint = {
|
|
47131
47953
|
...endpoint,
|
|
47132
47954
|
state: "idle",
|
|
@@ -47147,19 +47969,23 @@ async function resolveLocalEndpointForInvocation(invocation) {
|
|
|
47147
47969
|
const requestedHarness = invocation.execution?.harness;
|
|
47148
47970
|
const targetSessionId = invocationTargetSessionId(invocation);
|
|
47149
47971
|
const sessionPreference = invocation.execution?.session ?? "new";
|
|
47972
|
+
const shouldUseExistingSession = Boolean(targetSessionId);
|
|
47150
47973
|
const existing = activeLocalEndpointForAgent(invocation.targetAgentId, requestedHarness, targetSessionId);
|
|
47151
|
-
if (existing && (
|
|
47974
|
+
if (existing && (shouldUseExistingSession || existing.transport === "pairing_bridge")) {
|
|
47152
47975
|
return existing;
|
|
47153
47976
|
}
|
|
47154
|
-
|
|
47977
|
+
if (!shouldUseExistingSession && sessionPreference === "existing") {
|
|
47978
|
+
return;
|
|
47979
|
+
}
|
|
47980
|
+
const staleEndpoints = shouldUseExistingSession ? runtime.endpointsForAgent(invocation.targetAgentId, {
|
|
47155
47981
|
nodeId,
|
|
47156
47982
|
harness: requestedHarness
|
|
47157
|
-
}).filter((endpoint) => endpoint.id !== existing?.id &&
|
|
47983
|
+
}).filter((endpoint) => endpoint.id !== existing?.id && endpointMatchesTargetSession(endpoint, targetSessionId)) : [];
|
|
47158
47984
|
const staleLocalReason = staleEndpoints.map((endpoint) => staleLocalEndpointReason(endpoint)).find((reason) => Boolean(reason));
|
|
47159
47985
|
if (staleLocalReason) {
|
|
47160
47986
|
throw new Error(staleLocalReason);
|
|
47161
47987
|
}
|
|
47162
|
-
if (invocation.ensureAwake) {
|
|
47988
|
+
if (invocation.ensureAwake && shouldUseExistingSession) {
|
|
47163
47989
|
for (const endpoint of staleEndpoints) {
|
|
47164
47990
|
try {
|
|
47165
47991
|
const revived = await reviveManagedLocalSessionEndpoint(endpoint);
|
|
@@ -47192,9 +48018,6 @@ async function resolveLocalEndpointForInvocation(invocation) {
|
|
|
47192
48018
|
if (!invocation.ensureAwake) {
|
|
47193
48019
|
return;
|
|
47194
48020
|
}
|
|
47195
|
-
if (sessionPreference === "existing") {
|
|
47196
|
-
return;
|
|
47197
|
-
}
|
|
47198
48021
|
if (targetSessionId) {
|
|
47199
48022
|
return;
|
|
47200
48023
|
}
|
|
@@ -47236,7 +48059,8 @@ async function executeLocalInvocation(invocation, initialFlight) {
|
|
|
47236
48059
|
return;
|
|
47237
48060
|
}
|
|
47238
48061
|
if (!agent || !endpoint) {
|
|
47239
|
-
const
|
|
48062
|
+
const targetSessionId = invocationTargetSessionId(invocation);
|
|
48063
|
+
const staleEndpointReason = targetSessionId ? staleLocalEndpointReason(latestEndpointForAgent(runtime.snapshot(), invocation.targetAgentId)) : null;
|
|
47240
48064
|
if (staleEndpointReason) {
|
|
47241
48065
|
const failedFlight = {
|
|
47242
48066
|
...initialFlight,
|
|
@@ -47257,7 +48081,15 @@ async function executeLocalInvocation(invocation, initialFlight) {
|
|
|
47257
48081
|
const queuedFlight = {
|
|
47258
48082
|
...initialFlight,
|
|
47259
48083
|
state: "queued",
|
|
47260
|
-
summary: `Message stored for ${agent?.displayName ?? invocation.targetAgentId}. Will deliver when online
|
|
48084
|
+
summary: `Message stored for ${agent?.displayName ?? invocation.targetAgentId}. Will deliver when online.`,
|
|
48085
|
+
metadata: {
|
|
48086
|
+
...initialFlight.metadata ?? {},
|
|
48087
|
+
dispatchOutcome: {
|
|
48088
|
+
status: "queued_until_online",
|
|
48089
|
+
reason: "no_runnable_endpoint",
|
|
48090
|
+
checkedAt: Date.now()
|
|
48091
|
+
}
|
|
48092
|
+
}
|
|
47261
48093
|
};
|
|
47262
48094
|
await persistFlight(queuedFlight);
|
|
47263
48095
|
return;
|
|
@@ -47654,6 +48486,39 @@ function parseLimit(url2) {
|
|
|
47654
48486
|
return 100;
|
|
47655
48487
|
return Math.min(limit, 500);
|
|
47656
48488
|
}
|
|
48489
|
+
function parseTailLimit(url2) {
|
|
48490
|
+
const limit = Number.parseInt(url2.searchParams.get("limit") ?? "500", 10);
|
|
48491
|
+
if (!Number.isFinite(limit) || limit <= 0)
|
|
48492
|
+
return 500;
|
|
48493
|
+
return Math.min(limit, 1000);
|
|
48494
|
+
}
|
|
48495
|
+
async function readTailRecentPayload(url2) {
|
|
48496
|
+
const limit = parseTailLimit(url2);
|
|
48497
|
+
const bufferedEvents = await readRecentLiveEvents(limit);
|
|
48498
|
+
const eventsById = new Map;
|
|
48499
|
+
if (url2.searchParams.get("transcripts") === "true" || url2.searchParams.get("transcripts") === "1") {
|
|
48500
|
+
const transcriptEvents = await readRecentTranscriptEvents(limit, {
|
|
48501
|
+
perTranscriptLineLimit: Math.min(200, Math.max(50, limit))
|
|
48502
|
+
});
|
|
48503
|
+
for (const event of transcriptEvents) {
|
|
48504
|
+
eventsById.set(event.id, event);
|
|
48505
|
+
}
|
|
48506
|
+
}
|
|
48507
|
+
for (const event of bufferedEvents) {
|
|
48508
|
+
eventsById.set(event.id, event);
|
|
48509
|
+
}
|
|
48510
|
+
const events2 = [...eventsById.values()].sort((left, right) => {
|
|
48511
|
+
if (left.ts === right.ts)
|
|
48512
|
+
return left.id.localeCompare(right.id);
|
|
48513
|
+
return left.ts - right.ts;
|
|
48514
|
+
}).slice(-limit);
|
|
48515
|
+
return {
|
|
48516
|
+
generatedAt: Date.now(),
|
|
48517
|
+
limit,
|
|
48518
|
+
cursor: events2.at(-1)?.id ?? null,
|
|
48519
|
+
events: events2
|
|
48520
|
+
};
|
|
48521
|
+
}
|
|
47657
48522
|
function parseSince(url2) {
|
|
47658
48523
|
const since = Number.parseInt(url2.searchParams.get("since") ?? "", 10);
|
|
47659
48524
|
if (!Number.isFinite(since) || since <= 0) {
|
|
@@ -47683,7 +48548,7 @@ async function probeExistingBroker() {
|
|
|
47683
48548
|
}
|
|
47684
48549
|
}
|
|
47685
48550
|
async function prepareBrokerSocketPath(socketPath) {
|
|
47686
|
-
await mkdir8(
|
|
48551
|
+
await mkdir8(dirname16(socketPath), { recursive: true, mode: 448 });
|
|
47687
48552
|
try {
|
|
47688
48553
|
const existing = await lstat(socketPath);
|
|
47689
48554
|
if (!existing.isSocket()) {
|
|
@@ -48025,6 +48890,15 @@ async function routeRequest(request, response) {
|
|
|
48025
48890
|
json2(response, 200, await getHarnessTopologySnapshot(url2.searchParams.get("force") === "1"));
|
|
48026
48891
|
return;
|
|
48027
48892
|
}
|
|
48893
|
+
if (method === "GET" && url2.pathname === "/v1/tail/discover") {
|
|
48894
|
+
const force = url2.searchParams.get("force") === "1" || url2.searchParams.get("force") === "true";
|
|
48895
|
+
json2(response, 200, await getTailDiscovery(force));
|
|
48896
|
+
return;
|
|
48897
|
+
}
|
|
48898
|
+
if (method === "GET" && url2.pathname === "/v1/tail/recent") {
|
|
48899
|
+
json2(response, 200, await readTailRecentPayload(url2));
|
|
48900
|
+
return;
|
|
48901
|
+
}
|
|
48028
48902
|
if (method === "POST" && url2.pathname === "/v1/topology/nudge") {
|
|
48029
48903
|
json2(response, 200, await nudgeHarnessTopologyScan());
|
|
48030
48904
|
return;
|
|
@@ -48703,10 +49577,10 @@ data: ${JSON.stringify({ nodeId, meshId })}
|
|
|
48703
49577
|
const externalSessionId = sessionResult.externalSessionId?.trim();
|
|
48704
49578
|
const nextEndpoint = {
|
|
48705
49579
|
...endpoint,
|
|
48706
|
-
state: endpoint.state
|
|
49580
|
+
state: endpointStateAfterSuccessfulSessionWarmup(endpoint.state),
|
|
48707
49581
|
...externalSessionId ? { sessionId: externalSessionId } : {},
|
|
48708
49582
|
metadata: {
|
|
48709
|
-
...endpoint.metadata
|
|
49583
|
+
...clearEndpointFailureMetadata(endpoint.metadata),
|
|
48710
49584
|
...externalSessionId ? {
|
|
48711
49585
|
externalSessionId,
|
|
48712
49586
|
threadId: endpoint.transport === "codex_app_server" ? externalSessionId : endpoint.metadata?.threadId
|
|
@@ -49066,16 +49940,22 @@ function supportedRouteHarness(value) {
|
|
|
49066
49940
|
}
|
|
49067
49941
|
return;
|
|
49068
49942
|
}
|
|
49943
|
+
function supportedRouteModel(value) {
|
|
49944
|
+
const normalized = value?.trim();
|
|
49945
|
+
return normalized || undefined;
|
|
49946
|
+
}
|
|
49069
49947
|
function executionWithRouteParams(payload) {
|
|
49070
49948
|
const label = agentLabelForRouteParams(payload);
|
|
49071
49949
|
const identity2 = label ? parseAgentIdentity(label.startsWith("@") ? label : `@${label}`) : null;
|
|
49072
|
-
const harness = supportedRouteHarness(identity2?.harness);
|
|
49073
|
-
|
|
49950
|
+
const harness = payload.execution?.harness ? undefined : supportedRouteHarness(identity2?.harness);
|
|
49951
|
+
const model = payload.execution?.model ? undefined : supportedRouteModel(identity2?.model);
|
|
49952
|
+
if (!harness && !model) {
|
|
49074
49953
|
return payload.execution;
|
|
49075
49954
|
}
|
|
49076
49955
|
return {
|
|
49077
49956
|
...payload.execution ?? {},
|
|
49078
|
-
harness
|
|
49957
|
+
...harness ? { harness } : {},
|
|
49958
|
+
...model ? { model } : {}
|
|
49079
49959
|
};
|
|
49080
49960
|
}
|
|
49081
49961
|
function resolveBrokerDeliveryTarget(input) {
|
|
@@ -49088,43 +49968,82 @@ function projectPathRouteTarget(input) {
|
|
|
49088
49968
|
return input.target?.kind === "project_path" ? input.target.projectPath.trim() || undefined : undefined;
|
|
49089
49969
|
}
|
|
49090
49970
|
function implicitProjectAgentName(projectPath) {
|
|
49091
|
-
const base = normalizeAgentSelectorSegment(
|
|
49971
|
+
const base = normalizeAgentSelectorSegment(basename12(projectPath)) || "agent";
|
|
49092
49972
|
return `${base}-card-${createRuntimeId2("one").slice(-8)}`;
|
|
49093
49973
|
}
|
|
49094
|
-
|
|
49974
|
+
function projectAgentPersistence(spec) {
|
|
49975
|
+
return spec?.persistence === "sticky" ? "sticky" : "one_time";
|
|
49976
|
+
}
|
|
49977
|
+
function compactProjectAgentName(value) {
|
|
49978
|
+
const normalized = value?.trim();
|
|
49979
|
+
return normalized || undefined;
|
|
49980
|
+
}
|
|
49981
|
+
function shouldMaterializeProjectAgent(input) {
|
|
49982
|
+
if (!input.projectPath) {
|
|
49983
|
+
return false;
|
|
49984
|
+
}
|
|
49985
|
+
if (input.projectAgent?.persistence === "one_time") {
|
|
49986
|
+
return true;
|
|
49987
|
+
}
|
|
49988
|
+
if (input.projectAgent?.persistence === "sticky") {
|
|
49989
|
+
return input.resolved.kind !== "resolved" || Boolean(input.projectAgent.agentName?.trim()) || Boolean(input.projectAgent.displayName?.trim()) || Boolean(input.execution?.harness) || Boolean(input.execution?.model?.trim()) || Boolean(input.execution?.permissionProfile);
|
|
49990
|
+
}
|
|
49991
|
+
return input.resolved.kind === "unknown" || input.resolved.kind === "ambiguous" && (input.execution?.session ?? "new") === "new";
|
|
49992
|
+
}
|
|
49993
|
+
async function resolveBrokerDeliveryTargetWithImplicitProjectAgent(input, options) {
|
|
49095
49994
|
const resolved = resolveBrokerDeliveryTarget(input);
|
|
49096
49995
|
const projectPath = projectPathRouteTarget(input);
|
|
49097
|
-
const
|
|
49098
|
-
if (!
|
|
49996
|
+
const persistence = projectAgentPersistence(input.projectAgent);
|
|
49997
|
+
if (!shouldMaterializeProjectAgent({
|
|
49998
|
+
projectPath,
|
|
49999
|
+
resolved,
|
|
50000
|
+
persistence,
|
|
50001
|
+
projectAgent: input.projectAgent,
|
|
50002
|
+
execution: input.execution
|
|
50003
|
+
})) {
|
|
50004
|
+
return resolved;
|
|
50005
|
+
}
|
|
50006
|
+
if (!projectPath) {
|
|
49099
50007
|
return resolved;
|
|
49100
50008
|
}
|
|
49101
50009
|
const createdAt = Date.now();
|
|
49102
50010
|
const requesterId = options.requesterId?.trim();
|
|
50011
|
+
const agentName = persistence === "sticky" ? compactProjectAgentName(input.projectAgent?.agentName) : implicitProjectAgentName(projectPath);
|
|
50012
|
+
const displayName = compactProjectAgentName(input.projectAgent?.displayName);
|
|
49103
50013
|
const status = await startLocalAgent({
|
|
49104
50014
|
projectPath,
|
|
49105
|
-
agentName:
|
|
50015
|
+
...agentName ? { agentName } : {},
|
|
50016
|
+
...displayName ? { displayName } : {},
|
|
49106
50017
|
currentDirectory: options.currentDirectory ?? projectPath,
|
|
49107
50018
|
harness: input.execution?.harness,
|
|
50019
|
+
model: input.execution?.model,
|
|
50020
|
+
permissionProfile: input.execution?.permissionProfile,
|
|
49108
50021
|
ensureOnline: false,
|
|
49109
50022
|
card: {
|
|
49110
|
-
kind: "one_time",
|
|
50023
|
+
kind: persistence === "sticky" ? "persistent" : "one_time",
|
|
49111
50024
|
createdAt,
|
|
49112
50025
|
...requesterId ? { createdById: requesterId } : {},
|
|
49113
|
-
|
|
49114
|
-
|
|
50026
|
+
...persistence === "one_time" ? {
|
|
50027
|
+
expiresAt: createdAt + DEFAULT_IMPLICIT_PROJECT_CARD_TTL_MS,
|
|
50028
|
+
maxUses: 1
|
|
50029
|
+
} : {}
|
|
49115
50030
|
}
|
|
49116
50031
|
}).catch((error48) => {
|
|
49117
50032
|
const detail = error48 instanceof Error ? error48.message : String(error48);
|
|
49118
|
-
throw new Error(`could not create
|
|
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)}`);
|
|
50033
|
+
throw new Error(`could not create a ${persistence} agent for project ${projectPath}: ${detail}`);
|
|
49126
50034
|
});
|
|
49127
|
-
|
|
50035
|
+
if (persistence === "one_time") {
|
|
50036
|
+
await pruneOneTimeLocalAgentCards({
|
|
50037
|
+
...requesterId ? { createdById: requesterId } : {},
|
|
50038
|
+
projectRoot: status.projectRoot,
|
|
50039
|
+
excludeAgentIds: [status.agentId]
|
|
50040
|
+
}).catch((error48) => {
|
|
50041
|
+
console.warn(`[openscout-runtime] implicit project card cleanup failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
50042
|
+
});
|
|
50043
|
+
}
|
|
50044
|
+
clearGitBranchCache();
|
|
50045
|
+
console.log(`[openscout-runtime] local agent registry changed (${options.reason}); refreshing registered agents`);
|
|
50046
|
+
await syncRegisteredLocalAgents();
|
|
49128
50047
|
const agent = runtime.snapshot().agents[status.agentId];
|
|
49129
50048
|
if (agent && !isInactiveLocalAgent(agent)) {
|
|
49130
50049
|
return { kind: "resolved", agent };
|
|
@@ -49132,13 +50051,14 @@ async function resolveBrokerDeliveryTargetWithImplicitProjectCard(input, options
|
|
|
49132
50051
|
return resolveBrokerDeliveryTarget(input);
|
|
49133
50052
|
}
|
|
49134
50053
|
async function resolveInvocationTarget(payload) {
|
|
49135
|
-
return
|
|
50054
|
+
return resolveBrokerDeliveryTargetWithImplicitProjectAgent({
|
|
49136
50055
|
target: payload.target,
|
|
49137
50056
|
targetAgentId: payload.targetAgentId,
|
|
49138
50057
|
targetSessionId: payload.targetSessionId,
|
|
49139
50058
|
targetLabel: payload.targetLabel,
|
|
49140
50059
|
routePolicy: payload.routePolicy,
|
|
49141
|
-
execution: payload.execution
|
|
50060
|
+
execution: payload.execution,
|
|
50061
|
+
projectAgent: undefined
|
|
49142
50062
|
}, {
|
|
49143
50063
|
requesterId: payload.requesterId,
|
|
49144
50064
|
currentDirectory: projectPathRouteTarget(payload),
|
|
@@ -49156,7 +50076,7 @@ function remediationForDispatch(dispatch) {
|
|
|
49156
50076
|
}
|
|
49157
50077
|
if (dispatch.kind === "unavailable") {
|
|
49158
50078
|
return {
|
|
49159
|
-
kind: dispatch.target?.reason === "manual_wake_required" ? "wake_target" : "retry_later",
|
|
50079
|
+
kind: dispatch.target?.reason === "manual_wake_required" ? "wake_target" : dispatch.target?.reason === "stale_registration" ? "stale_reference" : "retry_later",
|
|
49160
50080
|
detail: dispatch.target?.detail ?? dispatch.detail,
|
|
49161
50081
|
targetAgentId: dispatch.target?.agentId,
|
|
49162
50082
|
targetLabel: dispatch.askedLabel,
|
|
@@ -49494,7 +50414,7 @@ async function acceptBrokerDelivery(payload) {
|
|
|
49494
50414
|
const askedLabel = askedLabelForRouteTarget(payload);
|
|
49495
50415
|
const execution = executionWithRouteParams(payload);
|
|
49496
50416
|
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;
|
|
50417
|
+
const targetSessionId = payload.target?.kind === "session_id" ? payload.target.sessionId.trim() : payload.targetSessionId?.trim() || payload.execution?.targetSessionId?.trim() || metadataStringValue2(payload.invocationMetadata, "targetSessionId") || metadataStringValue2(payload.messageMetadata, "targetSessionId") || undefined;
|
|
49498
50418
|
const replyToSessionId = payload.replyToSessionId?.trim() || metadataStringValue2(payload.invocationMetadata, "replyToSessionId") || metadataStringValue2(payload.messageMetadata, "replyToSessionId") || undefined;
|
|
49499
50419
|
const labels = normalizeScoutLabels(payload.labels);
|
|
49500
50420
|
const typedChannelTarget = payload.target?.kind === "channel" || payload.target?.kind === "broadcast";
|
|
@@ -49748,7 +50668,7 @@ async function acceptBrokerDelivery(payload) {
|
|
|
49748
50668
|
message: message2
|
|
49749
50669
|
};
|
|
49750
50670
|
}
|
|
49751
|
-
const resolved = await
|
|
50671
|
+
const resolved = await resolveBrokerDeliveryTargetWithImplicitProjectAgent({
|
|
49752
50672
|
...payload,
|
|
49753
50673
|
execution
|
|
49754
50674
|
}, {
|
|
@@ -49776,7 +50696,7 @@ async function acceptBrokerDelivery(payload) {
|
|
|
49776
50696
|
remediation: remediationForDispatch(record2)
|
|
49777
50697
|
};
|
|
49778
50698
|
}
|
|
49779
|
-
const unavailable = describeUnavailableDeliveryTarget(runtime.snapshot(), resolved.agent);
|
|
50699
|
+
const unavailable = describeUnavailableDeliveryTarget(runtime.snapshot(), resolved.agent, targetSessionId);
|
|
49780
50700
|
if (unavailable) {
|
|
49781
50701
|
const { record: record2 } = await recordScoutDispatchDurably(buildUnavailableDispatchEnvelope(askedLabel || brokerTargetLabel(resolved.agent), unavailable), {
|
|
49782
50702
|
requesterId
|
|
@@ -49881,9 +50801,11 @@ async function acceptBrokerDelivery(payload) {
|
|
|
49881
50801
|
...targetSessionId ? { targetSessionId } : {},
|
|
49882
50802
|
...payload.intent === "tell" && payload.invocationMetadata?.sourceIntent === undefined ? { sourceIntent: "direct_message" } : {}
|
|
49883
50803
|
};
|
|
50804
|
+
const baseInvocationExecution = execution ?? {};
|
|
49884
50805
|
const invocationExecution = {
|
|
49885
|
-
...
|
|
49886
|
-
|
|
50806
|
+
...baseInvocationExecution,
|
|
50807
|
+
session: targetSessionId ? "existing" : "new",
|
|
50808
|
+
...targetSessionId ? { targetSessionId } : {}
|
|
49887
50809
|
};
|
|
49888
50810
|
const invocation = {
|
|
49889
50811
|
id: createRuntimeId2("inv"),
|