@inspecto-dev/plugin 0.3.7 → 0.3.9
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/README.md +2 -1
- package/dist/astro.cjs +2687 -0
- package/dist/astro.cjs.map +1 -0
- package/dist/astro.d.cts +17 -0
- package/dist/astro.d.ts +17 -0
- package/dist/astro.js +2656 -0
- package/dist/astro.js.map +1 -0
- package/dist/index.cjs +932 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +930 -87
- package/dist/index.js.map +1 -1
- package/dist/legacy/rspack/index.cjs +530 -89
- package/dist/legacy/rspack/index.cjs.map +1 -1
- package/dist/legacy/rspack/index.js +530 -89
- package/dist/legacy/rspack/index.js.map +1 -1
- package/dist/legacy/rspack/loader.cjs +407 -3
- package/dist/legacy/rspack/loader.cjs.map +1 -1
- package/dist/legacy/rspack/loader.js +403 -3
- package/dist/legacy/rspack/loader.js.map +1 -1
- package/dist/legacy/webpack4/index.cjs +519 -78
- package/dist/legacy/webpack4/index.cjs.map +1 -1
- package/dist/legacy/webpack4/index.js +519 -78
- package/dist/legacy/webpack4/index.js.map +1 -1
- package/dist/legacy/webpack4/loader.cjs +407 -3
- package/dist/legacy/webpack4/loader.cjs.map +1 -1
- package/dist/legacy/webpack4/loader.js +403 -3
- package/dist/legacy/webpack4/loader.js.map +1 -1
- package/dist/rollup.cjs +932 -87
- package/dist/rollup.cjs.map +1 -1
- package/dist/rollup.d.cts +1 -1
- package/dist/rollup.d.ts +1 -1
- package/dist/rollup.js +930 -87
- package/dist/rollup.js.map +1 -1
- package/dist/rspack.cjs +932 -87
- package/dist/rspack.cjs.map +1 -1
- package/dist/rspack.d.cts +1 -1
- package/dist/rspack.d.ts +1 -1
- package/dist/rspack.js +930 -87
- package/dist/rspack.js.map +1 -1
- package/dist/vite.cjs +932 -87
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.cts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +930 -87
- package/dist/vite.js.map +1 -1
- package/dist/webpack.cjs +932 -87
- package/dist/webpack.cjs.map +1 -1
- package/dist/webpack.d.cts +1 -1
- package/dist/webpack.d.ts +1 -1
- package/dist/webpack.js +930 -87
- package/dist/webpack.js.map +1 -1
- package/package.json +13 -10
|
@@ -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.6.1_postcss@8.5.
|
|
8
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.10_typescript@5.9.3_yaml@2.8.3/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);
|
|
@@ -293,7 +293,7 @@ function readJsonSafely(filePath) {
|
|
|
293
293
|
}
|
|
294
294
|
return null;
|
|
295
295
|
}
|
|
296
|
-
function resolveTargetTool(config,
|
|
296
|
+
function resolveTargetTool(config, _ide = "vscode") {
|
|
297
297
|
const defaultProvider = config["provider.default"];
|
|
298
298
|
if (defaultProvider) {
|
|
299
299
|
const tool = defaultProvider.split(".")[0];
|
|
@@ -445,7 +445,7 @@ function watchConfig(onReload, cwd = process.cwd(), gitRoot) {
|
|
|
445
445
|
});
|
|
446
446
|
watcher.unref();
|
|
447
447
|
watchers.push(watcher);
|
|
448
|
-
} catch (
|
|
448
|
+
} catch (_e) {
|
|
449
449
|
}
|
|
450
450
|
}
|
|
451
451
|
}
|
|
@@ -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;
|
|
@@ -799,22 +1006,22 @@ function getAnnotationDispatchErrorCode(error) {
|
|
|
799
1006
|
}
|
|
800
1007
|
|
|
801
1008
|
// src/server/client-config.ts
|
|
802
|
-
async function buildClientConfig(
|
|
803
|
-
const userConfig = loadUserConfigSync(false,
|
|
804
|
-
const promptsConfig = await loadPromptsConfig(false,
|
|
1009
|
+
async function buildClientConfig(serverState2) {
|
|
1010
|
+
const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
|
|
1011
|
+
const promptsConfig = await loadPromptsConfig(false, serverState2.cwd, serverState2.configRoot);
|
|
805
1012
|
const effectiveIde = userConfig.ide ?? "vscode";
|
|
806
1013
|
let info;
|
|
807
|
-
if (!
|
|
1014
|
+
if (!serverState2.ideInfo) {
|
|
808
1015
|
info = { ide: effectiveIde };
|
|
809
1016
|
} else {
|
|
810
|
-
const { scheme: _scheme, ...rest } =
|
|
1017
|
+
const { scheme: _scheme, ...rest } = serverState2.ideInfo;
|
|
811
1018
|
info = rest;
|
|
812
1019
|
}
|
|
813
1020
|
return {
|
|
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(serverState3) {
|
|
|
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
|
}
|
|
@@ -850,13 +1053,13 @@ var VSCODE_FAMILY_SCHEMES = [
|
|
|
850
1053
|
function normalizeIdeToken2(value) {
|
|
851
1054
|
return (value ?? "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
852
1055
|
}
|
|
853
|
-
function handleOpenFileRequest(body,
|
|
854
|
-
const absolutePath = resolveWorkspacePath(body.file,
|
|
855
|
-
assertPathWithinIdeOpenScope(absolutePath,
|
|
856
|
-
const userConfig = loadUserConfigSync(false,
|
|
1056
|
+
function handleOpenFileRequest(body, serverState2) {
|
|
1057
|
+
const absolutePath = resolveWorkspacePath(body.file, serverState2.cwd);
|
|
1058
|
+
assertPathWithinIdeOpenScope(absolutePath, serverState2.projectRoot);
|
|
1059
|
+
const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
|
|
857
1060
|
const configuredIde = userConfig.ide;
|
|
858
|
-
const activeIde =
|
|
859
|
-
const activeIdeScheme =
|
|
1061
|
+
const activeIde = serverState2.ideInfo?.ide;
|
|
1062
|
+
const activeIdeScheme = serverState2.ideInfo?.scheme;
|
|
860
1063
|
const configuredIdeMatchesActiveScheme = Boolean(configuredIde) && Boolean(activeIdeScheme) && normalizeIdeToken2(configuredIde) === normalizeIdeToken2(activeIdeScheme);
|
|
861
1064
|
const rawEditorHint = configuredIdeMatchesActiveScheme ? activeIdeScheme : configuredIde || activeIde || activeIdeScheme || "code";
|
|
862
1065
|
if (configuredIde && activeIdeScheme && normalizeIdeToken2(activeIdeScheme).includes(normalizeIdeToken2(configuredIde)) === false) {
|
|
@@ -870,7 +1073,7 @@ function handleOpenFileRequest(body, serverState3) {
|
|
|
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, serverState3) {
|
|
|
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, serverState3) {
|
|
|
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,
|
|
@@ -946,6 +1149,7 @@ function resolveProjectRoot() {
|
|
|
946
1149
|
|
|
947
1150
|
// src/server/index.ts
|
|
948
1151
|
var serverLogger4 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
1152
|
+
var PORT_FILE_NAME = "inspecto.port.json";
|
|
949
1153
|
var serverState = {
|
|
950
1154
|
port: null,
|
|
951
1155
|
running: false,
|
|
@@ -954,6 +1158,42 @@ var serverState = {
|
|
|
954
1158
|
cwd: process.cwd()
|
|
955
1159
|
};
|
|
956
1160
|
var serverInstance = null;
|
|
1161
|
+
function getPortFilePath() {
|
|
1162
|
+
return path6.join(os2.tmpdir(), PORT_FILE_NAME);
|
|
1163
|
+
}
|
|
1164
|
+
function getProjectRootHash() {
|
|
1165
|
+
if (!serverState.projectRoot) return null;
|
|
1166
|
+
return crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
1167
|
+
}
|
|
1168
|
+
function readPortData(portFile) {
|
|
1169
|
+
if (!fs5.existsSync(portFile)) return {};
|
|
1170
|
+
try {
|
|
1171
|
+
return JSON.parse(fs5.readFileSync(portFile, "utf-8"));
|
|
1172
|
+
} catch {
|
|
1173
|
+
return {};
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
function writeProjectPort(port) {
|
|
1177
|
+
const rootHash = getProjectRootHash();
|
|
1178
|
+
if (!rootHash) return;
|
|
1179
|
+
const portFile = getPortFilePath();
|
|
1180
|
+
const portData = readPortData(portFile);
|
|
1181
|
+
portData[rootHash] = port;
|
|
1182
|
+
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
1183
|
+
}
|
|
1184
|
+
function removeProjectPort() {
|
|
1185
|
+
const rootHash = getProjectRootHash();
|
|
1186
|
+
if (!rootHash) return;
|
|
1187
|
+
const portFile = getPortFilePath();
|
|
1188
|
+
if (!fs5.existsSync(portFile)) return;
|
|
1189
|
+
const portData = readPortData(portFile);
|
|
1190
|
+
delete portData[rootHash];
|
|
1191
|
+
if (Object.keys(portData).length === 0) {
|
|
1192
|
+
fs5.unlinkSync(portFile);
|
|
1193
|
+
} else {
|
|
1194
|
+
fs5.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
957
1197
|
async function startServer() {
|
|
958
1198
|
if (serverState.running && serverState.port !== null) {
|
|
959
1199
|
return serverState.port;
|
|
@@ -987,7 +1227,7 @@ async function startServer() {
|
|
|
987
1227
|
});
|
|
988
1228
|
});
|
|
989
1229
|
await new Promise((resolve2, reject) => {
|
|
990
|
-
serverInstance.listen(port, "
|
|
1230
|
+
serverInstance.listen(port, "0.0.0.0", () => {
|
|
991
1231
|
serverInstance.unref();
|
|
992
1232
|
resolve2();
|
|
993
1233
|
});
|
|
@@ -998,37 +1238,18 @@ async function startServer() {
|
|
|
998
1238
|
});
|
|
999
1239
|
serverState.port = port;
|
|
1000
1240
|
serverState.running = true;
|
|
1001
|
-
const portFile = path6.join(os2.tmpdir(), "inspecto.port.json");
|
|
1002
1241
|
try {
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
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");
|
|
1013
|
-
} catch (e) {
|
|
1014
|
-
serverLogger4.warn("Failed to write port file:", e);
|
|
1242
|
+
writeProjectPort(port);
|
|
1243
|
+
} catch (_e) {
|
|
1244
|
+
serverLogger4.warn("Failed to write port file:", _e);
|
|
1015
1245
|
}
|
|
1016
1246
|
process.once("exit", () => {
|
|
1017
1247
|
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
|
-
}
|
|
1248
|
+
removeProjectPort();
|
|
1028
1249
|
} catch {
|
|
1029
1250
|
}
|
|
1030
1251
|
});
|
|
1031
|
-
serverLogger4.info(`server running at http://
|
|
1252
|
+
serverLogger4.info(`server running at http://0.0.0.0:${port}`);
|
|
1032
1253
|
return port;
|
|
1033
1254
|
}
|
|
1034
1255
|
async function readBody(req) {
|
|
@@ -1080,11 +1301,11 @@ async function handleRequest(url, req, res) {
|
|
|
1080
1301
|
}
|
|
1081
1302
|
return;
|
|
1082
1303
|
}
|
|
1083
|
-
if (pathname === INSPECTO_API_PATHS.IDE_OPEN && req.method === "POST") {
|
|
1304
|
+
if ((pathname === INSPECTO_API_PATHS.SOURCE_OPEN || pathname === INSPECTO_API_PATHS.IDE_OPEN) && req.method === "POST") {
|
|
1084
1305
|
let body;
|
|
1085
1306
|
try {
|
|
1086
1307
|
body = JSON.parse(await readBody(req));
|
|
1087
|
-
} catch (
|
|
1308
|
+
} catch (_e) {
|
|
1088
1309
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1089
1310
|
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
1090
1311
|
return;
|
|
@@ -1093,7 +1314,7 @@ async function handleRequest(url, req, res) {
|
|
|
1093
1314
|
handleOpenFileRequest(body, serverState);
|
|
1094
1315
|
} catch (err) {
|
|
1095
1316
|
serverLogger4.warn(
|
|
1096
|
-
`Security: Blocked path traversal attempt in
|
|
1317
|
+
`Security: Blocked path traversal attempt in SOURCE_OPEN: ${body.file}. Reason: ${err.message}`
|
|
1097
1318
|
);
|
|
1098
1319
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1099
1320
|
res.end(JSON.stringify({ error: "Access denied: File is outside of project workspace" }));
|
|
@@ -1167,6 +1388,212 @@ async function handleRequest(url, req, res) {
|
|
|
1167
1388
|
}
|
|
1168
1389
|
return;
|
|
1169
1390
|
}
|
|
1391
|
+
if (pathname === INSPECTO_API_PATHS.SESSION_CLAIM_NEXT && req.method === "POST") {
|
|
1392
|
+
try {
|
|
1393
|
+
const rawBody = await readBody(req);
|
|
1394
|
+
const body = rawBody ? JSON.parse(rawBody) : {};
|
|
1395
|
+
const timeoutMs = normalizeSessionClaimTimeout(
|
|
1396
|
+
body.timeoutMs === void 0 ? null : String(body.timeoutMs)
|
|
1397
|
+
);
|
|
1398
|
+
const result = await annotationSessionStore.claimNextSession({
|
|
1399
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
1400
|
+
});
|
|
1401
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1402
|
+
res.end(
|
|
1403
|
+
JSON.stringify({
|
|
1404
|
+
success: true,
|
|
1405
|
+
timedOut: result.timedOut,
|
|
1406
|
+
matchedExisting: result.matchedExisting,
|
|
1407
|
+
...result.event ? { event: result.event } : {},
|
|
1408
|
+
...result.session ? { session: result.session } : {}
|
|
1409
|
+
})
|
|
1410
|
+
);
|
|
1411
|
+
} catch (e) {
|
|
1412
|
+
serverLogger4.error(`Error parsing session claim request:`, e);
|
|
1413
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1414
|
+
res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
|
|
1415
|
+
}
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1418
|
+
if (pathname === INSPECTO_API_PATHS.SESSION_EVENTS && req.method === "GET") {
|
|
1419
|
+
const statusParam = url.searchParams.getAll("status");
|
|
1420
|
+
const statuses = statusParam.length ? new Set(statusParam) : null;
|
|
1421
|
+
const sessionId = url.searchParams.get("sessionId")?.trim() || null;
|
|
1422
|
+
res.writeHead(200, {
|
|
1423
|
+
"Content-Type": "text/event-stream",
|
|
1424
|
+
"Cache-Control": "no-cache",
|
|
1425
|
+
Connection: "keep-alive"
|
|
1426
|
+
});
|
|
1427
|
+
res.write(`event: ready
|
|
1428
|
+
data: ${JSON.stringify({ ok: true })}
|
|
1429
|
+
|
|
1430
|
+
`);
|
|
1431
|
+
const unsubscribe = annotationSessionStore.subscribe((event) => {
|
|
1432
|
+
if (sessionId && event.session.id !== sessionId) {
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
if (statuses && !statuses.has(event.session.status)) {
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
res.write(formatSessionSseEvent(event));
|
|
1439
|
+
});
|
|
1440
|
+
req.on("close", () => {
|
|
1441
|
+
unsubscribe();
|
|
1442
|
+
res.end();
|
|
1443
|
+
});
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
if (pathname === INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
|
|
1447
|
+
const statusParam = url.searchParams.getAll("status");
|
|
1448
|
+
const sessions = annotationSessionStore.listSessions(
|
|
1449
|
+
statusParam.length ? {
|
|
1450
|
+
status: statusParam
|
|
1451
|
+
} : void 0
|
|
1452
|
+
);
|
|
1453
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1454
|
+
res.end(JSON.stringify({ success: true, sessions }));
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
if (pathname.startsWith(`${INSPECTO_API_PATHS.SESSIONS}/`) && req.method === "GET") {
|
|
1458
|
+
const sessionId = pathname.substring(INSPECTO_API_PATHS.SESSIONS.length + 1);
|
|
1459
|
+
const session = annotationSessionStore.getSession(sessionId);
|
|
1460
|
+
if (!session) {
|
|
1461
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1462
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1466
|
+
res.end(JSON.stringify({ success: true, session }));
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
if (pathname.startsWith(`${INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX) && req.method === "POST") {
|
|
1470
|
+
const sessionId = pathname.slice(
|
|
1471
|
+
INSPECTO_API_PATHS.SESSIONS.length + 1,
|
|
1472
|
+
-INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX.length
|
|
1473
|
+
);
|
|
1474
|
+
try {
|
|
1475
|
+
const rawBody = await readBody(req);
|
|
1476
|
+
const body = JSON.parse(rawBody);
|
|
1477
|
+
if (!isAnnotationThreadRole(body.role)) {
|
|
1478
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1479
|
+
res.end(JSON.stringify({ success: false, error: "Reply role is invalid." }));
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
if (!body.text?.trim()) {
|
|
1483
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1484
|
+
res.end(JSON.stringify({ success: false, error: "Reply text is required." }));
|
|
1485
|
+
return;
|
|
1486
|
+
}
|
|
1487
|
+
const session = annotationSessionStore.appendMessage(sessionId, {
|
|
1488
|
+
role: body.role,
|
|
1489
|
+
text: body.text.trim()
|
|
1490
|
+
});
|
|
1491
|
+
if (!session) {
|
|
1492
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1493
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1497
|
+
res.end(JSON.stringify({ success: true, session }));
|
|
1498
|
+
} catch (e) {
|
|
1499
|
+
serverLogger4.error(`Error parsing session reply request:`, e);
|
|
1500
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1501
|
+
res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
|
|
1502
|
+
}
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
if (pathname.startsWith(`${INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX) && req.method === "POST") {
|
|
1506
|
+
const sessionId = pathname.slice(
|
|
1507
|
+
INSPECTO_API_PATHS.SESSIONS.length + 1,
|
|
1508
|
+
-INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX.length
|
|
1509
|
+
);
|
|
1510
|
+
try {
|
|
1511
|
+
const rawBody = await readBody(req);
|
|
1512
|
+
const body = rawBody ? JSON.parse(rawBody) : {};
|
|
1513
|
+
const message = body.message?.trim();
|
|
1514
|
+
const existingSession = annotationSessionStore.getSession(sessionId);
|
|
1515
|
+
if (!existingSession) {
|
|
1516
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1517
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
if (!message && !hasAgentReply(existingSession)) {
|
|
1521
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1522
|
+
res.end(
|
|
1523
|
+
JSON.stringify({
|
|
1524
|
+
success: false,
|
|
1525
|
+
error: "Resolve message is required until an agent reply is recorded."
|
|
1526
|
+
})
|
|
1527
|
+
);
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
if (message) {
|
|
1531
|
+
const repliedSession = annotationSessionStore.appendMessage(sessionId, {
|
|
1532
|
+
role: "agent",
|
|
1533
|
+
text: message
|
|
1534
|
+
});
|
|
1535
|
+
if (!repliedSession) {
|
|
1536
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1537
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
const session = annotationSessionStore.updateStatus(sessionId, "resolved");
|
|
1542
|
+
if (!session) {
|
|
1543
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1544
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1548
|
+
res.end(JSON.stringify({ success: true, session }));
|
|
1549
|
+
} catch (e) {
|
|
1550
|
+
serverLogger4.error(`Error parsing session resolve request:`, e);
|
|
1551
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1552
|
+
res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
|
|
1553
|
+
}
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
if (pathname.startsWith(`${INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX) && req.method === "POST") {
|
|
1557
|
+
const sessionId = pathname.slice(
|
|
1558
|
+
INSPECTO_API_PATHS.SESSIONS.length + 1,
|
|
1559
|
+
-INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX.length
|
|
1560
|
+
);
|
|
1561
|
+
try {
|
|
1562
|
+
const rawBody = await readBody(req);
|
|
1563
|
+
const body = rawBody ? JSON.parse(rawBody) : {};
|
|
1564
|
+
const message = body.message?.trim();
|
|
1565
|
+
const existingSession = annotationSessionStore.getSession(sessionId);
|
|
1566
|
+
if (!existingSession) {
|
|
1567
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1568
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
if (message) {
|
|
1572
|
+
const repliedSession = annotationSessionStore.appendMessage(sessionId, {
|
|
1573
|
+
role: "agent",
|
|
1574
|
+
text: message
|
|
1575
|
+
});
|
|
1576
|
+
if (!repliedSession) {
|
|
1577
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1578
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
const session = annotationSessionStore.updateStatus(sessionId, "dismissed");
|
|
1583
|
+
if (!session) {
|
|
1584
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1585
|
+
res.end(JSON.stringify({ success: false, error: "Session not found" }));
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1589
|
+
res.end(JSON.stringify({ success: true, session }));
|
|
1590
|
+
} catch (e) {
|
|
1591
|
+
serverLogger4.error(`Error parsing session dismiss request:`, e);
|
|
1592
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1593
|
+
res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
|
|
1594
|
+
}
|
|
1595
|
+
return;
|
|
1596
|
+
}
|
|
1170
1597
|
if (pathname.startsWith(`${INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
|
|
1171
1598
|
const ticketId = pathname.substring(INSPECTO_API_PATHS.AI_TICKET.length + 1);
|
|
1172
1599
|
const payloadStr = readTicket(ticketId);
|
|
@@ -1183,7 +1610,7 @@ async function handleRequest(url, req, res) {
|
|
|
1183
1610
|
res.end(JSON.stringify({ error: "not found" }));
|
|
1184
1611
|
}
|
|
1185
1612
|
async function dispatchToAi(req) {
|
|
1186
|
-
const { location, snippet, prompt
|
|
1613
|
+
const { location, snippet, prompt } = req;
|
|
1187
1614
|
const formattedPrompt = prompt ?? `Please help me with this code from \`${location.file}\` (line ${location.line}):
|
|
1188
1615
|
|
|
1189
1616
|
\`\`\`
|
|
@@ -1196,8 +1623,7 @@ ${snippet}
|
|
|
1196
1623
|
filePath: location.file,
|
|
1197
1624
|
line: location.line,
|
|
1198
1625
|
column: location.column,
|
|
1199
|
-
snippet
|
|
1200
|
-
...screenshotContext ? { screenshotContext } : {}
|
|
1626
|
+
snippet
|
|
1201
1627
|
});
|
|
1202
1628
|
}
|
|
1203
1629
|
function getBatchDispatchStatusCode(errorCode, success) {
|
|
@@ -1206,6 +1632,21 @@ function getBatchDispatchStatusCode(errorCode, success) {
|
|
|
1206
1632
|
if (errorCode === "FORBIDDEN_PATH") return 403;
|
|
1207
1633
|
return 500;
|
|
1208
1634
|
}
|
|
1635
|
+
function isAnnotationThreadRole(value) {
|
|
1636
|
+
return value === "user" || value === "agent" || value === "system";
|
|
1637
|
+
}
|
|
1638
|
+
function formatSessionSseEvent(event) {
|
|
1639
|
+
return `event: ${event.type}
|
|
1640
|
+
data: ${JSON.stringify(event)}
|
|
1641
|
+
|
|
1642
|
+
`;
|
|
1643
|
+
}
|
|
1644
|
+
function normalizeSessionClaimTimeout(value) {
|
|
1645
|
+
if (!value?.trim()) return 3e4;
|
|
1646
|
+
const parsed = Number.parseInt(value, 10);
|
|
1647
|
+
if (!Number.isFinite(parsed)) return 3e4;
|
|
1648
|
+
return Math.max(0, Math.min(parsed, 3e5));
|
|
1649
|
+
}
|
|
1209
1650
|
|
|
1210
1651
|
// src/injectors/utils.ts
|
|
1211
1652
|
import { createRequire } from "module";
|
|
@@ -1228,13 +1669,13 @@ var resolveClientModule = () => {
|
|
|
1228
1669
|
function getWebpackHtmlScript(serverPort2) {
|
|
1229
1670
|
return `
|
|
1230
1671
|
window.__AI_INSPECTOR_PORT__ = ${serverPort2};
|
|
1231
|
-
window.addEventListener('load', () => {
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
});
|
|
1672
|
+
window.addEventListener('load', () => {
|
|
1673
|
+
if (window.InspectoClient) {
|
|
1674
|
+
window.InspectoClient.mountInspector({
|
|
1675
|
+
serverUrl: 'http://0.0.0.0:' + window.__AI_INSPECTOR_PORT__,
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
});
|
|
1238
1679
|
`;
|
|
1239
1680
|
}
|
|
1240
1681
|
|