@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
|
@@ -42,13 +42,11 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
|
42
42
|
|
|
43
43
|
// src/server/index.ts
|
|
44
44
|
var import_node_http = __toESM(require("http"), 1);
|
|
45
|
-
var
|
|
46
|
-
var
|
|
45
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
46
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
47
47
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
48
|
-
var
|
|
49
|
-
var import_node_child_process = require("child_process");
|
|
48
|
+
var import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
50
49
|
var import_portfinder = __toESM(require("portfinder"), 1);
|
|
51
|
-
var import_launch_ide = require("launch-ide");
|
|
52
50
|
var import_types2 = require("@inspecto-dev/types");
|
|
53
51
|
|
|
54
52
|
// src/server/snippet.ts
|
|
@@ -368,9 +366,9 @@ function extractToolOverrides(ide, config) {
|
|
|
368
366
|
function resolveIntents(serverPrompts) {
|
|
369
367
|
const baseMap = /* @__PURE__ */ new Map();
|
|
370
368
|
for (const intent of import_types.DEFAULT_INTENTS) {
|
|
371
|
-
|
|
369
|
+
baseMap.set(intent.id, { ...intent });
|
|
372
370
|
}
|
|
373
|
-
const defaults = () =>
|
|
371
|
+
const defaults = () => Array.from(baseMap.values());
|
|
374
372
|
if (!serverPrompts) return defaults();
|
|
375
373
|
const isReplace = !Array.isArray(serverPrompts) && typeof serverPrompts === "object" && serverPrompts.$replace === true;
|
|
376
374
|
const promptsArray = Array.isArray(serverPrompts) ? serverPrompts : isReplace ? serverPrompts.items : [];
|
|
@@ -397,16 +395,18 @@ function resolveIntents(serverPrompts) {
|
|
|
397
395
|
);
|
|
398
396
|
continue;
|
|
399
397
|
}
|
|
400
|
-
if (item.
|
|
398
|
+
if (!item.aiIntent) {
|
|
401
399
|
configLogger.warn(
|
|
402
|
-
`
|
|
400
|
+
`Intent "${item.id}" is missing required "aiIntent".`
|
|
403
401
|
);
|
|
404
402
|
continue;
|
|
405
403
|
}
|
|
406
|
-
result.push(
|
|
404
|
+
result.push(
|
|
405
|
+
baseMap.has(item.id) ? { ...baseMap.get(item.id), ...item } : item
|
|
406
|
+
);
|
|
407
407
|
}
|
|
408
408
|
}
|
|
409
|
-
return
|
|
409
|
+
return result;
|
|
410
410
|
}
|
|
411
411
|
const merged = Array.from(baseMap.values());
|
|
412
412
|
for (const item of promptsArray) {
|
|
@@ -423,9 +423,9 @@ function resolveIntents(serverPrompts) {
|
|
|
423
423
|
configLogger.warn('Intent object missing required "id" field, skipping.');
|
|
424
424
|
continue;
|
|
425
425
|
}
|
|
426
|
-
if (item.
|
|
426
|
+
if (!item.aiIntent) {
|
|
427
427
|
configLogger.warn(
|
|
428
|
-
`
|
|
428
|
+
`Intent "${item.id}" is missing required "aiIntent".`
|
|
429
429
|
);
|
|
430
430
|
continue;
|
|
431
431
|
}
|
|
@@ -443,15 +443,7 @@ function resolveIntents(serverPrompts) {
|
|
|
443
443
|
}
|
|
444
444
|
}
|
|
445
445
|
}
|
|
446
|
-
return
|
|
447
|
-
}
|
|
448
|
-
function ensureOpenInEditorLast(intents) {
|
|
449
|
-
const idx = intents.findIndex((i) => i.id === "open-in-editor");
|
|
450
|
-
if (idx === -1 || idx === intents.length - 1) return intents;
|
|
451
|
-
const result = [...intents];
|
|
452
|
-
const item = result.splice(idx, 1)[0];
|
|
453
|
-
result.push(item);
|
|
454
|
-
return result;
|
|
446
|
+
return merged;
|
|
455
447
|
}
|
|
456
448
|
var watchers = [];
|
|
457
449
|
function watchConfig(onReload, cwd = process.cwd(), gitRoot) {
|
|
@@ -486,7 +478,10 @@ function watchConfig(onReload, cwd = process.cwd(), gitRoot) {
|
|
|
486
478
|
}
|
|
487
479
|
}
|
|
488
480
|
|
|
489
|
-
// src/server/
|
|
481
|
+
// src/server/dispatch-transport.ts
|
|
482
|
+
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
483
|
+
var import_node_child_process = require("child_process");
|
|
484
|
+
var import_launch_ide = require("launch-ide");
|
|
490
485
|
var serverLogger = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
491
486
|
var payloadTickets = /* @__PURE__ */ new Map();
|
|
492
487
|
function createTicket(payload) {
|
|
@@ -500,21 +495,363 @@ function createTicket(payload) {
|
|
|
500
495
|
);
|
|
501
496
|
return ticketId;
|
|
502
497
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
498
|
+
function readTicket(ticketId) {
|
|
499
|
+
return payloadTickets.get(ticketId);
|
|
500
|
+
}
|
|
501
|
+
function launchURI(uri) {
|
|
502
|
+
try {
|
|
503
|
+
if (process.platform === "darwin") {
|
|
504
|
+
(0, import_node_child_process.execFileSync)("open", [uri]);
|
|
505
|
+
} else if (process.platform === "win32") {
|
|
506
|
+
(0, import_node_child_process.execFileSync)("cmd", ["/c", "start", '""', uri]);
|
|
507
|
+
} else {
|
|
508
|
+
(0, import_node_child_process.execFileSync)("xdg-open", [uri]);
|
|
509
|
+
}
|
|
510
|
+
} catch (e) {
|
|
511
|
+
serverLogger.error("Failed to launch URI via execFileSync, falling back to launchIDE:", e);
|
|
512
|
+
(0, import_launch_ide.launchIDE)({ file: uri });
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// src/server/dispatch-runtime.ts
|
|
517
|
+
function resolvePromptDispatchRuntime(state) {
|
|
518
|
+
const userConfig = loadUserConfigSync(false, state.cwd, state.projectRoot);
|
|
519
|
+
const resolvedTarget = resolveTargetTool(userConfig);
|
|
520
|
+
const finalIde = resolveFinalIde(userConfig.ide, state.ideInfo?.ide, state.ideInfo?.scheme);
|
|
521
|
+
const mode = resolveProviderMode(resolvedTarget, finalIde, userConfig);
|
|
522
|
+
const overrides = extractToolOverrides(finalIde, userConfig)[resolvedTarget] || void 0;
|
|
523
|
+
return {
|
|
524
|
+
resolvedTarget,
|
|
525
|
+
finalIde,
|
|
526
|
+
mode,
|
|
527
|
+
...hasOverrides(overrides) ? { overrides } : {},
|
|
528
|
+
...userConfig["prompt.autoSend"] !== void 0 ? { autoSend: Boolean(userConfig["prompt.autoSend"]) } : {}
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
function dispatchPromptThroughIde(runtime, payload) {
|
|
532
|
+
const ticketId = createTicket({
|
|
533
|
+
ide: runtime.finalIde,
|
|
534
|
+
target: runtime.resolvedTarget,
|
|
535
|
+
targetType: runtime.mode,
|
|
536
|
+
prompt: payload.prompt,
|
|
537
|
+
filePath: payload.filePath,
|
|
538
|
+
line: payload.line,
|
|
539
|
+
column: payload.column,
|
|
540
|
+
snippet: payload.snippet,
|
|
541
|
+
...payload.screenshotContext ? { screenshotContext: payload.screenshotContext } : {},
|
|
542
|
+
overrides: runtime.overrides,
|
|
543
|
+
autoSend: runtime.autoSend
|
|
544
|
+
});
|
|
545
|
+
const params = new URLSearchParams();
|
|
546
|
+
params.set("ticket", ticketId);
|
|
547
|
+
params.set("target", runtime.resolvedTarget);
|
|
548
|
+
launchURI(`${runtime.finalIde}://inspecto.inspecto/send?${params.toString()}`);
|
|
549
|
+
return {
|
|
550
|
+
success: true,
|
|
551
|
+
fallbackPayload: {
|
|
552
|
+
prompt: payload.prompt,
|
|
553
|
+
...payload.filePath ? { file: payload.filePath } : {}
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function resolveFinalIde(configuredIde, activeIde, activeIdeScheme) {
|
|
558
|
+
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
559
|
+
return configuredIde;
|
|
560
|
+
}
|
|
561
|
+
return configuredIde || activeIdeScheme || activeIde || "vscode";
|
|
562
|
+
}
|
|
563
|
+
function hasOverrides(overrides) {
|
|
564
|
+
return Boolean(overrides && Object.keys(overrides).length > 0);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// src/server/path-guards.ts
|
|
568
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
569
|
+
function isWindowsAbsolutePath(file) {
|
|
570
|
+
return /^[a-zA-Z]:[\\/]/.test(file) || /^\\\\[^\\]+\\[^\\]+/.test(file);
|
|
571
|
+
}
|
|
572
|
+
function resolveWorkspacePath(file, cwd) {
|
|
573
|
+
if (isWindowsAbsolutePath(file)) {
|
|
574
|
+
return import_node_path2.default.win32.normalize(file);
|
|
575
|
+
}
|
|
576
|
+
return import_node_path2.default.isAbsolute(file) ? import_node_path2.default.resolve(file) : import_node_path2.default.resolve(cwd, file);
|
|
577
|
+
}
|
|
578
|
+
function assertPathWithinProject(file, projectRoot) {
|
|
579
|
+
const relativeToRoot = isWindowsAbsolutePath(file) || isWindowsAbsolutePath(projectRoot) ? import_node_path2.default.win32.relative(import_node_path2.default.win32.normalize(projectRoot), import_node_path2.default.win32.normalize(file)) : import_node_path2.default.relative(projectRoot, file);
|
|
580
|
+
if (relativeToRoot.startsWith("..") || import_node_path2.default.isAbsolute(relativeToRoot)) {
|
|
581
|
+
throw new Error("Access denied: File is outside of project workspace");
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// src/server/annotation-dispatch.ts
|
|
586
|
+
var AnnotationDispatchError = class extends Error {
|
|
587
|
+
constructor(message, errorCode) {
|
|
588
|
+
super(message);
|
|
589
|
+
this.name = "AnnotationDispatchError";
|
|
590
|
+
this.errorCode = errorCode;
|
|
591
|
+
}
|
|
509
592
|
};
|
|
510
|
-
|
|
593
|
+
async function dispatchAnnotationsToAi(req, state) {
|
|
594
|
+
try {
|
|
595
|
+
validateAnnotationDispatchRequest(req, state);
|
|
596
|
+
const batch = normalizeAnnotationBatch(req);
|
|
597
|
+
const prompt = buildAnnotationBatchPrompt(batch);
|
|
598
|
+
const representativeTarget = batch.annotations[0]?.targets[0];
|
|
599
|
+
const runtime = resolvePromptDispatchRuntime(state);
|
|
600
|
+
return dispatchPromptThroughIde(runtime, {
|
|
601
|
+
prompt,
|
|
602
|
+
...representativeTarget?.file ? { filePath: representativeTarget.file } : {},
|
|
603
|
+
...representativeTarget?.line ? { line: representativeTarget.line } : {},
|
|
604
|
+
...representativeTarget?.column ? { column: representativeTarget.column } : {},
|
|
605
|
+
...batch.screenshotContext ? { screenshotContext: batch.screenshotContext } : {}
|
|
606
|
+
});
|
|
607
|
+
} catch (error) {
|
|
608
|
+
return {
|
|
609
|
+
success: false,
|
|
610
|
+
error: error instanceof Error ? error.message : String(error),
|
|
611
|
+
errorCode: getAnnotationDispatchErrorCode(error)
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
function validateAnnotationDispatchRequest(req, state) {
|
|
616
|
+
if (!req.annotations.length) {
|
|
617
|
+
throw new AnnotationDispatchError("At least one annotation is required.", "INVALID_REQUEST");
|
|
618
|
+
}
|
|
619
|
+
for (const annotation of req.annotations) {
|
|
620
|
+
if (!annotation.targets.length) {
|
|
621
|
+
throw new AnnotationDispatchError(
|
|
622
|
+
"Each annotation must include at least one target.",
|
|
623
|
+
"INVALID_REQUEST"
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
for (const target of annotation.targets) {
|
|
627
|
+
const absolutePath = resolveWorkspacePath(target.location.file, state.cwd);
|
|
628
|
+
assertPathWithinProject(absolutePath, state.projectRoot);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
function normalizeAnnotationBatch(req) {
|
|
633
|
+
return {
|
|
634
|
+
instruction: req.instruction?.trim() ?? "",
|
|
635
|
+
responseMode: req.responseMode ?? "unified",
|
|
636
|
+
...req.runtimeContext ? { runtimeContext: req.runtimeContext } : {},
|
|
637
|
+
...req.screenshotContext ? { screenshotContext: req.screenshotContext } : {},
|
|
638
|
+
...req.cssContextPrompt?.trim() ? { cssContextPrompt: req.cssContextPrompt.trim() } : {},
|
|
639
|
+
annotations: req.annotations.map((annotation, index) => ({
|
|
640
|
+
index: index + 1,
|
|
641
|
+
note: annotation.note.trim(),
|
|
642
|
+
intent: annotation.intent,
|
|
643
|
+
targets: annotation.targets.map((target) => ({
|
|
644
|
+
file: target.location.file,
|
|
645
|
+
line: target.location.line,
|
|
646
|
+
column: target.location.column,
|
|
647
|
+
...target.label ? { label: target.label } : {},
|
|
648
|
+
...target.selector ? { selector: target.selector } : {},
|
|
649
|
+
...target.snippet ? { snippet: target.snippet } : {}
|
|
650
|
+
}))
|
|
651
|
+
}))
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
function buildAnnotationBatchPrompt(batch) {
|
|
655
|
+
const body = buildSelectedElementsPrompt(batch.annotations);
|
|
656
|
+
const prompt = batch.instruction ? `${batch.instruction}
|
|
657
|
+
|
|
658
|
+
${body}` : body;
|
|
659
|
+
return appendScreenshotContextSection(
|
|
660
|
+
appendCssContextSection(
|
|
661
|
+
appendRuntimeContextSection(prompt, batch.runtimeContext),
|
|
662
|
+
batch.cssContextPrompt
|
|
663
|
+
),
|
|
664
|
+
batch.screenshotContext
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
function appendCssContextSection(prompt, cssContextPrompt) {
|
|
668
|
+
if (!cssContextPrompt) return prompt;
|
|
669
|
+
return `${prompt}
|
|
670
|
+
|
|
671
|
+
${cssContextPrompt}`;
|
|
672
|
+
}
|
|
673
|
+
function buildSelectedElementsPrompt(annotations) {
|
|
674
|
+
const lines = ["Selected elements:"];
|
|
675
|
+
for (const annotation of annotations) {
|
|
676
|
+
const trimmedNote = annotation.note.trim();
|
|
677
|
+
for (const target of annotation.targets) {
|
|
678
|
+
const targetLabel = (target.label || "Unknown target").trim() || "Unknown target";
|
|
679
|
+
lines.push(`- ${targetLabel}`);
|
|
680
|
+
lines.push(`file=${target.file}:${target.line}:${target.column}`);
|
|
681
|
+
if (trimmedNote) {
|
|
682
|
+
lines.push(`note=${trimmedNote}`);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (lines.length === 1) {
|
|
687
|
+
lines.push("- None");
|
|
688
|
+
}
|
|
689
|
+
return lines.join("\n");
|
|
690
|
+
}
|
|
691
|
+
function appendScreenshotContextSection(prompt, screenshotContext) {
|
|
692
|
+
if (!screenshotContext || !screenshotContext.imageDataUrl && !screenshotContext.imageAssetId) {
|
|
693
|
+
return prompt;
|
|
694
|
+
}
|
|
695
|
+
const lines = [
|
|
696
|
+
"Visual screenshot context attached:",
|
|
697
|
+
`- capturedAt=${screenshotContext.capturedAt}`,
|
|
698
|
+
`- mimeType=${screenshotContext.mimeType}`,
|
|
699
|
+
...screenshotContext.imageAssetId ? [`- imageAssetId=${screenshotContext.imageAssetId}`] : []
|
|
700
|
+
];
|
|
701
|
+
return `${prompt}
|
|
702
|
+
|
|
703
|
+
${lines.join("\n")}`;
|
|
704
|
+
}
|
|
705
|
+
function appendRuntimeContextSection(prompt, runtimeContext) {
|
|
706
|
+
if (!runtimeContext?.records.length) {
|
|
707
|
+
return prompt;
|
|
708
|
+
}
|
|
709
|
+
return `${prompt}
|
|
710
|
+
|
|
711
|
+
${buildRuntimeContextSection(runtimeContext.records)}`;
|
|
712
|
+
}
|
|
713
|
+
function buildRuntimeContextSection(records) {
|
|
714
|
+
return ["Relevant runtime context:", ...records.map(formatRuntimeRecord)].join("\n");
|
|
715
|
+
}
|
|
716
|
+
function formatRuntimeRecord(record) {
|
|
717
|
+
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}`;
|
|
718
|
+
const reasonSummary = record.relevanceReasons.length ? record.relevanceReasons.join("; ") : "timing-based";
|
|
719
|
+
const stackSummary = record.stack ? `
|
|
720
|
+
stack=${record.stack.split("\n").slice(0, 5).join(" | ")}` : "";
|
|
721
|
+
return [
|
|
722
|
+
`- [${record.kind}] ${record.message}`,
|
|
723
|
+
` relevance=${record.relevanceLevel} (${reasonSummary})`,
|
|
724
|
+
` ${requestSummary}`,
|
|
725
|
+
stackSummary
|
|
726
|
+
].filter(Boolean).join("\n");
|
|
727
|
+
}
|
|
728
|
+
function getAnnotationDispatchErrorCode(error) {
|
|
729
|
+
if (error instanceof AnnotationDispatchError) return error.errorCode;
|
|
730
|
+
if (error instanceof Error && error.message.includes("outside of project workspace")) {
|
|
731
|
+
return "FORBIDDEN_PATH";
|
|
732
|
+
}
|
|
733
|
+
return "UNKNOWN";
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// src/server/client-config.ts
|
|
737
|
+
async function buildClientConfig(serverState3) {
|
|
738
|
+
const userConfig = loadUserConfigSync(false, serverState3.cwd, serverState3.configRoot);
|
|
739
|
+
const promptsConfig = await loadPromptsConfig(false, serverState3.cwd, serverState3.configRoot);
|
|
740
|
+
const effectiveIde = userConfig.ide ?? "vscode";
|
|
741
|
+
let info;
|
|
742
|
+
if (!serverState3.ideInfo) {
|
|
743
|
+
info = { ide: effectiveIde };
|
|
744
|
+
} else {
|
|
745
|
+
const { scheme: _scheme, ...rest } = serverState3.ideInfo;
|
|
746
|
+
info = rest;
|
|
747
|
+
}
|
|
748
|
+
return {
|
|
749
|
+
...info,
|
|
750
|
+
prompts: resolveIntents(promptsConfig),
|
|
751
|
+
hotKeys: userConfig["inspector.hotKey"] ?? "alt",
|
|
752
|
+
theme: userConfig["inspector.theme"] ?? "auto",
|
|
753
|
+
includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
|
|
754
|
+
runtimeContext: {
|
|
755
|
+
enabled: true,
|
|
756
|
+
preview: true,
|
|
757
|
+
maxRuntimeErrors: 3,
|
|
758
|
+
maxFailedRequests: 2
|
|
759
|
+
},
|
|
760
|
+
screenshotContext: {
|
|
761
|
+
enabled: false
|
|
762
|
+
},
|
|
763
|
+
annotationResponseMode: userConfig["prompt.annotationResponseMode"] ?? "unified",
|
|
764
|
+
autoSend: userConfig["prompt.autoSend"] ?? false
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// src/server/open-file.ts
|
|
769
|
+
var import_node_child_process2 = require("child_process");
|
|
770
|
+
var import_launch_ide2 = require("launch-ide");
|
|
771
|
+
var serverLogger2 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
772
|
+
var VSCODE_FAMILY_SCHEMES = [
|
|
773
|
+
"vscode",
|
|
774
|
+
"vscode-insiders",
|
|
775
|
+
"cursor",
|
|
776
|
+
"windsurf",
|
|
777
|
+
"trae",
|
|
778
|
+
"trae-cn",
|
|
779
|
+
"vscodium",
|
|
780
|
+
"codebuddy",
|
|
781
|
+
"codebuddy-cn",
|
|
782
|
+
"antigravity"
|
|
783
|
+
];
|
|
784
|
+
function handleOpenFileRequest(body, serverState3) {
|
|
785
|
+
const absolutePath = resolveWorkspacePath(body.file, serverState3.cwd);
|
|
786
|
+
assertPathWithinProject(absolutePath, serverState3.projectRoot);
|
|
787
|
+
const userConfig = loadUserConfigSync(false, serverState3.cwd, serverState3.configRoot);
|
|
788
|
+
const configuredIde = userConfig.ide;
|
|
789
|
+
const activeIde = serverState3.ideInfo?.ide;
|
|
790
|
+
const activeIdeScheme = serverState3.ideInfo?.scheme;
|
|
791
|
+
const rawEditorHint = configuredIde || activeIde || activeIdeScheme || "code";
|
|
792
|
+
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
793
|
+
serverLogger2.warn(
|
|
794
|
+
`Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
let editorHint = rawEditorHint;
|
|
798
|
+
if (rawEditorHint === "vscode") editorHint = "code";
|
|
799
|
+
else if (rawEditorHint === "vscode-insiders") editorHint = "code-insiders";
|
|
800
|
+
else if (rawEditorHint === "vscodium") editorHint = "codium";
|
|
801
|
+
else if (rawEditorHint === "trae-cn" || rawEditorHint === "trae") editorHint = "trae";
|
|
802
|
+
serverLogger2.debug(
|
|
803
|
+
`IDE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`
|
|
804
|
+
);
|
|
805
|
+
if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {
|
|
806
|
+
let normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
807
|
+
if (!normalizedPath.startsWith("/")) {
|
|
808
|
+
normalizedPath = "/" + normalizedPath;
|
|
809
|
+
}
|
|
810
|
+
const encodedPath = encodeURI(normalizedPath);
|
|
811
|
+
const uri = `${rawEditorHint}://file${encodedPath}:${body.line}:${body.column}`;
|
|
812
|
+
serverLogger2.debug(`IDE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
|
|
813
|
+
try {
|
|
814
|
+
if (process.platform === "darwin") {
|
|
815
|
+
(0, import_node_child_process2.execFileSync)("open", [uri]);
|
|
816
|
+
} else if (process.platform === "win32") {
|
|
817
|
+
(0, import_node_child_process2.execFileSync)("cmd", ["/c", "start", '""', uri]);
|
|
818
|
+
} else {
|
|
819
|
+
(0, import_node_child_process2.execFileSync)("xdg-open", [uri]);
|
|
820
|
+
}
|
|
821
|
+
} catch (e) {
|
|
822
|
+
serverLogger2.error(`Failed to launch URI for IDE_OPEN (${uri}):`, e);
|
|
823
|
+
(0, import_launch_ide2.launchIDE)({
|
|
824
|
+
file: absolutePath,
|
|
825
|
+
line: body.line,
|
|
826
|
+
column: body.column,
|
|
827
|
+
editor: editorHint,
|
|
828
|
+
type: process.platform === "darwin" ? "open" : "exec"
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
} else {
|
|
832
|
+
(0, import_launch_ide2.launchIDE)({
|
|
833
|
+
file: absolutePath,
|
|
834
|
+
line: body.line,
|
|
835
|
+
column: body.column,
|
|
836
|
+
editor: editorHint,
|
|
837
|
+
type: process.platform === "darwin" ? "open" : "exec"
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
return { success: true };
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// src/server/project-root.ts
|
|
844
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
845
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
846
|
+
var import_node_child_process3 = require("child_process");
|
|
847
|
+
var serverLogger3 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
511
848
|
function resolveProjectRoot() {
|
|
512
849
|
const cwd = process.cwd();
|
|
513
850
|
let gitRoot;
|
|
514
851
|
try {
|
|
515
|
-
gitRoot = (0,
|
|
852
|
+
gitRoot = (0, import_node_child_process3.execSync)("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
516
853
|
} catch (e) {
|
|
517
|
-
|
|
854
|
+
serverLogger3.warn("Failed to resolve git root via git rev-parse:", e);
|
|
518
855
|
gitRoot = cwd;
|
|
519
856
|
}
|
|
520
857
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -522,34 +859,31 @@ function resolveProjectRoot() {
|
|
|
522
859
|
let current = start;
|
|
523
860
|
while (!visited.has(current)) {
|
|
524
861
|
visited.add(current);
|
|
525
|
-
if (import_node_fs2.default.existsSync(
|
|
862
|
+
if (import_node_fs2.default.existsSync(import_node_path3.default.join(current, ".inspecto"))) return current;
|
|
526
863
|
if (current === stop) break;
|
|
527
|
-
const parent =
|
|
864
|
+
const parent = import_node_path3.default.dirname(current);
|
|
528
865
|
if (parent === current) break;
|
|
529
866
|
current = parent;
|
|
530
867
|
}
|
|
531
868
|
return null;
|
|
532
869
|
};
|
|
533
|
-
const cwdMatch = search(cwd,
|
|
870
|
+
const cwdMatch = search(cwd, import_node_path3.default.parse(cwd).root);
|
|
534
871
|
if (cwdMatch) return cwdMatch;
|
|
535
|
-
const repoMatch = search(gitRoot,
|
|
872
|
+
const repoMatch = search(gitRoot, import_node_path3.default.parse(gitRoot).root);
|
|
536
873
|
if (repoMatch) return repoMatch;
|
|
537
874
|
return gitRoot;
|
|
538
875
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
(0, import_launch_ide.launchIDE)({ file: uri });
|
|
551
|
-
}
|
|
552
|
-
}
|
|
876
|
+
|
|
877
|
+
// src/server/index.ts
|
|
878
|
+
var serverLogger4 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
879
|
+
var serverState = {
|
|
880
|
+
port: null,
|
|
881
|
+
running: false,
|
|
882
|
+
projectRoot: "",
|
|
883
|
+
configRoot: "",
|
|
884
|
+
cwd: process.cwd()
|
|
885
|
+
};
|
|
886
|
+
var serverInstance = null;
|
|
553
887
|
async function startServer() {
|
|
554
888
|
if (serverState.running && serverState.port !== null) {
|
|
555
889
|
return serverState.port;
|
|
@@ -561,7 +895,7 @@ async function startServer() {
|
|
|
561
895
|
const port = await import_portfinder.default.getPortPromise();
|
|
562
896
|
watchConfig(
|
|
563
897
|
() => {
|
|
564
|
-
|
|
898
|
+
serverLogger4.info("user config reloaded.");
|
|
565
899
|
},
|
|
566
900
|
serverState.cwd,
|
|
567
901
|
serverState.configRoot
|
|
@@ -577,7 +911,7 @@ async function startServer() {
|
|
|
577
911
|
}
|
|
578
912
|
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
579
913
|
handleRequest(url, req, res).catch((err) => {
|
|
580
|
-
|
|
914
|
+
serverLogger4.error("server error:", err);
|
|
581
915
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
582
916
|
res.end(JSON.stringify({ success: false, error: String(err) }));
|
|
583
917
|
});
|
|
@@ -590,41 +924,41 @@ async function startServer() {
|
|
|
590
924
|
serverInstance.once("error", reject);
|
|
591
925
|
});
|
|
592
926
|
serverInstance.on("error", (err) => {
|
|
593
|
-
|
|
927
|
+
serverLogger4.error("persistent server error:", err);
|
|
594
928
|
});
|
|
595
929
|
serverState.port = port;
|
|
596
930
|
serverState.running = true;
|
|
597
|
-
const portFile =
|
|
931
|
+
const portFile = import_node_path4.default.join(import_node_os2.default.tmpdir(), "inspecto.port.json");
|
|
598
932
|
try {
|
|
599
933
|
let portData = {};
|
|
600
|
-
if (
|
|
934
|
+
if (import_node_fs3.default.existsSync(portFile)) {
|
|
601
935
|
try {
|
|
602
|
-
portData = JSON.parse(
|
|
936
|
+
portData = JSON.parse(import_node_fs3.default.readFileSync(portFile, "utf-8"));
|
|
603
937
|
} catch (e) {
|
|
604
938
|
}
|
|
605
939
|
}
|
|
606
|
-
const rootHash =
|
|
940
|
+
const rootHash = import_node_crypto2.default.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
607
941
|
portData[rootHash] = port;
|
|
608
|
-
|
|
942
|
+
import_node_fs3.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
609
943
|
} catch (e) {
|
|
610
|
-
|
|
944
|
+
serverLogger4.warn("Failed to write port file:", e);
|
|
611
945
|
}
|
|
612
946
|
process.once("exit", () => {
|
|
613
947
|
try {
|
|
614
|
-
if (
|
|
615
|
-
const portData = JSON.parse(
|
|
616
|
-
const rootHash =
|
|
948
|
+
if (import_node_fs3.default.existsSync(portFile)) {
|
|
949
|
+
const portData = JSON.parse(import_node_fs3.default.readFileSync(portFile, "utf-8"));
|
|
950
|
+
const rootHash = import_node_crypto2.default.createHash("md5").update(serverState.projectRoot).digest("hex");
|
|
617
951
|
delete portData[rootHash];
|
|
618
952
|
if (Object.keys(portData).length === 0) {
|
|
619
|
-
|
|
953
|
+
import_node_fs3.default.unlinkSync(portFile);
|
|
620
954
|
} else {
|
|
621
|
-
|
|
955
|
+
import_node_fs3.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
|
|
622
956
|
}
|
|
623
957
|
}
|
|
624
958
|
} catch {
|
|
625
959
|
}
|
|
626
960
|
});
|
|
627
|
-
|
|
961
|
+
serverLogger4.info(`server running at http://127.0.0.1:${port}`);
|
|
628
962
|
return port;
|
|
629
963
|
}
|
|
630
964
|
async function readBody(req) {
|
|
@@ -643,26 +977,7 @@ async function handleRequest(url, req, res) {
|
|
|
643
977
|
return;
|
|
644
978
|
}
|
|
645
979
|
if (pathname === import_types2.INSPECTO_API_PATHS.CLIENT_CONFIG && req.method === "GET") {
|
|
646
|
-
const
|
|
647
|
-
const promptsConfig = await loadPromptsConfig(false, serverState.cwd, serverState.configRoot);
|
|
648
|
-
const effectiveIde = userConfig.ide ?? "vscode";
|
|
649
|
-
let info;
|
|
650
|
-
if (!serverState.ideInfo) {
|
|
651
|
-
info = {
|
|
652
|
-
ide: effectiveIde
|
|
653
|
-
};
|
|
654
|
-
} else {
|
|
655
|
-
const { scheme: _scheme, ...rest } = serverState.ideInfo;
|
|
656
|
-
info = rest;
|
|
657
|
-
}
|
|
658
|
-
const config = {
|
|
659
|
-
...info,
|
|
660
|
-
prompts: resolveIntents(promptsConfig),
|
|
661
|
-
hotKeys: userConfig["inspector.hotKey"] ?? "alt",
|
|
662
|
-
theme: userConfig["inspector.theme"] ?? "auto",
|
|
663
|
-
includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
|
|
664
|
-
autoSend: userConfig["prompt.autoSend"] ?? false
|
|
665
|
-
};
|
|
980
|
+
const config = await buildClientConfig(serverState);
|
|
666
981
|
delete config.providers;
|
|
667
982
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
668
983
|
res.end(JSON.stringify(config));
|
|
@@ -673,23 +988,23 @@ async function handleRequest(url, req, res) {
|
|
|
673
988
|
const body = JSON.parse(await readBody(req));
|
|
674
989
|
const ideWorkspace = body.workspaceRoot || "";
|
|
675
990
|
const serverProjectRoot = serverState.projectRoot || "";
|
|
676
|
-
const normalizedIdeRoot = ideWorkspace ?
|
|
677
|
-
const normalizedServerRoot = serverProjectRoot ?
|
|
678
|
-
const isSameProject = !normalizedIdeRoot || !normalizedServerRoot || normalizedIdeRoot === normalizedServerRoot || normalizedServerRoot.startsWith(normalizedIdeRoot +
|
|
991
|
+
const normalizedIdeRoot = ideWorkspace ? import_node_path4.default.resolve(ideWorkspace) : "";
|
|
992
|
+
const normalizedServerRoot = serverProjectRoot ? import_node_path4.default.resolve(serverProjectRoot) : "";
|
|
993
|
+
const isSameProject = !normalizedIdeRoot || !normalizedServerRoot || normalizedIdeRoot === normalizedServerRoot || normalizedServerRoot.startsWith(normalizedIdeRoot + import_node_path4.default.sep) || normalizedIdeRoot.startsWith(normalizedServerRoot + import_node_path4.default.sep);
|
|
679
994
|
if (isSameProject) {
|
|
680
995
|
serverState.ideInfo = body;
|
|
681
|
-
|
|
996
|
+
serverLogger4.debug(
|
|
682
997
|
`Accepted IDE info from matched workspace (ide-${body.ide} / schema-${body.scheme})`
|
|
683
998
|
);
|
|
684
999
|
} else {
|
|
685
|
-
|
|
1000
|
+
serverLogger4.debug(
|
|
686
1001
|
`Ignored IDE info from unrelated workspace (IDE Workspace: ${ideWorkspace}, Server: ${serverProjectRoot}, Scheme: ${body.scheme}, IDE: ${body.ide})`
|
|
687
1002
|
);
|
|
688
1003
|
}
|
|
689
1004
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
690
1005
|
res.end(JSON.stringify({ success: true }));
|
|
691
1006
|
} catch (e) {
|
|
692
|
-
|
|
1007
|
+
serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.IDE_INFO} POST request:`, e);
|
|
693
1008
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
694
1009
|
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
695
1010
|
}
|
|
@@ -704,79 +1019,14 @@ async function handleRequest(url, req, res) {
|
|
|
704
1019
|
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
705
1020
|
return;
|
|
706
1021
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
1022
|
+
try {
|
|
1023
|
+
handleOpenFileRequest(body, serverState);
|
|
1024
|
+
} catch {
|
|
1025
|
+
serverLogger4.warn(`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}`);
|
|
711
1026
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
712
1027
|
res.end(JSON.stringify({ error: "Access denied: File is outside of project workspace" }));
|
|
713
1028
|
return;
|
|
714
1029
|
}
|
|
715
|
-
const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot);
|
|
716
|
-
const configuredIde = userConfig.ide;
|
|
717
|
-
const activeIde = serverState.ideInfo?.ide;
|
|
718
|
-
const activeIdeScheme = serverState.ideInfo?.scheme;
|
|
719
|
-
const rawEditorHint = configuredIde || activeIde || activeIdeScheme || "code";
|
|
720
|
-
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
721
|
-
serverLogger.warn(
|
|
722
|
-
`Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`
|
|
723
|
-
);
|
|
724
|
-
}
|
|
725
|
-
let editorHint = rawEditorHint;
|
|
726
|
-
if (rawEditorHint === "vscode") editorHint = "code";
|
|
727
|
-
else if (rawEditorHint === "vscode-insiders") editorHint = "code-insiders";
|
|
728
|
-
else if (rawEditorHint === "vscodium") editorHint = "codium";
|
|
729
|
-
else if (rawEditorHint === "trae-cn" || rawEditorHint === "trae") editorHint = "trae";
|
|
730
|
-
serverLogger.debug(
|
|
731
|
-
`IDE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`
|
|
732
|
-
);
|
|
733
|
-
const VSCODE_FAMILY_SCHEMES = [
|
|
734
|
-
"vscode",
|
|
735
|
-
"vscode-insiders",
|
|
736
|
-
"cursor",
|
|
737
|
-
"windsurf",
|
|
738
|
-
"trae",
|
|
739
|
-
"trae-cn",
|
|
740
|
-
"vscodium",
|
|
741
|
-
"codebuddy",
|
|
742
|
-
"codebuddy-cn",
|
|
743
|
-
"antigravity"
|
|
744
|
-
];
|
|
745
|
-
if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {
|
|
746
|
-
let normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
747
|
-
if (!normalizedPath.startsWith("/")) {
|
|
748
|
-
normalizedPath = "/" + normalizedPath;
|
|
749
|
-
}
|
|
750
|
-
const encodedPath = encodeURI(normalizedPath);
|
|
751
|
-
const uri = `${rawEditorHint}://file${encodedPath}:${body.line}:${body.column}`;
|
|
752
|
-
serverLogger.debug(`IDE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
|
|
753
|
-
try {
|
|
754
|
-
if (process.platform === "darwin") {
|
|
755
|
-
(0, import_node_child_process.execFileSync)("open", [uri]);
|
|
756
|
-
} else if (process.platform === "win32") {
|
|
757
|
-
(0, import_node_child_process.execFileSync)("cmd", ["/c", "start", '""', uri]);
|
|
758
|
-
} else {
|
|
759
|
-
(0, import_node_child_process.execFileSync)("xdg-open", [uri]);
|
|
760
|
-
}
|
|
761
|
-
} catch (e) {
|
|
762
|
-
serverLogger.error(`Failed to launch URI for IDE_OPEN (${uri}):`, e);
|
|
763
|
-
(0, import_launch_ide.launchIDE)({
|
|
764
|
-
file: absolutePath,
|
|
765
|
-
line: body.line,
|
|
766
|
-
column: body.column,
|
|
767
|
-
editor: editorHint,
|
|
768
|
-
type: process.platform === "darwin" ? "open" : "exec"
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
} else {
|
|
772
|
-
(0, import_launch_ide.launchIDE)({
|
|
773
|
-
file: absolutePath,
|
|
774
|
-
line: body.line,
|
|
775
|
-
column: body.column,
|
|
776
|
-
editor: editorHint,
|
|
777
|
-
type: process.platform === "darwin" ? "open" : "exec"
|
|
778
|
-
});
|
|
779
|
-
}
|
|
780
1030
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
781
1031
|
res.end(JSON.stringify({ success: true }));
|
|
782
1032
|
return;
|
|
@@ -787,10 +1037,11 @@ async function handleRequest(url, req, res) {
|
|
|
787
1037
|
const column = parseInt(url.searchParams.get("column") ?? "1", 10);
|
|
788
1038
|
const maxLines = parseInt(url.searchParams.get("maxLines") ?? "100", 10);
|
|
789
1039
|
try {
|
|
790
|
-
const absolutePath =
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
1040
|
+
const absolutePath = resolveWorkspacePath(file, serverState.cwd);
|
|
1041
|
+
try {
|
|
1042
|
+
assertPathWithinProject(absolutePath, serverState.projectRoot);
|
|
1043
|
+
} catch {
|
|
1044
|
+
serverLogger4.warn(`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}`);
|
|
794
1045
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
795
1046
|
res.end(
|
|
796
1047
|
JSON.stringify({
|
|
@@ -820,7 +1071,23 @@ async function handleRequest(url, req, res) {
|
|
|
820
1071
|
res.writeHead(result.success ? 200 : 500, { "Content-Type": "application/json" });
|
|
821
1072
|
res.end(JSON.stringify(result));
|
|
822
1073
|
} catch (e) {
|
|
823
|
-
|
|
1074
|
+
serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.AI_DISPATCH} request:`, e);
|
|
1075
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1076
|
+
res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
|
|
1077
|
+
}
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
if (pathname === import_types2.INSPECTO_API_PATHS.AI_BATCH_DISPATCH && req.method === "POST") {
|
|
1081
|
+
try {
|
|
1082
|
+
const rawBody = await readBody(req);
|
|
1083
|
+
const body = JSON.parse(rawBody);
|
|
1084
|
+
const result = await dispatchAnnotationsToAi(body, serverState);
|
|
1085
|
+
res.writeHead(getBatchDispatchStatusCode(result.errorCode, result.success), {
|
|
1086
|
+
"Content-Type": "application/json"
|
|
1087
|
+
});
|
|
1088
|
+
res.end(JSON.stringify(result));
|
|
1089
|
+
} catch (e) {
|
|
1090
|
+
serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.AI_BATCH_DISPATCH} request:`, e);
|
|
824
1091
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
825
1092
|
res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
|
|
826
1093
|
}
|
|
@@ -828,7 +1095,7 @@ async function handleRequest(url, req, res) {
|
|
|
828
1095
|
}
|
|
829
1096
|
if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
|
|
830
1097
|
const ticketId = pathname.substring(import_types2.INSPECTO_API_PATHS.AI_TICKET.length + 1);
|
|
831
|
-
const payloadStr =
|
|
1098
|
+
const payloadStr = readTicket(ticketId);
|
|
832
1099
|
if (!payloadStr) {
|
|
833
1100
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
834
1101
|
res.end(JSON.stringify({ success: false, error: "Ticket not found or expired" }));
|
|
@@ -842,54 +1109,28 @@ async function handleRequest(url, req, res) {
|
|
|
842
1109
|
res.end(JSON.stringify({ error: "not found" }));
|
|
843
1110
|
}
|
|
844
1111
|
async function dispatchToAi(req) {
|
|
845
|
-
const { location, snippet, prompt } = req;
|
|
846
|
-
const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot);
|
|
847
|
-
const resolvedTarget = resolveTargetTool(userConfig);
|
|
1112
|
+
const { location, snippet, prompt, screenshotContext } = req;
|
|
848
1113
|
const formattedPrompt = prompt ?? `Please help me with this code from \`${location.file}\` (line ${location.line}):
|
|
849
1114
|
|
|
850
1115
|
\`\`\`
|
|
851
1116
|
${snippet}
|
|
852
1117
|
\`\`\`
|
|
853
1118
|
`;
|
|
854
|
-
const
|
|
855
|
-
|
|
856
|
-
const activeIde = serverState.ideInfo?.ide;
|
|
857
|
-
const activeIdeScheme = serverState.ideInfo?.scheme;
|
|
858
|
-
const finalIde = configuredIde || activeIdeScheme || activeIde || "vscode";
|
|
859
|
-
if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {
|
|
860
|
-
serverLogger.warn(
|
|
861
|
-
`dispatchToAi: Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`
|
|
862
|
-
);
|
|
863
|
-
}
|
|
864
|
-
const mode = resolveProviderMode(resolvedTarget, finalIde, userConfig);
|
|
865
|
-
const overrides = extractToolOverrides(finalIde, userConfig)[resolvedTarget] || {};
|
|
866
|
-
overrides.type = mode;
|
|
867
|
-
const fullPayload = {
|
|
868
|
-
ide: finalIde,
|
|
869
|
-
target: resolvedTarget,
|
|
870
|
-
targetType: mode,
|
|
1119
|
+
const runtime = resolvePromptDispatchRuntime(serverState);
|
|
1120
|
+
return dispatchPromptThroughIde(runtime, {
|
|
871
1121
|
prompt: formattedPrompt,
|
|
872
1122
|
filePath: location.file,
|
|
873
1123
|
line: location.line,
|
|
874
1124
|
column: location.column,
|
|
875
1125
|
snippet,
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
serverLogger.debug(`dispatchToAi: Generated URI: ${uri}`);
|
|
885
|
-
launchURI(uri);
|
|
886
|
-
return {
|
|
887
|
-
success: true,
|
|
888
|
-
fallbackPayload: {
|
|
889
|
-
prompt: formattedPrompt,
|
|
890
|
-
file: location.file
|
|
891
|
-
}
|
|
892
|
-
};
|
|
1126
|
+
...screenshotContext ? { screenshotContext } : {}
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
function getBatchDispatchStatusCode(errorCode, success) {
|
|
1130
|
+
if (success) return 200;
|
|
1131
|
+
if (errorCode === "INVALID_REQUEST") return 400;
|
|
1132
|
+
if (errorCode === "FORBIDDEN_PATH") return 403;
|
|
1133
|
+
return 500;
|
|
893
1134
|
}
|
|
894
1135
|
|
|
895
1136
|
// src/injectors/utils.ts
|
|
@@ -924,7 +1165,7 @@ window.addEventListener('load', () => {
|
|
|
924
1165
|
}
|
|
925
1166
|
|
|
926
1167
|
// src/legacy/rspack/index.ts
|
|
927
|
-
var
|
|
1168
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
928
1169
|
var _dirname = typeof __dirname !== "undefined" ? __dirname : __dirname;
|
|
929
1170
|
var DEFAULT_OPTIONS = {
|
|
930
1171
|
include: [],
|
|
@@ -994,7 +1235,7 @@ var InspectoRspackLegacyPlugin = class {
|
|
|
994
1235
|
);
|
|
995
1236
|
}
|
|
996
1237
|
});
|
|
997
|
-
const loaderPath =
|
|
1238
|
+
const loaderPath = import_node_path5.default.resolve(_dirname, "./loader.cjs");
|
|
998
1239
|
compiler.options.module.rules.push({
|
|
999
1240
|
test: /\.[jt]sx?$/,
|
|
1000
1241
|
use: [
|