@openscout/scout 0.2.55 → 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-ChjXbrxY.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 +2 -2
- package/dist/main.mjs +14776 -10216
- package/dist/pair-supervisor.mjs +16889 -13548
- package/dist/scout-control-plane-web.mjs +3847 -214
- package/package.json +2 -2
- package/dist/client/assets/index-DUtTv5D0.css +0 -1
- package/dist/client/assets/index-kOG7gvZY.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();
|
|
@@ -4795,17 +5501,127 @@ var init_mesh = () => {};
|
|
|
4795
5501
|
|
|
4796
5502
|
// packages/protocol/dist/conversations.js
|
|
4797
5503
|
var init_conversations = () => {};
|
|
4798
|
-
// packages/protocol/dist/messages.js
|
|
4799
|
-
var init_messages = () => {};
|
|
4800
5504
|
|
|
4801
|
-
// packages/protocol/dist/
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
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 = () => {};
|
|
4809
5625
|
|
|
4810
5626
|
// packages/protocol/dist/transports.js
|
|
4811
5627
|
var init_transports = () => {};
|
|
@@ -4886,9 +5702,9 @@ var init_support_paths = () => {};
|
|
|
4886
5702
|
// packages/runtime/src/harness-catalog.ts
|
|
4887
5703
|
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
4888
5704
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
4889
|
-
import { dirname as
|
|
5705
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
4890
5706
|
async function writeHarnessCatalogOverrides(overrides, overridePath = resolveOpenScoutSupportPaths().harnessCatalogPath) {
|
|
4891
|
-
await mkdir2(
|
|
5707
|
+
await mkdir2(dirname3(overridePath), { recursive: true });
|
|
4892
5708
|
const payload = {
|
|
4893
5709
|
version: HARNESS_CATALOG_VERSION,
|
|
4894
5710
|
entries: overrides,
|
|
@@ -4984,9 +5800,9 @@ var init_harness_catalog = __esm(() => {
|
|
|
4984
5800
|
// packages/runtime/src/user-project-hints.ts
|
|
4985
5801
|
import { readdir, readFile as readFile3, stat } from "fs/promises";
|
|
4986
5802
|
import { homedir as homedir5 } from "os";
|
|
4987
|
-
import { dirname as
|
|
5803
|
+
import { dirname as dirname4, join as join6, resolve as resolve2 } from "path";
|
|
4988
5804
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4989
|
-
function
|
|
5805
|
+
function decodeClaudeProjectsSlug3(name) {
|
|
4990
5806
|
if (!name || name === "." || name === "..") {
|
|
4991
5807
|
return null;
|
|
4992
5808
|
}
|
|
@@ -5011,7 +5827,7 @@ async function resolveExistingDirectoryHint(pathLike) {
|
|
|
5011
5827
|
return absolutePath;
|
|
5012
5828
|
}
|
|
5013
5829
|
if (info.isFile()) {
|
|
5014
|
-
return
|
|
5830
|
+
return dirname4(absolutePath);
|
|
5015
5831
|
}
|
|
5016
5832
|
} catch {
|
|
5017
5833
|
return null;
|
|
@@ -5038,7 +5854,7 @@ async function findLikelyProjectRoot(absolutePath) {
|
|
|
5038
5854
|
}
|
|
5039
5855
|
}
|
|
5040
5856
|
}
|
|
5041
|
-
const parent =
|
|
5857
|
+
const parent = dirname4(current);
|
|
5042
5858
|
if (parent === current) {
|
|
5043
5859
|
return lastCandidate ?? absolutePath;
|
|
5044
5860
|
}
|
|
@@ -5179,7 +5995,7 @@ async function appendCursorWorkspacePaths(home, roots) {
|
|
|
5179
5995
|
}
|
|
5180
5996
|
const wsRaw = await readFile3(wsFile, "utf8");
|
|
5181
5997
|
const wsDoc = JSON.parse(wsRaw);
|
|
5182
|
-
const wsDir =
|
|
5998
|
+
const wsDir = dirname4(wsFile);
|
|
5183
5999
|
for (const f of wsDoc.folders ?? []) {
|
|
5184
6000
|
if (typeof f.path !== "string" || !f.path) {
|
|
5185
6001
|
continue;
|
|
@@ -5200,7 +6016,7 @@ async function appendClaudeProjectSlugs(home, roots) {
|
|
|
5200
6016
|
return;
|
|
5201
6017
|
}
|
|
5202
6018
|
for (const name of names) {
|
|
5203
|
-
const decoded =
|
|
6019
|
+
const decoded = decodeClaudeProjectsSlug3(name);
|
|
5204
6020
|
if (!decoded) {
|
|
5205
6021
|
continue;
|
|
5206
6022
|
}
|
|
@@ -5336,7 +6152,7 @@ import { execFileSync } from "child_process";
|
|
|
5336
6152
|
import { existsSync as existsSync5, readFileSync } from "fs";
|
|
5337
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";
|
|
5338
6154
|
import { homedir as homedir6, hostname, userInfo } from "os";
|
|
5339
|
-
import { basename as
|
|
6155
|
+
import { basename as basename3, dirname as dirname5, isAbsolute, join as join7, relative, resolve as resolve3 } from "path";
|
|
5340
6156
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
5341
6157
|
function titleCaseWords(value) {
|
|
5342
6158
|
return value.split(/[\s._-]+/).map((part) => part.trim()).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
@@ -5811,7 +6627,7 @@ async function readJsonFile(filePath) {
|
|
|
5811
6627
|
}
|
|
5812
6628
|
}
|
|
5813
6629
|
async function writeJsonFile(filePath, value) {
|
|
5814
|
-
await mkdir3(
|
|
6630
|
+
await mkdir3(dirname5(filePath), { recursive: true });
|
|
5815
6631
|
await writeFile3(filePath, JSON.stringify(value, null, 2) + `
|
|
5816
6632
|
`, "utf8");
|
|
5817
6633
|
}
|
|
@@ -6056,7 +6872,7 @@ function applyImportedEnvironmentSeeds(config, codexImport, projectRoot) {
|
|
|
6056
6872
|
...(config.environment?.actions?.length ?? 0) === 0 && importedEnvironment.actions ? { actions: importedEnvironment.actions } : {}
|
|
6057
6873
|
};
|
|
6058
6874
|
}
|
|
6059
|
-
const defaultProjectName = titleCase(
|
|
6875
|
+
const defaultProjectName = titleCase(basename3(projectRoot));
|
|
6060
6876
|
if (codexImport?.name?.trim() && (!config.project.name?.trim() || config.project.name === defaultProjectName)) {
|
|
6061
6877
|
next.project = {
|
|
6062
6878
|
...config.project,
|
|
@@ -6224,7 +7040,7 @@ async function seedWorkspaceRoots(options) {
|
|
|
6224
7040
|
const roots = new Set;
|
|
6225
7041
|
const currentProjectRoot = options.currentDirectory ? await findNearestProjectRoot(options.currentDirectory) : null;
|
|
6226
7042
|
if (currentProjectRoot) {
|
|
6227
|
-
roots.add(
|
|
7043
|
+
roots.add(dirname5(currentProjectRoot));
|
|
6228
7044
|
}
|
|
6229
7045
|
const legacyRoot = options.legacyRelayConfig?.projectRoot?.trim();
|
|
6230
7046
|
if (legacyRoot) {
|
|
@@ -6232,7 +7048,7 @@ async function seedWorkspaceRoots(options) {
|
|
|
6232
7048
|
}
|
|
6233
7049
|
for (const record of Object.values(options.legacyAgents ?? {})) {
|
|
6234
7050
|
if (record.cwd?.trim()) {
|
|
6235
|
-
roots.add(
|
|
7051
|
+
roots.add(dirname5(normalizePath(record.cwd)));
|
|
6236
7052
|
}
|
|
6237
7053
|
}
|
|
6238
7054
|
if (roots.size === 0) {
|
|
@@ -6323,7 +7139,7 @@ async function installScoutSkillToHarnesses() {
|
|
|
6323
7139
|
continue;
|
|
6324
7140
|
}
|
|
6325
7141
|
try {
|
|
6326
|
-
await mkdir3(
|
|
7142
|
+
await mkdir3(dirname5(target), { recursive: true });
|
|
6327
7143
|
await writeFile3(target, content, "utf8");
|
|
6328
7144
|
entries.push({ harness, target, status: "installed" });
|
|
6329
7145
|
} catch (error) {
|
|
@@ -6424,7 +7240,7 @@ async function findNearestProjectRoot(startDirectory) {
|
|
|
6424
7240
|
if (await pathExists2(projectConfigPath(current)) || await pathExists2(join7(current, "package.json")) || await pathExists2(join7(current, "AGENTS.md")) || await pathExists2(join7(current, "CLAUDE.md"))) {
|
|
6425
7241
|
lastCandidate = current;
|
|
6426
7242
|
}
|
|
6427
|
-
const parent =
|
|
7243
|
+
const parent = dirname5(current);
|
|
6428
7244
|
if (parent === current) {
|
|
6429
7245
|
return lastCandidate;
|
|
6430
7246
|
}
|
|
@@ -6432,7 +7248,7 @@ async function findNearestProjectRoot(startDirectory) {
|
|
|
6432
7248
|
}
|
|
6433
7249
|
}
|
|
6434
7250
|
function defaultProjectConfig(projectRoot, settings, preferredHarness) {
|
|
6435
|
-
const projectName =
|
|
7251
|
+
const projectName = basename3(projectRoot);
|
|
6436
7252
|
const definitionId = normalizeAgentId(projectName);
|
|
6437
7253
|
const relativeRoot = relative(projectRoot, projectRoot) || ".";
|
|
6438
7254
|
return {
|
|
@@ -6738,8 +7554,8 @@ function selectorFromInput(value) {
|
|
|
6738
7554
|
}
|
|
6739
7555
|
async function resolveManifestBackedAgent(projectRoot, config, settings, override) {
|
|
6740
7556
|
const resolvedProjectRoot = resolveProjectRootFromConfig(projectRoot, config);
|
|
6741
|
-
const projectName = config.project.name?.trim() || titleCase(config.project.id ||
|
|
6742
|
-
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));
|
|
6743
7559
|
const definitionId = normalizeAgentId(config.agent?.id || override?.definitionId || fallbackDefinitionId);
|
|
6744
7560
|
const detectedHarness = await detectPreferredHarness(resolvedProjectRoot, settings.agents.defaultHarness);
|
|
6745
7561
|
const runtimeDefaults = config.agent?.runtime?.defaults;
|
|
@@ -6776,7 +7592,7 @@ async function resolveManifestBackedAgent(projectRoot, config, settings, overrid
|
|
|
6776
7592
|
return mergeResolvedAgentConfig(base, override, settings);
|
|
6777
7593
|
}
|
|
6778
7594
|
async function resolveInferredAgent(projectRoot, settings, override) {
|
|
6779
|
-
const projectName =
|
|
7595
|
+
const projectName = basename3(projectRoot);
|
|
6780
7596
|
const definitionId = normalizeAgentId(override?.definitionId?.trim() || projectName);
|
|
6781
7597
|
const detectedHarness = await detectPreferredHarness(projectRoot, settings.agents.defaultHarness);
|
|
6782
7598
|
const defaultHarness = normalizeManagedHarness(override?.defaultHarness ?? override?.runtime?.harness, normalizeManagedHarness(detectedHarness, "claude"));
|
|
@@ -6812,7 +7628,7 @@ async function resolveInferredAgent(projectRoot, settings, override) {
|
|
|
6812
7628
|
return mergeResolvedAgentConfig(base, override, settings);
|
|
6813
7629
|
}
|
|
6814
7630
|
async function buildProjectInventoryEntry(agent, sourceRoot) {
|
|
6815
|
-
const manifestRoot = agent.projectConfigPath ? normalizePath(join7(
|
|
7631
|
+
const manifestRoot = agent.projectConfigPath ? normalizePath(join7(dirname5(agent.projectConfigPath), "..")) : null;
|
|
6816
7632
|
const manifest = manifestRoot ? await readProjectConfig(manifestRoot) : null;
|
|
6817
7633
|
const markers = await detectHarnessMarkers(agent.projectRoot);
|
|
6818
7634
|
const harnesses = new Map;
|
|
@@ -7205,7 +8021,7 @@ var init_setup = __esm(() => {
|
|
|
7205
8021
|
PROJECT_STRONG_MARKERS_FLAT_NESTED = partitionFlatAndNestedMarkers(PROJECT_STRONG_MARKERS);
|
|
7206
8022
|
PROJECT_WEAK_MARKERS_FLAT_NESTED = partitionFlatAndNestedMarkers(PROJECT_WEAK_MARKERS);
|
|
7207
8023
|
gitBranchCache = new Map;
|
|
7208
|
-
SETUP_MODULE_DIRECTORY =
|
|
8024
|
+
SETUP_MODULE_DIRECTORY = dirname5(fileURLToPath3(import.meta.url));
|
|
7209
8025
|
SCOUT_SKILL_REPO_ROOT = resolve3(SETUP_MODULE_DIRECTORY, "..", "..", "..");
|
|
7210
8026
|
SCOUT_SKILL_INSTALL_PATHS = {
|
|
7211
8027
|
claude: join7(homedir6(), ".claude", "skills", "scout", SCOUT_SKILL_FILE_NAME),
|
|
@@ -7290,7 +8106,7 @@ function updateBlockCompletion(blockState, completed) {
|
|
|
7290
8106
|
blockState.status = completed ? "completed" : "streaming";
|
|
7291
8107
|
blockState.block.status = completed ? "completed" : "streaming";
|
|
7292
8108
|
}
|
|
7293
|
-
function
|
|
8109
|
+
function parseQuestionAnswer2(value) {
|
|
7294
8110
|
if (Array.isArray(value)) {
|
|
7295
8111
|
return value.map((entry) => typeof entry === "string" ? entry.trim() : String(entry).trim()).filter(Boolean);
|
|
7296
8112
|
}
|
|
@@ -7608,7 +8424,7 @@ function buildClaudeStreamJsonSessionSnapshot(raw2, options, targetClaudeSession
|
|
|
7608
8424
|
if (blockState.block.type === "question") {
|
|
7609
8425
|
const questionBlock = blockState.block;
|
|
7610
8426
|
questionBlock.questionStatus = result.is_error ? "denied" : "answered";
|
|
7611
|
-
const answer =
|
|
8427
|
+
const answer = parseQuestionAnswer2(result.content);
|
|
7612
8428
|
questionBlock.answer = answer.length > 0 ? answer : undefined;
|
|
7613
8429
|
updateBlockCompletion(blockState, true);
|
|
7614
8430
|
continue;
|
|
@@ -9621,7 +10437,7 @@ function buildInvocationCollaborationContextPrompt(invocation) {
|
|
|
9621
10437
|
import { spawnSync } from "child_process";
|
|
9622
10438
|
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
9623
10439
|
import { homedir as homedir11 } from "os";
|
|
9624
|
-
import { basename as
|
|
10440
|
+
import { basename as basename4, dirname as dirname10, join as join15, resolve as resolve5 } from "path";
|
|
9625
10441
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
9626
10442
|
function isTmpPath(p) {
|
|
9627
10443
|
return /^\/(?:private\/)?tmp\//.test(p);
|
|
@@ -9654,7 +10470,7 @@ function runtimePackageDir() {
|
|
|
9654
10470
|
const fromCwd = findWorkspaceRuntimeDir(process.cwd());
|
|
9655
10471
|
if (fromCwd)
|
|
9656
10472
|
return fromCwd;
|
|
9657
|
-
const moduleDir =
|
|
10473
|
+
const moduleDir = dirname10(fileURLToPath5(import.meta.url));
|
|
9658
10474
|
return resolve5(moduleDir, "..");
|
|
9659
10475
|
}
|
|
9660
10476
|
function isInstalledRuntimePackageDir(candidate) {
|
|
@@ -9692,7 +10508,7 @@ function findWorkspaceRuntimeDir(startDir) {
|
|
|
9692
10508
|
if (existsSync9(join15(candidate, "package.json")) && existsSync9(join15(candidate, "src"))) {
|
|
9693
10509
|
return candidate;
|
|
9694
10510
|
}
|
|
9695
|
-
const parent =
|
|
10511
|
+
const parent = dirname10(current);
|
|
9696
10512
|
if (parent === current)
|
|
9697
10513
|
return null;
|
|
9698
10514
|
current = parent;
|
|
@@ -9703,7 +10519,7 @@ function resolveBunExecutable2() {
|
|
|
9703
10519
|
if (explicit && explicit.trim().length > 0) {
|
|
9704
10520
|
return explicit;
|
|
9705
10521
|
}
|
|
9706
|
-
if (
|
|
10522
|
+
if (basename4(process.execPath).startsWith("bun") && existsSync9(process.execPath)) {
|
|
9707
10523
|
return process.execPath;
|
|
9708
10524
|
}
|
|
9709
10525
|
const pathEntries = (process.env.PATH ?? "").split(":").filter(Boolean);
|
|
@@ -9856,8 +10672,8 @@ function collectOptionalEnvVars(keys) {
|
|
|
9856
10672
|
}
|
|
9857
10673
|
function resolveLaunchAgentPATH() {
|
|
9858
10674
|
const entries = [
|
|
9859
|
-
...(process.env.PATH ?? "").split(":").filter(Boolean),
|
|
9860
10675
|
join15(homedir11(), ".bun", "bin"),
|
|
10676
|
+
...(process.env.PATH ?? "").split(":").filter(Boolean),
|
|
9861
10677
|
"/opt/homebrew/bin",
|
|
9862
10678
|
"/usr/local/bin",
|
|
9863
10679
|
"/usr/bin",
|
|
@@ -9871,7 +10687,7 @@ function xmlEscape(value) {
|
|
|
9871
10687
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
9872
10688
|
}
|
|
9873
10689
|
function ensureParentDirectory(filePath) {
|
|
9874
|
-
mkdirSync5(
|
|
10690
|
+
mkdirSync5(dirname10(filePath), { recursive: true });
|
|
9875
10691
|
}
|
|
9876
10692
|
function ensureServiceDirectories(config) {
|
|
9877
10693
|
ensureOpenScoutCleanSlateSync();
|
|
@@ -10128,7 +10944,7 @@ var DEFAULT_BROKER_HOST = "127.0.0.1", DEFAULT_BROKER_HOST_MESH = "0.0.0.0", DEF
|
|
|
10128
10944
|
var init_broker_service = __esm(async () => {
|
|
10129
10945
|
init_support_paths();
|
|
10130
10946
|
DEFAULT_BROKER_URL = buildDefaultBrokerUrl();
|
|
10131
|
-
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")) {
|
|
10132
10948
|
await main();
|
|
10133
10949
|
}
|
|
10134
10950
|
});
|
|
@@ -10184,7 +11000,7 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
10184
11000
|
import { execFileSync as execFileSync2, execSync } from "child_process";
|
|
10185
11001
|
import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
|
|
10186
11002
|
import { mkdir as mkdir6, rm as rm5, stat as stat4, writeFile as writeFile6 } from "fs/promises";
|
|
10187
|
-
import { basename as
|
|
11003
|
+
import { basename as basename5, dirname as dirname11, join as join16, resolve as resolve6 } from "path";
|
|
10188
11004
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
10189
11005
|
function resolveRelayHub() {
|
|
10190
11006
|
return resolveOpenScoutSupportPaths().relayHubDirectory;
|
|
@@ -10196,13 +11012,13 @@ function resolveProjectsRoot(projectPath) {
|
|
|
10196
11012
|
try {
|
|
10197
11013
|
const supportPaths = resolveOpenScoutSupportPaths();
|
|
10198
11014
|
if (!existsSync10(supportPaths.settingsPath)) {
|
|
10199
|
-
return
|
|
11015
|
+
return dirname11(projectPath);
|
|
10200
11016
|
}
|
|
10201
11017
|
const raw2 = JSON.parse(readFileSync6(supportPaths.settingsPath, "utf8"));
|
|
10202
11018
|
const workspaceRoot = raw2.discovery?.workspaceRoots?.find((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
10203
|
-
return workspaceRoot ? resolve6(workspaceRoot) :
|
|
11019
|
+
return workspaceRoot ? resolve6(workspaceRoot) : dirname11(projectPath);
|
|
10204
11020
|
} catch {
|
|
10205
|
-
return
|
|
11021
|
+
return dirname11(projectPath);
|
|
10206
11022
|
}
|
|
10207
11023
|
}
|
|
10208
11024
|
function resolveBrokerUrl() {
|
|
@@ -10629,7 +11445,7 @@ function recordForHarness(record, harnessOverride) {
|
|
|
10629
11445
|
function normalizeLocalAgentRecord(agentId, record) {
|
|
10630
11446
|
const cwd = normalizeProjectPath(record.cwd || process.cwd());
|
|
10631
11447
|
const projectRoot = normalizeProjectPath(record.projectRoot || cwd);
|
|
10632
|
-
const project = record.project?.trim() ||
|
|
11448
|
+
const project = record.project?.trim() || basename5(projectRoot);
|
|
10633
11449
|
const definitionId = record.definitionId?.trim() || agentId;
|
|
10634
11450
|
const defaultHarness = activeLocalHarness(record);
|
|
10635
11451
|
const harnessProfiles = normalizeLocalHarnessProfiles(agentId, {
|
|
@@ -10694,7 +11510,7 @@ function localAgentRecordFromResolvedConfig(config) {
|
|
|
10694
11510
|
function localAgentRecordFromRelayAgentOverride(agentId, override) {
|
|
10695
11511
|
return normalizeLocalAgentRecord(agentId, {
|
|
10696
11512
|
definitionId: override.definitionId ?? agentId,
|
|
10697
|
-
project: override.projectName ??
|
|
11513
|
+
project: override.projectName ?? basename5(override.projectRoot || override.runtime?.cwd || agentId),
|
|
10698
11514
|
projectRoot: override.projectRoot ?? override.runtime?.cwd,
|
|
10699
11515
|
tmuxSession: override.runtime?.sessionId ?? `relay-${agentId}`,
|
|
10700
11516
|
cwd: override.runtime?.cwd ?? override.projectRoot,
|
|
@@ -11135,7 +11951,7 @@ async function ensureLocalAgentOnline(agentName, record) {
|
|
|
11135
11951
|
return normalizedRecord;
|
|
11136
11952
|
}
|
|
11137
11953
|
const projectPath = normalizedRecord.cwd;
|
|
11138
|
-
const projectName = normalizedRecord.project ||
|
|
11954
|
+
const projectName = normalizedRecord.project || basename5(projectPath);
|
|
11139
11955
|
const systemPromptTemplate = normalizedRecord.systemPrompt || buildLocalAgentSystemPromptTemplate();
|
|
11140
11956
|
const systemPrompt = renderLocalAgentSystemPromptTemplate(systemPromptTemplate, buildLocalAgentTemplateContext(agentName, projectName, projectPath), { transport: normalizedRecord.transport });
|
|
11141
11957
|
const agentRuntimeDir = relayAgentRuntimeDirectory(agentName);
|
|
@@ -11357,7 +12173,7 @@ async function resolveLocalAgentIdentity(input) {
|
|
|
11357
12173
|
nodeQualifier: instance2.nodeQualifier,
|
|
11358
12174
|
harness: normalizeManagedHarness2(preferredHarness ?? override.defaultHarness, "claude"),
|
|
11359
12175
|
projectRoot: normalizeProjectPath(override.projectRoot),
|
|
11360
|
-
projectName: override.projectName ??
|
|
12176
|
+
projectName: override.projectName ?? basename5(override.projectRoot),
|
|
11361
12177
|
source: "existing"
|
|
11362
12178
|
};
|
|
11363
12179
|
}
|
|
@@ -11376,12 +12192,12 @@ async function resolveLocalAgentIdentity(input) {
|
|
|
11376
12192
|
nodeQualifier: instance2.nodeQualifier,
|
|
11377
12193
|
harness: normalizeManagedHarness2(preferredHarness ?? override.defaultHarness, "claude"),
|
|
11378
12194
|
projectRoot: normalizeProjectPath(override.projectRoot),
|
|
11379
|
-
projectName: override.projectName ??
|
|
12195
|
+
projectName: override.projectName ?? basename5(override.projectRoot),
|
|
11380
12196
|
source: "existing"
|
|
11381
12197
|
};
|
|
11382
12198
|
}
|
|
11383
12199
|
const configDefinitionId = config?.agent?.id?.trim() ? normalizeAgentSelectorSegment(config.agent.id.trim()) : "";
|
|
11384
|
-
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(
|
|
12200
|
+
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename5(projectRoot)) || "agent";
|
|
11385
12201
|
const configDisplayName = config?.agent?.displayName?.trim() || "";
|
|
11386
12202
|
const displayName = input.displayName || configDisplayName || titleCaseLocalAgentName(definitionId);
|
|
11387
12203
|
const instance = buildRelayAgentInstance(definitionId, projectRoot);
|
|
@@ -11395,7 +12211,7 @@ async function resolveLocalAgentIdentity(input) {
|
|
|
11395
12211
|
nodeQualifier: instance.nodeQualifier,
|
|
11396
12212
|
harness: effectiveHarness,
|
|
11397
12213
|
projectRoot,
|
|
11398
|
-
projectName:
|
|
12214
|
+
projectName: basename5(projectRoot),
|
|
11399
12215
|
source: configDefinitionId || configDisplayName ? "config" : "new"
|
|
11400
12216
|
};
|
|
11401
12217
|
}
|
|
@@ -11451,7 +12267,7 @@ async function startLocalAgent(input) {
|
|
|
11451
12267
|
}
|
|
11452
12268
|
if (!matchingOverride) {
|
|
11453
12269
|
const configDefinitionId = coldProjectConfig?.agent?.id?.trim() ? normalizeAgentSelectorSegment(coldProjectConfig.agent.id.trim()) : "";
|
|
11454
|
-
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(
|
|
12270
|
+
const definitionId = requestedDefinitionId || configDefinitionId || normalizeAgentSelectorSegment(basename5(projectRoot)) || "agent";
|
|
11455
12271
|
const configDisplayName = coldProjectConfig?.agent?.displayName?.trim() || "";
|
|
11456
12272
|
const effectiveDisplayName = input.displayName || configDisplayName || titleCaseLocalAgentName(definitionId);
|
|
11457
12273
|
const instance = buildRelayAgentInstance(definitionId, projectRoot);
|
|
@@ -11467,7 +12283,7 @@ async function startLocalAgent(input) {
|
|
|
11467
12283
|
agentId: instance.id,
|
|
11468
12284
|
definitionId,
|
|
11469
12285
|
displayName: effectiveDisplayName,
|
|
11470
|
-
projectName:
|
|
12286
|
+
projectName: basename5(projectRoot),
|
|
11471
12287
|
projectRoot,
|
|
11472
12288
|
projectConfigPath: coldProjectConfigPath,
|
|
11473
12289
|
source: "manual",
|
|
@@ -11503,7 +12319,7 @@ async function startLocalAgent(input) {
|
|
|
11503
12319
|
agentId: instance.id,
|
|
11504
12320
|
definitionId: requestedDefinitionId,
|
|
11505
12321
|
displayName: input.displayName || titleCaseLocalAgentName(requestedDefinitionId),
|
|
11506
|
-
projectName: matchingOverride.projectName ??
|
|
12322
|
+
projectName: matchingOverride.projectName ?? basename5(matchingProjectRoot),
|
|
11507
12323
|
projectRoot: matchingProjectRoot,
|
|
11508
12324
|
projectConfigPath: matchingOverride.projectConfigPath ?? null,
|
|
11509
12325
|
source: "manual",
|
|
@@ -11808,7 +12624,7 @@ async function invokeLocalAgentEndpoint(endpoint, invocation) {
|
|
|
11808
12624
|
const requestedHarness = invocation.execution?.harness;
|
|
11809
12625
|
const record = existing ?? (projectRoot ? {
|
|
11810
12626
|
definitionId,
|
|
11811
|
-
project:
|
|
12627
|
+
project: basename5(projectRoot),
|
|
11812
12628
|
projectRoot,
|
|
11813
12629
|
tmuxSession: String(endpoint.metadata?.tmuxSession ?? `relay-${agentRuntimeId}`),
|
|
11814
12630
|
cwd: projectRoot,
|
|
@@ -11888,20 +12704,20 @@ var init_local_agents = __esm(async () => {
|
|
|
11888
12704
|
init_support_paths();
|
|
11889
12705
|
init_local_agent_template();
|
|
11890
12706
|
await init_broker_service();
|
|
11891
|
-
MODULE_DIRECTORY =
|
|
12707
|
+
MODULE_DIRECTORY = dirname11(fileURLToPath6(import.meta.url));
|
|
11892
12708
|
OPENSCOUT_REPO_ROOT = resolve6(MODULE_DIRECTORY, "..", "..", "..");
|
|
11893
12709
|
DEFAULT_LOCAL_AGENT_CAPABILITIES = ["chat", "invoke", "deliver"];
|
|
11894
12710
|
SUPPORTED_LOCAL_AGENT_HARNESSES = ["claude", "codex"];
|
|
11895
12711
|
});
|
|
11896
12712
|
|
|
11897
12713
|
// packages/web/server/index.ts
|
|
11898
|
-
import { existsSync as
|
|
11899
|
-
import { dirname as
|
|
12714
|
+
import { existsSync as existsSync14 } from "fs";
|
|
12715
|
+
import { dirname as dirname13, join as join21, resolve as resolve10 } from "path";
|
|
11900
12716
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
11901
12717
|
|
|
11902
12718
|
// packages/web/server/create-openscout-web-server.ts
|
|
11903
|
-
import { existsSync as
|
|
11904
|
-
import { dirname as
|
|
12719
|
+
import { existsSync as existsSync12, rmSync as rmSync3 } from "fs";
|
|
12720
|
+
import { dirname as dirname12, resolve as resolve9 } from "path";
|
|
11905
12721
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
11906
12722
|
|
|
11907
12723
|
// node_modules/.bun/hono@4.12.10/node_modules/hono/dist/compose.js
|
|
@@ -13457,7 +14273,7 @@ import {
|
|
|
13457
14273
|
writeFileSync as writeFileSync3
|
|
13458
14274
|
} from "fs";
|
|
13459
14275
|
import { homedir as homedir8 } from "os";
|
|
13460
|
-
import { dirname as
|
|
14276
|
+
import { dirname as dirname7, join as join9, resolve as resolve4 } from "path";
|
|
13461
14277
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13462
14278
|
|
|
13463
14279
|
// packages/runtime/src/local-config.ts
|
|
@@ -13469,7 +14285,7 @@ import {
|
|
|
13469
14285
|
writeFileSync as writeFileSync2
|
|
13470
14286
|
} from "fs";
|
|
13471
14287
|
import { homedir as homedir7 } from "os";
|
|
13472
|
-
import { dirname as
|
|
14288
|
+
import { dirname as dirname6, join as join8 } from "path";
|
|
13473
14289
|
var LOCAL_CONFIG_VERSION = 1;
|
|
13474
14290
|
var DEFAULT_LOCAL_CONFIG = {
|
|
13475
14291
|
version: LOCAL_CONFIG_VERSION,
|
|
@@ -13523,7 +14339,7 @@ function isValidPort(value) {
|
|
|
13523
14339
|
}
|
|
13524
14340
|
function writeLocalConfig(config) {
|
|
13525
14341
|
const configPath = localConfigPath();
|
|
13526
|
-
mkdirSync2(
|
|
14342
|
+
mkdirSync2(dirname6(configPath), { recursive: true });
|
|
13527
14343
|
const body = JSON.stringify({ ...config, version: LOCAL_CONFIG_VERSION }, null, 2) + `
|
|
13528
14344
|
`;
|
|
13529
14345
|
const tmp = `${configPath}.tmp`;
|
|
@@ -13983,7 +14799,7 @@ function resolveScoutPairingRuntimeScriptPath() {
|
|
|
13983
14799
|
throw new Error("Unable to locate the Scout pair supervisor entrypoint.");
|
|
13984
14800
|
}
|
|
13985
14801
|
function resolveOpenScoutWebServerDirectory(moduleUrl = import.meta.url) {
|
|
13986
|
-
return
|
|
14802
|
+
return dirname7(fileURLToPath4(moduleUrl));
|
|
13987
14803
|
}
|
|
13988
14804
|
function resolveOpenScoutWebPackageRoot(moduleUrl = import.meta.url) {
|
|
13989
14805
|
return resolve4(resolveOpenScoutWebServerDirectory(moduleUrl), "..");
|
|
@@ -14141,6 +14957,17 @@ async function getScoutWebPairingState(currentDirectory) {
|
|
|
14141
14957
|
async function refreshScoutWebPairingState(currentDirectory) {
|
|
14142
14958
|
return readScoutPairingState(currentDirectory);
|
|
14143
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
|
+
}
|
|
14144
14971
|
async function controlScoutWebPairingService(action, currentDirectory) {
|
|
14145
14972
|
return serializePairingMutation(async () => {
|
|
14146
14973
|
switch (action) {
|
|
@@ -14679,7 +15506,7 @@ import { join as join12 } from "path";
|
|
|
14679
15506
|
// packages/runtime/src/user-config.ts
|
|
14680
15507
|
import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
14681
15508
|
import { homedir as homedir9 } from "os";
|
|
14682
|
-
import { dirname as
|
|
15509
|
+
import { dirname as dirname9, join as join11 } from "path";
|
|
14683
15510
|
function userConfigPath() {
|
|
14684
15511
|
return join11(process.env.OPENSCOUT_HOME ?? join11(homedir9(), ".openscout"), "user.json");
|
|
14685
15512
|
}
|
|
@@ -14695,7 +15522,7 @@ function loadUserConfig() {
|
|
|
14695
15522
|
}
|
|
14696
15523
|
function saveUserConfig(config) {
|
|
14697
15524
|
const configPath = userConfigPath();
|
|
14698
|
-
mkdirSync4(
|
|
15525
|
+
mkdirSync4(dirname9(configPath), { recursive: true });
|
|
14699
15526
|
writeFileSync4(configPath, JSON.stringify(config, null, 2) + `
|
|
14700
15527
|
`, "utf8");
|
|
14701
15528
|
}
|
|
@@ -15478,7 +16305,10 @@ function querySessions(limit = 80) {
|
|
|
15478
16305
|
a.id AS agent_id,
|
|
15479
16306
|
ac.display_name,
|
|
15480
16307
|
ep.harness,
|
|
16308
|
+
ep.transport,
|
|
15481
16309
|
ep.project_root,
|
|
16310
|
+
ep.session_id,
|
|
16311
|
+
ep.metadata_json AS endpoint_metadata_json,
|
|
15482
16312
|
a.metadata_json
|
|
15483
16313
|
FROM conversation_members cm
|
|
15484
16314
|
JOIN agents a ON a.id = cm.actor_id
|
|
@@ -15501,6 +16331,8 @@ function querySessions(limit = 80) {
|
|
|
15501
16331
|
const stats = statsStmt.get(r.id);
|
|
15502
16332
|
let agentName = null;
|
|
15503
16333
|
let harness = null;
|
|
16334
|
+
let harnessSessionId = null;
|
|
16335
|
+
let harnessLogPath = null;
|
|
15504
16336
|
let branch = null;
|
|
15505
16337
|
let workspaceRoot = null;
|
|
15506
16338
|
if (primaryAgent) {
|
|
@@ -15514,6 +16346,14 @@ function querySessions(limit = 80) {
|
|
|
15514
16346
|
}
|
|
15515
16347
|
branch = meta.branch ?? meta.workspaceQualifier ?? null;
|
|
15516
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
|
+
}
|
|
15517
16357
|
}
|
|
15518
16358
|
const preview = previewStmt.get(r.id)?.body ?? null;
|
|
15519
16359
|
return [{
|
|
@@ -15524,6 +16364,8 @@ function querySessions(limit = 80) {
|
|
|
15524
16364
|
agentId,
|
|
15525
16365
|
agentName,
|
|
15526
16366
|
harness,
|
|
16367
|
+
harnessSessionId,
|
|
16368
|
+
harnessLogPath,
|
|
15527
16369
|
currentBranch: branch,
|
|
15528
16370
|
preview: preview ? preview.slice(0, 200) : null,
|
|
15529
16371
|
messageCount: stats?.cnt ?? 0,
|
|
@@ -15621,23 +16463,30 @@ function parseDirectConversationId(conversationId) {
|
|
|
15621
16463
|
}
|
|
15622
16464
|
function synthesizeDirectSession(conversationId, agentId, operatorId) {
|
|
15623
16465
|
const agent = db().prepare(`SELECT
|
|
15624
|
-
|
|
15625
|
-
|
|
15626
|
-
|
|
15627
|
-
|
|
15628
|
-
|
|
15629
|
-
|
|
15630
|
-
|
|
15631
|
-
|
|
15632
|
-
|
|
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);
|
|
15633
16478
|
if (!agent) {
|
|
15634
16479
|
return null;
|
|
15635
16480
|
}
|
|
15636
16481
|
let currentBranch = null;
|
|
16482
|
+
let endpointMeta = {};
|
|
15637
16483
|
try {
|
|
15638
16484
|
const metadata = agent.metadata_json ? JSON.parse(agent.metadata_json) : {};
|
|
15639
16485
|
currentBranch = metadata.branch ?? metadata.workspaceQualifier ?? null;
|
|
15640
16486
|
} catch {}
|
|
16487
|
+
try {
|
|
16488
|
+
endpointMeta = agent.endpoint_metadata_json ? JSON.parse(agent.endpoint_metadata_json) : {};
|
|
16489
|
+
} catch {}
|
|
15641
16490
|
return {
|
|
15642
16491
|
id: conversationId,
|
|
15643
16492
|
kind: "direct",
|
|
@@ -15646,6 +16495,8 @@ function synthesizeDirectSession(conversationId, agentId, operatorId) {
|
|
|
15646
16495
|
agentId,
|
|
15647
16496
|
agentName: agent.display_name,
|
|
15648
16497
|
harness: agent.harness,
|
|
16498
|
+
harnessSessionId: resolveHarnessSessionId(agent.transport, agent.session_id, endpointMeta),
|
|
16499
|
+
harnessLogPath: resolveHarnessLogPath(agentId, agent.transport, agent.session_id, endpointMeta),
|
|
15649
16500
|
currentBranch,
|
|
15650
16501
|
preview: null,
|
|
15651
16502
|
messageCount: 0,
|
|
@@ -16026,7 +16877,7 @@ init_dist2();
|
|
|
16026
16877
|
init_setup();
|
|
16027
16878
|
init_support_paths();
|
|
16028
16879
|
await init_local_agents();
|
|
16029
|
-
import { basename as
|
|
16880
|
+
import { basename as basename6, join as join17, resolve as resolve7 } from "path";
|
|
16030
16881
|
|
|
16031
16882
|
// packages/web/server/core/broker/paths.ts
|
|
16032
16883
|
var scoutBrokerPaths = {
|
|
@@ -16943,135 +17794,2913 @@ function whoEntryState(endpoints, registrationKind) {
|
|
|
16943
17794
|
}, "offline");
|
|
16944
17795
|
}
|
|
16945
17796
|
|
|
16946
|
-
// packages/web/server/core/
|
|
16947
|
-
|
|
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";
|
|
16948
17802
|
|
|
16949
|
-
// packages/runtime/src/
|
|
16950
|
-
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
16955
|
-
|
|
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
|
+
};
|
|
16956
17816
|
}
|
|
16957
|
-
|
|
16958
|
-
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
|
|
16963
|
-
|
|
16964
|
-
online: peer.Online ?? false,
|
|
16965
|
-
hostName: peer.HostName,
|
|
16966
|
-
os: peer.OS,
|
|
16967
|
-
tags: peer.Tags ?? []
|
|
16968
|
-
}));
|
|
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}`;
|
|
16969
17824
|
}
|
|
16970
|
-
function
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
|
|
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);
|
|
16974
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) {
|
|
16975
17843
|
return {
|
|
16976
|
-
id:
|
|
16977
|
-
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
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
|
|
16985
17854
|
};
|
|
16986
17855
|
}
|
|
16987
|
-
|
|
16988
|
-
const
|
|
16989
|
-
|
|
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;
|
|
16990
17921
|
}
|
|
16991
|
-
|
|
16992
|
-
|
|
16993
|
-
|
|
16994
|
-
|
|
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;
|
|
16995
17964
|
}
|
|
16996
|
-
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
return null;
|
|
17965
|
+
mapToDriverValue(value) {
|
|
17966
|
+
return value;
|
|
17967
|
+
}
|
|
17968
|
+
shouldDisableInsert() {
|
|
17969
|
+
return this.config.generated !== undefined && this.config.generated.type !== "byDefault";
|
|
17002
17970
|
}
|
|
17003
17971
|
}
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
|
|
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;
|
|
17008
18026
|
}
|
|
17009
|
-
return parsePeers(status);
|
|
17010
18027
|
}
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
|
|
17014
|
-
|
|
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;
|
|
17015
18050
|
}
|
|
17016
|
-
|
|
18051
|
+
static [entityKind] = "PgColumn";
|
|
17017
18052
|
}
|
|
17018
18053
|
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
|
|
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
|
+
}
|
|
17022
18089
|
}
|
|
17023
|
-
|
|
17024
|
-
|
|
17025
|
-
|
|
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
|
+
}
|
|
17026
18103
|
}
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
return
|
|
18104
|
+
var isPgEnumSym = Symbol.for("drizzle:isPgEnum");
|
|
18105
|
+
function isPgEnum(obj) {
|
|
18106
|
+
return !!obj && typeof obj === "function" && isPgEnumSym in obj && obj[isPgEnumSym] === true;
|
|
17030
18107
|
}
|
|
17031
|
-
|
|
17032
|
-
|
|
17033
|
-
|
|
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;
|
|
17034
18115
|
}
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
return !isLoopbackHost(hostname2) && !isWildcardHost(hostname2);
|
|
17038
|
-
} catch {
|
|
17039
|
-
return false;
|
|
18116
|
+
getSQLType() {
|
|
18117
|
+
return this.enum.enumName;
|
|
17040
18118
|
}
|
|
17041
18119
|
}
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
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
|
+
};
|
|
17046
18133
|
}
|
|
17047
|
-
return trimmed.replace(/\.$/, "");
|
|
17048
18134
|
}
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17053
|
-
|
|
17054
|
-
|
|
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
|
|
17055
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
|
+
}
|
|
17056
18205
|
}
|
|
17057
|
-
|
|
17058
|
-
|
|
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";
|
|
17059
18210
|
}
|
|
17060
|
-
function
|
|
17061
|
-
const
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17068
|
-
|
|
17069
|
-
|
|
17070
|
-
}
|
|
17071
|
-
return issues;
|
|
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
|
+
}
|
|
17072
18222
|
}
|
|
17073
|
-
|
|
17074
|
-
|
|
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
|
+
});
|
|
20700
|
+
return issues;
|
|
20701
|
+
}
|
|
20702
|
+
if (localNode?.advertiseScope === "local") {
|
|
20703
|
+
issues.push({
|
|
17075
20704
|
code: "local_only",
|
|
17076
20705
|
severity: "warning",
|
|
17077
20706
|
title: "Not announced to peers",
|
|
@@ -17090,7 +20719,7 @@ function computeIssues(health, localNode, nodes, tailscale) {
|
|
|
17090
20719
|
});
|
|
17091
20720
|
}
|
|
17092
20721
|
const remoteNodes = Object.values(nodes).filter((n) => n.id !== localNode?.id);
|
|
17093
|
-
if (!
|
|
20722
|
+
if (!tailscale2.available && remoteNodes.length === 0) {
|
|
17094
20723
|
issues.push({
|
|
17095
20724
|
code: "discovery_unconfigured",
|
|
17096
20725
|
severity: "warning",
|
|
@@ -17179,7 +20808,7 @@ function filterCurrentMeshNodes(allNodes, meshId, localNodeId, now) {
|
|
|
17179
20808
|
}
|
|
17180
20809
|
async function loadMeshStatus() {
|
|
17181
20810
|
const brokerUrl = resolveScoutBrokerUrl();
|
|
17182
|
-
const [health, context,
|
|
20811
|
+
const [health, context, tailscale2] = await Promise.all([
|
|
17183
20812
|
readScoutBrokerHealth(brokerUrl),
|
|
17184
20813
|
loadScoutBrokerContext(brokerUrl),
|
|
17185
20814
|
readTailscaleStatus()
|
|
@@ -17189,9 +20818,9 @@ async function loadMeshStatus() {
|
|
|
17189
20818
|
const meshId = health.meshId ?? localNode?.meshId ?? null;
|
|
17190
20819
|
const identity = computeIdentitySummary(health, localNode, meshId);
|
|
17191
20820
|
const nodes = filterCurrentMeshNodes(allNodes, meshId, localNode?.id, Date.now());
|
|
17192
|
-
const issues = computeIssues(health, localNode, nodes,
|
|
20821
|
+
const issues = computeIssues(health, localNode, nodes, tailscale2);
|
|
17193
20822
|
const warnings = issues.map(formatIssueWarning);
|
|
17194
|
-
return { brokerUrl, health, localNode, meshId, identity, nodes, tailscale, issues, warnings };
|
|
20823
|
+
return { brokerUrl, health, localNode, meshId, identity, nodes, tailscale: tailscale2, issues, warnings };
|
|
17195
20824
|
}
|
|
17196
20825
|
function preferredAnnounceHost(self, currentBrokerUrl) {
|
|
17197
20826
|
const dnsName = stripTrailingDot(self?.dnsName);
|
|
@@ -17316,10 +20945,10 @@ function resolveConversationRouting(conversationId) {
|
|
|
17316
20945
|
return { directAgentId, senderId };
|
|
17317
20946
|
}
|
|
17318
20947
|
function resolveBundledStaticClientRoot(moduleUrl = import.meta.url) {
|
|
17319
|
-
return
|
|
20948
|
+
return resolve9(dirname12(fileURLToPath7(moduleUrl)), "client");
|
|
17320
20949
|
}
|
|
17321
20950
|
function resolveSourceStaticClientRoot(moduleUrl = import.meta.url) {
|
|
17322
|
-
return
|
|
20951
|
+
return resolve9(dirname12(fileURLToPath7(moduleUrl)), "../dist/client");
|
|
17323
20952
|
}
|
|
17324
20953
|
function resolveStaticRoot(staticRoot) {
|
|
17325
20954
|
const configured = staticRoot?.trim();
|
|
@@ -17327,7 +20956,7 @@ function resolveStaticRoot(staticRoot) {
|
|
|
17327
20956
|
return configured;
|
|
17328
20957
|
}
|
|
17329
20958
|
const bundled = resolveBundledStaticClientRoot(import.meta.url);
|
|
17330
|
-
if (
|
|
20959
|
+
if (existsSync12(resolve9(bundled, "index.html"))) {
|
|
17331
20960
|
return bundled;
|
|
17332
20961
|
}
|
|
17333
20962
|
return resolveSourceStaticClientRoot(import.meta.url);
|
|
@@ -17365,6 +20994,10 @@ async function createOpenScoutWebServer(options) {
|
|
|
17365
20994
|
app.get("/api/shell-state", async (c) => c.json(await shellStateCache.get()));
|
|
17366
20995
|
app.get("/api/shell-state/refresh", async (c) => c.json(await shellStateCache.refresh()));
|
|
17367
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
|
+
});
|
|
17368
21001
|
app.get("/api/activity", (c) => c.json(queryActivity()));
|
|
17369
21002
|
app.get("/api/heartrate", (c) => c.json(queryHeartrate()));
|
|
17370
21003
|
app.get("/api/fleet", (c) => c.json(queryFleet({
|
|
@@ -17608,8 +21241,8 @@ async function createOpenScoutWebServer(options) {
|
|
|
17608
21241
|
// ../hudson/packages/hudson-relay/src/relay/session.ts
|
|
17609
21242
|
import { createRequire } from "module";
|
|
17610
21243
|
import { execSync as execSync2 } from "child_process";
|
|
17611
|
-
import { existsSync as
|
|
17612
|
-
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";
|
|
17613
21246
|
var require2 = createRequire(import.meta.url);
|
|
17614
21247
|
var pty = require2("node-pty");
|
|
17615
21248
|
var DEFAULT_ORPHAN_TTL_MS = 30 * 60 * 1000;
|
|
@@ -17626,7 +21259,7 @@ function send(ws, data) {
|
|
|
17626
21259
|
function resolveCwd(raw2) {
|
|
17627
21260
|
const home = process.env.HOME || "/tmp";
|
|
17628
21261
|
const expanded = (raw2 || home).replace(/^~/, home);
|
|
17629
|
-
if (
|
|
21262
|
+
if (existsSync13(expanded))
|
|
17630
21263
|
return expanded;
|
|
17631
21264
|
try {
|
|
17632
21265
|
mkdirSync6(expanded, { recursive: true });
|
|
@@ -17662,11 +21295,11 @@ function tmuxSessionExists2(name) {
|
|
|
17662
21295
|
}
|
|
17663
21296
|
function bootstrapFiles(cwd, files, sessionId) {
|
|
17664
21297
|
for (const [relPath, content] of Object.entries(files)) {
|
|
17665
|
-
const absPath =
|
|
17666
|
-
if (!
|
|
21298
|
+
const absPath = join19(cwd, relPath);
|
|
21299
|
+
if (!existsSync13(absPath)) {
|
|
17667
21300
|
try {
|
|
17668
21301
|
const dir = pathDirname(absPath);
|
|
17669
|
-
if (!
|
|
21302
|
+
if (!existsSync13(dir))
|
|
17670
21303
|
mkdirSync6(dir, { recursive: true });
|
|
17671
21304
|
writeFileSync6(absPath, content, "utf-8");
|
|
17672
21305
|
console.log(`[relay] Session ${sessionId}: bootstrapped ${relPath}`);
|
|
@@ -17721,7 +21354,7 @@ function createSession(ws, msg) {
|
|
|
17721
21354
|
return null;
|
|
17722
21355
|
}
|
|
17723
21356
|
}
|
|
17724
|
-
if (!
|
|
21357
|
+
if (!existsSync13(agentBin)) {
|
|
17725
21358
|
const reason = `${agent} binary not found at ${agentBin}`;
|
|
17726
21359
|
console.error(`[relay] Session ${id} failed: ${reason}`);
|
|
17727
21360
|
send(ws, { type: "session:error", error: reason });
|
|
@@ -17881,7 +21514,7 @@ function destroy(sessionId) {
|
|
|
17881
21514
|
|
|
17882
21515
|
// packages/web/server/relay.ts
|
|
17883
21516
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
17884
|
-
import { join as
|
|
21517
|
+
import { join as join20 } from "path";
|
|
17885
21518
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
17886
21519
|
var UPLOAD_DIR = "/tmp/scout-uploads";
|
|
17887
21520
|
async function handleRelayUpload(req) {
|
|
@@ -17891,7 +21524,7 @@ async function handleRelayUpload(req) {
|
|
|
17891
21524
|
}
|
|
17892
21525
|
await mkdir7(UPLOAD_DIR, { recursive: true });
|
|
17893
21526
|
const filename = `${randomUUID3()}-${name}`;
|
|
17894
|
-
const filepath =
|
|
21527
|
+
const filepath = join20(UPLOAD_DIR, filename);
|
|
17895
21528
|
await Bun.write(filepath, Buffer.from(data, "base64"));
|
|
17896
21529
|
return Response.json({ path: filepath });
|
|
17897
21530
|
}
|
|
@@ -17996,13 +21629,13 @@ function resolveStaticRoot2() {
|
|
|
17996
21629
|
if (process.env.OPENSCOUT_WEB_STATIC_ROOT?.trim()) {
|
|
17997
21630
|
return process.env.OPENSCOUT_WEB_STATIC_ROOT.trim();
|
|
17998
21631
|
}
|
|
17999
|
-
const selfDir =
|
|
18000
|
-
const siblingClientRoot =
|
|
18001
|
-
if (
|
|
21632
|
+
const selfDir = dirname13(fileURLToPath8(import.meta.url));
|
|
21633
|
+
const siblingClientRoot = join21(selfDir, "client");
|
|
21634
|
+
if (existsSync14(join21(siblingClientRoot, "index.html"))) {
|
|
18002
21635
|
return siblingClientRoot;
|
|
18003
21636
|
}
|
|
18004
|
-
const sourceDistClientRoot =
|
|
18005
|
-
if (
|
|
21637
|
+
const sourceDistClientRoot = resolve10(selfDir, "../dist/client");
|
|
21638
|
+
if (existsSync14(join21(sourceDistClientRoot, "index.html"))) {
|
|
18006
21639
|
return sourceDistClientRoot;
|
|
18007
21640
|
}
|
|
18008
21641
|
return;
|