@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/index.cjs CHANGED
@@ -43,7 +43,7 @@ __export(src_exports, {
43
43
  });
44
44
  module.exports = __toCommonJS(src_exports);
45
45
 
46
- // ../../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
46
+ // ../../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
47
47
  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;
48
48
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
49
49
 
@@ -761,7 +761,7 @@ var import_node_path7 = __toESM(require("path"), 1);
761
761
  var import_node_os2 = __toESM(require("os"), 1);
762
762
  var import_node_crypto2 = __toESM(require("crypto"), 1);
763
763
  var import_portfinder = __toESM(require("portfinder"), 1);
764
- var import_types2 = require("@inspecto-dev/types");
764
+ var import_types3 = require("@inspecto-dev/types");
765
765
 
766
766
  // src/server/snippet.ts
767
767
  var fs = __toESM(require("fs"), 1);
@@ -1123,13 +1123,28 @@ function resolveIntents(serverPrompts) {
1123
1123
  );
1124
1124
  continue;
1125
1125
  }
1126
- if (!item.aiIntent) {
1127
- configLogger.warn(`Intent "${item.id}" is missing required "aiIntent".`);
1128
- continue;
1126
+ if (item.kind === "workflow") {
1127
+ if (!item.prompt) {
1128
+ configLogger.warn(`Workflow "${item.id}" missing required "prompt", skipping`);
1129
+ continue;
1130
+ }
1131
+ result.push({
1132
+ kind: "workflow",
1133
+ id: item.id,
1134
+ label: item.label ?? item.id,
1135
+ prompt: item.prompt,
1136
+ confirm: item.confirm ?? false,
1137
+ enabled: item.enabled ?? true
1138
+ });
1139
+ } else {
1140
+ if (!item.aiIntent) {
1141
+ configLogger.warn(`Intent "${item.id}" is missing required "aiIntent".`);
1142
+ continue;
1143
+ }
1144
+ result.push(
1145
+ baseMap.has(item.id) ? { ...baseMap.get(item.id), ...item } : item
1146
+ );
1129
1147
  }
1130
- result.push(
1131
- baseMap.has(item.id) ? { ...baseMap.get(item.id), ...item } : item
1132
- );
1133
1148
  }
1134
1149
  }
1135
1150
  return result;
@@ -1149,26 +1164,61 @@ function resolveIntents(serverPrompts) {
1149
1164
  configLogger.warn('Intent object missing required "id" field, skipping.');
1150
1165
  continue;
1151
1166
  }
1152
- if (!item.aiIntent) {
1153
- configLogger.warn(`Intent "${item.id}" is missing required "aiIntent".`);
1154
- continue;
1155
- }
1156
- const existingIdx = merged.findIndex((i2) => i2.id === item.id);
1157
- if (existingIdx !== -1) {
1158
- if (item.enabled === false) {
1159
- merged.splice(existingIdx, 1);
1167
+ if (item.kind === "workflow") {
1168
+ if (!item.prompt) {
1169
+ configLogger.warn(`Workflow "${item.id}" missing required "prompt", skipping`);
1170
+ continue;
1171
+ }
1172
+ const wfConfig = {
1173
+ kind: "workflow",
1174
+ id: item.id,
1175
+ label: item.label ?? item.id,
1176
+ prompt: item.prompt,
1177
+ confirm: item.confirm ?? false,
1178
+ enabled: item.enabled ?? true
1179
+ };
1180
+ const existingIdx = merged.findIndex((i2) => i2.id === item.id);
1181
+ if (existingIdx !== -1) {
1182
+ if (item.enabled === false) {
1183
+ merged.splice(existingIdx, 1);
1184
+ } else {
1185
+ merged[existingIdx] = wfConfig;
1186
+ }
1160
1187
  } else {
1161
- merged[existingIdx] = { ...merged[existingIdx], ...item };
1188
+ if (item.enabled !== false) {
1189
+ merged.push(wfConfig);
1190
+ }
1162
1191
  }
1163
1192
  } else {
1164
- if (item.enabled !== false) {
1165
- merged.push(item);
1193
+ if (!item.aiIntent) {
1194
+ configLogger.warn(`Intent "${item.id}" is missing required "aiIntent".`);
1195
+ continue;
1196
+ }
1197
+ const existingIdx = merged.findIndex((i2) => i2.id === item.id);
1198
+ if (existingIdx !== -1) {
1199
+ if (item.enabled === false) {
1200
+ merged.splice(existingIdx, 1);
1201
+ } else {
1202
+ merged[existingIdx] = { ...merged[existingIdx], ...item };
1203
+ }
1204
+ } else {
1205
+ if (item.enabled !== false) {
1206
+ merged.push(item);
1207
+ }
1166
1208
  }
1167
1209
  }
1168
1210
  }
1169
1211
  }
1170
1212
  return merged;
1171
1213
  }
1214
+ function resolveWorkflowSlots(intents) {
1215
+ return intents.filter(import_types.isWorkflowConfig).filter((w3) => w3.enabled !== false).map((w3) => ({
1216
+ id: w3.id,
1217
+ label: w3.label ?? w3.id,
1218
+ prompt: w3.prompt,
1219
+ confirm: w3.confirm ?? false
1220
+ }));
1221
+ }
1172
1222
  var watchers = [];
1173
1223
  function watchConfig(onReload, cwd = process.cwd(), gitRoot) {
1174
1224
  if (isWatching) return;
@@ -1398,6 +1448,10 @@ function assertPathWithinIdeOpenScope(file, projectRoot) {
1398
1448
  }
1399
1449
  }
1400
1450
 
1451
+ // src/server/annotation-dispatch.ts
1452
+ var import_node_child_process2 = require("child_process");
1453
+ var import_node_util = require("util");
1454
+
1401
1455
  // src/server/session-store.ts
1402
1456
  var DEFAULT_STATUS = "pending";
1403
1457
  function createAnnotationSessionStore(options = {}) {
@@ -1405,8 +1459,12 @@ function createAnnotationSessionStore(options = {}) {
1405
1459
  const listeners = /* @__PURE__ */ new Set();
1406
1460
  const now = options.now ?? (() => Date.now());
1407
1461
  const createId = options.createId ?? createRandomId;
1408
- function findNewestMatchingSession(statuses) {
1409
- return [...sessions.values()].filter((session) => statuses ? statuses.has(session.status) : true).sort((left, right) => right.updatedAt - left.updatedAt)[0] ?? null;
1462
+ function findNewestMatchingSession(statuses, source) {
1463
+ return [...sessions.values()].filter((session) => {
1464
+ if (statuses && !statuses.has(session.status)) return false;
1465
+ if (source && session.source !== source) return false;
1466
+ return true;
1467
+ }).sort((left, right) => right.updatedAt - left.updatedAt)[0] ?? null;
1410
1468
  }
1411
1469
  function updateSessionStatus(id, status) {
1412
1470
  const session = sessions.get(id);
@@ -1466,7 +1524,7 @@ function createAnnotationSessionStore(options = {}) {
1466
1524
  },
1467
1525
  async claimNextSession(options2 = {}) {
1468
1526
  const statuses = normalizeStatuses(DEFAULT_STATUS);
1469
- const existingSession = findNewestMatchingSession(statuses);
1527
+ const existingSession = findNewestMatchingSession(statuses, options2.source);
1470
1528
  if (existingSession) {
1471
1529
  return {
1472
1530
  session: claimSession(existingSession.id, statuses),
@@ -1581,6 +1639,7 @@ function cloneValue(value) {
1581
1639
  }
1582
1640
 
1583
1641
  // src/server/annotation-dispatch.ts
1642
+ var execAsync = (0, import_node_util.promisify)(import_node_child_process2.exec);
1584
1643
  var AnnotationDispatchError = class extends Error {
1585
1644
  constructor(message, errorCode) {
1586
1645
  super(message);
@@ -1592,9 +1651,14 @@ async function dispatchAnnotationsToAi(req, state, store = annotationSessionStor
1592
1651
  try {
1593
1652
  validateAnnotationDispatchRequest(req, state);
1594
1653
  const batch = normalizeAnnotationBatch(req);
1595
- const prompt = buildAnnotationBatchPrompt(batch);
1654
+ let prompt = buildAnnotationBatchPrompt(batch);
1655
+ if (req.source === "workflow") {
1656
+ prompt = await appendProjectMetadata(prompt, state);
1657
+ }
1596
1658
  const deliveryMode = normalizeDeliveryMode(req.deliveryMode);
1597
1659
  const session = store.createSession({
1660
+ source: req.source || "annotation",
1661
+ ...req.workflowId ? { workflowId: req.workflowId } : {},
1598
1662
  instruction: batch.instruction,
1599
1663
  annotations: toSessionAnnotations(batch.annotations),
1600
1664
  deliveryMode,
@@ -1620,6 +1684,33 @@ async function dispatchAnnotationsToAi(req, state, store = annotationSessionStor
1620
1684
  };
1621
1685
  }
1622
1686
  }
1687
+ async function appendProjectMetadata(prompt, state) {
1688
+ const lines = ["\n## Project"];
1689
+ lines.push(`- Root: ${state.projectRoot}`);
1690
+ try {
1691
+ const options = {
1692
+ cwd: state.projectRoot,
1693
+ encoding: "utf-8",
1694
+ timeout: 2e3
1695
+ };
1696
+ const { stdout: branchStdout } = await execAsync("git branch --show-current", options);
1697
+ const branch = branchStdout.trim();
1698
+ lines.push(`- Branch: ${branch}`);
1699
+ const { stdout: statusStdout } = await execAsync("git status --porcelain", options);
1700
+ const statusRaw = statusStdout.trim();
1701
+ const entries = statusRaw ? statusRaw.split("\n") : [];
1702
+ const staged = entries.filter((l) => l[0] !== " " && l[0] !== "?").length;
1703
+ const unstaged = entries.filter((l) => l[1] !== " " && l[1] !== "?").length;
1704
+ const untracked = entries.filter((l) => l[0] === "?").length;
1705
+ lines.push(`- Status: ${staged} staged, ${unstaged} unstaged, ${untracked} untracked`);
1706
+ } catch (err) {
1707
+ console.warn("[inspecto] Failed to get git status for workflow:", err);
1708
+ lines.push("- Git: unavailable or check timeout");
1709
+ }
1710
+ return `${prompt}
1711
+
1712
+ ${lines.join("\n")}`;
1713
+ }
1623
1714
  function normalizeDeliveryMode(input) {
1624
1715
  return input === "agent" ? "agent" : "ide";
1625
1716
  }
@@ -1656,7 +1747,7 @@ function toSessionSummary(session) {
1656
1747
  };
1657
1748
  }
1658
1749
  function validateAnnotationDispatchRequest(req, state) {
1659
- if (!req.annotations.length) {
1750
+ if (!req.annotations.length && req.source !== "workflow") {
1660
1751
  throw new AnnotationDispatchError("At least one annotation is required.", "INVALID_REQUEST");
1661
1752
  }
1662
1753
  for (const annotation of req.annotations) {
@@ -1758,6 +1849,7 @@ function getAnnotationDispatchErrorCode(error) {
1758
1849
  }
1759
1850
 
1760
1851
  // src/server/client-config.ts
1852
+ var import_types2 = require("@inspecto-dev/types");
1761
1853
  async function buildClientConfig(serverState2) {
1762
1854
  const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
1763
1855
  const promptsConfig = await loadPromptsConfig(false, serverState2.cwd, serverState2.configRoot);
@@ -1769,11 +1861,13 @@ async function buildClientConfig(serverState2) {
1769
1861
  const { scheme: _scheme, ...rest } = serverState2.ideInfo;
1770
1862
  info = rest;
1771
1863
  }
1864
+ const allIntents = resolveIntents(promptsConfig);
1772
1865
  return {
1773
1866
  ...info,
1774
- prompts: resolveIntents(promptsConfig),
1867
+ prompts: allIntents.filter(import_types2.isAiIntentConfig),
1868
+ workflows: resolveWorkflowSlots(allIntents),
1775
1869
  hotKeys: userConfig["inspector.hotKey"] ?? "alt",
1776
- annotateDeliveryMode: userConfig["annotate.deliveryMode"] ?? "both",
1870
+ annotateDeliveryMode: userConfig["annotate.deliveryMode"] ?? "agent",
1777
1871
  includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
1778
1872
  runtimeContext: {
1779
1873
  enabled: true,
@@ -1786,7 +1880,7 @@ async function buildClientConfig(serverState2) {
1786
1880
  }
1787
1881
 
1788
1882
  // src/server/open-file.ts
1789
- var import_node_child_process2 = require("child_process");
1883
+ var import_node_child_process3 = require("child_process");
1790
1884
  var import_launch_ide2 = require("launch-ide");
1791
1885
  var serverLogger2 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
1792
1886
  var VSCODE_FAMILY_SCHEMES = [
@@ -1837,11 +1931,11 @@ function handleOpenFileRequest(body, serverState2) {
1837
1931
  serverLogger2.debug(`SOURCE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
1838
1932
  try {
1839
1933
  if (process.platform === "darwin") {
1840
- (0, import_node_child_process2.execFileSync)("open", [uri]);
1934
+ (0, import_node_child_process3.execFileSync)("open", [uri]);
1841
1935
  } else if (process.platform === "win32") {
1842
- (0, import_node_child_process2.execFileSync)("cmd", ["/c", "start", '""', uri]);
1936
+ (0, import_node_child_process3.execFileSync)("cmd", ["/c", "start", '""', uri]);
1843
1937
  } else {
1844
- (0, import_node_child_process2.execFileSync)("xdg-open", [uri]);
1938
+ (0, import_node_child_process3.execFileSync)("xdg-open", [uri]);
1845
1939
  }
1846
1940
  } catch (e) {
1847
1941
  serverLogger2.error(`Failed to launch URI for SOURCE_OPEN (${uri}):`, e);
@@ -1868,35 +1962,72 @@ function handleOpenFileRequest(body, serverState2) {
1868
1962
  // src/server/project-root.ts
1869
1963
  var import_node_fs3 = __toESM(require("fs"), 1);
1870
1964
  var import_node_path6 = __toESM(require("path"), 1);
1871
- var import_node_child_process3 = require("child_process");
1965
+ var import_node_child_process4 = require("child_process");
1872
1966
  var serverLogger3 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
1873
- function resolveProjectRoot() {
1874
- const cwd = process.cwd();
1875
- let gitRoot;
1967
+ function resolveGitRoot(_cwd) {
1876
1968
  try {
1877
- gitRoot = (0, import_node_child_process3.execSync)("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
1969
+ const output = (0, import_node_child_process4.execSync)("git rev-parse --show-toplevel", { encoding: "utf-8" });
1970
+ return typeof output === "string" ? output.trim() : null;
1878
1971
  } catch (e) {
1879
1972
  serverLogger3.warn("Failed to resolve git root via git rev-parse:", e);
1880
- gitRoot = cwd;
1881
- }
1882
- const visited = /* @__PURE__ */ new Set();
1883
- const search = (start, stop) => {
1884
- let current = start;
1885
- while (!visited.has(current)) {
1886
- visited.add(current);
1887
- if (import_node_fs3.default.existsSync(import_node_path6.default.join(current, ".inspecto"))) return current;
1888
- if (current === stop) break;
1889
- const parent = import_node_path6.default.dirname(current);
1890
- if (parent === current) break;
1891
- current = parent;
1892
- }
1893
1973
  return null;
1894
- };
1895
- const cwdMatch = search(cwd, import_node_path6.default.parse(cwd).root);
1896
- if (cwdMatch) return cwdMatch;
1897
- const repoMatch = search(gitRoot, import_node_path6.default.parse(gitRoot).root);
1898
- if (repoMatch) return repoMatch;
1899
- return gitRoot;
1974
+ }
1975
+ }
1976
+ function findNearestAncestorWith(start, predicate) {
1977
+ let current = start;
1978
+ while (true) {
1979
+ if (predicate(current)) return current;
1980
+ const parent = import_node_path6.default.dirname(current);
1981
+ if (parent === current) break;
1982
+ current = parent;
1983
+ }
1984
+ return null;
1985
+ }
1986
+ function resolveWorkspaceRoot() {
1987
+ const cwd = process.cwd();
1988
+ const inspectoRoot = findNearestAncestorWith(
1989
+ cwd,
1990
+ (dir) => import_node_fs3.default.existsSync(import_node_path6.default.join(dir, ".inspecto"))
1991
+ );
1992
+ if (inspectoRoot) return inspectoRoot;
1993
+ const packageRoot = findNearestAncestorWith(
1994
+ cwd,
1995
+ (dir) => import_node_fs3.default.existsSync(import_node_path6.default.join(dir, "package.json"))
1996
+ );
1997
+ if (packageRoot) return packageRoot;
1998
+ return resolveGitRoot(cwd) ?? cwd;
1999
+ }
2000
+ function resolveProjectRoot() {
2001
+ const cwd = process.cwd();
2002
+ const packageRoot = findNearestAncestorWith(
2003
+ cwd,
2004
+ (dir) => import_node_fs3.default.existsSync(import_node_path6.default.join(dir, "package.json"))
2005
+ );
2006
+ if (packageRoot) return packageRoot;
2007
+ const inspectoRoot = findNearestAncestorWith(
2008
+ cwd,
2009
+ (dir) => import_node_fs3.default.existsSync(import_node_path6.default.join(dir, ".inspecto"))
2010
+ );
2011
+ if (inspectoRoot) return inspectoRoot;
2012
+ return resolveGitRoot(cwd) ?? cwd;
2013
+ }
2014
+
2015
+ // src/server/server-url.ts
2016
+ function resolveServerHost(cwd, configRoot) {
2017
+ if (process.env["VITEST"]) return "127.0.0.1";
2018
+ const userConfig = loadUserConfigSync(false, cwd, configRoot);
2019
+ const configuredHost = userConfig["server.host"]?.trim();
2020
+ if (configuredHost) return configuredHost;
2021
+ return "127.0.0.1";
2022
+ }
2023
+ function resolvePublicServerUrl(args) {
2024
+ const userConfig = loadUserConfigSync(false, args.cwd, args.configRoot);
2025
+ const configuredPublicUrl = userConfig["server.publicUrl"]?.trim();
2026
+ if (configuredPublicUrl) {
2027
+ return configuredPublicUrl.replace(/\/$/, "");
2028
+ }
2029
+ const host = resolveServerHost(args.cwd, args.configRoot);
2030
+ return `http://${host}:${args.port}`;
1900
2031
  }
1901
2032
 
1902
2033
  // src/server/index.ts
@@ -1951,8 +2082,9 @@ async function startServer() {
1951
2082
  return serverState.port;
1952
2083
  }
1953
2084
  serverState.projectRoot = resolveProjectRoot();
1954
- serverState.configRoot = serverState.projectRoot;
2085
+ serverState.configRoot = resolveWorkspaceRoot();
1955
2086
  serverState.cwd = process.cwd();
2087
+ const serverHost = resolveServerHost(serverState.cwd, serverState.configRoot);
1956
2088
  import_portfinder.default.basePort = 5678;
1957
2089
  const port = await import_portfinder.default.getPortPromise();
1958
2090
  watchConfig(
@@ -1979,7 +2111,7 @@ async function startServer() {
1979
2111
  });
1980
2112
  });
1981
2113
  await new Promise((resolve2, reject) => {
1982
- serverInstance.listen(port, "0.0.0.0", () => {
2114
+ serverInstance.listen(port, serverHost, () => {
1983
2115
  serverInstance.unref();
1984
2116
  resolve2();
1985
2117
  });
@@ -2001,7 +2133,7 @@ async function startServer() {
2001
2133
  } catch {
2002
2134
  }
2003
2135
  });
2004
- serverLogger4.info(`server running at http://0.0.0.0:${port}`);
2136
+ serverLogger4.info(`server running at http://${serverHost}:${port}`);
2005
2137
  return port;
2006
2138
  }
2007
2139
  async function readBody(req) {
@@ -2014,19 +2146,19 @@ async function readBody(req) {
2014
2146
  }
2015
2147
  async function handleRequest(url, req, res) {
2016
2148
  const pathname = url.pathname;
2017
- if ((pathname === "/health" || pathname === import_types2.INSPECTO_API_PATHS.HEALTH) && req.method === "GET") {
2149
+ if ((pathname === "/health" || pathname === import_types3.INSPECTO_API_PATHS.HEALTH) && req.method === "GET") {
2018
2150
  res.writeHead(200, { "Content-Type": "application/json" });
2019
2151
  res.end(JSON.stringify({ ok: true, port: serverState.port }));
2020
2152
  return;
2021
2153
  }
2022
- if (pathname === import_types2.INSPECTO_API_PATHS.CLIENT_CONFIG && req.method === "GET") {
2154
+ if (pathname === import_types3.INSPECTO_API_PATHS.CLIENT_CONFIG && req.method === "GET") {
2023
2155
  const config = await buildClientConfig(serverState);
2024
2156
  delete config.providers;
2025
2157
  res.writeHead(200, { "Content-Type": "application/json" });
2026
2158
  res.end(JSON.stringify(config));
2027
2159
  return;
2028
2160
  }
2029
- if (pathname === import_types2.INSPECTO_API_PATHS.IDE_INFO && req.method === "POST") {
2161
+ if (pathname === import_types3.INSPECTO_API_PATHS.IDE_INFO && req.method === "POST") {
2030
2162
  try {
2031
2163
  const body = JSON.parse(await readBody(req));
2032
2164
  const ideWorkspace = body.workspaceRoot || "";
@@ -2047,13 +2179,13 @@ async function handleRequest(url, req, res) {
2047
2179
  res.writeHead(200, { "Content-Type": "application/json" });
2048
2180
  res.end(JSON.stringify({ success: true }));
2049
2181
  } catch (e) {
2050
- serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.IDE_INFO} POST request:`, e);
2182
+ serverLogger4.error(`Error parsing ${import_types3.INSPECTO_API_PATHS.IDE_INFO} POST request:`, e);
2051
2183
  res.writeHead(400, { "Content-Type": "application/json" });
2052
2184
  res.end(JSON.stringify({ error: "Invalid JSON body" }));
2053
2185
  }
2054
2186
  return;
2055
2187
  }
2056
- if ((pathname === import_types2.INSPECTO_API_PATHS.SOURCE_OPEN || pathname === import_types2.INSPECTO_API_PATHS.IDE_OPEN) && req.method === "POST") {
2188
+ if ((pathname === import_types3.INSPECTO_API_PATHS.SOURCE_OPEN || pathname === import_types3.INSPECTO_API_PATHS.IDE_OPEN) && req.method === "POST") {
2057
2189
  let body;
2058
2190
  try {
2059
2191
  body = JSON.parse(await readBody(req));
@@ -2076,7 +2208,7 @@ async function handleRequest(url, req, res) {
2076
2208
  res.end(JSON.stringify({ success: true }));
2077
2209
  return;
2078
2210
  }
2079
- if (pathname === import_types2.INSPECTO_API_PATHS.PROJECT_SNIPPET && req.method === "GET") {
2211
+ if (pathname === import_types3.INSPECTO_API_PATHS.PROJECT_SNIPPET && req.method === "GET") {
2080
2212
  const file = url.searchParams.get("file") ?? "";
2081
2213
  const line = parseInt(url.searchParams.get("line") ?? "1", 10);
2082
2214
  const column = parseInt(url.searchParams.get("column") ?? "1", 10);
@@ -2110,7 +2242,7 @@ async function handleRequest(url, req, res) {
2110
2242
  }
2111
2243
  return;
2112
2244
  }
2113
- if (pathname === import_types2.INSPECTO_API_PATHS.AI_DISPATCH && req.method === "POST") {
2245
+ if (pathname === import_types3.INSPECTO_API_PATHS.AI_DISPATCH && req.method === "POST") {
2114
2246
  try {
2115
2247
  const rawBody = await readBody(req);
2116
2248
  const body = JSON.parse(rawBody);
@@ -2118,13 +2250,13 @@ async function handleRequest(url, req, res) {
2118
2250
  res.writeHead(result.success ? 200 : 500, { "Content-Type": "application/json" });
2119
2251
  res.end(JSON.stringify(result));
2120
2252
  } catch (e) {
2121
- serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.AI_DISPATCH} request:`, e);
2253
+ serverLogger4.error(`Error parsing ${import_types3.INSPECTO_API_PATHS.AI_DISPATCH} request:`, e);
2122
2254
  res.writeHead(500, { "Content-Type": "application/json" });
2123
2255
  res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
2124
2256
  }
2125
2257
  return;
2126
2258
  }
2127
- if (pathname === import_types2.INSPECTO_API_PATHS.AI_BATCH_DISPATCH && req.method === "POST") {
2259
+ if (pathname === import_types3.INSPECTO_API_PATHS.AI_BATCH_DISPATCH && req.method === "POST") {
2128
2260
  try {
2129
2261
  const rawBody = await readBody(req);
2130
2262
  const body = JSON.parse(rawBody);
@@ -2134,13 +2266,13 @@ async function handleRequest(url, req, res) {
2134
2266
  });
2135
2267
  res.end(JSON.stringify(result));
2136
2268
  } catch (e) {
2137
- serverLogger4.error(`Error parsing ${import_types2.INSPECTO_API_PATHS.AI_BATCH_DISPATCH} request:`, e);
2269
+ serverLogger4.error(`Error parsing ${import_types3.INSPECTO_API_PATHS.AI_BATCH_DISPATCH} request:`, e);
2138
2270
  res.writeHead(500, { "Content-Type": "application/json" });
2139
2271
  res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
2140
2272
  }
2141
2273
  return;
2142
2274
  }
2143
- if (pathname === import_types2.INSPECTO_API_PATHS.SESSION_CLAIM_NEXT && req.method === "POST") {
2275
+ if (pathname === import_types3.INSPECTO_API_PATHS.SESSION_CLAIM_NEXT && req.method === "POST") {
2144
2276
  try {
2145
2277
  const rawBody = await readBody(req);
2146
2278
  const body = rawBody ? JSON.parse(rawBody) : {};
@@ -2167,7 +2299,7 @@ async function handleRequest(url, req, res) {
2167
2299
  }
2168
2300
  return;
2169
2301
  }
2170
- if (pathname === import_types2.INSPECTO_API_PATHS.SESSION_EVENTS && req.method === "GET") {
2302
+ if (pathname === import_types3.INSPECTO_API_PATHS.SESSION_EVENTS && req.method === "GET") {
2171
2303
  const statusParam = url.searchParams.getAll("status");
2172
2304
  const statuses = statusParam.length ? new Set(statusParam) : null;
2173
2305
  const sessionId = url.searchParams.get("sessionId")?.trim() || null;
@@ -2195,7 +2327,7 @@ data: ${JSON.stringify({ ok: true })}
2195
2327
  });
2196
2328
  return;
2197
2329
  }
2198
- if (pathname === import_types2.INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
2330
+ if (pathname === import_types3.INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
2199
2331
  const statusParam = url.searchParams.getAll("status");
2200
2332
  const sessions = annotationSessionStore.listSessions(
2201
2333
  statusParam.length ? {
@@ -2206,8 +2338,8 @@ data: ${JSON.stringify({ ok: true })}
2206
2338
  res.end(JSON.stringify({ success: true, sessions }));
2207
2339
  return;
2208
2340
  }
2209
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && req.method === "GET") {
2210
- const sessionId = pathname.substring(import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1);
2341
+ if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && req.method === "GET") {
2342
+ const sessionId = pathname.substring(import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1);
2211
2343
  const session = annotationSessionStore.getSession(sessionId);
2212
2344
  if (!session) {
2213
2345
  res.writeHead(404, { "Content-Type": "application/json" });
@@ -2218,10 +2350,10 @@ data: ${JSON.stringify({ ok: true })}
2218
2350
  res.end(JSON.stringify({ success: true, session }));
2219
2351
  return;
2220
2352
  }
2221
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types2.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX) && req.method === "POST") {
2353
+ if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types3.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX) && req.method === "POST") {
2222
2354
  const sessionId = pathname.slice(
2223
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
2224
- -import_types2.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX.length
2355
+ import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1,
2356
+ -import_types3.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX.length
2225
2357
  );
2226
2358
  try {
2227
2359
  const rawBody = await readBody(req);
@@ -2254,10 +2386,10 @@ data: ${JSON.stringify({ ok: true })}
2254
2386
  }
2255
2387
  return;
2256
2388
  }
2257
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types2.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX) && req.method === "POST") {
2389
+ if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types3.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX) && req.method === "POST") {
2258
2390
  const sessionId = pathname.slice(
2259
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
2260
- -import_types2.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX.length
2391
+ import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1,
2392
+ -import_types3.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX.length
2261
2393
  );
2262
2394
  try {
2263
2395
  const rawBody = await readBody(req);
@@ -2305,10 +2437,10 @@ data: ${JSON.stringify({ ok: true })}
2305
2437
  }
2306
2438
  return;
2307
2439
  }
2308
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types2.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX) && req.method === "POST") {
2440
+ if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types3.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX) && req.method === "POST") {
2309
2441
  const sessionId = pathname.slice(
2310
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
2311
- -import_types2.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX.length
2442
+ import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1,
2443
+ -import_types3.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX.length
2312
2444
  );
2313
2445
  try {
2314
2446
  const rawBody = await readBody(req);
@@ -2346,8 +2478,8 @@ data: ${JSON.stringify({ ok: true })}
2346
2478
  }
2347
2479
  return;
2348
2480
  }
2349
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
2350
- const ticketId = pathname.substring(import_types2.INSPECTO_API_PATHS.AI_TICKET.length + 1);
2481
+ if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
2482
+ const ticketId = pathname.substring(import_types3.INSPECTO_API_PATHS.AI_TICKET.length + 1);
2351
2483
  const payloadStr = readTicket(ticketId);
2352
2484
  if (!payloadStr) {
2353
2485
  res.writeHead(404, { "Content-Type": "application/json" });
@@ -2363,10 +2495,23 @@ data: ${JSON.stringify({ ok: true })}
2363
2495
  }
2364
2496
  async function dispatchToAi(req) {
2365
2497
  const { location, snippet, prompt } = req;
2366
- const formattedPrompt = prompt ?? `Please help me with this code from \`${location.file}\` (line ${location.line}):
2498
+ if (prompt?.trim()) {
2499
+ const runtime2 = resolvePromptDispatchRuntime(serverState);
2500
+ return dispatchPromptThroughIde(runtime2, {
2501
+ prompt: prompt.trim()
2502
+ });
2503
+ }
2504
+ if (!location) {
2505
+ return {
2506
+ success: false,
2507
+ error: "Source location is required when prompt is omitted.",
2508
+ errorCode: "INVALID_REQUEST"
2509
+ };
2510
+ }
2511
+ const formattedPrompt = `Please help me with this code from \`${location.file}\` (line ${location.line}):
2367
2512
 
2368
2513
  \`\`\`
2369
- ${snippet}
2514
+ ${snippet ?? ""}
2370
2515
  \`\`\`
2371
2516
  `;
2372
2517
  const runtime = resolvePromptDispatchRuntime(serverState);
@@ -2375,7 +2520,7 @@ ${snippet}
2375
2520
  filePath: location.file,
2376
2521
  line: location.line,
2377
2522
  column: location.column,
2378
- snippet
2523
+ ...snippet !== void 0 ? { snippet } : {}
2379
2524
  });
2380
2525
  }
2381
2526
  function getBatchDispatchStatusCode(errorCode, success) {
@@ -2418,26 +2563,28 @@ var resolveClientModule = () => {
2418
2563
  };
2419
2564
 
2420
2565
  // src/injectors/webpack.ts
2421
- function getWebpackHtmlScript(serverPort) {
2566
+ function getWebpackHtmlScript(serverPort, publicServerUrl) {
2422
2567
  return `
2423
2568
  window.__AI_INSPECTOR_PORT__ = ${serverPort};
2569
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
2424
2570
  window.addEventListener('load', () => {
2425
2571
  if (window.InspectoClient) {
2426
2572
  window.InspectoClient.mountInspector({
2427
- serverUrl: 'http://0.0.0.0:' + window.__AI_INSPECTOR_PORT__,
2573
+ serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
2428
2574
  });
2429
2575
  }
2430
2576
  });
2431
2577
  `;
2432
2578
  }
2433
- function getWebpackAssetScript(serverPort) {
2579
+ function getWebpackAssetScript(serverPort, publicServerUrl) {
2434
2580
  return `
2435
2581
  if (typeof window !== 'undefined') {
2436
2582
  window.__AI_INSPECTOR_PORT__ = ${serverPort};
2583
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
2437
2584
  const _initInspecto = () => {
2438
2585
  if (window.InspectoClient) {
2439
2586
  window.InspectoClient.mountInspector({
2440
- serverUrl: 'http://0.0.0.0:' + window.__AI_INSPECTOR_PORT__,
2587
+ serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
2441
2588
  });
2442
2589
  } else {
2443
2590
  setTimeout(_initInspecto, 100);
@@ -2451,7 +2598,7 @@ if (typeof window !== 'undefined') {
2451
2598
  }
2452
2599
  `;
2453
2600
  }
2454
- function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
2601
+ function injectWebpack(compiler, serverPortFn, publicServerUrlFn, resolveClientModule2) {
2455
2602
  const inspectoClientPath = resolveClientModule2();
2456
2603
  if (compiler.webpack && compiler.webpack.EntryPlugin) {
2457
2604
  new compiler.webpack.EntryPlugin(compiler.context, inspectoClientPath, {
@@ -2466,11 +2613,12 @@ function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
2466
2613
  const hooks = HtmlWebpackPlugin.constructor.getHooks(compilation);
2467
2614
  hooks.alterAssetTagGroups.tapPromise("inspecto-overlay", async (data) => {
2468
2615
  const port = await serverPortFn();
2616
+ const publicServerUrl = publicServerUrlFn(port);
2469
2617
  data.headTags.unshift({
2470
2618
  tagName: "script",
2471
2619
  voidTag: false,
2472
2620
  meta: { plugin: "inspecto-overlay" },
2473
- innerHTML: getWebpackHtmlScript(port)
2621
+ innerHTML: getWebpackHtmlScript(port, publicServerUrl)
2474
2622
  });
2475
2623
  return data;
2476
2624
  });
@@ -2483,13 +2631,14 @@ function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
2483
2631
  },
2484
2632
  async (assets) => {
2485
2633
  const port = await serverPortFn();
2634
+ const publicServerUrl = publicServerUrlFn(port);
2486
2635
  const mainAssetKey = Object.keys(assets).find(
2487
2636
  (key) => key.endsWith(".js") && (key.includes("main") || key.includes("app") || key.includes("umi"))
2488
2637
  );
2489
2638
  if (!mainAssetKey) return;
2490
2639
  const originalSource = assets[mainAssetKey].source();
2491
2640
  assets[mainAssetKey] = new compiler.webpack.sources.RawSource(
2492
- getWebpackAssetScript(port) + "\n" + originalSource
2641
+ getWebpackAssetScript(port, publicServerUrl) + "\n" + originalSource
2493
2642
  );
2494
2643
  }
2495
2644
  );
@@ -2523,12 +2672,13 @@ function injectRspack(compiler, serverPortFn, resolveClientModule2) {
2523
2672
  }
2524
2673
 
2525
2674
  // src/injectors/vite.ts
2526
- function getViteVirtualModuleScript(serverPort) {
2675
+ function getViteVirtualModuleScript(serverPort, publicServerUrl) {
2527
2676
  return `
2528
2677
  import { mountInspector } from '@inspecto-dev/core';
2529
2678
  window.__AI_INSPECTOR_PORT__ = ${serverPort};
2679
+ window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
2530
2680
  mountInspector({
2531
- serverUrl: 'http://0.0.0.0:' + window.__AI_INSPECTOR_PORT__,
2681
+ serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
2532
2682
  });
2533
2683
  `;
2534
2684
  }
@@ -2561,6 +2711,11 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
2561
2711
  }
2562
2712
  return serverPort;
2563
2713
  };
2714
+ const getPublicServerUrl = (port) => resolvePublicServerUrl({
2715
+ cwd: serverState.cwd || process.cwd(),
2716
+ configRoot: serverState.configRoot || projectRoot,
2717
+ port
2718
+ });
2564
2719
  return {
2565
2720
  name: "inspecto-overlay",
2566
2721
  enforce: "pre",
@@ -2573,7 +2728,7 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
2573
2728
  },
2574
2729
  webpack: (compiler) => {
2575
2730
  if (isProduction) return;
2576
- injectWebpack(compiler, ensureServer, resolveClientModule);
2731
+ injectWebpack(compiler, ensureServer, getPublicServerUrl, resolveClientModule);
2577
2732
  },
2578
2733
  rspack: (compiler) => {
2579
2734
  if (isProduction) return;
@@ -2599,7 +2754,10 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
2599
2754
  },
2600
2755
  load(id) {
2601
2756
  if (id === VITE_VIRTUAL_MODULE_ID) {
2602
- return getViteVirtualModuleScript(serverPort ?? DEFAULT_PORT);
2757
+ return getViteVirtualModuleScript(
2758
+ serverPort ?? DEFAULT_PORT,
2759
+ getPublicServerUrl(serverPort ?? DEFAULT_PORT)
2760
+ );
2603
2761
  }
2604
2762
  return null;
2605
2763
  },