@inspecto-dev/plugin 0.2.0-alpha.3 → 0.3.0-alpha.1
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 +452 -195
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +452 -195
- package/dist/index.js.map +1 -1
- package/dist/legacy/rspack/index.cjs +454 -197
- package/dist/legacy/rspack/index.cjs.map +1 -1
- package/dist/legacy/rspack/index.js +454 -197
- package/dist/legacy/rspack/index.js.map +1 -1
- package/dist/legacy/webpack4/index.cjs +454 -197
- package/dist/legacy/webpack4/index.cjs.map +1 -1
- package/dist/legacy/webpack4/index.js +454 -197
- package/dist/legacy/webpack4/index.js.map +1 -1
- package/dist/rollup.cjs +452 -195
- package/dist/rollup.cjs.map +1 -1
- package/dist/rollup.js +452 -195
- package/dist/rollup.js.map +1 -1
- package/dist/rspack.cjs +452 -195
- package/dist/rspack.cjs.map +1 -1
- package/dist/rspack.js +452 -195
- package/dist/rspack.js.map +1 -1
- package/dist/vite.cjs +452 -195
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +452 -195
- package/dist/vite.js.map +1 -1
- package/dist/webpack.cjs +452 -195
- package/dist/webpack.cjs.map +1 -1
- package/dist/webpack.js +452 -195
- package/dist/webpack.js.map +1 -1
- package/package.json +2 -2
package/dist/vite.js
CHANGED
|
@@ -269,13 +269,11 @@ function transformRouter(options) {
|
|
|
269
269
|
|
|
270
270
|
// src/server/index.ts
|
|
271
271
|
import http from "http";
|
|
272
|
-
import
|
|
273
|
-
import
|
|
272
|
+
import fs4 from "fs";
|
|
273
|
+
import path8 from "path";
|
|
274
274
|
import os2 from "os";
|
|
275
|
-
import
|
|
276
|
-
import { execSync, execFileSync } from "child_process";
|
|
275
|
+
import crypto2 from "crypto";
|
|
277
276
|
import portfinder from "portfinder";
|
|
278
|
-
import { launchIDE } from "launch-ide";
|
|
279
277
|
import { INSPECTO_API_PATHS } from "@inspecto-dev/types";
|
|
280
278
|
|
|
281
279
|
// src/server/snippet.ts
|
|
@@ -613,9 +611,9 @@ function extractToolOverrides(ide, config) {
|
|
|
613
611
|
function resolveIntents(serverPrompts) {
|
|
614
612
|
const baseMap = /* @__PURE__ */ new Map();
|
|
615
613
|
for (const intent of DEFAULT_INTENTS) {
|
|
616
|
-
|
|
614
|
+
baseMap.set(intent.id, { ...intent });
|
|
617
615
|
}
|
|
618
|
-
const defaults = () =>
|
|
616
|
+
const defaults = () => Array.from(baseMap.values());
|
|
619
617
|
if (!serverPrompts) return defaults();
|
|
620
618
|
const isReplace = !Array.isArray(serverPrompts) && typeof serverPrompts === "object" && serverPrompts.$replace === true;
|
|
621
619
|
const promptsArray = Array.isArray(serverPrompts) ? serverPrompts : isReplace ? serverPrompts.items : [];
|
|
@@ -642,16 +640,18 @@ function resolveIntents(serverPrompts) {
|
|
|
642
640
|
);
|
|
643
641
|
continue;
|
|
644
642
|
}
|
|
645
|
-
if (item.
|
|
643
|
+
if (!item.aiIntent) {
|
|
646
644
|
configLogger.warn(
|
|
647
|
-
`
|
|
645
|
+
`Intent "${item.id}" is missing required "aiIntent".`
|
|
648
646
|
);
|
|
649
647
|
continue;
|
|
650
648
|
}
|
|
651
|
-
result.push(
|
|
649
|
+
result.push(
|
|
650
|
+
baseMap.has(item.id) ? { ...baseMap.get(item.id), ...item } : item
|
|
651
|
+
);
|
|
652
652
|
}
|
|
653
653
|
}
|
|
654
|
-
return
|
|
654
|
+
return result;
|
|
655
655
|
}
|
|
656
656
|
const merged = Array.from(baseMap.values());
|
|
657
657
|
for (const item of promptsArray) {
|
|
@@ -668,9 +668,9 @@ function resolveIntents(serverPrompts) {
|
|
|
668
668
|
configLogger.warn('Intent object missing required "id" field, skipping.');
|
|
669
669
|
continue;
|
|
670
670
|
}
|
|
671
|
-
if (item.
|
|
671
|
+
if (!item.aiIntent) {
|
|
672
672
|
configLogger.warn(
|
|
673
|
-
`
|
|
673
|
+
`Intent "${item.id}" is missing required "aiIntent".`
|
|
674
674
|
);
|
|
675
675
|
continue;
|
|
676
676
|
}
|
|
@@ -688,15 +688,7 @@ function resolveIntents(serverPrompts) {
|
|
|
688
688
|
}
|
|
689
689
|
}
|
|
690
690
|
}
|
|
691
|
-
return
|
|
692
|
-
}
|
|
693
|
-
function ensureOpenInEditorLast(intents) {
|
|
694
|
-
const idx = intents.findIndex((i) => i.id === "open-in-editor");
|
|
695
|
-
if (idx === -1 || idx === intents.length - 1) return intents;
|
|
696
|
-
const result = [...intents];
|
|
697
|
-
const item = result.splice(idx, 1)[0];
|
|
698
|
-
result.push(item);
|
|
699
|
-
return result;
|
|
691
|
+
return merged;
|
|
700
692
|
}
|
|
701
693
|
var watchers = [];
|
|
702
694
|
function watchConfig(onReload, cwd = process.cwd(), gitRoot) {
|
|
@@ -731,7 +723,10 @@ function watchConfig(onReload, cwd = process.cwd(), gitRoot) {
|
|
|
731
723
|
}
|
|
732
724
|
}
|
|
733
725
|
|
|
734
|
-
// src/server/
|
|
726
|
+
// src/server/dispatch-transport.ts
|
|
727
|
+
import crypto from "crypto";
|
|
728
|
+
import { execFileSync } from "child_process";
|
|
729
|
+
import { launchIDE } from "launch-ide";
|
|
735
730
|
var serverLogger = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
736
731
|
var payloadTickets = /* @__PURE__ */ new Map();
|
|
737
732
|
function createTicket(payload) {
|
|
@@ -745,32 +740,8 @@ function createTicket(payload) {
|
|
|
745
740
|
);
|
|
746
741
|
return ticketId;
|
|
747
742
|
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
running: false,
|
|
751
|
-
projectRoot: "",
|
|
752
|
-
configRoot: "",
|
|
753
|
-
cwd: process.cwd()
|
|
754
|
-
};
|
|
755
|
-
var serverInstance = null;
|
|
756
|
-
function resolveProjectRoot() {
|
|
757
|
-
let gitRoot;
|
|
758
|
-
try {
|
|
759
|
-
serverLogger.info("Resolving project root...");
|
|
760
|
-
gitRoot = execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
761
|
-
serverLogger.info("Resolved project root: " + gitRoot);
|
|
762
|
-
} catch (e) {
|
|
763
|
-
serverLogger.error("Failed to resolve project root:", e);
|
|
764
|
-
gitRoot = process.cwd();
|
|
765
|
-
}
|
|
766
|
-
let current = gitRoot;
|
|
767
|
-
while (true) {
|
|
768
|
-
if (fs3.existsSync(path6.join(current, ".inspecto"))) return current;
|
|
769
|
-
const parent = path6.dirname(current);
|
|
770
|
-
if (parent === current) break;
|
|
771
|
-
current = parent;
|
|
772
|
-
}
|
|
773
|
-
return gitRoot;
|
|
743
|
+
function readTicket(ticketId) {
|
|
744
|
+
return payloadTickets.get(ticketId);
|
|
774
745
|
}
|
|
775
746
|
function launchURI(uri) {
|
|
776
747
|
try {
|
|
@@ -786,6 +757,378 @@ function launchURI(uri) {
|
|
|
786
757
|
launchIDE({ file: uri });
|
|
787
758
|
}
|
|
788
759
|
}
|
|
760
|
+
|
|
761
|
+
// src/server/dispatch-runtime.ts
|
|
762
|
+
function resolvePromptDispatchRuntime(state) {
|
|
763
|
+
const userConfig = loadUserConfigSync(false, state.cwd, state.projectRoot);
|
|
764
|
+
const resolvedTarget = resolveTargetTool(userConfig);
|
|
765
|
+
const finalIde = resolveFinalIde(userConfig.ide, state.ideInfo?.ide, state.ideInfo?.scheme);
|
|
766
|
+
const mode = resolveProviderMode(resolvedTarget, finalIde, userConfig);
|
|
767
|
+
const overrides = extractToolOverrides(finalIde, userConfig)[resolvedTarget] || void 0;
|
|
768
|
+
return {
|
|
769
|
+
resolvedTarget,
|
|
770
|
+
finalIde,
|
|
771
|
+
mode,
|
|
772
|
+
...hasOverrides(overrides) ? { overrides } : {},
|
|
773
|
+
...userConfig["prompt.autoSend"] !== void 0 ? { autoSend: Boolean(userConfig["prompt.autoSend"]) } : {}
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function dispatchPromptThroughIde(runtime, payload) {
|
|
777
|
+
const ticketId = createTicket({
|
|
778
|
+
ide: runtime.finalIde,
|
|
779
|
+
target: runtime.resolvedTarget,
|
|
780
|
+
targetType: runtime.mode,
|
|
781
|
+
prompt: payload.prompt,
|
|
782
|
+
filePath: payload.filePath,
|
|
783
|
+
line: payload.line,
|
|
784
|
+
column: payload.column,
|
|
785
|
+
snippet: payload.snippet,
|
|
786
|
+
...payload.screenshotContext ? { screenshotContext: payload.screenshotContext } : {},
|
|
787
|
+
overrides: runtime.overrides,
|
|
788
|
+
autoSend: runtime.autoSend
|
|
789
|
+
});
|
|
790
|
+
const params = new URLSearchParams();
|
|
791
|
+
params.set("ticket", ticketId);
|
|
792
|
+
params.set("target", runtime.resolvedTarget);
|
|
793
|
+
launchURI(`${runtime.finalIde}://inspecto.inspecto/send?${params.toString()}`);
|
|
794
|
+
return {
|
|
795
|
+
success: true,
|
|
796
|
+
fallbackPayload: {
|
|
797
|
+
prompt: payload.prompt,
|
|
798
|
+
...payload.filePath ? { file: payload.filePath } : {}
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
function resolveFinalIde(configuredIde, activeIde, activeIdeScheme) {
|
|
803
|
+
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
804
|
+
return configuredIde;
|
|
805
|
+
}
|
|
806
|
+
return configuredIde || activeIdeScheme || activeIde || "vscode";
|
|
807
|
+
}
|
|
808
|
+
function hasOverrides(overrides) {
|
|
809
|
+
return Boolean(overrides && Object.keys(overrides).length > 0);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// src/server/path-guards.ts
|
|
813
|
+
import path6 from "path";
|
|
814
|
+
function isWindowsAbsolutePath(file) {
|
|
815
|
+
return /^[a-zA-Z]:[\\/]/.test(file) || /^\\\\[^\\]+\\[^\\]+/.test(file);
|
|
816
|
+
}
|
|
817
|
+
function resolveWorkspacePath(file, cwd) {
|
|
818
|
+
if (isWindowsAbsolutePath(file)) {
|
|
819
|
+
return path6.win32.normalize(file);
|
|
820
|
+
}
|
|
821
|
+
return path6.isAbsolute(file) ? path6.resolve(file) : path6.resolve(cwd, file);
|
|
822
|
+
}
|
|
823
|
+
function assertPathWithinProject(file, projectRoot) {
|
|
824
|
+
const relativeToRoot = isWindowsAbsolutePath(file) || isWindowsAbsolutePath(projectRoot) ? path6.win32.relative(path6.win32.normalize(projectRoot), path6.win32.normalize(file)) : path6.relative(projectRoot, file);
|
|
825
|
+
if (relativeToRoot.startsWith("..") || path6.isAbsolute(relativeToRoot)) {
|
|
826
|
+
throw new Error("Access denied: File is outside of project workspace");
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// src/server/annotation-dispatch.ts
|
|
831
|
+
var AnnotationDispatchError = class extends Error {
|
|
832
|
+
constructor(message, errorCode) {
|
|
833
|
+
super(message);
|
|
834
|
+
this.name = "AnnotationDispatchError";
|
|
835
|
+
this.errorCode = errorCode;
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
async function dispatchAnnotationsToAi(req, state) {
|
|
839
|
+
try {
|
|
840
|
+
validateAnnotationDispatchRequest(req, state);
|
|
841
|
+
const batch = normalizeAnnotationBatch(req);
|
|
842
|
+
const prompt = buildAnnotationBatchPrompt(batch);
|
|
843
|
+
const representativeTarget = batch.annotations[0]?.targets[0];
|
|
844
|
+
const runtime = resolvePromptDispatchRuntime(state);
|
|
845
|
+
return dispatchPromptThroughIde(runtime, {
|
|
846
|
+
prompt,
|
|
847
|
+
...representativeTarget?.file ? { filePath: representativeTarget.file } : {},
|
|
848
|
+
...representativeTarget?.line ? { line: representativeTarget.line } : {},
|
|
849
|
+
...representativeTarget?.column ? { column: representativeTarget.column } : {},
|
|
850
|
+
...batch.screenshotContext ? { screenshotContext: batch.screenshotContext } : {}
|
|
851
|
+
});
|
|
852
|
+
} catch (error) {
|
|
853
|
+
return {
|
|
854
|
+
success: false,
|
|
855
|
+
error: error instanceof Error ? error.message : String(error),
|
|
856
|
+
errorCode: getAnnotationDispatchErrorCode(error)
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
function validateAnnotationDispatchRequest(req, state) {
|
|
861
|
+
if (!req.annotations.length) {
|
|
862
|
+
throw new AnnotationDispatchError("At least one annotation is required.", "INVALID_REQUEST");
|
|
863
|
+
}
|
|
864
|
+
for (const annotation of req.annotations) {
|
|
865
|
+
if (!annotation.targets.length) {
|
|
866
|
+
throw new AnnotationDispatchError(
|
|
867
|
+
"Each annotation must include at least one target.",
|
|
868
|
+
"INVALID_REQUEST"
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
for (const target of annotation.targets) {
|
|
872
|
+
const absolutePath = resolveWorkspacePath(target.location.file, state.cwd);
|
|
873
|
+
assertPathWithinProject(absolutePath, state.projectRoot);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
function normalizeAnnotationBatch(req) {
|
|
878
|
+
return {
|
|
879
|
+
instruction: req.instruction?.trim() ?? "",
|
|
880
|
+
responseMode: req.responseMode ?? "unified",
|
|
881
|
+
...req.runtimeContext ? { runtimeContext: req.runtimeContext } : {},
|
|
882
|
+
...req.screenshotContext ? { screenshotContext: req.screenshotContext } : {},
|
|
883
|
+
...req.cssContextPrompt?.trim() ? { cssContextPrompt: req.cssContextPrompt.trim() } : {},
|
|
884
|
+
annotations: req.annotations.map((annotation, index) => ({
|
|
885
|
+
index: index + 1,
|
|
886
|
+
note: annotation.note.trim(),
|
|
887
|
+
intent: annotation.intent,
|
|
888
|
+
targets: annotation.targets.map((target) => ({
|
|
889
|
+
file: target.location.file,
|
|
890
|
+
line: target.location.line,
|
|
891
|
+
column: target.location.column,
|
|
892
|
+
...target.label ? { label: target.label } : {},
|
|
893
|
+
...target.selector ? { selector: target.selector } : {},
|
|
894
|
+
...target.snippet ? { snippet: target.snippet } : {}
|
|
895
|
+
}))
|
|
896
|
+
}))
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
function buildAnnotationBatchPrompt(batch) {
|
|
900
|
+
const body = buildSelectedElementsPrompt(batch.annotations);
|
|
901
|
+
const prompt = batch.instruction ? `${batch.instruction}
|
|
902
|
+
|
|
903
|
+
${body}` : body;
|
|
904
|
+
return appendScreenshotContextSection(
|
|
905
|
+
appendCssContextSection(
|
|
906
|
+
appendRuntimeContextSection(prompt, batch.runtimeContext),
|
|
907
|
+
batch.cssContextPrompt
|
|
908
|
+
),
|
|
909
|
+
batch.screenshotContext
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
function appendCssContextSection(prompt, cssContextPrompt) {
|
|
913
|
+
if (!cssContextPrompt) return prompt;
|
|
914
|
+
return `${prompt}
|
|
915
|
+
|
|
916
|
+
${cssContextPrompt}`;
|
|
917
|
+
}
|
|
918
|
+
function buildSelectedElementsPrompt(annotations) {
|
|
919
|
+
const lines = ["Selected elements:"];
|
|
920
|
+
for (const annotation of annotations) {
|
|
921
|
+
const trimmedNote = annotation.note.trim();
|
|
922
|
+
for (const target of annotation.targets) {
|
|
923
|
+
const targetLabel = (target.label || "Unknown target").trim() || "Unknown target";
|
|
924
|
+
lines.push(`- ${targetLabel}`);
|
|
925
|
+
lines.push(`file=${target.file}:${target.line}:${target.column}`);
|
|
926
|
+
if (trimmedNote) {
|
|
927
|
+
lines.push(`note=${trimmedNote}`);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
if (lines.length === 1) {
|
|
932
|
+
lines.push("- None");
|
|
933
|
+
}
|
|
934
|
+
return lines.join("\n");
|
|
935
|
+
}
|
|
936
|
+
function appendScreenshotContextSection(prompt, screenshotContext) {
|
|
937
|
+
if (!screenshotContext || !screenshotContext.imageDataUrl && !screenshotContext.imageAssetId) {
|
|
938
|
+
return prompt;
|
|
939
|
+
}
|
|
940
|
+
const lines = [
|
|
941
|
+
"Visual screenshot context attached:",
|
|
942
|
+
`- capturedAt=${screenshotContext.capturedAt}`,
|
|
943
|
+
`- mimeType=${screenshotContext.mimeType}`,
|
|
944
|
+
...screenshotContext.imageAssetId ? [`- imageAssetId=${screenshotContext.imageAssetId}`] : []
|
|
945
|
+
];
|
|
946
|
+
return `${prompt}
|
|
947
|
+
|
|
948
|
+
${lines.join("\n")}`;
|
|
949
|
+
}
|
|
950
|
+
function appendRuntimeContextSection(prompt, runtimeContext) {
|
|
951
|
+
if (!runtimeContext?.records.length) {
|
|
952
|
+
return prompt;
|
|
953
|
+
}
|
|
954
|
+
return `${prompt}
|
|
955
|
+
|
|
956
|
+
${buildRuntimeContextSection(runtimeContext.records)}`;
|
|
957
|
+
}
|
|
958
|
+
function buildRuntimeContextSection(records) {
|
|
959
|
+
return ["Relevant runtime context:", ...records.map(formatRuntimeRecord)].join("\n");
|
|
960
|
+
}
|
|
961
|
+
function formatRuntimeRecord(record) {
|
|
962
|
+
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}`;
|
|
963
|
+
const reasonSummary = record.relevanceReasons.length ? record.relevanceReasons.join("; ") : "timing-based";
|
|
964
|
+
const stackSummary = record.stack ? `
|
|
965
|
+
stack=${record.stack.split("\n").slice(0, 5).join(" | ")}` : "";
|
|
966
|
+
return [
|
|
967
|
+
`- [${record.kind}] ${record.message}`,
|
|
968
|
+
` relevance=${record.relevanceLevel} (${reasonSummary})`,
|
|
969
|
+
` ${requestSummary}`,
|
|
970
|
+
stackSummary
|
|
971
|
+
].filter(Boolean).join("\n");
|
|
972
|
+
}
|
|
973
|
+
function getAnnotationDispatchErrorCode(error) {
|
|
974
|
+
if (error instanceof AnnotationDispatchError) return error.errorCode;
|
|
975
|
+
if (error instanceof Error && error.message.includes("outside of project workspace")) {
|
|
976
|
+
return "FORBIDDEN_PATH";
|
|
977
|
+
}
|
|
978
|
+
return "UNKNOWN";
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// src/server/client-config.ts
|
|
982
|
+
async function buildClientConfig(serverState2) {
|
|
983
|
+
const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
|
|
984
|
+
const promptsConfig = await loadPromptsConfig(false, serverState2.cwd, serverState2.configRoot);
|
|
985
|
+
const effectiveIde = userConfig.ide ?? "vscode";
|
|
986
|
+
let info;
|
|
987
|
+
if (!serverState2.ideInfo) {
|
|
988
|
+
info = { ide: effectiveIde };
|
|
989
|
+
} else {
|
|
990
|
+
const { scheme: _scheme, ...rest } = serverState2.ideInfo;
|
|
991
|
+
info = rest;
|
|
992
|
+
}
|
|
993
|
+
return {
|
|
994
|
+
...info,
|
|
995
|
+
prompts: resolveIntents(promptsConfig),
|
|
996
|
+
hotKeys: userConfig["inspector.hotKey"] ?? "alt",
|
|
997
|
+
theme: userConfig["inspector.theme"] ?? "auto",
|
|
998
|
+
includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
|
|
999
|
+
runtimeContext: {
|
|
1000
|
+
enabled: true,
|
|
1001
|
+
preview: true,
|
|
1002
|
+
maxRuntimeErrors: 3,
|
|
1003
|
+
maxFailedRequests: 2
|
|
1004
|
+
},
|
|
1005
|
+
screenshotContext: {
|
|
1006
|
+
enabled: false
|
|
1007
|
+
},
|
|
1008
|
+
annotationResponseMode: userConfig["prompt.annotationResponseMode"] ?? "unified",
|
|
1009
|
+
autoSend: userConfig["prompt.autoSend"] ?? false
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// src/server/open-file.ts
|
|
1014
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
1015
|
+
import { launchIDE as launchIDE2 } from "launch-ide";
|
|
1016
|
+
var serverLogger2 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
1017
|
+
var VSCODE_FAMILY_SCHEMES = [
|
|
1018
|
+
"vscode",
|
|
1019
|
+
"vscode-insiders",
|
|
1020
|
+
"cursor",
|
|
1021
|
+
"windsurf",
|
|
1022
|
+
"trae",
|
|
1023
|
+
"trae-cn",
|
|
1024
|
+
"vscodium",
|
|
1025
|
+
"codebuddy",
|
|
1026
|
+
"codebuddy-cn",
|
|
1027
|
+
"antigravity"
|
|
1028
|
+
];
|
|
1029
|
+
function handleOpenFileRequest(body, serverState2) {
|
|
1030
|
+
const absolutePath = resolveWorkspacePath(body.file, serverState2.cwd);
|
|
1031
|
+
assertPathWithinProject(absolutePath, serverState2.projectRoot);
|
|
1032
|
+
const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
|
|
1033
|
+
const configuredIde = userConfig.ide;
|
|
1034
|
+
const activeIde = serverState2.ideInfo?.ide;
|
|
1035
|
+
const activeIdeScheme = serverState2.ideInfo?.scheme;
|
|
1036
|
+
const rawEditorHint = configuredIde || activeIde || activeIdeScheme || "code";
|
|
1037
|
+
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
1038
|
+
serverLogger2.warn(
|
|
1039
|
+
`Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`
|
|
1040
|
+
);
|
|
1041
|
+
}
|
|
1042
|
+
let editorHint = rawEditorHint;
|
|
1043
|
+
if (rawEditorHint === "vscode") editorHint = "code";
|
|
1044
|
+
else if (rawEditorHint === "vscode-insiders") editorHint = "code-insiders";
|
|
1045
|
+
else if (rawEditorHint === "vscodium") editorHint = "codium";
|
|
1046
|
+
else if (rawEditorHint === "trae-cn" || rawEditorHint === "trae") editorHint = "trae";
|
|
1047
|
+
serverLogger2.debug(
|
|
1048
|
+
`IDE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`
|
|
1049
|
+
);
|
|
1050
|
+
if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {
|
|
1051
|
+
let normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
1052
|
+
if (!normalizedPath.startsWith("/")) {
|
|
1053
|
+
normalizedPath = "/" + normalizedPath;
|
|
1054
|
+
}
|
|
1055
|
+
const encodedPath = encodeURI(normalizedPath);
|
|
1056
|
+
const uri = `${rawEditorHint}://file${encodedPath}:${body.line}:${body.column}`;
|
|
1057
|
+
serverLogger2.debug(`IDE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
|
|
1058
|
+
try {
|
|
1059
|
+
if (process.platform === "darwin") {
|
|
1060
|
+
execFileSync2("open", [uri]);
|
|
1061
|
+
} else if (process.platform === "win32") {
|
|
1062
|
+
execFileSync2("cmd", ["/c", "start", '""', uri]);
|
|
1063
|
+
} else {
|
|
1064
|
+
execFileSync2("xdg-open", [uri]);
|
|
1065
|
+
}
|
|
1066
|
+
} catch (e) {
|
|
1067
|
+
serverLogger2.error(`Failed to launch URI for IDE_OPEN (${uri}):`, e);
|
|
1068
|
+
launchIDE2({
|
|
1069
|
+
file: absolutePath,
|
|
1070
|
+
line: body.line,
|
|
1071
|
+
column: body.column,
|
|
1072
|
+
editor: editorHint,
|
|
1073
|
+
type: process.platform === "darwin" ? "open" : "exec"
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
} else {
|
|
1077
|
+
launchIDE2({
|
|
1078
|
+
file: absolutePath,
|
|
1079
|
+
line: body.line,
|
|
1080
|
+
column: body.column,
|
|
1081
|
+
editor: editorHint,
|
|
1082
|
+
type: process.platform === "darwin" ? "open" : "exec"
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
return { success: true };
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// src/server/project-root.ts
|
|
1089
|
+
import fs3 from "fs";
|
|
1090
|
+
import path7 from "path";
|
|
1091
|
+
import { execSync } from "child_process";
|
|
1092
|
+
var serverLogger3 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
1093
|
+
function resolveProjectRoot() {
|
|
1094
|
+
const cwd = process.cwd();
|
|
1095
|
+
let gitRoot;
|
|
1096
|
+
try {
|
|
1097
|
+
gitRoot = execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
1098
|
+
} catch (e) {
|
|
1099
|
+
serverLogger3.warn("Failed to resolve git root via git rev-parse:", e);
|
|
1100
|
+
gitRoot = cwd;
|
|
1101
|
+
}
|
|
1102
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1103
|
+
const search = (start, stop) => {
|
|
1104
|
+
let current = start;
|
|
1105
|
+
while (!visited.has(current)) {
|
|
1106
|
+
visited.add(current);
|
|
1107
|
+
if (fs3.existsSync(path7.join(current, ".inspecto"))) return current;
|
|
1108
|
+
if (current === stop) break;
|
|
1109
|
+
const parent = path7.dirname(current);
|
|
1110
|
+
if (parent === current) break;
|
|
1111
|
+
current = parent;
|
|
1112
|
+
}
|
|
1113
|
+
return null;
|
|
1114
|
+
};
|
|
1115
|
+
const cwdMatch = search(cwd, path7.parse(cwd).root);
|
|
1116
|
+
if (cwdMatch) return cwdMatch;
|
|
1117
|
+
const repoMatch = search(gitRoot, path7.parse(gitRoot).root);
|
|
1118
|
+
if (repoMatch) return repoMatch;
|
|
1119
|
+
return gitRoot;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
// src/server/index.ts
|
|
1123
|
+
var serverLogger4 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
1124
|
+
var serverState = {
|
|
1125
|
+
port: null,
|
|
1126
|
+
running: false,
|
|
1127
|
+
projectRoot: "",
|
|
1128
|
+
configRoot: "",
|
|
1129
|
+
cwd: process.cwd()
|
|
1130
|
+
};
|
|
1131
|
+
var serverInstance = null;
|
|
789
1132
|
async function startServer() {
|
|
790
1133
|
if (serverState.running && serverState.port !== null) {
|
|
791
1134
|
return serverState.port;
|
|
@@ -797,7 +1140,7 @@ async function startServer() {
|
|
|
797
1140
|
const port = await portfinder.getPortPromise();
|
|
798
1141
|
watchConfig(
|
|
799
1142
|
() => {
|
|
800
|
-
|
|
1143
|
+
serverLogger4.info("user config reloaded.");
|
|
801
1144
|
},
|
|
802
1145
|
serverState.cwd,
|
|
803
1146
|
serverState.configRoot
|
|
@@ -813,7 +1156,7 @@ async function startServer() {
|
|
|
813
1156
|
}
|
|
814
1157
|
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
815
1158
|
handleRequest(url, req, res).catch((err) => {
|
|
816
|
-
|
|
1159
|
+
serverLogger4.error("server error:", err);
|
|
817
1160
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
818
1161
|
res.end(JSON.stringify({ success: false, error: String(err) }));
|
|
819
1162
|
});
|
|
@@ -826,41 +1169,41 @@ async function startServer() {
|
|
|
826
1169
|
serverInstance.once("error", reject);
|
|
827
1170
|
});
|
|
828
1171
|
serverInstance.on("error", (err) => {
|
|
829
|
-
|
|
1172
|
+
serverLogger4.error("persistent server error:", err);
|
|
830
1173
|
});
|
|
831
1174
|
serverState.port = port;
|
|
832
1175
|
serverState.running = true;
|
|
833
|
-
const portFile =
|
|
1176
|
+
const portFile = path8.join(os2.tmpdir(), "inspecto.port.json");
|
|
834
1177
|
try {
|
|
835
1178
|
let portData = {};
|
|
836
|
-
if (
|
|
1179
|
+
if (fs4.existsSync(portFile)) {
|
|
837
1180
|
try {
|
|
838
|
-
portData = JSON.parse(
|
|
1181
|
+
portData = JSON.parse(fs4.readFileSync(portFile, "utf-8"));
|
|
839
1182
|
} catch (e) {
|
|
840
1183
|
}
|
|
841
1184
|
}
|
|
842
|
-
const rootHash =
|
|
1185
|
+
const rootHash = crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
843
1186
|
portData[rootHash] = port;
|
|
844
|
-
|
|
1187
|
+
fs4.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
845
1188
|
} catch (e) {
|
|
846
|
-
|
|
1189
|
+
serverLogger4.warn("Failed to write port file:", e);
|
|
847
1190
|
}
|
|
848
1191
|
process.once("exit", () => {
|
|
849
1192
|
try {
|
|
850
|
-
if (
|
|
851
|
-
const portData = JSON.parse(
|
|
852
|
-
const rootHash =
|
|
1193
|
+
if (fs4.existsSync(portFile)) {
|
|
1194
|
+
const portData = JSON.parse(fs4.readFileSync(portFile, "utf-8"));
|
|
1195
|
+
const rootHash = crypto2.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
853
1196
|
delete portData[rootHash];
|
|
854
1197
|
if (Object.keys(portData).length === 0) {
|
|
855
|
-
|
|
1198
|
+
fs4.unlinkSync(portFile);
|
|
856
1199
|
} else {
|
|
857
|
-
|
|
1200
|
+
fs4.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
858
1201
|
}
|
|
859
1202
|
}
|
|
860
1203
|
} catch {
|
|
861
1204
|
}
|
|
862
1205
|
});
|
|
863
|
-
|
|
1206
|
+
serverLogger4.info(`server running at http://127.0.0.1:${port}`);
|
|
864
1207
|
return port;
|
|
865
1208
|
}
|
|
866
1209
|
async function readBody(req) {
|
|
@@ -879,26 +1222,7 @@ async function handleRequest(url, req, res) {
|
|
|
879
1222
|
return;
|
|
880
1223
|
}
|
|
881
1224
|
if (pathname === INSPECTO_API_PATHS.CLIENT_CONFIG && req.method === "GET") {
|
|
882
|
-
const
|
|
883
|
-
const promptsConfig = await loadPromptsConfig(false, serverState.cwd, serverState.configRoot);
|
|
884
|
-
const effectiveIde = userConfig.ide ?? "vscode";
|
|
885
|
-
let info;
|
|
886
|
-
if (!serverState.ideInfo) {
|
|
887
|
-
info = {
|
|
888
|
-
ide: effectiveIde
|
|
889
|
-
};
|
|
890
|
-
} else {
|
|
891
|
-
const { scheme: _scheme, ...rest } = serverState.ideInfo;
|
|
892
|
-
info = rest;
|
|
893
|
-
}
|
|
894
|
-
const config = {
|
|
895
|
-
...info,
|
|
896
|
-
prompts: resolveIntents(promptsConfig),
|
|
897
|
-
hotKeys: userConfig["inspector.hotKey"] ?? "alt",
|
|
898
|
-
theme: userConfig["inspector.theme"] ?? "auto",
|
|
899
|
-
includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
|
|
900
|
-
autoSend: userConfig["prompt.autoSend"] ?? false
|
|
901
|
-
};
|
|
1225
|
+
const config = await buildClientConfig(serverState);
|
|
902
1226
|
delete config.providers;
|
|
903
1227
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
904
1228
|
res.end(JSON.stringify(config));
|
|
@@ -909,21 +1233,23 @@ async function handleRequest(url, req, res) {
|
|
|
909
1233
|
const body = JSON.parse(await readBody(req));
|
|
910
1234
|
const ideWorkspace = body.workspaceRoot || "";
|
|
911
1235
|
const serverProjectRoot = serverState.projectRoot || "";
|
|
912
|
-
const
|
|
1236
|
+
const normalizedIdeRoot = ideWorkspace ? path8.resolve(ideWorkspace) : "";
|
|
1237
|
+
const normalizedServerRoot = serverProjectRoot ? path8.resolve(serverProjectRoot) : "";
|
|
1238
|
+
const isSameProject = !normalizedIdeRoot || !normalizedServerRoot || normalizedIdeRoot === normalizedServerRoot || normalizedServerRoot.startsWith(normalizedIdeRoot + path8.sep) || normalizedIdeRoot.startsWith(normalizedServerRoot + path8.sep);
|
|
913
1239
|
if (isSameProject) {
|
|
914
1240
|
serverState.ideInfo = body;
|
|
915
|
-
|
|
1241
|
+
serverLogger4.debug(
|
|
916
1242
|
`Accepted IDE info from matched workspace (ide-${body.ide} / schema-${body.scheme})`
|
|
917
1243
|
);
|
|
918
1244
|
} else {
|
|
919
|
-
|
|
1245
|
+
serverLogger4.debug(
|
|
920
1246
|
`Ignored IDE info from unrelated workspace (IDE Workspace: ${ideWorkspace}, Server: ${serverProjectRoot}, Scheme: ${body.scheme}, IDE: ${body.ide})`
|
|
921
1247
|
);
|
|
922
1248
|
}
|
|
923
1249
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
924
1250
|
res.end(JSON.stringify({ success: true }));
|
|
925
1251
|
} catch (e) {
|
|
926
|
-
|
|
1252
|
+
serverLogger4.error(`Error parsing ${INSPECTO_API_PATHS.IDE_INFO} POST request:`, e);
|
|
927
1253
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
928
1254
|
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
929
1255
|
}
|
|
@@ -938,74 +1264,14 @@ async function handleRequest(url, req, res) {
|
|
|
938
1264
|
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
939
1265
|
return;
|
|
940
1266
|
}
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1267
|
+
try {
|
|
1268
|
+
handleOpenFileRequest(body, serverState);
|
|
1269
|
+
} catch {
|
|
1270
|
+
serverLogger4.warn(`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}`);
|
|
945
1271
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
946
1272
|
res.end(JSON.stringify({ error: "Access denied: File is outside of project workspace" }));
|
|
947
1273
|
return;
|
|
948
1274
|
}
|
|
949
|
-
const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot);
|
|
950
|
-
const configuredIde = userConfig.ide;
|
|
951
|
-
const activeIde = serverState.ideInfo?.ide;
|
|
952
|
-
const activeIdeScheme = serverState.ideInfo?.scheme;
|
|
953
|
-
const rawEditorHint = configuredIde || activeIde || activeIdeScheme || "code";
|
|
954
|
-
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
955
|
-
serverLogger.warn(
|
|
956
|
-
`Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`
|
|
957
|
-
);
|
|
958
|
-
}
|
|
959
|
-
let editorHint = rawEditorHint;
|
|
960
|
-
if (rawEditorHint === "vscode") editorHint = "code";
|
|
961
|
-
else if (rawEditorHint === "vscode-insiders") editorHint = "code-insiders";
|
|
962
|
-
else if (rawEditorHint === "vscodium") editorHint = "codium";
|
|
963
|
-
else if (rawEditorHint === "trae-cn" || rawEditorHint === "trae") editorHint = "trae";
|
|
964
|
-
serverLogger.debug(
|
|
965
|
-
`IDE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`
|
|
966
|
-
);
|
|
967
|
-
const VSCODE_FAMILY_SCHEMES = [
|
|
968
|
-
"vscode",
|
|
969
|
-
"vscode-insiders",
|
|
970
|
-
"cursor",
|
|
971
|
-
"windsurf",
|
|
972
|
-
"trae",
|
|
973
|
-
"trae-cn",
|
|
974
|
-
"vscodium",
|
|
975
|
-
"codebuddy",
|
|
976
|
-
"codebuddy-cn",
|
|
977
|
-
"antigravity"
|
|
978
|
-
];
|
|
979
|
-
if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {
|
|
980
|
-
const uri = `${rawEditorHint}://file${absolutePath}:${body.line}:${body.column}`;
|
|
981
|
-
serverLogger.debug(`IDE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
|
|
982
|
-
try {
|
|
983
|
-
if (process.platform === "darwin") {
|
|
984
|
-
execFileSync("open", [uri]);
|
|
985
|
-
} else if (process.platform === "win32") {
|
|
986
|
-
execFileSync("cmd", ["/c", "start", '""', uri]);
|
|
987
|
-
} else {
|
|
988
|
-
execFileSync("xdg-open", [uri]);
|
|
989
|
-
}
|
|
990
|
-
} catch (e) {
|
|
991
|
-
serverLogger.error(`Failed to launch URI for IDE_OPEN (${uri}):`, e);
|
|
992
|
-
launchIDE({
|
|
993
|
-
file: absolutePath,
|
|
994
|
-
line: body.line,
|
|
995
|
-
column: body.column,
|
|
996
|
-
editor: editorHint,
|
|
997
|
-
type: process.platform === "darwin" ? "open" : "exec"
|
|
998
|
-
});
|
|
999
|
-
}
|
|
1000
|
-
} else {
|
|
1001
|
-
launchIDE({
|
|
1002
|
-
file: absolutePath,
|
|
1003
|
-
line: body.line,
|
|
1004
|
-
column: body.column,
|
|
1005
|
-
editor: editorHint,
|
|
1006
|
-
type: process.platform === "darwin" ? "open" : "exec"
|
|
1007
|
-
});
|
|
1008
|
-
}
|
|
1009
1275
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1010
1276
|
res.end(JSON.stringify({ success: true }));
|
|
1011
1277
|
return;
|
|
@@ -1016,10 +1282,11 @@ async function handleRequest(url, req, res) {
|
|
|
1016
1282
|
const column = parseInt(url.searchParams.get("column") ?? "1", 10);
|
|
1017
1283
|
const maxLines = parseInt(url.searchParams.get("maxLines") ?? "100", 10);
|
|
1018
1284
|
try {
|
|
1019
|
-
const absolutePath =
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1285
|
+
const absolutePath = resolveWorkspacePath(file, serverState.cwd);
|
|
1286
|
+
try {
|
|
1287
|
+
assertPathWithinProject(absolutePath, serverState.projectRoot);
|
|
1288
|
+
} catch {
|
|
1289
|
+
serverLogger4.warn(`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}`);
|
|
1023
1290
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
1024
1291
|
res.end(
|
|
1025
1292
|
JSON.stringify({
|
|
@@ -1049,7 +1316,23 @@ async function handleRequest(url, req, res) {
|
|
|
1049
1316
|
res.writeHead(result.success ? 200 : 500, { "Content-Type": "application/json" });
|
|
1050
1317
|
res.end(JSON.stringify(result));
|
|
1051
1318
|
} catch (e) {
|
|
1052
|
-
|
|
1319
|
+
serverLogger4.error(`Error parsing ${INSPECTO_API_PATHS.AI_DISPATCH} request:`, e);
|
|
1320
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1321
|
+
res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
|
|
1322
|
+
}
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
if (pathname === INSPECTO_API_PATHS.AI_BATCH_DISPATCH && req.method === "POST") {
|
|
1326
|
+
try {
|
|
1327
|
+
const rawBody = await readBody(req);
|
|
1328
|
+
const body = JSON.parse(rawBody);
|
|
1329
|
+
const result = await dispatchAnnotationsToAi(body, serverState);
|
|
1330
|
+
res.writeHead(getBatchDispatchStatusCode(result.errorCode, result.success), {
|
|
1331
|
+
"Content-Type": "application/json"
|
|
1332
|
+
});
|
|
1333
|
+
res.end(JSON.stringify(result));
|
|
1334
|
+
} catch (e) {
|
|
1335
|
+
serverLogger4.error(`Error parsing ${INSPECTO_API_PATHS.AI_BATCH_DISPATCH} request:`, e);
|
|
1053
1336
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1054
1337
|
res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
|
|
1055
1338
|
}
|
|
@@ -1057,7 +1340,7 @@ async function handleRequest(url, req, res) {
|
|
|
1057
1340
|
}
|
|
1058
1341
|
if (pathname.startsWith(`${INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
|
|
1059
1342
|
const ticketId = pathname.substring(INSPECTO_API_PATHS.AI_TICKET.length + 1);
|
|
1060
|
-
const payloadStr =
|
|
1343
|
+
const payloadStr = readTicket(ticketId);
|
|
1061
1344
|
if (!payloadStr) {
|
|
1062
1345
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1063
1346
|
res.end(JSON.stringify({ success: false, error: "Ticket not found or expired" }));
|
|
@@ -1071,54 +1354,28 @@ async function handleRequest(url, req, res) {
|
|
|
1071
1354
|
res.end(JSON.stringify({ error: "not found" }));
|
|
1072
1355
|
}
|
|
1073
1356
|
async function dispatchToAi(req) {
|
|
1074
|
-
const { location, snippet, prompt } = req;
|
|
1075
|
-
const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot);
|
|
1076
|
-
const resolvedTarget = resolveTargetTool(userConfig);
|
|
1357
|
+
const { location, snippet, prompt, screenshotContext } = req;
|
|
1077
1358
|
const formattedPrompt = prompt ?? `Please help me with this code from \`${location.file}\` (line ${location.line}):
|
|
1078
1359
|
|
|
1079
1360
|
\`\`\`
|
|
1080
1361
|
${snippet}
|
|
1081
1362
|
\`\`\`
|
|
1082
1363
|
`;
|
|
1083
|
-
const
|
|
1084
|
-
|
|
1085
|
-
const activeIde = serverState.ideInfo?.ide;
|
|
1086
|
-
const activeIdeScheme = serverState.ideInfo?.scheme;
|
|
1087
|
-
const finalIde = configuredIde || activeIdeScheme || activeIde || "vscode";
|
|
1088
|
-
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
1089
|
-
serverLogger.warn(
|
|
1090
|
-
`dispatchToAi: Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`
|
|
1091
|
-
);
|
|
1092
|
-
}
|
|
1093
|
-
const mode = resolveProviderMode(resolvedTarget, finalIde, userConfig);
|
|
1094
|
-
const overrides = extractToolOverrides(finalIde, userConfig)[resolvedTarget] || {};
|
|
1095
|
-
overrides.type = mode;
|
|
1096
|
-
const fullPayload = {
|
|
1097
|
-
ide: finalIde,
|
|
1098
|
-
target: resolvedTarget,
|
|
1099
|
-
targetType: mode,
|
|
1364
|
+
const runtime = resolvePromptDispatchRuntime(serverState);
|
|
1365
|
+
return dispatchPromptThroughIde(runtime, {
|
|
1100
1366
|
prompt: formattedPrompt,
|
|
1101
1367
|
filePath: location.file,
|
|
1102
1368
|
line: location.line,
|
|
1103
1369
|
column: location.column,
|
|
1104
1370
|
snippet,
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
serverLogger.debug(`dispatchToAi: Generated URI: ${uri}`);
|
|
1114
|
-
launchURI(uri);
|
|
1115
|
-
return {
|
|
1116
|
-
success: true,
|
|
1117
|
-
fallbackPayload: {
|
|
1118
|
-
prompt: formattedPrompt,
|
|
1119
|
-
file: location.file
|
|
1120
|
-
}
|
|
1121
|
-
};
|
|
1371
|
+
...screenshotContext ? { screenshotContext } : {}
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
function getBatchDispatchStatusCode(errorCode, success) {
|
|
1375
|
+
if (success) return 200;
|
|
1376
|
+
if (errorCode === "INVALID_REQUEST") return 400;
|
|
1377
|
+
if (errorCode === "FORBIDDEN_PATH") return 403;
|
|
1378
|
+
return 500;
|
|
1122
1379
|
}
|
|
1123
1380
|
|
|
1124
1381
|
// src/injectors/utils.ts
|