@inspecto-dev/plugin 0.3.8 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/astro.cjs +572 -86
  2. package/dist/astro.cjs.map +1 -1
  3. package/dist/astro.d.cts +1 -1
  4. package/dist/astro.d.ts +1 -1
  5. package/dist/astro.js +571 -85
  6. package/dist/astro.js.map +1 -1
  7. package/dist/index.cjs +559 -83
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +1 -0
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.js +558 -82
  12. package/dist/index.js.map +1 -1
  13. package/dist/legacy/rspack/index.cjs +526 -74
  14. package/dist/legacy/rspack/index.cjs.map +1 -1
  15. package/dist/legacy/rspack/index.js +526 -74
  16. package/dist/legacy/rspack/index.js.map +1 -1
  17. package/dist/legacy/rspack/loader.cjs +4 -1
  18. package/dist/legacy/rspack/loader.cjs.map +1 -1
  19. package/dist/legacy/rspack/loader.js +3 -0
  20. package/dist/legacy/rspack/loader.js.map +1 -1
  21. package/dist/legacy/webpack4/index.cjs +526 -74
  22. package/dist/legacy/webpack4/index.cjs.map +1 -1
  23. package/dist/legacy/webpack4/index.js +526 -74
  24. package/dist/legacy/webpack4/index.js.map +1 -1
  25. package/dist/legacy/webpack4/loader.cjs +4 -1
  26. package/dist/legacy/webpack4/loader.cjs.map +1 -1
  27. package/dist/legacy/webpack4/loader.js +3 -0
  28. package/dist/legacy/webpack4/loader.js.map +1 -1
  29. package/dist/rollup.cjs +559 -83
  30. package/dist/rollup.cjs.map +1 -1
  31. package/dist/rollup.js +558 -82
  32. package/dist/rollup.js.map +1 -1
  33. package/dist/rspack.cjs +559 -83
  34. package/dist/rspack.cjs.map +1 -1
  35. package/dist/rspack.js +558 -82
  36. package/dist/rspack.js.map +1 -1
  37. package/dist/vite.cjs +559 -83
  38. package/dist/vite.cjs.map +1 -1
  39. package/dist/vite.js +558 -82
  40. package/dist/vite.js.map +1 -1
  41. package/dist/webpack.cjs +559 -83
  42. package/dist/webpack.cjs.map +1 -1
  43. package/dist/webpack.js +558 -82
  44. package/dist/webpack.js.map +1 -1
  45. package/package.json +8 -12
package/dist/astro.cjs CHANGED
@@ -36,7 +36,7 @@ __export(astro_exports, {
36
36
  });
37
37
  module.exports = __toCommonJS(astro_exports);
38
38
 
39
- // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.10_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js
39
+ // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.14_typescript@5.9.3_yaml@2.8.4/node_modules/tsup/assets/cjs_shims.js
40
40
  var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
41
41
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
42
42
 
@@ -551,7 +551,6 @@ function dispatchPromptThroughIde(runtime, payload) {
551
551
  line: payload.line,
552
552
  column: payload.column,
553
553
  snippet: payload.snippet,
554
- ...payload.screenshotContext ? { screenshotContext: payload.screenshotContext } : {},
555
554
  overrides: runtime.overrides,
556
555
  autoSend: runtime.autoSend
557
556
  });
@@ -685,6 +684,188 @@ function assertPathWithinIdeOpenScope(file, projectRoot) {
685
684
  }
686
685
  }
687
686
 
687
+ // src/server/session-store.ts
688
+ var DEFAULT_STATUS = "pending";
689
+ function createAnnotationSessionStore(options = {}) {
690
+ const sessions = /* @__PURE__ */ new Map();
691
+ const listeners = /* @__PURE__ */ new Set();
692
+ const now = options.now ?? (() => Date.now());
693
+ const createId = options.createId ?? createRandomId;
694
+ function findNewestMatchingSession(statuses) {
695
+ return [...sessions.values()].filter((session) => statuses ? statuses.has(session.status) : true).sort((left, right) => right.updatedAt - left.updatedAt)[0] ?? null;
696
+ }
697
+ function updateSessionStatus(id, status) {
698
+ const session = sessions.get(id);
699
+ if (!session) return null;
700
+ const timestamp = now();
701
+ session.status = status;
702
+ session.updatedAt = timestamp;
703
+ if (status === "acknowledged") {
704
+ session.acknowledgedAt = timestamp;
705
+ }
706
+ if (status === "resolved") {
707
+ session.resolvedAt = timestamp;
708
+ }
709
+ emit({ type: "session-status-updated", session });
710
+ return cloneSession(session);
711
+ }
712
+ function claimSession(id, statuses) {
713
+ const session = sessions.get(id);
714
+ if (!session || statuses && !statuses.has(session.status)) return null;
715
+ if (session.status === "acknowledged") return cloneSession(session);
716
+ return updateSessionStatus(id, "acknowledged");
717
+ }
718
+ function emit(event) {
719
+ const snapshot = cloneSession(event.session);
720
+ for (const listener of listeners) {
721
+ listener({ type: event.type, session: snapshot });
722
+ }
723
+ }
724
+ const store = {
725
+ createSession(input) {
726
+ const timestamp = now();
727
+ const session = {
728
+ id: createId(),
729
+ instruction: input.instruction?.trim() ?? "",
730
+ annotations: cloneArray(input.annotations),
731
+ ...input.deliveryMode ? { deliveryMode: input.deliveryMode } : {},
732
+ status: DEFAULT_STATUS,
733
+ messages: cloneArray(input.messages ?? []),
734
+ createdAt: timestamp,
735
+ updatedAt: timestamp,
736
+ ...input.runtimeContext ? { runtimeContext: cloneValue(input.runtimeContext) } : {},
737
+ ...input.cssContextPrompt?.trim() ? { cssContextPrompt: input.cssContextPrompt.trim() } : {},
738
+ ...input.pageUrl ? { pageUrl: input.pageUrl } : {},
739
+ ...input.route ? { route: input.route } : {}
740
+ };
741
+ sessions.set(session.id, session);
742
+ emit({ type: "session-created", session });
743
+ return cloneSession(session);
744
+ },
745
+ getSession(id) {
746
+ const session = sessions.get(id);
747
+ return session ? cloneSession(session) : null;
748
+ },
749
+ listSessions(options2 = {}) {
750
+ const statuses = normalizeStatuses(options2.status);
751
+ return [...sessions.values()].filter((session) => statuses ? statuses.has(session.status) : true).sort((left, right) => right.updatedAt - left.updatedAt).map((session) => cloneSession(session));
752
+ },
753
+ async claimNextSession(options2 = {}) {
754
+ const statuses = normalizeStatuses(DEFAULT_STATUS);
755
+ const existingSession = findNewestMatchingSession(statuses);
756
+ if (existingSession) {
757
+ return {
758
+ session: claimSession(existingSession.id, statuses),
759
+ timedOut: false,
760
+ matchedExisting: true
761
+ };
762
+ }
763
+ const timeoutMs = normalizeTimeoutMs(options2.timeoutMs);
764
+ if (timeoutMs === 0) {
765
+ return {
766
+ session: null,
767
+ timedOut: true,
768
+ matchedExisting: false
769
+ };
770
+ }
771
+ return await new Promise((resolve2) => {
772
+ let settled = false;
773
+ let timeout = null;
774
+ const finish = (result) => {
775
+ if (settled) return;
776
+ settled = true;
777
+ unsubscribe();
778
+ if (timeout) {
779
+ clearTimeout(timeout);
780
+ }
781
+ resolve2(result);
782
+ };
783
+ const unsubscribe = this.subscribe((event) => {
784
+ const session = claimSession(event.session.id, statuses);
785
+ if (!session) return;
786
+ finish({
787
+ session,
788
+ timedOut: false,
789
+ matchedExisting: false,
790
+ event: event.type
791
+ });
792
+ });
793
+ if (timeoutMs !== null) {
794
+ timeout = setTimeout(() => {
795
+ finish({
796
+ session: null,
797
+ timedOut: true,
798
+ matchedExisting: false
799
+ });
800
+ }, timeoutMs);
801
+ }
802
+ });
803
+ },
804
+ appendMessage(id, input) {
805
+ const session = sessions.get(id);
806
+ if (!session) return null;
807
+ const timestamp = now();
808
+ session.messages.push({
809
+ id: createId(),
810
+ role: input.role,
811
+ text: input.text,
812
+ createdAt: timestamp
813
+ });
814
+ session.updatedAt = timestamp;
815
+ if (input.role === "agent" && isPendingLikeStatus(session.status)) {
816
+ session.status = "in_progress";
817
+ }
818
+ emit({ type: "session-message-appended", session });
819
+ return cloneSession(session);
820
+ },
821
+ updateStatus(id, status) {
822
+ return updateSessionStatus(id, status);
823
+ },
824
+ subscribe(listener) {
825
+ listeners.add(listener);
826
+ return () => {
827
+ listeners.delete(listener);
828
+ };
829
+ },
830
+ clear() {
831
+ sessions.clear();
832
+ listeners.clear();
833
+ }
834
+ };
835
+ return store;
836
+ }
837
+ var annotationSessionStore = createAnnotationSessionStore();
838
+ function normalizeStatuses(status) {
839
+ if (!status) return null;
840
+ return new Set(Array.isArray(status) ? status : [status]);
841
+ }
842
+ function normalizeTimeoutMs(value) {
843
+ if (value === void 0) return null;
844
+ if (!Number.isFinite(value)) return 0;
845
+ return Math.max(0, Math.floor(value));
846
+ }
847
+ function isPendingLikeStatus(status) {
848
+ return status === "pending" || status === "acknowledged";
849
+ }
850
+ function hasAgentReply(session) {
851
+ return session.messages.some((message) => message.role === "agent" && Boolean(message.text?.trim()));
852
+ }
853
+ function createRandomId() {
854
+ return `annotation-session-${Math.random().toString(36).slice(2, 10)}`;
855
+ }
856
+ function cloneSession(session) {
857
+ return cloneValue(session);
858
+ }
859
+ function cloneArray(value) {
860
+ return cloneValue(value);
861
+ }
862
+ function cloneValue(value) {
863
+ if (typeof structuredClone === "function") {
864
+ return structuredClone(value);
865
+ }
866
+ return JSON.parse(JSON.stringify(value));
867
+ }
868
+
688
869
  // src/server/annotation-dispatch.ts
689
870
  var AnnotationDispatchError = class extends Error {
690
871
  constructor(message, errorCode) {
@@ -693,20 +874,30 @@ var AnnotationDispatchError = class extends Error {
693
874
  this.errorCode = errorCode;
694
875
  }
695
876
  };
696
- async function dispatchAnnotationsToAi(req, state) {
877
+ async function dispatchAnnotationsToAi(req, state, store = annotationSessionStore) {
697
878
  try {
698
879
  validateAnnotationDispatchRequest(req, state);
699
880
  const batch = normalizeAnnotationBatch(req);
700
881
  const prompt = buildAnnotationBatchPrompt(batch);
882
+ const deliveryMode = normalizeDeliveryMode(req.deliveryMode);
883
+ const session = store.createSession({
884
+ instruction: batch.instruction,
885
+ annotations: toSessionAnnotations(batch.annotations),
886
+ deliveryMode,
887
+ ...batch.runtimeContext ? { runtimeContext: batch.runtimeContext } : {},
888
+ ...batch.cssContextPrompt ? { cssContextPrompt: batch.cssContextPrompt } : {}
889
+ });
701
890
  const representativeTarget = batch.annotations[0]?.targets[0];
702
- const runtime = resolvePromptDispatchRuntime(state);
703
- return dispatchPromptThroughIde(runtime, {
891
+ const dispatchResult = deliveryMode === "ide" ? dispatchPromptThroughIde(resolvePromptDispatchRuntime(state), {
704
892
  prompt,
705
893
  ...representativeTarget?.file ? { filePath: representativeTarget.file } : {},
706
894
  ...representativeTarget?.line ? { line: representativeTarget.line } : {},
707
- ...representativeTarget?.column ? { column: representativeTarget.column } : {},
708
- ...batch.screenshotContext ? { screenshotContext: batch.screenshotContext } : {}
709
- });
895
+ ...representativeTarget?.column ? { column: representativeTarget.column } : {}
896
+ }) : { success: true };
897
+ return {
898
+ ...dispatchResult,
899
+ session: toSessionSummary(session)
900
+ };
710
901
  } catch (error) {
711
902
  return {
712
903
  success: false,
@@ -715,6 +906,41 @@ async function dispatchAnnotationsToAi(req, state) {
715
906
  };
716
907
  }
717
908
  }
909
+ function normalizeDeliveryMode(input) {
910
+ return input === "agent" ? "agent" : "ide";
911
+ }
912
+ function toSessionAnnotations(annotations) {
913
+ return annotations.map((annotation) => ({
914
+ id: `annotation-${annotation.index}`,
915
+ note: annotation.note,
916
+ intent: annotation.intent,
917
+ targets: annotation.targets.map((target, targetIndex) => ({
918
+ id: `annotation-${annotation.index}-target-${targetIndex + 1}`,
919
+ label: target.label ?? "Unknown target",
920
+ location: {
921
+ file: target.file,
922
+ line: target.line,
923
+ column: target.column
924
+ },
925
+ ...target.selector ? { selector: target.selector } : {},
926
+ ...target.snippet ? { snippet: target.snippet } : {},
927
+ rect: {
928
+ x: 0,
929
+ y: 0,
930
+ width: 0,
931
+ height: 0
932
+ }
933
+ }))
934
+ }));
935
+ }
936
+ function toSessionSummary(session) {
937
+ return {
938
+ id: session.id,
939
+ status: session.status,
940
+ createdAt: session.createdAt,
941
+ updatedAt: session.updatedAt
942
+ };
943
+ }
718
944
  function validateAnnotationDispatchRequest(req, state) {
719
945
  if (!req.annotations.length) {
720
946
  throw new AnnotationDispatchError("At least one annotation is required.", "INVALID_REQUEST");
@@ -735,9 +961,7 @@ function validateAnnotationDispatchRequest(req, state) {
735
961
  function normalizeAnnotationBatch(req) {
736
962
  return {
737
963
  instruction: req.instruction?.trim() ?? "",
738
- responseMode: req.responseMode ?? "unified",
739
964
  ...req.runtimeContext ? { runtimeContext: req.runtimeContext } : {},
740
- ...req.screenshotContext ? { screenshotContext: req.screenshotContext } : {},
741
965
  ...req.cssContextPrompt?.trim() ? { cssContextPrompt: req.cssContextPrompt.trim() } : {},
742
966
  annotations: req.annotations.map((annotation, index) => ({
743
967
  index: index + 1,
@@ -759,12 +983,9 @@ function buildAnnotationBatchPrompt(batch) {
759
983
  const prompt = batch.instruction ? `${batch.instruction}
760
984
 
761
985
  ${body}` : body;
762
- return appendScreenshotContextSection(
763
- appendCssContextSection(
764
- appendRuntimeContextSection(prompt, batch.runtimeContext),
765
- batch.cssContextPrompt
766
- ),
767
- batch.screenshotContext
986
+ return appendCssContextSection(
987
+ appendRuntimeContextSection(prompt, batch.runtimeContext),
988
+ batch.cssContextPrompt
768
989
  );
769
990
  }
770
991
  function appendCssContextSection(prompt, cssContextPrompt) {
@@ -791,20 +1012,6 @@ function buildSelectedElementsPrompt(annotations) {
791
1012
  }
792
1013
  return lines.join("\n");
793
1014
  }
794
- function appendScreenshotContextSection(prompt, screenshotContext) {
795
- if (!screenshotContext || !screenshotContext.imageDataUrl && !screenshotContext.imageAssetId) {
796
- return prompt;
797
- }
798
- const lines = [
799
- "Visual screenshot context attached:",
800
- `- capturedAt=${screenshotContext.capturedAt}`,
801
- `- mimeType=${screenshotContext.mimeType}`,
802
- ...screenshotContext.imageAssetId ? [`- imageAssetId=${screenshotContext.imageAssetId}`] : []
803
- ];
804
- return `${prompt}
805
-
806
- ${lines.join("\n")}`;
807
- }
808
1015
  function appendRuntimeContextSection(prompt, runtimeContext) {
809
1016
  if (!runtimeContext?.records.length) {
810
1017
  return prompt;
@@ -852,7 +1059,7 @@ async function buildClientConfig(serverState2) {
852
1059
  ...info,
853
1060
  prompts: resolveIntents(promptsConfig),
854
1061
  hotKeys: userConfig["inspector.hotKey"] ?? "alt",
855
- theme: userConfig["inspector.theme"] ?? "auto",
1062
+ annotateDeliveryMode: userConfig["annotate.deliveryMode"] ?? "both",
856
1063
  includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
857
1064
  runtimeContext: {
858
1065
  enabled: true,
@@ -860,10 +1067,6 @@ async function buildClientConfig(serverState2) {
860
1067
  maxRuntimeErrors: 3,
861
1068
  maxFailedRequests: 2
862
1069
  },
863
- screenshotContext: {
864
- enabled: false
865
- },
866
- annotationResponseMode: userConfig["prompt.annotationResponseMode"] ?? "unified",
867
1070
  autoSend: userConfig["prompt.autoSend"] ?? false
868
1071
  };
869
1072
  }
@@ -908,7 +1111,7 @@ function handleOpenFileRequest(body, serverState2) {
908
1111
  else if (rawEditorHint === "vscodium") editorHint = "codium";
909
1112
  else if (rawEditorHint === "trae-cn" || rawEditorHint === "trae") editorHint = "trae";
910
1113
  serverLogger2.debug(
911
- `IDE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`
1114
+ `SOURCE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`
912
1115
  );
913
1116
  if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {
914
1117
  let normalizedPath = absolutePath.replace(/\\/g, "/");
@@ -917,7 +1120,7 @@ function handleOpenFileRequest(body, serverState2) {
917
1120
  }
918
1121
  const encodedPath = encodeURI(normalizedPath);
919
1122
  const uri = `${rawEditorHint}://file${encodedPath}:${body.line}:${body.column}`;
920
- serverLogger2.debug(`IDE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
1123
+ serverLogger2.debug(`SOURCE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
921
1124
  try {
922
1125
  if (process.platform === "darwin") {
923
1126
  (0, import_node_child_process2.execFileSync)("open", [uri]);
@@ -927,7 +1130,7 @@ function handleOpenFileRequest(body, serverState2) {
927
1130
  (0, import_node_child_process2.execFileSync)("xdg-open", [uri]);
928
1131
  }
929
1132
  } catch (e) {
930
- serverLogger2.error(`Failed to launch URI for IDE_OPEN (${uri}):`, e);
1133
+ serverLogger2.error(`Failed to launch URI for SOURCE_OPEN (${uri}):`, e);
931
1134
  (0, import_launch_ide2.launchIDE)({
932
1135
  file: absolutePath,
933
1136
  line: body.line,
@@ -982,8 +1185,27 @@ function resolveProjectRoot() {
982
1185
  return gitRoot;
983
1186
  }
984
1187
 
1188
+ // src/server/server-url.ts
1189
+ function resolveServerHost(cwd, configRoot) {
1190
+ const userConfig = loadUserConfigSync(false, cwd, configRoot);
1191
+ const configuredHost = userConfig["server.host"]?.trim();
1192
+ if (configuredHost) return configuredHost;
1193
+ if (process.env["VITEST"]) return "127.0.0.1";
1194
+ return "127.0.0.1";
1195
+ }
1196
+ function resolvePublicServerUrl(args) {
1197
+ const userConfig = loadUserConfigSync(false, args.cwd, args.configRoot);
1198
+ const configuredPublicUrl = userConfig["server.publicUrl"]?.trim();
1199
+ if (configuredPublicUrl) {
1200
+ return configuredPublicUrl.replace(/\/$/, "");
1201
+ }
1202
+ const host = resolveServerHost(args.cwd, args.configRoot);
1203
+ return `http://${host}:${args.port}`;
1204
+ }
1205
+
985
1206
  // src/server/index.ts
986
1207
  var serverLogger4 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
1208
+ var PORT_FILE_NAME = "inspecto.port.json";
987
1209
  var serverState = {
988
1210
  port: null,
989
1211
  running: false,
@@ -992,6 +1214,42 @@ var serverState = {
992
1214
  cwd: process.cwd()
993
1215
  };
994
1216
  var serverInstance = null;
1217
+ function getPortFilePath() {
1218
+ return import_node_path4.default.join(import_node_os2.default.tmpdir(), PORT_FILE_NAME);
1219
+ }
1220
+ function getProjectRootHash() {
1221
+ if (!serverState.projectRoot) return null;
1222
+ return import_node_crypto2.default.createHash("md5").update(serverState.projectRoot).digest("hex");
1223
+ }
1224
+ function readPortData(portFile) {
1225
+ if (!import_node_fs4.default.existsSync(portFile)) return {};
1226
+ try {
1227
+ return JSON.parse(import_node_fs4.default.readFileSync(portFile, "utf-8"));
1228
+ } catch {
1229
+ return {};
1230
+ }
1231
+ }
1232
+ function writeProjectPort(port) {
1233
+ const rootHash = getProjectRootHash();
1234
+ if (!rootHash) return;
1235
+ const portFile = getPortFilePath();
1236
+ const portData = readPortData(portFile);
1237
+ portData[rootHash] = port;
1238
+ import_node_fs4.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
1239
+ }
1240
+ function removeProjectPort() {
1241
+ const rootHash = getProjectRootHash();
1242
+ if (!rootHash) return;
1243
+ const portFile = getPortFilePath();
1244
+ if (!import_node_fs4.default.existsSync(portFile)) return;
1245
+ const portData = readPortData(portFile);
1246
+ delete portData[rootHash];
1247
+ if (Object.keys(portData).length === 0) {
1248
+ import_node_fs4.default.unlinkSync(portFile);
1249
+ } else {
1250
+ import_node_fs4.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
1251
+ }
1252
+ }
995
1253
  async function startServer() {
996
1254
  if (serverState.running && serverState.port !== null) {
997
1255
  return serverState.port;
@@ -999,6 +1257,7 @@ async function startServer() {
999
1257
  serverState.projectRoot = resolveProjectRoot();
1000
1258
  serverState.configRoot = serverState.projectRoot;
1001
1259
  serverState.cwd = process.cwd();
1260
+ const serverHost = resolveServerHost(serverState.cwd, serverState.configRoot);
1002
1261
  import_portfinder.default.basePort = 5678;
1003
1262
  const port = await import_portfinder.default.getPortPromise();
1004
1263
  watchConfig(
@@ -1025,7 +1284,7 @@ async function startServer() {
1025
1284
  });
1026
1285
  });
1027
1286
  await new Promise((resolve2, reject) => {
1028
- serverInstance.listen(port, "127.0.0.1", () => {
1287
+ serverInstance.listen(port, serverHost, () => {
1029
1288
  serverInstance.unref();
1030
1289
  resolve2();
1031
1290
  });
@@ -1036,37 +1295,18 @@ async function startServer() {
1036
1295
  });
1037
1296
  serverState.port = port;
1038
1297
  serverState.running = true;
1039
- const portFile = import_node_path4.default.join(import_node_os2.default.tmpdir(), "inspecto.port.json");
1040
1298
  try {
1041
- let portData = {};
1042
- if (import_node_fs4.default.existsSync(portFile)) {
1043
- try {
1044
- portData = JSON.parse(import_node_fs4.default.readFileSync(portFile, "utf-8"));
1045
- } catch (_e) {
1046
- }
1047
- }
1048
- const rootHash = import_node_crypto2.default.createHash("md5").update(serverState.projectRoot).digest("hex");
1049
- portData[rootHash] = port;
1050
- import_node_fs4.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
1299
+ writeProjectPort(port);
1051
1300
  } catch (_e) {
1052
1301
  serverLogger4.warn("Failed to write port file:", _e);
1053
1302
  }
1054
1303
  process.once("exit", () => {
1055
1304
  try {
1056
- if (import_node_fs4.default.existsSync(portFile)) {
1057
- const portData = JSON.parse(import_node_fs4.default.readFileSync(portFile, "utf-8"));
1058
- const rootHash = import_node_crypto2.default.createHash("md5").update(serverState.projectRoot).digest("hex");
1059
- delete portData[rootHash];
1060
- if (Object.keys(portData).length === 0) {
1061
- import_node_fs4.default.unlinkSync(portFile);
1062
- } else {
1063
- import_node_fs4.default.writeFileSync(portFile, JSON.stringify(portData, null, 2), "utf-8");
1064
- }
1065
- }
1305
+ removeProjectPort();
1066
1306
  } catch {
1067
1307
  }
1068
1308
  });
1069
- serverLogger4.info(`server running at http://127.0.0.1:${port}`);
1309
+ serverLogger4.info(`server running at http://${serverHost}:${port}`);
1070
1310
  return port;
1071
1311
  }
1072
1312
  async function readBody(req) {
@@ -1118,7 +1358,7 @@ async function handleRequest(url, req, res) {
1118
1358
  }
1119
1359
  return;
1120
1360
  }
1121
- if (pathname === import_types2.INSPECTO_API_PATHS.IDE_OPEN && req.method === "POST") {
1361
+ if ((pathname === import_types2.INSPECTO_API_PATHS.SOURCE_OPEN || pathname === import_types2.INSPECTO_API_PATHS.IDE_OPEN) && req.method === "POST") {
1122
1362
  let body;
1123
1363
  try {
1124
1364
  body = JSON.parse(await readBody(req));
@@ -1131,7 +1371,7 @@ async function handleRequest(url, req, res) {
1131
1371
  handleOpenFileRequest(body, serverState);
1132
1372
  } catch (err) {
1133
1373
  serverLogger4.warn(
1134
- `Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}. Reason: ${err.message}`
1374
+ `Security: Blocked path traversal attempt in SOURCE_OPEN: ${body.file}. Reason: ${err.message}`
1135
1375
  );
1136
1376
  res.writeHead(403, { "Content-Type": "application/json" });
1137
1377
  res.end(JSON.stringify({ error: "Access denied: File is outside of project workspace" }));
@@ -1205,6 +1445,212 @@ async function handleRequest(url, req, res) {
1205
1445
  }
1206
1446
  return;
1207
1447
  }
1448
+ if (pathname === import_types2.INSPECTO_API_PATHS.SESSION_CLAIM_NEXT && req.method === "POST") {
1449
+ try {
1450
+ const rawBody = await readBody(req);
1451
+ const body = rawBody ? JSON.parse(rawBody) : {};
1452
+ const timeoutMs = normalizeSessionClaimTimeout(
1453
+ body.timeoutMs === void 0 ? null : String(body.timeoutMs)
1454
+ );
1455
+ const result = await annotationSessionStore.claimNextSession({
1456
+ ...timeoutMs !== void 0 ? { timeoutMs } : {}
1457
+ });
1458
+ res.writeHead(200, { "Content-Type": "application/json" });
1459
+ res.end(
1460
+ JSON.stringify({
1461
+ success: true,
1462
+ timedOut: result.timedOut,
1463
+ matchedExisting: result.matchedExisting,
1464
+ ...result.event ? { event: result.event } : {},
1465
+ ...result.session ? { session: result.session } : {}
1466
+ })
1467
+ );
1468
+ } catch (e) {
1469
+ serverLogger4.error(`Error parsing session claim request:`, e);
1470
+ res.writeHead(400, { "Content-Type": "application/json" });
1471
+ res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
1472
+ }
1473
+ return;
1474
+ }
1475
+ if (pathname === import_types2.INSPECTO_API_PATHS.SESSION_EVENTS && req.method === "GET") {
1476
+ const statusParam = url.searchParams.getAll("status");
1477
+ const statuses = statusParam.length ? new Set(statusParam) : null;
1478
+ const sessionId = url.searchParams.get("sessionId")?.trim() || null;
1479
+ res.writeHead(200, {
1480
+ "Content-Type": "text/event-stream",
1481
+ "Cache-Control": "no-cache",
1482
+ Connection: "keep-alive"
1483
+ });
1484
+ res.write(`event: ready
1485
+ data: ${JSON.stringify({ ok: true })}
1486
+
1487
+ `);
1488
+ const unsubscribe = annotationSessionStore.subscribe((event) => {
1489
+ if (sessionId && event.session.id !== sessionId) {
1490
+ return;
1491
+ }
1492
+ if (statuses && !statuses.has(event.session.status)) {
1493
+ return;
1494
+ }
1495
+ res.write(formatSessionSseEvent(event));
1496
+ });
1497
+ req.on("close", () => {
1498
+ unsubscribe();
1499
+ res.end();
1500
+ });
1501
+ return;
1502
+ }
1503
+ if (pathname === import_types2.INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
1504
+ const statusParam = url.searchParams.getAll("status");
1505
+ const sessions = annotationSessionStore.listSessions(
1506
+ statusParam.length ? {
1507
+ status: statusParam
1508
+ } : void 0
1509
+ );
1510
+ res.writeHead(200, { "Content-Type": "application/json" });
1511
+ res.end(JSON.stringify({ success: true, sessions }));
1512
+ return;
1513
+ }
1514
+ if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && req.method === "GET") {
1515
+ const sessionId = pathname.substring(import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1);
1516
+ const session = annotationSessionStore.getSession(sessionId);
1517
+ if (!session) {
1518
+ res.writeHead(404, { "Content-Type": "application/json" });
1519
+ res.end(JSON.stringify({ success: false, error: "Session not found" }));
1520
+ return;
1521
+ }
1522
+ res.writeHead(200, { "Content-Type": "application/json" });
1523
+ res.end(JSON.stringify({ success: true, session }));
1524
+ return;
1525
+ }
1526
+ if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types2.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX) && req.method === "POST") {
1527
+ const sessionId = pathname.slice(
1528
+ import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
1529
+ -import_types2.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX.length
1530
+ );
1531
+ try {
1532
+ const rawBody = await readBody(req);
1533
+ const body = JSON.parse(rawBody);
1534
+ if (!isAnnotationThreadRole(body.role)) {
1535
+ res.writeHead(400, { "Content-Type": "application/json" });
1536
+ res.end(JSON.stringify({ success: false, error: "Reply role is invalid." }));
1537
+ return;
1538
+ }
1539
+ if (!body.text?.trim()) {
1540
+ res.writeHead(400, { "Content-Type": "application/json" });
1541
+ res.end(JSON.stringify({ success: false, error: "Reply text is required." }));
1542
+ return;
1543
+ }
1544
+ const session = annotationSessionStore.appendMessage(sessionId, {
1545
+ role: body.role,
1546
+ text: body.text.trim()
1547
+ });
1548
+ if (!session) {
1549
+ res.writeHead(404, { "Content-Type": "application/json" });
1550
+ res.end(JSON.stringify({ success: false, error: "Session not found" }));
1551
+ return;
1552
+ }
1553
+ res.writeHead(200, { "Content-Type": "application/json" });
1554
+ res.end(JSON.stringify({ success: true, session }));
1555
+ } catch (e) {
1556
+ serverLogger4.error(`Error parsing session reply request:`, e);
1557
+ res.writeHead(400, { "Content-Type": "application/json" });
1558
+ res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
1559
+ }
1560
+ return;
1561
+ }
1562
+ if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types2.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX) && req.method === "POST") {
1563
+ const sessionId = pathname.slice(
1564
+ import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
1565
+ -import_types2.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX.length
1566
+ );
1567
+ try {
1568
+ const rawBody = await readBody(req);
1569
+ const body = rawBody ? JSON.parse(rawBody) : {};
1570
+ const message = body.message?.trim();
1571
+ const existingSession = annotationSessionStore.getSession(sessionId);
1572
+ if (!existingSession) {
1573
+ res.writeHead(404, { "Content-Type": "application/json" });
1574
+ res.end(JSON.stringify({ success: false, error: "Session not found" }));
1575
+ return;
1576
+ }
1577
+ if (!message && !hasAgentReply(existingSession)) {
1578
+ res.writeHead(400, { "Content-Type": "application/json" });
1579
+ res.end(
1580
+ JSON.stringify({
1581
+ success: false,
1582
+ error: "Resolve message is required until an agent reply is recorded."
1583
+ })
1584
+ );
1585
+ return;
1586
+ }
1587
+ if (message) {
1588
+ const repliedSession = annotationSessionStore.appendMessage(sessionId, {
1589
+ role: "agent",
1590
+ text: message
1591
+ });
1592
+ if (!repliedSession) {
1593
+ res.writeHead(404, { "Content-Type": "application/json" });
1594
+ res.end(JSON.stringify({ success: false, error: "Session not found" }));
1595
+ return;
1596
+ }
1597
+ }
1598
+ const session = annotationSessionStore.updateStatus(sessionId, "resolved");
1599
+ if (!session) {
1600
+ res.writeHead(404, { "Content-Type": "application/json" });
1601
+ res.end(JSON.stringify({ success: false, error: "Session not found" }));
1602
+ return;
1603
+ }
1604
+ res.writeHead(200, { "Content-Type": "application/json" });
1605
+ res.end(JSON.stringify({ success: true, session }));
1606
+ } catch (e) {
1607
+ serverLogger4.error(`Error parsing session resolve request:`, e);
1608
+ res.writeHead(400, { "Content-Type": "application/json" });
1609
+ res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
1610
+ }
1611
+ return;
1612
+ }
1613
+ if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types2.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX) && req.method === "POST") {
1614
+ const sessionId = pathname.slice(
1615
+ import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
1616
+ -import_types2.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX.length
1617
+ );
1618
+ try {
1619
+ const rawBody = await readBody(req);
1620
+ const body = rawBody ? JSON.parse(rawBody) : {};
1621
+ const message = body.message?.trim();
1622
+ const existingSession = annotationSessionStore.getSession(sessionId);
1623
+ if (!existingSession) {
1624
+ res.writeHead(404, { "Content-Type": "application/json" });
1625
+ res.end(JSON.stringify({ success: false, error: "Session not found" }));
1626
+ return;
1627
+ }
1628
+ if (message) {
1629
+ const repliedSession = annotationSessionStore.appendMessage(sessionId, {
1630
+ role: "agent",
1631
+ text: message
1632
+ });
1633
+ if (!repliedSession) {
1634
+ res.writeHead(404, { "Content-Type": "application/json" });
1635
+ res.end(JSON.stringify({ success: false, error: "Session not found" }));
1636
+ return;
1637
+ }
1638
+ }
1639
+ const session = annotationSessionStore.updateStatus(sessionId, "dismissed");
1640
+ if (!session) {
1641
+ res.writeHead(404, { "Content-Type": "application/json" });
1642
+ res.end(JSON.stringify({ success: false, error: "Session not found" }));
1643
+ return;
1644
+ }
1645
+ res.writeHead(200, { "Content-Type": "application/json" });
1646
+ res.end(JSON.stringify({ success: true, session }));
1647
+ } catch (e) {
1648
+ serverLogger4.error(`Error parsing session dismiss request:`, e);
1649
+ res.writeHead(400, { "Content-Type": "application/json" });
1650
+ res.end(JSON.stringify({ success: false, error: "Invalid JSON body" }));
1651
+ }
1652
+ return;
1653
+ }
1208
1654
  if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
1209
1655
  const ticketId = pathname.substring(import_types2.INSPECTO_API_PATHS.AI_TICKET.length + 1);
1210
1656
  const payloadStr = readTicket(ticketId);
@@ -1221,7 +1667,7 @@ async function handleRequest(url, req, res) {
1221
1667
  res.end(JSON.stringify({ error: "not found" }));
1222
1668
  }
1223
1669
  async function dispatchToAi(req) {
1224
- const { location, snippet, prompt, screenshotContext } = req;
1670
+ const { location, snippet, prompt } = req;
1225
1671
  const formattedPrompt = prompt ?? `Please help me with this code from \`${location.file}\` (line ${location.line}):
1226
1672
 
1227
1673
  \`\`\`
@@ -1234,8 +1680,7 @@ ${snippet}
1234
1680
  filePath: location.file,
1235
1681
  line: location.line,
1236
1682
  column: location.column,
1237
- snippet,
1238
- ...screenshotContext ? { screenshotContext } : {}
1683
+ snippet
1239
1684
  });
1240
1685
  }
1241
1686
  function getBatchDispatchStatusCode(errorCode, success) {
@@ -1244,6 +1689,21 @@ function getBatchDispatchStatusCode(errorCode, success) {
1244
1689
  if (errorCode === "FORBIDDEN_PATH") return 403;
1245
1690
  return 500;
1246
1691
  }
1692
+ function isAnnotationThreadRole(value) {
1693
+ return value === "user" || value === "agent" || value === "system";
1694
+ }
1695
+ function formatSessionSseEvent(event) {
1696
+ return `event: ${event.type}
1697
+ data: ${JSON.stringify(event)}
1698
+
1699
+ `;
1700
+ }
1701
+ function normalizeSessionClaimTimeout(value) {
1702
+ if (!value?.trim()) return 3e4;
1703
+ const parsed = Number.parseInt(value, 10);
1704
+ if (!Number.isFinite(parsed)) return 3e4;
1705
+ return Math.max(0, Math.min(parsed, 3e5));
1706
+ }
1247
1707
 
1248
1708
  // src/index.ts
1249
1709
  var import_unplugin = require("unplugin");
@@ -1934,7 +2394,9 @@ function transformRouter(options) {
1934
2394
  return transformSvelte({
1935
2395
  filePath,
1936
2396
  source,
2397
+ projectRoot,
1937
2398
  escapeTags: pluginOptions.escapeTags,
2399
+ pathType: pluginOptions.pathType,
1938
2400
  attributeName: pluginOptions.attributeName
1939
2401
  });
1940
2402
  }
@@ -1943,6 +2405,7 @@ function transformRouter(options) {
1943
2405
  filePath,
1944
2406
  source,
1945
2407
  escapeTags: pluginOptions.escapeTags,
2408
+ pathType: pluginOptions.pathType,
1946
2409
  attributeName: pluginOptions.attributeName
1947
2410
  });
1948
2411
  }
@@ -1967,26 +2430,28 @@ var resolveClientModule = () => {
1967
2430
  };
1968
2431
 
1969
2432
  // src/injectors/webpack.ts
1970
- function getWebpackHtmlScript(serverPort) {
2433
+ function getWebpackHtmlScript(serverPort, publicServerUrl) {
1971
2434
  return `
1972
2435
  window.__AI_INSPECTOR_PORT__ = ${serverPort};
1973
- window.addEventListener('load', () => {
1974
- if (window.InspectoClient) {
1975
- window.InspectoClient.mountInspector({
1976
- serverUrl: 'http://127.0.0.1:' + window.__AI_INSPECTOR_PORT__,
1977
- });
1978
- }
1979
- });
2436
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
2437
+ window.addEventListener('load', () => {
2438
+ if (window.InspectoClient) {
2439
+ window.InspectoClient.mountInspector({
2440
+ serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
2441
+ });
2442
+ }
2443
+ });
1980
2444
  `;
1981
2445
  }
1982
- function getWebpackAssetScript(serverPort) {
2446
+ function getWebpackAssetScript(serverPort, publicServerUrl) {
1983
2447
  return `
1984
2448
  if (typeof window !== 'undefined') {
1985
2449
  window.__AI_INSPECTOR_PORT__ = ${serverPort};
2450
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
1986
2451
  const _initInspecto = () => {
1987
2452
  if (window.InspectoClient) {
1988
2453
  window.InspectoClient.mountInspector({
1989
- serverUrl: 'http://127.0.0.1:' + window.__AI_INSPECTOR_PORT__,
2454
+ serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
1990
2455
  });
1991
2456
  } else {
1992
2457
  setTimeout(_initInspecto, 100);
@@ -2000,7 +2465,7 @@ if (typeof window !== 'undefined') {
2000
2465
  }
2001
2466
  `;
2002
2467
  }
2003
- function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
2468
+ function injectWebpack(compiler, serverPortFn, publicServerUrlFn, resolveClientModule2) {
2004
2469
  const inspectoClientPath = resolveClientModule2();
2005
2470
  if (compiler.webpack && compiler.webpack.EntryPlugin) {
2006
2471
  new compiler.webpack.EntryPlugin(compiler.context, inspectoClientPath, {
@@ -2015,11 +2480,12 @@ function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
2015
2480
  const hooks = HtmlWebpackPlugin.constructor.getHooks(compilation);
2016
2481
  hooks.alterAssetTagGroups.tapPromise("inspecto-overlay", async (data) => {
2017
2482
  const port = await serverPortFn();
2483
+ const publicServerUrl = publicServerUrlFn(port);
2018
2484
  data.headTags.unshift({
2019
2485
  tagName: "script",
2020
2486
  voidTag: false,
2021
2487
  meta: { plugin: "inspecto-overlay" },
2022
- innerHTML: getWebpackHtmlScript(port)
2488
+ innerHTML: getWebpackHtmlScript(port, publicServerUrl)
2023
2489
  });
2024
2490
  return data;
2025
2491
  });
@@ -2032,13 +2498,14 @@ function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
2032
2498
  },
2033
2499
  async (assets) => {
2034
2500
  const port = await serverPortFn();
2501
+ const publicServerUrl = publicServerUrlFn(port);
2035
2502
  const mainAssetKey = Object.keys(assets).find(
2036
2503
  (key) => key.endsWith(".js") && (key.includes("main") || key.includes("app") || key.includes("umi"))
2037
2504
  );
2038
2505
  if (!mainAssetKey) return;
2039
2506
  const originalSource = assets[mainAssetKey].source();
2040
2507
  assets[mainAssetKey] = new compiler.webpack.sources.RawSource(
2041
- getWebpackAssetScript(port) + "\n" + originalSource
2508
+ getWebpackAssetScript(port, publicServerUrl) + "\n" + originalSource
2042
2509
  );
2043
2510
  }
2044
2511
  );
@@ -2072,12 +2539,13 @@ function injectRspack(compiler, serverPortFn, resolveClientModule2) {
2072
2539
  }
2073
2540
 
2074
2541
  // src/injectors/vite.ts
2075
- function getViteVirtualModuleScript(serverPort) {
2542
+ function getViteVirtualModuleScript(serverPort, publicServerUrl) {
2076
2543
  return `
2077
2544
  import { mountInspector } from '@inspecto-dev/core';
2078
2545
  window.__AI_INSPECTOR_PORT__ = ${serverPort};
2546
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
2079
2547
  mountInspector({
2080
- serverUrl: 'http://127.0.0.1:' + window.__AI_INSPECTOR_PORT__,
2548
+ serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
2081
2549
  });
2082
2550
  `;
2083
2551
  }
@@ -2110,6 +2578,11 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
2110
2578
  }
2111
2579
  return serverPort;
2112
2580
  };
2581
+ const getPublicServerUrl = (port) => resolvePublicServerUrl({
2582
+ cwd: serverState.cwd || process.cwd(),
2583
+ configRoot: serverState.configRoot || projectRoot,
2584
+ port
2585
+ });
2113
2586
  return {
2114
2587
  name: "inspecto-overlay",
2115
2588
  enforce: "pre",
@@ -2122,7 +2595,7 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
2122
2595
  },
2123
2596
  webpack: (compiler) => {
2124
2597
  if (isProduction) return;
2125
- injectWebpack(compiler, ensureServer, resolveClientModule);
2598
+ injectWebpack(compiler, ensureServer, getPublicServerUrl, resolveClientModule);
2126
2599
  },
2127
2600
  rspack: (compiler) => {
2128
2601
  if (isProduction) return;
@@ -2148,7 +2621,10 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
2148
2621
  },
2149
2622
  load(id) {
2150
2623
  if (id === VITE_VIRTUAL_MODULE_ID) {
2151
- return getViteVirtualModuleScript(serverPort ?? DEFAULT_PORT);
2624
+ return getViteVirtualModuleScript(
2625
+ serverPort ?? DEFAULT_PORT,
2626
+ getPublicServerUrl(serverPort ?? DEFAULT_PORT)
2627
+ );
2152
2628
  }
2153
2629
  return null;
2154
2630
  },
@@ -2206,10 +2682,10 @@ var rollupPlugin = InspectoPlugin.rollup;
2206
2682
  var esbuildPlugin = InspectoPlugin.esbuild;
2207
2683
 
2208
2684
  // src/astro.ts
2209
- function getAstroInjectedScript(serverPort) {
2685
+ function getAstroInjectedScript(serverPort, publicServerUrl) {
2210
2686
  return `
2211
2687
  import { mountInspector } from '@inspecto-dev/core';
2212
- window.__AI_INSPECTOR_SERVER_URL__ = 'http://127.0.0.1:${serverPort}';
2688
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
2213
2689
  mountInspector({
2214
2690
  serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
2215
2691
  });
@@ -2229,7 +2705,17 @@ function astroIntegration(options) {
2229
2705
  return;
2230
2706
  }
2231
2707
  const serverPort = await startServer();
2232
- injectScript("page", getAstroInjectedScript(serverPort));
2708
+ injectScript(
2709
+ "page",
2710
+ getAstroInjectedScript(
2711
+ serverPort,
2712
+ resolvePublicServerUrl({
2713
+ cwd: serverState.cwd || process.cwd(),
2714
+ configRoot: serverState.configRoot || process.cwd(),
2715
+ port: serverPort
2716
+ })
2717
+ )
2718
+ );
2233
2719
  }
2234
2720
  }
2235
2721
  };