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/README.md +11 -3
- package/dist/cli.js +896 -63
- package/dist/index.d.mts +37 -7
- package/dist/index.d.ts +37 -7
- package/dist/index.js +739 -136
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +740 -137
- package/dist/index.mjs.map +1 -1
- package/dist/mcp.js +413 -0
- package/dist/server.d.mts +107 -31
- package/dist/server.d.ts +107 -31
- package/dist/server.js +451 -42
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +430 -32
- package/dist/server.mjs.map +1 -1
- package/package.json +11 -4
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
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
1282
|
-
|
|
1283
|
-
if (
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
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
|
|
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.
|
|
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;
|