@inspecto-dev/plugin 0.3.9 → 0.3.11

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/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
 
@@ -47,7 +47,7 @@ var import_node_path4 = __toESM(require("path"), 1);
47
47
  var import_node_os2 = __toESM(require("os"), 1);
48
48
  var import_node_crypto2 = __toESM(require("crypto"), 1);
49
49
  var import_portfinder = __toESM(require("portfinder"), 1);
50
- var import_types2 = require("@inspecto-dev/types");
50
+ var import_types3 = require("@inspecto-dev/types");
51
51
 
52
52
  // src/server/snippet.ts
53
53
  var fs = __toESM(require("fs"), 1);
@@ -409,13 +409,28 @@ function resolveIntents(serverPrompts) {
409
409
  );
410
410
  continue;
411
411
  }
412
- if (!item.aiIntent) {
413
- configLogger.warn(`Intent "${item.id}" is missing required "aiIntent".`);
414
- continue;
412
+ if (item.kind === "workflow") {
413
+ if (!item.prompt) {
414
+ configLogger.warn(`Workflow "${item.id}" missing required "prompt", skipping`);
415
+ continue;
416
+ }
417
+ result.push({
418
+ kind: "workflow",
419
+ id: item.id,
420
+ label: item.label ?? item.id,
421
+ prompt: item.prompt,
422
+ confirm: item.confirm ?? false,
423
+ enabled: item.enabled ?? true
424
+ });
425
+ } else {
426
+ if (!item.aiIntent) {
427
+ configLogger.warn(`Intent "${item.id}" is missing required "aiIntent".`);
428
+ continue;
429
+ }
430
+ result.push(
431
+ baseMap.has(item.id) ? { ...baseMap.get(item.id), ...item } : item
432
+ );
415
433
  }
416
- result.push(
417
- baseMap.has(item.id) ? { ...baseMap.get(item.id), ...item } : item
418
- );
419
434
  }
420
435
  }
421
436
  return result;
@@ -435,26 +450,61 @@ function resolveIntents(serverPrompts) {
435
450
  configLogger.warn('Intent object missing required "id" field, skipping.');
436
451
  continue;
437
452
  }
438
- if (!item.aiIntent) {
439
- configLogger.warn(`Intent "${item.id}" is missing required "aiIntent".`);
440
- continue;
441
- }
442
- const existingIdx = merged.findIndex((i2) => i2.id === item.id);
443
- if (existingIdx !== -1) {
444
- if (item.enabled === false) {
445
- merged.splice(existingIdx, 1);
453
+ if (item.kind === "workflow") {
454
+ if (!item.prompt) {
455
+ configLogger.warn(`Workflow "${item.id}" missing required "prompt", skipping`);
456
+ continue;
457
+ }
458
+ const wfConfig = {
459
+ kind: "workflow",
460
+ id: item.id,
461
+ label: item.label ?? item.id,
462
+ prompt: item.prompt,
463
+ confirm: item.confirm ?? false,
464
+ enabled: item.enabled ?? true
465
+ };
466
+ const existingIdx = merged.findIndex((i2) => i2.id === item.id);
467
+ if (existingIdx !== -1) {
468
+ if (item.enabled === false) {
469
+ merged.splice(existingIdx, 1);
470
+ } else {
471
+ merged[existingIdx] = wfConfig;
472
+ }
446
473
  } else {
447
- merged[existingIdx] = { ...merged[existingIdx], ...item };
474
+ if (item.enabled !== false) {
475
+ merged.push(wfConfig);
476
+ }
448
477
  }
449
478
  } else {
450
- if (item.enabled !== false) {
451
- merged.push(item);
479
+ if (!item.aiIntent) {
480
+ configLogger.warn(`Intent "${item.id}" is missing required "aiIntent".`);
481
+ continue;
482
+ }
483
+ const existingIdx = merged.findIndex((i2) => i2.id === item.id);
484
+ if (existingIdx !== -1) {
485
+ if (item.enabled === false) {
486
+ merged.splice(existingIdx, 1);
487
+ } else {
488
+ merged[existingIdx] = { ...merged[existingIdx], ...item };
489
+ }
490
+ } else {
491
+ if (item.enabled !== false) {
492
+ merged.push(item);
493
+ }
452
494
  }
453
495
  }
454
496
  }
455
497
  }
456
498
  return merged;
457
499
  }
500
+ function resolveWorkflowSlots(intents) {
501
+ return intents.filter(import_types.isWorkflowConfig).filter((w3) => w3.enabled !== false).map((w3) => ({
502
+ id: w3.id,
503
+ label: w3.label ?? w3.id,
504
+ prompt: w3.prompt,
505
+ confirm: w3.confirm ?? false
506
+ }));
507
+ }
458
508
  var watchers = [];
459
509
  function watchConfig(onReload, cwd = process.cwd(), gitRoot) {
460
510
  if (isWatching) return;
@@ -684,6 +734,10 @@ function assertPathWithinIdeOpenScope(file, projectRoot) {
684
734
  }
685
735
  }
686
736
 
737
+ // src/server/annotation-dispatch.ts
738
+ var import_node_child_process2 = require("child_process");
739
+ var import_node_util = require("util");
740
+
687
741
  // src/server/session-store.ts
688
742
  var DEFAULT_STATUS = "pending";
689
743
  function createAnnotationSessionStore(options = {}) {
@@ -691,8 +745,12 @@ function createAnnotationSessionStore(options = {}) {
691
745
  const listeners = /* @__PURE__ */ new Set();
692
746
  const now = options.now ?? (() => Date.now());
693
747
  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;
748
+ function findNewestMatchingSession(statuses, source) {
749
+ return [...sessions.values()].filter((session) => {
750
+ if (statuses && !statuses.has(session.status)) return false;
751
+ if (source && session.source !== source) return false;
752
+ return true;
753
+ }).sort((left, right) => right.updatedAt - left.updatedAt)[0] ?? null;
696
754
  }
697
755
  function updateSessionStatus(id, status) {
698
756
  const session = sessions.get(id);
@@ -752,7 +810,7 @@ function createAnnotationSessionStore(options = {}) {
752
810
  },
753
811
  async claimNextSession(options2 = {}) {
754
812
  const statuses = normalizeStatuses(DEFAULT_STATUS);
755
- const existingSession = findNewestMatchingSession(statuses);
813
+ const existingSession = findNewestMatchingSession(statuses, options2.source);
756
814
  if (existingSession) {
757
815
  return {
758
816
  session: claimSession(existingSession.id, statuses),
@@ -867,6 +925,7 @@ function cloneValue(value) {
867
925
  }
868
926
 
869
927
  // src/server/annotation-dispatch.ts
928
+ var execAsync = (0, import_node_util.promisify)(import_node_child_process2.exec);
870
929
  var AnnotationDispatchError = class extends Error {
871
930
  constructor(message, errorCode) {
872
931
  super(message);
@@ -878,9 +937,14 @@ async function dispatchAnnotationsToAi(req, state, store = annotationSessionStor
878
937
  try {
879
938
  validateAnnotationDispatchRequest(req, state);
880
939
  const batch = normalizeAnnotationBatch(req);
881
- const prompt = buildAnnotationBatchPrompt(batch);
940
+ let prompt = buildAnnotationBatchPrompt(batch);
941
+ if (req.source === "workflow") {
942
+ prompt = await appendProjectMetadata(prompt, state);
943
+ }
882
944
  const deliveryMode = normalizeDeliveryMode(req.deliveryMode);
883
945
  const session = store.createSession({
946
+ source: req.source || "annotation",
947
+ ...req.workflowId ? { workflowId: req.workflowId } : {},
884
948
  instruction: batch.instruction,
885
949
  annotations: toSessionAnnotations(batch.annotations),
886
950
  deliveryMode,
@@ -906,6 +970,33 @@ async function dispatchAnnotationsToAi(req, state, store = annotationSessionStor
906
970
  };
907
971
  }
908
972
  }
973
+ async function appendProjectMetadata(prompt, state) {
974
+ const lines = ["\n## Project"];
975
+ lines.push(`- Root: ${state.projectRoot}`);
976
+ try {
977
+ const options = {
978
+ cwd: state.projectRoot,
979
+ encoding: "utf-8",
980
+ timeout: 2e3
981
+ };
982
+ const { stdout: branchStdout } = await execAsync("git branch --show-current", options);
983
+ const branch = branchStdout.trim();
984
+ lines.push(`- Branch: ${branch}`);
985
+ const { stdout: statusStdout } = await execAsync("git status --porcelain", options);
986
+ const statusRaw = statusStdout.trim();
987
+ const entries = statusRaw ? statusRaw.split("\n") : [];
988
+ const staged = entries.filter((l) => l[0] !== " " && l[0] !== "?").length;
989
+ const unstaged = entries.filter((l) => l[1] !== " " && l[1] !== "?").length;
990
+ const untracked = entries.filter((l) => l[0] === "?").length;
991
+ lines.push(`- Status: ${staged} staged, ${unstaged} unstaged, ${untracked} untracked`);
992
+ } catch (err) {
993
+ console.warn("[inspecto] Failed to get git status for workflow:", err);
994
+ lines.push("- Git: unavailable or check timeout");
995
+ }
996
+ return `${prompt}
997
+
998
+ ${lines.join("\n")}`;
999
+ }
909
1000
  function normalizeDeliveryMode(input) {
910
1001
  return input === "agent" ? "agent" : "ide";
911
1002
  }
@@ -942,7 +1033,7 @@ function toSessionSummary(session) {
942
1033
  };
943
1034
  }
944
1035
  function validateAnnotationDispatchRequest(req, state) {
945
- if (!req.annotations.length) {
1036
+ if (!req.annotations.length && req.source !== "workflow") {
946
1037
  throw new AnnotationDispatchError("At least one annotation is required.", "INVALID_REQUEST");
947
1038
  }
948
1039
  for (const annotation of req.annotations) {
@@ -1044,6 +1135,7 @@ function getAnnotationDispatchErrorCode(error) {
1044
1135
  }
1045
1136
 
1046
1137
  // src/server/client-config.ts
1138
+ var import_types2 = require("@inspecto-dev/types");
1047
1139
  async function buildClientConfig(serverState2) {
1048
1140
  const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
1049
1141
  const promptsConfig = await loadPromptsConfig(false, serverState2.cwd, serverState2.configRoot);
@@ -1055,11 +1147,13 @@ async function buildClientConfig(serverState2) {
1055
1147
  const { scheme: _scheme, ...rest } = serverState2.ideInfo;
1056
1148
  info = rest;
1057
1149
  }
1150
+ const allIntents = resolveIntents(promptsConfig);
1058
1151
  return {
1059
1152
  ...info,
1060
- prompts: resolveIntents(promptsConfig),
1153
+ prompts: allIntents.filter(import_types2.isAiIntentConfig),
1154
+ workflows: resolveWorkflowSlots(allIntents),
1061
1155
  hotKeys: userConfig["inspector.hotKey"] ?? "alt",
1062
- annotateDeliveryMode: userConfig["annotate.deliveryMode"] ?? "both",
1156
+ annotateDeliveryMode: userConfig["annotate.deliveryMode"] ?? "agent",
1063
1157
  includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
1064
1158
  runtimeContext: {
1065
1159
  enabled: true,
@@ -1072,7 +1166,7 @@ async function buildClientConfig(serverState2) {
1072
1166
  }
1073
1167
 
1074
1168
  // src/server/open-file.ts
1075
- var import_node_child_process2 = require("child_process");
1169
+ var import_node_child_process3 = require("child_process");
1076
1170
  var import_launch_ide2 = require("launch-ide");
1077
1171
  var serverLogger2 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
1078
1172
  var VSCODE_FAMILY_SCHEMES = [
@@ -1123,11 +1217,11 @@ function handleOpenFileRequest(body, serverState2) {
1123
1217
  serverLogger2.debug(`SOURCE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
1124
1218
  try {
1125
1219
  if (process.platform === "darwin") {
1126
- (0, import_node_child_process2.execFileSync)("open", [uri]);
1220
+ (0, import_node_child_process3.execFileSync)("open", [uri]);
1127
1221
  } else if (process.platform === "win32") {
1128
- (0, import_node_child_process2.execFileSync)("cmd", ["/c", "start", '""', uri]);
1222
+ (0, import_node_child_process3.execFileSync)("cmd", ["/c", "start", '""', uri]);
1129
1223
  } else {
1130
- (0, import_node_child_process2.execFileSync)("xdg-open", [uri]);
1224
+ (0, import_node_child_process3.execFileSync)("xdg-open", [uri]);
1131
1225
  }
1132
1226
  } catch (e) {
1133
1227
  serverLogger2.error(`Failed to launch URI for SOURCE_OPEN (${uri}):`, e);
@@ -1154,35 +1248,72 @@ function handleOpenFileRequest(body, serverState2) {
1154
1248
  // src/server/project-root.ts
1155
1249
  var import_node_fs3 = __toESM(require("fs"), 1);
1156
1250
  var import_node_path3 = __toESM(require("path"), 1);
1157
- var import_node_child_process3 = require("child_process");
1251
+ var import_node_child_process4 = require("child_process");
1158
1252
  var serverLogger3 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
1159
- function resolveProjectRoot() {
1160
- const cwd = process.cwd();
1161
- let gitRoot;
1253
+ function resolveGitRoot(_cwd) {
1162
1254
  try {
1163
- gitRoot = (0, import_node_child_process3.execSync)("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
1255
+ const output = (0, import_node_child_process4.execSync)("git rev-parse --show-toplevel", { encoding: "utf-8" });
1256
+ return typeof output === "string" ? output.trim() : null;
1164
1257
  } catch (e) {
1165
1258
  serverLogger3.warn("Failed to resolve git root via git rev-parse:", e);
1166
- gitRoot = cwd;
1167
- }
1168
- const visited = /* @__PURE__ */ new Set();
1169
- const search = (start, stop) => {
1170
- let current = start;
1171
- while (!visited.has(current)) {
1172
- visited.add(current);
1173
- if (import_node_fs3.default.existsSync(import_node_path3.default.join(current, ".inspecto"))) return current;
1174
- if (current === stop) break;
1175
- const parent = import_node_path3.default.dirname(current);
1176
- if (parent === current) break;
1177
- current = parent;
1178
- }
1179
1259
  return null;
1180
- };
1181
- const cwdMatch = search(cwd, import_node_path3.default.parse(cwd).root);
1182
- if (cwdMatch) return cwdMatch;
1183
- const repoMatch = search(gitRoot, import_node_path3.default.parse(gitRoot).root);
1184
- if (repoMatch) return repoMatch;
1185
- return gitRoot;
1260
+ }
1261
+ }
1262
+ function findNearestAncestorWith(start, predicate) {
1263
+ let current = start;
1264
+ while (true) {
1265
+ if (predicate(current)) return current;
1266
+ const parent = import_node_path3.default.dirname(current);
1267
+ if (parent === current) break;
1268
+ current = parent;
1269
+ }
1270
+ return null;
1271
+ }
1272
+ function resolveWorkspaceRoot() {
1273
+ const cwd = process.cwd();
1274
+ const inspectoRoot = findNearestAncestorWith(
1275
+ cwd,
1276
+ (dir) => import_node_fs3.default.existsSync(import_node_path3.default.join(dir, ".inspecto"))
1277
+ );
1278
+ if (inspectoRoot) return inspectoRoot;
1279
+ const packageRoot = findNearestAncestorWith(
1280
+ cwd,
1281
+ (dir) => import_node_fs3.default.existsSync(import_node_path3.default.join(dir, "package.json"))
1282
+ );
1283
+ if (packageRoot) return packageRoot;
1284
+ return resolveGitRoot(cwd) ?? cwd;
1285
+ }
1286
+ function resolveProjectRoot() {
1287
+ const cwd = process.cwd();
1288
+ const packageRoot = findNearestAncestorWith(
1289
+ cwd,
1290
+ (dir) => import_node_fs3.default.existsSync(import_node_path3.default.join(dir, "package.json"))
1291
+ );
1292
+ if (packageRoot) return packageRoot;
1293
+ const inspectoRoot = findNearestAncestorWith(
1294
+ cwd,
1295
+ (dir) => import_node_fs3.default.existsSync(import_node_path3.default.join(dir, ".inspecto"))
1296
+ );
1297
+ if (inspectoRoot) return inspectoRoot;
1298
+ return resolveGitRoot(cwd) ?? cwd;
1299
+ }
1300
+
1301
+ // src/server/server-url.ts
1302
+ function resolveServerHost(cwd, configRoot) {
1303
+ if (process.env["VITEST"]) return "127.0.0.1";
1304
+ const userConfig = loadUserConfigSync(false, cwd, configRoot);
1305
+ const configuredHost = userConfig["server.host"]?.trim();
1306
+ if (configuredHost) return configuredHost;
1307
+ return "127.0.0.1";
1308
+ }
1309
+ function resolvePublicServerUrl(args) {
1310
+ const userConfig = loadUserConfigSync(false, args.cwd, args.configRoot);
1311
+ const configuredPublicUrl = userConfig["server.publicUrl"]?.trim();
1312
+ if (configuredPublicUrl) {
1313
+ return configuredPublicUrl.replace(/\/$/, "");
1314
+ }
1315
+ const host = resolveServerHost(args.cwd, args.configRoot);
1316
+ return `http://${host}:${args.port}`;
1186
1317
  }
1187
1318
 
1188
1319
  // src/server/index.ts
@@ -1237,8 +1368,9 @@ async function startServer() {
1237
1368
  return serverState.port;
1238
1369
  }
1239
1370
  serverState.projectRoot = resolveProjectRoot();
1240
- serverState.configRoot = serverState.projectRoot;
1371
+ serverState.configRoot = resolveWorkspaceRoot();
1241
1372
  serverState.cwd = process.cwd();
1373
+ const serverHost = resolveServerHost(serverState.cwd, serverState.configRoot);
1242
1374
  import_portfinder.default.basePort = 5678;
1243
1375
  const port = await import_portfinder.default.getPortPromise();
1244
1376
  watchConfig(
@@ -1265,7 +1397,7 @@ async function startServer() {
1265
1397
  });
1266
1398
  });
1267
1399
  await new Promise((resolve2, reject) => {
1268
- serverInstance.listen(port, "0.0.0.0", () => {
1400
+ serverInstance.listen(port, serverHost, () => {
1269
1401
  serverInstance.unref();
1270
1402
  resolve2();
1271
1403
  });
@@ -1287,7 +1419,7 @@ async function startServer() {
1287
1419
  } catch {
1288
1420
  }
1289
1421
  });
1290
- serverLogger4.info(`server running at http://0.0.0.0:${port}`);
1422
+ serverLogger4.info(`server running at http://${serverHost}:${port}`);
1291
1423
  return port;
1292
1424
  }
1293
1425
  async function readBody(req) {
@@ -1300,19 +1432,19 @@ async function readBody(req) {
1300
1432
  }
1301
1433
  async function handleRequest(url, req, res) {
1302
1434
  const pathname = url.pathname;
1303
- if ((pathname === "/health" || pathname === import_types2.INSPECTO_API_PATHS.HEALTH) && req.method === "GET") {
1435
+ if ((pathname === "/health" || pathname === import_types3.INSPECTO_API_PATHS.HEALTH) && req.method === "GET") {
1304
1436
  res.writeHead(200, { "Content-Type": "application/json" });
1305
1437
  res.end(JSON.stringify({ ok: true, port: serverState.port }));
1306
1438
  return;
1307
1439
  }
1308
- if (pathname === import_types2.INSPECTO_API_PATHS.CLIENT_CONFIG && req.method === "GET") {
1440
+ if (pathname === import_types3.INSPECTO_API_PATHS.CLIENT_CONFIG && req.method === "GET") {
1309
1441
  const config = await buildClientConfig(serverState);
1310
1442
  delete config.providers;
1311
1443
  res.writeHead(200, { "Content-Type": "application/json" });
1312
1444
  res.end(JSON.stringify(config));
1313
1445
  return;
1314
1446
  }
1315
- if (pathname === import_types2.INSPECTO_API_PATHS.IDE_INFO && req.method === "POST") {
1447
+ if (pathname === import_types3.INSPECTO_API_PATHS.IDE_INFO && req.method === "POST") {
1316
1448
  try {
1317
1449
  const body = JSON.parse(await readBody(req));
1318
1450
  const ideWorkspace = body.workspaceRoot || "";
@@ -1333,13 +1465,13 @@ async function handleRequest(url, req, res) {
1333
1465
  res.writeHead(200, { "Content-Type": "application/json" });
1334
1466
  res.end(JSON.stringify({ success: true }));
1335
1467
  } catch (e) {
1336
- serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.IDE_INFO} POST request:`, e);
1468
+ serverLogger4.error(`Error parsing ${import_types3.INSPECTO_API_PATHS.IDE_INFO} POST request:`, e);
1337
1469
  res.writeHead(400, { "Content-Type": "application/json" });
1338
1470
  res.end(JSON.stringify({ error: "Invalid JSON body" }));
1339
1471
  }
1340
1472
  return;
1341
1473
  }
1342
- if ((pathname === import_types2.INSPECTO_API_PATHS.SOURCE_OPEN || pathname === import_types2.INSPECTO_API_PATHS.IDE_OPEN) && req.method === "POST") {
1474
+ if ((pathname === import_types3.INSPECTO_API_PATHS.SOURCE_OPEN || pathname === import_types3.INSPECTO_API_PATHS.IDE_OPEN) && req.method === "POST") {
1343
1475
  let body;
1344
1476
  try {
1345
1477
  body = JSON.parse(await readBody(req));
@@ -1362,7 +1494,7 @@ async function handleRequest(url, req, res) {
1362
1494
  res.end(JSON.stringify({ success: true }));
1363
1495
  return;
1364
1496
  }
1365
- if (pathname === import_types2.INSPECTO_API_PATHS.PROJECT_SNIPPET && req.method === "GET") {
1497
+ if (pathname === import_types3.INSPECTO_API_PATHS.PROJECT_SNIPPET && req.method === "GET") {
1366
1498
  const file = url.searchParams.get("file") ?? "";
1367
1499
  const line = parseInt(url.searchParams.get("line") ?? "1", 10);
1368
1500
  const column = parseInt(url.searchParams.get("column") ?? "1", 10);
@@ -1396,7 +1528,7 @@ async function handleRequest(url, req, res) {
1396
1528
  }
1397
1529
  return;
1398
1530
  }
1399
- if (pathname === import_types2.INSPECTO_API_PATHS.AI_DISPATCH && req.method === "POST") {
1531
+ if (pathname === import_types3.INSPECTO_API_PATHS.AI_DISPATCH && req.method === "POST") {
1400
1532
  try {
1401
1533
  const rawBody = await readBody(req);
1402
1534
  const body = JSON.parse(rawBody);
@@ -1404,13 +1536,13 @@ async function handleRequest(url, req, res) {
1404
1536
  res.writeHead(result.success ? 200 : 500, { "Content-Type": "application/json" });
1405
1537
  res.end(JSON.stringify(result));
1406
1538
  } catch (e) {
1407
- serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.AI_DISPATCH} request:`, e);
1539
+ serverLogger4.error(`Error parsing ${import_types3.INSPECTO_API_PATHS.AI_DISPATCH} request:`, e);
1408
1540
  res.writeHead(500, { "Content-Type": "application/json" });
1409
1541
  res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
1410
1542
  }
1411
1543
  return;
1412
1544
  }
1413
- if (pathname === import_types2.INSPECTO_API_PATHS.AI_BATCH_DISPATCH && req.method === "POST") {
1545
+ if (pathname === import_types3.INSPECTO_API_PATHS.AI_BATCH_DISPATCH && req.method === "POST") {
1414
1546
  try {
1415
1547
  const rawBody = await readBody(req);
1416
1548
  const body = JSON.parse(rawBody);
@@ -1420,13 +1552,13 @@ async function handleRequest(url, req, res) {
1420
1552
  });
1421
1553
  res.end(JSON.stringify(result));
1422
1554
  } catch (e) {
1423
- serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.AI_BATCH_DISPATCH} request:`, e);
1555
+ serverLogger4.error(`Error parsing ${import_types3.INSPECTO_API_PATHS.AI_BATCH_DISPATCH} request:`, e);
1424
1556
  res.writeHead(500, { "Content-Type": "application/json" });
1425
1557
  res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
1426
1558
  }
1427
1559
  return;
1428
1560
  }
1429
- if (pathname === import_types2.INSPECTO_API_PATHS.SESSION_CLAIM_NEXT && req.method === "POST") {
1561
+ if (pathname === import_types3.INSPECTO_API_PATHS.SESSION_CLAIM_NEXT && req.method === "POST") {
1430
1562
  try {
1431
1563
  const rawBody = await readBody(req);
1432
1564
  const body = rawBody ? JSON.parse(rawBody) : {};
@@ -1453,7 +1585,7 @@ async function handleRequest(url, req, res) {
1453
1585
  }
1454
1586
  return;
1455
1587
  }
1456
- if (pathname === import_types2.INSPECTO_API_PATHS.SESSION_EVENTS && req.method === "GET") {
1588
+ if (pathname === import_types3.INSPECTO_API_PATHS.SESSION_EVENTS && req.method === "GET") {
1457
1589
  const statusParam = url.searchParams.getAll("status");
1458
1590
  const statuses = statusParam.length ? new Set(statusParam) : null;
1459
1591
  const sessionId = url.searchParams.get("sessionId")?.trim() || null;
@@ -1481,7 +1613,7 @@ data: ${JSON.stringify({ ok: true })}
1481
1613
  });
1482
1614
  return;
1483
1615
  }
1484
- if (pathname === import_types2.INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
1616
+ if (pathname === import_types3.INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
1485
1617
  const statusParam = url.searchParams.getAll("status");
1486
1618
  const sessions = annotationSessionStore.listSessions(
1487
1619
  statusParam.length ? {
@@ -1492,8 +1624,8 @@ data: ${JSON.stringify({ ok: true })}
1492
1624
  res.end(JSON.stringify({ success: true, sessions }));
1493
1625
  return;
1494
1626
  }
1495
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && req.method === "GET") {
1496
- const sessionId = pathname.substring(import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1);
1627
+ if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && req.method === "GET") {
1628
+ const sessionId = pathname.substring(import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1);
1497
1629
  const session = annotationSessionStore.getSession(sessionId);
1498
1630
  if (!session) {
1499
1631
  res.writeHead(404, { "Content-Type": "application/json" });
@@ -1504,10 +1636,10 @@ data: ${JSON.stringify({ ok: true })}
1504
1636
  res.end(JSON.stringify({ success: true, session }));
1505
1637
  return;
1506
1638
  }
1507
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types2.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX) && req.method === "POST") {
1639
+ if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types3.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX) && req.method === "POST") {
1508
1640
  const sessionId = pathname.slice(
1509
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
1510
- -import_types2.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX.length
1641
+ import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1,
1642
+ -import_types3.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX.length
1511
1643
  );
1512
1644
  try {
1513
1645
  const rawBody = await readBody(req);
@@ -1540,10 +1672,10 @@ data: ${JSON.stringify({ ok: true })}
1540
1672
  }
1541
1673
  return;
1542
1674
  }
1543
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types2.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX) && req.method === "POST") {
1675
+ if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types3.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX) && req.method === "POST") {
1544
1676
  const sessionId = pathname.slice(
1545
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
1546
- -import_types2.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX.length
1677
+ import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1,
1678
+ -import_types3.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX.length
1547
1679
  );
1548
1680
  try {
1549
1681
  const rawBody = await readBody(req);
@@ -1591,10 +1723,10 @@ data: ${JSON.stringify({ ok: true })}
1591
1723
  }
1592
1724
  return;
1593
1725
  }
1594
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types2.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX) && req.method === "POST") {
1726
+ if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types3.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX) && req.method === "POST") {
1595
1727
  const sessionId = pathname.slice(
1596
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
1597
- -import_types2.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX.length
1728
+ import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1,
1729
+ -import_types3.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX.length
1598
1730
  );
1599
1731
  try {
1600
1732
  const rawBody = await readBody(req);
@@ -1632,8 +1764,8 @@ data: ${JSON.stringify({ ok: true })}
1632
1764
  }
1633
1765
  return;
1634
1766
  }
1635
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
1636
- const ticketId = pathname.substring(import_types2.INSPECTO_API_PATHS.AI_TICKET.length + 1);
1767
+ if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
1768
+ const ticketId = pathname.substring(import_types3.INSPECTO_API_PATHS.AI_TICKET.length + 1);
1637
1769
  const payloadStr = readTicket(ticketId);
1638
1770
  if (!payloadStr) {
1639
1771
  res.writeHead(404, { "Content-Type": "application/json" });
@@ -1649,10 +1781,23 @@ data: ${JSON.stringify({ ok: true })}
1649
1781
  }
1650
1782
  async function dispatchToAi(req) {
1651
1783
  const { location, snippet, prompt } = req;
1652
- const formattedPrompt = prompt ?? `Please help me with this code from \`${location.file}\` (line ${location.line}):
1784
+ if (prompt?.trim()) {
1785
+ const runtime2 = resolvePromptDispatchRuntime(serverState);
1786
+ return dispatchPromptThroughIde(runtime2, {
1787
+ prompt: prompt.trim()
1788
+ });
1789
+ }
1790
+ if (!location) {
1791
+ return {
1792
+ success: false,
1793
+ error: "Source location is required when prompt is omitted.",
1794
+ errorCode: "INVALID_REQUEST"
1795
+ };
1796
+ }
1797
+ const formattedPrompt = `Please help me with this code from \`${location.file}\` (line ${location.line}):
1653
1798
 
1654
1799
  \`\`\`
1655
- ${snippet}
1800
+ ${snippet ?? ""}
1656
1801
  \`\`\`
1657
1802
  `;
1658
1803
  const runtime = resolvePromptDispatchRuntime(serverState);
@@ -1661,7 +1806,7 @@ ${snippet}
1661
1806
  filePath: location.file,
1662
1807
  line: location.line,
1663
1808
  column: location.column,
1664
- snippet
1809
+ ...snippet !== void 0 ? { snippet } : {}
1665
1810
  });
1666
1811
  }
1667
1812
  function getBatchDispatchStatusCode(errorCode, success) {
@@ -2411,26 +2556,28 @@ var resolveClientModule = () => {
2411
2556
  };
2412
2557
 
2413
2558
  // src/injectors/webpack.ts
2414
- function getWebpackHtmlScript(serverPort) {
2559
+ function getWebpackHtmlScript(serverPort, publicServerUrl) {
2415
2560
  return `
2416
2561
  window.__AI_INSPECTOR_PORT__ = ${serverPort};
2562
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
2417
2563
  window.addEventListener('load', () => {
2418
2564
  if (window.InspectoClient) {
2419
2565
  window.InspectoClient.mountInspector({
2420
- serverUrl: 'http://0.0.0.0:' + window.__AI_INSPECTOR_PORT__,
2566
+ serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
2421
2567
  });
2422
2568
  }
2423
2569
  });
2424
2570
  `;
2425
2571
  }
2426
- function getWebpackAssetScript(serverPort) {
2572
+ function getWebpackAssetScript(serverPort, publicServerUrl) {
2427
2573
  return `
2428
2574
  if (typeof window !== 'undefined') {
2429
2575
  window.__AI_INSPECTOR_PORT__ = ${serverPort};
2576
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
2430
2577
  const _initInspecto = () => {
2431
2578
  if (window.InspectoClient) {
2432
2579
  window.InspectoClient.mountInspector({
2433
- serverUrl: 'http://0.0.0.0:' + window.__AI_INSPECTOR_PORT__,
2580
+ serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
2434
2581
  });
2435
2582
  } else {
2436
2583
  setTimeout(_initInspecto, 100);
@@ -2444,7 +2591,7 @@ if (typeof window !== 'undefined') {
2444
2591
  }
2445
2592
  `;
2446
2593
  }
2447
- function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
2594
+ function injectWebpack(compiler, serverPortFn, publicServerUrlFn, resolveClientModule2) {
2448
2595
  const inspectoClientPath = resolveClientModule2();
2449
2596
  if (compiler.webpack && compiler.webpack.EntryPlugin) {
2450
2597
  new compiler.webpack.EntryPlugin(compiler.context, inspectoClientPath, {
@@ -2459,11 +2606,12 @@ function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
2459
2606
  const hooks = HtmlWebpackPlugin.constructor.getHooks(compilation);
2460
2607
  hooks.alterAssetTagGroups.tapPromise("inspecto-overlay", async (data) => {
2461
2608
  const port = await serverPortFn();
2609
+ const publicServerUrl = publicServerUrlFn(port);
2462
2610
  data.headTags.unshift({
2463
2611
  tagName: "script",
2464
2612
  voidTag: false,
2465
2613
  meta: { plugin: "inspecto-overlay" },
2466
- innerHTML: getWebpackHtmlScript(port)
2614
+ innerHTML: getWebpackHtmlScript(port, publicServerUrl)
2467
2615
  });
2468
2616
  return data;
2469
2617
  });
@@ -2476,13 +2624,14 @@ function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
2476
2624
  },
2477
2625
  async (assets) => {
2478
2626
  const port = await serverPortFn();
2627
+ const publicServerUrl = publicServerUrlFn(port);
2479
2628
  const mainAssetKey = Object.keys(assets).find(
2480
2629
  (key) => key.endsWith(".js") && (key.includes("main") || key.includes("app") || key.includes("umi"))
2481
2630
  );
2482
2631
  if (!mainAssetKey) return;
2483
2632
  const originalSource = assets[mainAssetKey].source();
2484
2633
  assets[mainAssetKey] = new compiler.webpack.sources.RawSource(
2485
- getWebpackAssetScript(port) + "\n" + originalSource
2634
+ getWebpackAssetScript(port, publicServerUrl) + "\n" + originalSource
2486
2635
  );
2487
2636
  }
2488
2637
  );
@@ -2516,12 +2665,13 @@ function injectRspack(compiler, serverPortFn, resolveClientModule2) {
2516
2665
  }
2517
2666
 
2518
2667
  // src/injectors/vite.ts
2519
- function getViteVirtualModuleScript(serverPort) {
2668
+ function getViteVirtualModuleScript(serverPort, publicServerUrl) {
2520
2669
  return `
2521
2670
  import { mountInspector } from '@inspecto-dev/core';
2522
2671
  window.__AI_INSPECTOR_PORT__ = ${serverPort};
2672
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
2523
2673
  mountInspector({
2524
- serverUrl: 'http://0.0.0.0:' + window.__AI_INSPECTOR_PORT__,
2674
+ serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
2525
2675
  });
2526
2676
  `;
2527
2677
  }
@@ -2554,6 +2704,11 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
2554
2704
  }
2555
2705
  return serverPort;
2556
2706
  };
2707
+ const getPublicServerUrl = (port) => resolvePublicServerUrl({
2708
+ cwd: serverState.cwd || process.cwd(),
2709
+ configRoot: serverState.configRoot || projectRoot,
2710
+ port
2711
+ });
2557
2712
  return {
2558
2713
  name: "inspecto-overlay",
2559
2714
  enforce: "pre",
@@ -2566,7 +2721,7 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
2566
2721
  },
2567
2722
  webpack: (compiler) => {
2568
2723
  if (isProduction) return;
2569
- injectWebpack(compiler, ensureServer, resolveClientModule);
2724
+ injectWebpack(compiler, ensureServer, getPublicServerUrl, resolveClientModule);
2570
2725
  },
2571
2726
  rspack: (compiler) => {
2572
2727
  if (isProduction) return;
@@ -2592,7 +2747,10 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
2592
2747
  },
2593
2748
  load(id) {
2594
2749
  if (id === VITE_VIRTUAL_MODULE_ID) {
2595
- return getViteVirtualModuleScript(serverPort ?? DEFAULT_PORT);
2750
+ return getViteVirtualModuleScript(
2751
+ serverPort ?? DEFAULT_PORT,
2752
+ getPublicServerUrl(serverPort ?? DEFAULT_PORT)
2753
+ );
2596
2754
  }
2597
2755
  return null;
2598
2756
  },
@@ -2650,10 +2808,10 @@ var rollupPlugin = InspectoPlugin.rollup;
2650
2808
  var esbuildPlugin = InspectoPlugin.esbuild;
2651
2809
 
2652
2810
  // src/astro.ts
2653
- function getAstroInjectedScript(serverPort) {
2811
+ function getAstroInjectedScript(serverPort, publicServerUrl) {
2654
2812
  return `
2655
2813
  import { mountInspector } from '@inspecto-dev/core';
2656
- window.__AI_INSPECTOR_SERVER_URL__ = 'http://0.0.0.0:${serverPort}';
2814
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
2657
2815
  mountInspector({
2658
2816
  serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
2659
2817
  });
@@ -2673,7 +2831,17 @@ function astroIntegration(options) {
2673
2831
  return;
2674
2832
  }
2675
2833
  const serverPort = await startServer();
2676
- injectScript("page", getAstroInjectedScript(serverPort));
2834
+ injectScript(
2835
+ "page",
2836
+ getAstroInjectedScript(
2837
+ serverPort,
2838
+ resolvePublicServerUrl({
2839
+ cwd: serverState.cwd || process.cwd(),
2840
+ configRoot: serverState.configRoot || process.cwd(),
2841
+ port: serverPort
2842
+ })
2843
+ )
2844
+ );
2677
2845
  }
2678
2846
  }
2679
2847
  };