skema-core 0.2.0 → 2.1.0

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/server.js CHANGED
@@ -45,7 +45,7 @@ function getGridCellReference(x, y, gridSize = 100) {
45
45
  // src/server/prompts.ts
46
46
  var CRITICAL_RULES = `CRITICAL RULES:
47
47
  - Do NOT create new files. Only edit existing files.
48
- - Do NOT modify the import { SkemaWrapper } from "@/components/skema-wrapper" line.
48
+ - Do NOT modify the Skema overlay component import or the SkemaOverlay component itself.
49
49
  - Ensure all JSX tags are properly closed - every <tag> needs a matching </tag>.
50
50
  - Do NOT run any shell commands. No npm, no git, no lint, no build commands. Just edit files.
51
51
  - STOP immediately after making the file changes. Do not verify, do not run tests, do not check status.`;
@@ -184,7 +184,7 @@ var DRAWING_IMPLEMENTATION_GUIDELINES = `- **CRITICAL: DO NOT CREATE ANY NEW FIL
184
184
  var DRAWING_ERROR_PREVENTION_RULES = `1. **NEVER CREATE NEW FILES** - Do NOT create new component files, utility files, or any other files. Write everything inline in the existing file
185
185
  2. You do not need to update package.json or anything, just add / edit the react component.
186
186
  3. Do NOT add import statements in the middle of the file or inside JSX - imports go ONLY at the top
187
- 4. Do NOT modify the import { SkemaWrapper } from "@/components/skema-wrapper" line or the SkemaWrapper component itself
187
+ 4. Do NOT modify the Skema overlay component import or the SkemaOverlay component itself
188
188
  5. If you need something that requires an import and it's not already imported, either use an alternative that doesn't need an import, or add the import at the very TOP of the file with the other imports
189
189
  6. DONT MAKE ANY CHANGES THAT WOULD RESULT IN A Build Error
190
190
  7. **JSX SYNTAX VALIDATION** - ALWAYS ensure every JSX tag is properly closed. Every opening tag like <div>, <a>, <span>, <button> MUST have a matching closing tag </div>, </a>, </span>, </button>. Self-closing tags like <img />, <input />, <br /> must end with />. Before finishing, mentally verify all tag pairs are balanced.`;
@@ -859,6 +859,50 @@ function isProviderAvailable(provider) {
859
859
  function getAvailableProviders() {
860
860
  return ["gemini", "claude"].filter(isProviderAvailable);
861
861
  }
862
+ function checkProviderAuthorized(provider) {
863
+ const { execSync: execSync3 } = __require("child_process");
864
+ try {
865
+ if (provider === "gemini") {
866
+ execSync3("gemini --version", { stdio: "ignore", timeout: 5e3 });
867
+ return true;
868
+ } else if (provider === "claude") {
869
+ execSync3("claude --version", { stdio: "ignore", timeout: 5e3 });
870
+ return true;
871
+ }
872
+ return false;
873
+ } catch {
874
+ return false;
875
+ }
876
+ }
877
+ function getProviderStatus(provider) {
878
+ const installed = isProviderAvailable(provider);
879
+ if (!installed) {
880
+ return {
881
+ installed: false,
882
+ authorized: false,
883
+ message: `${provider} CLI not installed`
884
+ };
885
+ }
886
+ const authorized = checkProviderAuthorized(provider);
887
+ if (!authorized) {
888
+ return {
889
+ installed: true,
890
+ authorized: false,
891
+ message: `${provider} CLI installed but not authorized`
892
+ };
893
+ }
894
+ return {
895
+ installed: true,
896
+ authorized: true,
897
+ message: "Ready"
898
+ };
899
+ }
900
+ function getAllProviderStatuses() {
901
+ return {
902
+ gemini: getProviderStatus("gemini"),
903
+ claude: getProviderStatus("claude")
904
+ };
905
+ }
862
906
  async function analyzeWithGemini(base64Image, apiKey, model = "gemini-2.5-flash") {
863
907
  try {
864
908
  const genAI = new generativeAi.GoogleGenerativeAI(apiKey);
@@ -966,10 +1010,108 @@ function isVisionAvailable(provider) {
966
1010
  }
967
1011
  }
968
1012
 
1013
+ // src/server/annotation-store.ts
1014
+ var storedAnnotations = /* @__PURE__ */ new Map();
1015
+ var listeners = /* @__PURE__ */ new Set();
1016
+ function notify(event, annotation) {
1017
+ for (const listener of listeners) {
1018
+ try {
1019
+ listener(event, annotation);
1020
+ } catch (e) {
1021
+ console.error("[AnnotationStore] Listener error:", e);
1022
+ }
1023
+ }
1024
+ }
1025
+ function queueAnnotation(annotation, comment) {
1026
+ const id = annotation.id || `ann-${Date.now()}`;
1027
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1028
+ const stored = {
1029
+ annotation: { ...annotation, id },
1030
+ comment,
1031
+ status: "pending",
1032
+ createdAt: now,
1033
+ updatedAt: now
1034
+ };
1035
+ storedAnnotations.set(id, stored);
1036
+ console.log(`[AnnotationStore] Queued annotation ${id}: "${comment.slice(0, 50)}..."`);
1037
+ notify("annotation.created", stored);
1038
+ return stored;
1039
+ }
1040
+ function getPendingAnnotations() {
1041
+ return Array.from(storedAnnotations.values()).filter((a) => a.status === "pending");
1042
+ }
1043
+ function getAllAnnotations() {
1044
+ return Array.from(storedAnnotations.values());
1045
+ }
1046
+ function getAnnotation(id) {
1047
+ return storedAnnotations.get(id);
1048
+ }
1049
+ function acknowledgeAnnotation(id) {
1050
+ const stored = storedAnnotations.get(id);
1051
+ if (!stored) return void 0;
1052
+ stored.status = "acknowledged";
1053
+ stored.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1054
+ notify("annotation.updated", stored);
1055
+ return stored;
1056
+ }
1057
+ function resolveAnnotation(id, summary) {
1058
+ const stored = storedAnnotations.get(id);
1059
+ if (!stored) return void 0;
1060
+ stored.status = "resolved";
1061
+ stored.resolvedBy = "agent";
1062
+ stored.resolutionSummary = summary;
1063
+ stored.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1064
+ notify("annotation.updated", stored);
1065
+ return stored;
1066
+ }
1067
+ function dismissAnnotation(id, reason) {
1068
+ const stored = storedAnnotations.get(id);
1069
+ if (!stored) return void 0;
1070
+ stored.status = "dismissed";
1071
+ stored.resolvedBy = "agent";
1072
+ stored.dismissalReason = reason;
1073
+ stored.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1074
+ notify("annotation.updated", stored);
1075
+ return stored;
1076
+ }
1077
+ function removeAnnotation(id) {
1078
+ const stored = storedAnnotations.get(id);
1079
+ if (!stored) return void 0;
1080
+ storedAnnotations.delete(id);
1081
+ notify("annotation.deleted", stored);
1082
+ return stored;
1083
+ }
1084
+ function clearAnnotations() {
1085
+ storedAnnotations.clear();
1086
+ }
1087
+ function onStoreEvent(listener) {
1088
+ listeners.add(listener);
1089
+ return () => listeners.delete(listener);
1090
+ }
1091
+ function getPendingCount() {
1092
+ let count = 0;
1093
+ for (const a of storedAnnotations.values()) {
1094
+ if (a.status === "pending") count++;
1095
+ }
1096
+ return count;
1097
+ }
1098
+
969
1099
  // src/server/daemon.ts
970
1100
  var currentProvider = "gemini";
971
1101
  var workingDirectory = process.cwd();
1102
+ var currentMode = "direct-cli";
972
1103
  var annotationSnapshots2 = /* @__PURE__ */ new Map();
1104
+ var mcpServerClient = null;
1105
+ var mcpClientName = null;
1106
+ function getAnnotationCounts() {
1107
+ const all = getAllAnnotations();
1108
+ return {
1109
+ pending: all.filter((a) => a.status === "pending").length,
1110
+ acknowledged: all.filter((a) => a.status === "acknowledged").length,
1111
+ resolved: all.filter((a) => a.status === "resolved").length,
1112
+ dismissed: all.filter((a) => a.status === "dismissed").length
1113
+ };
1114
+ }
973
1115
  function createSnapshot2(annotationId) {
974
1116
  try {
975
1117
  const stashRef = child_process.execSync("git stash create", { cwd: workingDirectory, encoding: "utf-8" }).trim();
@@ -1029,17 +1171,45 @@ var handlers = {
1029
1171
  if (!["gemini", "claude"].includes(newProvider)) {
1030
1172
  return { id: msg.id, type: "error", error: `Invalid provider: ${newProvider}` };
1031
1173
  }
1032
- if (!isProviderAvailable(newProvider)) {
1174
+ if (currentMode === "direct-cli" && !isProviderAvailable(newProvider)) {
1033
1175
  return {
1034
1176
  id: msg.id,
1035
1177
  type: "error",
1036
- error: `Provider "${newProvider}" is not installed. Run: ${newProvider === "gemini" ? "npm install -g @anthropic-ai/gemini-cli" : "npm install -g @anthropic-ai/claude-code"}`
1178
+ error: `Provider "${newProvider}" CLI is not installed.`
1037
1179
  };
1038
1180
  }
1039
1181
  currentProvider = newProvider;
1040
1182
  console.log(`[Daemon] Switched to provider: ${currentProvider}`);
1041
1183
  return { id: msg.id, type: "provider-changed", provider: currentProvider };
1042
1184
  },
1185
+ "check-providers": async (msg) => {
1186
+ const statuses = getAllProviderStatuses();
1187
+ return {
1188
+ id: msg.id,
1189
+ type: "provider-statuses",
1190
+ providerStatus: statuses
1191
+ };
1192
+ },
1193
+ // -------------------------------------------------------------------------
1194
+ // Mode Management
1195
+ // -------------------------------------------------------------------------
1196
+ "get-mode": async (msg) => {
1197
+ return {
1198
+ id: msg.id,
1199
+ type: "mode",
1200
+ mode: currentMode,
1201
+ availableModes: ["direct-cli", "mcp"]
1202
+ };
1203
+ },
1204
+ "set-mode": async (msg) => {
1205
+ const newMode = msg.mode;
1206
+ if (!["direct-cli", "mcp"].includes(newMode)) {
1207
+ return { id: msg.id, type: "error", error: `Invalid mode: ${newMode}` };
1208
+ }
1209
+ currentMode = newMode;
1210
+ console.log(`[Daemon] Switched to mode: ${currentMode}`);
1211
+ return { id: msg.id, type: "mode-changed", mode: currentMode };
1212
+ },
1043
1213
  // -------------------------------------------------------------------------
1044
1214
  // AI Generation (streaming)
1045
1215
  // -------------------------------------------------------------------------
@@ -1047,21 +1217,41 @@ var handlers = {
1047
1217
  const annotation = msg.annotation;
1048
1218
  const projectContext = msg.projectContext;
1049
1219
  const annotationId = annotation.id || `temp-${Date.now()}`;
1220
+ const requestMode = msg.mode || currentMode;
1221
+ const requestProvider = msg.provider || currentProvider;
1222
+ if (requestMode === "mcp") {
1223
+ const comment = annotation.comment || "";
1224
+ const stored = queueAnnotation(annotation, comment);
1225
+ const counts = getAnnotationCounts();
1226
+ sendMessage(ws, {
1227
+ id: msg.id,
1228
+ type: "annotation-queued",
1229
+ success: true,
1230
+ annotationId: stored.annotation.id,
1231
+ pendingCount: getPendingCount(),
1232
+ annotationCounts: counts
1233
+ });
1234
+ broadcastToClients({
1235
+ type: "mcp-annotation-counts",
1236
+ counts
1237
+ });
1238
+ return;
1239
+ }
1050
1240
  createSnapshot2(annotationId);
1051
1241
  let visionDescription = "";
1052
1242
  const drawingAnnotation = annotation;
1053
1243
  if (annotation.type === "drawing" && drawingAnnotation.drawingImage) {
1244
+ sendMessage(ws, {
1245
+ id: msg.id,
1246
+ type: "ai-event",
1247
+ event: {
1248
+ type: "text",
1249
+ content: `[Analyzing drawing with vision...]`,
1250
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1251
+ provider: requestProvider
1252
+ }
1253
+ });
1054
1254
  if (isVisionAvailable("gemini")) {
1055
- sendMessage(ws, {
1056
- id: msg.id,
1057
- type: "ai-event",
1058
- event: {
1059
- type: "text",
1060
- content: `[Analyzing drawing with Gemini vision...]`,
1061
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1062
- provider: currentProvider
1063
- }
1064
- });
1065
1255
  const visionResult = await analyzeImage(drawingAnnotation.drawingImage, {
1066
1256
  provider: "gemini"
1067
1257
  });
@@ -1075,7 +1265,7 @@ var handlers = {
1075
1265
  content: `[Vision analysis complete]
1076
1266
  ${visionDescription}`,
1077
1267
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1078
- provider: currentProvider
1268
+ provider: requestProvider
1079
1269
  }
1080
1270
  });
1081
1271
  } else {
@@ -1086,7 +1276,7 @@ ${visionDescription}`,
1086
1276
  type: "error",
1087
1277
  content: `Vision analysis failed: ${visionResult.error}`,
1088
1278
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1089
- provider: currentProvider
1279
+ provider: requestProvider
1090
1280
  }
1091
1281
  });
1092
1282
  }
@@ -1098,14 +1288,13 @@ ${visionDescription}`,
1098
1288
  type: "text",
1099
1289
  content: `[Vision not available - set GEMINI_API_KEY for image analysis]`,
1100
1290
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1101
- provider: currentProvider
1291
+ provider: requestProvider
1102
1292
  }
1103
1293
  });
1104
1294
  }
1105
1295
  }
1106
1296
  const prompt = buildPromptFromAnnotation(annotation, projectContext, {
1107
1297
  fastMode: msg.fastMode === true,
1108
- // Default to detailed mode (false) unless explicitly set to true
1109
1298
  visionDescription
1110
1299
  });
1111
1300
  sendMessage(ws, {
@@ -1115,11 +1304,25 @@ ${visionDescription}`,
1115
1304
  type: "debug",
1116
1305
  content: prompt,
1117
1306
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1118
- provider: currentProvider
1307
+ provider: requestProvider
1119
1308
  }
1120
1309
  });
1310
+ const cliProvider = requestProvider;
1311
+ if (!isProviderAvailable(cliProvider)) {
1312
+ sendMessage(ws, {
1313
+ id: msg.id,
1314
+ type: "ai-event",
1315
+ event: {
1316
+ type: "error",
1317
+ content: `${requestProvider} CLI is not installed. Run: npm install -g @google/gemini-cli`,
1318
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1319
+ provider: requestProvider
1320
+ }
1321
+ });
1322
+ return;
1323
+ }
1121
1324
  const config = {
1122
- provider: currentProvider,
1325
+ provider: cliProvider,
1123
1326
  cwd: workingDirectory,
1124
1327
  model: msg.model
1125
1328
  };
@@ -1137,7 +1340,8 @@ ${visionDescription}`,
1137
1340
  type: "generate-complete",
1138
1341
  success: true,
1139
1342
  annotationId,
1140
- provider: currentProvider
1343
+ provider: requestProvider,
1344
+ mode: requestMode
1141
1345
  });
1142
1346
  break;
1143
1347
  }
@@ -1155,6 +1359,109 @@ ${visionDescription}`,
1155
1359
  return { id: msg.id, type: "revert-result", ...result };
1156
1360
  },
1157
1361
  // -------------------------------------------------------------------------
1362
+ // MCP Annotation Queue Management
1363
+ // -------------------------------------------------------------------------
1364
+ "get-pending-annotations": async (msg) => {
1365
+ const pending = getPendingAnnotations();
1366
+ return {
1367
+ id: msg.id,
1368
+ type: "pending-annotations",
1369
+ count: pending.length,
1370
+ annotations: pending.map(serializeStoredAnnotation)
1371
+ };
1372
+ },
1373
+ "get-all-annotations": async (msg) => {
1374
+ const all = getAllAnnotations();
1375
+ return {
1376
+ id: msg.id,
1377
+ type: "all-annotations",
1378
+ count: all.length,
1379
+ annotations: all.map(serializeStoredAnnotation)
1380
+ };
1381
+ },
1382
+ "get-annotation": async (msg) => {
1383
+ const id = msg.annotationId;
1384
+ const stored = getAnnotation(id);
1385
+ if (!stored) {
1386
+ return { id: msg.id, type: "error", error: `Annotation not found: ${id}` };
1387
+ }
1388
+ return {
1389
+ id: msg.id,
1390
+ type: "annotation",
1391
+ annotation: serializeStoredAnnotation(stored)
1392
+ };
1393
+ },
1394
+ "acknowledge-annotation": async (msg) => {
1395
+ const id = msg.annotationId;
1396
+ const stored = acknowledgeAnnotation(id);
1397
+ if (!stored) {
1398
+ return { id: msg.id, type: "error", error: `Annotation not found: ${id}` };
1399
+ }
1400
+ const counts = getAnnotationCounts();
1401
+ broadcastToClients({
1402
+ type: "annotation-status-changed",
1403
+ annotationId: id,
1404
+ status: "acknowledged"
1405
+ });
1406
+ broadcastToClients({ type: "mcp-annotation-counts", counts });
1407
+ return {
1408
+ id: msg.id,
1409
+ type: "annotation-acknowledged",
1410
+ annotationId: id
1411
+ };
1412
+ },
1413
+ "resolve-annotation": async (msg) => {
1414
+ const id = msg.annotationId;
1415
+ const summary = msg.summary;
1416
+ const stored = resolveAnnotation(id, summary);
1417
+ if (!stored) {
1418
+ return { id: msg.id, type: "error", error: `Annotation not found: ${id}` };
1419
+ }
1420
+ const counts = getAnnotationCounts();
1421
+ broadcastToClients({
1422
+ type: "annotation-status-changed",
1423
+ annotationId: id,
1424
+ status: "resolved",
1425
+ summary
1426
+ });
1427
+ broadcastToClients({ type: "mcp-annotation-counts", counts });
1428
+ return {
1429
+ id: msg.id,
1430
+ type: "annotation-resolved",
1431
+ annotationId: id,
1432
+ summary
1433
+ };
1434
+ },
1435
+ "dismiss-annotation": async (msg) => {
1436
+ const id = msg.annotationId;
1437
+ const reason = msg.reason;
1438
+ const stored = dismissAnnotation(id, reason);
1439
+ if (!stored) {
1440
+ return { id: msg.id, type: "error", error: `Annotation not found: ${id}` };
1441
+ }
1442
+ const counts = getAnnotationCounts();
1443
+ broadcastToClients({
1444
+ type: "annotation-status-changed",
1445
+ annotationId: id,
1446
+ status: "dismissed",
1447
+ reason
1448
+ });
1449
+ broadcastToClients({ type: "mcp-annotation-counts", counts });
1450
+ return {
1451
+ id: msg.id,
1452
+ type: "annotation-dismissed",
1453
+ annotationId: id,
1454
+ reason
1455
+ };
1456
+ },
1457
+ "clear-queued-annotations": async (msg) => {
1458
+ clearAnnotations();
1459
+ return {
1460
+ id: msg.id,
1461
+ type: "annotations-cleared"
1462
+ };
1463
+ },
1464
+ // -------------------------------------------------------------------------
1158
1465
  // File Operations
1159
1466
  // -------------------------------------------------------------------------
1160
1467
  "read-file": async (msg) => {
@@ -1216,6 +1523,33 @@ ${visionDescription}`,
1216
1523
  });
1217
1524
  },
1218
1525
  // -------------------------------------------------------------------------
1526
+ // MCP Server Identification
1527
+ // -------------------------------------------------------------------------
1528
+ identify: async (msg, ws) => {
1529
+ if (msg.client === "mcp-server") {
1530
+ mcpServerClient = ws;
1531
+ mcpClientName = null;
1532
+ console.log("[Daemon] MCP server identified and connected");
1533
+ broadcastToClients({
1534
+ type: "mcp-server-status",
1535
+ connected: true,
1536
+ clientName: null
1537
+ });
1538
+ return { id: msg.id, type: "identified", client: "mcp-server" };
1539
+ }
1540
+ return { id: msg.id, type: "identified", client: "unknown" };
1541
+ },
1542
+ "mcp-client-info": async (msg) => {
1543
+ mcpClientName = msg.clientName || null;
1544
+ console.log("[Daemon] MCP client identified:", mcpClientName, msg.clientVersion || "");
1545
+ broadcastToClients({
1546
+ type: "mcp-server-status",
1547
+ connected: true,
1548
+ clientName: mcpClientName
1549
+ });
1550
+ return { id: msg.id, type: "ok" };
1551
+ },
1552
+ // -------------------------------------------------------------------------
1219
1553
  // Status
1220
1554
  // -------------------------------------------------------------------------
1221
1555
  ping: async (msg) => {
@@ -1223,54 +1557,112 @@ ${visionDescription}`,
1223
1557
  id: msg.id,
1224
1558
  type: "pong",
1225
1559
  provider: currentProvider,
1560
+ mode: currentMode,
1226
1561
  cwd: workingDirectory,
1227
- availableProviders: getAvailableProviders()
1562
+ availableProviders: getAvailableProviders(),
1563
+ availableModes: ["direct-cli", "mcp"],
1564
+ mcpServerConnected: mcpServerClient?.readyState === ws.WebSocket.OPEN,
1565
+ mcpClientName
1228
1566
  };
1229
1567
  }
1230
1568
  };
1569
+ var connectedClients = /* @__PURE__ */ new Set();
1570
+ function broadcastToClients(message) {
1571
+ for (const client of connectedClients) {
1572
+ sendMessage(client, message);
1573
+ }
1574
+ }
1575
+ function serializeStoredAnnotation(stored) {
1576
+ return {
1577
+ id: stored.annotation.id,
1578
+ type: stored.annotation.type,
1579
+ comment: stored.comment,
1580
+ status: stored.status,
1581
+ createdAt: stored.createdAt,
1582
+ updatedAt: stored.updatedAt,
1583
+ resolvedBy: stored.resolvedBy,
1584
+ resolutionSummary: stored.resolutionSummary,
1585
+ dismissalReason: stored.dismissalReason,
1586
+ // Include key annotation data the agent needs
1587
+ annotation: {
1588
+ type: stored.annotation.type,
1589
+ selector: stored.annotation.selector,
1590
+ tagName: stored.annotation.tagName,
1591
+ text: stored.annotation.text,
1592
+ elementPath: stored.annotation.elementPath,
1593
+ boundingBox: stored.annotation.boundingBox,
1594
+ drawingSvg: stored.annotation.drawingSvg,
1595
+ drawingImage: stored.annotation.drawingImage,
1596
+ extractedText: stored.annotation.extractedText,
1597
+ nearbyElements: stored.annotation.nearbyElements,
1598
+ viewport: stored.annotation.viewport,
1599
+ projectStyles: stored.annotation.projectStyles,
1600
+ isMultiSelect: stored.annotation.isMultiSelect,
1601
+ elements: stored.annotation.elements
1602
+ }
1603
+ };
1604
+ }
1231
1605
  function sendMessage(ws$1, message) {
1232
1606
  if (ws$1.readyState === ws.WebSocket.OPEN) {
1233
1607
  ws$1.send(JSON.stringify(message));
1234
1608
  }
1235
1609
  }
1236
- function handleConnection(ws) {
1610
+ function handleConnection(ws$1) {
1237
1611
  console.log("[Daemon] Client connected");
1238
- sendMessage(ws, {
1612
+ connectedClients.add(ws$1);
1613
+ sendMessage(ws$1, {
1239
1614
  type: "connected",
1240
1615
  provider: currentProvider,
1616
+ mode: currentMode,
1241
1617
  cwd: workingDirectory,
1242
- availableProviders: getAvailableProviders()
1618
+ availableProviders: getAvailableProviders(),
1619
+ availableModes: ["direct-cli", "mcp"],
1620
+ pendingAnnotations: currentMode === "mcp" ? getPendingCount() : 0,
1621
+ providerStatus: getAllProviderStatuses(),
1622
+ mcpServerConnected: mcpServerClient?.readyState === ws.WebSocket.OPEN,
1623
+ mcpClientName
1243
1624
  });
1244
- ws.on("message", async (data) => {
1625
+ ws$1.on("message", async (data) => {
1245
1626
  let msg;
1246
1627
  try {
1247
1628
  msg = JSON.parse(data.toString());
1248
1629
  } catch {
1249
- sendMessage(ws, { type: "error", error: "Invalid JSON" });
1630
+ sendMessage(ws$1, { type: "error", error: "Invalid JSON" });
1250
1631
  return;
1251
1632
  }
1252
1633
  const handler = handlers[msg.type];
1253
1634
  if (!handler) {
1254
- sendMessage(ws, { id: msg.id, type: "error", error: `Unknown message type: ${msg.type}` });
1635
+ sendMessage(ws$1, { id: msg.id, type: "error", error: `Unknown message type: ${msg.type}` });
1255
1636
  return;
1256
1637
  }
1257
1638
  try {
1258
- const response = await handler(msg, ws);
1639
+ const response = await handler(msg, ws$1);
1259
1640
  if (response) {
1260
- sendMessage(ws, response);
1641
+ sendMessage(ws$1, response);
1261
1642
  }
1262
1643
  } catch (error) {
1263
- sendMessage(ws, {
1644
+ sendMessage(ws$1, {
1264
1645
  id: msg.id,
1265
1646
  type: "error",
1266
1647
  error: `Handler error: ${error}`
1267
1648
  });
1268
1649
  }
1269
1650
  });
1270
- ws.on("close", () => {
1651
+ ws$1.on("close", () => {
1271
1652
  console.log("[Daemon] Client disconnected");
1653
+ connectedClients.delete(ws$1);
1654
+ if (ws$1 === mcpServerClient) {
1655
+ mcpServerClient = null;
1656
+ mcpClientName = null;
1657
+ console.log("[Daemon] MCP server disconnected");
1658
+ broadcastToClients({
1659
+ type: "mcp-server-status",
1660
+ connected: false,
1661
+ clientName: null
1662
+ });
1663
+ }
1272
1664
  });
1273
- ws.on("error", (error) => {
1665
+ ws$1.on("error", (error) => {
1274
1666
  console.error("[Daemon] WebSocket error:", error);
1275
1667
  });
1276
1668
  }
@@ -1278,25 +1670,31 @@ function startDaemon(config = {}) {
1278
1670
  const port = config.port ?? 9999;
1279
1671
  workingDirectory = config.cwd ?? process.cwd();
1280
1672
  currentProvider = config.defaultProvider ?? "gemini";
1281
- if (!isProviderAvailable(currentProvider)) {
1282
- const available = getAvailableProviders();
1283
- if (available.length > 0) {
1284
- console.log(`[Daemon] ${currentProvider} not found, falling back to ${available[0]}`);
1285
- currentProvider = available[0];
1286
- } else {
1287
- console.warn("[Daemon] Warning: No AI providers found. Install gemini or claude CLI.");
1673
+ currentMode = config.defaultMode ?? "direct-cli";
1674
+ if (currentMode === "direct-cli") {
1675
+ if (!isProviderAvailable(currentProvider)) {
1676
+ const available = getAvailableProviders();
1677
+ if (available.length > 0) {
1678
+ console.log(`[Daemon] ${currentProvider} CLI not found, falling back to ${available[0]}`);
1679
+ currentProvider = available[0];
1680
+ } else {
1681
+ console.warn("[Daemon] Warning: No CLI providers found. Install gemini or claude CLI.");
1682
+ }
1288
1683
  }
1289
1684
  }
1290
1685
  const wss = new ws.WebSocketServer({ port });
1291
1686
  wss.on("connection", handleConnection);
1292
1687
  wss.on("listening", () => {
1688
+ const cliProviders = getAvailableProviders();
1293
1689
  console.log("");
1294
1690
  console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1295
1691
  console.log(" \u2502 \u2502");
1296
- console.log(` \u2502 \u{1F3A8} Skema Daemon running on ws://localhost:${port} \u2502`);
1692
+ console.log(` \u2502 Skema Daemon running on ws://localhost:${port} \u2502`);
1297
1693
  console.log(" \u2502 \u2502");
1694
+ console.log(` \u2502 Mode: ${currentMode.padEnd(39)}\u2502`);
1298
1695
  console.log(` \u2502 Provider: ${currentProvider.padEnd(35)}\u2502`);
1299
1696
  console.log(` \u2502 Directory: ${workingDirectory.slice(-33).padEnd(34)}\u2502`);
1697
+ console.log(` \u2502 CLI Providers: ${(cliProviders.join(", ") || "none").padEnd(29)}\u2502`);
1300
1698
  console.log(" \u2502 \u2502");
1301
1699
  console.log(" \u2502 Waiting for browser connections... \u2502");
1302
1700
  console.log(" \u2502 \u2502");
@@ -1322,19 +1720,30 @@ function startDaemon(config = {}) {
1322
1720
  exports.DELETE = DELETE;
1323
1721
  exports.IMAGE_ANALYSIS_PROMPT = IMAGE_ANALYSIS_PROMPT;
1324
1722
  exports.POST = POST;
1723
+ exports.acknowledgeAnnotation = acknowledgeAnnotation;
1325
1724
  exports.analyzeImage = analyzeImage;
1326
1725
  exports.buildDetailedDomSelectionPrompt = buildDetailedDomSelectionPrompt;
1327
1726
  exports.buildDrawingToCodePrompt = buildDrawingToCodePrompt;
1328
1727
  exports.buildFastDomSelectionPrompt = buildFastDomSelectionPrompt;
1329
1728
  exports.buildGesturePrompt = buildGesturePrompt;
1330
1729
  exports.buildPromptFromAnnotation = buildPromptFromAnnotation;
1730
+ exports.clearAnnotations = clearAnnotations;
1331
1731
  exports.createGeminiCLIStream = createGeminiCLIStream;
1332
1732
  exports.createGeminiRouteHandler = createGeminiRouteHandler;
1333
1733
  exports.createRevertRouteHandler = createRevertRouteHandler;
1334
- exports.getAvailableProviders = getAvailableProviders;
1734
+ exports.dismissAnnotation = dismissAnnotation;
1735
+ exports.getAllAnnotations = getAllAnnotations;
1736
+ exports.getAnnotation = getAnnotation;
1737
+ exports.getCLIProviders = getAvailableProviders;
1738
+ exports.getPendingAnnotations = getPendingAnnotations;
1739
+ exports.getPendingCount = getPendingCount;
1335
1740
  exports.getTrackedAnnotations = getTrackedAnnotations;
1336
1741
  exports.isProviderAvailable = isProviderAvailable;
1337
1742
  exports.isVisionAvailable = isVisionAvailable;
1743
+ exports.onStoreEvent = onStoreEvent;
1744
+ exports.queueAnnotation = queueAnnotation;
1745
+ exports.removeAnnotation = removeAnnotation;
1746
+ exports.resolveAnnotation = resolveAnnotation;
1338
1747
  exports.revertAnnotation = revertAnnotation;
1339
1748
  exports.runAICLI = runAICLI;
1340
1749
  exports.runGeminiCLI = runGeminiCLI;