@inspecto-dev/plugin 0.2.0-alpha.4 → 0.3.0
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 +1 -1
- package/dist/index.cjs +444 -203
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +443 -202
- package/dist/index.js.map +1 -1
- package/dist/legacy/rspack/index.cjs +446 -205
- package/dist/legacy/rspack/index.cjs.map +1 -1
- package/dist/legacy/rspack/index.js +445 -204
- package/dist/legacy/rspack/index.js.map +1 -1
- package/dist/legacy/webpack4/index.cjs +446 -205
- package/dist/legacy/webpack4/index.cjs.map +1 -1
- package/dist/legacy/webpack4/index.js +445 -204
- package/dist/legacy/webpack4/index.js.map +1 -1
- package/dist/rollup.cjs +444 -203
- package/dist/rollup.cjs.map +1 -1
- package/dist/rollup.js +443 -202
- package/dist/rollup.js.map +1 -1
- package/dist/rspack.cjs +444 -203
- package/dist/rspack.cjs.map +1 -1
- package/dist/rspack.js +443 -202
- package/dist/rspack.js.map +1 -1
- package/dist/vite.cjs +444 -203
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +443 -202
- package/dist/vite.js.map +1 -1
- package/dist/webpack.cjs +444 -203
- package/dist/webpack.cjs.map +1 -1
- package/dist/webpack.js +443 -202
- package/dist/webpack.js.map +1 -1
- package/package.json +2 -2
package/dist/vite.cjs
CHANGED
|
@@ -309,13 +309,11 @@ function transformRouter(options) {
|
|
|
309
309
|
|
|
310
310
|
// src/server/index.ts
|
|
311
311
|
var import_node_http = __toESM(require("http"), 1);
|
|
312
|
-
var
|
|
313
|
-
var
|
|
312
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
313
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
314
314
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
315
|
-
var
|
|
316
|
-
var import_node_child_process = require("child_process");
|
|
315
|
+
var import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
317
316
|
var import_portfinder = __toESM(require("portfinder"), 1);
|
|
318
|
-
var import_launch_ide = require("launch-ide");
|
|
319
317
|
var import_types2 = require("@inspecto-dev/types");
|
|
320
318
|
|
|
321
319
|
// src/server/snippet.ts
|
|
@@ -649,9 +647,9 @@ function extractToolOverrides(ide, config) {
|
|
|
649
647
|
function resolveIntents(serverPrompts) {
|
|
650
648
|
const baseMap = /* @__PURE__ */ new Map();
|
|
651
649
|
for (const intent of import_types.DEFAULT_INTENTS) {
|
|
652
|
-
|
|
650
|
+
baseMap.set(intent.id, { ...intent });
|
|
653
651
|
}
|
|
654
|
-
const defaults = () =>
|
|
652
|
+
const defaults = () => Array.from(baseMap.values());
|
|
655
653
|
if (!serverPrompts) return defaults();
|
|
656
654
|
const isReplace = !Array.isArray(serverPrompts) && typeof serverPrompts === "object" && serverPrompts.$replace === true;
|
|
657
655
|
const promptsArray = Array.isArray(serverPrompts) ? serverPrompts : isReplace ? serverPrompts.items : [];
|
|
@@ -678,16 +676,18 @@ function resolveIntents(serverPrompts) {
|
|
|
678
676
|
);
|
|
679
677
|
continue;
|
|
680
678
|
}
|
|
681
|
-
if (item.
|
|
679
|
+
if (!item.aiIntent) {
|
|
682
680
|
configLogger.warn(
|
|
683
|
-
`
|
|
681
|
+
`Intent "${item.id}" is missing required "aiIntent".`
|
|
684
682
|
);
|
|
685
683
|
continue;
|
|
686
684
|
}
|
|
687
|
-
result.push(
|
|
685
|
+
result.push(
|
|
686
|
+
baseMap.has(item.id) ? { ...baseMap.get(item.id), ...item } : item
|
|
687
|
+
);
|
|
688
688
|
}
|
|
689
689
|
}
|
|
690
|
-
return
|
|
690
|
+
return result;
|
|
691
691
|
}
|
|
692
692
|
const merged = Array.from(baseMap.values());
|
|
693
693
|
for (const item of promptsArray) {
|
|
@@ -704,9 +704,9 @@ function resolveIntents(serverPrompts) {
|
|
|
704
704
|
configLogger.warn('Intent object missing required "id" field, skipping.');
|
|
705
705
|
continue;
|
|
706
706
|
}
|
|
707
|
-
if (item.
|
|
707
|
+
if (!item.aiIntent) {
|
|
708
708
|
configLogger.warn(
|
|
709
|
-
`
|
|
709
|
+
`Intent "${item.id}" is missing required "aiIntent".`
|
|
710
710
|
);
|
|
711
711
|
continue;
|
|
712
712
|
}
|
|
@@ -724,15 +724,7 @@ function resolveIntents(serverPrompts) {
|
|
|
724
724
|
}
|
|
725
725
|
}
|
|
726
726
|
}
|
|
727
|
-
return
|
|
728
|
-
}
|
|
729
|
-
function ensureOpenInEditorLast(intents) {
|
|
730
|
-
const idx = intents.findIndex((i) => i.id === "open-in-editor");
|
|
731
|
-
if (idx === -1 || idx === intents.length - 1) return intents;
|
|
732
|
-
const result = [...intents];
|
|
733
|
-
const item = result.splice(idx, 1)[0];
|
|
734
|
-
result.push(item);
|
|
735
|
-
return result;
|
|
727
|
+
return merged;
|
|
736
728
|
}
|
|
737
729
|
var watchers = [];
|
|
738
730
|
function watchConfig(onReload, cwd = process.cwd(), gitRoot) {
|
|
@@ -767,7 +759,10 @@ function watchConfig(onReload, cwd = process.cwd(), gitRoot) {
|
|
|
767
759
|
}
|
|
768
760
|
}
|
|
769
761
|
|
|
770
|
-
// src/server/
|
|
762
|
+
// src/server/dispatch-transport.ts
|
|
763
|
+
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
764
|
+
var import_node_child_process = require("child_process");
|
|
765
|
+
var import_launch_ide = require("launch-ide");
|
|
771
766
|
var serverLogger = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
772
767
|
var payloadTickets = /* @__PURE__ */ new Map();
|
|
773
768
|
function createTicket(payload) {
|
|
@@ -781,21 +776,363 @@ function createTicket(payload) {
|
|
|
781
776
|
);
|
|
782
777
|
return ticketId;
|
|
783
778
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
779
|
+
function readTicket(ticketId) {
|
|
780
|
+
return payloadTickets.get(ticketId);
|
|
781
|
+
}
|
|
782
|
+
function launchURI(uri) {
|
|
783
|
+
try {
|
|
784
|
+
if (process.platform === "darwin") {
|
|
785
|
+
(0, import_node_child_process.execFileSync)("open", [uri]);
|
|
786
|
+
} else if (process.platform === "win32") {
|
|
787
|
+
(0, import_node_child_process.execFileSync)("cmd", ["/c", "start", '""', uri]);
|
|
788
|
+
} else {
|
|
789
|
+
(0, import_node_child_process.execFileSync)("xdg-open", [uri]);
|
|
790
|
+
}
|
|
791
|
+
} catch (e) {
|
|
792
|
+
serverLogger.error("Failed to launch URI via execFileSync, falling back to launchIDE:", e);
|
|
793
|
+
(0, import_launch_ide.launchIDE)({ file: uri });
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// src/server/dispatch-runtime.ts
|
|
798
|
+
function resolvePromptDispatchRuntime(state) {
|
|
799
|
+
const userConfig = loadUserConfigSync(false, state.cwd, state.projectRoot);
|
|
800
|
+
const resolvedTarget = resolveTargetTool(userConfig);
|
|
801
|
+
const finalIde = resolveFinalIde(userConfig.ide, state.ideInfo?.ide, state.ideInfo?.scheme);
|
|
802
|
+
const mode = resolveProviderMode(resolvedTarget, finalIde, userConfig);
|
|
803
|
+
const overrides = extractToolOverrides(finalIde, userConfig)[resolvedTarget] || void 0;
|
|
804
|
+
return {
|
|
805
|
+
resolvedTarget,
|
|
806
|
+
finalIde,
|
|
807
|
+
mode,
|
|
808
|
+
...hasOverrides(overrides) ? { overrides } : {},
|
|
809
|
+
...userConfig["prompt.autoSend"] !== void 0 ? { autoSend: Boolean(userConfig["prompt.autoSend"]) } : {}
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
function dispatchPromptThroughIde(runtime, payload) {
|
|
813
|
+
const ticketId = createTicket({
|
|
814
|
+
ide: runtime.finalIde,
|
|
815
|
+
target: runtime.resolvedTarget,
|
|
816
|
+
targetType: runtime.mode,
|
|
817
|
+
prompt: payload.prompt,
|
|
818
|
+
filePath: payload.filePath,
|
|
819
|
+
line: payload.line,
|
|
820
|
+
column: payload.column,
|
|
821
|
+
snippet: payload.snippet,
|
|
822
|
+
...payload.screenshotContext ? { screenshotContext: payload.screenshotContext } : {},
|
|
823
|
+
overrides: runtime.overrides,
|
|
824
|
+
autoSend: runtime.autoSend
|
|
825
|
+
});
|
|
826
|
+
const params = new URLSearchParams();
|
|
827
|
+
params.set("ticket", ticketId);
|
|
828
|
+
params.set("target", runtime.resolvedTarget);
|
|
829
|
+
launchURI(`${runtime.finalIde}://inspecto.inspecto/send?${params.toString()}`);
|
|
830
|
+
return {
|
|
831
|
+
success: true,
|
|
832
|
+
fallbackPayload: {
|
|
833
|
+
prompt: payload.prompt,
|
|
834
|
+
...payload.filePath ? { file: payload.filePath } : {}
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
function resolveFinalIde(configuredIde, activeIde, activeIdeScheme) {
|
|
839
|
+
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
840
|
+
return configuredIde;
|
|
841
|
+
}
|
|
842
|
+
return configuredIde || activeIdeScheme || activeIde || "vscode";
|
|
843
|
+
}
|
|
844
|
+
function hasOverrides(overrides) {
|
|
845
|
+
return Boolean(overrides && Object.keys(overrides).length > 0);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// src/server/path-guards.ts
|
|
849
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
850
|
+
function isWindowsAbsolutePath(file) {
|
|
851
|
+
return /^[a-zA-Z]:[\\/]/.test(file) || /^\\\\[^\\]+\\[^\\]+/.test(file);
|
|
852
|
+
}
|
|
853
|
+
function resolveWorkspacePath(file, cwd) {
|
|
854
|
+
if (isWindowsAbsolutePath(file)) {
|
|
855
|
+
return import_node_path5.default.win32.normalize(file);
|
|
856
|
+
}
|
|
857
|
+
return import_node_path5.default.isAbsolute(file) ? import_node_path5.default.resolve(file) : import_node_path5.default.resolve(cwd, file);
|
|
858
|
+
}
|
|
859
|
+
function assertPathWithinProject(file, projectRoot) {
|
|
860
|
+
const relativeToRoot = isWindowsAbsolutePath(file) || isWindowsAbsolutePath(projectRoot) ? import_node_path5.default.win32.relative(import_node_path5.default.win32.normalize(projectRoot), import_node_path5.default.win32.normalize(file)) : import_node_path5.default.relative(projectRoot, file);
|
|
861
|
+
if (relativeToRoot.startsWith("..") || import_node_path5.default.isAbsolute(relativeToRoot)) {
|
|
862
|
+
throw new Error("Access denied: File is outside of project workspace");
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// src/server/annotation-dispatch.ts
|
|
867
|
+
var AnnotationDispatchError = class extends Error {
|
|
868
|
+
constructor(message, errorCode) {
|
|
869
|
+
super(message);
|
|
870
|
+
this.name = "AnnotationDispatchError";
|
|
871
|
+
this.errorCode = errorCode;
|
|
872
|
+
}
|
|
790
873
|
};
|
|
791
|
-
|
|
874
|
+
async function dispatchAnnotationsToAi(req, state) {
|
|
875
|
+
try {
|
|
876
|
+
validateAnnotationDispatchRequest(req, state);
|
|
877
|
+
const batch = normalizeAnnotationBatch(req);
|
|
878
|
+
const prompt = buildAnnotationBatchPrompt(batch);
|
|
879
|
+
const representativeTarget = batch.annotations[0]?.targets[0];
|
|
880
|
+
const runtime = resolvePromptDispatchRuntime(state);
|
|
881
|
+
return dispatchPromptThroughIde(runtime, {
|
|
882
|
+
prompt,
|
|
883
|
+
...representativeTarget?.file ? { filePath: representativeTarget.file } : {},
|
|
884
|
+
...representativeTarget?.line ? { line: representativeTarget.line } : {},
|
|
885
|
+
...representativeTarget?.column ? { column: representativeTarget.column } : {},
|
|
886
|
+
...batch.screenshotContext ? { screenshotContext: batch.screenshotContext } : {}
|
|
887
|
+
});
|
|
888
|
+
} catch (error) {
|
|
889
|
+
return {
|
|
890
|
+
success: false,
|
|
891
|
+
error: error instanceof Error ? error.message : String(error),
|
|
892
|
+
errorCode: getAnnotationDispatchErrorCode(error)
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
function validateAnnotationDispatchRequest(req, state) {
|
|
897
|
+
if (!req.annotations.length) {
|
|
898
|
+
throw new AnnotationDispatchError("At least one annotation is required.", "INVALID_REQUEST");
|
|
899
|
+
}
|
|
900
|
+
for (const annotation of req.annotations) {
|
|
901
|
+
if (!annotation.targets.length) {
|
|
902
|
+
throw new AnnotationDispatchError(
|
|
903
|
+
"Each annotation must include at least one target.",
|
|
904
|
+
"INVALID_REQUEST"
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
for (const target of annotation.targets) {
|
|
908
|
+
const absolutePath = resolveWorkspacePath(target.location.file, state.cwd);
|
|
909
|
+
assertPathWithinProject(absolutePath, state.projectRoot);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
function normalizeAnnotationBatch(req) {
|
|
914
|
+
return {
|
|
915
|
+
instruction: req.instruction?.trim() ?? "",
|
|
916
|
+
responseMode: req.responseMode ?? "unified",
|
|
917
|
+
...req.runtimeContext ? { runtimeContext: req.runtimeContext } : {},
|
|
918
|
+
...req.screenshotContext ? { screenshotContext: req.screenshotContext } : {},
|
|
919
|
+
...req.cssContextPrompt?.trim() ? { cssContextPrompt: req.cssContextPrompt.trim() } : {},
|
|
920
|
+
annotations: req.annotations.map((annotation, index) => ({
|
|
921
|
+
index: index + 1,
|
|
922
|
+
note: annotation.note.trim(),
|
|
923
|
+
intent: annotation.intent,
|
|
924
|
+
targets: annotation.targets.map((target) => ({
|
|
925
|
+
file: target.location.file,
|
|
926
|
+
line: target.location.line,
|
|
927
|
+
column: target.location.column,
|
|
928
|
+
...target.label ? { label: target.label } : {},
|
|
929
|
+
...target.selector ? { selector: target.selector } : {},
|
|
930
|
+
...target.snippet ? { snippet: target.snippet } : {}
|
|
931
|
+
}))
|
|
932
|
+
}))
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
function buildAnnotationBatchPrompt(batch) {
|
|
936
|
+
const body = buildSelectedElementsPrompt(batch.annotations);
|
|
937
|
+
const prompt = batch.instruction ? `${batch.instruction}
|
|
938
|
+
|
|
939
|
+
${body}` : body;
|
|
940
|
+
return appendScreenshotContextSection(
|
|
941
|
+
appendCssContextSection(
|
|
942
|
+
appendRuntimeContextSection(prompt, batch.runtimeContext),
|
|
943
|
+
batch.cssContextPrompt
|
|
944
|
+
),
|
|
945
|
+
batch.screenshotContext
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
function appendCssContextSection(prompt, cssContextPrompt) {
|
|
949
|
+
if (!cssContextPrompt) return prompt;
|
|
950
|
+
return `${prompt}
|
|
951
|
+
|
|
952
|
+
${cssContextPrompt}`;
|
|
953
|
+
}
|
|
954
|
+
function buildSelectedElementsPrompt(annotations) {
|
|
955
|
+
const lines = ["Selected elements:"];
|
|
956
|
+
for (const annotation of annotations) {
|
|
957
|
+
const trimmedNote = annotation.note.trim();
|
|
958
|
+
for (const target of annotation.targets) {
|
|
959
|
+
const targetLabel = (target.label || "Unknown target").trim() || "Unknown target";
|
|
960
|
+
lines.push(`- ${targetLabel}`);
|
|
961
|
+
lines.push(`file=${target.file}:${target.line}:${target.column}`);
|
|
962
|
+
if (trimmedNote) {
|
|
963
|
+
lines.push(`note=${trimmedNote}`);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
if (lines.length === 1) {
|
|
968
|
+
lines.push("- None");
|
|
969
|
+
}
|
|
970
|
+
return lines.join("\n");
|
|
971
|
+
}
|
|
972
|
+
function appendScreenshotContextSection(prompt, screenshotContext) {
|
|
973
|
+
if (!screenshotContext || !screenshotContext.imageDataUrl && !screenshotContext.imageAssetId) {
|
|
974
|
+
return prompt;
|
|
975
|
+
}
|
|
976
|
+
const lines = [
|
|
977
|
+
"Visual screenshot context attached:",
|
|
978
|
+
`- capturedAt=${screenshotContext.capturedAt}`,
|
|
979
|
+
`- mimeType=${screenshotContext.mimeType}`,
|
|
980
|
+
...screenshotContext.imageAssetId ? [`- imageAssetId=${screenshotContext.imageAssetId}`] : []
|
|
981
|
+
];
|
|
982
|
+
return `${prompt}
|
|
983
|
+
|
|
984
|
+
${lines.join("\n")}`;
|
|
985
|
+
}
|
|
986
|
+
function appendRuntimeContextSection(prompt, runtimeContext) {
|
|
987
|
+
if (!runtimeContext?.records.length) {
|
|
988
|
+
return prompt;
|
|
989
|
+
}
|
|
990
|
+
return `${prompt}
|
|
991
|
+
|
|
992
|
+
${buildRuntimeContextSection(runtimeContext.records)}`;
|
|
993
|
+
}
|
|
994
|
+
function buildRuntimeContextSection(records) {
|
|
995
|
+
return ["Relevant runtime context:", ...records.map(formatRuntimeRecord)].join("\n");
|
|
996
|
+
}
|
|
997
|
+
function formatRuntimeRecord(record) {
|
|
998
|
+
const requestSummary = record.kind === "failed-request" ? `request=${record.request?.method ?? "GET"} ${record.request?.pathname ?? record.request?.url ?? "unknown"} status=${record.request?.status ?? "unknown"}` : `occurrences=${record.occurrenceCount}`;
|
|
999
|
+
const reasonSummary = record.relevanceReasons.length ? record.relevanceReasons.join("; ") : "timing-based";
|
|
1000
|
+
const stackSummary = record.stack ? `
|
|
1001
|
+
stack=${record.stack.split("\n").slice(0, 5).join(" | ")}` : "";
|
|
1002
|
+
return [
|
|
1003
|
+
`- [${record.kind}] ${record.message}`,
|
|
1004
|
+
` relevance=${record.relevanceLevel} (${reasonSummary})`,
|
|
1005
|
+
` ${requestSummary}`,
|
|
1006
|
+
stackSummary
|
|
1007
|
+
].filter(Boolean).join("\n");
|
|
1008
|
+
}
|
|
1009
|
+
function getAnnotationDispatchErrorCode(error) {
|
|
1010
|
+
if (error instanceof AnnotationDispatchError) return error.errorCode;
|
|
1011
|
+
if (error instanceof Error && error.message.includes("outside of project workspace")) {
|
|
1012
|
+
return "FORBIDDEN_PATH";
|
|
1013
|
+
}
|
|
1014
|
+
return "UNKNOWN";
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// src/server/client-config.ts
|
|
1018
|
+
async function buildClientConfig(serverState2) {
|
|
1019
|
+
const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
|
|
1020
|
+
const promptsConfig = await loadPromptsConfig(false, serverState2.cwd, serverState2.configRoot);
|
|
1021
|
+
const effectiveIde = userConfig.ide ?? "vscode";
|
|
1022
|
+
let info;
|
|
1023
|
+
if (!serverState2.ideInfo) {
|
|
1024
|
+
info = { ide: effectiveIde };
|
|
1025
|
+
} else {
|
|
1026
|
+
const { scheme: _scheme, ...rest } = serverState2.ideInfo;
|
|
1027
|
+
info = rest;
|
|
1028
|
+
}
|
|
1029
|
+
return {
|
|
1030
|
+
...info,
|
|
1031
|
+
prompts: resolveIntents(promptsConfig),
|
|
1032
|
+
hotKeys: userConfig["inspector.hotKey"] ?? "alt",
|
|
1033
|
+
theme: userConfig["inspector.theme"] ?? "auto",
|
|
1034
|
+
includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
|
|
1035
|
+
runtimeContext: {
|
|
1036
|
+
enabled: true,
|
|
1037
|
+
preview: true,
|
|
1038
|
+
maxRuntimeErrors: 3,
|
|
1039
|
+
maxFailedRequests: 2
|
|
1040
|
+
},
|
|
1041
|
+
screenshotContext: {
|
|
1042
|
+
enabled: false
|
|
1043
|
+
},
|
|
1044
|
+
annotationResponseMode: userConfig["prompt.annotationResponseMode"] ?? "unified",
|
|
1045
|
+
autoSend: userConfig["prompt.autoSend"] ?? false
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// src/server/open-file.ts
|
|
1050
|
+
var import_node_child_process2 = require("child_process");
|
|
1051
|
+
var import_launch_ide2 = require("launch-ide");
|
|
1052
|
+
var serverLogger2 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
1053
|
+
var VSCODE_FAMILY_SCHEMES = [
|
|
1054
|
+
"vscode",
|
|
1055
|
+
"vscode-insiders",
|
|
1056
|
+
"cursor",
|
|
1057
|
+
"windsurf",
|
|
1058
|
+
"trae",
|
|
1059
|
+
"trae-cn",
|
|
1060
|
+
"vscodium",
|
|
1061
|
+
"codebuddy",
|
|
1062
|
+
"codebuddy-cn",
|
|
1063
|
+
"antigravity"
|
|
1064
|
+
];
|
|
1065
|
+
function handleOpenFileRequest(body, serverState2) {
|
|
1066
|
+
const absolutePath = resolveWorkspacePath(body.file, serverState2.cwd);
|
|
1067
|
+
assertPathWithinProject(absolutePath, serverState2.projectRoot);
|
|
1068
|
+
const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
|
|
1069
|
+
const configuredIde = userConfig.ide;
|
|
1070
|
+
const activeIde = serverState2.ideInfo?.ide;
|
|
1071
|
+
const activeIdeScheme = serverState2.ideInfo?.scheme;
|
|
1072
|
+
const rawEditorHint = configuredIde || activeIde || activeIdeScheme || "code";
|
|
1073
|
+
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
1074
|
+
serverLogger2.warn(
|
|
1075
|
+
`Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
let editorHint = rawEditorHint;
|
|
1079
|
+
if (rawEditorHint === "vscode") editorHint = "code";
|
|
1080
|
+
else if (rawEditorHint === "vscode-insiders") editorHint = "code-insiders";
|
|
1081
|
+
else if (rawEditorHint === "vscodium") editorHint = "codium";
|
|
1082
|
+
else if (rawEditorHint === "trae-cn" || rawEditorHint === "trae") editorHint = "trae";
|
|
1083
|
+
serverLogger2.debug(
|
|
1084
|
+
`IDE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`
|
|
1085
|
+
);
|
|
1086
|
+
if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {
|
|
1087
|
+
let normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
1088
|
+
if (!normalizedPath.startsWith("/")) {
|
|
1089
|
+
normalizedPath = "/" + normalizedPath;
|
|
1090
|
+
}
|
|
1091
|
+
const encodedPath = encodeURI(normalizedPath);
|
|
1092
|
+
const uri = `${rawEditorHint}://file${encodedPath}:${body.line}:${body.column}`;
|
|
1093
|
+
serverLogger2.debug(`IDE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
|
|
1094
|
+
try {
|
|
1095
|
+
if (process.platform === "darwin") {
|
|
1096
|
+
(0, import_node_child_process2.execFileSync)("open", [uri]);
|
|
1097
|
+
} else if (process.platform === "win32") {
|
|
1098
|
+
(0, import_node_child_process2.execFileSync)("cmd", ["/c", "start", '""', uri]);
|
|
1099
|
+
} else {
|
|
1100
|
+
(0, import_node_child_process2.execFileSync)("xdg-open", [uri]);
|
|
1101
|
+
}
|
|
1102
|
+
} catch (e) {
|
|
1103
|
+
serverLogger2.error(`Failed to launch URI for IDE_OPEN (${uri}):`, e);
|
|
1104
|
+
(0, import_launch_ide2.launchIDE)({
|
|
1105
|
+
file: absolutePath,
|
|
1106
|
+
line: body.line,
|
|
1107
|
+
column: body.column,
|
|
1108
|
+
editor: editorHint,
|
|
1109
|
+
type: process.platform === "darwin" ? "open" : "exec"
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
} else {
|
|
1113
|
+
(0, import_launch_ide2.launchIDE)({
|
|
1114
|
+
file: absolutePath,
|
|
1115
|
+
line: body.line,
|
|
1116
|
+
column: body.column,
|
|
1117
|
+
editor: editorHint,
|
|
1118
|
+
type: process.platform === "darwin" ? "open" : "exec"
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
return { success: true };
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// src/server/project-root.ts
|
|
1125
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
1126
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
1127
|
+
var import_node_child_process3 = require("child_process");
|
|
1128
|
+
var serverLogger3 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
792
1129
|
function resolveProjectRoot() {
|
|
793
1130
|
const cwd = process.cwd();
|
|
794
1131
|
let gitRoot;
|
|
795
1132
|
try {
|
|
796
|
-
gitRoot = (0,
|
|
1133
|
+
gitRoot = (0, import_node_child_process3.execSync)("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
797
1134
|
} catch (e) {
|
|
798
|
-
|
|
1135
|
+
serverLogger3.warn("Failed to resolve git root via git rev-parse:", e);
|
|
799
1136
|
gitRoot = cwd;
|
|
800
1137
|
}
|
|
801
1138
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -803,34 +1140,31 @@ function resolveProjectRoot() {
|
|
|
803
1140
|
let current = start;
|
|
804
1141
|
while (!visited.has(current)) {
|
|
805
1142
|
visited.add(current);
|
|
806
|
-
if (import_node_fs2.default.existsSync(
|
|
1143
|
+
if (import_node_fs2.default.existsSync(import_node_path6.default.join(current, ".inspecto"))) return current;
|
|
807
1144
|
if (current === stop) break;
|
|
808
|
-
const parent =
|
|
1145
|
+
const parent = import_node_path6.default.dirname(current);
|
|
809
1146
|
if (parent === current) break;
|
|
810
1147
|
current = parent;
|
|
811
1148
|
}
|
|
812
1149
|
return null;
|
|
813
1150
|
};
|
|
814
|
-
const cwdMatch = search(cwd,
|
|
1151
|
+
const cwdMatch = search(cwd, import_node_path6.default.parse(cwd).root);
|
|
815
1152
|
if (cwdMatch) return cwdMatch;
|
|
816
|
-
const repoMatch = search(gitRoot,
|
|
1153
|
+
const repoMatch = search(gitRoot, import_node_path6.default.parse(gitRoot).root);
|
|
817
1154
|
if (repoMatch) return repoMatch;
|
|
818
1155
|
return gitRoot;
|
|
819
1156
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
(0, import_launch_ide.launchIDE)({ file: uri });
|
|
832
|
-
}
|
|
833
|
-
}
|
|
1157
|
+
|
|
1158
|
+
// src/server/index.ts
|
|
1159
|
+
var serverLogger4 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
1160
|
+
var serverState = {
|
|
1161
|
+
port: null,
|
|
1162
|
+
running: false,
|
|
1163
|
+
projectRoot: "",
|
|
1164
|
+
configRoot: "",
|
|
1165
|
+
cwd: process.cwd()
|
|
1166
|
+
};
|
|
1167
|
+
var serverInstance = null;
|
|
834
1168
|
async function startServer() {
|
|
835
1169
|
if (serverState.running && serverState.port !== null) {
|
|
836
1170
|
return serverState.port;
|
|
@@ -842,7 +1176,7 @@ async function startServer() {
|
|
|
842
1176
|
const port = await import_portfinder.default.getPortPromise();
|
|
843
1177
|
watchConfig(
|
|
844
1178
|
() => {
|
|
845
|
-
|
|
1179
|
+
serverLogger4.info("user config reloaded.");
|
|
846
1180
|
},
|
|
847
1181
|
serverState.cwd,
|
|
848
1182
|
serverState.configRoot
|
|
@@ -858,7 +1192,7 @@ async function startServer() {
|
|
|
858
1192
|
}
|
|
859
1193
|
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
860
1194
|
handleRequest(url, req, res).catch((err) => {
|
|
861
|
-
|
|
1195
|
+
serverLogger4.error("server error:", err);
|
|
862
1196
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
863
1197
|
res.end(JSON.stringify({ success: false, error: String(err) }));
|
|
864
1198
|
});
|
|
@@ -871,41 +1205,41 @@ async function startServer() {
|
|
|
871
1205
|
serverInstance.once("error", reject);
|
|
872
1206
|
});
|
|
873
1207
|
serverInstance.on("error", (err) => {
|
|
874
|
-
|
|
1208
|
+
serverLogger4.error("persistent server error:", err);
|
|
875
1209
|
});
|
|
876
1210
|
serverState.port = port;
|
|
877
1211
|
serverState.running = true;
|
|
878
|
-
const portFile =
|
|
1212
|
+
const portFile = import_node_path7.default.join(import_node_os2.default.tmpdir(), "inspecto.port.json");
|
|
879
1213
|
try {
|
|
880
1214
|
let portData = {};
|
|
881
|
-
if (
|
|
1215
|
+
if (import_node_fs3.default.existsSync(portFile)) {
|
|
882
1216
|
try {
|
|
883
|
-
portData = JSON.parse(
|
|
1217
|
+
portData = JSON.parse(import_node_fs3.default.readFileSync(portFile, "utf-8"));
|
|
884
1218
|
} catch (e) {
|
|
885
1219
|
}
|
|
886
1220
|
}
|
|
887
|
-
const rootHash =
|
|
1221
|
+
const rootHash = import_node_crypto2.default.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
888
1222
|
portData[rootHash] = port;
|
|
889
|
-
|
|
1223
|
+
import_node_fs3.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
890
1224
|
} catch (e) {
|
|
891
|
-
|
|
1225
|
+
serverLogger4.warn("Failed to write port file:", e);
|
|
892
1226
|
}
|
|
893
1227
|
process.once("exit", () => {
|
|
894
1228
|
try {
|
|
895
|
-
if (
|
|
896
|
-
const portData = JSON.parse(
|
|
897
|
-
const rootHash =
|
|
1229
|
+
if (import_node_fs3.default.existsSync(portFile)) {
|
|
1230
|
+
const portData = JSON.parse(import_node_fs3.default.readFileSync(portFile, "utf-8"));
|
|
1231
|
+
const rootHash = import_node_crypto2.default.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
898
1232
|
delete portData[rootHash];
|
|
899
1233
|
if (Object.keys(portData).length === 0) {
|
|
900
|
-
|
|
1234
|
+
import_node_fs3.default.unlinkSync(portFile);
|
|
901
1235
|
} else {
|
|
902
|
-
|
|
1236
|
+
import_node_fs3.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
903
1237
|
}
|
|
904
1238
|
}
|
|
905
1239
|
} catch {
|
|
906
1240
|
}
|
|
907
1241
|
});
|
|
908
|
-
|
|
1242
|
+
serverLogger4.info(`server running at http://127.0.0.1:${port}`);
|
|
909
1243
|
return port;
|
|
910
1244
|
}
|
|
911
1245
|
async function readBody(req) {
|
|
@@ -924,26 +1258,7 @@ async function handleRequest(url, req, res) {
|
|
|
924
1258
|
return;
|
|
925
1259
|
}
|
|
926
1260
|
if (pathname === import_types2.INSPECTO_API_PATHS.CLIENT_CONFIG && req.method === "GET") {
|
|
927
|
-
const
|
|
928
|
-
const promptsConfig = await loadPromptsConfig(false, serverState.cwd, serverState.configRoot);
|
|
929
|
-
const effectiveIde = userConfig.ide ?? "vscode";
|
|
930
|
-
let info;
|
|
931
|
-
if (!serverState.ideInfo) {
|
|
932
|
-
info = {
|
|
933
|
-
ide: effectiveIde
|
|
934
|
-
};
|
|
935
|
-
} else {
|
|
936
|
-
const { scheme: _scheme, ...rest } = serverState.ideInfo;
|
|
937
|
-
info = rest;
|
|
938
|
-
}
|
|
939
|
-
const config = {
|
|
940
|
-
...info,
|
|
941
|
-
prompts: resolveIntents(promptsConfig),
|
|
942
|
-
hotKeys: userConfig["inspector.hotKey"] ?? "alt",
|
|
943
|
-
theme: userConfig["inspector.theme"] ?? "auto",
|
|
944
|
-
includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
|
|
945
|
-
autoSend: userConfig["prompt.autoSend"] ?? false
|
|
946
|
-
};
|
|
1261
|
+
const config = await buildClientConfig(serverState);
|
|
947
1262
|
delete config.providers;
|
|
948
1263
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
949
1264
|
res.end(JSON.stringify(config));
|
|
@@ -954,23 +1269,23 @@ async function handleRequest(url, req, res) {
|
|
|
954
1269
|
const body = JSON.parse(await readBody(req));
|
|
955
1270
|
const ideWorkspace = body.workspaceRoot || "";
|
|
956
1271
|
const serverProjectRoot = serverState.projectRoot || "";
|
|
957
|
-
const normalizedIdeRoot = ideWorkspace ?
|
|
958
|
-
const normalizedServerRoot = serverProjectRoot ?
|
|
959
|
-
const isSameProject = !normalizedIdeRoot || !normalizedServerRoot || normalizedIdeRoot === normalizedServerRoot || normalizedServerRoot.startsWith(normalizedIdeRoot +
|
|
1272
|
+
const normalizedIdeRoot = ideWorkspace ? import_node_path7.default.resolve(ideWorkspace) : "";
|
|
1273
|
+
const normalizedServerRoot = serverProjectRoot ? import_node_path7.default.resolve(serverProjectRoot) : "";
|
|
1274
|
+
const isSameProject = !normalizedIdeRoot || !normalizedServerRoot || normalizedIdeRoot === normalizedServerRoot || normalizedServerRoot.startsWith(normalizedIdeRoot + import_node_path7.default.sep) || normalizedIdeRoot.startsWith(normalizedServerRoot + import_node_path7.default.sep);
|
|
960
1275
|
if (isSameProject) {
|
|
961
1276
|
serverState.ideInfo = body;
|
|
962
|
-
|
|
1277
|
+
serverLogger4.debug(
|
|
963
1278
|
`Accepted IDE info from matched workspace (ide-${body.ide} / schema-${body.scheme})`
|
|
964
1279
|
);
|
|
965
1280
|
} else {
|
|
966
|
-
|
|
1281
|
+
serverLogger4.debug(
|
|
967
1282
|
`Ignored IDE info from unrelated workspace (IDE Workspace: ${ideWorkspace}, Server: ${serverProjectRoot}, Scheme: ${body.scheme}, IDE: ${body.ide})`
|
|
968
1283
|
);
|
|
969
1284
|
}
|
|
970
1285
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
971
1286
|
res.end(JSON.stringify({ success: true }));
|
|
972
1287
|
} catch (e) {
|
|
973
|
-
|
|
1288
|
+
serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.IDE_INFO} POST request:`, e);
|
|
974
1289
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
975
1290
|
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
976
1291
|
}
|
|
@@ -985,79 +1300,14 @@ async function handleRequest(url, req, res) {
|
|
|
985
1300
|
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
986
1301
|
return;
|
|
987
1302
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1303
|
+
try {
|
|
1304
|
+
handleOpenFileRequest(body, serverState);
|
|
1305
|
+
} catch {
|
|
1306
|
+
serverLogger4.warn(`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}`);
|
|
992
1307
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
993
1308
|
res.end(JSON.stringify({ error: "Access denied: File is outside of project workspace" }));
|
|
994
1309
|
return;
|
|
995
1310
|
}
|
|
996
|
-
const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot);
|
|
997
|
-
const configuredIde = userConfig.ide;
|
|
998
|
-
const activeIde = serverState.ideInfo?.ide;
|
|
999
|
-
const activeIdeScheme = serverState.ideInfo?.scheme;
|
|
1000
|
-
const rawEditorHint = configuredIde || activeIde || activeIdeScheme || "code";
|
|
1001
|
-
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
1002
|
-
serverLogger.warn(
|
|
1003
|
-
`Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`
|
|
1004
|
-
);
|
|
1005
|
-
}
|
|
1006
|
-
let editorHint = rawEditorHint;
|
|
1007
|
-
if (rawEditorHint === "vscode") editorHint = "code";
|
|
1008
|
-
else if (rawEditorHint === "vscode-insiders") editorHint = "code-insiders";
|
|
1009
|
-
else if (rawEditorHint === "vscodium") editorHint = "codium";
|
|
1010
|
-
else if (rawEditorHint === "trae-cn" || rawEditorHint === "trae") editorHint = "trae";
|
|
1011
|
-
serverLogger.debug(
|
|
1012
|
-
`IDE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`
|
|
1013
|
-
);
|
|
1014
|
-
const VSCODE_FAMILY_SCHEMES = [
|
|
1015
|
-
"vscode",
|
|
1016
|
-
"vscode-insiders",
|
|
1017
|
-
"cursor",
|
|
1018
|
-
"windsurf",
|
|
1019
|
-
"trae",
|
|
1020
|
-
"trae-cn",
|
|
1021
|
-
"vscodium",
|
|
1022
|
-
"codebuddy",
|
|
1023
|
-
"codebuddy-cn",
|
|
1024
|
-
"antigravity"
|
|
1025
|
-
];
|
|
1026
|
-
if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {
|
|
1027
|
-
let normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
1028
|
-
if (!normalizedPath.startsWith("/")) {
|
|
1029
|
-
normalizedPath = "/" + normalizedPath;
|
|
1030
|
-
}
|
|
1031
|
-
const encodedPath = encodeURI(normalizedPath);
|
|
1032
|
-
const uri = `${rawEditorHint}://file${encodedPath}:${body.line}:${body.column}`;
|
|
1033
|
-
serverLogger.debug(`IDE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
|
|
1034
|
-
try {
|
|
1035
|
-
if (process.platform === "darwin") {
|
|
1036
|
-
(0, import_node_child_process.execFileSync)("open", [uri]);
|
|
1037
|
-
} else if (process.platform === "win32") {
|
|
1038
|
-
(0, import_node_child_process.execFileSync)("cmd", ["/c", "start", '""', uri]);
|
|
1039
|
-
} else {
|
|
1040
|
-
(0, import_node_child_process.execFileSync)("xdg-open", [uri]);
|
|
1041
|
-
}
|
|
1042
|
-
} catch (e) {
|
|
1043
|
-
serverLogger.error(`Failed to launch URI for IDE_OPEN (${uri}):`, e);
|
|
1044
|
-
(0, import_launch_ide.launchIDE)({
|
|
1045
|
-
file: absolutePath,
|
|
1046
|
-
line: body.line,
|
|
1047
|
-
column: body.column,
|
|
1048
|
-
editor: editorHint,
|
|
1049
|
-
type: process.platform === "darwin" ? "open" : "exec"
|
|
1050
|
-
});
|
|
1051
|
-
}
|
|
1052
|
-
} else {
|
|
1053
|
-
(0, import_launch_ide.launchIDE)({
|
|
1054
|
-
file: absolutePath,
|
|
1055
|
-
line: body.line,
|
|
1056
|
-
column: body.column,
|
|
1057
|
-
editor: editorHint,
|
|
1058
|
-
type: process.platform === "darwin" ? "open" : "exec"
|
|
1059
|
-
});
|
|
1060
|
-
}
|
|
1061
1311
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1062
1312
|
res.end(JSON.stringify({ success: true }));
|
|
1063
1313
|
return;
|
|
@@ -1068,10 +1318,11 @@ async function handleRequest(url, req, res) {
|
|
|
1068
1318
|
const column = parseInt(url.searchParams.get("column") ?? "1", 10);
|
|
1069
1319
|
const maxLines = parseInt(url.searchParams.get("maxLines") ?? "100", 10);
|
|
1070
1320
|
try {
|
|
1071
|
-
const absolutePath =
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1321
|
+
const absolutePath = resolveWorkspacePath(file, serverState.cwd);
|
|
1322
|
+
try {
|
|
1323
|
+
assertPathWithinProject(absolutePath, serverState.projectRoot);
|
|
1324
|
+
} catch {
|
|
1325
|
+
serverLogger4.warn(`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}`);
|
|
1075
1326
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1076
1327
|
res.end(
|
|
1077
1328
|
JSON.stringify({
|
|
@@ -1101,7 +1352,23 @@ async function handleRequest(url, req, res) {
|
|
|
1101
1352
|
res.writeHead(result.success ? 200 : 500, { "Content-Type": "application/json" });
|
|
1102
1353
|
res.end(JSON.stringify(result));
|
|
1103
1354
|
} catch (e) {
|
|
1104
|
-
|
|
1355
|
+
serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.AI_DISPATCH} request:`, e);
|
|
1356
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1357
|
+
res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
|
|
1358
|
+
}
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
if (pathname === import_types2.INSPECTO_API_PATHS.AI_BATCH_DISPATCH && req.method === "POST") {
|
|
1362
|
+
try {
|
|
1363
|
+
const rawBody = await readBody(req);
|
|
1364
|
+
const body = JSON.parse(rawBody);
|
|
1365
|
+
const result = await dispatchAnnotationsToAi(body, serverState);
|
|
1366
|
+
res.writeHead(getBatchDispatchStatusCode(result.errorCode, result.success), {
|
|
1367
|
+
"Content-Type": "application/json"
|
|
1368
|
+
});
|
|
1369
|
+
res.end(JSON.stringify(result));
|
|
1370
|
+
} catch (e) {
|
|
1371
|
+
serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.AI_BATCH_DISPATCH} request:`, e);
|
|
1105
1372
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1106
1373
|
res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
|
|
1107
1374
|
}
|
|
@@ -1109,7 +1376,7 @@ async function handleRequest(url, req, res) {
|
|
|
1109
1376
|
}
|
|
1110
1377
|
if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
|
|
1111
1378
|
const ticketId = pathname.substring(import_types2.INSPECTO_API_PATHS.AI_TICKET.length + 1);
|
|
1112
|
-
const payloadStr =
|
|
1379
|
+
const payloadStr = readTicket(ticketId);
|
|
1113
1380
|
if (!payloadStr) {
|
|
1114
1381
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1115
1382
|
res.end(JSON.stringify({ success: false, error: "Ticket not found or expired" }));
|
|
@@ -1123,54 +1390,28 @@ async function handleRequest(url, req, res) {
|
|
|
1123
1390
|
res.end(JSON.stringify({ error: "not found" }));
|
|
1124
1391
|
}
|
|
1125
1392
|
async function dispatchToAi(req) {
|
|
1126
|
-
const { location, snippet, prompt } = req;
|
|
1127
|
-
const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot);
|
|
1128
|
-
const resolvedTarget = resolveTargetTool(userConfig);
|
|
1393
|
+
const { location, snippet, prompt, screenshotContext } = req;
|
|
1129
1394
|
const formattedPrompt = prompt ?? `Please help me with this code from \`${location.file}\` (line ${location.line}):
|
|
1130
1395
|
|
|
1131
1396
|
\`\`\`
|
|
1132
1397
|
${snippet}
|
|
1133
1398
|
\`\`\`
|
|
1134
1399
|
`;
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
const activeIde = serverState.ideInfo?.ide;
|
|
1138
|
-
const activeIdeScheme = serverState.ideInfo?.scheme;
|
|
1139
|
-
const finalIde = configuredIde || activeIdeScheme || activeIde || "vscode";
|
|
1140
|
-
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
1141
|
-
serverLogger.warn(
|
|
1142
|
-
`dispatchToAi: Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`
|
|
1143
|
-
);
|
|
1144
|
-
}
|
|
1145
|
-
const mode = resolveProviderMode(resolvedTarget, finalIde, userConfig);
|
|
1146
|
-
const overrides = extractToolOverrides(finalIde, userConfig)[resolvedTarget] || {};
|
|
1147
|
-
overrides.type = mode;
|
|
1148
|
-
const fullPayload = {
|
|
1149
|
-
ide: finalIde,
|
|
1150
|
-
target: resolvedTarget,
|
|
1151
|
-
targetType: mode,
|
|
1400
|
+
const runtime = resolvePromptDispatchRuntime(serverState);
|
|
1401
|
+
return dispatchPromptThroughIde(runtime, {
|
|
1152
1402
|
prompt: formattedPrompt,
|
|
1153
1403
|
filePath: location.file,
|
|
1154
1404
|
line: location.line,
|
|
1155
1405
|
column: location.column,
|
|
1156
1406
|
snippet,
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
serverLogger.debug(`dispatchToAi: Generated URI: ${uri}`);
|
|
1166
|
-
launchURI(uri);
|
|
1167
|
-
return {
|
|
1168
|
-
success: true,
|
|
1169
|
-
fallbackPayload: {
|
|
1170
|
-
prompt: formattedPrompt,
|
|
1171
|
-
file: location.file
|
|
1172
|
-
}
|
|
1173
|
-
};
|
|
1407
|
+
...screenshotContext ? { screenshotContext } : {}
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
function getBatchDispatchStatusCode(errorCode, success) {
|
|
1411
|
+
if (success) return 200;
|
|
1412
|
+
if (errorCode === "INVALID_REQUEST") return 400;
|
|
1413
|
+
if (errorCode === "FORBIDDEN_PATH") return 403;
|
|
1414
|
+
return 500;
|
|
1174
1415
|
}
|
|
1175
1416
|
|
|
1176
1417
|
// src/injectors/utils.ts
|