@openscout/scout 0.2.54 → 0.2.56
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/{arc.es-CCzVmJbw.js → arc.es-Cs--6ecm.js} +1 -1
- package/dist/client/assets/index-DvJjuWtM.js +146 -0
- package/dist/client/assets/index-MaClzcbW.css +1 -0
- package/dist/client/index.html +3 -3
- package/dist/main.mjs +15532 -10927
- package/dist/pair-supervisor.mjs +15515 -12173
- package/dist/scout-control-plane-web.mjs +3895 -217
- package/package.json +2 -2
- package/dist/client/assets/index-CazCcdzO.css +0 -1
- package/dist/client/assets/index-D0N02a0Z.js +0 -139
|
@@ -122,6 +122,35 @@ function extractPendingApprovalRequests(snapshot) {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
// packages/agent-sessions/src/state.ts
|
|
125
|
+
function normalizeTrackedTimestamp(value) {
|
|
126
|
+
if (value == null) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
if (typeof value === "number") {
|
|
130
|
+
if (!Number.isFinite(value)) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
return value < 1000000000000 ? value * 1000 : value;
|
|
134
|
+
}
|
|
135
|
+
if (value instanceof Date) {
|
|
136
|
+
const ms = value.getTime();
|
|
137
|
+
return Number.isFinite(ms) ? ms : null;
|
|
138
|
+
}
|
|
139
|
+
if (typeof value === "string") {
|
|
140
|
+
const trimmed = value.trim();
|
|
141
|
+
if (!trimmed) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const numeric = Number(trimmed);
|
|
145
|
+
if (Number.isFinite(numeric)) {
|
|
146
|
+
return numeric < 1000000000000 ? numeric * 1000 : numeric;
|
|
147
|
+
}
|
|
148
|
+
const parsed = Date.parse(trimmed);
|
|
149
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
125
154
|
class StateTracker {
|
|
126
155
|
states = new Map;
|
|
127
156
|
createSession(sessionId, session) {
|
|
@@ -156,7 +185,7 @@ class StateTracker {
|
|
|
156
185
|
}
|
|
157
186
|
return summaries;
|
|
158
187
|
}
|
|
159
|
-
trackEvent(sessionId, event) {
|
|
188
|
+
trackEvent(sessionId, event, capturedAt) {
|
|
160
189
|
const state = this.states.get(sessionId);
|
|
161
190
|
if (!state)
|
|
162
191
|
return;
|
|
@@ -168,13 +197,13 @@ class StateTracker {
|
|
|
168
197
|
state.session = { ...state.session, status: "closed" };
|
|
169
198
|
break;
|
|
170
199
|
case "turn:start":
|
|
171
|
-
this.handleTurnStart(state, event);
|
|
200
|
+
this.handleTurnStart(state, event, capturedAt);
|
|
172
201
|
break;
|
|
173
202
|
case "turn:end":
|
|
174
|
-
this.handleTurnEnd(state, event);
|
|
203
|
+
this.handleTurnEnd(state, event, capturedAt);
|
|
175
204
|
break;
|
|
176
205
|
case "turn:error":
|
|
177
|
-
this.handleTurnError(state, event);
|
|
206
|
+
this.handleTurnError(state, event, capturedAt);
|
|
178
207
|
break;
|
|
179
208
|
case "block:start":
|
|
180
209
|
this.handleBlockStart(state, event);
|
|
@@ -199,17 +228,17 @@ class StateTracker {
|
|
|
199
228
|
break;
|
|
200
229
|
}
|
|
201
230
|
}
|
|
202
|
-
handleTurnStart(state, event) {
|
|
231
|
+
handleTurnStart(state, event, capturedAt) {
|
|
203
232
|
const turn = {
|
|
204
233
|
id: event.turn.id,
|
|
205
234
|
status: "streaming",
|
|
206
235
|
blocks: [],
|
|
207
|
-
startedAt: Date.now()
|
|
236
|
+
startedAt: normalizeTrackedTimestamp(event.turn.startedAt) ?? normalizeTrackedTimestamp(capturedAt) ?? Date.now()
|
|
208
237
|
};
|
|
209
238
|
state.turns.push(turn);
|
|
210
239
|
state.currentTurnId = turn.id;
|
|
211
240
|
}
|
|
212
|
-
handleTurnEnd(state, event) {
|
|
241
|
+
handleTurnEnd(state, event, capturedAt) {
|
|
213
242
|
const turn = this.findTurn(state, event.turnId);
|
|
214
243
|
if (!turn)
|
|
215
244
|
return;
|
|
@@ -227,17 +256,17 @@ class StateTracker {
|
|
|
227
256
|
turn.status = "completed";
|
|
228
257
|
break;
|
|
229
258
|
}
|
|
230
|
-
turn.endedAt = Date.now();
|
|
259
|
+
turn.endedAt = normalizeTrackedTimestamp(capturedAt) ?? Date.now();
|
|
231
260
|
if (state.currentTurnId === event.turnId) {
|
|
232
261
|
state.currentTurnId = undefined;
|
|
233
262
|
}
|
|
234
263
|
}
|
|
235
|
-
handleTurnError(state, event) {
|
|
264
|
+
handleTurnError(state, event, capturedAt) {
|
|
236
265
|
const turn = this.findTurn(state, event.turnId);
|
|
237
266
|
if (!turn)
|
|
238
267
|
return;
|
|
239
268
|
turn.status = "error";
|
|
240
|
-
turn.endedAt = Date.now();
|
|
269
|
+
turn.endedAt = normalizeTrackedTimestamp(capturedAt) ?? Date.now();
|
|
241
270
|
if (state.currentTurnId === event.turnId) {
|
|
242
271
|
state.currentTurnId = undefined;
|
|
243
272
|
}
|
|
@@ -577,6 +606,682 @@ var init_registry = __esm(() => {
|
|
|
577
606
|
};
|
|
578
607
|
});
|
|
579
608
|
|
|
609
|
+
// packages/agent-sessions/src/history.ts
|
|
610
|
+
import { basename, dirname } from "path";
|
|
611
|
+
function decodeClaudeProjectsSlug(name) {
|
|
612
|
+
if (!name || !name.startsWith("-")) {
|
|
613
|
+
return null;
|
|
614
|
+
}
|
|
615
|
+
const tail = name.slice(1);
|
|
616
|
+
if (!tail) {
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
return `/${tail.replace(/-/g, "/")}`;
|
|
620
|
+
}
|
|
621
|
+
function inferClaudeHistoryCwd(path) {
|
|
622
|
+
const parent = basename(dirname(path));
|
|
623
|
+
return decodeClaudeProjectsSlug(parent);
|
|
624
|
+
}
|
|
625
|
+
function deriveHistoryName(path) {
|
|
626
|
+
const claudeCwd = inferClaudeHistoryCwd(path);
|
|
627
|
+
if (claudeCwd) {
|
|
628
|
+
return basename(claudeCwd) || claudeCwd;
|
|
629
|
+
}
|
|
630
|
+
const parent = basename(dirname(path));
|
|
631
|
+
return parent || basename(path) || "History Session";
|
|
632
|
+
}
|
|
633
|
+
function normalizeTimestamp(value) {
|
|
634
|
+
if (typeof value === "number") {
|
|
635
|
+
if (!Number.isFinite(value)) {
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
return value < 1000000000000 ? value * 1000 : value;
|
|
639
|
+
}
|
|
640
|
+
if (value instanceof Date) {
|
|
641
|
+
const time = value.getTime();
|
|
642
|
+
return Number.isFinite(time) ? time : null;
|
|
643
|
+
}
|
|
644
|
+
if (typeof value === "string") {
|
|
645
|
+
const trimmed = value.trim();
|
|
646
|
+
if (!trimmed) {
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
const numeric = Number(trimmed);
|
|
650
|
+
if (Number.isFinite(numeric)) {
|
|
651
|
+
return numeric < 1000000000000 ? numeric * 1000 : numeric;
|
|
652
|
+
}
|
|
653
|
+
const parsed = Date.parse(trimmed);
|
|
654
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
655
|
+
}
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
function extractRecordTimestamp(record) {
|
|
659
|
+
const candidates = [
|
|
660
|
+
record.timestamp,
|
|
661
|
+
record.createdAt,
|
|
662
|
+
record.created_at,
|
|
663
|
+
record.updatedAt,
|
|
664
|
+
record.updated_at,
|
|
665
|
+
record.time,
|
|
666
|
+
record.ts
|
|
667
|
+
];
|
|
668
|
+
for (const candidate of candidates) {
|
|
669
|
+
const normalized = normalizeTimestamp(candidate);
|
|
670
|
+
if (normalized !== null) {
|
|
671
|
+
return normalized;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
function stringifyUnknown(value) {
|
|
677
|
+
if (typeof value === "string") {
|
|
678
|
+
return value;
|
|
679
|
+
}
|
|
680
|
+
if (value == null) {
|
|
681
|
+
return "";
|
|
682
|
+
}
|
|
683
|
+
try {
|
|
684
|
+
return JSON.stringify(value);
|
|
685
|
+
} catch {
|
|
686
|
+
return String(value);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
function renderToolResultContent(content) {
|
|
690
|
+
if (typeof content === "string") {
|
|
691
|
+
return content;
|
|
692
|
+
}
|
|
693
|
+
if (Array.isArray(content)) {
|
|
694
|
+
const text = content.map((entry) => {
|
|
695
|
+
if (typeof entry === "string") {
|
|
696
|
+
return entry;
|
|
697
|
+
}
|
|
698
|
+
const item = entry;
|
|
699
|
+
if (typeof item.text === "string") {
|
|
700
|
+
return item.text;
|
|
701
|
+
}
|
|
702
|
+
if (typeof item.content === "string") {
|
|
703
|
+
return item.content;
|
|
704
|
+
}
|
|
705
|
+
return stringifyUnknown(entry);
|
|
706
|
+
}).filter(Boolean).join(`
|
|
707
|
+
`);
|
|
708
|
+
return text || stringifyUnknown(content);
|
|
709
|
+
}
|
|
710
|
+
return stringifyUnknown(content);
|
|
711
|
+
}
|
|
712
|
+
function extractQuestionOptions(firstQuestion) {
|
|
713
|
+
const options = Array.isArray(firstQuestion.options) ? firstQuestion.options : [];
|
|
714
|
+
return options.map((option) => {
|
|
715
|
+
if (typeof option === "string") {
|
|
716
|
+
return { label: option };
|
|
717
|
+
}
|
|
718
|
+
const record = option;
|
|
719
|
+
return {
|
|
720
|
+
label: typeof record.label === "string" ? record.label : String(option),
|
|
721
|
+
description: typeof record.description === "string" ? record.description : undefined
|
|
722
|
+
};
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
function parseQuestionAnswer(content) {
|
|
726
|
+
const text = renderToolResultContent(content).trim();
|
|
727
|
+
if (!text) {
|
|
728
|
+
return [];
|
|
729
|
+
}
|
|
730
|
+
return text.split(/\s*,\s*/u).map((part) => part.trim()).filter(Boolean);
|
|
731
|
+
}
|
|
732
|
+
function inferHistoryAdapterType(path, adapterType) {
|
|
733
|
+
const normalizedAdapter = adapterType?.trim();
|
|
734
|
+
if (normalizedAdapter === "claude-code") {
|
|
735
|
+
return "claude-code";
|
|
736
|
+
}
|
|
737
|
+
if (normalizedAdapter === "codex") {
|
|
738
|
+
return "codex";
|
|
739
|
+
}
|
|
740
|
+
const normalizedPath = path.toLowerCase();
|
|
741
|
+
if (normalizedPath.includes("/.claude/projects/")) {
|
|
742
|
+
return "claude-code";
|
|
743
|
+
}
|
|
744
|
+
if (normalizedPath.includes("/.codex/") || normalizedPath.includes("/.openai-codex/")) {
|
|
745
|
+
return "codex";
|
|
746
|
+
}
|
|
747
|
+
return "unknown";
|
|
748
|
+
}
|
|
749
|
+
function buildBaseHistorySession(input, adapterType) {
|
|
750
|
+
const cwd = input.cwd?.trim() || inferClaudeHistoryCwd(input.path) || undefined;
|
|
751
|
+
return {
|
|
752
|
+
id: input.sessionId?.trim() || `history:${input.path}`,
|
|
753
|
+
name: input.name?.trim() || deriveHistoryName(input.path),
|
|
754
|
+
adapterType,
|
|
755
|
+
status: "idle",
|
|
756
|
+
...cwd ? { cwd } : {},
|
|
757
|
+
providerMeta: {
|
|
758
|
+
historyPath: input.path,
|
|
759
|
+
historyAdapterType: adapterType,
|
|
760
|
+
source: "external_history"
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
class ClaudeCodeHistoryParser {
|
|
766
|
+
session;
|
|
767
|
+
baseTimestampMs;
|
|
768
|
+
events = [];
|
|
769
|
+
currentTurn = null;
|
|
770
|
+
turnCounter = 0;
|
|
771
|
+
blockIndex = 0;
|
|
772
|
+
toolBlockMap = new Map;
|
|
773
|
+
questionBlockMap = new Map;
|
|
774
|
+
blockById = new Map;
|
|
775
|
+
activeStreamBlocks = new Map;
|
|
776
|
+
sawStreamTextThisTurn = false;
|
|
777
|
+
constructor(session, baseTimestampMs) {
|
|
778
|
+
this.session = session;
|
|
779
|
+
this.baseTimestampMs = baseTimestampMs;
|
|
780
|
+
}
|
|
781
|
+
parse(content) {
|
|
782
|
+
const lines = content.split(/\r?\n/u);
|
|
783
|
+
let parsedLineCount = 0;
|
|
784
|
+
let skippedLineCount = 0;
|
|
785
|
+
let lineCount = 0;
|
|
786
|
+
for (let index = 0;index < lines.length; index += 1) {
|
|
787
|
+
const rawLine = lines[index];
|
|
788
|
+
const trimmed = rawLine.trim();
|
|
789
|
+
if (!trimmed) {
|
|
790
|
+
continue;
|
|
791
|
+
}
|
|
792
|
+
lineCount += 1;
|
|
793
|
+
let record;
|
|
794
|
+
try {
|
|
795
|
+
const parsed = JSON.parse(trimmed);
|
|
796
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
797
|
+
skippedLineCount += 1;
|
|
798
|
+
continue;
|
|
799
|
+
}
|
|
800
|
+
record = parsed;
|
|
801
|
+
} catch {
|
|
802
|
+
skippedLineCount += 1;
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
const capturedAt = extractRecordTimestamp(record) ?? this.baseTimestampMs + index;
|
|
806
|
+
if (this.handleRecord(record, capturedAt)) {
|
|
807
|
+
parsedLineCount += 1;
|
|
808
|
+
} else {
|
|
809
|
+
skippedLineCount += 1;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
return {
|
|
813
|
+
events: this.events,
|
|
814
|
+
lineCount,
|
|
815
|
+
parsedLineCount,
|
|
816
|
+
skippedLineCount
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
handleRecord(record, capturedAt) {
|
|
820
|
+
const type = typeof record.type === "string" ? record.type : null;
|
|
821
|
+
if (!type) {
|
|
822
|
+
return false;
|
|
823
|
+
}
|
|
824
|
+
switch (type) {
|
|
825
|
+
case "system":
|
|
826
|
+
this.handleSystem(record, capturedAt);
|
|
827
|
+
return true;
|
|
828
|
+
case "user":
|
|
829
|
+
this.startTurn(capturedAt);
|
|
830
|
+
return true;
|
|
831
|
+
case "assistant":
|
|
832
|
+
this.handleAssistant(record, capturedAt);
|
|
833
|
+
return true;
|
|
834
|
+
case "tool_use":
|
|
835
|
+
this.handleToolUse(record, capturedAt);
|
|
836
|
+
return true;
|
|
837
|
+
case "tool_result":
|
|
838
|
+
this.handleToolResult(record, capturedAt);
|
|
839
|
+
return true;
|
|
840
|
+
case "stream_event":
|
|
841
|
+
this.handleStreamEvent(record, capturedAt);
|
|
842
|
+
return true;
|
|
843
|
+
case "result":
|
|
844
|
+
this.handleResult(record, capturedAt);
|
|
845
|
+
return true;
|
|
846
|
+
case "error":
|
|
847
|
+
this.handleError(record, capturedAt);
|
|
848
|
+
return true;
|
|
849
|
+
default:
|
|
850
|
+
return false;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
handleSystem(record, capturedAt) {
|
|
854
|
+
if (record.subtype !== "init") {
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
let changed = false;
|
|
858
|
+
const externalSessionId = typeof record.session_id === "string" ? record.session_id : typeof record.sessionId === "string" ? record.sessionId : null;
|
|
859
|
+
if (externalSessionId) {
|
|
860
|
+
const providerMeta = { ...this.session.providerMeta ?? {} };
|
|
861
|
+
if (providerMeta.externalSessionId !== externalSessionId) {
|
|
862
|
+
providerMeta.externalSessionId = externalSessionId;
|
|
863
|
+
this.session.providerMeta = providerMeta;
|
|
864
|
+
changed = true;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (typeof record.cwd === "string" && record.cwd.trim() && this.session.cwd !== record.cwd) {
|
|
868
|
+
this.session.cwd = record.cwd;
|
|
869
|
+
changed = true;
|
|
870
|
+
}
|
|
871
|
+
if (typeof record.model === "string" && record.model.trim() && this.session.model !== record.model) {
|
|
872
|
+
this.session.model = record.model;
|
|
873
|
+
changed = true;
|
|
874
|
+
}
|
|
875
|
+
if (changed) {
|
|
876
|
+
this.emitEvent(capturedAt, {
|
|
877
|
+
event: "session:update",
|
|
878
|
+
session: { ...this.session }
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
handleAssistant(record, capturedAt) {
|
|
883
|
+
const turn = this.ensureTurn(capturedAt);
|
|
884
|
+
if (this.sawStreamTextThisTurn) {
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const content = record.message && typeof record.message === "object" ? record.message.content : record.content;
|
|
888
|
+
if (!Array.isArray(content)) {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
for (const part of content) {
|
|
892
|
+
const contentPart = part;
|
|
893
|
+
const contentType = typeof contentPart.type === "string" ? contentPart.type : "";
|
|
894
|
+
if (contentType === "thinking" || contentType === "reasoning") {
|
|
895
|
+
const block = this.startBlock(turn, capturedAt, {
|
|
896
|
+
type: "reasoning",
|
|
897
|
+
text: typeof contentPart.thinking === "string" ? contentPart.thinking : typeof contentPart.text === "string" ? contentPart.text : "",
|
|
898
|
+
status: "completed"
|
|
899
|
+
});
|
|
900
|
+
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
901
|
+
} else if (contentType === "text") {
|
|
902
|
+
const block = this.startBlock(turn, capturedAt, {
|
|
903
|
+
type: "text",
|
|
904
|
+
text: typeof contentPart.text === "string" ? contentPart.text : "",
|
|
905
|
+
status: "completed"
|
|
906
|
+
});
|
|
907
|
+
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
handleStreamEvent(record, capturedAt) {
|
|
912
|
+
const turn = this.ensureTurn(capturedAt);
|
|
913
|
+
const streamEvent = record.event;
|
|
914
|
+
if (!streamEvent || typeof streamEvent !== "object") {
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
const eventRecord = streamEvent;
|
|
918
|
+
const streamType = typeof eventRecord.type === "string" ? eventRecord.type : "";
|
|
919
|
+
if (streamType === "message_start") {
|
|
920
|
+
this.activeStreamBlocks.clear();
|
|
921
|
+
this.sawStreamTextThisTurn = false;
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
if (streamType === "content_block_start") {
|
|
925
|
+
const index = typeof eventRecord.index === "number" ? eventRecord.index : 0;
|
|
926
|
+
const contentBlock = eventRecord.content_block;
|
|
927
|
+
if (!contentBlock || typeof contentBlock !== "object") {
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
const contentRecord = contentBlock;
|
|
931
|
+
const contentType = typeof contentRecord.type === "string" ? contentRecord.type : "";
|
|
932
|
+
if (contentType !== "text" && contentType !== "thinking") {
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
const block = this.startBlock(turn, capturedAt, {
|
|
936
|
+
type: contentType === "thinking" ? "reasoning" : "text",
|
|
937
|
+
text: "",
|
|
938
|
+
status: "streaming"
|
|
939
|
+
});
|
|
940
|
+
this.activeStreamBlocks.set(index, block);
|
|
941
|
+
this.sawStreamTextThisTurn = true;
|
|
942
|
+
const initialText = contentType === "thinking" ? typeof contentRecord.thinking === "string" ? contentRecord.thinking : "" : typeof contentRecord.text === "string" ? contentRecord.text : "";
|
|
943
|
+
this.appendTextDelta(capturedAt, turn, block, initialText);
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
if (streamType === "content_block_delta") {
|
|
947
|
+
const index = typeof eventRecord.index === "number" ? eventRecord.index : 0;
|
|
948
|
+
const block = this.activeStreamBlocks.get(index);
|
|
949
|
+
const delta = eventRecord.delta;
|
|
950
|
+
if (!block || !delta || typeof delta !== "object") {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
const deltaRecord = delta;
|
|
954
|
+
const deltaType = typeof deltaRecord.type === "string" ? deltaRecord.type : "";
|
|
955
|
+
if (deltaType === "text_delta") {
|
|
956
|
+
this.appendTextDelta(capturedAt, turn, block, typeof deltaRecord.text === "string" ? deltaRecord.text : "");
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
if (deltaType === "thinking_delta") {
|
|
960
|
+
this.appendTextDelta(capturedAt, turn, block, typeof deltaRecord.thinking === "string" ? deltaRecord.thinking : "");
|
|
961
|
+
}
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
if (streamType === "content_block_stop") {
|
|
965
|
+
const index = typeof eventRecord.index === "number" ? eventRecord.index : 0;
|
|
966
|
+
const block = this.activeStreamBlocks.get(index);
|
|
967
|
+
if (!block) {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
971
|
+
this.activeStreamBlocks.delete(index);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
handleToolUse(record, capturedAt) {
|
|
975
|
+
const turn = this.ensureTurn(capturedAt);
|
|
976
|
+
const toolName = typeof record.tool_name === "string" ? record.tool_name : typeof record.name === "string" ? record.name : "unknown";
|
|
977
|
+
const toolCallId = typeof record.tool_use_id === "string" ? record.tool_use_id : typeof record.id === "string" ? record.id : `${turn.id}:tool:${this.blockIndex}`;
|
|
978
|
+
if (toolName === "AskUserQuestion") {
|
|
979
|
+
const input = record.input && typeof record.input === "object" ? record.input : {};
|
|
980
|
+
const questions = Array.isArray(input.questions) ? input.questions : [];
|
|
981
|
+
const firstQuestion = questions[0] ?? {};
|
|
982
|
+
const block2 = this.startBlock(turn, capturedAt, {
|
|
983
|
+
id: `${turn.id}:question:${toolCallId}`,
|
|
984
|
+
type: "question",
|
|
985
|
+
header: typeof firstQuestion.header === "string" ? firstQuestion.header : undefined,
|
|
986
|
+
question: typeof firstQuestion.question === "string" ? firstQuestion.question : "",
|
|
987
|
+
options: extractQuestionOptions(firstQuestion),
|
|
988
|
+
multiSelect: firstQuestion.multiSelect === true,
|
|
989
|
+
questionStatus: "awaiting_answer",
|
|
990
|
+
answer: undefined,
|
|
991
|
+
status: "streaming"
|
|
992
|
+
});
|
|
993
|
+
this.toolBlockMap.set(toolCallId, block2.id);
|
|
994
|
+
this.questionBlockMap.set(toolCallId, block2.id);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
let action;
|
|
998
|
+
if (toolName === "Edit" || toolName === "Write" || toolName === "MultiEdit") {
|
|
999
|
+
const input = record.input && typeof record.input === "object" ? record.input : {};
|
|
1000
|
+
action = {
|
|
1001
|
+
kind: "file_change",
|
|
1002
|
+
path: typeof input.file_path === "string" ? input.file_path : typeof input.path === "string" ? input.path : "",
|
|
1003
|
+
diff: "",
|
|
1004
|
+
status: "running",
|
|
1005
|
+
output: ""
|
|
1006
|
+
};
|
|
1007
|
+
} else if (toolName === "Bash") {
|
|
1008
|
+
const input = record.input && typeof record.input === "object" ? record.input : {};
|
|
1009
|
+
action = {
|
|
1010
|
+
kind: "command",
|
|
1011
|
+
command: typeof input.command === "string" ? input.command : "",
|
|
1012
|
+
status: "running",
|
|
1013
|
+
output: ""
|
|
1014
|
+
};
|
|
1015
|
+
} else if (toolName === "Agent") {
|
|
1016
|
+
const input = record.input && typeof record.input === "object" ? record.input : {};
|
|
1017
|
+
action = {
|
|
1018
|
+
kind: "subagent",
|
|
1019
|
+
agentId: toolCallId,
|
|
1020
|
+
agentName: typeof input.description === "string" ? input.description : undefined,
|
|
1021
|
+
prompt: typeof input.prompt === "string" ? input.prompt : undefined,
|
|
1022
|
+
status: "running",
|
|
1023
|
+
output: ""
|
|
1024
|
+
};
|
|
1025
|
+
} else {
|
|
1026
|
+
action = {
|
|
1027
|
+
kind: "tool_call",
|
|
1028
|
+
toolName,
|
|
1029
|
+
toolCallId,
|
|
1030
|
+
input: record.input,
|
|
1031
|
+
status: "running",
|
|
1032
|
+
output: ""
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
const block = this.startBlock(turn, capturedAt, {
|
|
1036
|
+
id: `${turn.id}:action:${toolCallId}`,
|
|
1037
|
+
type: "action",
|
|
1038
|
+
action,
|
|
1039
|
+
status: "streaming"
|
|
1040
|
+
});
|
|
1041
|
+
this.toolBlockMap.set(toolCallId, block.id);
|
|
1042
|
+
}
|
|
1043
|
+
handleToolResult(record, capturedAt) {
|
|
1044
|
+
const turn = this.ensureTurn(capturedAt);
|
|
1045
|
+
const toolCallId = typeof record.tool_use_id === "string" ? record.tool_use_id : typeof record.id === "string" ? record.id : "";
|
|
1046
|
+
if (!toolCallId) {
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
const questionBlockId = this.questionBlockMap.get(toolCallId);
|
|
1050
|
+
if (questionBlockId) {
|
|
1051
|
+
const answer = parseQuestionAnswer(record.content);
|
|
1052
|
+
this.emitEvent(capturedAt, {
|
|
1053
|
+
event: "block:question:answer",
|
|
1054
|
+
sessionId: this.session.id,
|
|
1055
|
+
turnId: turn.id,
|
|
1056
|
+
blockId: questionBlockId,
|
|
1057
|
+
questionStatus: "answered",
|
|
1058
|
+
...answer.length > 0 ? { answer } : {}
|
|
1059
|
+
});
|
|
1060
|
+
const block2 = this.blockById.get(questionBlockId);
|
|
1061
|
+
if (block2) {
|
|
1062
|
+
this.emitBlockEnd(capturedAt, turn, block2, "completed");
|
|
1063
|
+
}
|
|
1064
|
+
this.questionBlockMap.delete(toolCallId);
|
|
1065
|
+
this.toolBlockMap.delete(toolCallId);
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
const blockId = this.toolBlockMap.get(toolCallId);
|
|
1069
|
+
if (!blockId) {
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
const output = renderToolResultContent(record.content);
|
|
1073
|
+
if (output) {
|
|
1074
|
+
this.emitEvent(capturedAt, {
|
|
1075
|
+
event: "block:action:output",
|
|
1076
|
+
sessionId: this.session.id,
|
|
1077
|
+
turnId: turn.id,
|
|
1078
|
+
blockId,
|
|
1079
|
+
output
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
const status = record.is_error === true ? "failed" : "completed";
|
|
1083
|
+
this.emitEvent(capturedAt, {
|
|
1084
|
+
event: "block:action:status",
|
|
1085
|
+
sessionId: this.session.id,
|
|
1086
|
+
turnId: turn.id,
|
|
1087
|
+
blockId,
|
|
1088
|
+
status
|
|
1089
|
+
});
|
|
1090
|
+
const block = this.blockById.get(blockId);
|
|
1091
|
+
if (block) {
|
|
1092
|
+
this.emitBlockEnd(capturedAt, turn, block, status === "failed" ? "failed" : "completed");
|
|
1093
|
+
}
|
|
1094
|
+
this.toolBlockMap.delete(toolCallId);
|
|
1095
|
+
}
|
|
1096
|
+
handleResult(record, capturedAt) {
|
|
1097
|
+
const turn = this.currentTurn;
|
|
1098
|
+
if (!turn) {
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
this.completeOpenStreamBlocks(capturedAt, turn);
|
|
1102
|
+
const denials = Array.isArray(record.permission_denials) ? record.permission_denials : [];
|
|
1103
|
+
for (const denial of denials) {
|
|
1104
|
+
const denialRecord = denial;
|
|
1105
|
+
if (denialRecord.tool_name !== "AskUserQuestion") {
|
|
1106
|
+
continue;
|
|
1107
|
+
}
|
|
1108
|
+
const input = denialRecord.tool_input && typeof denialRecord.tool_input === "object" ? denialRecord.tool_input : {};
|
|
1109
|
+
const questions = Array.isArray(input.questions) ? input.questions : [];
|
|
1110
|
+
const firstQuestion = questions[0] ?? {};
|
|
1111
|
+
const block = this.startBlock(turn, capturedAt, {
|
|
1112
|
+
type: "question",
|
|
1113
|
+
header: typeof firstQuestion.header === "string" ? firstQuestion.header : undefined,
|
|
1114
|
+
question: typeof firstQuestion.question === "string" ? firstQuestion.question : "",
|
|
1115
|
+
options: extractQuestionOptions(firstQuestion),
|
|
1116
|
+
multiSelect: firstQuestion.multiSelect === true,
|
|
1117
|
+
questionStatus: "denied",
|
|
1118
|
+
status: "completed"
|
|
1119
|
+
});
|
|
1120
|
+
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
1121
|
+
}
|
|
1122
|
+
this.endTurn(record.subtype === "error" ? "failed" : "completed", capturedAt);
|
|
1123
|
+
}
|
|
1124
|
+
handleError(record, capturedAt) {
|
|
1125
|
+
const turn = this.ensureTurn(capturedAt);
|
|
1126
|
+
const error = record.error && typeof record.error === "object" ? record.error : {};
|
|
1127
|
+
const message = typeof error.message === "string" ? error.message : typeof record.message === "string" ? record.message : "Unknown error";
|
|
1128
|
+
this.emitError(turn, capturedAt, message);
|
|
1129
|
+
this.endTurn("failed", capturedAt);
|
|
1130
|
+
}
|
|
1131
|
+
startTurn(capturedAt) {
|
|
1132
|
+
if (this.currentTurn) {
|
|
1133
|
+
this.endTurn("stopped", capturedAt);
|
|
1134
|
+
}
|
|
1135
|
+
this.turnCounter += 1;
|
|
1136
|
+
this.blockIndex = 0;
|
|
1137
|
+
this.toolBlockMap.clear();
|
|
1138
|
+
this.questionBlockMap.clear();
|
|
1139
|
+
this.blockById.clear();
|
|
1140
|
+
this.activeStreamBlocks.clear();
|
|
1141
|
+
this.sawStreamTextThisTurn = false;
|
|
1142
|
+
this.session.status = "active";
|
|
1143
|
+
this.emitEvent(capturedAt, {
|
|
1144
|
+
event: "session:update",
|
|
1145
|
+
session: { ...this.session }
|
|
1146
|
+
});
|
|
1147
|
+
const turn = {
|
|
1148
|
+
id: `history-turn-${this.turnCounter}`,
|
|
1149
|
+
sessionId: this.session.id,
|
|
1150
|
+
status: "started",
|
|
1151
|
+
startedAt: new Date(capturedAt).toISOString(),
|
|
1152
|
+
blocks: []
|
|
1153
|
+
};
|
|
1154
|
+
this.currentTurn = turn;
|
|
1155
|
+
this.emitEvent(capturedAt, {
|
|
1156
|
+
event: "turn:start",
|
|
1157
|
+
sessionId: this.session.id,
|
|
1158
|
+
turn
|
|
1159
|
+
});
|
|
1160
|
+
return turn;
|
|
1161
|
+
}
|
|
1162
|
+
ensureTurn(capturedAt) {
|
|
1163
|
+
return this.currentTurn ?? this.startTurn(capturedAt);
|
|
1164
|
+
}
|
|
1165
|
+
endTurn(status, capturedAt) {
|
|
1166
|
+
const turn = this.currentTurn;
|
|
1167
|
+
if (!turn) {
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
turn.status = status;
|
|
1171
|
+
turn.endedAt = new Date(capturedAt).toISOString();
|
|
1172
|
+
this.emitEvent(capturedAt, {
|
|
1173
|
+
event: "turn:end",
|
|
1174
|
+
sessionId: this.session.id,
|
|
1175
|
+
turnId: turn.id,
|
|
1176
|
+
status
|
|
1177
|
+
});
|
|
1178
|
+
this.currentTurn = null;
|
|
1179
|
+
this.toolBlockMap.clear();
|
|
1180
|
+
this.questionBlockMap.clear();
|
|
1181
|
+
this.blockById.clear();
|
|
1182
|
+
this.activeStreamBlocks.clear();
|
|
1183
|
+
this.sawStreamTextThisTurn = false;
|
|
1184
|
+
this.session.status = "idle";
|
|
1185
|
+
this.emitEvent(capturedAt, {
|
|
1186
|
+
event: "session:update",
|
|
1187
|
+
session: { ...this.session }
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
startBlock(turn, capturedAt, partial) {
|
|
1191
|
+
const block = {
|
|
1192
|
+
...partial,
|
|
1193
|
+
id: partial.id || `${turn.id}:block:${this.blockIndex}`,
|
|
1194
|
+
turnId: turn.id,
|
|
1195
|
+
index: this.blockIndex
|
|
1196
|
+
};
|
|
1197
|
+
this.blockIndex += 1;
|
|
1198
|
+
turn.blocks.push(block);
|
|
1199
|
+
this.blockById.set(block.id, block);
|
|
1200
|
+
this.emitEvent(capturedAt, {
|
|
1201
|
+
event: "block:start",
|
|
1202
|
+
sessionId: this.session.id,
|
|
1203
|
+
turnId: turn.id,
|
|
1204
|
+
block
|
|
1205
|
+
});
|
|
1206
|
+
return block;
|
|
1207
|
+
}
|
|
1208
|
+
appendTextDelta(capturedAt, turn, block, text) {
|
|
1209
|
+
if (!text) {
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
block.text += text;
|
|
1213
|
+
block.status = "streaming";
|
|
1214
|
+
this.emitEvent(capturedAt, {
|
|
1215
|
+
event: "block:delta",
|
|
1216
|
+
sessionId: this.session.id,
|
|
1217
|
+
turnId: turn.id,
|
|
1218
|
+
blockId: block.id,
|
|
1219
|
+
text
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
emitBlockEnd(capturedAt, turn, block, status) {
|
|
1223
|
+
block.status = status;
|
|
1224
|
+
this.emitEvent(capturedAt, {
|
|
1225
|
+
event: "block:end",
|
|
1226
|
+
sessionId: this.session.id,
|
|
1227
|
+
turnId: turn.id,
|
|
1228
|
+
blockId: block.id,
|
|
1229
|
+
status
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
completeOpenStreamBlocks(capturedAt, turn) {
|
|
1233
|
+
for (const block of this.activeStreamBlocks.values()) {
|
|
1234
|
+
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
1235
|
+
}
|
|
1236
|
+
this.activeStreamBlocks.clear();
|
|
1237
|
+
}
|
|
1238
|
+
emitError(turn, capturedAt, message) {
|
|
1239
|
+
const block = this.startBlock(turn, capturedAt, {
|
|
1240
|
+
type: "error",
|
|
1241
|
+
message,
|
|
1242
|
+
status: "completed"
|
|
1243
|
+
});
|
|
1244
|
+
this.emitBlockEnd(capturedAt, turn, block, "completed");
|
|
1245
|
+
}
|
|
1246
|
+
emitEvent(capturedAt, event) {
|
|
1247
|
+
this.events.push({
|
|
1248
|
+
capturedAt,
|
|
1249
|
+
event: structuredClone(event)
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
function supportsHistorySessionSnapshotForPath(path, adapterType) {
|
|
1254
|
+
return inferHistoryAdapterType(path, adapterType) === "claude-code";
|
|
1255
|
+
}
|
|
1256
|
+
function createHistorySessionSnapshot(input) {
|
|
1257
|
+
const adapterType = inferHistoryAdapterType(input.path, input.adapterType);
|
|
1258
|
+
if (adapterType !== "claude-code") {
|
|
1259
|
+
throw new Error(`History snapshot is not supported for adapter type "${adapterType}".`);
|
|
1260
|
+
}
|
|
1261
|
+
const session = buildBaseHistorySession(input, adapterType);
|
|
1262
|
+
const baseTimestampMs = normalizeTimestamp(input.baseTimestampMs) ?? Date.now();
|
|
1263
|
+
const parser = new ClaudeCodeHistoryParser(session, baseTimestampMs);
|
|
1264
|
+
const replay = parser.parse(input.content);
|
|
1265
|
+
const tracker = new StateTracker;
|
|
1266
|
+
tracker.createSession(session.id, session);
|
|
1267
|
+
for (const entry of replay.events) {
|
|
1268
|
+
tracker.trackEvent(session.id, entry.event, entry.capturedAt);
|
|
1269
|
+
}
|
|
1270
|
+
const snapshot = tracker.getSessionState(session.id);
|
|
1271
|
+
if (!snapshot) {
|
|
1272
|
+
throw new Error("Failed to reconstruct session snapshot from history.");
|
|
1273
|
+
}
|
|
1274
|
+
return {
|
|
1275
|
+
adapterType,
|
|
1276
|
+
lineCount: replay.lineCount,
|
|
1277
|
+
parsedLineCount: replay.parsedLineCount,
|
|
1278
|
+
skippedLineCount: replay.skippedLineCount,
|
|
1279
|
+
events: replay.events,
|
|
1280
|
+
snapshot
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
var init_history = () => {};
|
|
1284
|
+
|
|
580
1285
|
// packages/agent-sessions/src/adapters/claude-code.ts
|
|
581
1286
|
import { existsSync, readdirSync, statSync } from "fs";
|
|
582
1287
|
import { homedir } from "os";
|
|
@@ -602,7 +1307,7 @@ function resolveClaudeResumeContext(config) {
|
|
|
602
1307
|
if (!existsSync(sessionPath)) {
|
|
603
1308
|
continue;
|
|
604
1309
|
}
|
|
605
|
-
const cwd =
|
|
1310
|
+
const cwd = decodeClaudeProjectsSlug2(slug);
|
|
606
1311
|
if (!cwd) {
|
|
607
1312
|
continue;
|
|
608
1313
|
}
|
|
@@ -621,7 +1326,7 @@ function resolveClaudeResumeContext(config) {
|
|
|
621
1326
|
}
|
|
622
1327
|
return null;
|
|
623
1328
|
}
|
|
624
|
-
function
|
|
1329
|
+
function decodeClaudeProjectsSlug2(slug) {
|
|
625
1330
|
if (!slug.startsWith("-")) {
|
|
626
1331
|
return null;
|
|
627
1332
|
}
|
|
@@ -1142,7 +1847,7 @@ Referenced files: ${prompt.files.join(", ")}` });
|
|
|
1142
1847
|
// packages/agent-sessions/src/codex-launch-config.ts
|
|
1143
1848
|
import { accessSync, constants, existsSync as existsSync2 } from "fs";
|
|
1144
1849
|
import { homedir as homedir2 } from "os";
|
|
1145
|
-
import { basename, delimiter, dirname, join as join2, resolve } from "path";
|
|
1850
|
+
import { basename as basename2, delimiter, dirname as dirname2, join as join2, resolve } from "path";
|
|
1146
1851
|
import { fileURLToPath } from "url";
|
|
1147
1852
|
function isExecutable(filePath) {
|
|
1148
1853
|
if (!filePath) {
|
|
@@ -1163,7 +1868,7 @@ function ancestorChain(start) {
|
|
|
1163
1868
|
let current = resolve(start);
|
|
1164
1869
|
while (true) {
|
|
1165
1870
|
chain.push(current);
|
|
1166
|
-
const parent =
|
|
1871
|
+
const parent = dirname2(current);
|
|
1167
1872
|
if (parent === current) {
|
|
1168
1873
|
return chain;
|
|
1169
1874
|
}
|
|
@@ -1199,7 +1904,7 @@ function resolveBunExecutable(env) {
|
|
|
1199
1904
|
return candidate;
|
|
1200
1905
|
}
|
|
1201
1906
|
}
|
|
1202
|
-
if (
|
|
1907
|
+
if (basename2(process.execPath).startsWith("bun") && isExecutable(process.execPath)) {
|
|
1203
1908
|
return process.execPath;
|
|
1204
1909
|
}
|
|
1205
1910
|
return resolveExecutableFromSearchPath(["bun"], env);
|
|
@@ -1219,7 +1924,7 @@ function resolveScoutExecutable(env) {
|
|
|
1219
1924
|
return resolveExecutableFromSearchPath(["scout"], env);
|
|
1220
1925
|
}
|
|
1221
1926
|
function resolveRepoScoutScript(currentDirectory) {
|
|
1222
|
-
const moduleDirectory =
|
|
1927
|
+
const moduleDirectory = dirname2(fileURLToPath(import.meta.url));
|
|
1223
1928
|
const starts = uniquePaths([currentDirectory, moduleDirectory]);
|
|
1224
1929
|
for (const start of starts) {
|
|
1225
1930
|
for (const candidate of ancestorChain(start)) {
|
|
@@ -3394,6 +4099,7 @@ var init_echo = __esm(() => {
|
|
|
3394
4099
|
var init_src = __esm(() => {
|
|
3395
4100
|
init_registry();
|
|
3396
4101
|
init_registry();
|
|
4102
|
+
init_history();
|
|
3397
4103
|
init_claude_code();
|
|
3398
4104
|
init_codex();
|
|
3399
4105
|
init_openai_compat();
|
|
@@ -4388,7 +5094,14 @@ var init_dist = __esm(() => {
|
|
|
4388
5094
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
4389
5095
|
*/
|
|
4390
5096
|
});
|
|
4391
|
-
|
|
5097
|
+
|
|
5098
|
+
// packages/protocol/dist/common.js
|
|
5099
|
+
var init_common = () => {};
|
|
5100
|
+
|
|
5101
|
+
// packages/protocol/dist/actors.js
|
|
5102
|
+
var init_actors = () => {};
|
|
5103
|
+
|
|
5104
|
+
// packages/protocol/dist/agent-identity.js
|
|
4392
5105
|
function trimIdentityPrefix(value) {
|
|
4393
5106
|
return value.trim().replace(/^@+/, "").replace(/[.,!?;)\]]+$/, "");
|
|
4394
5107
|
}
|
|
@@ -4738,17 +5451,17 @@ var init_agent_identity = __esm(() => {
|
|
|
4738
5451
|
resolveAgentSelector = resolveAgentIdentity;
|
|
4739
5452
|
});
|
|
4740
5453
|
|
|
4741
|
-
// packages/protocol/
|
|
5454
|
+
// packages/protocol/dist/agent-address.js
|
|
4742
5455
|
var init_agent_address = __esm(() => {
|
|
4743
5456
|
init_agent_identity();
|
|
4744
5457
|
});
|
|
4745
5458
|
|
|
4746
|
-
// packages/protocol/
|
|
5459
|
+
// packages/protocol/dist/agent-selectors.js
|
|
4747
5460
|
var init_agent_selectors = __esm(() => {
|
|
4748
5461
|
init_agent_address();
|
|
4749
5462
|
});
|
|
4750
5463
|
|
|
4751
|
-
// packages/protocol/
|
|
5464
|
+
// packages/protocol/dist/scout-agent-card.js
|
|
4752
5465
|
function buildScoutReturnAddress(input) {
|
|
4753
5466
|
const next = {
|
|
4754
5467
|
actorId: input.actorId,
|
|
@@ -4783,16 +5496,163 @@ function buildScoutReturnAddress(input) {
|
|
|
4783
5496
|
}
|
|
4784
5497
|
return next;
|
|
4785
5498
|
}
|
|
4786
|
-
// packages/protocol/
|
|
4787
|
-
var
|
|
4788
|
-
init_agent_identity();
|
|
4789
|
-
init_agent_address();
|
|
4790
|
-
init_agent_selectors();
|
|
4791
|
-
});
|
|
5499
|
+
// packages/protocol/dist/mesh.js
|
|
5500
|
+
var init_mesh = () => {};
|
|
4792
5501
|
|
|
4793
|
-
// packages/
|
|
4794
|
-
|
|
4795
|
-
|
|
5502
|
+
// packages/protocol/dist/conversations.js
|
|
5503
|
+
var init_conversations = () => {};
|
|
5504
|
+
|
|
5505
|
+
// packages/protocol/dist/collaboration.js
|
|
5506
|
+
function isQuestionTerminalState(state) {
|
|
5507
|
+
return state === "closed" || state === "declined";
|
|
5508
|
+
}
|
|
5509
|
+
function isWorkItemTerminalState(state) {
|
|
5510
|
+
return state === "done" || state === "cancelled";
|
|
5511
|
+
}
|
|
5512
|
+
function collaborationRequiresNextMoveOwner(record) {
|
|
5513
|
+
if (record.kind === "question") {
|
|
5514
|
+
return !isQuestionTerminalState(record.state);
|
|
5515
|
+
}
|
|
5516
|
+
return !isWorkItemTerminalState(record.state);
|
|
5517
|
+
}
|
|
5518
|
+
function collaborationRequiresOwner(record) {
|
|
5519
|
+
return record.kind === "work_item" && !isWorkItemTerminalState(record.state);
|
|
5520
|
+
}
|
|
5521
|
+
function collaborationRequiresWaitingOn(record) {
|
|
5522
|
+
return record.kind === "work_item" && record.state === "waiting";
|
|
5523
|
+
}
|
|
5524
|
+
function collaborationRequiresAcceptance(record) {
|
|
5525
|
+
if (record.acceptanceState === "none") {
|
|
5526
|
+
return false;
|
|
5527
|
+
}
|
|
5528
|
+
if (record.kind === "question") {
|
|
5529
|
+
return Boolean(record.askedById && record.askedOfId);
|
|
5530
|
+
}
|
|
5531
|
+
return Boolean(record.requestedById);
|
|
5532
|
+
}
|
|
5533
|
+
function validateCollaborationRecord(record) {
|
|
5534
|
+
const errors = [];
|
|
5535
|
+
if (!record.id.trim()) {
|
|
5536
|
+
errors.push("collaboration record id is required");
|
|
5537
|
+
}
|
|
5538
|
+
if (!record.title.trim()) {
|
|
5539
|
+
errors.push("collaboration title is required");
|
|
5540
|
+
}
|
|
5541
|
+
if (!record.createdById.trim()) {
|
|
5542
|
+
errors.push("createdById is required");
|
|
5543
|
+
}
|
|
5544
|
+
if (record.parentId && record.parentId === record.id) {
|
|
5545
|
+
errors.push("parentId cannot reference the record itself");
|
|
5546
|
+
}
|
|
5547
|
+
if (record.createdAt > record.updatedAt) {
|
|
5548
|
+
errors.push("updatedAt must be greater than or equal to createdAt");
|
|
5549
|
+
}
|
|
5550
|
+
if (collaborationRequiresOwner(record) && !record.ownerId) {
|
|
5551
|
+
errors.push("non-terminal work items require ownerId");
|
|
5552
|
+
}
|
|
5553
|
+
if (collaborationRequiresNextMoveOwner(record) && !record.nextMoveOwnerId) {
|
|
5554
|
+
errors.push("non-terminal collaboration records require nextMoveOwnerId");
|
|
5555
|
+
}
|
|
5556
|
+
if (record.kind === "work_item" && collaborationRequiresWaitingOn(record) && !record.waitingOn) {
|
|
5557
|
+
errors.push("waiting work items require waitingOn");
|
|
5558
|
+
}
|
|
5559
|
+
if (record.kind === "question") {
|
|
5560
|
+
if (record.spawnedWorkItemId && record.spawnedWorkItemId === record.id) {
|
|
5561
|
+
errors.push("question spawnedWorkItemId cannot reference the question itself");
|
|
5562
|
+
}
|
|
5563
|
+
} else if (record.waitingOn?.targetId && record.waitingOn.targetId === record.id) {
|
|
5564
|
+
errors.push("waitingOn.targetId cannot reference the work item itself");
|
|
5565
|
+
}
|
|
5566
|
+
if (record.acceptanceState !== "none" && !collaborationRequiresAcceptance(record)) {
|
|
5567
|
+
errors.push("acceptanceState requires the corresponding requester and reviewer identities");
|
|
5568
|
+
}
|
|
5569
|
+
return errors;
|
|
5570
|
+
}
|
|
5571
|
+
function assertValidCollaborationRecord(record) {
|
|
5572
|
+
const errors = validateCollaborationRecord(record);
|
|
5573
|
+
if (errors.length > 0) {
|
|
5574
|
+
throw new Error(errors.join("; "));
|
|
5575
|
+
}
|
|
5576
|
+
}
|
|
5577
|
+
function validateCollaborationEvent(event, record) {
|
|
5578
|
+
const errors = [];
|
|
5579
|
+
if (!event.id.trim()) {
|
|
5580
|
+
errors.push("collaboration event id is required");
|
|
5581
|
+
}
|
|
5582
|
+
if (!event.recordId.trim()) {
|
|
5583
|
+
errors.push("collaboration event recordId is required");
|
|
5584
|
+
}
|
|
5585
|
+
if (!event.actorId.trim()) {
|
|
5586
|
+
errors.push("collaboration event actorId is required");
|
|
5587
|
+
}
|
|
5588
|
+
if (record) {
|
|
5589
|
+
if (record.id !== event.recordId) {
|
|
5590
|
+
errors.push("collaboration event recordId does not match the target record");
|
|
5591
|
+
}
|
|
5592
|
+
if (record.kind !== event.recordKind) {
|
|
5593
|
+
errors.push("collaboration event recordKind does not match the target record");
|
|
5594
|
+
}
|
|
5595
|
+
}
|
|
5596
|
+
if (event.kind === "answered" && event.recordKind !== "question") {
|
|
5597
|
+
errors.push("answered events only apply to questions");
|
|
5598
|
+
}
|
|
5599
|
+
if (event.kind === "declined" && event.recordKind !== "question") {
|
|
5600
|
+
errors.push("declined events only apply to questions");
|
|
5601
|
+
}
|
|
5602
|
+
if ((event.kind === "waiting" || event.kind === "progressed" || event.kind === "review_requested" || event.kind === "done" || event.kind === "cancelled") && event.recordKind !== "work_item") {
|
|
5603
|
+
errors.push(`${event.kind} events only apply to work items`);
|
|
5604
|
+
}
|
|
5605
|
+
return errors;
|
|
5606
|
+
}
|
|
5607
|
+
function assertValidCollaborationEvent(event, record) {
|
|
5608
|
+
const errors = validateCollaborationEvent(event, record);
|
|
5609
|
+
if (errors.length > 0) {
|
|
5610
|
+
throw new Error(errors.join("; "));
|
|
5611
|
+
}
|
|
5612
|
+
}
|
|
5613
|
+
|
|
5614
|
+
// packages/protocol/dist/messages.js
|
|
5615
|
+
var init_messages = () => {};
|
|
5616
|
+
|
|
5617
|
+
// packages/protocol/dist/invocations.js
|
|
5618
|
+
var init_invocations = () => {};
|
|
5619
|
+
|
|
5620
|
+
// packages/protocol/dist/scout-dispatch.js
|
|
5621
|
+
var init_scout_dispatch = () => {};
|
|
5622
|
+
|
|
5623
|
+
// packages/protocol/dist/deliveries.js
|
|
5624
|
+
var init_deliveries = () => {};
|
|
5625
|
+
|
|
5626
|
+
// packages/protocol/dist/transports.js
|
|
5627
|
+
var init_transports = () => {};
|
|
5628
|
+
|
|
5629
|
+
// packages/protocol/dist/events.js
|
|
5630
|
+
var init_events = () => {};
|
|
5631
|
+
|
|
5632
|
+
// packages/protocol/dist/thread-events.js
|
|
5633
|
+
var init_thread_events = () => {};
|
|
5634
|
+
|
|
5635
|
+
// packages/protocol/dist/index.js
|
|
5636
|
+
var init_dist2 = __esm(() => {
|
|
5637
|
+
init_common();
|
|
5638
|
+
init_actors();
|
|
5639
|
+
init_agent_identity();
|
|
5640
|
+
init_agent_address();
|
|
5641
|
+
init_agent_selectors();
|
|
5642
|
+
init_mesh();
|
|
5643
|
+
init_conversations();
|
|
5644
|
+
init_messages();
|
|
5645
|
+
init_invocations();
|
|
5646
|
+
init_scout_dispatch();
|
|
5647
|
+
init_deliveries();
|
|
5648
|
+
init_transports();
|
|
5649
|
+
init_events();
|
|
5650
|
+
init_thread_events();
|
|
5651
|
+
});
|
|
5652
|
+
|
|
5653
|
+
// packages/runtime/src/support-paths.ts
|
|
5654
|
+
import { existsSync as existsSync3, mkdirSync, rmSync, writeFileSync } from "fs";
|
|
5655
|
+
import { homedir as homedir4 } from "os";
|
|
4796
5656
|
import { join as join4 } from "path";
|
|
4797
5657
|
function resolveOpenScoutSupportPaths() {
|
|
4798
5658
|
const home = homedir4();
|
|
@@ -4842,9 +5702,9 @@ var init_support_paths = () => {};
|
|
|
4842
5702
|
// packages/runtime/src/harness-catalog.ts
|
|
4843
5703
|
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
4844
5704
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
4845
|
-
import { dirname as
|
|
5705
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
4846
5706
|
async function writeHarnessCatalogOverrides(overrides, overridePath = resolveOpenScoutSupportPaths().harnessCatalogPath) {
|
|
4847
|
-
await mkdir2(
|
|
5707
|
+
await mkdir2(dirname3(overridePath), { recursive: true });
|
|
4848
5708
|
const payload = {
|
|
4849
5709
|
version: HARNESS_CATALOG_VERSION,
|
|
4850
5710
|
entries: overrides,
|
|
@@ -4940,9 +5800,9 @@ var init_harness_catalog = __esm(() => {
|
|
|
4940
5800
|
// packages/runtime/src/user-project-hints.ts
|
|
4941
5801
|
import { readdir, readFile as readFile3, stat } from "fs/promises";
|
|
4942
5802
|
import { homedir as homedir5 } from "os";
|
|
4943
|
-
import { dirname as
|
|
5803
|
+
import { dirname as dirname4, join as join6, resolve as resolve2 } from "path";
|
|
4944
5804
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4945
|
-
function
|
|
5805
|
+
function decodeClaudeProjectsSlug3(name) {
|
|
4946
5806
|
if (!name || name === "." || name === "..") {
|
|
4947
5807
|
return null;
|
|
4948
5808
|
}
|
|
@@ -4967,7 +5827,7 @@ async function resolveExistingDirectoryHint(pathLike) {
|
|
|
4967
5827
|
return absolutePath;
|
|
4968
5828
|
}
|
|
4969
5829
|
if (info.isFile()) {
|
|
4970
|
-
return
|
|
5830
|
+
return dirname4(absolutePath);
|
|
4971
5831
|
}
|
|
4972
5832
|
} catch {
|
|
4973
5833
|
return null;
|
|
@@ -4994,7 +5854,7 @@ async function findLikelyProjectRoot(absolutePath) {
|
|
|
4994
5854
|
}
|
|
4995
5855
|
}
|
|
4996
5856
|
}
|
|
4997
|
-
const parent =
|
|
5857
|
+
const parent = dirname4(current);
|
|
4998
5858
|
if (parent === current) {
|
|
4999
5859
|
return lastCandidate ?? absolutePath;
|
|
5000
5860
|
}
|
|
@@ -5135,7 +5995,7 @@ async function appendCursorWorkspacePaths(home, roots) {
|
|
|
5135
5995
|
}
|
|
5136
5996
|
const wsRaw = await readFile3(wsFile, "utf8");
|
|
5137
5997
|
const wsDoc = JSON.parse(wsRaw);
|
|
5138
|
-
const wsDir =
|
|
5998
|
+
const wsDir = dirname4(wsFile);
|
|
5139
5999
|
for (const f of wsDoc.folders ?? []) {
|
|
5140
6000
|
if (typeof f.path !== "string" || !f.path) {
|
|
5141
6001
|
continue;
|
|
@@ -5156,7 +6016,7 @@ async function appendClaudeProjectSlugs(home, roots) {
|
|
|
5156
6016
|
return;
|
|
5157
6017
|
}
|
|
5158
6018
|
for (const name of names) {
|
|
5159
|
-
const decoded =
|
|
6019
|
+
const decoded = decodeClaudeProjectsSlug3(name);
|
|
5160
6020
|
if (!decoded) {
|
|
5161
6021
|
continue;
|
|
5162
6022
|
}
|
|
@@ -5292,7 +6152,7 @@ import { execFileSync } from "child_process";
|
|
|
5292
6152
|
import { existsSync as existsSync5, readFileSync } from "fs";
|
|
5293
6153
|
import { access as access2, mkdir as mkdir3, readdir as readdir2, readFile as readFile4, realpath, rm as rm2, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
5294
6154
|
import { homedir as homedir6, hostname, userInfo } from "os";
|
|
5295
|
-
import { basename as
|
|
6155
|
+
import { basename as basename3, dirname as dirname5, isAbsolute, join as join7, relative, resolve as resolve3 } from "path";
|
|
5296
6156
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
5297
6157
|
function titleCaseWords(value) {
|
|
5298
6158
|
return value.split(/[\s._-]+/).map((part) => part.trim()).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
@@ -5767,7 +6627,7 @@ async function readJsonFile(filePath) {
|
|
|
5767
6627
|
}
|
|
5768
6628
|
}
|
|
5769
6629
|
async function writeJsonFile(filePath, value) {
|
|
5770
|
-
await mkdir3(
|
|
6630
|
+
await mkdir3(dirname5(filePath), { recursive: true });
|
|
5771
6631
|
await writeFile3(filePath, JSON.stringify(value, null, 2) + `
|
|
5772
6632
|
`, "utf8");
|
|
5773
6633
|
}
|
|
@@ -6012,7 +6872,7 @@ function applyImportedEnvironmentSeeds(config, codexImport, projectRoot) {
|
|
|
6012
6872
|
...(config.environment?.actions?.length ?? 0) === 0 && importedEnvironment.actions ? { actions: importedEnvironment.actions } : {}
|
|
6013
6873
|
};
|
|
6014
6874
|
}
|
|
6015
|
-
const defaultProjectName = titleCase(
|
|
6875
|
+
const defaultProjectName = titleCase(basename3(projectRoot));
|
|
6016
6876
|
if (codexImport?.name?.trim() && (!config.project.name?.trim() || config.project.name === defaultProjectName)) {
|
|
6017
6877
|
next.project = {
|
|
6018
6878
|
...config.project,
|
|
@@ -6180,7 +7040,7 @@ async function seedWorkspaceRoots(options) {
|
|
|
6180
7040
|
const roots = new Set;
|
|
6181
7041
|
const currentProjectRoot = options.currentDirectory ? await findNearestProjectRoot(options.currentDirectory) : null;
|
|
6182
7042
|
if (currentProjectRoot) {
|
|
6183
|
-
roots.add(
|
|
7043
|
+
roots.add(dirname5(currentProjectRoot));
|
|
6184
7044
|
}
|
|
6185
7045
|
const legacyRoot = options.legacyRelayConfig?.projectRoot?.trim();
|
|
6186
7046
|
if (legacyRoot) {
|
|
@@ -6188,7 +7048,7 @@ async function seedWorkspaceRoots(options) {
|
|
|
6188
7048
|
}
|
|
6189
7049
|
for (const record of Object.values(options.legacyAgents ?? {})) {
|
|
6190
7050
|
if (record.cwd?.trim()) {
|
|
6191
|
-
roots.add(
|
|
7051
|
+
roots.add(dirname5(normalizePath(record.cwd)));
|
|
6192
7052
|
}
|
|
6193
7053
|
}
|
|
6194
7054
|
if (roots.size === 0) {
|
|
@@ -6279,7 +7139,7 @@ async function installScoutSkillToHarnesses() {
|
|
|
6279
7139
|
continue;
|
|
6280
7140
|
}
|
|
6281
7141
|
try {
|
|
6282
|
-
await mkdir3(
|
|
7142
|
+
await mkdir3(dirname5(target), { recursive: true });
|
|
6283
7143
|
await writeFile3(target, content, "utf8");
|
|
6284
7144
|
entries.push({ harness, target, status: "installed" });
|
|
6285
7145
|
} catch (error) {
|
|
@@ -6380,7 +7240,7 @@ async function findNearestProjectRoot(startDirectory) {
|
|
|
6380
7240
|
if (await pathExists2(projectConfigPath(current)) || await pathExists2(join7(current, "package.json")) || await pathExists2(join7(current, "AGENTS.md")) || await pathExists2(join7(current, "CLAUDE.md"))) {
|
|
6381
7241
|
lastCandidate = current;
|
|
6382
7242
|
}
|
|
6383
|
-
const parent =
|
|
7243
|
+
const parent = dirname5(current);
|
|
6384
7244
|
if (parent === current) {
|
|
6385
7245
|
return lastCandidate;
|
|
6386
7246
|
}
|
|
@@ -6388,7 +7248,7 @@ async function findNearestProjectRoot(startDirectory) {
|
|
|
6388
7248
|
}
|
|
6389
7249
|
}
|
|
6390
7250
|
function defaultProjectConfig(projectRoot, settings, preferredHarness) {
|
|
6391
|
-
const projectName =
|
|
7251
|
+
const projectName = basename3(projectRoot);
|
|
6392
7252
|
const definitionId = normalizeAgentId(projectName);
|
|
6393
7253
|
const relativeRoot = relative(projectRoot, projectRoot) || ".";
|
|
6394
7254
|
return {
|
|
@@ -6694,8 +7554,8 @@ function selectorFromInput(value) {
|
|
|
6694
7554
|
}
|
|
6695
7555
|
async function resolveManifestBackedAgent(projectRoot, config, settings, override) {
|
|
6696
7556
|
const resolvedProjectRoot = resolveProjectRootFromConfig(projectRoot, config);
|
|
6697
|
-
const projectName = config.project.name?.trim() || titleCase(config.project.id ||
|
|
6698
|
-
const fallbackDefinitionId = normalizeAgentId(config.project.id ||
|
|
7557
|
+
const projectName = config.project.name?.trim() || titleCase(config.project.id || basename3(resolvedProjectRoot));
|
|
7558
|
+
const fallbackDefinitionId = normalizeAgentId(config.project.id || basename3(resolvedProjectRoot));
|
|
6699
7559
|
const definitionId = normalizeAgentId(config.agent?.id || override?.definitionId || fallbackDefinitionId);
|
|
6700
7560
|
const detectedHarness = await detectPreferredHarness(resolvedProjectRoot, settings.agents.defaultHarness);
|
|
6701
7561
|
const runtimeDefaults = config.agent?.runtime?.defaults;
|
|
@@ -6732,7 +7592,7 @@ async function resolveManifestBackedAgent(projectRoot, config, settings, overrid
|
|
|
6732
7592
|
return mergeResolvedAgentConfig(base, override, settings);
|
|
6733
7593
|
}
|
|
6734
7594
|
async function resolveInferredAgent(projectRoot, settings, override) {
|
|
6735
|
-
const projectName =
|
|
7595
|
+
const projectName = basename3(projectRoot);
|
|
6736
7596
|
const definitionId = normalizeAgentId(override?.definitionId?.trim() || projectName);
|
|
6737
7597
|
const detectedHarness = await detectPreferredHarness(projectRoot, settings.agents.defaultHarness);
|
|
6738
7598
|
const defaultHarness = normalizeManagedHarness(override?.defaultHarness ?? override?.runtime?.harness, normalizeManagedHarness(detectedHarness, "claude"));
|
|
@@ -6768,7 +7628,7 @@ async function resolveInferredAgent(projectRoot, settings, override) {
|
|
|
6768
7628
|
return mergeResolvedAgentConfig(base, override, settings);
|
|
6769
7629
|
}
|
|
6770
7630
|
async function buildProjectInventoryEntry(agent, sourceRoot) {
|
|
6771
|
-
const manifestRoot = agent.projectConfigPath ? normalizePath(join7(
|
|
7631
|
+
const manifestRoot = agent.projectConfigPath ? normalizePath(join7(dirname5(agent.projectConfigPath), "..")) : null;
|
|
6772
7632
|
const manifest = manifestRoot ? await readProjectConfig(manifestRoot) : null;
|
|
6773
7633
|
const markers = await detectHarnessMarkers(agent.projectRoot);
|
|
6774
7634
|
const harnesses = new Map;
|
|
@@ -7067,7 +7927,7 @@ async function initializeOpenScoutSetup(options = {}) {
|
|
|
7067
7927
|
var SCOUT_AGENT_ID = "scout", SCOUT_PRIMARY_CONVERSATION_ID = "dm.scout.primary", MANAGED_AGENT_HARNESSES, DEFAULT_OPERATOR_NAME, DEFAULT_CAPABILITIES, DEFAULT_TRANSPORT = "claude_stream_json", DEFAULT_TELEGRAM_MODE = "polling", LEGACY_DEFAULT_TELEGRAM_CONVERSATION_ID = "channel.shared", DEFAULT_TELEGRAM_CONVERSATION_ID, SETTINGS_VERSION = 1, PROJECT_CONFIG_VERSION = 1, PROJECT_SCAN_SKIP_DIRECTORIES, PROJECT_STRONG_MARKERS, PROJECT_WEAK_MARKERS, PROJECT_HARNESS_MARKERS, PROJECT_STRONG_MARKERS_FLAT_NESTED, PROJECT_WEAK_MARKERS_FLAT_NESTED, GIT_BRANCH_CACHE_TTL_MS = 15000, gitBranchCache, SCOUT_SKILL_FILE_NAME = "SKILL.md", SETUP_MODULE_DIRECTORY, SCOUT_SKILL_REPO_ROOT, SCOUT_SKILL_INSTALL_PATHS, PROJECT_SCAN_MAX_DEPTH = 64;
|
|
7068
7928
|
var init_setup = __esm(() => {
|
|
7069
7929
|
init_dist();
|
|
7070
|
-
|
|
7930
|
+
init_dist2();
|
|
7071
7931
|
init_harness_catalog();
|
|
7072
7932
|
init_support_paths();
|
|
7073
7933
|
init_user_project_hints();
|
|
@@ -7161,7 +8021,7 @@ var init_setup = __esm(() => {
|
|
|
7161
8021
|
PROJECT_STRONG_MARKERS_FLAT_NESTED = partitionFlatAndNestedMarkers(PROJECT_STRONG_MARKERS);
|
|
7162
8022
|
PROJECT_WEAK_MARKERS_FLAT_NESTED = partitionFlatAndNestedMarkers(PROJECT_WEAK_MARKERS);
|
|
7163
8023
|
gitBranchCache = new Map;
|
|
7164
|
-
SETUP_MODULE_DIRECTORY =
|
|
8024
|
+
SETUP_MODULE_DIRECTORY = dirname5(fileURLToPath3(import.meta.url));
|
|
7165
8025
|
SCOUT_SKILL_REPO_ROOT = resolve3(SETUP_MODULE_DIRECTORY, "..", "..", "..");
|
|
7166
8026
|
SCOUT_SKILL_INSTALL_PATHS = {
|
|
7167
8027
|
claude: join7(homedir6(), ".claude", "skills", "scout", SCOUT_SKILL_FILE_NAME),
|
|
@@ -7246,7 +8106,7 @@ function updateBlockCompletion(blockState, completed) {
|
|
|
7246
8106
|
blockState.status = completed ? "completed" : "streaming";
|
|
7247
8107
|
blockState.block.status = completed ? "completed" : "streaming";
|
|
7248
8108
|
}
|
|
7249
|
-
function
|
|
8109
|
+
function parseQuestionAnswer2(value) {
|
|
7250
8110
|
if (Array.isArray(value)) {
|
|
7251
8111
|
return value.map((entry) => typeof entry === "string" ? entry.trim() : String(entry).trim()).filter(Boolean);
|
|
7252
8112
|
}
|
|
@@ -7564,7 +8424,7 @@ function buildClaudeStreamJsonSessionSnapshot(raw2, options, targetClaudeSession
|
|
|
7564
8424
|
if (blockState.block.type === "question") {
|
|
7565
8425
|
const questionBlock = blockState.block;
|
|
7566
8426
|
questionBlock.questionStatus = result.is_error ? "denied" : "answered";
|
|
7567
|
-
const answer =
|
|
8427
|
+
const answer = parseQuestionAnswer2(result.content);
|
|
7568
8428
|
questionBlock.answer = answer.length > 0 ? answer : undefined;
|
|
7569
8429
|
updateBlockCompletion(blockState, true);
|
|
7570
8430
|
continue;
|
|
@@ -7783,6 +8643,7 @@ class ClaudeStreamJsonSession {
|
|
|
7783
8643
|
await writeFile4(join13(this.options.runtimeDirectory, "prompt.txt"), this.options.systemPrompt);
|
|
7784
8644
|
this.claudeSessionId = await readOptionalFile2(this.sessionStatePath);
|
|
7785
8645
|
const args = [
|
|
8646
|
+
"--verbose",
|
|
7786
8647
|
"--print",
|
|
7787
8648
|
"--input-format",
|
|
7788
8649
|
"stream-json",
|
|
@@ -9576,7 +10437,7 @@ function buildInvocationCollaborationContextPrompt(invocation) {
|
|
|
9576
10437
|
import { spawnSync } from "child_process";
|
|
9577
10438
|
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
9578
10439
|
import { homedir as homedir11 } from "os";
|
|
9579
|
-
import { basename as
|
|
10440
|
+
import { basename as basename4, dirname as dirname10, join as join15, resolve as resolve5 } from "path";
|
|
9580
10441
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
9581
10442
|
function isTmpPath(p) {
|
|
9582
10443
|
return /^\/(?:private\/)?tmp\//.test(p);
|
|
@@ -9609,7 +10470,7 @@ function runtimePackageDir() {
|
|
|
9609
10470
|
const fromCwd = findWorkspaceRuntimeDir(process.cwd());
|
|
9610
10471
|
if (fromCwd)
|
|
9611
10472
|
return fromCwd;
|
|
9612
|
-
const moduleDir =
|
|
10473
|
+
const moduleDir = dirname10(fileURLToPath5(import.meta.url));
|
|
9613
10474
|
return resolve5(moduleDir, "..");
|
|
9614
10475
|
}
|
|
9615
10476
|
function isInstalledRuntimePackageDir(candidate) {
|
|
@@ -9647,7 +10508,7 @@ function findWorkspaceRuntimeDir(startDir) {
|
|
|
9647
10508
|
if (existsSync9(join15(candidate, "package.json")) && existsSync9(join15(candidate, "src"))) {
|
|
9648
10509
|
return candidate;
|
|
9649
10510
|
}
|
|
9650
|
-
const parent =
|
|
10511
|
+
const parent = dirname10(current);
|
|
9651
10512
|
if (parent === current)
|
|
9652
10513
|
return null;
|
|
9653
10514
|
current = parent;
|
|
@@ -9658,7 +10519,7 @@ function resolveBunExecutable2() {
|
|
|
9658
10519
|
if (explicit && explicit.trim().length > 0) {
|
|
9659
10520
|
return explicit;
|
|
9660
10521
|
}
|
|
9661
|
-
if (
|
|
10522
|
+
if (basename4(process.execPath).startsWith("bun") && existsSync9(process.execPath)) {
|
|
9662
10523
|
return process.execPath;
|
|
9663
10524
|
}
|
|
9664
10525
|
const pathEntries = (process.env.PATH ?? "").split(":").filter(Boolean);
|
|
@@ -9811,8 +10672,8 @@ function collectOptionalEnvVars(keys) {
|
|
|
9811
10672
|
}
|
|
9812
10673
|
function resolveLaunchAgentPATH() {
|
|
9813
10674
|
const entries = [
|
|
9814
|
-
...(process.env.PATH ?? "").split(":").filter(Boolean),
|
|
9815
10675
|
join15(homedir11(), ".bun", "bin"),
|
|
10676
|
+
...(process.env.PATH ?? "").split(":").filter(Boolean),
|
|
9816
10677
|
"/opt/homebrew/bin",
|
|
9817
10678
|
"/usr/local/bin",
|
|
9818
10679
|
"/usr/bin",
|
|
@@ -9826,7 +10687,7 @@ function xmlEscape(value) {
|
|
|
9826
10687
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
9827
10688
|
}
|
|
9828
10689
|
function ensureParentDirectory(filePath) {
|
|
9829
|
-
mkdirSync5(
|
|
10690
|
+
mkdirSync5(dirname10(filePath), { recursive: true });
|
|
9830
10691
|
}
|
|
9831
10692
|
function ensureServiceDirectories(config) {
|
|
9832
10693
|
ensureOpenScoutCleanSlateSync();
|
|
@@ -10083,7 +10944,7 @@ var DEFAULT_BROKER_HOST = "127.0.0.1", DEFAULT_BROKER_HOST_MESH = "0.0.0.0", DEF
|
|
|
10083
10944
|
var init_broker_service = __esm(async () => {
|
|
10084
10945
|
init_support_paths();
|
|
10085
10946
|
DEFAULT_BROKER_URL = buildDefaultBrokerUrl();
|
|
10086
|
-
if (process.argv[1] && fileURLToPath5(import.meta.url) === process.argv[1]) {
|
|
10947
|
+
if (process.argv[1] && fileURLToPath5(import.meta.url) === process.argv[1] && !process.argv[1].endsWith("/main.mjs")) {
|
|
10087
10948
|
await main();
|
|
10088
10949
|
}
|
|
10089
10950
|
});
|
|
@@ -10139,7 +11000,7 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
10139
11000
|
import { execFileSync as execFileSync2, execSync } from "child_process";
|
|
10140
11001
|
import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
|
|
10141
11002
|
import { mkdir as mkdir6, rm as rm5, stat as stat4, writeFile as writeFile6 } from "fs/promises";
|
|
10142
|
-
import { basename as
|
|
11003
|
+
import { basename as basename5, dirname as dirname11, join as join16, resolve as resolve6 } from "path";
|
|
10143
11004
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
10144
11005
|
function resolveRelayHub() {
|
|
10145
11006
|
return resolveOpenScoutSupportPaths().relayHubDirectory;
|
|
@@ -10151,13 +11012,13 @@ function resolveProjectsRoot(projectPath) {
|
|
|
10151
11012
|
try {
|
|
10152
11013
|
const supportPaths = resolveOpenScoutSupportPaths();
|
|
10153
11014
|
if (!existsSync10(supportPaths.settingsPath)) {
|
|
10154
|
-
return
|
|
11015
|
+
return dirname11(projectPath);
|
|
10155
11016
|
}
|
|
10156
11017
|
const raw2 = JSON.parse(readFileSync6(supportPaths.settingsPath, "utf8"));
|
|
10157
11018
|
const workspaceRoot = raw2.discovery?.workspaceRoots?.find((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
10158
|
-
return workspaceRoot ? resolve6(workspaceRoot) :
|
|
11019
|
+
return workspaceRoot ? resolve6(workspaceRoot) : dirname11(projectPath);
|
|
10159
11020
|
} catch {
|
|
10160
|
-
return
|
|
11021
|
+
return dirname11(projectPath);
|
|
10161
11022
|
}
|
|
10162
11023
|
}
|
|
10163
11024
|
function resolveBrokerUrl() {
|
|
@@ -10584,7 +11445,7 @@ function recordForHarness(record, harnessOverride) {
|
|
|
10584
11445
|
function normalizeLocalAgentRecord(agentId, record) {
|
|
10585
11446
|
const cwd = normalizeProjectPath(record.cwd || process.cwd());
|
|
10586
11447
|
const projectRoot = normalizeProjectPath(record.projectRoot || cwd);
|
|
10587
|
-
const project = record.project?.trim() ||
|
|
11448
|
+
const project = record.project?.trim() || basename5(projectRoot);
|
|
10588
11449
|
const definitionId = record.definitionId?.trim() || agentId;
|
|
10589
11450
|
const defaultHarness = activeLocalHarness(record);
|
|
10590
11451
|
const harnessProfiles = normalizeLocalHarnessProfiles(agentId, {
|
|
@@ -10649,7 +11510,7 @@ function localAgentRecordFromResolvedConfig(config) {
|
|
|
10649
11510
|
function localAgentRecordFromRelayAgentOverride(agentId, override) {
|
|
10650
11511
|
return normalizeLocalAgentRecord(agentId, {
|
|
10651
11512
|
definitionId: override.definitionId ?? agentId,
|
|
10652
|
-
project: override.projectName ??
|
|
11513
|
+
project: override.projectName ?? basename5(override.projectRoot || override.runtime?.cwd || agentId),
|
|
10653
11514
|
projectRoot: override.projectRoot ?? override.runtime?.cwd,
|
|
10654
11515
|
tmuxSession: override.runtime?.sessionId ?? `relay-${agentId}`,
|
|
10655
11516
|
cwd: override.runtime?.cwd ?? override.projectRoot,
|
|
@@ -11090,7 +11951,7 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
11090
11951
|
return normalizedRecord;
|
|
11091
11952
|
}
|
|
11092
11953
|
const projectPath = normalizedRecord.cwd;
|
|
11093
|
-
const projectName = normalizedRecord.project ||
|
|
11954
|
+
const projectName = normalizedRecord.project || basename5(projectPath);
|
|
11094
11955
|
const systemPromptTemplate = normalizedRecord.systemPrompt || buildLocalAgentSystemPromptTemplate();
|
|
11095
11956
|
const systemPrompt = renderLocalAgentSystemPromptTemplate(systemPromptTemplate, buildLocalAgentTemplateContext(agentName, projectName, projectPath), { transport: normalizedRecord.transport });
|
|
11096
11957
|
const agentRuntimeDir = relayAgentRuntimeDirectory(agentName);
|
|
@@ -11312,7 +12173,7 @@ async function resolveLocalAgentIdentity(input) {
|
|
|
11312
12173
|
nodeQualifier: instance2.nodeQualifier,
|
|
11313
12174
|
harness: normalizeManagedHarness2(preferredHarness ?? override.defaultHarness, "claude"),
|
|
11314
12175
|
projectRoot: normalizeProjectPath(override.projectRoot),
|
|
11315
|
-
projectName: override.projectName ??
|
|
12176
|
+
projectName: override.projectName ?? basename5(override.projectRoot),
|
|
11316
12177
|
source: "existing"
|
|
11317
12178
|
};
|
|
11318
12179
|
}
|
|
@@ -11331,12 +12192,12 @@ async function resolveLocalAgentIdentity(input) {
|
|
|
11331
12192
|
nodeQualifier: instance2.nodeQualifier,
|
|
11332
12193
|
harness: normalizeManagedHarness2(preferredHarness ?? override.defaultHarness, "claude"),
|
|
11333
12194
|
projectRoot: normalizeProjectPath(override.projectRoot),
|
|
11334
|
-
projectName: override.projectName ??
|
|
12195
|
+
projectName: override.projectName ?? basename5(override.projectRoot),
|
|
11335
12196
|
source: "existing"
|
|
11336
12197
|
};
|
|
11337
12198
|
}
|
|
11338
12199
|
const configDefinitionId = config?.agent?.id?.trim() ? normalizeAgentSelectorSegment(config.agent.id.trim()) : "";
|
|
11339
|
-
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(
|
|
12200
|
+
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename5(projectRoot)) || "agent";
|
|
11340
12201
|
const configDisplayName = config?.agent?.displayName?.trim() || "";
|
|
11341
12202
|
const displayName = input.displayName || configDisplayName || titleCaseLocalAgentName(definitionId);
|
|
11342
12203
|
const instance = buildRelayAgentInstance(definitionId, projectRoot);
|
|
@@ -11350,7 +12211,7 @@ async function resolveLocalAgentIdentity(input) {
|
|
|
11350
12211
|
nodeQualifier: instance.nodeQualifier,
|
|
11351
12212
|
harness: effectiveHarness,
|
|
11352
12213
|
projectRoot,
|
|
11353
|
-
projectName:
|
|
12214
|
+
projectName: basename5(projectRoot),
|
|
11354
12215
|
source: configDefinitionId || configDisplayName ? "config" : "new"
|
|
11355
12216
|
};
|
|
11356
12217
|
}
|
|
@@ -11406,7 +12267,7 @@ async function startLocalAgent(input) {
|
|
|
11406
12267
|
}
|
|
11407
12268
|
if (!matchingOverride) {
|
|
11408
12269
|
const configDefinitionId = coldProjectConfig?.agent?.id?.trim() ? normalizeAgentSelectorSegment(coldProjectConfig.agent.id.trim()) : "";
|
|
11409
|
-
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(
|
|
12270
|
+
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename5(projectRoot)) || "agent";
|
|
11410
12271
|
const configDisplayName = coldProjectConfig?.agent?.displayName?.trim() || "";
|
|
11411
12272
|
const effectiveDisplayName = input.displayName || configDisplayName || titleCaseLocalAgentName(definitionId);
|
|
11412
12273
|
const instance = buildRelayAgentInstance(definitionId, projectRoot);
|
|
@@ -11422,7 +12283,7 @@ async function startLocalAgent(input) {
|
|
|
11422
12283
|
agentId: instance.id,
|
|
11423
12284
|
definitionId,
|
|
11424
12285
|
displayName: effectiveDisplayName,
|
|
11425
|
-
projectName:
|
|
12286
|
+
projectName: basename5(projectRoot),
|
|
11426
12287
|
projectRoot,
|
|
11427
12288
|
projectConfigPath: coldProjectConfigPath,
|
|
11428
12289
|
source: "manual",
|
|
@@ -11458,7 +12319,7 @@ async function startLocalAgent(input) {
|
|
|
11458
12319
|
agentId: instance.id,
|
|
11459
12320
|
definitionId: requestedDefinitionId,
|
|
11460
12321
|
displayName: input.displayName || titleCaseLocalAgentName(requestedDefinitionId),
|
|
11461
|
-
projectName: matchingOverride.projectName ??
|
|
12322
|
+
projectName: matchingOverride.projectName ?? basename5(matchingProjectRoot),
|
|
11462
12323
|
projectRoot: matchingProjectRoot,
|
|
11463
12324
|
projectConfigPath: matchingOverride.projectConfigPath ?? null,
|
|
11464
12325
|
source: "manual",
|
|
@@ -11763,7 +12624,7 @@ async function invokeLocalAgentEndpoint(endpoint, invocation) {
|
|
|
11763
12624
|
const requestedHarness = invocation.execution?.harness;
|
|
11764
12625
|
const record = existing ?? (projectRoot ? {
|
|
11765
12626
|
definitionId,
|
|
11766
|
-
project:
|
|
12627
|
+
project: basename5(projectRoot),
|
|
11767
12628
|
projectRoot,
|
|
11768
12629
|
tmuxSession: String(endpoint.metadata?.tmuxSession ?? `relay-${agentRuntimeId}`),
|
|
11769
12630
|
cwd: projectRoot,
|
|
@@ -11836,27 +12697,27 @@ function shouldDisableGeneratedCodexEndpoint(endpoint) {
|
|
|
11836
12697
|
}
|
|
11837
12698
|
var MODULE_DIRECTORY, OPENSCOUT_REPO_ROOT, DEFAULT_LOCAL_AGENT_CAPABILITIES, DEFAULT_LOCAL_AGENT_HARNESS = "claude", SUPPORTED_LOCAL_AGENT_HARNESSES;
|
|
11838
12699
|
var init_local_agents = __esm(async () => {
|
|
11839
|
-
|
|
12700
|
+
init_dist2();
|
|
11840
12701
|
init_claude_stream_json();
|
|
11841
12702
|
init_codex_app_server();
|
|
11842
12703
|
init_setup();
|
|
11843
12704
|
init_support_paths();
|
|
11844
12705
|
init_local_agent_template();
|
|
11845
12706
|
await init_broker_service();
|
|
11846
|
-
MODULE_DIRECTORY =
|
|
12707
|
+
MODULE_DIRECTORY = dirname11(fileURLToPath6(import.meta.url));
|
|
11847
12708
|
OPENSCOUT_REPO_ROOT = resolve6(MODULE_DIRECTORY, "..", "..", "..");
|
|
11848
12709
|
DEFAULT_LOCAL_AGENT_CAPABILITIES = ["chat", "invoke", "deliver"];
|
|
11849
12710
|
SUPPORTED_LOCAL_AGENT_HARNESSES = ["claude", "codex"];
|
|
11850
12711
|
});
|
|
11851
12712
|
|
|
11852
12713
|
// packages/web/server/index.ts
|
|
11853
|
-
import { existsSync as
|
|
11854
|
-
import { dirname as
|
|
12714
|
+
import { existsSync as existsSync14 } from "fs";
|
|
12715
|
+
import { dirname as dirname13, join as join21, resolve as resolve10 } from "path";
|
|
11855
12716
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
11856
12717
|
|
|
11857
12718
|
// packages/web/server/create-openscout-web-server.ts
|
|
11858
|
-
import { existsSync as
|
|
11859
|
-
import { dirname as
|
|
12719
|
+
import { existsSync as existsSync12, rmSync as rmSync3 } from "fs";
|
|
12720
|
+
import { dirname as dirname12, resolve as resolve9 } from "path";
|
|
11860
12721
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
11861
12722
|
|
|
11862
12723
|
// node_modules/.bun/hono@4.12.10/node_modules/hono/dist/compose.js
|
|
@@ -13412,7 +14273,7 @@ import {
|
|
|
13412
14273
|
writeFileSync as writeFileSync3
|
|
13413
14274
|
} from "fs";
|
|
13414
14275
|
import { homedir as homedir8 } from "os";
|
|
13415
|
-
import { dirname as
|
|
14276
|
+
import { dirname as dirname7, join as join9, resolve as resolve4 } from "path";
|
|
13416
14277
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13417
14278
|
|
|
13418
14279
|
// packages/runtime/src/local-config.ts
|
|
@@ -13424,7 +14285,7 @@ import {
|
|
|
13424
14285
|
writeFileSync as writeFileSync2
|
|
13425
14286
|
} from "fs";
|
|
13426
14287
|
import { homedir as homedir7 } from "os";
|
|
13427
|
-
import { dirname as
|
|
14288
|
+
import { dirname as dirname6, join as join8 } from "path";
|
|
13428
14289
|
var LOCAL_CONFIG_VERSION = 1;
|
|
13429
14290
|
var DEFAULT_LOCAL_CONFIG = {
|
|
13430
14291
|
version: LOCAL_CONFIG_VERSION,
|
|
@@ -13478,7 +14339,7 @@ function isValidPort(value) {
|
|
|
13478
14339
|
}
|
|
13479
14340
|
function writeLocalConfig(config) {
|
|
13480
14341
|
const configPath = localConfigPath();
|
|
13481
|
-
mkdirSync2(
|
|
14342
|
+
mkdirSync2(dirname6(configPath), { recursive: true });
|
|
13482
14343
|
const body = JSON.stringify({ ...config, version: LOCAL_CONFIG_VERSION }, null, 2) + `
|
|
13483
14344
|
`;
|
|
13484
14345
|
const tmp = `${configPath}.tmp`;
|
|
@@ -13938,7 +14799,7 @@ function resolveScoutPairingRuntimeScriptPath() {
|
|
|
13938
14799
|
throw new Error("Unable to locate the Scout pair supervisor entrypoint.");
|
|
13939
14800
|
}
|
|
13940
14801
|
function resolveOpenScoutWebServerDirectory(moduleUrl = import.meta.url) {
|
|
13941
|
-
return
|
|
14802
|
+
return dirname7(fileURLToPath4(moduleUrl));
|
|
13942
14803
|
}
|
|
13943
14804
|
function resolveOpenScoutWebPackageRoot(moduleUrl = import.meta.url) {
|
|
13944
14805
|
return resolve4(resolveOpenScoutWebServerDirectory(moduleUrl), "..");
|
|
@@ -14096,6 +14957,17 @@ async function getScoutWebPairingState(currentDirectory) {
|
|
|
14096
14957
|
async function refreshScoutWebPairingState(currentDirectory) {
|
|
14097
14958
|
return readScoutPairingState(currentDirectory);
|
|
14098
14959
|
}
|
|
14960
|
+
async function getScoutWebPairingSessionSnapshot(sessionId) {
|
|
14961
|
+
if (!isScoutPairingRuntimeRunning()) {
|
|
14962
|
+
return null;
|
|
14963
|
+
}
|
|
14964
|
+
const resolvedConfig = resolveScoutPairingConfig();
|
|
14965
|
+
try {
|
|
14966
|
+
return await withScoutPairingBridgeClient(resolvedConfig.port, async (client) => client.query("session.snapshot", { sessionId }));
|
|
14967
|
+
} catch {
|
|
14968
|
+
return null;
|
|
14969
|
+
}
|
|
14970
|
+
}
|
|
14099
14971
|
async function controlScoutWebPairingService(action, currentDirectory) {
|
|
14100
14972
|
return serializePairingMutation(async () => {
|
|
14101
14973
|
switch (action) {
|
|
@@ -14634,7 +15506,7 @@ import { join as join12 } from "path";
|
|
|
14634
15506
|
// packages/runtime/src/user-config.ts
|
|
14635
15507
|
import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
14636
15508
|
import { homedir as homedir9 } from "os";
|
|
14637
|
-
import { dirname as
|
|
15509
|
+
import { dirname as dirname9, join as join11 } from "path";
|
|
14638
15510
|
function userConfigPath() {
|
|
14639
15511
|
return join11(process.env.OPENSCOUT_HOME ?? join11(homedir9(), ".openscout"), "user.json");
|
|
14640
15512
|
}
|
|
@@ -14650,7 +15522,7 @@ function loadUserConfig() {
|
|
|
14650
15522
|
}
|
|
14651
15523
|
function saveUserConfig(config) {
|
|
14652
15524
|
const configPath = userConfigPath();
|
|
14653
|
-
mkdirSync4(
|
|
15525
|
+
mkdirSync4(dirname9(configPath), { recursive: true });
|
|
14654
15526
|
writeFileSync4(configPath, JSON.stringify(config, null, 2) + `
|
|
14655
15527
|
`, "utf8");
|
|
14656
15528
|
}
|
|
@@ -15433,7 +16305,10 @@ function querySessions(limit = 80) {
|
|
|
15433
16305
|
a.id AS agent_id,
|
|
15434
16306
|
ac.display_name,
|
|
15435
16307
|
ep.harness,
|
|
16308
|
+
ep.transport,
|
|
15436
16309
|
ep.project_root,
|
|
16310
|
+
ep.session_id,
|
|
16311
|
+
ep.metadata_json AS endpoint_metadata_json,
|
|
15437
16312
|
a.metadata_json
|
|
15438
16313
|
FROM conversation_members cm
|
|
15439
16314
|
JOIN agents a ON a.id = cm.actor_id
|
|
@@ -15456,6 +16331,8 @@ function querySessions(limit = 80) {
|
|
|
15456
16331
|
const stats = statsStmt.get(r.id);
|
|
15457
16332
|
let agentName = null;
|
|
15458
16333
|
let harness = null;
|
|
16334
|
+
let harnessSessionId = null;
|
|
16335
|
+
let harnessLogPath = null;
|
|
15459
16336
|
let branch = null;
|
|
15460
16337
|
let workspaceRoot = null;
|
|
15461
16338
|
if (primaryAgent) {
|
|
@@ -15469,6 +16346,14 @@ function querySessions(limit = 80) {
|
|
|
15469
16346
|
}
|
|
15470
16347
|
branch = meta.branch ?? meta.workspaceQualifier ?? null;
|
|
15471
16348
|
} catch {}
|
|
16349
|
+
try {
|
|
16350
|
+
const endpointMeta = primaryAgent.endpoint_metadata_json ? JSON.parse(primaryAgent.endpoint_metadata_json) : {};
|
|
16351
|
+
harnessSessionId = resolveHarnessSessionId(primaryAgent.transport, primaryAgent.session_id, endpointMeta);
|
|
16352
|
+
harnessLogPath = resolveHarnessLogPath(primaryAgent.agent_id, primaryAgent.transport, primaryAgent.session_id, endpointMeta);
|
|
16353
|
+
} catch {
|
|
16354
|
+
harnessSessionId = resolveHarnessSessionId(primaryAgent.transport, primaryAgent.session_id, undefined);
|
|
16355
|
+
harnessLogPath = resolveHarnessLogPath(primaryAgent.agent_id, primaryAgent.transport, primaryAgent.session_id, undefined);
|
|
16356
|
+
}
|
|
15472
16357
|
}
|
|
15473
16358
|
const preview = previewStmt.get(r.id)?.body ?? null;
|
|
15474
16359
|
return [{
|
|
@@ -15479,6 +16364,8 @@ function querySessions(limit = 80) {
|
|
|
15479
16364
|
agentId,
|
|
15480
16365
|
agentName,
|
|
15481
16366
|
harness,
|
|
16367
|
+
harnessSessionId,
|
|
16368
|
+
harnessLogPath,
|
|
15482
16369
|
currentBranch: branch,
|
|
15483
16370
|
preview: preview ? preview.slice(0, 200) : null,
|
|
15484
16371
|
messageCount: stats?.cnt ?? 0,
|
|
@@ -15576,23 +16463,30 @@ function parseDirectConversationId(conversationId) {
|
|
|
15576
16463
|
}
|
|
15577
16464
|
function synthesizeDirectSession(conversationId, agentId, operatorId) {
|
|
15578
16465
|
const agent = db().prepare(`SELECT
|
|
15579
|
-
|
|
15580
|
-
|
|
15581
|
-
|
|
15582
|
-
|
|
15583
|
-
|
|
15584
|
-
|
|
15585
|
-
|
|
15586
|
-
|
|
15587
|
-
|
|
16466
|
+
a.id AS agent_id,
|
|
16467
|
+
ac.display_name,
|
|
16468
|
+
ep.harness,
|
|
16469
|
+
ep.transport,
|
|
16470
|
+
ep.project_root,
|
|
16471
|
+
ep.session_id,
|
|
16472
|
+
ep.metadata_json AS endpoint_metadata_json,
|
|
16473
|
+
a.metadata_json
|
|
16474
|
+
FROM agents a
|
|
16475
|
+
JOIN actors ac ON ac.id = a.id
|
|
16476
|
+
${LATEST_AGENT_ENDPOINT_JOIN}
|
|
16477
|
+
WHERE a.id = ?`).get(agentId);
|
|
15588
16478
|
if (!agent) {
|
|
15589
16479
|
return null;
|
|
15590
16480
|
}
|
|
15591
16481
|
let currentBranch = null;
|
|
16482
|
+
let endpointMeta = {};
|
|
15592
16483
|
try {
|
|
15593
16484
|
const metadata = agent.metadata_json ? JSON.parse(agent.metadata_json) : {};
|
|
15594
16485
|
currentBranch = metadata.branch ?? metadata.workspaceQualifier ?? null;
|
|
15595
16486
|
} catch {}
|
|
16487
|
+
try {
|
|
16488
|
+
endpointMeta = agent.endpoint_metadata_json ? JSON.parse(agent.endpoint_metadata_json) : {};
|
|
16489
|
+
} catch {}
|
|
15596
16490
|
return {
|
|
15597
16491
|
id: conversationId,
|
|
15598
16492
|
kind: "direct",
|
|
@@ -15601,6 +16495,8 @@ function synthesizeDirectSession(conversationId, agentId, operatorId) {
|
|
|
15601
16495
|
agentId,
|
|
15602
16496
|
agentName: agent.display_name,
|
|
15603
16497
|
harness: agent.harness,
|
|
16498
|
+
harnessSessionId: resolveHarnessSessionId(agent.transport, agent.session_id, endpointMeta),
|
|
16499
|
+
harnessLogPath: resolveHarnessLogPath(agentId, agent.transport, agent.session_id, endpointMeta),
|
|
15604
16500
|
currentBranch,
|
|
15605
16501
|
preview: null,
|
|
15606
16502
|
messageCount: 0,
|
|
@@ -15977,11 +16873,11 @@ function queryHeartrate(numBuckets = 48) {
|
|
|
15977
16873
|
}
|
|
15978
16874
|
|
|
15979
16875
|
// packages/web/server/core/broker/service.ts
|
|
15980
|
-
|
|
16876
|
+
init_dist2();
|
|
15981
16877
|
init_setup();
|
|
15982
16878
|
init_support_paths();
|
|
15983
16879
|
await init_local_agents();
|
|
15984
|
-
import { basename as
|
|
16880
|
+
import { basename as basename6, join as join17, resolve as resolve7 } from "path";
|
|
15985
16881
|
|
|
15986
16882
|
// packages/web/server/core/broker/paths.ts
|
|
15987
16883
|
var scoutBrokerPaths = {
|
|
@@ -16898,131 +17794,2909 @@ function whoEntryState(endpoints, registrationKind) {
|
|
|
16898
17794
|
}, "offline");
|
|
16899
17795
|
}
|
|
16900
17796
|
|
|
16901
|
-
// packages/web/server/core/
|
|
16902
|
-
|
|
17797
|
+
// packages/web/server/core/observe/service.ts
|
|
17798
|
+
init_src();
|
|
17799
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7, statSync as statSync4 } from "fs";
|
|
17800
|
+
import { homedir as homedir12 } from "os";
|
|
17801
|
+
import { join as join18, resolve as resolve8 } from "path";
|
|
16903
17802
|
|
|
16904
|
-
// packages/runtime/src/
|
|
16905
|
-
|
|
16906
|
-
|
|
16907
|
-
|
|
16908
|
-
|
|
16909
|
-
|
|
16910
|
-
|
|
17803
|
+
// packages/runtime/src/registry.ts
|
|
17804
|
+
function createRuntimeRegistrySnapshot(value = {}) {
|
|
17805
|
+
return {
|
|
17806
|
+
nodes: value.nodes ?? {},
|
|
17807
|
+
actors: value.actors ?? {},
|
|
17808
|
+
agents: value.agents ?? {},
|
|
17809
|
+
endpoints: value.endpoints ?? {},
|
|
17810
|
+
conversations: value.conversations ?? {},
|
|
17811
|
+
bindings: value.bindings ?? {},
|
|
17812
|
+
messages: value.messages ?? {},
|
|
17813
|
+
flights: value.flights ?? {},
|
|
17814
|
+
collaborationRecords: value.collaborationRecords ?? {}
|
|
17815
|
+
};
|
|
16911
17816
|
}
|
|
16912
|
-
|
|
16913
|
-
|
|
16914
|
-
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
online: peer.Online ?? false,
|
|
16920
|
-
hostName: peer.HostName,
|
|
16921
|
-
os: peer.OS,
|
|
16922
|
-
tags: peer.Tags ?? []
|
|
16923
|
-
}));
|
|
17817
|
+
|
|
17818
|
+
// packages/runtime/src/index.ts
|
|
17819
|
+
init_harness_catalog();
|
|
17820
|
+
|
|
17821
|
+
// packages/runtime/src/planner.ts
|
|
17822
|
+
function createDeliveryId(messageId, targetId, reason, transport) {
|
|
17823
|
+
return `del-${messageId}-${targetId}-${reason}-${transport}`;
|
|
16924
17824
|
}
|
|
16925
|
-
function
|
|
16926
|
-
|
|
16927
|
-
|
|
16928
|
-
|
|
17825
|
+
function unique(values) {
|
|
17826
|
+
return [...new Set(values)];
|
|
17827
|
+
}
|
|
17828
|
+
function resolveVisibilityAudience(message, conversation) {
|
|
17829
|
+
if (message.audience?.visibleTo?.length) {
|
|
17830
|
+
return unique(message.audience.visibleTo);
|
|
16929
17831
|
}
|
|
17832
|
+
return unique(conversation.participantIds.filter((participantId) => participantId !== message.actorId));
|
|
17833
|
+
}
|
|
17834
|
+
function resolveNotifyAudience(message) {
|
|
17835
|
+
const fromMentions = (message.mentions ?? []).map((mention) => mention.actorId);
|
|
17836
|
+
const explicit = message.audience?.notify ?? [];
|
|
17837
|
+
return unique([...fromMentions, ...explicit].filter((actorId) => actorId !== message.actorId));
|
|
17838
|
+
}
|
|
17839
|
+
function resolveInvocationAudience(message) {
|
|
17840
|
+
return unique((message.audience?.invoke ?? []).filter((actorId) => actorId !== message.actorId));
|
|
17841
|
+
}
|
|
17842
|
+
function planTargetDelivery(message, route, reason, policy) {
|
|
16930
17843
|
return {
|
|
16931
|
-
id:
|
|
16932
|
-
|
|
16933
|
-
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
|
|
16937
|
-
|
|
16938
|
-
|
|
16939
|
-
|
|
17844
|
+
id: createDeliveryId(message.id, route.targetId, reason, route.transport),
|
|
17845
|
+
messageId: message.id,
|
|
17846
|
+
targetId: route.targetId,
|
|
17847
|
+
targetNodeId: route.nodeId,
|
|
17848
|
+
targetKind: route.targetKind,
|
|
17849
|
+
transport: route.transport,
|
|
17850
|
+
reason,
|
|
17851
|
+
policy,
|
|
17852
|
+
status: "pending",
|
|
17853
|
+
bindingId: route.bindingId
|
|
16940
17854
|
};
|
|
16941
17855
|
}
|
|
16942
|
-
|
|
16943
|
-
const
|
|
16944
|
-
|
|
17856
|
+
function planMessageDeliveries(input) {
|
|
17857
|
+
const visibilityIds = new Set(resolveVisibilityAudience(input.message, input.conversation));
|
|
17858
|
+
const notifyIds = new Set(resolveNotifyAudience(input.message));
|
|
17859
|
+
const invokeIds = new Set(resolveInvocationAudience(input.message));
|
|
17860
|
+
const deliveries2 = new Map;
|
|
17861
|
+
for (const route of input.participantRoutes) {
|
|
17862
|
+
if (visibilityIds.has(route.targetId)) {
|
|
17863
|
+
const intent = planTargetDelivery(input.message, {
|
|
17864
|
+
...route,
|
|
17865
|
+
transport: route.nodeId && input.localNodeId && route.nodeId !== input.localNodeId ? "peer_broker" : route.transport
|
|
17866
|
+
}, input.conversation.kind === "direct" || input.conversation.kind === "group_direct" ? "direct_message" : "conversation_visibility", "durable");
|
|
17867
|
+
deliveries2.set(intent.id, intent);
|
|
17868
|
+
}
|
|
17869
|
+
if (notifyIds.has(route.targetId)) {
|
|
17870
|
+
const intent = planTargetDelivery(input.message, {
|
|
17871
|
+
...route,
|
|
17872
|
+
transport: route.nodeId && input.localNodeId && route.nodeId !== input.localNodeId ? "peer_broker" : route.transport
|
|
17873
|
+
}, "mention", "must_ack");
|
|
17874
|
+
deliveries2.set(intent.id, intent);
|
|
17875
|
+
}
|
|
17876
|
+
if (invokeIds.has(route.targetId)) {
|
|
17877
|
+
const intent = planTargetDelivery(input.message, {
|
|
17878
|
+
...route,
|
|
17879
|
+
transport: route.nodeId && input.localNodeId && route.nodeId !== input.localNodeId ? "peer_broker" : route.transport
|
|
17880
|
+
}, "invocation", "must_ack");
|
|
17881
|
+
deliveries2.set(intent.id, intent);
|
|
17882
|
+
}
|
|
17883
|
+
if (input.message.speech?.text && route.speechEnabled) {
|
|
17884
|
+
const speechIntent = planTargetDelivery(input.message, {
|
|
17885
|
+
...route,
|
|
17886
|
+
transport: route.transport === "local_socket" ? "native_voice" : "tts",
|
|
17887
|
+
targetKind: route.targetKind === "device" ? "voice_session" : route.targetKind
|
|
17888
|
+
}, "speech", "best_effort");
|
|
17889
|
+
deliveries2.set(speechIntent.id, speechIntent);
|
|
17890
|
+
}
|
|
17891
|
+
}
|
|
17892
|
+
for (const route of input.bindingRoutes ?? []) {
|
|
17893
|
+
const intent = planTargetDelivery(input.message, route, "bridge_outbound", "durable");
|
|
17894
|
+
deliveries2.set(intent.id, intent);
|
|
17895
|
+
}
|
|
17896
|
+
return [...deliveries2.values()];
|
|
17897
|
+
}
|
|
17898
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/entity.js
|
|
17899
|
+
var entityKind = Symbol.for("drizzle:entityKind");
|
|
17900
|
+
var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
|
|
17901
|
+
function is(value, type) {
|
|
17902
|
+
if (!value || typeof value !== "object") {
|
|
17903
|
+
return false;
|
|
17904
|
+
}
|
|
17905
|
+
if (value instanceof type) {
|
|
17906
|
+
return true;
|
|
17907
|
+
}
|
|
17908
|
+
if (!Object.prototype.hasOwnProperty.call(type, entityKind)) {
|
|
17909
|
+
throw new Error(`Class "${type.name ?? "<unknown>"}" doesn't look like a Drizzle entity. If this is incorrect and the class is provided by Drizzle, please report this as a bug.`);
|
|
17910
|
+
}
|
|
17911
|
+
let cls = Object.getPrototypeOf(value).constructor;
|
|
17912
|
+
if (cls) {
|
|
17913
|
+
while (cls) {
|
|
17914
|
+
if (entityKind in cls && cls[entityKind] === type[entityKind]) {
|
|
17915
|
+
return true;
|
|
17916
|
+
}
|
|
17917
|
+
cls = Object.getPrototypeOf(cls);
|
|
17918
|
+
}
|
|
17919
|
+
}
|
|
17920
|
+
return false;
|
|
16945
17921
|
}
|
|
16946
|
-
|
|
16947
|
-
|
|
16948
|
-
|
|
16949
|
-
|
|
17922
|
+
|
|
17923
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/column.js
|
|
17924
|
+
class Column {
|
|
17925
|
+
constructor(table, config) {
|
|
17926
|
+
this.table = table;
|
|
17927
|
+
this.config = config;
|
|
17928
|
+
this.name = config.name;
|
|
17929
|
+
this.keyAsName = config.keyAsName;
|
|
17930
|
+
this.notNull = config.notNull;
|
|
17931
|
+
this.default = config.default;
|
|
17932
|
+
this.defaultFn = config.defaultFn;
|
|
17933
|
+
this.onUpdateFn = config.onUpdateFn;
|
|
17934
|
+
this.hasDefault = config.hasDefault;
|
|
17935
|
+
this.primary = config.primaryKey;
|
|
17936
|
+
this.isUnique = config.isUnique;
|
|
17937
|
+
this.uniqueName = config.uniqueName;
|
|
17938
|
+
this.uniqueType = config.uniqueType;
|
|
17939
|
+
this.dataType = config.dataType;
|
|
17940
|
+
this.columnType = config.columnType;
|
|
17941
|
+
this.generated = config.generated;
|
|
17942
|
+
this.generatedIdentity = config.generatedIdentity;
|
|
17943
|
+
}
|
|
17944
|
+
static [entityKind] = "Column";
|
|
17945
|
+
name;
|
|
17946
|
+
keyAsName;
|
|
17947
|
+
primary;
|
|
17948
|
+
notNull;
|
|
17949
|
+
default;
|
|
17950
|
+
defaultFn;
|
|
17951
|
+
onUpdateFn;
|
|
17952
|
+
hasDefault;
|
|
17953
|
+
isUnique;
|
|
17954
|
+
uniqueName;
|
|
17955
|
+
uniqueType;
|
|
17956
|
+
dataType;
|
|
17957
|
+
columnType;
|
|
17958
|
+
enumValues = undefined;
|
|
17959
|
+
generated = undefined;
|
|
17960
|
+
generatedIdentity = undefined;
|
|
17961
|
+
config;
|
|
17962
|
+
mapFromDriverValue(value) {
|
|
17963
|
+
return value;
|
|
16950
17964
|
}
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
16955
|
-
|
|
16956
|
-
return null;
|
|
17965
|
+
mapToDriverValue(value) {
|
|
17966
|
+
return value;
|
|
17967
|
+
}
|
|
17968
|
+
shouldDisableInsert() {
|
|
17969
|
+
return this.config.generated !== undefined && this.config.generated.type !== "byDefault";
|
|
16957
17970
|
}
|
|
16958
17971
|
}
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
|
|
17972
|
+
|
|
17973
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/column-builder.js
|
|
17974
|
+
class ColumnBuilder {
|
|
17975
|
+
static [entityKind] = "ColumnBuilder";
|
|
17976
|
+
config;
|
|
17977
|
+
constructor(name, dataType, columnType) {
|
|
17978
|
+
this.config = {
|
|
17979
|
+
name,
|
|
17980
|
+
keyAsName: name === "",
|
|
17981
|
+
notNull: false,
|
|
17982
|
+
default: undefined,
|
|
17983
|
+
hasDefault: false,
|
|
17984
|
+
primaryKey: false,
|
|
17985
|
+
isUnique: false,
|
|
17986
|
+
uniqueName: undefined,
|
|
17987
|
+
uniqueType: undefined,
|
|
17988
|
+
dataType,
|
|
17989
|
+
columnType,
|
|
17990
|
+
generated: undefined
|
|
17991
|
+
};
|
|
17992
|
+
}
|
|
17993
|
+
$type() {
|
|
17994
|
+
return this;
|
|
17995
|
+
}
|
|
17996
|
+
notNull() {
|
|
17997
|
+
this.config.notNull = true;
|
|
17998
|
+
return this;
|
|
17999
|
+
}
|
|
18000
|
+
default(value) {
|
|
18001
|
+
this.config.default = value;
|
|
18002
|
+
this.config.hasDefault = true;
|
|
18003
|
+
return this;
|
|
18004
|
+
}
|
|
18005
|
+
$defaultFn(fn) {
|
|
18006
|
+
this.config.defaultFn = fn;
|
|
18007
|
+
this.config.hasDefault = true;
|
|
18008
|
+
return this;
|
|
18009
|
+
}
|
|
18010
|
+
$default = this.$defaultFn;
|
|
18011
|
+
$onUpdateFn(fn) {
|
|
18012
|
+
this.config.onUpdateFn = fn;
|
|
18013
|
+
this.config.hasDefault = true;
|
|
18014
|
+
return this;
|
|
18015
|
+
}
|
|
18016
|
+
$onUpdate = this.$onUpdateFn;
|
|
18017
|
+
primaryKey() {
|
|
18018
|
+
this.config.primaryKey = true;
|
|
18019
|
+
this.config.notNull = true;
|
|
18020
|
+
return this;
|
|
18021
|
+
}
|
|
18022
|
+
setName(name) {
|
|
18023
|
+
if (this.config.name !== "")
|
|
18024
|
+
return;
|
|
18025
|
+
this.config.name = name;
|
|
16963
18026
|
}
|
|
16964
|
-
return parsePeers(status);
|
|
16965
18027
|
}
|
|
16966
|
-
|
|
16967
|
-
|
|
16968
|
-
|
|
16969
|
-
|
|
18028
|
+
|
|
18029
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/table.utils.js
|
|
18030
|
+
var TableName = Symbol.for("drizzle:Name");
|
|
18031
|
+
|
|
18032
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/tracing-utils.js
|
|
18033
|
+
function iife(fn, ...args) {
|
|
18034
|
+
return fn(...args);
|
|
18035
|
+
}
|
|
18036
|
+
|
|
18037
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/pg-core/unique-constraint.js
|
|
18038
|
+
function uniqueKeyName(table, columns) {
|
|
18039
|
+
return `${table[TableName]}_${columns.join("_")}_unique`;
|
|
18040
|
+
}
|
|
18041
|
+
|
|
18042
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/pg-core/columns/common.js
|
|
18043
|
+
class PgColumn extends Column {
|
|
18044
|
+
constructor(table, config) {
|
|
18045
|
+
if (!config.uniqueName) {
|
|
18046
|
+
config.uniqueName = uniqueKeyName(table, [config.name]);
|
|
18047
|
+
}
|
|
18048
|
+
super(table, config);
|
|
18049
|
+
this.table = table;
|
|
16970
18050
|
}
|
|
16971
|
-
|
|
18051
|
+
static [entityKind] = "PgColumn";
|
|
16972
18052
|
}
|
|
16973
18053
|
|
|
16974
|
-
|
|
16975
|
-
|
|
16976
|
-
|
|
18054
|
+
class ExtraConfigColumn extends PgColumn {
|
|
18055
|
+
static [entityKind] = "ExtraConfigColumn";
|
|
18056
|
+
getSQLType() {
|
|
18057
|
+
return this.getSQLType();
|
|
18058
|
+
}
|
|
18059
|
+
indexConfig = {
|
|
18060
|
+
order: this.config.order ?? "asc",
|
|
18061
|
+
nulls: this.config.nulls ?? "last",
|
|
18062
|
+
opClass: this.config.opClass
|
|
18063
|
+
};
|
|
18064
|
+
defaultConfig = {
|
|
18065
|
+
order: "asc",
|
|
18066
|
+
nulls: "last",
|
|
18067
|
+
opClass: undefined
|
|
18068
|
+
};
|
|
18069
|
+
asc() {
|
|
18070
|
+
this.indexConfig.order = "asc";
|
|
18071
|
+
return this;
|
|
18072
|
+
}
|
|
18073
|
+
desc() {
|
|
18074
|
+
this.indexConfig.order = "desc";
|
|
18075
|
+
return this;
|
|
18076
|
+
}
|
|
18077
|
+
nullsFirst() {
|
|
18078
|
+
this.indexConfig.nulls = "first";
|
|
18079
|
+
return this;
|
|
18080
|
+
}
|
|
18081
|
+
nullsLast() {
|
|
18082
|
+
this.indexConfig.nulls = "last";
|
|
18083
|
+
return this;
|
|
18084
|
+
}
|
|
18085
|
+
op(opClass) {
|
|
18086
|
+
this.indexConfig.opClass = opClass;
|
|
18087
|
+
return this;
|
|
18088
|
+
}
|
|
16977
18089
|
}
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
|
|
18090
|
+
|
|
18091
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/pg-core/columns/enum.js
|
|
18092
|
+
class PgEnumObjectColumn extends PgColumn {
|
|
18093
|
+
static [entityKind] = "PgEnumObjectColumn";
|
|
18094
|
+
enum;
|
|
18095
|
+
enumValues = this.config.enum.enumValues;
|
|
18096
|
+
constructor(table, config) {
|
|
18097
|
+
super(table, config);
|
|
18098
|
+
this.enum = config.enum;
|
|
18099
|
+
}
|
|
18100
|
+
getSQLType() {
|
|
18101
|
+
return this.enum.enumName;
|
|
18102
|
+
}
|
|
16981
18103
|
}
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
return
|
|
18104
|
+
var isPgEnumSym = Symbol.for("drizzle:isPgEnum");
|
|
18105
|
+
function isPgEnum(obj) {
|
|
18106
|
+
return !!obj && typeof obj === "function" && isPgEnumSym in obj && obj[isPgEnumSym] === true;
|
|
16985
18107
|
}
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
|
|
18108
|
+
class PgEnumColumn extends PgColumn {
|
|
18109
|
+
static [entityKind] = "PgEnumColumn";
|
|
18110
|
+
enum = this.config.enum;
|
|
18111
|
+
enumValues = this.config.enum.enumValues;
|
|
18112
|
+
constructor(table, config) {
|
|
18113
|
+
super(table, config);
|
|
18114
|
+
this.enum = config.enum;
|
|
16989
18115
|
}
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
return !isLoopbackHost(hostname2) && !isWildcardHost(hostname2);
|
|
16993
|
-
} catch {
|
|
16994
|
-
return false;
|
|
18116
|
+
getSQLType() {
|
|
18117
|
+
return this.enum.enumName;
|
|
16995
18118
|
}
|
|
16996
18119
|
}
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
18120
|
+
|
|
18121
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/subquery.js
|
|
18122
|
+
class Subquery {
|
|
18123
|
+
static [entityKind] = "Subquery";
|
|
18124
|
+
constructor(sql, fields, alias, isWith = false, usedTables = []) {
|
|
18125
|
+
this._ = {
|
|
18126
|
+
brand: "Subquery",
|
|
18127
|
+
sql,
|
|
18128
|
+
selectedFields: fields,
|
|
18129
|
+
alias,
|
|
18130
|
+
isWith,
|
|
18131
|
+
usedTables
|
|
18132
|
+
};
|
|
17001
18133
|
}
|
|
17002
|
-
return trimmed.replace(/\.$/, "");
|
|
17003
18134
|
}
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
|
|
17009
|
-
|
|
18135
|
+
|
|
18136
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/version.js
|
|
18137
|
+
var version = "0.45.2";
|
|
18138
|
+
|
|
18139
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/tracing.js
|
|
18140
|
+
var otel;
|
|
18141
|
+
var rawTracer;
|
|
18142
|
+
var tracer = {
|
|
18143
|
+
startActiveSpan(name, fn) {
|
|
18144
|
+
if (!otel) {
|
|
18145
|
+
return fn();
|
|
18146
|
+
}
|
|
18147
|
+
if (!rawTracer) {
|
|
18148
|
+
rawTracer = otel.trace.getTracer("drizzle-orm", version);
|
|
18149
|
+
}
|
|
18150
|
+
return iife((otel2, rawTracer2) => rawTracer2.startActiveSpan(name, (span) => {
|
|
18151
|
+
try {
|
|
18152
|
+
return fn(span);
|
|
18153
|
+
} catch (e) {
|
|
18154
|
+
span.setStatus({
|
|
18155
|
+
code: otel2.SpanStatusCode.ERROR,
|
|
18156
|
+
message: e instanceof Error ? e.message : "Unknown error"
|
|
18157
|
+
});
|
|
18158
|
+
throw e;
|
|
18159
|
+
} finally {
|
|
18160
|
+
span.end();
|
|
18161
|
+
}
|
|
18162
|
+
}), otel, rawTracer);
|
|
18163
|
+
}
|
|
18164
|
+
};
|
|
18165
|
+
|
|
18166
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/view-common.js
|
|
18167
|
+
var ViewBaseConfig = Symbol.for("drizzle:ViewBaseConfig");
|
|
18168
|
+
|
|
18169
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/table.js
|
|
18170
|
+
var Schema = Symbol.for("drizzle:Schema");
|
|
18171
|
+
var Columns = Symbol.for("drizzle:Columns");
|
|
18172
|
+
var ExtraConfigColumns = Symbol.for("drizzle:ExtraConfigColumns");
|
|
18173
|
+
var OriginalName = Symbol.for("drizzle:OriginalName");
|
|
18174
|
+
var BaseName = Symbol.for("drizzle:BaseName");
|
|
18175
|
+
var IsAlias = Symbol.for("drizzle:IsAlias");
|
|
18176
|
+
var ExtraConfigBuilder = Symbol.for("drizzle:ExtraConfigBuilder");
|
|
18177
|
+
var IsDrizzleTable = Symbol.for("drizzle:IsDrizzleTable");
|
|
18178
|
+
|
|
18179
|
+
class Table {
|
|
18180
|
+
static [entityKind] = "Table";
|
|
18181
|
+
static Symbol = {
|
|
18182
|
+
Name: TableName,
|
|
18183
|
+
Schema,
|
|
18184
|
+
OriginalName,
|
|
18185
|
+
Columns,
|
|
18186
|
+
ExtraConfigColumns,
|
|
18187
|
+
BaseName,
|
|
18188
|
+
IsAlias,
|
|
18189
|
+
ExtraConfigBuilder
|
|
17010
18190
|
};
|
|
18191
|
+
[TableName];
|
|
18192
|
+
[OriginalName];
|
|
18193
|
+
[Schema];
|
|
18194
|
+
[Columns];
|
|
18195
|
+
[ExtraConfigColumns];
|
|
18196
|
+
[BaseName];
|
|
18197
|
+
[IsAlias] = false;
|
|
18198
|
+
[IsDrizzleTable] = true;
|
|
18199
|
+
[ExtraConfigBuilder] = undefined;
|
|
18200
|
+
constructor(name, schema, baseName) {
|
|
18201
|
+
this[TableName] = this[OriginalName] = name;
|
|
18202
|
+
this[Schema] = schema;
|
|
18203
|
+
this[BaseName] = baseName;
|
|
18204
|
+
}
|
|
17011
18205
|
}
|
|
17012
|
-
|
|
17013
|
-
|
|
18206
|
+
|
|
18207
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sql/sql.js
|
|
18208
|
+
function isSQLWrapper(value) {
|
|
18209
|
+
return value !== null && value !== undefined && typeof value.getSQL === "function";
|
|
17014
18210
|
}
|
|
17015
|
-
function
|
|
17016
|
-
const
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
17025
|
-
}
|
|
18211
|
+
function mergeQueries(queries) {
|
|
18212
|
+
const result = { sql: "", params: [] };
|
|
18213
|
+
for (const query of queries) {
|
|
18214
|
+
result.sql += query.sql;
|
|
18215
|
+
result.params.push(...query.params);
|
|
18216
|
+
if (query.typings?.length) {
|
|
18217
|
+
if (!result.typings) {
|
|
18218
|
+
result.typings = [];
|
|
18219
|
+
}
|
|
18220
|
+
result.typings.push(...query.typings);
|
|
18221
|
+
}
|
|
18222
|
+
}
|
|
18223
|
+
return result;
|
|
18224
|
+
}
|
|
18225
|
+
|
|
18226
|
+
class StringChunk {
|
|
18227
|
+
static [entityKind] = "StringChunk";
|
|
18228
|
+
value;
|
|
18229
|
+
constructor(value) {
|
|
18230
|
+
this.value = Array.isArray(value) ? value : [value];
|
|
18231
|
+
}
|
|
18232
|
+
getSQL() {
|
|
18233
|
+
return new SQL([this]);
|
|
18234
|
+
}
|
|
18235
|
+
}
|
|
18236
|
+
|
|
18237
|
+
class SQL {
|
|
18238
|
+
constructor(queryChunks) {
|
|
18239
|
+
this.queryChunks = queryChunks;
|
|
18240
|
+
for (const chunk of queryChunks) {
|
|
18241
|
+
if (is(chunk, Table)) {
|
|
18242
|
+
const schemaName = chunk[Table.Symbol.Schema];
|
|
18243
|
+
this.usedTables.push(schemaName === undefined ? chunk[Table.Symbol.Name] : schemaName + "." + chunk[Table.Symbol.Name]);
|
|
18244
|
+
}
|
|
18245
|
+
}
|
|
18246
|
+
}
|
|
18247
|
+
static [entityKind] = "SQL";
|
|
18248
|
+
decoder = noopDecoder;
|
|
18249
|
+
shouldInlineParams = false;
|
|
18250
|
+
usedTables = [];
|
|
18251
|
+
append(query) {
|
|
18252
|
+
this.queryChunks.push(...query.queryChunks);
|
|
18253
|
+
return this;
|
|
18254
|
+
}
|
|
18255
|
+
toQuery(config) {
|
|
18256
|
+
return tracer.startActiveSpan("drizzle.buildSQL", (span) => {
|
|
18257
|
+
const query = this.buildQueryFromSourceParams(this.queryChunks, config);
|
|
18258
|
+
span?.setAttributes({
|
|
18259
|
+
"drizzle.query.text": query.sql,
|
|
18260
|
+
"drizzle.query.params": JSON.stringify(query.params)
|
|
18261
|
+
});
|
|
18262
|
+
return query;
|
|
18263
|
+
});
|
|
18264
|
+
}
|
|
18265
|
+
buildQueryFromSourceParams(chunks, _config) {
|
|
18266
|
+
const config = Object.assign({}, _config, {
|
|
18267
|
+
inlineParams: _config.inlineParams || this.shouldInlineParams,
|
|
18268
|
+
paramStartIndex: _config.paramStartIndex || { value: 0 }
|
|
18269
|
+
});
|
|
18270
|
+
const {
|
|
18271
|
+
casing,
|
|
18272
|
+
escapeName,
|
|
18273
|
+
escapeParam,
|
|
18274
|
+
prepareTyping,
|
|
18275
|
+
inlineParams,
|
|
18276
|
+
paramStartIndex
|
|
18277
|
+
} = config;
|
|
18278
|
+
return mergeQueries(chunks.map((chunk) => {
|
|
18279
|
+
if (is(chunk, StringChunk)) {
|
|
18280
|
+
return { sql: chunk.value.join(""), params: [] };
|
|
18281
|
+
}
|
|
18282
|
+
if (is(chunk, Name)) {
|
|
18283
|
+
return { sql: escapeName(chunk.value), params: [] };
|
|
18284
|
+
}
|
|
18285
|
+
if (chunk === undefined) {
|
|
18286
|
+
return { sql: "", params: [] };
|
|
18287
|
+
}
|
|
18288
|
+
if (Array.isArray(chunk)) {
|
|
18289
|
+
const result = [new StringChunk("(")];
|
|
18290
|
+
for (const [i, p] of chunk.entries()) {
|
|
18291
|
+
result.push(p);
|
|
18292
|
+
if (i < chunk.length - 1) {
|
|
18293
|
+
result.push(new StringChunk(", "));
|
|
18294
|
+
}
|
|
18295
|
+
}
|
|
18296
|
+
result.push(new StringChunk(")"));
|
|
18297
|
+
return this.buildQueryFromSourceParams(result, config);
|
|
18298
|
+
}
|
|
18299
|
+
if (is(chunk, SQL)) {
|
|
18300
|
+
return this.buildQueryFromSourceParams(chunk.queryChunks, {
|
|
18301
|
+
...config,
|
|
18302
|
+
inlineParams: inlineParams || chunk.shouldInlineParams
|
|
18303
|
+
});
|
|
18304
|
+
}
|
|
18305
|
+
if (is(chunk, Table)) {
|
|
18306
|
+
const schemaName = chunk[Table.Symbol.Schema];
|
|
18307
|
+
const tableName = chunk[Table.Symbol.Name];
|
|
18308
|
+
return {
|
|
18309
|
+
sql: schemaName === undefined || chunk[IsAlias] ? escapeName(tableName) : escapeName(schemaName) + "." + escapeName(tableName),
|
|
18310
|
+
params: []
|
|
18311
|
+
};
|
|
18312
|
+
}
|
|
18313
|
+
if (is(chunk, Column)) {
|
|
18314
|
+
const columnName = casing.getColumnCasing(chunk);
|
|
18315
|
+
if (_config.invokeSource === "indexes") {
|
|
18316
|
+
return { sql: escapeName(columnName), params: [] };
|
|
18317
|
+
}
|
|
18318
|
+
const schemaName = chunk.table[Table.Symbol.Schema];
|
|
18319
|
+
return {
|
|
18320
|
+
sql: chunk.table[IsAlias] || schemaName === undefined ? escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName) : escapeName(schemaName) + "." + escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName),
|
|
18321
|
+
params: []
|
|
18322
|
+
};
|
|
18323
|
+
}
|
|
18324
|
+
if (is(chunk, View)) {
|
|
18325
|
+
const schemaName = chunk[ViewBaseConfig].schema;
|
|
18326
|
+
const viewName = chunk[ViewBaseConfig].name;
|
|
18327
|
+
return {
|
|
18328
|
+
sql: schemaName === undefined || chunk[ViewBaseConfig].isAlias ? escapeName(viewName) : escapeName(schemaName) + "." + escapeName(viewName),
|
|
18329
|
+
params: []
|
|
18330
|
+
};
|
|
18331
|
+
}
|
|
18332
|
+
if (is(chunk, Param)) {
|
|
18333
|
+
if (is(chunk.value, Placeholder)) {
|
|
18334
|
+
return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ["none"] };
|
|
18335
|
+
}
|
|
18336
|
+
const mappedValue = chunk.value === null ? null : chunk.encoder.mapToDriverValue(chunk.value);
|
|
18337
|
+
if (is(mappedValue, SQL)) {
|
|
18338
|
+
return this.buildQueryFromSourceParams([mappedValue], config);
|
|
18339
|
+
}
|
|
18340
|
+
if (inlineParams) {
|
|
18341
|
+
return { sql: this.mapInlineParam(mappedValue, config), params: [] };
|
|
18342
|
+
}
|
|
18343
|
+
let typings = ["none"];
|
|
18344
|
+
if (prepareTyping) {
|
|
18345
|
+
typings = [prepareTyping(chunk.encoder)];
|
|
18346
|
+
}
|
|
18347
|
+
return { sql: escapeParam(paramStartIndex.value++, mappedValue), params: [mappedValue], typings };
|
|
18348
|
+
}
|
|
18349
|
+
if (is(chunk, Placeholder)) {
|
|
18350
|
+
return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ["none"] };
|
|
18351
|
+
}
|
|
18352
|
+
if (is(chunk, SQL.Aliased) && chunk.fieldAlias !== undefined) {
|
|
18353
|
+
return { sql: escapeName(chunk.fieldAlias), params: [] };
|
|
18354
|
+
}
|
|
18355
|
+
if (is(chunk, Subquery)) {
|
|
18356
|
+
if (chunk._.isWith) {
|
|
18357
|
+
return { sql: escapeName(chunk._.alias), params: [] };
|
|
18358
|
+
}
|
|
18359
|
+
return this.buildQueryFromSourceParams([
|
|
18360
|
+
new StringChunk("("),
|
|
18361
|
+
chunk._.sql,
|
|
18362
|
+
new StringChunk(") "),
|
|
18363
|
+
new Name(chunk._.alias)
|
|
18364
|
+
], config);
|
|
18365
|
+
}
|
|
18366
|
+
if (isPgEnum(chunk)) {
|
|
18367
|
+
if (chunk.schema) {
|
|
18368
|
+
return { sql: escapeName(chunk.schema) + "." + escapeName(chunk.enumName), params: [] };
|
|
18369
|
+
}
|
|
18370
|
+
return { sql: escapeName(chunk.enumName), params: [] };
|
|
18371
|
+
}
|
|
18372
|
+
if (isSQLWrapper(chunk)) {
|
|
18373
|
+
if (chunk.shouldOmitSQLParens?.()) {
|
|
18374
|
+
return this.buildQueryFromSourceParams([chunk.getSQL()], config);
|
|
18375
|
+
}
|
|
18376
|
+
return this.buildQueryFromSourceParams([
|
|
18377
|
+
new StringChunk("("),
|
|
18378
|
+
chunk.getSQL(),
|
|
18379
|
+
new StringChunk(")")
|
|
18380
|
+
], config);
|
|
18381
|
+
}
|
|
18382
|
+
if (inlineParams) {
|
|
18383
|
+
return { sql: this.mapInlineParam(chunk, config), params: [] };
|
|
18384
|
+
}
|
|
18385
|
+
return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ["none"] };
|
|
18386
|
+
}));
|
|
18387
|
+
}
|
|
18388
|
+
mapInlineParam(chunk, { escapeString }) {
|
|
18389
|
+
if (chunk === null) {
|
|
18390
|
+
return "null";
|
|
18391
|
+
}
|
|
18392
|
+
if (typeof chunk === "number" || typeof chunk === "boolean") {
|
|
18393
|
+
return chunk.toString();
|
|
18394
|
+
}
|
|
18395
|
+
if (typeof chunk === "string") {
|
|
18396
|
+
return escapeString(chunk);
|
|
18397
|
+
}
|
|
18398
|
+
if (typeof chunk === "object") {
|
|
18399
|
+
const mappedValueAsString = chunk.toString();
|
|
18400
|
+
if (mappedValueAsString === "[object Object]") {
|
|
18401
|
+
return escapeString(JSON.stringify(chunk));
|
|
18402
|
+
}
|
|
18403
|
+
return escapeString(mappedValueAsString);
|
|
18404
|
+
}
|
|
18405
|
+
throw new Error("Unexpected param value: " + chunk);
|
|
18406
|
+
}
|
|
18407
|
+
getSQL() {
|
|
18408
|
+
return this;
|
|
18409
|
+
}
|
|
18410
|
+
as(alias) {
|
|
18411
|
+
if (alias === undefined) {
|
|
18412
|
+
return this;
|
|
18413
|
+
}
|
|
18414
|
+
return new SQL.Aliased(this, alias);
|
|
18415
|
+
}
|
|
18416
|
+
mapWith(decoder) {
|
|
18417
|
+
this.decoder = typeof decoder === "function" ? { mapFromDriverValue: decoder } : decoder;
|
|
18418
|
+
return this;
|
|
18419
|
+
}
|
|
18420
|
+
inlineParams() {
|
|
18421
|
+
this.shouldInlineParams = true;
|
|
18422
|
+
return this;
|
|
18423
|
+
}
|
|
18424
|
+
if(condition) {
|
|
18425
|
+
return condition ? this : undefined;
|
|
18426
|
+
}
|
|
18427
|
+
}
|
|
18428
|
+
|
|
18429
|
+
class Name {
|
|
18430
|
+
constructor(value) {
|
|
18431
|
+
this.value = value;
|
|
18432
|
+
}
|
|
18433
|
+
static [entityKind] = "Name";
|
|
18434
|
+
brand;
|
|
18435
|
+
getSQL() {
|
|
18436
|
+
return new SQL([this]);
|
|
18437
|
+
}
|
|
18438
|
+
}
|
|
18439
|
+
var noopDecoder = {
|
|
18440
|
+
mapFromDriverValue: (value) => value
|
|
18441
|
+
};
|
|
18442
|
+
var noopEncoder = {
|
|
18443
|
+
mapToDriverValue: (value) => value
|
|
18444
|
+
};
|
|
18445
|
+
var noopMapper = {
|
|
18446
|
+
...noopDecoder,
|
|
18447
|
+
...noopEncoder
|
|
18448
|
+
};
|
|
18449
|
+
|
|
18450
|
+
class Param {
|
|
18451
|
+
constructor(value, encoder = noopEncoder) {
|
|
18452
|
+
this.value = value;
|
|
18453
|
+
this.encoder = encoder;
|
|
18454
|
+
}
|
|
18455
|
+
static [entityKind] = "Param";
|
|
18456
|
+
brand;
|
|
18457
|
+
getSQL() {
|
|
18458
|
+
return new SQL([this]);
|
|
18459
|
+
}
|
|
18460
|
+
}
|
|
18461
|
+
function sql(strings, ...params) {
|
|
18462
|
+
const queryChunks = [];
|
|
18463
|
+
if (params.length > 0 || strings.length > 0 && strings[0] !== "") {
|
|
18464
|
+
queryChunks.push(new StringChunk(strings[0]));
|
|
18465
|
+
}
|
|
18466
|
+
for (const [paramIndex, param2] of params.entries()) {
|
|
18467
|
+
queryChunks.push(param2, new StringChunk(strings[paramIndex + 1]));
|
|
18468
|
+
}
|
|
18469
|
+
return new SQL(queryChunks);
|
|
18470
|
+
}
|
|
18471
|
+
((sql2) => {
|
|
18472
|
+
function empty() {
|
|
18473
|
+
return new SQL([]);
|
|
18474
|
+
}
|
|
18475
|
+
sql2.empty = empty;
|
|
18476
|
+
function fromList(list) {
|
|
18477
|
+
return new SQL(list);
|
|
18478
|
+
}
|
|
18479
|
+
sql2.fromList = fromList;
|
|
18480
|
+
function raw2(str) {
|
|
18481
|
+
return new SQL([new StringChunk(str)]);
|
|
18482
|
+
}
|
|
18483
|
+
sql2.raw = raw2;
|
|
18484
|
+
function join18(chunks, separator) {
|
|
18485
|
+
const result = [];
|
|
18486
|
+
for (const [i, chunk] of chunks.entries()) {
|
|
18487
|
+
if (i > 0 && separator !== undefined) {
|
|
18488
|
+
result.push(separator);
|
|
18489
|
+
}
|
|
18490
|
+
result.push(chunk);
|
|
18491
|
+
}
|
|
18492
|
+
return new SQL(result);
|
|
18493
|
+
}
|
|
18494
|
+
sql2.join = join18;
|
|
18495
|
+
function identifier(value) {
|
|
18496
|
+
return new Name(value);
|
|
18497
|
+
}
|
|
18498
|
+
sql2.identifier = identifier;
|
|
18499
|
+
function placeholder2(name2) {
|
|
18500
|
+
return new Placeholder(name2);
|
|
18501
|
+
}
|
|
18502
|
+
sql2.placeholder = placeholder2;
|
|
18503
|
+
function param2(value, encoder) {
|
|
18504
|
+
return new Param(value, encoder);
|
|
18505
|
+
}
|
|
18506
|
+
sql2.param = param2;
|
|
18507
|
+
})(sql || (sql = {}));
|
|
18508
|
+
((SQL2) => {
|
|
18509
|
+
|
|
18510
|
+
class Aliased {
|
|
18511
|
+
constructor(sql2, fieldAlias) {
|
|
18512
|
+
this.sql = sql2;
|
|
18513
|
+
this.fieldAlias = fieldAlias;
|
|
18514
|
+
}
|
|
18515
|
+
static [entityKind] = "SQL.Aliased";
|
|
18516
|
+
isSelectionField = false;
|
|
18517
|
+
getSQL() {
|
|
18518
|
+
return this.sql;
|
|
18519
|
+
}
|
|
18520
|
+
clone() {
|
|
18521
|
+
return new Aliased(this.sql, this.fieldAlias);
|
|
18522
|
+
}
|
|
18523
|
+
}
|
|
18524
|
+
SQL2.Aliased = Aliased;
|
|
18525
|
+
})(SQL || (SQL = {}));
|
|
18526
|
+
|
|
18527
|
+
class Placeholder {
|
|
18528
|
+
constructor(name2) {
|
|
18529
|
+
this.name = name2;
|
|
18530
|
+
}
|
|
18531
|
+
static [entityKind] = "Placeholder";
|
|
18532
|
+
getSQL() {
|
|
18533
|
+
return new SQL([this]);
|
|
18534
|
+
}
|
|
18535
|
+
}
|
|
18536
|
+
var IsDrizzleView = Symbol.for("drizzle:IsDrizzleView");
|
|
18537
|
+
|
|
18538
|
+
class View {
|
|
18539
|
+
static [entityKind] = "View";
|
|
18540
|
+
[ViewBaseConfig];
|
|
18541
|
+
[IsDrizzleView] = true;
|
|
18542
|
+
constructor({ name: name2, schema, selectedFields, query }) {
|
|
18543
|
+
this[ViewBaseConfig] = {
|
|
18544
|
+
name: name2,
|
|
18545
|
+
originalName: name2,
|
|
18546
|
+
schema,
|
|
18547
|
+
selectedFields,
|
|
18548
|
+
query,
|
|
18549
|
+
isExisting: !query,
|
|
18550
|
+
isAlias: false
|
|
18551
|
+
};
|
|
18552
|
+
}
|
|
18553
|
+
getSQL() {
|
|
18554
|
+
return new SQL([this]);
|
|
18555
|
+
}
|
|
18556
|
+
}
|
|
18557
|
+
Column.prototype.getSQL = function() {
|
|
18558
|
+
return new SQL([this]);
|
|
18559
|
+
};
|
|
18560
|
+
Table.prototype.getSQL = function() {
|
|
18561
|
+
return new SQL([this]);
|
|
18562
|
+
};
|
|
18563
|
+
Subquery.prototype.getSQL = function() {
|
|
18564
|
+
return new SQL([this]);
|
|
18565
|
+
};
|
|
18566
|
+
|
|
18567
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/utils.js
|
|
18568
|
+
function getColumnNameAndConfig(a, b) {
|
|
18569
|
+
return {
|
|
18570
|
+
name: typeof a === "string" && a.length > 0 ? a : "",
|
|
18571
|
+
config: typeof a === "object" ? a : b
|
|
18572
|
+
};
|
|
18573
|
+
}
|
|
18574
|
+
var textDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder;
|
|
18575
|
+
|
|
18576
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/foreign-keys.js
|
|
18577
|
+
class ForeignKeyBuilder {
|
|
18578
|
+
static [entityKind] = "SQLiteForeignKeyBuilder";
|
|
18579
|
+
reference;
|
|
18580
|
+
_onUpdate;
|
|
18581
|
+
_onDelete;
|
|
18582
|
+
constructor(config, actions) {
|
|
18583
|
+
this.reference = () => {
|
|
18584
|
+
const { name, columns, foreignColumns } = config();
|
|
18585
|
+
return { name, columns, foreignTable: foreignColumns[0].table, foreignColumns };
|
|
18586
|
+
};
|
|
18587
|
+
if (actions) {
|
|
18588
|
+
this._onUpdate = actions.onUpdate;
|
|
18589
|
+
this._onDelete = actions.onDelete;
|
|
18590
|
+
}
|
|
18591
|
+
}
|
|
18592
|
+
onUpdate(action) {
|
|
18593
|
+
this._onUpdate = action;
|
|
18594
|
+
return this;
|
|
18595
|
+
}
|
|
18596
|
+
onDelete(action) {
|
|
18597
|
+
this._onDelete = action;
|
|
18598
|
+
return this;
|
|
18599
|
+
}
|
|
18600
|
+
build(table) {
|
|
18601
|
+
return new ForeignKey(table, this);
|
|
18602
|
+
}
|
|
18603
|
+
}
|
|
18604
|
+
|
|
18605
|
+
class ForeignKey {
|
|
18606
|
+
constructor(table, builder) {
|
|
18607
|
+
this.table = table;
|
|
18608
|
+
this.reference = builder.reference;
|
|
18609
|
+
this.onUpdate = builder._onUpdate;
|
|
18610
|
+
this.onDelete = builder._onDelete;
|
|
18611
|
+
}
|
|
18612
|
+
static [entityKind] = "SQLiteForeignKey";
|
|
18613
|
+
reference;
|
|
18614
|
+
onUpdate;
|
|
18615
|
+
onDelete;
|
|
18616
|
+
getName() {
|
|
18617
|
+
const { name, columns, foreignColumns } = this.reference();
|
|
18618
|
+
const columnNames = columns.map((column) => column.name);
|
|
18619
|
+
const foreignColumnNames = foreignColumns.map((column) => column.name);
|
|
18620
|
+
const chunks = [
|
|
18621
|
+
this.table[TableName],
|
|
18622
|
+
...columnNames,
|
|
18623
|
+
foreignColumns[0].table[TableName],
|
|
18624
|
+
...foreignColumnNames
|
|
18625
|
+
];
|
|
18626
|
+
return name ?? `${chunks.join("_")}_fk`;
|
|
18627
|
+
}
|
|
18628
|
+
}
|
|
18629
|
+
|
|
18630
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/unique-constraint.js
|
|
18631
|
+
function uniqueKeyName2(table, columns) {
|
|
18632
|
+
return `${table[TableName]}_${columns.join("_")}_unique`;
|
|
18633
|
+
}
|
|
18634
|
+
|
|
18635
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/common.js
|
|
18636
|
+
class SQLiteColumnBuilder extends ColumnBuilder {
|
|
18637
|
+
static [entityKind] = "SQLiteColumnBuilder";
|
|
18638
|
+
foreignKeyConfigs = [];
|
|
18639
|
+
references(ref, actions = {}) {
|
|
18640
|
+
this.foreignKeyConfigs.push({ ref, actions });
|
|
18641
|
+
return this;
|
|
18642
|
+
}
|
|
18643
|
+
unique(name) {
|
|
18644
|
+
this.config.isUnique = true;
|
|
18645
|
+
this.config.uniqueName = name;
|
|
18646
|
+
return this;
|
|
18647
|
+
}
|
|
18648
|
+
generatedAlwaysAs(as, config) {
|
|
18649
|
+
this.config.generated = {
|
|
18650
|
+
as,
|
|
18651
|
+
type: "always",
|
|
18652
|
+
mode: config?.mode ?? "virtual"
|
|
18653
|
+
};
|
|
18654
|
+
return this;
|
|
18655
|
+
}
|
|
18656
|
+
buildForeignKeys(column, table) {
|
|
18657
|
+
return this.foreignKeyConfigs.map(({ ref, actions }) => {
|
|
18658
|
+
return ((ref2, actions2) => {
|
|
18659
|
+
const builder = new ForeignKeyBuilder(() => {
|
|
18660
|
+
const foreignColumn = ref2();
|
|
18661
|
+
return { columns: [column], foreignColumns: [foreignColumn] };
|
|
18662
|
+
});
|
|
18663
|
+
if (actions2.onUpdate) {
|
|
18664
|
+
builder.onUpdate(actions2.onUpdate);
|
|
18665
|
+
}
|
|
18666
|
+
if (actions2.onDelete) {
|
|
18667
|
+
builder.onDelete(actions2.onDelete);
|
|
18668
|
+
}
|
|
18669
|
+
return builder.build(table);
|
|
18670
|
+
})(ref, actions);
|
|
18671
|
+
});
|
|
18672
|
+
}
|
|
18673
|
+
}
|
|
18674
|
+
|
|
18675
|
+
class SQLiteColumn extends Column {
|
|
18676
|
+
constructor(table, config) {
|
|
18677
|
+
if (!config.uniqueName) {
|
|
18678
|
+
config.uniqueName = uniqueKeyName2(table, [config.name]);
|
|
18679
|
+
}
|
|
18680
|
+
super(table, config);
|
|
18681
|
+
this.table = table;
|
|
18682
|
+
}
|
|
18683
|
+
static [entityKind] = "SQLiteColumn";
|
|
18684
|
+
}
|
|
18685
|
+
|
|
18686
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/blob.js
|
|
18687
|
+
class SQLiteBigIntBuilder extends SQLiteColumnBuilder {
|
|
18688
|
+
static [entityKind] = "SQLiteBigIntBuilder";
|
|
18689
|
+
constructor(name) {
|
|
18690
|
+
super(name, "bigint", "SQLiteBigInt");
|
|
18691
|
+
}
|
|
18692
|
+
build(table) {
|
|
18693
|
+
return new SQLiteBigInt(table, this.config);
|
|
18694
|
+
}
|
|
18695
|
+
}
|
|
18696
|
+
|
|
18697
|
+
class SQLiteBigInt extends SQLiteColumn {
|
|
18698
|
+
static [entityKind] = "SQLiteBigInt";
|
|
18699
|
+
getSQLType() {
|
|
18700
|
+
return "blob";
|
|
18701
|
+
}
|
|
18702
|
+
mapFromDriverValue(value) {
|
|
18703
|
+
if (typeof Buffer !== "undefined" && Buffer.from) {
|
|
18704
|
+
const buf = Buffer.isBuffer(value) ? value : value instanceof ArrayBuffer ? Buffer.from(value) : value.buffer ? Buffer.from(value.buffer, value.byteOffset, value.byteLength) : Buffer.from(value);
|
|
18705
|
+
return BigInt(buf.toString("utf8"));
|
|
18706
|
+
}
|
|
18707
|
+
return BigInt(textDecoder.decode(value));
|
|
18708
|
+
}
|
|
18709
|
+
mapToDriverValue(value) {
|
|
18710
|
+
return Buffer.from(value.toString());
|
|
18711
|
+
}
|
|
18712
|
+
}
|
|
18713
|
+
|
|
18714
|
+
class SQLiteBlobJsonBuilder extends SQLiteColumnBuilder {
|
|
18715
|
+
static [entityKind] = "SQLiteBlobJsonBuilder";
|
|
18716
|
+
constructor(name) {
|
|
18717
|
+
super(name, "json", "SQLiteBlobJson");
|
|
18718
|
+
}
|
|
18719
|
+
build(table) {
|
|
18720
|
+
return new SQLiteBlobJson(table, this.config);
|
|
18721
|
+
}
|
|
18722
|
+
}
|
|
18723
|
+
|
|
18724
|
+
class SQLiteBlobJson extends SQLiteColumn {
|
|
18725
|
+
static [entityKind] = "SQLiteBlobJson";
|
|
18726
|
+
getSQLType() {
|
|
18727
|
+
return "blob";
|
|
18728
|
+
}
|
|
18729
|
+
mapFromDriverValue(value) {
|
|
18730
|
+
if (typeof Buffer !== "undefined" && Buffer.from) {
|
|
18731
|
+
const buf = Buffer.isBuffer(value) ? value : value instanceof ArrayBuffer ? Buffer.from(value) : value.buffer ? Buffer.from(value.buffer, value.byteOffset, value.byteLength) : Buffer.from(value);
|
|
18732
|
+
return JSON.parse(buf.toString("utf8"));
|
|
18733
|
+
}
|
|
18734
|
+
return JSON.parse(textDecoder.decode(value));
|
|
18735
|
+
}
|
|
18736
|
+
mapToDriverValue(value) {
|
|
18737
|
+
return Buffer.from(JSON.stringify(value));
|
|
18738
|
+
}
|
|
18739
|
+
}
|
|
18740
|
+
|
|
18741
|
+
class SQLiteBlobBufferBuilder extends SQLiteColumnBuilder {
|
|
18742
|
+
static [entityKind] = "SQLiteBlobBufferBuilder";
|
|
18743
|
+
constructor(name) {
|
|
18744
|
+
super(name, "buffer", "SQLiteBlobBuffer");
|
|
18745
|
+
}
|
|
18746
|
+
build(table) {
|
|
18747
|
+
return new SQLiteBlobBuffer(table, this.config);
|
|
18748
|
+
}
|
|
18749
|
+
}
|
|
18750
|
+
|
|
18751
|
+
class SQLiteBlobBuffer extends SQLiteColumn {
|
|
18752
|
+
static [entityKind] = "SQLiteBlobBuffer";
|
|
18753
|
+
mapFromDriverValue(value) {
|
|
18754
|
+
if (Buffer.isBuffer(value)) {
|
|
18755
|
+
return value;
|
|
18756
|
+
}
|
|
18757
|
+
return Buffer.from(value);
|
|
18758
|
+
}
|
|
18759
|
+
getSQLType() {
|
|
18760
|
+
return "blob";
|
|
18761
|
+
}
|
|
18762
|
+
}
|
|
18763
|
+
function blob(a, b) {
|
|
18764
|
+
const { name, config } = getColumnNameAndConfig(a, b);
|
|
18765
|
+
if (config?.mode === "json") {
|
|
18766
|
+
return new SQLiteBlobJsonBuilder(name);
|
|
18767
|
+
}
|
|
18768
|
+
if (config?.mode === "bigint") {
|
|
18769
|
+
return new SQLiteBigIntBuilder(name);
|
|
18770
|
+
}
|
|
18771
|
+
return new SQLiteBlobBufferBuilder(name);
|
|
18772
|
+
}
|
|
18773
|
+
|
|
18774
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/custom.js
|
|
18775
|
+
class SQLiteCustomColumnBuilder extends SQLiteColumnBuilder {
|
|
18776
|
+
static [entityKind] = "SQLiteCustomColumnBuilder";
|
|
18777
|
+
constructor(name, fieldConfig, customTypeParams) {
|
|
18778
|
+
super(name, "custom", "SQLiteCustomColumn");
|
|
18779
|
+
this.config.fieldConfig = fieldConfig;
|
|
18780
|
+
this.config.customTypeParams = customTypeParams;
|
|
18781
|
+
}
|
|
18782
|
+
build(table) {
|
|
18783
|
+
return new SQLiteCustomColumn(table, this.config);
|
|
18784
|
+
}
|
|
18785
|
+
}
|
|
18786
|
+
|
|
18787
|
+
class SQLiteCustomColumn extends SQLiteColumn {
|
|
18788
|
+
static [entityKind] = "SQLiteCustomColumn";
|
|
18789
|
+
sqlName;
|
|
18790
|
+
mapTo;
|
|
18791
|
+
mapFrom;
|
|
18792
|
+
constructor(table, config) {
|
|
18793
|
+
super(table, config);
|
|
18794
|
+
this.sqlName = config.customTypeParams.dataType(config.fieldConfig);
|
|
18795
|
+
this.mapTo = config.customTypeParams.toDriver;
|
|
18796
|
+
this.mapFrom = config.customTypeParams.fromDriver;
|
|
18797
|
+
}
|
|
18798
|
+
getSQLType() {
|
|
18799
|
+
return this.sqlName;
|
|
18800
|
+
}
|
|
18801
|
+
mapFromDriverValue(value) {
|
|
18802
|
+
return typeof this.mapFrom === "function" ? this.mapFrom(value) : value;
|
|
18803
|
+
}
|
|
18804
|
+
mapToDriverValue(value) {
|
|
18805
|
+
return typeof this.mapTo === "function" ? this.mapTo(value) : value;
|
|
18806
|
+
}
|
|
18807
|
+
}
|
|
18808
|
+
function customType(customTypeParams) {
|
|
18809
|
+
return (a, b) => {
|
|
18810
|
+
const { name, config } = getColumnNameAndConfig(a, b);
|
|
18811
|
+
return new SQLiteCustomColumnBuilder(name, config, customTypeParams);
|
|
18812
|
+
};
|
|
18813
|
+
}
|
|
18814
|
+
|
|
18815
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/integer.js
|
|
18816
|
+
class SQLiteBaseIntegerBuilder extends SQLiteColumnBuilder {
|
|
18817
|
+
static [entityKind] = "SQLiteBaseIntegerBuilder";
|
|
18818
|
+
constructor(name, dataType, columnType) {
|
|
18819
|
+
super(name, dataType, columnType);
|
|
18820
|
+
this.config.autoIncrement = false;
|
|
18821
|
+
}
|
|
18822
|
+
primaryKey(config) {
|
|
18823
|
+
if (config?.autoIncrement) {
|
|
18824
|
+
this.config.autoIncrement = true;
|
|
18825
|
+
}
|
|
18826
|
+
this.config.hasDefault = true;
|
|
18827
|
+
return super.primaryKey();
|
|
18828
|
+
}
|
|
18829
|
+
}
|
|
18830
|
+
|
|
18831
|
+
class SQLiteBaseInteger extends SQLiteColumn {
|
|
18832
|
+
static [entityKind] = "SQLiteBaseInteger";
|
|
18833
|
+
autoIncrement = this.config.autoIncrement;
|
|
18834
|
+
getSQLType() {
|
|
18835
|
+
return "integer";
|
|
18836
|
+
}
|
|
18837
|
+
}
|
|
18838
|
+
|
|
18839
|
+
class SQLiteIntegerBuilder extends SQLiteBaseIntegerBuilder {
|
|
18840
|
+
static [entityKind] = "SQLiteIntegerBuilder";
|
|
18841
|
+
constructor(name) {
|
|
18842
|
+
super(name, "number", "SQLiteInteger");
|
|
18843
|
+
}
|
|
18844
|
+
build(table) {
|
|
18845
|
+
return new SQLiteInteger(table, this.config);
|
|
18846
|
+
}
|
|
18847
|
+
}
|
|
18848
|
+
|
|
18849
|
+
class SQLiteInteger extends SQLiteBaseInteger {
|
|
18850
|
+
static [entityKind] = "SQLiteInteger";
|
|
18851
|
+
}
|
|
18852
|
+
|
|
18853
|
+
class SQLiteTimestampBuilder extends SQLiteBaseIntegerBuilder {
|
|
18854
|
+
static [entityKind] = "SQLiteTimestampBuilder";
|
|
18855
|
+
constructor(name, mode) {
|
|
18856
|
+
super(name, "date", "SQLiteTimestamp");
|
|
18857
|
+
this.config.mode = mode;
|
|
18858
|
+
}
|
|
18859
|
+
defaultNow() {
|
|
18860
|
+
return this.default(sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`);
|
|
18861
|
+
}
|
|
18862
|
+
build(table) {
|
|
18863
|
+
return new SQLiteTimestamp(table, this.config);
|
|
18864
|
+
}
|
|
18865
|
+
}
|
|
18866
|
+
|
|
18867
|
+
class SQLiteTimestamp extends SQLiteBaseInteger {
|
|
18868
|
+
static [entityKind] = "SQLiteTimestamp";
|
|
18869
|
+
mode = this.config.mode;
|
|
18870
|
+
mapFromDriverValue(value) {
|
|
18871
|
+
if (this.config.mode === "timestamp") {
|
|
18872
|
+
return new Date(value * 1000);
|
|
18873
|
+
}
|
|
18874
|
+
return new Date(value);
|
|
18875
|
+
}
|
|
18876
|
+
mapToDriverValue(value) {
|
|
18877
|
+
const unix = value.getTime();
|
|
18878
|
+
if (this.config.mode === "timestamp") {
|
|
18879
|
+
return Math.floor(unix / 1000);
|
|
18880
|
+
}
|
|
18881
|
+
return unix;
|
|
18882
|
+
}
|
|
18883
|
+
}
|
|
18884
|
+
|
|
18885
|
+
class SQLiteBooleanBuilder extends SQLiteBaseIntegerBuilder {
|
|
18886
|
+
static [entityKind] = "SQLiteBooleanBuilder";
|
|
18887
|
+
constructor(name, mode) {
|
|
18888
|
+
super(name, "boolean", "SQLiteBoolean");
|
|
18889
|
+
this.config.mode = mode;
|
|
18890
|
+
}
|
|
18891
|
+
build(table) {
|
|
18892
|
+
return new SQLiteBoolean(table, this.config);
|
|
18893
|
+
}
|
|
18894
|
+
}
|
|
18895
|
+
|
|
18896
|
+
class SQLiteBoolean extends SQLiteBaseInteger {
|
|
18897
|
+
static [entityKind] = "SQLiteBoolean";
|
|
18898
|
+
mode = this.config.mode;
|
|
18899
|
+
mapFromDriverValue(value) {
|
|
18900
|
+
return Number(value) === 1;
|
|
18901
|
+
}
|
|
18902
|
+
mapToDriverValue(value) {
|
|
18903
|
+
return value ? 1 : 0;
|
|
18904
|
+
}
|
|
18905
|
+
}
|
|
18906
|
+
function integer(a, b) {
|
|
18907
|
+
const { name, config } = getColumnNameAndConfig(a, b);
|
|
18908
|
+
if (config?.mode === "timestamp" || config?.mode === "timestamp_ms") {
|
|
18909
|
+
return new SQLiteTimestampBuilder(name, config.mode);
|
|
18910
|
+
}
|
|
18911
|
+
if (config?.mode === "boolean") {
|
|
18912
|
+
return new SQLiteBooleanBuilder(name, config.mode);
|
|
18913
|
+
}
|
|
18914
|
+
return new SQLiteIntegerBuilder(name);
|
|
18915
|
+
}
|
|
18916
|
+
|
|
18917
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/numeric.js
|
|
18918
|
+
class SQLiteNumericBuilder extends SQLiteColumnBuilder {
|
|
18919
|
+
static [entityKind] = "SQLiteNumericBuilder";
|
|
18920
|
+
constructor(name) {
|
|
18921
|
+
super(name, "string", "SQLiteNumeric");
|
|
18922
|
+
}
|
|
18923
|
+
build(table) {
|
|
18924
|
+
return new SQLiteNumeric(table, this.config);
|
|
18925
|
+
}
|
|
18926
|
+
}
|
|
18927
|
+
|
|
18928
|
+
class SQLiteNumeric extends SQLiteColumn {
|
|
18929
|
+
static [entityKind] = "SQLiteNumeric";
|
|
18930
|
+
mapFromDriverValue(value) {
|
|
18931
|
+
if (typeof value === "string")
|
|
18932
|
+
return value;
|
|
18933
|
+
return String(value);
|
|
18934
|
+
}
|
|
18935
|
+
getSQLType() {
|
|
18936
|
+
return "numeric";
|
|
18937
|
+
}
|
|
18938
|
+
}
|
|
18939
|
+
|
|
18940
|
+
class SQLiteNumericNumberBuilder extends SQLiteColumnBuilder {
|
|
18941
|
+
static [entityKind] = "SQLiteNumericNumberBuilder";
|
|
18942
|
+
constructor(name) {
|
|
18943
|
+
super(name, "number", "SQLiteNumericNumber");
|
|
18944
|
+
}
|
|
18945
|
+
build(table) {
|
|
18946
|
+
return new SQLiteNumericNumber(table, this.config);
|
|
18947
|
+
}
|
|
18948
|
+
}
|
|
18949
|
+
|
|
18950
|
+
class SQLiteNumericNumber extends SQLiteColumn {
|
|
18951
|
+
static [entityKind] = "SQLiteNumericNumber";
|
|
18952
|
+
mapFromDriverValue(value) {
|
|
18953
|
+
if (typeof value === "number")
|
|
18954
|
+
return value;
|
|
18955
|
+
return Number(value);
|
|
18956
|
+
}
|
|
18957
|
+
mapToDriverValue = String;
|
|
18958
|
+
getSQLType() {
|
|
18959
|
+
return "numeric";
|
|
18960
|
+
}
|
|
18961
|
+
}
|
|
18962
|
+
|
|
18963
|
+
class SQLiteNumericBigIntBuilder extends SQLiteColumnBuilder {
|
|
18964
|
+
static [entityKind] = "SQLiteNumericBigIntBuilder";
|
|
18965
|
+
constructor(name) {
|
|
18966
|
+
super(name, "bigint", "SQLiteNumericBigInt");
|
|
18967
|
+
}
|
|
18968
|
+
build(table) {
|
|
18969
|
+
return new SQLiteNumericBigInt(table, this.config);
|
|
18970
|
+
}
|
|
18971
|
+
}
|
|
18972
|
+
|
|
18973
|
+
class SQLiteNumericBigInt extends SQLiteColumn {
|
|
18974
|
+
static [entityKind] = "SQLiteNumericBigInt";
|
|
18975
|
+
mapFromDriverValue = BigInt;
|
|
18976
|
+
mapToDriverValue = String;
|
|
18977
|
+
getSQLType() {
|
|
18978
|
+
return "numeric";
|
|
18979
|
+
}
|
|
18980
|
+
}
|
|
18981
|
+
function numeric(a, b) {
|
|
18982
|
+
const { name, config } = getColumnNameAndConfig(a, b);
|
|
18983
|
+
const mode = config?.mode;
|
|
18984
|
+
return mode === "number" ? new SQLiteNumericNumberBuilder(name) : mode === "bigint" ? new SQLiteNumericBigIntBuilder(name) : new SQLiteNumericBuilder(name);
|
|
18985
|
+
}
|
|
18986
|
+
|
|
18987
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/real.js
|
|
18988
|
+
class SQLiteRealBuilder extends SQLiteColumnBuilder {
|
|
18989
|
+
static [entityKind] = "SQLiteRealBuilder";
|
|
18990
|
+
constructor(name) {
|
|
18991
|
+
super(name, "number", "SQLiteReal");
|
|
18992
|
+
}
|
|
18993
|
+
build(table) {
|
|
18994
|
+
return new SQLiteReal(table, this.config);
|
|
18995
|
+
}
|
|
18996
|
+
}
|
|
18997
|
+
|
|
18998
|
+
class SQLiteReal extends SQLiteColumn {
|
|
18999
|
+
static [entityKind] = "SQLiteReal";
|
|
19000
|
+
getSQLType() {
|
|
19001
|
+
return "real";
|
|
19002
|
+
}
|
|
19003
|
+
}
|
|
19004
|
+
function real(name) {
|
|
19005
|
+
return new SQLiteRealBuilder(name ?? "");
|
|
19006
|
+
}
|
|
19007
|
+
|
|
19008
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/text.js
|
|
19009
|
+
class SQLiteTextBuilder extends SQLiteColumnBuilder {
|
|
19010
|
+
static [entityKind] = "SQLiteTextBuilder";
|
|
19011
|
+
constructor(name, config) {
|
|
19012
|
+
super(name, "string", "SQLiteText");
|
|
19013
|
+
this.config.enumValues = config.enum;
|
|
19014
|
+
this.config.length = config.length;
|
|
19015
|
+
}
|
|
19016
|
+
build(table) {
|
|
19017
|
+
return new SQLiteText(table, this.config);
|
|
19018
|
+
}
|
|
19019
|
+
}
|
|
19020
|
+
|
|
19021
|
+
class SQLiteText extends SQLiteColumn {
|
|
19022
|
+
static [entityKind] = "SQLiteText";
|
|
19023
|
+
enumValues = this.config.enumValues;
|
|
19024
|
+
length = this.config.length;
|
|
19025
|
+
constructor(table, config) {
|
|
19026
|
+
super(table, config);
|
|
19027
|
+
}
|
|
19028
|
+
getSQLType() {
|
|
19029
|
+
return `text${this.config.length ? `(${this.config.length})` : ""}`;
|
|
19030
|
+
}
|
|
19031
|
+
}
|
|
19032
|
+
|
|
19033
|
+
class SQLiteTextJsonBuilder extends SQLiteColumnBuilder {
|
|
19034
|
+
static [entityKind] = "SQLiteTextJsonBuilder";
|
|
19035
|
+
constructor(name) {
|
|
19036
|
+
super(name, "json", "SQLiteTextJson");
|
|
19037
|
+
}
|
|
19038
|
+
build(table) {
|
|
19039
|
+
return new SQLiteTextJson(table, this.config);
|
|
19040
|
+
}
|
|
19041
|
+
}
|
|
19042
|
+
|
|
19043
|
+
class SQLiteTextJson extends SQLiteColumn {
|
|
19044
|
+
static [entityKind] = "SQLiteTextJson";
|
|
19045
|
+
getSQLType() {
|
|
19046
|
+
return "text";
|
|
19047
|
+
}
|
|
19048
|
+
mapFromDriverValue(value) {
|
|
19049
|
+
return JSON.parse(value);
|
|
19050
|
+
}
|
|
19051
|
+
mapToDriverValue(value) {
|
|
19052
|
+
return JSON.stringify(value);
|
|
19053
|
+
}
|
|
19054
|
+
}
|
|
19055
|
+
function text(a, b = {}) {
|
|
19056
|
+
const { name, config } = getColumnNameAndConfig(a, b);
|
|
19057
|
+
if (config.mode === "json") {
|
|
19058
|
+
return new SQLiteTextJsonBuilder(name);
|
|
19059
|
+
}
|
|
19060
|
+
return new SQLiteTextBuilder(name, config);
|
|
19061
|
+
}
|
|
19062
|
+
|
|
19063
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/columns/all.js
|
|
19064
|
+
function getSQLiteColumnBuilders() {
|
|
19065
|
+
return {
|
|
19066
|
+
blob,
|
|
19067
|
+
customType,
|
|
19068
|
+
integer,
|
|
19069
|
+
numeric,
|
|
19070
|
+
real,
|
|
19071
|
+
text
|
|
19072
|
+
};
|
|
19073
|
+
}
|
|
19074
|
+
|
|
19075
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/table.js
|
|
19076
|
+
var InlineForeignKeys = Symbol.for("drizzle:SQLiteInlineForeignKeys");
|
|
19077
|
+
|
|
19078
|
+
class SQLiteTable extends Table {
|
|
19079
|
+
static [entityKind] = "SQLiteTable";
|
|
19080
|
+
static Symbol = Object.assign({}, Table.Symbol, {
|
|
19081
|
+
InlineForeignKeys
|
|
19082
|
+
});
|
|
19083
|
+
[Table.Symbol.Columns];
|
|
19084
|
+
[InlineForeignKeys] = [];
|
|
19085
|
+
[Table.Symbol.ExtraConfigBuilder] = undefined;
|
|
19086
|
+
}
|
|
19087
|
+
function sqliteTableBase(name, columns, extraConfig, schema, baseName = name) {
|
|
19088
|
+
const rawTable = new SQLiteTable(name, schema, baseName);
|
|
19089
|
+
const parsedColumns = typeof columns === "function" ? columns(getSQLiteColumnBuilders()) : columns;
|
|
19090
|
+
const builtColumns = Object.fromEntries(Object.entries(parsedColumns).map(([name2, colBuilderBase]) => {
|
|
19091
|
+
const colBuilder = colBuilderBase;
|
|
19092
|
+
colBuilder.setName(name2);
|
|
19093
|
+
const column = colBuilder.build(rawTable);
|
|
19094
|
+
rawTable[InlineForeignKeys].push(...colBuilder.buildForeignKeys(column, rawTable));
|
|
19095
|
+
return [name2, column];
|
|
19096
|
+
}));
|
|
19097
|
+
const table = Object.assign(rawTable, builtColumns);
|
|
19098
|
+
table[Table.Symbol.Columns] = builtColumns;
|
|
19099
|
+
table[Table.Symbol.ExtraConfigColumns] = builtColumns;
|
|
19100
|
+
if (extraConfig) {
|
|
19101
|
+
table[SQLiteTable.Symbol.ExtraConfigBuilder] = extraConfig;
|
|
19102
|
+
}
|
|
19103
|
+
return table;
|
|
19104
|
+
}
|
|
19105
|
+
var sqliteTable = (name, columns, extraConfig) => {
|
|
19106
|
+
return sqliteTableBase(name, columns, extraConfig);
|
|
19107
|
+
};
|
|
19108
|
+
|
|
19109
|
+
// node_modules/.bun/drizzle-orm@0.45.2+29ab9a45addfc34e/node_modules/drizzle-orm/sqlite-core/indexes.js
|
|
19110
|
+
class IndexBuilderOn {
|
|
19111
|
+
constructor(name, unique2) {
|
|
19112
|
+
this.name = name;
|
|
19113
|
+
this.unique = unique2;
|
|
19114
|
+
}
|
|
19115
|
+
static [entityKind] = "SQLiteIndexBuilderOn";
|
|
19116
|
+
on(...columns) {
|
|
19117
|
+
return new IndexBuilder(this.name, columns, this.unique);
|
|
19118
|
+
}
|
|
19119
|
+
}
|
|
19120
|
+
|
|
19121
|
+
class IndexBuilder {
|
|
19122
|
+
static [entityKind] = "SQLiteIndexBuilder";
|
|
19123
|
+
config;
|
|
19124
|
+
constructor(name, columns, unique2) {
|
|
19125
|
+
this.config = {
|
|
19126
|
+
name,
|
|
19127
|
+
columns,
|
|
19128
|
+
unique: unique2,
|
|
19129
|
+
where: undefined
|
|
19130
|
+
};
|
|
19131
|
+
}
|
|
19132
|
+
where(condition) {
|
|
19133
|
+
this.config.where = condition;
|
|
19134
|
+
return this;
|
|
19135
|
+
}
|
|
19136
|
+
build(table) {
|
|
19137
|
+
return new Index(this.config, table);
|
|
19138
|
+
}
|
|
19139
|
+
}
|
|
19140
|
+
|
|
19141
|
+
class Index {
|
|
19142
|
+
static [entityKind] = "SQLiteIndex";
|
|
19143
|
+
config;
|
|
19144
|
+
constructor(config, table) {
|
|
19145
|
+
this.config = { ...config, table };
|
|
19146
|
+
}
|
|
19147
|
+
}
|
|
19148
|
+
function index(name) {
|
|
19149
|
+
return new IndexBuilderOn(name, false);
|
|
19150
|
+
}
|
|
19151
|
+
|
|
19152
|
+
// packages/runtime/src/drizzle-schema.ts
|
|
19153
|
+
var deliveriesTable = sqliteTable("deliveries", {
|
|
19154
|
+
id: text("id").primaryKey(),
|
|
19155
|
+
messageId: text("message_id"),
|
|
19156
|
+
invocationId: text("invocation_id"),
|
|
19157
|
+
targetId: text("target_id").notNull(),
|
|
19158
|
+
targetNodeId: text("target_node_id"),
|
|
19159
|
+
targetKind: text("target_kind").$type().notNull(),
|
|
19160
|
+
transport: text("transport").$type().notNull(),
|
|
19161
|
+
reason: text("reason").$type().notNull(),
|
|
19162
|
+
policy: text("policy").$type().notNull(),
|
|
19163
|
+
status: text("status").$type().notNull(),
|
|
19164
|
+
bindingId: text("binding_id"),
|
|
19165
|
+
leaseOwner: text("lease_owner"),
|
|
19166
|
+
leaseExpiresAt: integer("lease_expires_at"),
|
|
19167
|
+
metadataJson: text("metadata_json"),
|
|
19168
|
+
createdAt: integer("created_at").notNull().default(sql`(unixepoch())`)
|
|
19169
|
+
}, (table) => [
|
|
19170
|
+
index("idx_deliveries_status_transport").on(table.status, table.transport)
|
|
19171
|
+
]);
|
|
19172
|
+
var deliveryAttemptsTable = sqliteTable("delivery_attempts", {
|
|
19173
|
+
id: text("id").primaryKey(),
|
|
19174
|
+
deliveryId: text("delivery_id").notNull(),
|
|
19175
|
+
attempt: integer("attempt").notNull(),
|
|
19176
|
+
status: text("status").$type().notNull(),
|
|
19177
|
+
error: text("error"),
|
|
19178
|
+
externalRef: text("external_ref"),
|
|
19179
|
+
metadataJson: text("metadata_json"),
|
|
19180
|
+
createdAt: integer("created_at").notNull()
|
|
19181
|
+
});
|
|
19182
|
+
// packages/runtime/src/broker.ts
|
|
19183
|
+
init_dist2();
|
|
19184
|
+
function createRuntimeId(prefix) {
|
|
19185
|
+
return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
19186
|
+
}
|
|
19187
|
+
function toTargetKind(actor) {
|
|
19188
|
+
if (!actor)
|
|
19189
|
+
return "participant";
|
|
19190
|
+
if (actor.kind === "agent")
|
|
19191
|
+
return "agent";
|
|
19192
|
+
if (actor.kind === "device")
|
|
19193
|
+
return "device";
|
|
19194
|
+
if (actor.kind === "bridge")
|
|
19195
|
+
return "bridge";
|
|
19196
|
+
return "participant";
|
|
19197
|
+
}
|
|
19198
|
+
function defaultTransportForActor(actor) {
|
|
19199
|
+
if (!actor)
|
|
19200
|
+
return "local_socket";
|
|
19201
|
+
switch (actor.kind) {
|
|
19202
|
+
case "bridge":
|
|
19203
|
+
return "webhook";
|
|
19204
|
+
case "device":
|
|
19205
|
+
return "local_socket";
|
|
19206
|
+
case "agent":
|
|
19207
|
+
return "local_socket";
|
|
19208
|
+
default:
|
|
19209
|
+
return "local_socket";
|
|
19210
|
+
}
|
|
19211
|
+
}
|
|
19212
|
+
function endpointTransportRank(transport) {
|
|
19213
|
+
switch (transport) {
|
|
19214
|
+
case "codex_app_server":
|
|
19215
|
+
return 0;
|
|
19216
|
+
case "claude_stream_json":
|
|
19217
|
+
return 1;
|
|
19218
|
+
case "tmux":
|
|
19219
|
+
return 2;
|
|
19220
|
+
case "local_socket":
|
|
19221
|
+
return 3;
|
|
19222
|
+
default:
|
|
19223
|
+
return 4;
|
|
19224
|
+
}
|
|
19225
|
+
}
|
|
19226
|
+
function shouldBridgeMessageToBinding(binding, message) {
|
|
19227
|
+
if (binding.platform !== "telegram") {
|
|
19228
|
+
return true;
|
|
19229
|
+
}
|
|
19230
|
+
const source = typeof message.metadata?.source === "string" ? String(message.metadata.source) : "";
|
|
19231
|
+
if (source === "telegram") {
|
|
19232
|
+
return false;
|
|
19233
|
+
}
|
|
19234
|
+
const outboundMode = typeof binding.metadata?.outboundMode === "string" ? String(binding.metadata.outboundMode) : "operator_only";
|
|
19235
|
+
const operatorId = typeof binding.metadata?.operatorId === "string" ? String(binding.metadata.operatorId) : "operator";
|
|
19236
|
+
const allowedActorIds = Array.isArray(binding.metadata?.allowedActorIds) ? binding.metadata.allowedActorIds.map((entry) => String(entry).trim()).filter(Boolean) : [];
|
|
19237
|
+
if (outboundMode === "all") {
|
|
19238
|
+
return true;
|
|
19239
|
+
}
|
|
19240
|
+
if (outboundMode === "allowlist") {
|
|
19241
|
+
return allowedActorIds.includes(message.actorId);
|
|
19242
|
+
}
|
|
19243
|
+
return message.actorId === operatorId;
|
|
19244
|
+
}
|
|
19245
|
+
function resolveBindingRoutes(bindings, message) {
|
|
19246
|
+
return bindings.filter((binding) => shouldBridgeMessageToBinding(binding, message)).map((binding) => ({
|
|
19247
|
+
targetId: binding.id,
|
|
19248
|
+
targetKind: "bridge",
|
|
19249
|
+
transport: binding.platform === "telegram" ? "telegram" : binding.platform === "discord" ? "discord" : "webhook",
|
|
19250
|
+
bindingId: binding.id
|
|
19251
|
+
}));
|
|
19252
|
+
}
|
|
19253
|
+
function preferredEndpoint(endpoints) {
|
|
19254
|
+
let preferred;
|
|
19255
|
+
let preferredRank = Number.POSITIVE_INFINITY;
|
|
19256
|
+
for (const endpoint of endpoints) {
|
|
19257
|
+
const rank = endpointTransportRank(endpoint.transport);
|
|
19258
|
+
if (!preferred || rank < preferredRank) {
|
|
19259
|
+
preferred = endpoint;
|
|
19260
|
+
preferredRank = rank;
|
|
19261
|
+
}
|
|
19262
|
+
}
|
|
19263
|
+
return preferred;
|
|
19264
|
+
}
|
|
19265
|
+
|
|
19266
|
+
class InMemoryControlRuntime {
|
|
19267
|
+
registry;
|
|
19268
|
+
listeners = new Set;
|
|
19269
|
+
eventBuffer = [];
|
|
19270
|
+
localNodeId;
|
|
19271
|
+
endpointIdsByAgentId = new Map;
|
|
19272
|
+
bindingIdsByConversationId = new Map;
|
|
19273
|
+
flightIdByInvocationId = new Map;
|
|
19274
|
+
constructor(initial = {}, options = {}) {
|
|
19275
|
+
this.registry = createRuntimeRegistrySnapshot(initial);
|
|
19276
|
+
this.localNodeId = options.localNodeId;
|
|
19277
|
+
this.rebuildIndexes();
|
|
19278
|
+
}
|
|
19279
|
+
snapshot() {
|
|
19280
|
+
return createRuntimeRegistrySnapshot({
|
|
19281
|
+
nodes: { ...this.registry.nodes },
|
|
19282
|
+
actors: { ...this.registry.actors },
|
|
19283
|
+
agents: { ...this.registry.agents },
|
|
19284
|
+
endpoints: { ...this.registry.endpoints },
|
|
19285
|
+
conversations: { ...this.registry.conversations },
|
|
19286
|
+
bindings: { ...this.registry.bindings },
|
|
19287
|
+
messages: { ...this.registry.messages },
|
|
19288
|
+
flights: { ...this.registry.flights },
|
|
19289
|
+
collaborationRecords: { ...this.registry.collaborationRecords }
|
|
19290
|
+
});
|
|
19291
|
+
}
|
|
19292
|
+
peek() {
|
|
19293
|
+
return this.registry;
|
|
19294
|
+
}
|
|
19295
|
+
node(nodeId) {
|
|
19296
|
+
return this.registry.nodes[nodeId];
|
|
19297
|
+
}
|
|
19298
|
+
agent(agentId) {
|
|
19299
|
+
return this.registry.agents[agentId];
|
|
19300
|
+
}
|
|
19301
|
+
conversation(conversationId) {
|
|
19302
|
+
return this.registry.conversations[conversationId];
|
|
19303
|
+
}
|
|
19304
|
+
message(messageId) {
|
|
19305
|
+
return this.registry.messages[messageId];
|
|
19306
|
+
}
|
|
19307
|
+
collaborationRecord(recordId) {
|
|
19308
|
+
return this.registry.collaborationRecords[recordId];
|
|
19309
|
+
}
|
|
19310
|
+
flightForInvocation(invocationId) {
|
|
19311
|
+
const flightId = this.flightIdByInvocationId.get(invocationId);
|
|
19312
|
+
return flightId ? this.registry.flights[flightId] : undefined;
|
|
19313
|
+
}
|
|
19314
|
+
bindingsForConversation(conversationId) {
|
|
19315
|
+
const bindingIds = this.bindingIdsByConversationId.get(conversationId);
|
|
19316
|
+
if (!bindingIds) {
|
|
19317
|
+
return [];
|
|
19318
|
+
}
|
|
19319
|
+
const bindings = [];
|
|
19320
|
+
for (const bindingId of bindingIds) {
|
|
19321
|
+
const binding = this.registry.bindings[bindingId];
|
|
19322
|
+
if (binding) {
|
|
19323
|
+
bindings.push(binding);
|
|
19324
|
+
}
|
|
19325
|
+
}
|
|
19326
|
+
return bindings;
|
|
19327
|
+
}
|
|
19328
|
+
endpointsForAgent(agentId, options = {}) {
|
|
19329
|
+
const endpointIds = this.endpointIdsByAgentId.get(agentId);
|
|
19330
|
+
if (!endpointIds) {
|
|
19331
|
+
return [];
|
|
19332
|
+
}
|
|
19333
|
+
const endpoints = [];
|
|
19334
|
+
for (const endpointId of endpointIds) {
|
|
19335
|
+
const endpoint = this.registry.endpoints[endpointId];
|
|
19336
|
+
if (!endpoint)
|
|
19337
|
+
continue;
|
|
19338
|
+
if (!options.includeOffline && endpoint.state === "offline")
|
|
19339
|
+
continue;
|
|
19340
|
+
if (options.nodeId && endpoint.nodeId !== options.nodeId)
|
|
19341
|
+
continue;
|
|
19342
|
+
if (options.harness && endpoint.harness !== options.harness)
|
|
19343
|
+
continue;
|
|
19344
|
+
endpoints.push(endpoint);
|
|
19345
|
+
}
|
|
19346
|
+
return endpoints;
|
|
19347
|
+
}
|
|
19348
|
+
recentEvents(limit = 100) {
|
|
19349
|
+
return this.eventBuffer.slice(-limit);
|
|
19350
|
+
}
|
|
19351
|
+
subscribe(listener) {
|
|
19352
|
+
this.listeners.add(listener);
|
|
19353
|
+
return () => {
|
|
19354
|
+
this.listeners.delete(listener);
|
|
19355
|
+
};
|
|
19356
|
+
}
|
|
19357
|
+
async dispatch(command) {
|
|
19358
|
+
switch (command.kind) {
|
|
19359
|
+
case "node.upsert":
|
|
19360
|
+
await this.upsertNode(command.node);
|
|
19361
|
+
return;
|
|
19362
|
+
case "actor.upsert":
|
|
19363
|
+
await this.upsertActor(command.actor);
|
|
19364
|
+
return;
|
|
19365
|
+
case "agent.upsert":
|
|
19366
|
+
await this.upsertAgent(command.agent);
|
|
19367
|
+
return;
|
|
19368
|
+
case "agent.endpoint.upsert":
|
|
19369
|
+
await this.upsertEndpoint(command.endpoint);
|
|
19370
|
+
return;
|
|
19371
|
+
case "conversation.upsert":
|
|
19372
|
+
await this.upsertConversation(command.conversation);
|
|
19373
|
+
return;
|
|
19374
|
+
case "binding.upsert":
|
|
19375
|
+
await this.upsertBinding(command.binding);
|
|
19376
|
+
return;
|
|
19377
|
+
case "collaboration.upsert":
|
|
19378
|
+
await this.upsertCollaboration(command.record);
|
|
19379
|
+
return;
|
|
19380
|
+
case "collaboration.event.append":
|
|
19381
|
+
await this.appendCollaborationEvent(command.event);
|
|
19382
|
+
return;
|
|
19383
|
+
case "conversation.post":
|
|
19384
|
+
await this.postMessage(command.message);
|
|
19385
|
+
return;
|
|
19386
|
+
case "agent.invoke":
|
|
19387
|
+
await this.invokeAgent(command.invocation);
|
|
19388
|
+
return;
|
|
19389
|
+
case "agent.ensure_awake":
|
|
19390
|
+
this.emit({
|
|
19391
|
+
id: createRuntimeId("evt"),
|
|
19392
|
+
kind: "flight.updated",
|
|
19393
|
+
ts: Date.now(),
|
|
19394
|
+
actorId: command.requesterId,
|
|
19395
|
+
nodeId: this.localNodeId,
|
|
19396
|
+
payload: {
|
|
19397
|
+
flight: {
|
|
19398
|
+
id: createRuntimeId("flt"),
|
|
19399
|
+
invocationId: command.agentId,
|
|
19400
|
+
requesterId: command.requesterId,
|
|
19401
|
+
targetAgentId: command.agentId,
|
|
19402
|
+
state: "waking",
|
|
19403
|
+
summary: command.reason
|
|
19404
|
+
}
|
|
19405
|
+
}
|
|
19406
|
+
});
|
|
19407
|
+
return;
|
|
19408
|
+
case "stream.subscribe":
|
|
19409
|
+
return;
|
|
19410
|
+
default: {
|
|
19411
|
+
const exhaustive = command;
|
|
19412
|
+
return exhaustive;
|
|
19413
|
+
}
|
|
19414
|
+
}
|
|
19415
|
+
}
|
|
19416
|
+
async upsertNode(node) {
|
|
19417
|
+
this.registry.nodes[node.id] = node;
|
|
19418
|
+
this.emit({
|
|
19419
|
+
id: createRuntimeId("evt"),
|
|
19420
|
+
kind: "node.upserted",
|
|
19421
|
+
ts: Date.now(),
|
|
19422
|
+
actorId: node.id,
|
|
19423
|
+
nodeId: node.id,
|
|
19424
|
+
payload: { node }
|
|
19425
|
+
});
|
|
19426
|
+
}
|
|
19427
|
+
async upsertActor(actor) {
|
|
19428
|
+
this.registry.actors[actor.id] = {
|
|
19429
|
+
id: actor.id,
|
|
19430
|
+
kind: actor.kind,
|
|
19431
|
+
displayName: actor.displayName,
|
|
19432
|
+
handle: actor.handle,
|
|
19433
|
+
labels: actor.labels,
|
|
19434
|
+
metadata: actor.metadata
|
|
19435
|
+
};
|
|
19436
|
+
this.emit({
|
|
19437
|
+
id: createRuntimeId("evt"),
|
|
19438
|
+
kind: "actor.registered",
|
|
19439
|
+
ts: Date.now(),
|
|
19440
|
+
actorId: actor.id,
|
|
19441
|
+
nodeId: this.localNodeId,
|
|
19442
|
+
payload: { actor }
|
|
19443
|
+
});
|
|
19444
|
+
}
|
|
19445
|
+
async upsertAgent(agent) {
|
|
19446
|
+
if (!this.registry.actors[agent.id]) {
|
|
19447
|
+
this.registry.actors[agent.id] = {
|
|
19448
|
+
id: agent.id,
|
|
19449
|
+
kind: agent.kind,
|
|
19450
|
+
displayName: agent.displayName,
|
|
19451
|
+
handle: agent.handle,
|
|
19452
|
+
labels: agent.labels,
|
|
19453
|
+
metadata: agent.metadata
|
|
19454
|
+
};
|
|
19455
|
+
}
|
|
19456
|
+
this.registry.agents[agent.id] = agent;
|
|
19457
|
+
this.emit({
|
|
19458
|
+
id: createRuntimeId("evt"),
|
|
19459
|
+
kind: "agent.registered",
|
|
19460
|
+
ts: Date.now(),
|
|
19461
|
+
actorId: agent.id,
|
|
19462
|
+
nodeId: agent.authorityNodeId,
|
|
19463
|
+
payload: { agent }
|
|
19464
|
+
});
|
|
19465
|
+
}
|
|
19466
|
+
async upsertEndpoint(endpoint) {
|
|
19467
|
+
const previous = this.registry.endpoints[endpoint.id];
|
|
19468
|
+
if (previous) {
|
|
19469
|
+
this.unindexEndpoint(previous);
|
|
19470
|
+
}
|
|
19471
|
+
this.registry.endpoints[endpoint.id] = endpoint;
|
|
19472
|
+
this.indexEndpoint(endpoint);
|
|
19473
|
+
this.emit({
|
|
19474
|
+
id: createRuntimeId("evt"),
|
|
19475
|
+
kind: "agent.endpoint.upserted",
|
|
19476
|
+
ts: Date.now(),
|
|
19477
|
+
actorId: endpoint.agentId,
|
|
19478
|
+
nodeId: endpoint.nodeId,
|
|
19479
|
+
payload: { endpoint }
|
|
19480
|
+
});
|
|
19481
|
+
}
|
|
19482
|
+
async upsertConversation(conversation) {
|
|
19483
|
+
this.registry.conversations[conversation.id] = conversation;
|
|
19484
|
+
this.emit({
|
|
19485
|
+
id: createRuntimeId("evt"),
|
|
19486
|
+
kind: "conversation.upserted",
|
|
19487
|
+
ts: Date.now(),
|
|
19488
|
+
actorId: "system",
|
|
19489
|
+
nodeId: conversation.authorityNodeId,
|
|
19490
|
+
payload: { conversation }
|
|
19491
|
+
});
|
|
19492
|
+
}
|
|
19493
|
+
async upsertBinding(binding) {
|
|
19494
|
+
const previous = this.registry.bindings[binding.id];
|
|
19495
|
+
if (previous) {
|
|
19496
|
+
this.unindexBinding(previous);
|
|
19497
|
+
}
|
|
19498
|
+
this.registry.bindings[binding.id] = binding;
|
|
19499
|
+
this.indexBinding(binding);
|
|
19500
|
+
this.emit({
|
|
19501
|
+
id: createRuntimeId("evt"),
|
|
19502
|
+
kind: "binding.upserted",
|
|
19503
|
+
ts: Date.now(),
|
|
19504
|
+
actorId: "system",
|
|
19505
|
+
nodeId: this.localNodeId,
|
|
19506
|
+
payload: { binding }
|
|
19507
|
+
});
|
|
19508
|
+
}
|
|
19509
|
+
async upsertCollaboration(record) {
|
|
19510
|
+
assertValidCollaborationRecord(record);
|
|
19511
|
+
this.registry.collaborationRecords[record.id] = record;
|
|
19512
|
+
this.emit({
|
|
19513
|
+
id: createRuntimeId("evt"),
|
|
19514
|
+
kind: "collaboration.upserted",
|
|
19515
|
+
ts: Date.now(),
|
|
19516
|
+
actorId: record.createdById,
|
|
19517
|
+
nodeId: this.localNodeId,
|
|
19518
|
+
payload: { record }
|
|
19519
|
+
});
|
|
19520
|
+
}
|
|
19521
|
+
async appendCollaborationEvent(event) {
|
|
19522
|
+
const record = this.registry.collaborationRecords[event.recordId];
|
|
19523
|
+
if (!record) {
|
|
19524
|
+
throw new Error(`unknown collaboration record: ${event.recordId}`);
|
|
19525
|
+
}
|
|
19526
|
+
assertValidCollaborationEvent(event, record);
|
|
19527
|
+
this.emit({
|
|
19528
|
+
id: createRuntimeId("evt"),
|
|
19529
|
+
kind: "collaboration.event.appended",
|
|
19530
|
+
ts: Date.now(),
|
|
19531
|
+
actorId: event.actorId,
|
|
19532
|
+
nodeId: this.localNodeId,
|
|
19533
|
+
payload: { event }
|
|
19534
|
+
});
|
|
19535
|
+
}
|
|
19536
|
+
async upsertFlight(flight) {
|
|
19537
|
+
const previous = this.registry.flights[flight.id];
|
|
19538
|
+
if (previous && this.flightIdByInvocationId.get(previous.invocationId) === previous.id) {
|
|
19539
|
+
this.flightIdByInvocationId.delete(previous.invocationId);
|
|
19540
|
+
}
|
|
19541
|
+
this.registry.flights[flight.id] = flight;
|
|
19542
|
+
this.flightIdByInvocationId.set(flight.invocationId, flight.id);
|
|
19543
|
+
this.emit({
|
|
19544
|
+
id: createRuntimeId("evt"),
|
|
19545
|
+
kind: "flight.updated",
|
|
19546
|
+
ts: Date.now(),
|
|
19547
|
+
actorId: flight.requesterId,
|
|
19548
|
+
nodeId: this.localNodeId,
|
|
19549
|
+
payload: { flight }
|
|
19550
|
+
});
|
|
19551
|
+
}
|
|
19552
|
+
async postMessage(message, options = {}) {
|
|
19553
|
+
const deliveries2 = this.planMessage(message, options);
|
|
19554
|
+
await this.commitMessage(message, deliveries2);
|
|
19555
|
+
return deliveries2;
|
|
19556
|
+
}
|
|
19557
|
+
planMessage(message, options = {}) {
|
|
19558
|
+
const conversation = this.registry.conversations[message.conversationId];
|
|
19559
|
+
if (!conversation) {
|
|
19560
|
+
throw new Error(`unknown conversation: ${message.conversationId}`);
|
|
19561
|
+
}
|
|
19562
|
+
const bindingRoutes = resolveBindingRoutes(this.bindingsForConversation(conversation.id), message);
|
|
19563
|
+
const plannedParticipantRoutes = this.resolveParticipantRoutes(conversation.participantIds);
|
|
19564
|
+
const participantRoutes = options.localOnly ? plannedParticipantRoutes.filter((route) => !route.nodeId || route.nodeId === this.localNodeId) : plannedParticipantRoutes;
|
|
19565
|
+
const deliveries2 = planMessageDeliveries({
|
|
19566
|
+
localNodeId: this.localNodeId,
|
|
19567
|
+
message,
|
|
19568
|
+
conversation,
|
|
19569
|
+
participantRoutes,
|
|
19570
|
+
bindingRoutes: options.localOnly ? [] : bindingRoutes
|
|
19571
|
+
});
|
|
19572
|
+
return deliveries2;
|
|
19573
|
+
}
|
|
19574
|
+
async commitMessage(message, deliveries2) {
|
|
19575
|
+
this.registry.messages[message.id] = message;
|
|
19576
|
+
this.emit({
|
|
19577
|
+
id: createRuntimeId("evt"),
|
|
19578
|
+
kind: "message.posted",
|
|
19579
|
+
ts: Date.now(),
|
|
19580
|
+
actorId: message.actorId,
|
|
19581
|
+
nodeId: message.originNodeId,
|
|
19582
|
+
payload: { message }
|
|
19583
|
+
});
|
|
19584
|
+
for (const delivery of deliveries2) {
|
|
19585
|
+
this.emit({
|
|
19586
|
+
id: createRuntimeId("evt"),
|
|
19587
|
+
kind: "delivery.planned",
|
|
19588
|
+
ts: Date.now(),
|
|
19589
|
+
actorId: message.actorId,
|
|
19590
|
+
nodeId: message.originNodeId,
|
|
19591
|
+
payload: { delivery }
|
|
19592
|
+
});
|
|
19593
|
+
}
|
|
19594
|
+
}
|
|
19595
|
+
async invokeAgent(invocation) {
|
|
19596
|
+
const flight = this.planInvocation(invocation);
|
|
19597
|
+
await this.commitInvocation(invocation, flight);
|
|
19598
|
+
return flight;
|
|
19599
|
+
}
|
|
19600
|
+
planInvocation(invocation) {
|
|
19601
|
+
const targetAgent = this.registry.agents[invocation.targetAgentId];
|
|
19602
|
+
if (!targetAgent) {
|
|
19603
|
+
throw new Error(`unknown agent: ${invocation.targetAgentId}`);
|
|
19604
|
+
}
|
|
19605
|
+
const targetEndpoints = this.endpointsForAgent(invocation.targetAgentId, {
|
|
19606
|
+
nodeId: targetAgent.authorityNodeId,
|
|
19607
|
+
harness: invocation.execution?.harness
|
|
19608
|
+
});
|
|
19609
|
+
const isLocalAuthority = !this.localNodeId || targetAgent.authorityNodeId === this.localNodeId;
|
|
19610
|
+
const startedAt = Date.now();
|
|
19611
|
+
let state = invocation.ensureAwake ? "waking" : "queued";
|
|
19612
|
+
let summary;
|
|
19613
|
+
let error;
|
|
19614
|
+
let completedAt;
|
|
19615
|
+
if (isLocalAuthority) {
|
|
19616
|
+
if (targetEndpoints.length == 0) {
|
|
19617
|
+
state = invocation.ensureAwake ? "waking" : "queued";
|
|
19618
|
+
summary = invocation.ensureAwake ? invocation.execution?.harness ? `${targetAgent.displayName} waking on ${invocation.execution.harness}.` : `${targetAgent.displayName} waking.` : `Message stored for ${targetAgent.displayName}. Will deliver when online.`;
|
|
19619
|
+
} else {
|
|
19620
|
+
state = "queued";
|
|
19621
|
+
summary = `${targetAgent.displayName} queued for local execution.`;
|
|
19622
|
+
}
|
|
19623
|
+
}
|
|
19624
|
+
const flight = {
|
|
19625
|
+
id: createRuntimeId("flt"),
|
|
19626
|
+
invocationId: invocation.id,
|
|
19627
|
+
requesterId: invocation.requesterId,
|
|
19628
|
+
targetAgentId: invocation.targetAgentId,
|
|
19629
|
+
state,
|
|
19630
|
+
summary,
|
|
19631
|
+
error,
|
|
19632
|
+
startedAt,
|
|
19633
|
+
completedAt,
|
|
19634
|
+
metadata: invocation.metadata
|
|
19635
|
+
};
|
|
19636
|
+
return flight;
|
|
19637
|
+
}
|
|
19638
|
+
async commitInvocation(invocation, flight) {
|
|
19639
|
+
const previous = this.registry.flights[flight.id];
|
|
19640
|
+
if (previous && this.flightIdByInvocationId.get(previous.invocationId) === previous.id) {
|
|
19641
|
+
this.flightIdByInvocationId.delete(previous.invocationId);
|
|
19642
|
+
}
|
|
19643
|
+
this.registry.flights[flight.id] = flight;
|
|
19644
|
+
this.flightIdByInvocationId.set(flight.invocationId, flight.id);
|
|
19645
|
+
const targetAgent = this.registry.agents[invocation.targetAgentId];
|
|
19646
|
+
this.emit({
|
|
19647
|
+
id: createRuntimeId("evt"),
|
|
19648
|
+
kind: "invocation.requested",
|
|
19649
|
+
ts: Date.now(),
|
|
19650
|
+
actorId: invocation.requesterId,
|
|
19651
|
+
nodeId: invocation.requesterNodeId,
|
|
19652
|
+
payload: { invocation }
|
|
19653
|
+
});
|
|
19654
|
+
this.emit({
|
|
19655
|
+
id: createRuntimeId("evt"),
|
|
19656
|
+
kind: "flight.updated",
|
|
19657
|
+
ts: Date.now(),
|
|
19658
|
+
actorId: invocation.requesterId,
|
|
19659
|
+
nodeId: targetAgent?.authorityNodeId,
|
|
19660
|
+
payload: { flight }
|
|
19661
|
+
});
|
|
19662
|
+
}
|
|
19663
|
+
rebuildIndexes() {
|
|
19664
|
+
for (const endpoint of Object.values(this.registry.endpoints)) {
|
|
19665
|
+
this.indexEndpoint(endpoint);
|
|
19666
|
+
}
|
|
19667
|
+
for (const binding of Object.values(this.registry.bindings)) {
|
|
19668
|
+
this.indexBinding(binding);
|
|
19669
|
+
}
|
|
19670
|
+
for (const flight of Object.values(this.registry.flights)) {
|
|
19671
|
+
this.flightIdByInvocationId.set(flight.invocationId, flight.id);
|
|
19672
|
+
}
|
|
19673
|
+
}
|
|
19674
|
+
indexEndpoint(endpoint) {
|
|
19675
|
+
this.addIndexedId(this.endpointIdsByAgentId, endpoint.agentId, endpoint.id);
|
|
19676
|
+
}
|
|
19677
|
+
unindexEndpoint(endpoint) {
|
|
19678
|
+
this.removeIndexedId(this.endpointIdsByAgentId, endpoint.agentId, endpoint.id);
|
|
19679
|
+
}
|
|
19680
|
+
indexBinding(binding) {
|
|
19681
|
+
this.addIndexedId(this.bindingIdsByConversationId, binding.conversationId, binding.id);
|
|
19682
|
+
}
|
|
19683
|
+
unindexBinding(binding) {
|
|
19684
|
+
this.removeIndexedId(this.bindingIdsByConversationId, binding.conversationId, binding.id);
|
|
19685
|
+
}
|
|
19686
|
+
addIndexedId(index2, key, value) {
|
|
19687
|
+
const ids = index2.get(key) ?? new Set;
|
|
19688
|
+
ids.add(value);
|
|
19689
|
+
index2.set(key, ids);
|
|
19690
|
+
}
|
|
19691
|
+
removeIndexedId(index2, key, value) {
|
|
19692
|
+
const ids = index2.get(key);
|
|
19693
|
+
if (!ids) {
|
|
19694
|
+
return;
|
|
19695
|
+
}
|
|
19696
|
+
ids.delete(value);
|
|
19697
|
+
if (ids.size === 0) {
|
|
19698
|
+
index2.delete(key);
|
|
19699
|
+
}
|
|
19700
|
+
}
|
|
19701
|
+
resolveParticipantRoutes(participantIds) {
|
|
19702
|
+
const routes = [];
|
|
19703
|
+
for (const participantId of participantIds) {
|
|
19704
|
+
const actor = this.registry.actors[participantId];
|
|
19705
|
+
const agent = this.registry.agents[participantId];
|
|
19706
|
+
const targetIdentity = actor ?? agent;
|
|
19707
|
+
const endpoints = this.endpointsForAgent(participantId);
|
|
19708
|
+
const endpoint = preferredEndpoint(endpoints);
|
|
19709
|
+
if (!endpoint) {
|
|
19710
|
+
if (agent?.authorityNodeId && agent.authorityNodeId !== this.localNodeId) {
|
|
19711
|
+
routes.push({
|
|
19712
|
+
targetId: participantId,
|
|
19713
|
+
nodeId: agent.authorityNodeId,
|
|
19714
|
+
targetKind: toTargetKind(targetIdentity),
|
|
19715
|
+
transport: defaultTransportForActor(targetIdentity),
|
|
19716
|
+
speechEnabled: false
|
|
19717
|
+
});
|
|
19718
|
+
} else if (agent) {
|
|
19719
|
+
routes.push({
|
|
19720
|
+
targetId: participantId,
|
|
19721
|
+
nodeId: agent.authorityNodeId ?? this.localNodeId,
|
|
19722
|
+
targetKind: toTargetKind(targetIdentity),
|
|
19723
|
+
transport: defaultTransportForActor(targetIdentity),
|
|
19724
|
+
speechEnabled: false
|
|
19725
|
+
});
|
|
19726
|
+
}
|
|
19727
|
+
continue;
|
|
19728
|
+
}
|
|
19729
|
+
routes.push({
|
|
19730
|
+
targetId: participantId,
|
|
19731
|
+
nodeId: endpoint.nodeId ?? agent?.authorityNodeId,
|
|
19732
|
+
targetKind: toTargetKind(targetIdentity),
|
|
19733
|
+
transport: endpoint.transport ?? defaultTransportForActor(targetIdentity),
|
|
19734
|
+
speechEnabled: Boolean(actor?.kind === "device" || endpoints.some((candidate) => candidate.transport === "local_socket" || candidate.transport === "websocket"))
|
|
19735
|
+
});
|
|
19736
|
+
}
|
|
19737
|
+
return routes;
|
|
19738
|
+
}
|
|
19739
|
+
emit(event) {
|
|
19740
|
+
this.eventBuffer.push(event);
|
|
19741
|
+
if (this.eventBuffer.length > 500) {
|
|
19742
|
+
this.eventBuffer.shift();
|
|
19743
|
+
}
|
|
19744
|
+
for (const listener of this.listeners) {
|
|
19745
|
+
listener(event);
|
|
19746
|
+
}
|
|
19747
|
+
}
|
|
19748
|
+
}
|
|
19749
|
+
// packages/runtime/src/tailscale.ts
|
|
19750
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
19751
|
+
import { execFile } from "child_process";
|
|
19752
|
+
import { promisify } from "util";
|
|
19753
|
+
var execFileAsync = promisify(execFile);
|
|
19754
|
+
function parseStatusJson(raw2) {
|
|
19755
|
+
return JSON.parse(raw2);
|
|
19756
|
+
}
|
|
19757
|
+
function parsePeers(status) {
|
|
19758
|
+
const peers = Object.entries(status.Peer ?? {});
|
|
19759
|
+
return peers.map(([fallbackId, peer]) => ({
|
|
19760
|
+
id: peer.ID ?? fallbackId,
|
|
19761
|
+
name: peer.HostName ?? peer.DNSName ?? fallbackId,
|
|
19762
|
+
dnsName: peer.DNSName,
|
|
19763
|
+
addresses: peer.TailscaleIPs ?? [],
|
|
19764
|
+
online: peer.Online ?? false,
|
|
19765
|
+
hostName: peer.HostName,
|
|
19766
|
+
os: peer.OS,
|
|
19767
|
+
tags: peer.Tags ?? []
|
|
19768
|
+
}));
|
|
19769
|
+
}
|
|
19770
|
+
function parseSelf(status) {
|
|
19771
|
+
const self = status.Self;
|
|
19772
|
+
if (!self) {
|
|
19773
|
+
return null;
|
|
19774
|
+
}
|
|
19775
|
+
return {
|
|
19776
|
+
id: self.ID ?? self.DNSName ?? self.HostName ?? "self",
|
|
19777
|
+
name: self.HostName ?? self.DNSName ?? "self",
|
|
19778
|
+
dnsName: self.DNSName,
|
|
19779
|
+
addresses: self.TailscaleIPs ?? [],
|
|
19780
|
+
online: self.Online ?? true,
|
|
19781
|
+
hostName: self.HostName,
|
|
19782
|
+
os: self.OS,
|
|
19783
|
+
tailnetName: status.CurrentTailnet?.Name,
|
|
19784
|
+
magicDnsSuffix: status.CurrentTailnet?.MagicDNSSuffix
|
|
19785
|
+
};
|
|
19786
|
+
}
|
|
19787
|
+
async function readStatusJsonFromFile(filePath) {
|
|
19788
|
+
const raw2 = await readFile7(filePath, "utf8");
|
|
19789
|
+
return parseStatusJson(raw2);
|
|
19790
|
+
}
|
|
19791
|
+
async function readStatusJson() {
|
|
19792
|
+
const fixturePath = process.env.OPENSCOUT_TAILSCALE_STATUS_JSON;
|
|
19793
|
+
if (fixturePath) {
|
|
19794
|
+
return readStatusJsonFromFile(fixturePath);
|
|
19795
|
+
}
|
|
19796
|
+
try {
|
|
19797
|
+
const tailscaleBin = process.env.OPENSCOUT_TAILSCALE_BIN ?? "tailscale";
|
|
19798
|
+
const { stdout } = await execFileAsync(tailscaleBin, ["status", "--json"]);
|
|
19799
|
+
return parseStatusJson(stdout);
|
|
19800
|
+
} catch {
|
|
19801
|
+
return null;
|
|
19802
|
+
}
|
|
19803
|
+
}
|
|
19804
|
+
async function readTailscalePeers() {
|
|
19805
|
+
const status = await readStatusJson();
|
|
19806
|
+
if (!status) {
|
|
19807
|
+
return [];
|
|
19808
|
+
}
|
|
19809
|
+
return parsePeers(status);
|
|
19810
|
+
}
|
|
19811
|
+
async function readTailscaleSelf() {
|
|
19812
|
+
const status = await readStatusJson();
|
|
19813
|
+
if (!status) {
|
|
19814
|
+
return null;
|
|
19815
|
+
}
|
|
19816
|
+
return parseSelf(status);
|
|
19817
|
+
}
|
|
19818
|
+
|
|
19819
|
+
// packages/runtime/src/index.ts
|
|
19820
|
+
init_broker_service();
|
|
19821
|
+
init_local_agents();
|
|
19822
|
+
|
|
19823
|
+
// packages/runtime/src/scout-broker.ts
|
|
19824
|
+
init_dist2();
|
|
19825
|
+
init_setup();
|
|
19826
|
+
init_support_paths();
|
|
19827
|
+
await __promiseAll([
|
|
19828
|
+
init_local_agents(),
|
|
19829
|
+
init_broker_service()
|
|
19830
|
+
]);
|
|
19831
|
+
|
|
19832
|
+
// packages/runtime/src/index.ts
|
|
19833
|
+
init_codex_app_server();
|
|
19834
|
+
init_setup();
|
|
19835
|
+
init_support_paths();
|
|
19836
|
+
|
|
19837
|
+
// packages/runtime/src/scout-agent-cards.ts
|
|
19838
|
+
init_dist2();
|
|
19839
|
+
// packages/runtime/src/thread-events.ts
|
|
19840
|
+
class ThreadWatchProtocolError extends Error {
|
|
19841
|
+
status;
|
|
19842
|
+
body;
|
|
19843
|
+
constructor(status, body) {
|
|
19844
|
+
super(body.message);
|
|
19845
|
+
this.status = status;
|
|
19846
|
+
this.body = body;
|
|
19847
|
+
}
|
|
19848
|
+
}
|
|
19849
|
+
function watchKey(conversationId, watcherNodeId, watcherId) {
|
|
19850
|
+
return `${conversationId}:${watcherNodeId}:${watcherId}`;
|
|
19851
|
+
}
|
|
19852
|
+
function writeSse(response, eventName, payload) {
|
|
19853
|
+
response.write(`event: ${eventName}
|
|
19854
|
+
data: ${JSON.stringify(payload)}
|
|
19855
|
+
|
|
19856
|
+
`);
|
|
19857
|
+
}
|
|
19858
|
+
|
|
19859
|
+
class ThreadEventPlane {
|
|
19860
|
+
options;
|
|
19861
|
+
watches = new Map;
|
|
19862
|
+
watchIdsByKey = new Map;
|
|
19863
|
+
watchIdsByConversation = new Map;
|
|
19864
|
+
constructor(options) {
|
|
19865
|
+
this.options = options;
|
|
19866
|
+
}
|
|
19867
|
+
async openWatch(request) {
|
|
19868
|
+
const conversation = this.requireConversationAuthority(request.conversationId);
|
|
19869
|
+
this.requireRemoteWatchAllowed(conversation);
|
|
19870
|
+
const afterSeq = Math.max(0, request.afterSeq ?? 0);
|
|
19871
|
+
const oldestSeq = await this.options.projection.oldestThreadSeq(conversation.id);
|
|
19872
|
+
const latestSeq = await this.options.projection.latestThreadSeq(conversation.id);
|
|
19873
|
+
if (latestSeq > 0 && oldestSeq > 0 && afterSeq < oldestSeq - 1) {
|
|
19874
|
+
throw new ThreadWatchProtocolError(409, {
|
|
19875
|
+
code: "cursor_out_of_range",
|
|
19876
|
+
message: `thread cursor ${afterSeq} is older than retained seq ${oldestSeq}`
|
|
19877
|
+
});
|
|
19878
|
+
}
|
|
19879
|
+
const key = watchKey(conversation.id, request.watcherNodeId, request.watcherId);
|
|
19880
|
+
const existingWatchId = this.watchIdsByKey.get(key);
|
|
19881
|
+
if (existingWatchId) {
|
|
19882
|
+
this.closeWatchInternal(existingWatchId);
|
|
19883
|
+
}
|
|
19884
|
+
const watchId = `thread-watch:${conversation.id}:${request.watcherNodeId}:${request.watcherId}`;
|
|
19885
|
+
const leaseExpiresAt = Date.now() + this.normalizeLeaseMs(request.leaseMs);
|
|
19886
|
+
const watch = {
|
|
19887
|
+
watchId,
|
|
19888
|
+
conversationId: conversation.id,
|
|
19889
|
+
watcherNodeId: request.watcherNodeId,
|
|
19890
|
+
watcherId: request.watcherId,
|
|
19891
|
+
acceptedAfterSeq: afterSeq,
|
|
19892
|
+
leaseExpiresAt,
|
|
19893
|
+
mode: conversation.shareMode === "summary" ? "summary" : "shared",
|
|
19894
|
+
clients: new Set
|
|
19895
|
+
};
|
|
19896
|
+
this.watches.set(watchId, watch);
|
|
19897
|
+
this.watchIdsByKey.set(key, watchId);
|
|
19898
|
+
this.indexWatch(watch);
|
|
19899
|
+
return {
|
|
19900
|
+
watchId,
|
|
19901
|
+
conversationId: conversation.id,
|
|
19902
|
+
authorityNodeId: conversation.authorityNodeId,
|
|
19903
|
+
acceptedAfterSeq: afterSeq,
|
|
19904
|
+
latestSeq,
|
|
19905
|
+
leaseExpiresAt,
|
|
19906
|
+
mode: watch.mode
|
|
19907
|
+
};
|
|
19908
|
+
}
|
|
19909
|
+
async renewWatch(request) {
|
|
19910
|
+
const watch = this.requireLiveWatch(request.watchId);
|
|
19911
|
+
watch.leaseExpiresAt = Date.now() + this.normalizeLeaseMs(request.leaseMs);
|
|
19912
|
+
return {
|
|
19913
|
+
watchId: watch.watchId,
|
|
19914
|
+
leaseExpiresAt: watch.leaseExpiresAt
|
|
19915
|
+
};
|
|
19916
|
+
}
|
|
19917
|
+
async closeWatch(request) {
|
|
19918
|
+
this.closeWatchInternal(request.watchId);
|
|
19919
|
+
}
|
|
19920
|
+
async replay(options) {
|
|
19921
|
+
const conversation = this.requireConversationAuthority(options.conversationId);
|
|
19922
|
+
this.requireRemoteWatchAllowed(conversation);
|
|
19923
|
+
const oldestSeq = await this.options.projection.oldestThreadSeq(conversation.id);
|
|
19924
|
+
const latestSeq = await this.options.projection.latestThreadSeq(conversation.id);
|
|
19925
|
+
if (latestSeq > 0 && oldestSeq > 0 && options.afterSeq < oldestSeq - 1) {
|
|
19926
|
+
throw new ThreadWatchProtocolError(409, {
|
|
19927
|
+
code: "cursor_out_of_range",
|
|
19928
|
+
message: `thread cursor ${options.afterSeq} is older than retained seq ${oldestSeq}`
|
|
19929
|
+
});
|
|
19930
|
+
}
|
|
19931
|
+
return this.options.projection.listThreadEvents({
|
|
19932
|
+
conversationId: conversation.id,
|
|
19933
|
+
afterSeq: options.afterSeq,
|
|
19934
|
+
limit: Math.min(options.limit ?? 500, this.options.maxReplayLimit ?? 2000)
|
|
19935
|
+
});
|
|
19936
|
+
}
|
|
19937
|
+
async snapshot(conversationId) {
|
|
19938
|
+
const conversation = this.requireConversationAuthority(conversationId);
|
|
19939
|
+
this.requireRemoteWatchAllowed(conversation);
|
|
19940
|
+
const snapshot = await this.options.projection.getThreadSnapshot(conversation.id);
|
|
19941
|
+
if (!snapshot) {
|
|
19942
|
+
throw new ThreadWatchProtocolError(404, {
|
|
19943
|
+
code: "unknown_conversation",
|
|
19944
|
+
message: `unknown conversation ${conversation.id}`
|
|
19945
|
+
});
|
|
19946
|
+
}
|
|
19947
|
+
return snapshot;
|
|
19948
|
+
}
|
|
19949
|
+
async streamWatch(watchId, request, response) {
|
|
19950
|
+
const watch = this.requireLiveWatch(watchId);
|
|
19951
|
+
const backlog = await this.options.projection.listThreadEvents({
|
|
19952
|
+
conversationId: watch.conversationId,
|
|
19953
|
+
afterSeq: watch.acceptedAfterSeq,
|
|
19954
|
+
limit: this.options.maxReplayLimit ?? 2000
|
|
19955
|
+
});
|
|
19956
|
+
response.writeHead(200, {
|
|
19957
|
+
"content-type": "text/event-stream",
|
|
19958
|
+
"cache-control": "no-cache, no-transform",
|
|
19959
|
+
connection: "keep-alive"
|
|
19960
|
+
});
|
|
19961
|
+
writeSse(response, "hello", {
|
|
19962
|
+
watchId: watch.watchId,
|
|
19963
|
+
conversationId: watch.conversationId,
|
|
19964
|
+
leaseExpiresAt: watch.leaseExpiresAt
|
|
19965
|
+
});
|
|
19966
|
+
for (const event of backlog) {
|
|
19967
|
+
writeSse(response, "thread.event", event);
|
|
19968
|
+
}
|
|
19969
|
+
watch.clients.add(response);
|
|
19970
|
+
request.on("close", () => {
|
|
19971
|
+
watch.clients.delete(response);
|
|
19972
|
+
response.end();
|
|
19973
|
+
});
|
|
19974
|
+
}
|
|
19975
|
+
publish(events2) {
|
|
19976
|
+
for (const event of events2) {
|
|
19977
|
+
const watchIds = this.watchIdsByConversation.get(event.conversationId);
|
|
19978
|
+
if (!watchIds || watchIds.size === 0) {
|
|
19979
|
+
continue;
|
|
19980
|
+
}
|
|
19981
|
+
for (const watchId of [...watchIds]) {
|
|
19982
|
+
const watch = this.watches.get(watchId);
|
|
19983
|
+
if (!watch) {
|
|
19984
|
+
watchIds.delete(watchId);
|
|
19985
|
+
continue;
|
|
19986
|
+
}
|
|
19987
|
+
if (watch.leaseExpiresAt <= Date.now()) {
|
|
19988
|
+
this.closeWatchInternal(watchId);
|
|
19989
|
+
continue;
|
|
19990
|
+
}
|
|
19991
|
+
for (const client of watch.clients) {
|
|
19992
|
+
writeSse(client, "thread.event", event);
|
|
19993
|
+
}
|
|
19994
|
+
}
|
|
19995
|
+
}
|
|
19996
|
+
}
|
|
19997
|
+
normalizeLeaseMs(requestedLeaseMs) {
|
|
19998
|
+
const defaultLeaseMs = this.options.defaultLeaseMs ?? 30000;
|
|
19999
|
+
const maxLeaseMs = this.options.maxLeaseMs ?? 300000;
|
|
20000
|
+
if (!requestedLeaseMs || !Number.isFinite(requestedLeaseMs) || requestedLeaseMs <= 0) {
|
|
20001
|
+
return defaultLeaseMs;
|
|
20002
|
+
}
|
|
20003
|
+
return Math.min(Math.max(requestedLeaseMs, 5000), maxLeaseMs);
|
|
20004
|
+
}
|
|
20005
|
+
requireConversationAuthority(conversationId) {
|
|
20006
|
+
const conversation = this.options.runtime.conversation(conversationId);
|
|
20007
|
+
if (!conversation) {
|
|
20008
|
+
throw new ThreadWatchProtocolError(404, {
|
|
20009
|
+
code: "unknown_conversation",
|
|
20010
|
+
message: `unknown conversation ${conversationId}`
|
|
20011
|
+
});
|
|
20012
|
+
}
|
|
20013
|
+
if (conversation.authorityNodeId !== this.options.nodeId) {
|
|
20014
|
+
throw new ThreadWatchProtocolError(409, {
|
|
20015
|
+
code: "no_responder",
|
|
20016
|
+
message: `conversation ${conversationId} is owned by ${conversation.authorityNodeId}`
|
|
20017
|
+
});
|
|
20018
|
+
}
|
|
20019
|
+
return conversation;
|
|
20020
|
+
}
|
|
20021
|
+
requireRemoteWatchAllowed(conversation) {
|
|
20022
|
+
if (conversation.shareMode === "local") {
|
|
20023
|
+
throw new ThreadWatchProtocolError(403, {
|
|
20024
|
+
code: "forbidden",
|
|
20025
|
+
message: `conversation ${conversation.id} does not allow remote watches`
|
|
20026
|
+
});
|
|
20027
|
+
}
|
|
20028
|
+
}
|
|
20029
|
+
requireLiveWatch(watchId) {
|
|
20030
|
+
const watch = this.watches.get(watchId);
|
|
20031
|
+
if (!watch) {
|
|
20032
|
+
throw new ThreadWatchProtocolError(404, {
|
|
20033
|
+
code: "invalid_request",
|
|
20034
|
+
message: `unknown watch ${watchId}`
|
|
20035
|
+
});
|
|
20036
|
+
}
|
|
20037
|
+
if (watch.leaseExpiresAt <= Date.now()) {
|
|
20038
|
+
this.closeWatchInternal(watchId);
|
|
20039
|
+
throw new ThreadWatchProtocolError(410, {
|
|
20040
|
+
code: "lease_expired",
|
|
20041
|
+
message: `watch ${watchId} lease expired`
|
|
20042
|
+
});
|
|
20043
|
+
}
|
|
20044
|
+
return watch;
|
|
20045
|
+
}
|
|
20046
|
+
indexWatch(watch) {
|
|
20047
|
+
const ids = this.watchIdsByConversation.get(watch.conversationId) ?? new Set;
|
|
20048
|
+
ids.add(watch.watchId);
|
|
20049
|
+
this.watchIdsByConversation.set(watch.conversationId, ids);
|
|
20050
|
+
}
|
|
20051
|
+
closeWatchInternal(watchId) {
|
|
20052
|
+
const watch = this.watches.get(watchId);
|
|
20053
|
+
if (!watch) {
|
|
20054
|
+
return;
|
|
20055
|
+
}
|
|
20056
|
+
this.watches.delete(watchId);
|
|
20057
|
+
this.watchIdsByKey.delete(watchKey(watch.conversationId, watch.watcherNodeId, watch.watcherId));
|
|
20058
|
+
const ids = this.watchIdsByConversation.get(watch.conversationId);
|
|
20059
|
+
if (ids) {
|
|
20060
|
+
ids.delete(watchId);
|
|
20061
|
+
if (ids.size === 0) {
|
|
20062
|
+
this.watchIdsByConversation.delete(watch.conversationId);
|
|
20063
|
+
}
|
|
20064
|
+
}
|
|
20065
|
+
for (const client of watch.clients) {
|
|
20066
|
+
client.end();
|
|
20067
|
+
}
|
|
20068
|
+
watch.clients.clear();
|
|
20069
|
+
}
|
|
20070
|
+
}
|
|
20071
|
+
// packages/runtime/src/mobile-push.ts
|
|
20072
|
+
init_support_paths();
|
|
20073
|
+
// packages/web/server/core/observe/service.ts
|
|
20074
|
+
function activeEndpoint(snapshot, agentId) {
|
|
20075
|
+
const candidates = Object.values(snapshot.endpoints ?? {}).filter((endpoint) => endpoint.agentId === agentId);
|
|
20076
|
+
const rank = (state) => {
|
|
20077
|
+
switch (state) {
|
|
20078
|
+
case "active":
|
|
20079
|
+
return 0;
|
|
20080
|
+
case "idle":
|
|
20081
|
+
return 1;
|
|
20082
|
+
case "waiting":
|
|
20083
|
+
return 2;
|
|
20084
|
+
case "offline":
|
|
20085
|
+
return 5;
|
|
20086
|
+
default:
|
|
20087
|
+
return 4;
|
|
20088
|
+
}
|
|
20089
|
+
};
|
|
20090
|
+
return [...candidates].sort((left, right) => rank(left.state) - rank(right.state))[0] ?? null;
|
|
20091
|
+
}
|
|
20092
|
+
function expandHome(value) {
|
|
20093
|
+
if (!value) {
|
|
20094
|
+
return null;
|
|
20095
|
+
}
|
|
20096
|
+
if (value === "~") {
|
|
20097
|
+
return homedir12();
|
|
20098
|
+
}
|
|
20099
|
+
if (value.startsWith("~/")) {
|
|
20100
|
+
return join18(homedir12(), value.slice(2));
|
|
20101
|
+
}
|
|
20102
|
+
return value;
|
|
20103
|
+
}
|
|
20104
|
+
function encodeClaudeProjectsSlug2(absolutePath) {
|
|
20105
|
+
const normalized = resolve8(absolutePath);
|
|
20106
|
+
return `-${normalized.replace(/^\//u, "").replace(/\//gu, "-")}`;
|
|
20107
|
+
}
|
|
20108
|
+
function resolveClaudeHistoryPath(cwd, sessionId) {
|
|
20109
|
+
const normalizedCwd = expandHome(cwd)?.trim();
|
|
20110
|
+
const normalizedSessionId = sessionId?.trim().replace(/\.jsonl$/u, "") || "";
|
|
20111
|
+
if (!normalizedCwd || !normalizedSessionId) {
|
|
20112
|
+
return null;
|
|
20113
|
+
}
|
|
20114
|
+
return join18(homedir12(), ".claude", "projects", encodeClaudeProjectsSlug2(normalizedCwd), `${normalizedSessionId}.jsonl`);
|
|
20115
|
+
}
|
|
20116
|
+
function historyAdapterAlias(value) {
|
|
20117
|
+
const normalized = value?.trim().toLowerCase();
|
|
20118
|
+
if (!normalized) {
|
|
20119
|
+
return null;
|
|
20120
|
+
}
|
|
20121
|
+
if (normalized === "claude" || normalized === "claude-code" || normalized === "claude_stream_json") {
|
|
20122
|
+
return "claude-code";
|
|
20123
|
+
}
|
|
20124
|
+
if (normalized === "codex" || normalized === "codex_app_server") {
|
|
20125
|
+
return "codex";
|
|
20126
|
+
}
|
|
20127
|
+
return null;
|
|
20128
|
+
}
|
|
20129
|
+
function snapshotProviderMeta(snapshot) {
|
|
20130
|
+
const providerMeta = snapshot.session.providerMeta;
|
|
20131
|
+
return providerMeta && typeof providerMeta === "object" ? providerMeta : {};
|
|
20132
|
+
}
|
|
20133
|
+
function firstString(...values) {
|
|
20134
|
+
for (const value of values) {
|
|
20135
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
20136
|
+
return value.trim();
|
|
20137
|
+
}
|
|
20138
|
+
}
|
|
20139
|
+
return null;
|
|
20140
|
+
}
|
|
20141
|
+
function resolveHistoryCandidate(agent, snapshot) {
|
|
20142
|
+
const snapshotAdapter = historyAdapterAlias(snapshot?.session.adapterType);
|
|
20143
|
+
const agentAdapter = historyAdapterAlias(agent.harness);
|
|
20144
|
+
const providerMeta = snapshot ? snapshotProviderMeta(snapshot) : {};
|
|
20145
|
+
const directPath = firstString(providerMeta.resumeSessionPath, providerMeta.threadPath);
|
|
20146
|
+
if (directPath) {
|
|
20147
|
+
const adapterType = snapshotAdapter ?? agentAdapter;
|
|
20148
|
+
if (adapterType) {
|
|
20149
|
+
return { path: directPath, adapterType };
|
|
20150
|
+
}
|
|
20151
|
+
}
|
|
20152
|
+
const claudeSessionId = firstString(providerMeta.transportSessionId, agent.harnessSessionId);
|
|
20153
|
+
const claudeCwd = firstString(snapshot?.session.cwd, agent.cwd, agent.projectRoot);
|
|
20154
|
+
if ((snapshotAdapter ?? agentAdapter) === "claude-code") {
|
|
20155
|
+
const path = resolveClaudeHistoryPath(claudeCwd, claudeSessionId);
|
|
20156
|
+
if (path) {
|
|
20157
|
+
return { path, adapterType: "claude-code" };
|
|
20158
|
+
}
|
|
20159
|
+
}
|
|
20160
|
+
return null;
|
|
20161
|
+
}
|
|
20162
|
+
function normalizeTimedEvents(events2) {
|
|
20163
|
+
if (!events2) {
|
|
20164
|
+
return [];
|
|
20165
|
+
}
|
|
20166
|
+
return events2.map((entry) => ({
|
|
20167
|
+
timestamp: entry.capturedAt,
|
|
20168
|
+
event: entry.event
|
|
20169
|
+
}));
|
|
20170
|
+
}
|
|
20171
|
+
function readHistorySnapshot(candidate) {
|
|
20172
|
+
if (!candidate) {
|
|
20173
|
+
return null;
|
|
20174
|
+
}
|
|
20175
|
+
if (!supportsHistorySessionSnapshotForPath(candidate.path, candidate.adapterType)) {
|
|
20176
|
+
return null;
|
|
20177
|
+
}
|
|
20178
|
+
if (!existsSync11(candidate.path)) {
|
|
20179
|
+
return null;
|
|
20180
|
+
}
|
|
20181
|
+
const stat5 = statSync4(candidate.path);
|
|
20182
|
+
const replay = createHistorySessionSnapshot({
|
|
20183
|
+
path: candidate.path,
|
|
20184
|
+
content: readFileSync7(candidate.path, "utf8"),
|
|
20185
|
+
adapterType: candidate.adapterType,
|
|
20186
|
+
baseTimestampMs: stat5.mtimeMs
|
|
20187
|
+
});
|
|
20188
|
+
return {
|
|
20189
|
+
historyPath: candidate.path,
|
|
20190
|
+
snapshot: replay.snapshot,
|
|
20191
|
+
timedEvents: normalizeTimedEvents(replay.events)
|
|
20192
|
+
};
|
|
20193
|
+
}
|
|
20194
|
+
async function readLiveSnapshot(endpoint) {
|
|
20195
|
+
if (!endpoint?.sessionId) {
|
|
20196
|
+
return null;
|
|
20197
|
+
}
|
|
20198
|
+
if (endpoint.transport === "pairing_bridge") {
|
|
20199
|
+
return await getScoutWebPairingSessionSnapshot(endpoint.sessionId);
|
|
20200
|
+
}
|
|
20201
|
+
if (endpoint.transport === "codex_app_server" || endpoint.transport === "claude_stream_json") {
|
|
20202
|
+
return await getLocalAgentEndpointSessionSnapshot(endpoint);
|
|
20203
|
+
}
|
|
20204
|
+
return null;
|
|
20205
|
+
}
|
|
20206
|
+
function summarizeCommandOutput(output) {
|
|
20207
|
+
const lines = output.split(/\r?\n/u).map((line) => line.trimEnd()).filter((line) => line.length > 0);
|
|
20208
|
+
if (lines.length === 0) {
|
|
20209
|
+
return;
|
|
20210
|
+
}
|
|
20211
|
+
return lines.slice(-12);
|
|
20212
|
+
}
|
|
20213
|
+
function truncatePreview(value, maxLines = 6, maxChars = 400) {
|
|
20214
|
+
const lines = value.split(/\r?\n/u).map((line) => line.trimEnd()).filter((line) => line.length > 0).slice(0, maxLines);
|
|
20215
|
+
const joined = lines.join(`
|
|
20216
|
+
`);
|
|
20217
|
+
return joined.length <= maxChars ? joined : `${joined.slice(0, maxChars - 1).trimEnd()}\u2026`;
|
|
20218
|
+
}
|
|
20219
|
+
function countDiffStats(value) {
|
|
20220
|
+
let add = 0;
|
|
20221
|
+
let del = 0;
|
|
20222
|
+
for (const line of value.split(/\r?\n/u)) {
|
|
20223
|
+
if (line.startsWith("+++ ") || line.startsWith("--- ")) {
|
|
20224
|
+
continue;
|
|
20225
|
+
}
|
|
20226
|
+
if (line.startsWith("+")) {
|
|
20227
|
+
add += 1;
|
|
20228
|
+
} else if (line.startsWith("-")) {
|
|
20229
|
+
del += 1;
|
|
20230
|
+
}
|
|
20231
|
+
}
|
|
20232
|
+
return { add, del };
|
|
20233
|
+
}
|
|
20234
|
+
function toolArgSummary(input) {
|
|
20235
|
+
if (typeof input === "string") {
|
|
20236
|
+
return input;
|
|
20237
|
+
}
|
|
20238
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
20239
|
+
return "";
|
|
20240
|
+
}
|
|
20241
|
+
const record = input;
|
|
20242
|
+
const preferred = firstString(record.file_path, record.path, record.command, record.pattern, record.query, record.glob, record.prompt, record.description);
|
|
20243
|
+
if (preferred) {
|
|
20244
|
+
return preferred;
|
|
20245
|
+
}
|
|
20246
|
+
try {
|
|
20247
|
+
return JSON.stringify(record);
|
|
20248
|
+
} catch {
|
|
20249
|
+
return "";
|
|
20250
|
+
}
|
|
20251
|
+
}
|
|
20252
|
+
function normalizeToolName(toolName) {
|
|
20253
|
+
switch (toolName.trim().toLowerCase()) {
|
|
20254
|
+
case "read":
|
|
20255
|
+
case "view":
|
|
20256
|
+
return "read";
|
|
20257
|
+
case "grep":
|
|
20258
|
+
case "glob":
|
|
20259
|
+
case "search":
|
|
20260
|
+
return "grep";
|
|
20261
|
+
case "edit":
|
|
20262
|
+
case "multiedit":
|
|
20263
|
+
return "edit";
|
|
20264
|
+
case "write":
|
|
20265
|
+
return "write";
|
|
20266
|
+
case "bash":
|
|
20267
|
+
return "bash";
|
|
20268
|
+
case "agent":
|
|
20269
|
+
return "agent";
|
|
20270
|
+
default:
|
|
20271
|
+
return toolName.trim().toLowerCase() || "tool";
|
|
20272
|
+
}
|
|
20273
|
+
}
|
|
20274
|
+
function fileStatePriority(state) {
|
|
20275
|
+
switch (state) {
|
|
20276
|
+
case "created":
|
|
20277
|
+
return 3;
|
|
20278
|
+
case "modified":
|
|
20279
|
+
return 2;
|
|
20280
|
+
case "read":
|
|
20281
|
+
return 1;
|
|
20282
|
+
}
|
|
20283
|
+
}
|
|
20284
|
+
function addTouchedFile(files, path, state, lastT) {
|
|
20285
|
+
const normalizedPath = path.trim();
|
|
20286
|
+
if (!normalizedPath) {
|
|
20287
|
+
return;
|
|
20288
|
+
}
|
|
20289
|
+
const existing = files.get(normalizedPath);
|
|
20290
|
+
if (!existing) {
|
|
20291
|
+
files.set(normalizedPath, {
|
|
20292
|
+
path: normalizedPath,
|
|
20293
|
+
state,
|
|
20294
|
+
touches: 1,
|
|
20295
|
+
lastT
|
|
20296
|
+
});
|
|
20297
|
+
return;
|
|
20298
|
+
}
|
|
20299
|
+
existing.touches += 1;
|
|
20300
|
+
existing.lastT = Math.max(existing.lastT, lastT);
|
|
20301
|
+
if (fileStatePriority(state) > fileStatePriority(existing.state)) {
|
|
20302
|
+
existing.state = state;
|
|
20303
|
+
}
|
|
20304
|
+
}
|
|
20305
|
+
function detectFileTouches(block, t, files) {
|
|
20306
|
+
if (block.type !== "action") {
|
|
20307
|
+
return;
|
|
20308
|
+
}
|
|
20309
|
+
const { action } = block;
|
|
20310
|
+
if (action.kind === "file_change" && action.path.trim()) {
|
|
20311
|
+
addTouchedFile(files, action.path, "modified", t);
|
|
20312
|
+
return;
|
|
20313
|
+
}
|
|
20314
|
+
if (action.kind !== "tool_call") {
|
|
20315
|
+
return;
|
|
20316
|
+
}
|
|
20317
|
+
const toolName = normalizeToolName(action.toolName);
|
|
20318
|
+
const input = action.input;
|
|
20319
|
+
const path = firstString(input?.file_path, input?.path);
|
|
20320
|
+
if (!path) {
|
|
20321
|
+
return;
|
|
20322
|
+
}
|
|
20323
|
+
if (toolName === "read" || toolName === "grep") {
|
|
20324
|
+
addTouchedFile(files, path, "read", t);
|
|
20325
|
+
return;
|
|
20326
|
+
}
|
|
20327
|
+
if (toolName === "write") {
|
|
20328
|
+
addTouchedFile(files, path, "created", t);
|
|
20329
|
+
return;
|
|
20330
|
+
}
|
|
20331
|
+
if (toolName === "edit") {
|
|
20332
|
+
addTouchedFile(files, path, "modified", t);
|
|
20333
|
+
}
|
|
20334
|
+
}
|
|
20335
|
+
function buildTimingLookup(snapshot, timedEvents) {
|
|
20336
|
+
const turnStartedAtMs = new Map;
|
|
20337
|
+
const turnEndedAtMs = new Map;
|
|
20338
|
+
const blockStartedAtMs = new Map;
|
|
20339
|
+
const questionAnsweredAtMs = new Map;
|
|
20340
|
+
let bootTimestampMs = Number.POSITIVE_INFINITY;
|
|
20341
|
+
for (const entry of timedEvents) {
|
|
20342
|
+
if (entry.event.event === "session:update") {
|
|
20343
|
+
bootTimestampMs = Math.min(bootTimestampMs, entry.timestamp);
|
|
20344
|
+
continue;
|
|
20345
|
+
}
|
|
20346
|
+
if (entry.event.event === "turn:start") {
|
|
20347
|
+
turnStartedAtMs.set(entry.event.turn.id, entry.timestamp);
|
|
20348
|
+
bootTimestampMs = Math.min(bootTimestampMs, entry.timestamp);
|
|
20349
|
+
continue;
|
|
20350
|
+
}
|
|
20351
|
+
if (entry.event.event === "turn:end" || entry.event.event === "turn:error") {
|
|
20352
|
+
turnEndedAtMs.set(entry.event.turnId, entry.timestamp);
|
|
20353
|
+
continue;
|
|
20354
|
+
}
|
|
20355
|
+
if (entry.event.event === "block:start") {
|
|
20356
|
+
blockStartedAtMs.set(entry.event.block.id, entry.timestamp);
|
|
20357
|
+
continue;
|
|
20358
|
+
}
|
|
20359
|
+
if (entry.event.event === "block:question:answer") {
|
|
20360
|
+
questionAnsweredAtMs.set(entry.event.blockId, entry.timestamp);
|
|
20361
|
+
}
|
|
20362
|
+
}
|
|
20363
|
+
for (const turn of snapshot.turns) {
|
|
20364
|
+
if (!turnStartedAtMs.has(turn.id) && Number.isFinite(turn.startedAt)) {
|
|
20365
|
+
turnStartedAtMs.set(turn.id, turn.startedAt);
|
|
20366
|
+
}
|
|
20367
|
+
if (!turnEndedAtMs.has(turn.id) && Number.isFinite(turn.endedAt ?? NaN)) {
|
|
20368
|
+
turnEndedAtMs.set(turn.id, turn.endedAt);
|
|
20369
|
+
}
|
|
20370
|
+
bootTimestampMs = Math.min(bootTimestampMs, turnStartedAtMs.get(turn.id) ?? Number.POSITIVE_INFINITY);
|
|
20371
|
+
}
|
|
20372
|
+
if (!Number.isFinite(bootTimestampMs)) {
|
|
20373
|
+
bootTimestampMs = Date.now();
|
|
20374
|
+
}
|
|
20375
|
+
return {
|
|
20376
|
+
baseTimestampMs: bootTimestampMs,
|
|
20377
|
+
bootTimestampMs,
|
|
20378
|
+
turnStartedAtMs,
|
|
20379
|
+
turnEndedAtMs,
|
|
20380
|
+
blockStartedAtMs,
|
|
20381
|
+
questionAnsweredAtMs
|
|
20382
|
+
};
|
|
20383
|
+
}
|
|
20384
|
+
function blockTimestampMs(turnId, block, turnBlockCount, timing) {
|
|
20385
|
+
const explicit = timing.blockStartedAtMs.get(block.id);
|
|
20386
|
+
if (typeof explicit === "number" && Number.isFinite(explicit)) {
|
|
20387
|
+
return explicit;
|
|
20388
|
+
}
|
|
20389
|
+
const turnStart = timing.turnStartedAtMs.get(turnId) ?? timing.baseTimestampMs;
|
|
20390
|
+
const turnEnd = timing.turnEndedAtMs.get(turnId) ?? turnStart + Math.max(3000, turnBlockCount * 2000);
|
|
20391
|
+
const duration = Math.max(1000, turnEnd - turnStart);
|
|
20392
|
+
const step = duration / Math.max(1, turnBlockCount + 1);
|
|
20393
|
+
return Math.round(turnStart + step * (block.index + 1));
|
|
20394
|
+
}
|
|
20395
|
+
function timelineSeconds(values, baseTimestampMs) {
|
|
20396
|
+
let last = 0;
|
|
20397
|
+
return values.map((timestamp) => {
|
|
20398
|
+
const seconds = Math.max(0, Math.round((timestamp - baseTimestampMs) / 1000));
|
|
20399
|
+
last = Math.max(last, seconds);
|
|
20400
|
+
return last;
|
|
20401
|
+
});
|
|
20402
|
+
}
|
|
20403
|
+
function syntheticContextUsage(eventCount) {
|
|
20404
|
+
if (eventCount <= 0) {
|
|
20405
|
+
return [];
|
|
20406
|
+
}
|
|
20407
|
+
const length = Math.max(2, Math.min(eventCount, 24));
|
|
20408
|
+
return Array.from({ length }, (_, index2) => {
|
|
20409
|
+
const progress = length <= 1 ? 1 : index2 / (length - 1);
|
|
20410
|
+
return Math.min(0.92, 0.08 + progress * 0.66);
|
|
20411
|
+
});
|
|
20412
|
+
}
|
|
20413
|
+
function buildObserveDataFromSnapshot(snapshot, timedEvents = [], live = false) {
|
|
20414
|
+
const timing = buildTimingLookup(snapshot, timedEvents);
|
|
20415
|
+
const files = new Map;
|
|
20416
|
+
const eventDrafts = [
|
|
20417
|
+
{
|
|
20418
|
+
timestampMs: timing.bootTimestampMs,
|
|
20419
|
+
build: (t) => ({
|
|
20420
|
+
id: `${snapshot.session.id}:boot`,
|
|
20421
|
+
t,
|
|
20422
|
+
kind: "boot",
|
|
20423
|
+
text: `Session started \xB7 ${snapshot.session.model ?? snapshot.session.adapterType}`,
|
|
20424
|
+
detail: [
|
|
20425
|
+
snapshot.session.cwd ? `workspace: ${snapshot.session.cwd}` : null,
|
|
20426
|
+
`turns: ${snapshot.turns.length}`,
|
|
20427
|
+
`status: ${snapshot.session.status}`
|
|
20428
|
+
].filter(Boolean).join(" \xB7 ")
|
|
20429
|
+
})
|
|
20430
|
+
}
|
|
20431
|
+
];
|
|
20432
|
+
for (const turn of snapshot.turns) {
|
|
20433
|
+
const turnBlockCount = turn.blocks.length;
|
|
20434
|
+
for (const blockState of turn.blocks) {
|
|
20435
|
+
const { block } = blockState;
|
|
20436
|
+
const timestampMs = blockTimestampMs(turn.id, block, turnBlockCount, timing);
|
|
20437
|
+
eventDrafts.push({
|
|
20438
|
+
timestampMs,
|
|
20439
|
+
block,
|
|
20440
|
+
build: (t) => {
|
|
20441
|
+
switch (block.type) {
|
|
20442
|
+
case "reasoning":
|
|
20443
|
+
return {
|
|
20444
|
+
id: block.id,
|
|
20445
|
+
t,
|
|
20446
|
+
kind: "think",
|
|
20447
|
+
text: block.text.trim(),
|
|
20448
|
+
live: live && snapshot.currentTurnId === turn.id && blockState.status === "streaming"
|
|
20449
|
+
};
|
|
20450
|
+
case "text":
|
|
20451
|
+
return {
|
|
20452
|
+
id: block.id,
|
|
20453
|
+
t,
|
|
20454
|
+
kind: "message",
|
|
20455
|
+
text: block.text.trim(),
|
|
20456
|
+
to: "human"
|
|
20457
|
+
};
|
|
20458
|
+
case "question": {
|
|
20459
|
+
const answeredAt = timing.questionAnsweredAtMs.get(block.id);
|
|
20460
|
+
return {
|
|
20461
|
+
id: block.id,
|
|
20462
|
+
t,
|
|
20463
|
+
kind: "ask",
|
|
20464
|
+
text: block.question.trim(),
|
|
20465
|
+
to: "human",
|
|
20466
|
+
answer: block.answer?.join(", "),
|
|
20467
|
+
answerT: answeredAt ? Math.max(t, Math.round((answeredAt - timing.baseTimestampMs) / 1000)) : undefined
|
|
20468
|
+
};
|
|
20469
|
+
}
|
|
20470
|
+
case "error":
|
|
20471
|
+
return {
|
|
20472
|
+
id: block.id,
|
|
20473
|
+
t,
|
|
20474
|
+
kind: "system",
|
|
20475
|
+
text: block.message,
|
|
20476
|
+
detail: block.code
|
|
20477
|
+
};
|
|
20478
|
+
case "file":
|
|
20479
|
+
return {
|
|
20480
|
+
id: block.id,
|
|
20481
|
+
t,
|
|
20482
|
+
kind: "note",
|
|
20483
|
+
text: block.name ? `Generated file ${block.name}` : "Generated file artifact"
|
|
20484
|
+
};
|
|
20485
|
+
case "action": {
|
|
20486
|
+
if (block.action.kind === "command") {
|
|
20487
|
+
return {
|
|
20488
|
+
id: block.id,
|
|
20489
|
+
t,
|
|
20490
|
+
kind: "tool",
|
|
20491
|
+
text: "",
|
|
20492
|
+
tool: "bash",
|
|
20493
|
+
arg: block.action.command,
|
|
20494
|
+
stream: summarizeCommandOutput(block.action.output)
|
|
20495
|
+
};
|
|
20496
|
+
}
|
|
20497
|
+
if (block.action.kind === "file_change") {
|
|
20498
|
+
const diffBody = block.action.diff?.trim() || block.action.output.trim();
|
|
20499
|
+
const diff = diffBody ? {
|
|
20500
|
+
...countDiffStats(diffBody),
|
|
20501
|
+
preview: truncatePreview(diffBody)
|
|
20502
|
+
} : undefined;
|
|
20503
|
+
return {
|
|
20504
|
+
id: block.id,
|
|
20505
|
+
t,
|
|
20506
|
+
kind: "tool",
|
|
20507
|
+
text: "",
|
|
20508
|
+
tool: block.action.path ? "edit" : "write",
|
|
20509
|
+
arg: block.action.path,
|
|
20510
|
+
...diff ? { diff } : {}
|
|
20511
|
+
};
|
|
20512
|
+
}
|
|
20513
|
+
if (block.action.kind === "subagent") {
|
|
20514
|
+
return {
|
|
20515
|
+
id: block.id,
|
|
20516
|
+
t,
|
|
20517
|
+
kind: "tool",
|
|
20518
|
+
text: "",
|
|
20519
|
+
tool: "agent",
|
|
20520
|
+
arg: block.action.agentName ?? block.action.agentId,
|
|
20521
|
+
stream: summarizeCommandOutput(block.action.output)
|
|
20522
|
+
};
|
|
20523
|
+
}
|
|
20524
|
+
return {
|
|
20525
|
+
id: block.id,
|
|
20526
|
+
t,
|
|
20527
|
+
kind: "tool",
|
|
20528
|
+
text: "",
|
|
20529
|
+
tool: normalizeToolName(block.action.toolName),
|
|
20530
|
+
arg: toolArgSummary(block.action.input),
|
|
20531
|
+
stream: summarizeCommandOutput(block.action.output)
|
|
20532
|
+
};
|
|
20533
|
+
}
|
|
20534
|
+
}
|
|
20535
|
+
}
|
|
20536
|
+
});
|
|
20537
|
+
}
|
|
20538
|
+
}
|
|
20539
|
+
const seconds = timelineSeconds(eventDrafts.map((draft) => draft.timestampMs), timing.baseTimestampMs);
|
|
20540
|
+
const builtEntries = eventDrafts.map((draft, index2) => ({
|
|
20541
|
+
draft,
|
|
20542
|
+
event: draft.build(seconds[index2] ?? 0)
|
|
20543
|
+
})).filter(({ event }) => event.text.length > 0 || event.kind === "tool" || event.kind === "boot");
|
|
20544
|
+
const events2 = builtEntries.map((entry) => entry.event);
|
|
20545
|
+
for (const { draft, event } of builtEntries) {
|
|
20546
|
+
if (draft.block) {
|
|
20547
|
+
detectFileTouches(draft.block, event.t, files);
|
|
20548
|
+
}
|
|
20549
|
+
}
|
|
20550
|
+
return {
|
|
20551
|
+
events: events2,
|
|
20552
|
+
files: [...files.values()].sort((left, right) => right.lastT - left.lastT || left.path.localeCompare(right.path)),
|
|
20553
|
+
contextUsage: syntheticContextUsage(events2.length),
|
|
20554
|
+
live
|
|
20555
|
+
};
|
|
20556
|
+
}
|
|
20557
|
+
function unavailableObserveData(agent) {
|
|
20558
|
+
return {
|
|
20559
|
+
events: [
|
|
20560
|
+
{
|
|
20561
|
+
id: `${agent.id}:unavailable`,
|
|
20562
|
+
t: 0,
|
|
20563
|
+
kind: "system",
|
|
20564
|
+
text: "No session trace is available for this agent yet.",
|
|
20565
|
+
detail: agent.harness ? `${agent.harness} \xB7 waiting for a live session or a readable history file` : "waiting for a live session or a readable history file"
|
|
20566
|
+
}
|
|
20567
|
+
],
|
|
20568
|
+
files: [],
|
|
20569
|
+
contextUsage: [],
|
|
20570
|
+
live: false
|
|
20571
|
+
};
|
|
20572
|
+
}
|
|
20573
|
+
async function resolveSnapshotSource(agent) {
|
|
20574
|
+
const broker2 = await loadScoutBrokerContext();
|
|
20575
|
+
const endpoint = broker2 ? activeEndpoint(broker2.snapshot, agent.id) : null;
|
|
20576
|
+
const liveSnapshot = await readLiveSnapshot(endpoint);
|
|
20577
|
+
const live = Boolean(liveSnapshot && (liveSnapshot.currentTurnId || liveSnapshot.session.status === "active"));
|
|
20578
|
+
const historyCandidate = resolveHistoryCandidate(agent, liveSnapshot);
|
|
20579
|
+
const historySnapshot = readHistorySnapshot(historyCandidate);
|
|
20580
|
+
if (historySnapshot) {
|
|
20581
|
+
return {
|
|
20582
|
+
source: "history",
|
|
20583
|
+
historyPath: historySnapshot.historyPath,
|
|
20584
|
+
snapshot: historySnapshot.snapshot,
|
|
20585
|
+
timedEvents: historySnapshot.timedEvents,
|
|
20586
|
+
live,
|
|
20587
|
+
sessionId: liveSnapshot?.session.id ?? endpoint?.sessionId ?? null
|
|
20588
|
+
};
|
|
20589
|
+
}
|
|
20590
|
+
if (liveSnapshot) {
|
|
20591
|
+
return {
|
|
20592
|
+
source: "live",
|
|
20593
|
+
historyPath: historyCandidate?.path ?? null,
|
|
20594
|
+
snapshot: liveSnapshot,
|
|
20595
|
+
timedEvents: [],
|
|
20596
|
+
live,
|
|
20597
|
+
sessionId: liveSnapshot.session.id
|
|
20598
|
+
};
|
|
20599
|
+
}
|
|
20600
|
+
const agentHistorySnapshot = readHistorySnapshot(resolveHistoryCandidate(agent, null));
|
|
20601
|
+
if (agentHistorySnapshot) {
|
|
20602
|
+
return {
|
|
20603
|
+
source: "history",
|
|
20604
|
+
historyPath: agentHistorySnapshot.historyPath,
|
|
20605
|
+
snapshot: agentHistorySnapshot.snapshot,
|
|
20606
|
+
timedEvents: agentHistorySnapshot.timedEvents,
|
|
20607
|
+
live: false,
|
|
20608
|
+
sessionId: null
|
|
20609
|
+
};
|
|
20610
|
+
}
|
|
20611
|
+
return {
|
|
20612
|
+
source: "unavailable",
|
|
20613
|
+
historyPath: null,
|
|
20614
|
+
live: false,
|
|
20615
|
+
sessionId: null
|
|
20616
|
+
};
|
|
20617
|
+
}
|
|
20618
|
+
async function loadAgentObservePayload(agentId) {
|
|
20619
|
+
const agent = queryAgents(200).find((entry) => entry.id === agentId) ?? null;
|
|
20620
|
+
if (!agent) {
|
|
20621
|
+
return null;
|
|
20622
|
+
}
|
|
20623
|
+
const source = await resolveSnapshotSource(agent);
|
|
20624
|
+
if (source.source === "unavailable") {
|
|
20625
|
+
return {
|
|
20626
|
+
agentId,
|
|
20627
|
+
source: "unavailable",
|
|
20628
|
+
fidelity: "synthetic",
|
|
20629
|
+
historyPath: null,
|
|
20630
|
+
sessionId: null,
|
|
20631
|
+
updatedAt: Date.now(),
|
|
20632
|
+
data: unavailableObserveData(agent)
|
|
20633
|
+
};
|
|
20634
|
+
}
|
|
20635
|
+
const fidelity = source.timedEvents.length > 0 ? "timestamped" : "synthetic";
|
|
20636
|
+
return {
|
|
20637
|
+
agentId,
|
|
20638
|
+
source: source.source,
|
|
20639
|
+
fidelity,
|
|
20640
|
+
historyPath: source.historyPath,
|
|
20641
|
+
sessionId: source.sessionId,
|
|
20642
|
+
updatedAt: Date.now(),
|
|
20643
|
+
data: buildObserveDataFromSnapshot(source.snapshot, source.timedEvents, source.live)
|
|
20644
|
+
};
|
|
20645
|
+
}
|
|
20646
|
+
|
|
20647
|
+
// packages/web/server/core/mesh/service.ts
|
|
20648
|
+
await init_broker_service();
|
|
20649
|
+
function normalizeHost(host) {
|
|
20650
|
+
return host.trim().replace(/^\[/, "").replace(/\]$/, "").toLowerCase();
|
|
20651
|
+
}
|
|
20652
|
+
function isLoopbackHost(host) {
|
|
20653
|
+
const normalized = normalizeHost(host);
|
|
20654
|
+
return normalized === "127.0.0.1" || normalized === "::1" || normalized === "localhost";
|
|
20655
|
+
}
|
|
20656
|
+
function isWildcardHost(host) {
|
|
20657
|
+
const normalized = normalizeHost(host);
|
|
20658
|
+
return normalized === "0.0.0.0" || normalized === "::";
|
|
20659
|
+
}
|
|
20660
|
+
function isPeerReachableBrokerUrl(url) {
|
|
20661
|
+
if (!url) {
|
|
20662
|
+
return false;
|
|
20663
|
+
}
|
|
20664
|
+
try {
|
|
20665
|
+
const hostname2 = new URL(url).hostname;
|
|
20666
|
+
return !isLoopbackHost(hostname2) && !isWildcardHost(hostname2);
|
|
20667
|
+
} catch {
|
|
20668
|
+
return false;
|
|
20669
|
+
}
|
|
20670
|
+
}
|
|
20671
|
+
function stripTrailingDot(value) {
|
|
20672
|
+
const trimmed = value?.trim();
|
|
20673
|
+
if (!trimmed) {
|
|
20674
|
+
return null;
|
|
20675
|
+
}
|
|
20676
|
+
return trimmed.replace(/\.$/, "");
|
|
20677
|
+
}
|
|
20678
|
+
async function readTailscaleStatus() {
|
|
20679
|
+
const peers = await readTailscalePeers();
|
|
20680
|
+
return {
|
|
20681
|
+
available: peers.length > 0,
|
|
20682
|
+
peers,
|
|
20683
|
+
onlineCount: peers.filter((p) => p.online).length
|
|
20684
|
+
};
|
|
20685
|
+
}
|
|
20686
|
+
function formatIssueWarning(issue) {
|
|
20687
|
+
return issue.action ? `${issue.title} \u2014 ${issue.summary} ${issue.action}` : `${issue.title} \u2014 ${issue.summary}`;
|
|
20688
|
+
}
|
|
20689
|
+
function computeIssues(health, localNode, nodes, tailscale2) {
|
|
20690
|
+
const issues = [];
|
|
20691
|
+
if (!health.reachable) {
|
|
20692
|
+
issues.push({
|
|
20693
|
+
code: "broker_unreachable",
|
|
20694
|
+
severity: "error",
|
|
20695
|
+
title: "Broker not reachable",
|
|
20696
|
+
summary: "The mesh page cannot reach the local broker yet, so peer status is incomplete.",
|
|
20697
|
+
action: "Start the broker, then reload this page.",
|
|
20698
|
+
actionCommand: null
|
|
20699
|
+
});
|
|
17026
20700
|
return issues;
|
|
17027
20701
|
}
|
|
17028
20702
|
if (localNode?.advertiseScope === "local") {
|
|
@@ -17045,7 +20719,7 @@ function computeIssues(health, localNode, nodes, tailscale) {
|
|
|
17045
20719
|
});
|
|
17046
20720
|
}
|
|
17047
20721
|
const remoteNodes = Object.values(nodes).filter((n) => n.id !== localNode?.id);
|
|
17048
|
-
if (!
|
|
20722
|
+
if (!tailscale2.available && remoteNodes.length === 0) {
|
|
17049
20723
|
issues.push({
|
|
17050
20724
|
code: "discovery_unconfigured",
|
|
17051
20725
|
severity: "warning",
|
|
@@ -17134,7 +20808,7 @@ function filterCurrentMeshNodes(allNodes, meshId, localNodeId, now) {
|
|
|
17134
20808
|
}
|
|
17135
20809
|
async function loadMeshStatus() {
|
|
17136
20810
|
const brokerUrl = resolveScoutBrokerUrl();
|
|
17137
|
-
const [health, context,
|
|
20811
|
+
const [health, context, tailscale2] = await Promise.all([
|
|
17138
20812
|
readScoutBrokerHealth(brokerUrl),
|
|
17139
20813
|
loadScoutBrokerContext(brokerUrl),
|
|
17140
20814
|
readTailscaleStatus()
|
|
@@ -17144,9 +20818,9 @@ async function loadMeshStatus() {
|
|
|
17144
20818
|
const meshId = health.meshId ?? localNode?.meshId ?? null;
|
|
17145
20819
|
const identity = computeIdentitySummary(health, localNode, meshId);
|
|
17146
20820
|
const nodes = filterCurrentMeshNodes(allNodes, meshId, localNode?.id, Date.now());
|
|
17147
|
-
const issues = computeIssues(health, localNode, nodes,
|
|
20821
|
+
const issues = computeIssues(health, localNode, nodes, tailscale2);
|
|
17148
20822
|
const warnings = issues.map(formatIssueWarning);
|
|
17149
|
-
return { brokerUrl, health, localNode, meshId, identity, nodes, tailscale, issues, warnings };
|
|
20823
|
+
return { brokerUrl, health, localNode, meshId, identity, nodes, tailscale: tailscale2, issues, warnings };
|
|
17150
20824
|
}
|
|
17151
20825
|
function preferredAnnounceHost(self, currentBrokerUrl) {
|
|
17152
20826
|
const dnsName = stripTrailingDot(self?.dnsName);
|
|
@@ -17271,10 +20945,10 @@ function resolveConversationRouting(conversationId) {
|
|
|
17271
20945
|
return { directAgentId, senderId };
|
|
17272
20946
|
}
|
|
17273
20947
|
function resolveBundledStaticClientRoot(moduleUrl = import.meta.url) {
|
|
17274
|
-
return
|
|
20948
|
+
return resolve9(dirname12(fileURLToPath7(moduleUrl)), "client");
|
|
17275
20949
|
}
|
|
17276
20950
|
function resolveSourceStaticClientRoot(moduleUrl = import.meta.url) {
|
|
17277
|
-
return
|
|
20951
|
+
return resolve9(dirname12(fileURLToPath7(moduleUrl)), "../dist/client");
|
|
17278
20952
|
}
|
|
17279
20953
|
function resolveStaticRoot(staticRoot) {
|
|
17280
20954
|
const configured = staticRoot?.trim();
|
|
@@ -17282,7 +20956,7 @@ function resolveStaticRoot(staticRoot) {
|
|
|
17282
20956
|
return configured;
|
|
17283
20957
|
}
|
|
17284
20958
|
const bundled = resolveBundledStaticClientRoot(import.meta.url);
|
|
17285
|
-
if (
|
|
20959
|
+
if (existsSync12(resolve9(bundled, "index.html"))) {
|
|
17286
20960
|
return bundled;
|
|
17287
20961
|
}
|
|
17288
20962
|
return resolveSourceStaticClientRoot(import.meta.url);
|
|
@@ -17320,6 +20994,10 @@ async function createOpenScoutWebServer(options) {
|
|
|
17320
20994
|
app.get("/api/shell-state", async (c) => c.json(await shellStateCache.get()));
|
|
17321
20995
|
app.get("/api/shell-state/refresh", async (c) => c.json(await shellStateCache.refresh()));
|
|
17322
20996
|
app.get("/api/agents", (c) => c.json(queryAgents()));
|
|
20997
|
+
app.get("/api/agents/:id/observe", async (c) => {
|
|
20998
|
+
const payload = await loadAgentObservePayload(c.req.param("id"));
|
|
20999
|
+
return payload ? c.json(payload) : c.json({ error: "not found" }, 404);
|
|
21000
|
+
});
|
|
17323
21001
|
app.get("/api/activity", (c) => c.json(queryActivity()));
|
|
17324
21002
|
app.get("/api/heartrate", (c) => c.json(queryHeartrate()));
|
|
17325
21003
|
app.get("/api/fleet", (c) => c.json(queryFleet({
|
|
@@ -17563,8 +21241,8 @@ async function createOpenScoutWebServer(options) {
|
|
|
17563
21241
|
// ../hudson/packages/hudson-relay/src/relay/session.ts
|
|
17564
21242
|
import { createRequire } from "module";
|
|
17565
21243
|
import { execSync as execSync2 } from "child_process";
|
|
17566
|
-
import { existsSync as
|
|
17567
|
-
import { join as
|
|
21244
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
21245
|
+
import { join as join19, dirname as pathDirname } from "path";
|
|
17568
21246
|
var require2 = createRequire(import.meta.url);
|
|
17569
21247
|
var pty = require2("node-pty");
|
|
17570
21248
|
var DEFAULT_ORPHAN_TTL_MS = 30 * 60 * 1000;
|
|
@@ -17581,7 +21259,7 @@ function send(ws, data) {
|
|
|
17581
21259
|
function resolveCwd(raw2) {
|
|
17582
21260
|
const home = process.env.HOME || "/tmp";
|
|
17583
21261
|
const expanded = (raw2 || home).replace(/^~/, home);
|
|
17584
|
-
if (
|
|
21262
|
+
if (existsSync13(expanded))
|
|
17585
21263
|
return expanded;
|
|
17586
21264
|
try {
|
|
17587
21265
|
mkdirSync6(expanded, { recursive: true });
|
|
@@ -17617,11 +21295,11 @@ function tmuxSessionExists2(name) {
|
|
|
17617
21295
|
}
|
|
17618
21296
|
function bootstrapFiles(cwd, files, sessionId) {
|
|
17619
21297
|
for (const [relPath, content] of Object.entries(files)) {
|
|
17620
|
-
const absPath =
|
|
17621
|
-
if (!
|
|
21298
|
+
const absPath = join19(cwd, relPath);
|
|
21299
|
+
if (!existsSync13(absPath)) {
|
|
17622
21300
|
try {
|
|
17623
21301
|
const dir = pathDirname(absPath);
|
|
17624
|
-
if (!
|
|
21302
|
+
if (!existsSync13(dir))
|
|
17625
21303
|
mkdirSync6(dir, { recursive: true });
|
|
17626
21304
|
writeFileSync6(absPath, content, "utf-8");
|
|
17627
21305
|
console.log(`[relay] Session ${sessionId}: bootstrapped ${relPath}`);
|
|
@@ -17676,7 +21354,7 @@ function createSession(ws, msg) {
|
|
|
17676
21354
|
return null;
|
|
17677
21355
|
}
|
|
17678
21356
|
}
|
|
17679
|
-
if (!
|
|
21357
|
+
if (!existsSync13(agentBin)) {
|
|
17680
21358
|
const reason = `${agent} binary not found at ${agentBin}`;
|
|
17681
21359
|
console.error(`[relay] Session ${id} failed: ${reason}`);
|
|
17682
21360
|
send(ws, { type: "session:error", error: reason });
|
|
@@ -17836,7 +21514,7 @@ function destroy(sessionId) {
|
|
|
17836
21514
|
|
|
17837
21515
|
// packages/web/server/relay.ts
|
|
17838
21516
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
17839
|
-
import { join as
|
|
21517
|
+
import { join as join20 } from "path";
|
|
17840
21518
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
17841
21519
|
var UPLOAD_DIR = "/tmp/scout-uploads";
|
|
17842
21520
|
async function handleRelayUpload(req) {
|
|
@@ -17846,7 +21524,7 @@ async function handleRelayUpload(req) {
|
|
|
17846
21524
|
}
|
|
17847
21525
|
await mkdir7(UPLOAD_DIR, { recursive: true });
|
|
17848
21526
|
const filename = `${randomUUID3()}-${name}`;
|
|
17849
|
-
const filepath =
|
|
21527
|
+
const filepath = join20(UPLOAD_DIR, filename);
|
|
17850
21528
|
await Bun.write(filepath, Buffer.from(data, "base64"));
|
|
17851
21529
|
return Response.json({ path: filepath });
|
|
17852
21530
|
}
|
|
@@ -17951,13 +21629,13 @@ function resolveStaticRoot2() {
|
|
|
17951
21629
|
if (process.env.OPENSCOUT_WEB_STATIC_ROOT?.trim()) {
|
|
17952
21630
|
return process.env.OPENSCOUT_WEB_STATIC_ROOT.trim();
|
|
17953
21631
|
}
|
|
17954
|
-
const selfDir =
|
|
17955
|
-
const siblingClientRoot =
|
|
17956
|
-
if (
|
|
21632
|
+
const selfDir = dirname13(fileURLToPath8(import.meta.url));
|
|
21633
|
+
const siblingClientRoot = join21(selfDir, "client");
|
|
21634
|
+
if (existsSync14(join21(siblingClientRoot, "index.html"))) {
|
|
17957
21635
|
return siblingClientRoot;
|
|
17958
21636
|
}
|
|
17959
|
-
const sourceDistClientRoot =
|
|
17960
|
-
if (
|
|
21637
|
+
const sourceDistClientRoot = resolve10(selfDir, "../dist/client");
|
|
21638
|
+
if (existsSync14(join21(sourceDistClientRoot, "index.html"))) {
|
|
17961
21639
|
return sourceDistClientRoot;
|
|
17962
21640
|
}
|
|
17963
21641
|
return;
|