@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/astro.cjs CHANGED
@@ -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,43 +1248,62 @@ 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;
1186
1299
  }
1187
1300
 
1188
1301
  // src/server/server-url.ts
1189
1302
  function resolveServerHost(cwd, configRoot) {
1303
+ if (process.env["VITEST"]) return "127.0.0.1";
1190
1304
  const userConfig = loadUserConfigSync(false, cwd, configRoot);
1191
1305
  const configuredHost = userConfig["server.host"]?.trim();
1192
1306
  if (configuredHost) return configuredHost;
1193
- if (process.env["VITEST"]) return "127.0.0.1";
1194
1307
  return "127.0.0.1";
1195
1308
  }
1196
1309
  function resolvePublicServerUrl(args) {
@@ -1255,7 +1368,7 @@ async function startServer() {
1255
1368
  return serverState.port;
1256
1369
  }
1257
1370
  serverState.projectRoot = resolveProjectRoot();
1258
- serverState.configRoot = serverState.projectRoot;
1371
+ serverState.configRoot = resolveWorkspaceRoot();
1259
1372
  serverState.cwd = process.cwd();
1260
1373
  const serverHost = resolveServerHost(serverState.cwd, serverState.configRoot);
1261
1374
  import_portfinder.default.basePort = 5678;
@@ -1319,19 +1432,19 @@ async function readBody(req) {
1319
1432
  }
1320
1433
  async function handleRequest(url, req, res) {
1321
1434
  const pathname = url.pathname;
1322
- 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") {
1323
1436
  res.writeHead(200, { "Content-Type": "application/json" });
1324
1437
  res.end(JSON.stringify({ ok: true, port: serverState.port }));
1325
1438
  return;
1326
1439
  }
1327
- 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") {
1328
1441
  const config = await buildClientConfig(serverState);
1329
1442
  delete config.providers;
1330
1443
  res.writeHead(200, { "Content-Type": "application/json" });
1331
1444
  res.end(JSON.stringify(config));
1332
1445
  return;
1333
1446
  }
1334
- 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") {
1335
1448
  try {
1336
1449
  const body = JSON.parse(await readBody(req));
1337
1450
  const ideWorkspace = body.workspaceRoot || "";
@@ -1352,13 +1465,13 @@ async function handleRequest(url, req, res) {
1352
1465
  res.writeHead(200, { "Content-Type": "application/json" });
1353
1466
  res.end(JSON.stringify({ success: true }));
1354
1467
  } catch (e) {
1355
- 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);
1356
1469
  res.writeHead(400, { "Content-Type": "application/json" });
1357
1470
  res.end(JSON.stringify({ error: "Invalid JSON body" }));
1358
1471
  }
1359
1472
  return;
1360
1473
  }
1361
- 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") {
1362
1475
  let body;
1363
1476
  try {
1364
1477
  body = JSON.parse(await readBody(req));
@@ -1381,7 +1494,7 @@ async function handleRequest(url, req, res) {
1381
1494
  res.end(JSON.stringify({ success: true }));
1382
1495
  return;
1383
1496
  }
1384
- 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") {
1385
1498
  const file = url.searchParams.get("file") ?? "";
1386
1499
  const line = parseInt(url.searchParams.get("line") ?? "1", 10);
1387
1500
  const column = parseInt(url.searchParams.get("column") ?? "1", 10);
@@ -1415,7 +1528,7 @@ async function handleRequest(url, req, res) {
1415
1528
  }
1416
1529
  return;
1417
1530
  }
1418
- 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") {
1419
1532
  try {
1420
1533
  const rawBody = await readBody(req);
1421
1534
  const body = JSON.parse(rawBody);
@@ -1423,13 +1536,13 @@ async function handleRequest(url, req, res) {
1423
1536
  res.writeHead(result.success ? 200 : 500, { "Content-Type": "application/json" });
1424
1537
  res.end(JSON.stringify(result));
1425
1538
  } catch (e) {
1426
- 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);
1427
1540
  res.writeHead(500, { "Content-Type": "application/json" });
1428
1541
  res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
1429
1542
  }
1430
1543
  return;
1431
1544
  }
1432
- 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") {
1433
1546
  try {
1434
1547
  const rawBody = await readBody(req);
1435
1548
  const body = JSON.parse(rawBody);
@@ -1439,13 +1552,13 @@ async function handleRequest(url, req, res) {
1439
1552
  });
1440
1553
  res.end(JSON.stringify(result));
1441
1554
  } catch (e) {
1442
- 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);
1443
1556
  res.writeHead(500, { "Content-Type": "application/json" });
1444
1557
  res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
1445
1558
  }
1446
1559
  return;
1447
1560
  }
1448
- 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") {
1449
1562
  try {
1450
1563
  const rawBody = await readBody(req);
1451
1564
  const body = rawBody ? JSON.parse(rawBody) : {};
@@ -1472,7 +1585,7 @@ async function handleRequest(url, req, res) {
1472
1585
  }
1473
1586
  return;
1474
1587
  }
1475
- 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") {
1476
1589
  const statusParam = url.searchParams.getAll("status");
1477
1590
  const statuses = statusParam.length ? new Set(statusParam) : null;
1478
1591
  const sessionId = url.searchParams.get("sessionId")?.trim() || null;
@@ -1500,7 +1613,7 @@ data: ${JSON.stringify({ ok: true })}
1500
1613
  });
1501
1614
  return;
1502
1615
  }
1503
- if (pathname === import_types2.INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
1616
+ if (pathname === import_types3.INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
1504
1617
  const statusParam = url.searchParams.getAll("status");
1505
1618
  const sessions = annotationSessionStore.listSessions(
1506
1619
  statusParam.length ? {
@@ -1511,8 +1624,8 @@ data: ${JSON.stringify({ ok: true })}
1511
1624
  res.end(JSON.stringify({ success: true, sessions }));
1512
1625
  return;
1513
1626
  }
1514
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.SESSIONS}/`) && req.method === "GET") {
1515
- const sessionId = pathname.substring(import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1);
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);
1516
1629
  const session = annotationSessionStore.getSession(sessionId);
1517
1630
  if (!session) {
1518
1631
  res.writeHead(404, { "Content-Type": "application/json" });
@@ -1523,10 +1636,10 @@ data: ${JSON.stringify({ ok: true })}
1523
1636
  res.end(JSON.stringify({ success: true, session }));
1524
1637
  return;
1525
1638
  }
1526
- 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") {
1527
1640
  const sessionId = pathname.slice(
1528
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
1529
- -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
1530
1643
  );
1531
1644
  try {
1532
1645
  const rawBody = await readBody(req);
@@ -1559,10 +1672,10 @@ data: ${JSON.stringify({ ok: true })}
1559
1672
  }
1560
1673
  return;
1561
1674
  }
1562
- 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") {
1563
1676
  const sessionId = pathname.slice(
1564
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
1565
- -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
1566
1679
  );
1567
1680
  try {
1568
1681
  const rawBody = await readBody(req);
@@ -1610,10 +1723,10 @@ data: ${JSON.stringify({ ok: true })}
1610
1723
  }
1611
1724
  return;
1612
1725
  }
1613
- 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") {
1614
1727
  const sessionId = pathname.slice(
1615
- import_types2.INSPECTO_API_PATHS.SESSIONS.length + 1,
1616
- -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
1617
1730
  );
1618
1731
  try {
1619
1732
  const rawBody = await readBody(req);
@@ -1651,8 +1764,8 @@ data: ${JSON.stringify({ ok: true })}
1651
1764
  }
1652
1765
  return;
1653
1766
  }
1654
- if (pathname.startsWith(`${import_types2.INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
1655
- 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);
1656
1769
  const payloadStr = readTicket(ticketId);
1657
1770
  if (!payloadStr) {
1658
1771
  res.writeHead(404, { "Content-Type": "application/json" });
@@ -1668,10 +1781,23 @@ data: ${JSON.stringify({ ok: true })}
1668
1781
  }
1669
1782
  async function dispatchToAi(req) {
1670
1783
  const { location, snippet, prompt } = req;
1671
- 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}):
1672
1798
 
1673
1799
  \`\`\`
1674
- ${snippet}
1800
+ ${snippet ?? ""}
1675
1801
  \`\`\`
1676
1802
  `;
1677
1803
  const runtime = resolvePromptDispatchRuntime(serverState);
@@ -1680,7 +1806,7 @@ ${snippet}
1680
1806
  filePath: location.file,
1681
1807
  line: location.line,
1682
1808
  column: location.column,
1683
- snippet
1809
+ ...snippet !== void 0 ? { snippet } : {}
1684
1810
  });
1685
1811
  }
1686
1812
  function getBatchDispatchStatusCode(errorCode, success) {