@inspecto-dev/plugin 0.3.10 → 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/rollup.cjs CHANGED
@@ -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,43 +1962,62 @@ 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;
1900
2013
  }
1901
2014
 
1902
2015
  // src/server/server-url.ts
1903
2016
  function resolveServerHost(cwd, configRoot) {
2017
+ if (process.env["VITEST"]) return "127.0.0.1";
1904
2018
  const userConfig = loadUserConfigSync(false, cwd, configRoot);
1905
2019
  const configuredHost = userConfig["server.host"]?.trim();
1906
2020
  if (configuredHost) return configuredHost;
1907
- if (process.env["VITEST"]) return "127.0.0.1";
1908
2021
  return "127.0.0.1";
1909
2022
  }
1910
2023
  function resolvePublicServerUrl(args) {
@@ -1969,7 +2082,7 @@ async function startServer() {
1969
2082
  return serverState.port;
1970
2083
  }
1971
2084
  serverState.projectRoot = resolveProjectRoot();
1972
- serverState.configRoot = serverState.projectRoot;
2085
+ serverState.configRoot = resolveWorkspaceRoot();
1973
2086
  serverState.cwd = process.cwd();
1974
2087
  const serverHost = resolveServerHost(serverState.cwd, serverState.configRoot);
1975
2088
  import_portfinder.default.basePort = 5678;
@@ -2033,19 +2146,19 @@ async function readBody(req) {
2033
2146
  }
2034
2147
  async function handleRequest(url, req, res) {
2035
2148
  const pathname = url.pathname;
2036
- 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") {
2037
2150
  res.writeHead(200, { "Content-Type": "application/json" });
2038
2151
  res.end(JSON.stringify({ ok: true, port: serverState.port }));
2039
2152
  return;
2040
2153
  }
2041
- 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") {
2042
2155
  const config = await buildClientConfig(serverState);
2043
2156
  delete config.providers;
2044
2157
  res.writeHead(200, { "Content-Type": "application/json" });
2045
2158
  res.end(JSON.stringify(config));
2046
2159
  return;
2047
2160
  }
2048
- 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") {
2049
2162
  try {
2050
2163
  const body = JSON.parse(await readBody(req));
2051
2164
  const ideWorkspace = body.workspaceRoot || "";
@@ -2066,13 +2179,13 @@ async function handleRequest(url, req, res) {
2066
2179
  res.writeHead(200, { "Content-Type": "application/json" });
2067
2180
  res.end(JSON.stringify({ success: true }));
2068
2181
  } catch (e) {
2069
- 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);
2070
2183
  res.writeHead(400, { "Content-Type": "application/json" });
2071
2184
  res.end(JSON.stringify({ error: "Invalid JSON body" }));
2072
2185
  }
2073
2186
  return;
2074
2187
  }
2075
- 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") {
2076
2189
  let body;
2077
2190
  try {
2078
2191
  body = JSON.parse(await readBody(req));
@@ -2095,7 +2208,7 @@ async function handleRequest(url, req, res) {
2095
2208
  res.end(JSON.stringify({ success: true }));
2096
2209
  return;
2097
2210
  }
2098
- 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") {
2099
2212
  const file = url.searchParams.get("file") ?? "";
2100
2213
  const line = parseInt(url.searchParams.get("line") ?? "1", 10);
2101
2214
  const column = parseInt(url.searchParams.get("column") ?? "1", 10);
@@ -2129,7 +2242,7 @@ async function handleRequest(url, req, res) {
2129
2242
  }
2130
2243
  return;
2131
2244
  }
2132
- 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") {
2133
2246
  try {
2134
2247
  const rawBody = await readBody(req);
2135
2248
  const body = JSON.parse(rawBody);
@@ -2137,13 +2250,13 @@ async function handleRequest(url, req, res) {
2137
2250
  res.writeHead(result.success ? 200 : 500, { "Content-Type": "application/json" });
2138
2251
  res.end(JSON.stringify(result));
2139
2252
  } catch (e) {
2140
- 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);
2141
2254
  res.writeHead(500, { "Content-Type": "application/json" });
2142
2255
  res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
2143
2256
  }
2144
2257
  return;
2145
2258
  }
2146
- 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") {
2147
2260
  try {
2148
2261
  const rawBody = await readBody(req);
2149
2262
  const body = JSON.parse(rawBody);
@@ -2153,13 +2266,13 @@ async function handleRequest(url, req, res) {
2153
2266
  });
2154
2267
  res.end(JSON.stringify(result));
2155
2268
  } catch (e) {
2156
- 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);
2157
2270
  res.writeHead(500, { "Content-Type": "application/json" });
2158
2271
  res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
2159
2272
  }
2160
2273
  return;
2161
2274
  }
2162
- 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") {
2163
2276
  try {
2164
2277
  const rawBody = await readBody(req);
2165
2278
  const body = rawBody ? JSON.parse(rawBody) : {};
@@ -2186,7 +2299,7 @@ async function handleRequest(url, req, res) {
2186
2299
  }
2187
2300
  return;
2188
2301
  }
2189
- 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") {
2190
2303
  const statusParam = url.searchParams.getAll("status");
2191
2304
  const statuses = statusParam.length ? new Set(statusParam) : null;
2192
2305
  const sessionId = url.searchParams.get("sessionId")?.trim() || null;
@@ -2214,7 +2327,7 @@ data: ${JSON.stringify({ ok: true })}
2214
2327
  });
2215
2328
  return;
2216
2329
  }
2217
- if (pathname === import_types2.INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
2330
+ if (pathname === import_types3.INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
2218
2331
  const statusParam = url.searchParams.getAll("status");
2219
2332
  const sessions = annotationSessionStore.listSessions(
2220
2333
  statusParam.length ? {
@@ -2225,8 +2338,8 @@ data: ${JSON.stringify({ ok: true })}
2225
2338
  res.end(JSON.stringify({ success: true, sessions }));
2226
2339
  return;
2227
2340
  }
2228
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && req.method === "GET") {
2229
- 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);
2230
2343
  const session = annotationSessionStore.getSession(sessionId);
2231
2344
  if (!session) {
2232
2345
  res.writeHead(404, { "Content-Type": "application/json" });
@@ -2237,10 +2350,10 @@ data: ${JSON.stringify({ ok: true })}
2237
2350
  res.end(JSON.stringify({ success: true, session }));
2238
2351
  return;
2239
2352
  }
2240
- 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") {
2241
2354
  const sessionId = pathname.slice(
2242
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
2243
- -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
2244
2357
  );
2245
2358
  try {
2246
2359
  const rawBody = await readBody(req);
@@ -2273,10 +2386,10 @@ data: ${JSON.stringify({ ok: true })}
2273
2386
  }
2274
2387
  return;
2275
2388
  }
2276
- 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") {
2277
2390
  const sessionId = pathname.slice(
2278
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
2279
- -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
2280
2393
  );
2281
2394
  try {
2282
2395
  const rawBody = await readBody(req);
@@ -2324,10 +2437,10 @@ data: ${JSON.stringify({ ok: true })}
2324
2437
  }
2325
2438
  return;
2326
2439
  }
2327
- 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") {
2328
2441
  const sessionId = pathname.slice(
2329
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
2330
- -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
2331
2444
  );
2332
2445
  try {
2333
2446
  const rawBody = await readBody(req);
@@ -2365,8 +2478,8 @@ data: ${JSON.stringify({ ok: true })}
2365
2478
  }
2366
2479
  return;
2367
2480
  }
2368
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
2369
- 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);
2370
2483
  const payloadStr = readTicket(ticketId);
2371
2484
  if (!payloadStr) {
2372
2485
  res.writeHead(404, { "Content-Type": "application/json" });
@@ -2382,10 +2495,23 @@ data: ${JSON.stringify({ ok: true })}
2382
2495
  }
2383
2496
  async function dispatchToAi(req) {
2384
2497
  const { location, snippet, prompt } = req;
2385
- 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}):
2386
2512
 
2387
2513
  \`\`\`
2388
- ${snippet}
2514
+ ${snippet ?? ""}
2389
2515
  \`\`\`
2390
2516
  `;
2391
2517
  const runtime = resolvePromptDispatchRuntime(serverState);
@@ -2394,7 +2520,7 @@ ${snippet}
2394
2520
  filePath: location.file,
2395
2521
  line: location.line,
2396
2522
  column: location.column,
2397
- snippet
2523
+ ...snippet !== void 0 ? { snippet } : {}
2398
2524
  });
2399
2525
  }
2400
2526
  function getBatchDispatchStatusCode(errorCode, success) {