@inspecto-dev/plugin 0.3.8 → 0.3.10
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/astro.cjs +572 -86
- package/dist/astro.cjs.map +1 -1
- package/dist/astro.d.cts +1 -1
- package/dist/astro.d.ts +1 -1
- package/dist/astro.js +571 -85
- package/dist/astro.js.map +1 -1
- package/dist/index.cjs +559 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +558 -82
- package/dist/index.js.map +1 -1
- package/dist/legacy/rspack/index.cjs +526 -74
- package/dist/legacy/rspack/index.cjs.map +1 -1
- package/dist/legacy/rspack/index.js +526 -74
- package/dist/legacy/rspack/index.js.map +1 -1
- package/dist/legacy/rspack/loader.cjs +4 -1
- package/dist/legacy/rspack/loader.cjs.map +1 -1
- package/dist/legacy/rspack/loader.js +3 -0
- package/dist/legacy/rspack/loader.js.map +1 -1
- package/dist/legacy/webpack4/index.cjs +526 -74
- package/dist/legacy/webpack4/index.cjs.map +1 -1
- package/dist/legacy/webpack4/index.js +526 -74
- package/dist/legacy/webpack4/index.js.map +1 -1
- package/dist/legacy/webpack4/loader.cjs +4 -1
- package/dist/legacy/webpack4/loader.cjs.map +1 -1
- package/dist/legacy/webpack4/loader.js +3 -0
- package/dist/legacy/webpack4/loader.js.map +1 -1
- package/dist/rollup.cjs +559 -83
- package/dist/rollup.cjs.map +1 -1
- package/dist/rollup.js +558 -82
- package/dist/rollup.js.map +1 -1
- package/dist/rspack.cjs +559 -83
- package/dist/rspack.cjs.map +1 -1
- package/dist/rspack.js +558 -82
- package/dist/rspack.js.map +1 -1
- package/dist/vite.cjs +559 -83
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +558 -82
- package/dist/vite.js.map +1 -1
- package/dist/webpack.cjs +559 -83
- package/dist/webpack.cjs.map +1 -1
- package/dist/webpack.js +558 -82
- package/dist/webpack.js.map +1 -1
- package/package.json +8 -12
|
@@ -5,7 +5,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
5
5
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
-
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.
|
|
8
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.14_typescript@5.9.3_yaml@2.8.4/node_modules/tsup/assets/esm_shims.js
|
|
9
9
|
import path from "path";
|
|
10
10
|
import { fileURLToPath } from "url";
|
|
11
11
|
var getFilename = () => fileURLToPath(import.meta.url);
|
|
@@ -513,7 +513,6 @@ function dispatchPromptThroughIde(runtime, payload) {
|
|
|
513
513
|
line: payload.line,
|
|
514
514
|
column: payload.column,
|
|
515
515
|
snippet: payload.snippet,
|
|
516
|
-
...payload.screenshotContext ? { screenshotContext: payload.screenshotContext } : {},
|
|
517
516
|
overrides: runtime.overrides,
|
|
518
517
|
autoSend: runtime.autoSend
|
|
519
518
|
});
|
|
@@ -647,6 +646,188 @@ function assertPathWithinIdeOpenScope(file, projectRoot) {
|
|
|
647
646
|
}
|
|
648
647
|
}
|
|
649
648
|
|
|
649
|
+
// src/server/session-store.ts
|
|
650
|
+
var DEFAULT_STATUS = "pending";
|
|
651
|
+
function createAnnotationSessionStore(options = {}) {
|
|
652
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
653
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
654
|
+
const now = options.now ?? (() => Date.now());
|
|
655
|
+
const createId = options.createId ?? createRandomId;
|
|
656
|
+
function findNewestMatchingSession(statuses) {
|
|
657
|
+
return [...sessions.values()].filter((session) => statuses ? statuses.has(session.status) : true).sort((left, right) => right.updatedAt - left.updatedAt)[0] ?? null;
|
|
658
|
+
}
|
|
659
|
+
function updateSessionStatus(id, status) {
|
|
660
|
+
const session = sessions.get(id);
|
|
661
|
+
if (!session) return null;
|
|
662
|
+
const timestamp = now();
|
|
663
|
+
session.status = status;
|
|
664
|
+
session.updatedAt = timestamp;
|
|
665
|
+
if (status === "acknowledged") {
|
|
666
|
+
session.acknowledgedAt = timestamp;
|
|
667
|
+
}
|
|
668
|
+
if (status === "resolved") {
|
|
669
|
+
session.resolvedAt = timestamp;
|
|
670
|
+
}
|
|
671
|
+
emit({ type: "session-status-updated", session });
|
|
672
|
+
return cloneSession(session);
|
|
673
|
+
}
|
|
674
|
+
function claimSession(id, statuses) {
|
|
675
|
+
const session = sessions.get(id);
|
|
676
|
+
if (!session || statuses && !statuses.has(session.status)) return null;
|
|
677
|
+
if (session.status === "acknowledged") return cloneSession(session);
|
|
678
|
+
return updateSessionStatus(id, "acknowledged");
|
|
679
|
+
}
|
|
680
|
+
function emit(event) {
|
|
681
|
+
const snapshot = cloneSession(event.session);
|
|
682
|
+
for (const listener of listeners) {
|
|
683
|
+
listener({ type: event.type, session: snapshot });
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
const store = {
|
|
687
|
+
createSession(input) {
|
|
688
|
+
const timestamp = now();
|
|
689
|
+
const session = {
|
|
690
|
+
id: createId(),
|
|
691
|
+
instruction: input.instruction?.trim() ?? "",
|
|
692
|
+
annotations: cloneArray(input.annotations),
|
|
693
|
+
...input.deliveryMode ? { deliveryMode: input.deliveryMode } : {},
|
|
694
|
+
status: DEFAULT_STATUS,
|
|
695
|
+
messages: cloneArray(input.messages ?? []),
|
|
696
|
+
createdAt: timestamp,
|
|
697
|
+
updatedAt: timestamp,
|
|
698
|
+
...input.runtimeContext ? { runtimeContext: cloneValue(input.runtimeContext) } : {},
|
|
699
|
+
...input.cssContextPrompt?.trim() ? { cssContextPrompt: input.cssContextPrompt.trim() } : {},
|
|
700
|
+
...input.pageUrl ? { pageUrl: input.pageUrl } : {},
|
|
701
|
+
...input.route ? { route: input.route } : {}
|
|
702
|
+
};
|
|
703
|
+
sessions.set(session.id, session);
|
|
704
|
+
emit({ type: "session-created", session });
|
|
705
|
+
return cloneSession(session);
|
|
706
|
+
},
|
|
707
|
+
getSession(id) {
|
|
708
|
+
const session = sessions.get(id);
|
|
709
|
+
return session ? cloneSession(session) : null;
|
|
710
|
+
},
|
|
711
|
+
listSessions(options2 = {}) {
|
|
712
|
+
const statuses = normalizeStatuses(options2.status);
|
|
713
|
+
return [...sessions.values()].filter((session) => statuses ? statuses.has(session.status) : true).sort((left, right) => right.updatedAt - left.updatedAt).map((session) => cloneSession(session));
|
|
714
|
+
},
|
|
715
|
+
async claimNextSession(options2 = {}) {
|
|
716
|
+
const statuses = normalizeStatuses(DEFAULT_STATUS);
|
|
717
|
+
const existingSession = findNewestMatchingSession(statuses);
|
|
718
|
+
if (existingSession) {
|
|
719
|
+
return {
|
|
720
|
+
session: claimSession(existingSession.id, statuses),
|
|
721
|
+
timedOut: false,
|
|
722
|
+
matchedExisting: true
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
const timeoutMs = normalizeTimeoutMs(options2.timeoutMs);
|
|
726
|
+
if (timeoutMs === 0) {
|
|
727
|
+
return {
|
|
728
|
+
session: null,
|
|
729
|
+
timedOut: true,
|
|
730
|
+
matchedExisting: false
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
return await new Promise((resolve2) => {
|
|
734
|
+
let settled = false;
|
|
735
|
+
let timeout = null;
|
|
736
|
+
const finish = (result) => {
|
|
737
|
+
if (settled) return;
|
|
738
|
+
settled = true;
|
|
739
|
+
unsubscribe();
|
|
740
|
+
if (timeout) {
|
|
741
|
+
clearTimeout(timeout);
|
|
742
|
+
}
|
|
743
|
+
resolve2(result);
|
|
744
|
+
};
|
|
745
|
+
const unsubscribe = this.subscribe((event) => {
|
|
746
|
+
const session = claimSession(event.session.id, statuses);
|
|
747
|
+
if (!session) return;
|
|
748
|
+
finish({
|
|
749
|
+
session,
|
|
750
|
+
timedOut: false,
|
|
751
|
+
matchedExisting: false,
|
|
752
|
+
event: event.type
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
if (timeoutMs !== null) {
|
|
756
|
+
timeout = setTimeout(() => {
|
|
757
|
+
finish({
|
|
758
|
+
session: null,
|
|
759
|
+
timedOut: true,
|
|
760
|
+
matchedExisting: false
|
|
761
|
+
});
|
|
762
|
+
}, timeoutMs);
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
},
|
|
766
|
+
appendMessage(id, input) {
|
|
767
|
+
const session = sessions.get(id);
|
|
768
|
+
if (!session) return null;
|
|
769
|
+
const timestamp = now();
|
|
770
|
+
session.messages.push({
|
|
771
|
+
id: createId(),
|
|
772
|
+
role: input.role,
|
|
773
|
+
text: input.text,
|
|
774
|
+
createdAt: timestamp
|
|
775
|
+
});
|
|
776
|
+
session.updatedAt = timestamp;
|
|
777
|
+
if (input.role === "agent" && isPendingLikeStatus(session.status)) {
|
|
778
|
+
session.status = "in_progress";
|
|
779
|
+
}
|
|
780
|
+
emit({ type: "session-message-appended", session });
|
|
781
|
+
return cloneSession(session);
|
|
782
|
+
},
|
|
783
|
+
updateStatus(id, status) {
|
|
784
|
+
return updateSessionStatus(id, status);
|
|
785
|
+
},
|
|
786
|
+
subscribe(listener) {
|
|
787
|
+
listeners.add(listener);
|
|
788
|
+
return () => {
|
|
789
|
+
listeners.delete(listener);
|
|
790
|
+
};
|
|
791
|
+
},
|
|
792
|
+
clear() {
|
|
793
|
+
sessions.clear();
|
|
794
|
+
listeners.clear();
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
return store;
|
|
798
|
+
}
|
|
799
|
+
var annotationSessionStore = createAnnotationSessionStore();
|
|
800
|
+
function normalizeStatuses(status) {
|
|
801
|
+
if (!status) return null;
|
|
802
|
+
return new Set(Array.isArray(status) ? status : [status]);
|
|
803
|
+
}
|
|
804
|
+
function normalizeTimeoutMs(value) {
|
|
805
|
+
if (value === void 0) return null;
|
|
806
|
+
if (!Number.isFinite(value)) return 0;
|
|
807
|
+
return Math.max(0, Math.floor(value));
|
|
808
|
+
}
|
|
809
|
+
function isPendingLikeStatus(status) {
|
|
810
|
+
return status === "pending" || status === "acknowledged";
|
|
811
|
+
}
|
|
812
|
+
function hasAgentReply(session) {
|
|
813
|
+
return session.messages.some((message) => message.role === "agent" && Boolean(message.text?.trim()));
|
|
814
|
+
}
|
|
815
|
+
function createRandomId() {
|
|
816
|
+
return `annotation-session-${Math.random().toString(36).slice(2, 10)}`;
|
|
817
|
+
}
|
|
818
|
+
function cloneSession(session) {
|
|
819
|
+
return cloneValue(session);
|
|
820
|
+
}
|
|
821
|
+
function cloneArray(value) {
|
|
822
|
+
return cloneValue(value);
|
|
823
|
+
}
|
|
824
|
+
function cloneValue(value) {
|
|
825
|
+
if (typeof structuredClone === "function") {
|
|
826
|
+
return structuredClone(value);
|
|
827
|
+
}
|
|
828
|
+
return JSON.parse(JSON.stringify(value));
|
|
829
|
+
}
|
|
830
|
+
|
|
650
831
|
// src/server/annotation-dispatch.ts
|
|
651
832
|
var AnnotationDispatchError = class extends Error {
|
|
652
833
|
constructor(message, errorCode) {
|
|
@@ -655,20 +836,30 @@ var AnnotationDispatchError = class extends Error {
|
|
|
655
836
|
this.errorCode = errorCode;
|
|
656
837
|
}
|
|
657
838
|
};
|
|
658
|
-
async function dispatchAnnotationsToAi(req, state) {
|
|
839
|
+
async function dispatchAnnotationsToAi(req, state, store = annotationSessionStore) {
|
|
659
840
|
try {
|
|
660
841
|
validateAnnotationDispatchRequest(req, state);
|
|
661
842
|
const batch = normalizeAnnotationBatch(req);
|
|
662
843
|
const prompt = buildAnnotationBatchPrompt(batch);
|
|
844
|
+
const deliveryMode = normalizeDeliveryMode(req.deliveryMode);
|
|
845
|
+
const session = store.createSession({
|
|
846
|
+
instruction: batch.instruction,
|
|
847
|
+
annotations: toSessionAnnotations(batch.annotations),
|
|
848
|
+
deliveryMode,
|
|
849
|
+
...batch.runtimeContext ? { runtimeContext: batch.runtimeContext } : {},
|
|
850
|
+
...batch.cssContextPrompt ? { cssContextPrompt: batch.cssContextPrompt } : {}
|
|
851
|
+
});
|
|
663
852
|
const representativeTarget = batch.annotations[0]?.targets[0];
|
|
664
|
-
const
|
|
665
|
-
return dispatchPromptThroughIde(runtime, {
|
|
853
|
+
const dispatchResult = deliveryMode === "ide" ? dispatchPromptThroughIde(resolvePromptDispatchRuntime(state), {
|
|
666
854
|
prompt,
|
|
667
855
|
...representativeTarget?.file ? { filePath: representativeTarget.file } : {},
|
|
668
856
|
...representativeTarget?.line ? { line: representativeTarget.line } : {},
|
|
669
|
-
...representativeTarget?.column ? { column: representativeTarget.column } : {}
|
|
670
|
-
|
|
671
|
-
|
|
857
|
+
...representativeTarget?.column ? { column: representativeTarget.column } : {}
|
|
858
|
+
}) : { success: true };
|
|
859
|
+
return {
|
|
860
|
+
...dispatchResult,
|
|
861
|
+
session: toSessionSummary(session)
|
|
862
|
+
};
|
|
672
863
|
} catch (error) {
|
|
673
864
|
return {
|
|
674
865
|
success: false,
|
|
@@ -677,6 +868,41 @@ async function dispatchAnnotationsToAi(req, state) {
|
|
|
677
868
|
};
|
|
678
869
|
}
|
|
679
870
|
}
|
|
871
|
+
function normalizeDeliveryMode(input) {
|
|
872
|
+
return input === "agent" ? "agent" : "ide";
|
|
873
|
+
}
|
|
874
|
+
function toSessionAnnotations(annotations) {
|
|
875
|
+
return annotations.map((annotation) => ({
|
|
876
|
+
id: `annotation-${annotation.index}`,
|
|
877
|
+
note: annotation.note,
|
|
878
|
+
intent: annotation.intent,
|
|
879
|
+
targets: annotation.targets.map((target, targetIndex) => ({
|
|
880
|
+
id: `annotation-${annotation.index}-target-${targetIndex + 1}`,
|
|
881
|
+
label: target.label ?? "Unknown target",
|
|
882
|
+
location: {
|
|
883
|
+
file: target.file,
|
|
884
|
+
line: target.line,
|
|
885
|
+
column: target.column
|
|
886
|
+
},
|
|
887
|
+
...target.selector ? { selector: target.selector } : {},
|
|
888
|
+
...target.snippet ? { snippet: target.snippet } : {},
|
|
889
|
+
rect: {
|
|
890
|
+
x: 0,
|
|
891
|
+
y: 0,
|
|
892
|
+
width: 0,
|
|
893
|
+
height: 0
|
|
894
|
+
}
|
|
895
|
+
}))
|
|
896
|
+
}));
|
|
897
|
+
}
|
|
898
|
+
function toSessionSummary(session) {
|
|
899
|
+
return {
|
|
900
|
+
id: session.id,
|
|
901
|
+
status: session.status,
|
|
902
|
+
createdAt: session.createdAt,
|
|
903
|
+
updatedAt: session.updatedAt
|
|
904
|
+
};
|
|
905
|
+
}
|
|
680
906
|
function validateAnnotationDispatchRequest(req, state) {
|
|
681
907
|
if (!req.annotations.length) {
|
|
682
908
|
throw new AnnotationDispatchError("At least one annotation is required.", "INVALID_REQUEST");
|
|
@@ -697,9 +923,7 @@ function validateAnnotationDispatchRequest(req, state) {
|
|
|
697
923
|
function normalizeAnnotationBatch(req) {
|
|
698
924
|
return {
|
|
699
925
|
instruction: req.instruction?.trim() ?? "",
|
|
700
|
-
responseMode: req.responseMode ?? "unified",
|
|
701
926
|
...req.runtimeContext ? { runtimeContext: req.runtimeContext } : {},
|
|
702
|
-
...req.screenshotContext ? { screenshotContext: req.screenshotContext } : {},
|
|
703
927
|
...req.cssContextPrompt?.trim() ? { cssContextPrompt: req.cssContextPrompt.trim() } : {},
|
|
704
928
|
annotations: req.annotations.map((annotation, index) => ({
|
|
705
929
|
index: index + 1,
|
|
@@ -721,12 +945,9 @@ function buildAnnotationBatchPrompt(batch) {
|
|
|
721
945
|
const prompt = batch.instruction ? `${batch.instruction}
|
|
722
946
|
|
|
723
947
|
${body}` : body;
|
|
724
|
-
return
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
batch.cssContextPrompt
|
|
728
|
-
),
|
|
729
|
-
batch.screenshotContext
|
|
948
|
+
return appendCssContextSection(
|
|
949
|
+
appendRuntimeContextSection(prompt, batch.runtimeContext),
|
|
950
|
+
batch.cssContextPrompt
|
|
730
951
|
);
|
|
731
952
|
}
|
|
732
953
|
function appendCssContextSection(prompt, cssContextPrompt) {
|
|
@@ -753,20 +974,6 @@ function buildSelectedElementsPrompt(annotations) {
|
|
|
753
974
|
}
|
|
754
975
|
return lines.join("\n");
|
|
755
976
|
}
|
|
756
|
-
function appendScreenshotContextSection(prompt, screenshotContext) {
|
|
757
|
-
if (!screenshotContext || !screenshotContext.imageDataUrl && !screenshotContext.imageAssetId) {
|
|
758
|
-
return prompt;
|
|
759
|
-
}
|
|
760
|
-
const lines = [
|
|
761
|
-
"Visual screenshot context attached:",
|
|
762
|
-
`- capturedAt=${screenshotContext.capturedAt}`,
|
|
763
|
-
`- mimeType=${screenshotContext.mimeType}`,
|
|
764
|
-
...screenshotContext.imageAssetId ? [`- imageAssetId=${screenshotContext.imageAssetId}`] : []
|
|
765
|
-
];
|
|
766
|
-
return `${prompt}
|
|
767
|
-
|
|
768
|
-
${lines.join("\n")}`;
|
|
769
|
-
}
|
|
770
977
|
function appendRuntimeContextSection(prompt, runtimeContext) {
|
|
771
978
|
if (!runtimeContext?.records.length) {
|
|
772
979
|
return prompt;
|
|
@@ -814,7 +1021,7 @@ async function buildClientConfig(serverState2) {
|
|
|
814
1021
|
...info,
|
|
815
1022
|
prompts: resolveIntents(promptsConfig),
|
|
816
1023
|
hotKeys: userConfig["inspector.hotKey"] ?? "alt",
|
|
817
|
-
|
|
1024
|
+
annotateDeliveryMode: userConfig["annotate.deliveryMode"] ?? "both",
|
|
818
1025
|
includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
|
|
819
1026
|
runtimeContext: {
|
|
820
1027
|
enabled: true,
|
|
@@ -822,10 +1029,6 @@ async function buildClientConfig(serverState2) {
|
|
|
822
1029
|
maxRuntimeErrors: 3,
|
|
823
1030
|
maxFailedRequests: 2
|
|
824
1031
|
},
|
|
825
|
-
screenshotContext: {
|
|
826
|
-
enabled: false
|
|
827
|
-
},
|
|
828
|
-
annotationResponseMode: userConfig["prompt.annotationResponseMode"] ?? "unified",
|
|
829
1032
|
autoSend: userConfig["prompt.autoSend"] ?? false
|
|
830
1033
|
};
|
|
831
1034
|
}
|
|
@@ -870,7 +1073,7 @@ function handleOpenFileRequest(body, serverState2) {
|
|
|
870
1073
|
else if (rawEditorHint === "vscodium") editorHint = "codium";
|
|
871
1074
|
else if (rawEditorHint === "trae-cn" || rawEditorHint === "trae") editorHint = "trae";
|
|
872
1075
|
serverLogger2.debug(
|
|
873
|
-
`
|
|
1076
|
+
`SOURCE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`
|
|
874
1077
|
);
|
|
875
1078
|
if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {
|
|
876
1079
|
let normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
@@ -879,7 +1082,7 @@ function handleOpenFileRequest(body, serverState2) {
|
|
|
879
1082
|
}
|
|
880
1083
|
const encodedPath = encodeURI(normalizedPath);
|
|
881
1084
|
const uri = `${rawEditorHint}://file${encodedPath}:${body.line}:${body.column}`;
|
|
882
|
-
serverLogger2.debug(`
|
|
1085
|
+
serverLogger2.debug(`SOURCE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
|
|
883
1086
|
try {
|
|
884
1087
|
if (process.platform === "darwin") {
|
|
885
1088
|
execFileSync2("open", [uri]);
|
|
@@ -889,7 +1092,7 @@ function handleOpenFileRequest(body, serverState2) {
|
|
|
889
1092
|
execFileSync2("xdg-open", [uri]);
|
|
890
1093
|
}
|
|
891
1094
|
} catch (e) {
|
|
892
|
-
serverLogger2.error(`Failed to launch URI for
|
|
1095
|
+
serverLogger2.error(`Failed to launch URI for SOURCE_OPEN (${uri}):`, e);
|
|
893
1096
|
launchIDE2({
|
|
894
1097
|
file: absolutePath,
|
|
895
1098
|
line: body.line,
|
|
@@ -944,8 +1147,18 @@ function resolveProjectRoot() {
|
|
|
944
1147
|
return gitRoot;
|
|
945
1148
|
}
|
|
946
1149
|
|
|
1150
|
+
// src/server/server-url.ts
|
|
1151
|
+
function resolveServerHost(cwd, configRoot) {
|
|
1152
|
+
const userConfig = loadUserConfigSync(false, cwd, configRoot);
|
|
1153
|
+
const configuredHost = userConfig["server.host"]?.trim();
|
|
1154
|
+
if (configuredHost) return configuredHost;
|
|
1155
|
+
if (process.env["VITEST"]) return "127.0.0.1";
|
|
1156
|
+
return "127.0.0.1";
|
|
1157
|
+
}
|
|
1158
|
+
|
|
947
1159
|
// src/server/index.ts
|
|
948
1160
|
var serverLogger4 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
1161
|
+
var PORT_FILE_NAME = "inspecto.port.json";
|
|
949
1162
|
var serverState = {
|
|
950
1163
|
port: null,
|
|
951
1164
|
running: false,
|
|
@@ -954,6 +1167,42 @@ var serverState = {
|
|
|
954
1167
|
cwd: process.cwd()
|
|
955
1168
|
};
|
|
956
1169
|
var serverInstance = null;
|
|
1170
|
+
function getPortFilePath() {
|
|
1171
|
+
return path6.join(os2.tmpdir(), PORT_FILE_NAME);
|
|
1172
|
+
}
|
|
1173
|
+
function getProjectRootHash() {
|
|
1174
|
+
if (!serverState.projectRoot) return null;
|
|
1175
|
+
return crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
1176
|
+
}
|
|
1177
|
+
function readPortData(portFile) {
|
|
1178
|
+
if (!fs5.existsSync(portFile)) return {};
|
|
1179
|
+
try {
|
|
1180
|
+
return JSON.parse(fs5.readFileSync(portFile, "utf-8"));
|
|
1181
|
+
} catch {
|
|
1182
|
+
return {};
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
function writeProjectPort(port) {
|
|
1186
|
+
const rootHash = getProjectRootHash();
|
|
1187
|
+
if (!rootHash) return;
|
|
1188
|
+
const portFile = getPortFilePath();
|
|
1189
|
+
const portData = readPortData(portFile);
|
|
1190
|
+
portData[rootHash] = port;
|
|
1191
|
+
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
1192
|
+
}
|
|
1193
|
+
function removeProjectPort() {
|
|
1194
|
+
const rootHash = getProjectRootHash();
|
|
1195
|
+
if (!rootHash) return;
|
|
1196
|
+
const portFile = getPortFilePath();
|
|
1197
|
+
if (!fs5.existsSync(portFile)) return;
|
|
1198
|
+
const portData = readPortData(portFile);
|
|
1199
|
+
delete portData[rootHash];
|
|
1200
|
+
if (Object.keys(portData).length === 0) {
|
|
1201
|
+
fs5.unlinkSync(portFile);
|
|
1202
|
+
} else {
|
|
1203
|
+
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
957
1206
|
async function startServer() {
|
|
958
1207
|
if (serverState.running && serverState.port !== null) {
|
|
959
1208
|
return serverState.port;
|
|
@@ -961,6 +1210,7 @@ async function startServer() {
|
|
|
961
1210
|
serverState.projectRoot = resolveProjectRoot();
|
|
962
1211
|
serverState.configRoot = serverState.projectRoot;
|
|
963
1212
|
serverState.cwd = process.cwd();
|
|
1213
|
+
const serverHost = resolveServerHost(serverState.cwd, serverState.configRoot);
|
|
964
1214
|
portfinder.basePort = 5678;
|
|
965
1215
|
const port = await portfinder.getPortPromise();
|
|
966
1216
|
watchConfig(
|
|
@@ -987,7 +1237,7 @@ async function startServer() {
|
|
|
987
1237
|
});
|
|
988
1238
|
});
|
|
989
1239
|
await new Promise((resolve2, reject) => {
|
|
990
|
-
serverInstance.listen(port,
|
|
1240
|
+
serverInstance.listen(port, serverHost, () => {
|
|
991
1241
|
serverInstance.unref();
|
|
992
1242
|
resolve2();
|
|
993
1243
|
});
|
|
@@ -998,37 +1248,18 @@ async function startServer() {
|
|
|
998
1248
|
});
|
|
999
1249
|
serverState.port = port;
|
|
1000
1250
|
serverState.running = true;
|
|
1001
|
-
const portFile = path6.join(os2.tmpdir(), "inspecto.port.json");
|
|
1002
1251
|
try {
|
|
1003
|
-
|
|
1004
|
-
if (fs5.existsSync(portFile)) {
|
|
1005
|
-
try {
|
|
1006
|
-
portData = JSON.parse(fs5.readFileSync(portFile, "utf-8"));
|
|
1007
|
-
} catch (_e) {
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
const rootHash = crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
1011
|
-
portData[rootHash] = port;
|
|
1012
|
-
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
1252
|
+
writeProjectPort(port);
|
|
1013
1253
|
} catch (_e) {
|
|
1014
1254
|
serverLogger4.warn("Failed to write port file:", _e);
|
|
1015
1255
|
}
|
|
1016
1256
|
process.once("exit", () => {
|
|
1017
1257
|
try {
|
|
1018
|
-
|
|
1019
|
-
const portData = JSON.parse(fs5.readFileSync(portFile, "utf-8"));
|
|
1020
|
-
const rootHash = crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
1021
|
-
delete portData[rootHash];
|
|
1022
|
-
if (Object.keys(portData).length === 0) {
|
|
1023
|
-
fs5.unlinkSync(portFile);
|
|
1024
|
-
} else {
|
|
1025
|
-
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1258
|
+
removeProjectPort();
|
|
1028
1259
|
} catch {
|
|
1029
1260
|
}
|
|
1030
1261
|
});
|
|
1031
|
-
serverLogger4.info(`server running at http
|
|
1262
|
+
serverLogger4.info(`server running at http://${serverHost}:${port}`);
|
|
1032
1263
|
return port;
|
|
1033
1264
|
}
|
|
1034
1265
|
async function readBody(req) {
|
|
@@ -1080,7 +1311,7 @@ async function handleRequest(url, req, res) {
|
|
|
1080
1311
|
}
|
|
1081
1312
|
return;
|
|
1082
1313
|
}
|
|
1083
|
-
if (pathname === INSPECTO_API_PATHS.IDE_OPEN && req.method === "POST") {
|
|
1314
|
+
if ((pathname === INSPECTO_API_PATHS.SOURCE_OPEN || pathname === INSPECTO_API_PATHS.IDE_OPEN) && req.method === "POST") {
|
|
1084
1315
|
let body;
|
|
1085
1316
|
try {
|
|
1086
1317
|
body = JSON.parse(await readBody(req));
|
|
@@ -1093,7 +1324,7 @@ async function handleRequest(url, req, res) {
|
|
|
1093
1324
|
handleOpenFileRequest(body, serverState);
|
|
1094
1325
|
} catch (err) {
|
|
1095
1326
|
serverLogger4.warn(
|
|
1096
|
-
`Security: Blocked path traversal attempt in
|
|
1327
|
+
`Security: Blocked path traversal attempt in SOURCE_OPEN: ${body.file}. Reason: ${err.message}`
|
|
1097
1328
|
);
|
|
1098
1329
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1099
1330
|
res.end(JSON.stringify({ error: "Access denied: File is outside of project workspace" }));
|
|
@@ -1167,6 +1398,212 @@ async function handleRequest(url, req, res) {
|
|
|
1167
1398
|
}
|
|
1168
1399
|
return;
|
|
1169
1400
|
}
|
|
1401
|
+
if (pathname === INSPECTO_API_PATHS.SESSION_CLAIM_NEXT && req.method === "POST") {
|
|
1402
|
+
try {
|
|
1403
|
+
const rawBody = await readBody(req);
|
|
1404
|
+
const body = rawBody ? JSON.parse(rawBody) : {};
|
|
1405
|
+
const timeoutMs = normalizeSessionClaimTimeout(
|
|
1406
|
+
body.timeoutMs === void 0 ? null : String(body.timeoutMs)
|
|
1407
|
+
);
|
|
1408
|
+
const result = await annotationSessionStore.claimNextSession({
|
|
1409
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
1410
|
+
});
|
|
1411
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1412
|
+
res.end(
|
|
1413
|
+
JSON.stringify({
|
|
1414
|
+
success: true,
|
|
1415
|
+
timedOut: result.timedOut,
|
|
1416
|
+
matchedExisting: result.matchedExisting,
|
|
1417
|
+
...result.event ? { event: result.event } : {},
|
|
1418
|
+
...result.session ? { session: result.session } : {}
|
|
1419
|
+
})
|
|
1420
|
+
);
|
|
1421
|
+
} catch (e) {
|
|
1422
|
+
serverLogger4.error(`Error parsing session claim request:`, e);
|
|
1423
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1424
|
+
res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
|
|
1425
|
+
}
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
if (pathname === INSPECTO_API_PATHS.SESSION_EVENTS && req.method === "GET") {
|
|
1429
|
+
const statusParam = url.searchParams.getAll("status");
|
|
1430
|
+
const statuses = statusParam.length ? new Set(statusParam) : null;
|
|
1431
|
+
const sessionId = url.searchParams.get("sessionId")?.trim() || null;
|
|
1432
|
+
res.writeHead(200, {
|
|
1433
|
+
"Content-Type": "text/event-stream",
|
|
1434
|
+
"Cache-Control": "no-cache",
|
|
1435
|
+
Connection: "keep-alive"
|
|
1436
|
+
});
|
|
1437
|
+
res.write(`event: ready
|
|
1438
|
+
data: ${JSON.stringify({ ok: true })}
|
|
1439
|
+
|
|
1440
|
+
`);
|
|
1441
|
+
const unsubscribe = annotationSessionStore.subscribe((event) => {
|
|
1442
|
+
if (sessionId && event.session.id !== sessionId) {
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1445
|
+
if (statuses && !statuses.has(event.session.status)) {
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
res.write(formatSessionSseEvent(event));
|
|
1449
|
+
});
|
|
1450
|
+
req.on("close", () => {
|
|
1451
|
+
unsubscribe();
|
|
1452
|
+
res.end();
|
|
1453
|
+
});
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
if (pathname === INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
|
|
1457
|
+
const statusParam = url.searchParams.getAll("status");
|
|
1458
|
+
const sessions = annotationSessionStore.listSessions(
|
|
1459
|
+
statusParam.length ? {
|
|
1460
|
+
status: statusParam
|
|
1461
|
+
} : void 0
|
|
1462
|
+
);
|
|
1463
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1464
|
+
res.end(JSON.stringify({ success: true, sessions }));
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
if (pathname.startsWith(`${INSPECTO_API_PATHS.SESSIONS}/`) && req.method === "GET") {
|
|
1468
|
+
const sessionId = pathname.substring(INSPECTO_API_PATHS.SESSIONS.length + 1);
|
|
1469
|
+
const session = annotationSessionStore.getSession(sessionId);
|
|
1470
|
+
if (!session) {
|
|
1471
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1472
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1476
|
+
res.end(JSON.stringify({ success: true, session }));
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
if (pathname.startsWith(`${INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX) && req.method === "POST") {
|
|
1480
|
+
const sessionId = pathname.slice(
|
|
1481
|
+
INSPECTO_API_PATHS.SESSIONS.length + 1,
|
|
1482
|
+
-INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX.length
|
|
1483
|
+
);
|
|
1484
|
+
try {
|
|
1485
|
+
const rawBody = await readBody(req);
|
|
1486
|
+
const body = JSON.parse(rawBody);
|
|
1487
|
+
if (!isAnnotationThreadRole(body.role)) {
|
|
1488
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1489
|
+
res.end(JSON.stringify({ success: false, error: "Reply role is invalid." }));
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
if (!body.text?.trim()) {
|
|
1493
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1494
|
+
res.end(JSON.stringify({ success: false, error: "Reply text is required." }));
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
const session = annotationSessionStore.appendMessage(sessionId, {
|
|
1498
|
+
role: body.role,
|
|
1499
|
+
text: body.text.trim()
|
|
1500
|
+
});
|
|
1501
|
+
if (!session) {
|
|
1502
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1503
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1504
|
+
return;
|
|
1505
|
+
}
|
|
1506
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1507
|
+
res.end(JSON.stringify({ success: true, session }));
|
|
1508
|
+
} catch (e) {
|
|
1509
|
+
serverLogger4.error(`Error parsing session reply request:`, e);
|
|
1510
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1511
|
+
res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
|
|
1512
|
+
}
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
if (pathname.startsWith(`${INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX) && req.method === "POST") {
|
|
1516
|
+
const sessionId = pathname.slice(
|
|
1517
|
+
INSPECTO_API_PATHS.SESSIONS.length + 1,
|
|
1518
|
+
-INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX.length
|
|
1519
|
+
);
|
|
1520
|
+
try {
|
|
1521
|
+
const rawBody = await readBody(req);
|
|
1522
|
+
const body = rawBody ? JSON.parse(rawBody) : {};
|
|
1523
|
+
const message = body.message?.trim();
|
|
1524
|
+
const existingSession = annotationSessionStore.getSession(sessionId);
|
|
1525
|
+
if (!existingSession) {
|
|
1526
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1527
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
if (!message && !hasAgentReply(existingSession)) {
|
|
1531
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1532
|
+
res.end(
|
|
1533
|
+
JSON.stringify({
|
|
1534
|
+
success: false,
|
|
1535
|
+
error: "Resolve message is required until an agent reply is recorded."
|
|
1536
|
+
})
|
|
1537
|
+
);
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
if (message) {
|
|
1541
|
+
const repliedSession = annotationSessionStore.appendMessage(sessionId, {
|
|
1542
|
+
role: "agent",
|
|
1543
|
+
text: message
|
|
1544
|
+
});
|
|
1545
|
+
if (!repliedSession) {
|
|
1546
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1547
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
const session = annotationSessionStore.updateStatus(sessionId, "resolved");
|
|
1552
|
+
if (!session) {
|
|
1553
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1554
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1558
|
+
res.end(JSON.stringify({ success: true, session }));
|
|
1559
|
+
} catch (e) {
|
|
1560
|
+
serverLogger4.error(`Error parsing session resolve request:`, e);
|
|
1561
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1562
|
+
res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
|
|
1563
|
+
}
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
if (pathname.startsWith(`${INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX) && req.method === "POST") {
|
|
1567
|
+
const sessionId = pathname.slice(
|
|
1568
|
+
INSPECTO_API_PATHS.SESSIONS.length + 1,
|
|
1569
|
+
-INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX.length
|
|
1570
|
+
);
|
|
1571
|
+
try {
|
|
1572
|
+
const rawBody = await readBody(req);
|
|
1573
|
+
const body = rawBody ? JSON.parse(rawBody) : {};
|
|
1574
|
+
const message = body.message?.trim();
|
|
1575
|
+
const existingSession = annotationSessionStore.getSession(sessionId);
|
|
1576
|
+
if (!existingSession) {
|
|
1577
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1578
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
if (message) {
|
|
1582
|
+
const repliedSession = annotationSessionStore.appendMessage(sessionId, {
|
|
1583
|
+
role: "agent",
|
|
1584
|
+
text: message
|
|
1585
|
+
});
|
|
1586
|
+
if (!repliedSession) {
|
|
1587
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1588
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
const session = annotationSessionStore.updateStatus(sessionId, "dismissed");
|
|
1593
|
+
if (!session) {
|
|
1594
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1595
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1599
|
+
res.end(JSON.stringify({ success: true, session }));
|
|
1600
|
+
} catch (e) {
|
|
1601
|
+
serverLogger4.error(`Error parsing session dismiss request:`, e);
|
|
1602
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1603
|
+
res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
|
|
1604
|
+
}
|
|
1605
|
+
return;
|
|
1606
|
+
}
|
|
1170
1607
|
if (pathname.startsWith(`${INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
|
|
1171
1608
|
const ticketId = pathname.substring(INSPECTO_API_PATHS.AI_TICKET.length + 1);
|
|
1172
1609
|
const payloadStr = readTicket(ticketId);
|
|
@@ -1183,7 +1620,7 @@ async function handleRequest(url, req, res) {
|
|
|
1183
1620
|
res.end(JSON.stringify({ error: "not found" }));
|
|
1184
1621
|
}
|
|
1185
1622
|
async function dispatchToAi(req) {
|
|
1186
|
-
const { location, snippet, prompt
|
|
1623
|
+
const { location, snippet, prompt } = req;
|
|
1187
1624
|
const formattedPrompt = prompt ?? `Please help me with this code from \`${location.file}\` (line ${location.line}):
|
|
1188
1625
|
|
|
1189
1626
|
\`\`\`
|
|
@@ -1196,8 +1633,7 @@ ${snippet}
|
|
|
1196
1633
|
filePath: location.file,
|
|
1197
1634
|
line: location.line,
|
|
1198
1635
|
column: location.column,
|
|
1199
|
-
snippet
|
|
1200
|
-
...screenshotContext ? { screenshotContext } : {}
|
|
1636
|
+
snippet
|
|
1201
1637
|
});
|
|
1202
1638
|
}
|
|
1203
1639
|
function getBatchDispatchStatusCode(errorCode, success) {
|
|
@@ -1206,6 +1642,21 @@ function getBatchDispatchStatusCode(errorCode, success) {
|
|
|
1206
1642
|
if (errorCode === "FORBIDDEN_PATH") return 403;
|
|
1207
1643
|
return 500;
|
|
1208
1644
|
}
|
|
1645
|
+
function isAnnotationThreadRole(value) {
|
|
1646
|
+
return value === "user" || value === "agent" || value === "system";
|
|
1647
|
+
}
|
|
1648
|
+
function formatSessionSseEvent(event) {
|
|
1649
|
+
return `event: ${event.type}
|
|
1650
|
+
data: ${JSON.stringify(event)}
|
|
1651
|
+
|
|
1652
|
+
`;
|
|
1653
|
+
}
|
|
1654
|
+
function normalizeSessionClaimTimeout(value) {
|
|
1655
|
+
if (!value?.trim()) return 3e4;
|
|
1656
|
+
const parsed = Number.parseInt(value, 10);
|
|
1657
|
+
if (!Number.isFinite(parsed)) return 3e4;
|
|
1658
|
+
return Math.max(0, Math.min(parsed, 3e5));
|
|
1659
|
+
}
|
|
1209
1660
|
|
|
1210
1661
|
// src/injectors/utils.ts
|
|
1211
1662
|
import { createRequire } from "module";
|
|
@@ -1225,16 +1676,17 @@ var resolveClientModule = () => {
|
|
|
1225
1676
|
};
|
|
1226
1677
|
|
|
1227
1678
|
// src/injectors/webpack.ts
|
|
1228
|
-
function getWebpackHtmlScript(serverPort2) {
|
|
1679
|
+
function getWebpackHtmlScript(serverPort2, publicServerUrl) {
|
|
1229
1680
|
return `
|
|
1230
1681
|
window.__AI_INSPECTOR_PORT__ = ${serverPort2};
|
|
1231
|
-
window.
|
|
1232
|
-
|
|
1233
|
-
window.InspectoClient
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
}
|
|
1682
|
+
window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort2}`}';
|
|
1683
|
+
window.addEventListener('load', () => {
|
|
1684
|
+
if (window.InspectoClient) {
|
|
1685
|
+
window.InspectoClient.mountInspector({
|
|
1686
|
+
serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
});
|
|
1238
1690
|
`;
|
|
1239
1691
|
}
|
|
1240
1692
|
|