bluera-knowledge 0.10.0 → 0.11.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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +25 -0
- package/README.md +98 -2
- package/commands/sync.md +96 -0
- package/dist/{chunk-ITH6FWQY.js → chunk-2WBITQWZ.js} +24 -3
- package/dist/{chunk-ITH6FWQY.js.map → chunk-2WBITQWZ.js.map} +1 -1
- package/dist/{chunk-CUHYSPRV.js → chunk-565OVW3C.js} +999 -2
- package/dist/chunk-565OVW3C.js.map +1 -0
- package/dist/{chunk-DWAIT2OD.js → chunk-TRDMYKGC.js} +190 -5
- package/dist/chunk-TRDMYKGC.js.map +1 -0
- package/dist/index.js +217 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +2 -2
- package/dist/workers/background-worker-cli.js +2 -2
- package/package.json +1 -1
- package/src/analysis/adapter-registry.test.ts +211 -0
- package/src/analysis/adapter-registry.ts +155 -0
- package/src/analysis/language-adapter.ts +127 -0
- package/src/analysis/parser-factory.test.ts +79 -1
- package/src/analysis/parser-factory.ts +8 -0
- package/src/analysis/zil/index.ts +34 -0
- package/src/analysis/zil/zil-adapter.test.ts +187 -0
- package/src/analysis/zil/zil-adapter.ts +121 -0
- package/src/analysis/zil/zil-lexer.test.ts +222 -0
- package/src/analysis/zil/zil-lexer.ts +239 -0
- package/src/analysis/zil/zil-parser.test.ts +210 -0
- package/src/analysis/zil/zil-parser.ts +360 -0
- package/src/analysis/zil/zil-special-forms.ts +193 -0
- package/src/cli/commands/sync.test.ts +54 -0
- package/src/cli/commands/sync.ts +264 -0
- package/src/cli/index.ts +1 -0
- package/src/crawl/claude-client.test.ts +56 -0
- package/src/crawl/claude-client.ts +27 -1
- package/src/index.ts +8 -0
- package/src/mcp/commands/index.ts +2 -0
- package/src/mcp/commands/sync.commands.test.ts +283 -0
- package/src/mcp/commands/sync.commands.ts +233 -0
- package/src/mcp/server.ts +9 -1
- package/src/services/gitignore.service.test.ts +157 -0
- package/src/services/gitignore.service.ts +132 -0
- package/src/services/store-definition.service.test.ts +440 -0
- package/src/services/store-definition.service.ts +198 -0
- package/src/services/store.service.test.ts +279 -1
- package/src/services/store.service.ts +101 -4
- package/src/types/index.ts +18 -0
- package/src/types/store-definition.test.ts +492 -0
- package/src/types/store-definition.ts +129 -0
- package/dist/chunk-CUHYSPRV.js.map +0 -1
- package/dist/chunk-DWAIT2OD.js.map +0 -1
|
@@ -1,16 +1,639 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AdapterRegistry,
|
|
2
3
|
JobService,
|
|
4
|
+
ProjectRootService,
|
|
3
5
|
createLogger,
|
|
4
6
|
createServices,
|
|
5
7
|
createStoreId,
|
|
6
8
|
summarizePayload
|
|
7
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-TRDMYKGC.js";
|
|
8
10
|
|
|
9
11
|
// src/mcp/server.ts
|
|
10
12
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
11
13
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
14
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
13
15
|
|
|
16
|
+
// src/analysis/zil/zil-lexer.ts
|
|
17
|
+
var ZilLexer = class {
|
|
18
|
+
input = "";
|
|
19
|
+
pos = 0;
|
|
20
|
+
line = 1;
|
|
21
|
+
column = 1;
|
|
22
|
+
tokens = [];
|
|
23
|
+
/**
|
|
24
|
+
* Tokenize ZIL source code
|
|
25
|
+
*
|
|
26
|
+
* @param input - Source code string
|
|
27
|
+
* @returns Array of tokens
|
|
28
|
+
* @throws On unterminated strings
|
|
29
|
+
*/
|
|
30
|
+
tokenize(input) {
|
|
31
|
+
this.input = input;
|
|
32
|
+
this.pos = 0;
|
|
33
|
+
this.line = 1;
|
|
34
|
+
this.column = 1;
|
|
35
|
+
this.tokens = [];
|
|
36
|
+
while (!this.isAtEnd()) {
|
|
37
|
+
this.scanToken();
|
|
38
|
+
}
|
|
39
|
+
return this.tokens;
|
|
40
|
+
}
|
|
41
|
+
isAtEnd() {
|
|
42
|
+
return this.pos >= this.input.length;
|
|
43
|
+
}
|
|
44
|
+
peek() {
|
|
45
|
+
if (this.isAtEnd()) return "\0";
|
|
46
|
+
return this.input[this.pos] ?? "\0";
|
|
47
|
+
}
|
|
48
|
+
advance() {
|
|
49
|
+
const char = this.input[this.pos] ?? "\0";
|
|
50
|
+
this.pos++;
|
|
51
|
+
if (char === "\n") {
|
|
52
|
+
this.line++;
|
|
53
|
+
this.column = 1;
|
|
54
|
+
} else {
|
|
55
|
+
this.column++;
|
|
56
|
+
}
|
|
57
|
+
return char;
|
|
58
|
+
}
|
|
59
|
+
addToken(type, value, startLine, startColumn) {
|
|
60
|
+
this.tokens.push({
|
|
61
|
+
type,
|
|
62
|
+
value,
|
|
63
|
+
line: startLine,
|
|
64
|
+
column: startColumn
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
scanToken() {
|
|
68
|
+
const startLine = this.line;
|
|
69
|
+
const startColumn = this.column;
|
|
70
|
+
const char = this.advance();
|
|
71
|
+
switch (char) {
|
|
72
|
+
case "<":
|
|
73
|
+
this.addToken("LANGLE" /* LANGLE */, "<", startLine, startColumn);
|
|
74
|
+
break;
|
|
75
|
+
case ">":
|
|
76
|
+
this.addToken("RANGLE" /* RANGLE */, ">", startLine, startColumn);
|
|
77
|
+
break;
|
|
78
|
+
case "(":
|
|
79
|
+
this.addToken("LPAREN" /* LPAREN */, "(", startLine, startColumn);
|
|
80
|
+
break;
|
|
81
|
+
case ")":
|
|
82
|
+
this.addToken("RPAREN" /* RPAREN */, ")", startLine, startColumn);
|
|
83
|
+
break;
|
|
84
|
+
case '"':
|
|
85
|
+
this.scanString(startLine, startColumn);
|
|
86
|
+
break;
|
|
87
|
+
case ";":
|
|
88
|
+
this.skipComment();
|
|
89
|
+
break;
|
|
90
|
+
case " ":
|
|
91
|
+
case " ":
|
|
92
|
+
case "\r":
|
|
93
|
+
case "\n":
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
if (this.isDigit(char) || char === "-" && this.isDigit(this.peek())) {
|
|
97
|
+
this.scanNumber(char, startLine, startColumn);
|
|
98
|
+
} else if (this.isAtomStart(char)) {
|
|
99
|
+
this.scanAtom(char, startLine, startColumn);
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
scanString(startLine, startColumn) {
|
|
105
|
+
let value = "";
|
|
106
|
+
while (!this.isAtEnd() && this.peek() !== '"') {
|
|
107
|
+
const char = this.peek();
|
|
108
|
+
if (char === "\\") {
|
|
109
|
+
this.advance();
|
|
110
|
+
const escaped = this.advance();
|
|
111
|
+
switch (escaped) {
|
|
112
|
+
case '"':
|
|
113
|
+
value += '"';
|
|
114
|
+
break;
|
|
115
|
+
case "\\":
|
|
116
|
+
value += "\\";
|
|
117
|
+
break;
|
|
118
|
+
case "n":
|
|
119
|
+
value += "\n";
|
|
120
|
+
break;
|
|
121
|
+
case "t":
|
|
122
|
+
value += " ";
|
|
123
|
+
break;
|
|
124
|
+
default:
|
|
125
|
+
value += escaped;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
value += this.advance();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (this.isAtEnd()) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`Unterminated string at line ${String(startLine)}, column ${String(startColumn)}`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
this.advance();
|
|
138
|
+
this.addToken("STRING" /* STRING */, value, startLine, startColumn);
|
|
139
|
+
}
|
|
140
|
+
scanNumber(firstChar, startLine, startColumn) {
|
|
141
|
+
let value = firstChar;
|
|
142
|
+
while (this.isDigit(this.peek())) {
|
|
143
|
+
value += this.advance();
|
|
144
|
+
}
|
|
145
|
+
this.addToken("NUMBER" /* NUMBER */, value, startLine, startColumn);
|
|
146
|
+
}
|
|
147
|
+
scanAtom(firstChar, startLine, startColumn) {
|
|
148
|
+
let value = firstChar;
|
|
149
|
+
while (this.isAtomChar(this.peek())) {
|
|
150
|
+
value += this.advance();
|
|
151
|
+
}
|
|
152
|
+
this.addToken("ATOM" /* ATOM */, value, startLine, startColumn);
|
|
153
|
+
}
|
|
154
|
+
skipComment() {
|
|
155
|
+
while (!this.isAtEnd() && this.peek() !== "\n") {
|
|
156
|
+
this.advance();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
isDigit(char) {
|
|
160
|
+
return char >= "0" && char <= "9";
|
|
161
|
+
}
|
|
162
|
+
isAtomStart(char) {
|
|
163
|
+
return char >= "A" && char <= "Z" || char >= "a" && char <= "z" || char === "_" || char === "," || // Global reference prefix
|
|
164
|
+
char === "." || // Local reference prefix
|
|
165
|
+
char === "%" || // Sometimes used in ZIL
|
|
166
|
+
char === "#";
|
|
167
|
+
}
|
|
168
|
+
isAtomChar(char) {
|
|
169
|
+
return char >= "A" && char <= "Z" || char >= "a" && char <= "z" || char >= "0" && char <= "9" || char === "_" || char === "-" || char === "?" || char === "!" || char === "," || char === "." || char === "%" || char === "#";
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// src/analysis/zil/zil-special-forms.ts
|
|
174
|
+
var ZIL_SPECIAL_FORMS = /* @__PURE__ */ new Set([
|
|
175
|
+
// Conditionals
|
|
176
|
+
"COND",
|
|
177
|
+
"AND",
|
|
178
|
+
"OR",
|
|
179
|
+
"NOT",
|
|
180
|
+
"IF",
|
|
181
|
+
"ELSE",
|
|
182
|
+
// Assignment
|
|
183
|
+
"SET",
|
|
184
|
+
"SETG",
|
|
185
|
+
"BIND",
|
|
186
|
+
"PROG",
|
|
187
|
+
// Loops
|
|
188
|
+
"REPEAT",
|
|
189
|
+
"DO",
|
|
190
|
+
"MAP",
|
|
191
|
+
"MAPF",
|
|
192
|
+
"MAPR",
|
|
193
|
+
"MAPRET",
|
|
194
|
+
"MAPLEAVE",
|
|
195
|
+
// Output
|
|
196
|
+
"TELL",
|
|
197
|
+
"PRINT",
|
|
198
|
+
"PRINTN",
|
|
199
|
+
"PRINTD",
|
|
200
|
+
"PRINTC",
|
|
201
|
+
"PRINTR",
|
|
202
|
+
"CRLF",
|
|
203
|
+
// Control flow
|
|
204
|
+
"RETURN",
|
|
205
|
+
"AGAIN",
|
|
206
|
+
"RTRUE",
|
|
207
|
+
"RFALSE",
|
|
208
|
+
"QUIT",
|
|
209
|
+
// Predicates (end with ?)
|
|
210
|
+
"EQUAL?",
|
|
211
|
+
"ZERO?",
|
|
212
|
+
"LESS?",
|
|
213
|
+
"GRTR?",
|
|
214
|
+
"FSET?",
|
|
215
|
+
"IN?",
|
|
216
|
+
"VERB?",
|
|
217
|
+
"PRSO?",
|
|
218
|
+
"PRSI?",
|
|
219
|
+
"HELD?",
|
|
220
|
+
"HERE?",
|
|
221
|
+
"ACCESSIBLE?",
|
|
222
|
+
"VISIBLE?",
|
|
223
|
+
"FIRST?",
|
|
224
|
+
"NEXT?",
|
|
225
|
+
"PROB?",
|
|
226
|
+
"RANDOM",
|
|
227
|
+
// Property/flag manipulation
|
|
228
|
+
"FSET",
|
|
229
|
+
"FCLEAR",
|
|
230
|
+
"GETP",
|
|
231
|
+
"PUTP",
|
|
232
|
+
"GETPT",
|
|
233
|
+
"PTSIZE",
|
|
234
|
+
// Object manipulation
|
|
235
|
+
"MOVE",
|
|
236
|
+
"REMOVE",
|
|
237
|
+
"LOC",
|
|
238
|
+
"FIRST",
|
|
239
|
+
"NEXT",
|
|
240
|
+
// Arithmetic
|
|
241
|
+
"ADD",
|
|
242
|
+
"SUB",
|
|
243
|
+
"MUL",
|
|
244
|
+
"DIV",
|
|
245
|
+
"MOD",
|
|
246
|
+
"BAND",
|
|
247
|
+
"BOR",
|
|
248
|
+
"BCOM",
|
|
249
|
+
"LSH",
|
|
250
|
+
// Table operations
|
|
251
|
+
"GET",
|
|
252
|
+
"PUT",
|
|
253
|
+
"GETB",
|
|
254
|
+
"PUTB",
|
|
255
|
+
"TABLE",
|
|
256
|
+
"ITABLE",
|
|
257
|
+
"LTABLE",
|
|
258
|
+
"PTABLE",
|
|
259
|
+
// Stack operations
|
|
260
|
+
"PUSH",
|
|
261
|
+
"POP",
|
|
262
|
+
"FSTACK",
|
|
263
|
+
// Input
|
|
264
|
+
"READ",
|
|
265
|
+
"INPUT",
|
|
266
|
+
"READLINE",
|
|
267
|
+
// Definition forms (handled separately for symbol extraction)
|
|
268
|
+
"ROUTINE",
|
|
269
|
+
"OBJECT",
|
|
270
|
+
"ROOM",
|
|
271
|
+
"GLOBAL",
|
|
272
|
+
"CONSTANT",
|
|
273
|
+
"SYNTAX",
|
|
274
|
+
"INSERT-FILE",
|
|
275
|
+
// Misc builtins
|
|
276
|
+
"VERSION?",
|
|
277
|
+
"ASCII",
|
|
278
|
+
"USL",
|
|
279
|
+
"APPLY",
|
|
280
|
+
"EVAL",
|
|
281
|
+
"FORM",
|
|
282
|
+
"REST",
|
|
283
|
+
"LENGTH",
|
|
284
|
+
"NTH",
|
|
285
|
+
"ZGET",
|
|
286
|
+
"ZPUT",
|
|
287
|
+
"ZWSTR",
|
|
288
|
+
"DIROUT",
|
|
289
|
+
"DIRIN",
|
|
290
|
+
"BUFOUT",
|
|
291
|
+
"HLIGHT",
|
|
292
|
+
"COLOR",
|
|
293
|
+
"FONT",
|
|
294
|
+
"SPLIT",
|
|
295
|
+
"SCREEN",
|
|
296
|
+
"WINGET",
|
|
297
|
+
"WINPUT",
|
|
298
|
+
"WINATTR",
|
|
299
|
+
"PICINF",
|
|
300
|
+
"DISPLAY",
|
|
301
|
+
"DCLEAR",
|
|
302
|
+
"SOUND",
|
|
303
|
+
"INTBL?",
|
|
304
|
+
"CATCH",
|
|
305
|
+
"THROW",
|
|
306
|
+
"LEGAL?",
|
|
307
|
+
"COPYT",
|
|
308
|
+
"VALUE",
|
|
309
|
+
"GASSIGNED?",
|
|
310
|
+
"ASSIGNED?",
|
|
311
|
+
"DEFINE",
|
|
312
|
+
"DEFMAC"
|
|
313
|
+
]);
|
|
314
|
+
function isSpecialForm(name) {
|
|
315
|
+
return ZIL_SPECIAL_FORMS.has(name.toUpperCase());
|
|
316
|
+
}
|
|
317
|
+
var ZIL_DEFINITION_FORMS = /* @__PURE__ */ new Set([
|
|
318
|
+
"ROUTINE",
|
|
319
|
+
"OBJECT",
|
|
320
|
+
"ROOM",
|
|
321
|
+
"GLOBAL",
|
|
322
|
+
"CONSTANT",
|
|
323
|
+
"SYNTAX",
|
|
324
|
+
"VERB",
|
|
325
|
+
"DEFINE",
|
|
326
|
+
"DEFMAC"
|
|
327
|
+
]);
|
|
328
|
+
function isDefinitionForm(name) {
|
|
329
|
+
return ZIL_DEFINITION_FORMS.has(name.toUpperCase());
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/analysis/zil/zil-parser.ts
|
|
333
|
+
var ZilParser = class {
|
|
334
|
+
lexer = new ZilLexer();
|
|
335
|
+
tokens = [];
|
|
336
|
+
pos = 0;
|
|
337
|
+
/**
|
|
338
|
+
* Parse ZIL source code
|
|
339
|
+
*/
|
|
340
|
+
parse(input) {
|
|
341
|
+
this.tokens = this.lexer.tokenize(input);
|
|
342
|
+
this.pos = 0;
|
|
343
|
+
const forms = [];
|
|
344
|
+
const symbols = [];
|
|
345
|
+
const imports = [];
|
|
346
|
+
const calls = [];
|
|
347
|
+
while (!this.isAtEnd()) {
|
|
348
|
+
if (this.check("LANGLE" /* LANGLE */)) {
|
|
349
|
+
const form = this.parseForm();
|
|
350
|
+
if (form !== void 0) {
|
|
351
|
+
forms.push(form);
|
|
352
|
+
const symbol = this.extractSymbol(form);
|
|
353
|
+
if (symbol !== void 0) {
|
|
354
|
+
symbols.push(symbol);
|
|
355
|
+
}
|
|
356
|
+
const imp = this.extractImport(form);
|
|
357
|
+
if (imp !== void 0) {
|
|
358
|
+
imports.push(imp);
|
|
359
|
+
}
|
|
360
|
+
if (form.head.toUpperCase() === "ROUTINE") {
|
|
361
|
+
const routineName = this.getRoutineName(form);
|
|
362
|
+
if (routineName !== void 0) {
|
|
363
|
+
this.extractCalls(form, routineName, calls);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
this.advance();
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return { forms, symbols, imports, calls };
|
|
372
|
+
}
|
|
373
|
+
isAtEnd() {
|
|
374
|
+
return this.pos >= this.tokens.length;
|
|
375
|
+
}
|
|
376
|
+
peek() {
|
|
377
|
+
return this.tokens[this.pos];
|
|
378
|
+
}
|
|
379
|
+
check(type) {
|
|
380
|
+
if (this.isAtEnd()) return false;
|
|
381
|
+
return this.peek()?.type === type;
|
|
382
|
+
}
|
|
383
|
+
advance() {
|
|
384
|
+
if (!this.isAtEnd()) {
|
|
385
|
+
const token = this.tokens[this.pos];
|
|
386
|
+
this.pos++;
|
|
387
|
+
return token;
|
|
388
|
+
}
|
|
389
|
+
return void 0;
|
|
390
|
+
}
|
|
391
|
+
parseForm() {
|
|
392
|
+
if (!this.check("LANGLE" /* LANGLE */)) return void 0;
|
|
393
|
+
const startToken = this.advance();
|
|
394
|
+
const startLine = startToken?.line ?? 1;
|
|
395
|
+
let endLine = startLine;
|
|
396
|
+
let head = "";
|
|
397
|
+
if (this.check("ATOM" /* ATOM */)) {
|
|
398
|
+
head = this.advance()?.value ?? "";
|
|
399
|
+
}
|
|
400
|
+
const children = [];
|
|
401
|
+
while (!this.isAtEnd() && !this.check("RANGLE" /* RANGLE */)) {
|
|
402
|
+
const child = this.parseNode();
|
|
403
|
+
if (child !== void 0) {
|
|
404
|
+
children.push(child);
|
|
405
|
+
endLine = this.getNodeEndLine(child);
|
|
406
|
+
} else {
|
|
407
|
+
this.advance();
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (this.check("RANGLE" /* RANGLE */)) {
|
|
411
|
+
const closeToken = this.advance();
|
|
412
|
+
endLine = closeToken?.line ?? endLine;
|
|
413
|
+
}
|
|
414
|
+
return { head, children, startLine, endLine };
|
|
415
|
+
}
|
|
416
|
+
parseGroup() {
|
|
417
|
+
if (!this.check("LPAREN" /* LPAREN */)) return void 0;
|
|
418
|
+
const startToken = this.advance();
|
|
419
|
+
const startLine = startToken?.line ?? 1;
|
|
420
|
+
let endLine = startLine;
|
|
421
|
+
const children = [];
|
|
422
|
+
while (!this.isAtEnd() && !this.check("RPAREN" /* RPAREN */)) {
|
|
423
|
+
const child = this.parseNode();
|
|
424
|
+
if (child !== void 0) {
|
|
425
|
+
children.push(child);
|
|
426
|
+
endLine = this.getNodeEndLine(child);
|
|
427
|
+
} else {
|
|
428
|
+
this.advance();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
if (this.check("RPAREN" /* RPAREN */)) {
|
|
432
|
+
const closeToken = this.advance();
|
|
433
|
+
endLine = closeToken?.line ?? endLine;
|
|
434
|
+
}
|
|
435
|
+
return { type: "group", children, startLine, endLine };
|
|
436
|
+
}
|
|
437
|
+
parseNode() {
|
|
438
|
+
const token = this.peek();
|
|
439
|
+
if (token === void 0) return void 0;
|
|
440
|
+
switch (token.type) {
|
|
441
|
+
case "LANGLE" /* LANGLE */:
|
|
442
|
+
return this.parseForm();
|
|
443
|
+
case "LPAREN" /* LPAREN */:
|
|
444
|
+
return this.parseGroup();
|
|
445
|
+
case "ATOM" /* ATOM */:
|
|
446
|
+
this.advance();
|
|
447
|
+
return { type: "atom", value: token.value, line: token.line };
|
|
448
|
+
case "STRING" /* STRING */:
|
|
449
|
+
this.advance();
|
|
450
|
+
return { type: "string", value: token.value, line: token.line };
|
|
451
|
+
case "NUMBER" /* NUMBER */:
|
|
452
|
+
this.advance();
|
|
453
|
+
return { type: "number", value: token.value, line: token.line };
|
|
454
|
+
default:
|
|
455
|
+
return void 0;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
getNodeEndLine(node) {
|
|
459
|
+
if ("endLine" in node) {
|
|
460
|
+
return node.endLine;
|
|
461
|
+
}
|
|
462
|
+
return node.line;
|
|
463
|
+
}
|
|
464
|
+
extractSymbol(form) {
|
|
465
|
+
const headUpper = form.head.toUpperCase();
|
|
466
|
+
if (!isDefinitionForm(headUpper)) {
|
|
467
|
+
return void 0;
|
|
468
|
+
}
|
|
469
|
+
const nameNode = form.children.find((c) => "type" in c && c.type === "atom");
|
|
470
|
+
if (nameNode === void 0) {
|
|
471
|
+
return void 0;
|
|
472
|
+
}
|
|
473
|
+
const kindMap = {
|
|
474
|
+
ROUTINE: "routine",
|
|
475
|
+
OBJECT: "object",
|
|
476
|
+
ROOM: "room",
|
|
477
|
+
GLOBAL: "global",
|
|
478
|
+
CONSTANT: "constant",
|
|
479
|
+
SYNTAX: "syntax",
|
|
480
|
+
VERB: "verb",
|
|
481
|
+
DEFINE: "routine",
|
|
482
|
+
DEFMAC: "routine"
|
|
483
|
+
};
|
|
484
|
+
const kind = kindMap[headUpper];
|
|
485
|
+
if (kind === void 0) {
|
|
486
|
+
return void 0;
|
|
487
|
+
}
|
|
488
|
+
const result = {
|
|
489
|
+
name: nameNode.value,
|
|
490
|
+
kind,
|
|
491
|
+
startLine: form.startLine,
|
|
492
|
+
endLine: form.endLine
|
|
493
|
+
};
|
|
494
|
+
if (headUpper === "ROUTINE" || headUpper === "DEFINE" || headUpper === "DEFMAC") {
|
|
495
|
+
result.signature = this.extractRoutineSignature(form, nameNode.value);
|
|
496
|
+
}
|
|
497
|
+
return result;
|
|
498
|
+
}
|
|
499
|
+
extractRoutineSignature(form, name) {
|
|
500
|
+
const argsGroup = form.children.find((c) => "type" in c && c.type === "group");
|
|
501
|
+
if (argsGroup === void 0) {
|
|
502
|
+
return `ROUTINE ${name} ()`;
|
|
503
|
+
}
|
|
504
|
+
const args = argsGroup.children.filter((c) => "type" in c && c.type === "atom").map((c) => c.value).join(" ");
|
|
505
|
+
return `ROUTINE ${name} (${args})`;
|
|
506
|
+
}
|
|
507
|
+
extractImport(form) {
|
|
508
|
+
if (form.head.toUpperCase() !== "INSERT-FILE") {
|
|
509
|
+
return void 0;
|
|
510
|
+
}
|
|
511
|
+
const fileNode = form.children.find((c) => "type" in c && c.type === "string");
|
|
512
|
+
if (fileNode === void 0) {
|
|
513
|
+
return void 0;
|
|
514
|
+
}
|
|
515
|
+
return {
|
|
516
|
+
source: fileNode.value,
|
|
517
|
+
specifiers: [],
|
|
518
|
+
isType: false
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
getRoutineName(form) {
|
|
522
|
+
const nameNode = form.children.find((c) => "type" in c && c.type === "atom");
|
|
523
|
+
return nameNode?.value;
|
|
524
|
+
}
|
|
525
|
+
extractCalls(node, caller, calls) {
|
|
526
|
+
if ("head" in node) {
|
|
527
|
+
const headUpper = node.head.toUpperCase();
|
|
528
|
+
if (node.head !== "" && !isSpecialForm(headUpper)) {
|
|
529
|
+
calls.push({
|
|
530
|
+
caller,
|
|
531
|
+
callee: node.head,
|
|
532
|
+
line: node.startLine
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
for (const child of node.children) {
|
|
536
|
+
this.extractCalls(child, caller, calls);
|
|
537
|
+
}
|
|
538
|
+
} else if ("type" in node && node.type === "group") {
|
|
539
|
+
for (const child of node.children) {
|
|
540
|
+
this.extractCalls(child, caller, calls);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
// src/analysis/zil/zil-adapter.ts
|
|
547
|
+
var ZilAdapter = class {
|
|
548
|
+
languageId = "zil";
|
|
549
|
+
extensions = [".zil", ".mud"];
|
|
550
|
+
displayName = "ZIL (Zork Implementation Language)";
|
|
551
|
+
parser = new ZilParser();
|
|
552
|
+
/**
|
|
553
|
+
* Parse ZIL code and extract symbols as CodeNode[]
|
|
554
|
+
*/
|
|
555
|
+
parse(content, _filePath) {
|
|
556
|
+
const result = this.parser.parse(content);
|
|
557
|
+
return result.symbols.map((symbol) => {
|
|
558
|
+
const node = {
|
|
559
|
+
type: this.mapSymbolKindToNodeType(symbol.kind),
|
|
560
|
+
name: symbol.name,
|
|
561
|
+
exported: true,
|
|
562
|
+
// ZIL doesn't have export concept, treat all as exported
|
|
563
|
+
startLine: symbol.startLine,
|
|
564
|
+
endLine: symbol.endLine
|
|
565
|
+
};
|
|
566
|
+
if (symbol.signature !== void 0) {
|
|
567
|
+
node.signature = symbol.signature;
|
|
568
|
+
}
|
|
569
|
+
return node;
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Extract imports from INSERT-FILE directives
|
|
574
|
+
*/
|
|
575
|
+
extractImports(content, _filePath) {
|
|
576
|
+
const result = this.parser.parse(content);
|
|
577
|
+
return result.imports;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Chunk ZIL code by top-level forms
|
|
581
|
+
*/
|
|
582
|
+
chunk(content, _filePath) {
|
|
583
|
+
const result = this.parser.parse(content);
|
|
584
|
+
const lines = content.split("\n");
|
|
585
|
+
return result.forms.filter((form) => form.head !== "").map((form) => {
|
|
586
|
+
const chunkLines = lines.slice(form.startLine - 1, form.endLine);
|
|
587
|
+
const chunkContent = chunkLines.join("\n");
|
|
588
|
+
const symbol = result.symbols.find(
|
|
589
|
+
(s) => s.startLine === form.startLine && s.endLine === form.endLine
|
|
590
|
+
);
|
|
591
|
+
const chunk = {
|
|
592
|
+
content: chunkContent,
|
|
593
|
+
startLine: form.startLine,
|
|
594
|
+
endLine: form.endLine
|
|
595
|
+
};
|
|
596
|
+
if (symbol !== void 0) {
|
|
597
|
+
chunk.symbolName = symbol.name;
|
|
598
|
+
chunk.symbolKind = symbol.kind;
|
|
599
|
+
}
|
|
600
|
+
return chunk;
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Analyze call relationships within ZIL code
|
|
605
|
+
*/
|
|
606
|
+
analyzeCallRelationships(content, filePath) {
|
|
607
|
+
const result = this.parser.parse(content);
|
|
608
|
+
return result.calls.map((call) => ({
|
|
609
|
+
from: `${filePath}:${call.caller}`,
|
|
610
|
+
to: `${filePath}:${call.callee}`,
|
|
611
|
+
type: "calls",
|
|
612
|
+
confidence: 0.9
|
|
613
|
+
// High confidence for ZIL - calls are explicit
|
|
614
|
+
}));
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Map ZIL symbol kinds to CodeNode types
|
|
618
|
+
*/
|
|
619
|
+
mapSymbolKindToNodeType(kind) {
|
|
620
|
+
switch (kind) {
|
|
621
|
+
case "routine":
|
|
622
|
+
return "function";
|
|
623
|
+
case "object":
|
|
624
|
+
case "room":
|
|
625
|
+
case "global":
|
|
626
|
+
case "constant":
|
|
627
|
+
return "const";
|
|
628
|
+
case "syntax":
|
|
629
|
+
case "verb":
|
|
630
|
+
return "const";
|
|
631
|
+
default:
|
|
632
|
+
return "const";
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
|
|
14
637
|
// src/mcp/commands/job.commands.ts
|
|
15
638
|
import { z as z2 } from "zod";
|
|
16
639
|
|
|
@@ -599,10 +1222,375 @@ var storeCommands = [
|
|
|
599
1222
|
}
|
|
600
1223
|
];
|
|
601
1224
|
|
|
1225
|
+
// src/mcp/commands/sync.commands.ts
|
|
1226
|
+
import { z as z7 } from "zod";
|
|
1227
|
+
|
|
1228
|
+
// src/services/store-definition.service.ts
|
|
1229
|
+
import { readFile, writeFile, mkdir, access } from "fs/promises";
|
|
1230
|
+
import { dirname, resolve, isAbsolute, join as join2 } from "path";
|
|
1231
|
+
|
|
1232
|
+
// src/types/store-definition.ts
|
|
1233
|
+
import { z as z6 } from "zod";
|
|
1234
|
+
var BaseStoreDefinitionSchema = z6.object({
|
|
1235
|
+
name: z6.string().min(1, "Store name is required"),
|
|
1236
|
+
description: z6.string().optional(),
|
|
1237
|
+
tags: z6.array(z6.string()).optional()
|
|
1238
|
+
});
|
|
1239
|
+
var FileStoreDefinitionSchema = BaseStoreDefinitionSchema.extend({
|
|
1240
|
+
type: z6.literal("file"),
|
|
1241
|
+
path: z6.string().min(1, "Path is required for file stores")
|
|
1242
|
+
});
|
|
1243
|
+
var RepoStoreDefinitionSchema = BaseStoreDefinitionSchema.extend({
|
|
1244
|
+
type: z6.literal("repo"),
|
|
1245
|
+
url: z6.url("Valid URL is required for repo stores"),
|
|
1246
|
+
branch: z6.string().optional(),
|
|
1247
|
+
depth: z6.number().int().positive("Depth must be a positive integer").optional()
|
|
1248
|
+
});
|
|
1249
|
+
var WebStoreDefinitionSchema = BaseStoreDefinitionSchema.extend({
|
|
1250
|
+
type: z6.literal("web"),
|
|
1251
|
+
url: z6.url("Valid URL is required for web stores"),
|
|
1252
|
+
depth: z6.number().int().min(0, "Depth must be non-negative").default(1),
|
|
1253
|
+
maxPages: z6.number().int().positive("maxPages must be a positive integer").optional(),
|
|
1254
|
+
crawlInstructions: z6.string().optional(),
|
|
1255
|
+
extractInstructions: z6.string().optional()
|
|
1256
|
+
});
|
|
1257
|
+
var StoreDefinitionSchema = z6.discriminatedUnion("type", [
|
|
1258
|
+
FileStoreDefinitionSchema,
|
|
1259
|
+
RepoStoreDefinitionSchema,
|
|
1260
|
+
WebStoreDefinitionSchema
|
|
1261
|
+
]);
|
|
1262
|
+
var StoreDefinitionsConfigSchema = z6.object({
|
|
1263
|
+
version: z6.literal(1),
|
|
1264
|
+
stores: z6.array(StoreDefinitionSchema)
|
|
1265
|
+
});
|
|
1266
|
+
function isFileStoreDefinition(def) {
|
|
1267
|
+
return def.type === "file";
|
|
1268
|
+
}
|
|
1269
|
+
function isRepoStoreDefinition(def) {
|
|
1270
|
+
return def.type === "repo";
|
|
1271
|
+
}
|
|
1272
|
+
function isWebStoreDefinition(def) {
|
|
1273
|
+
return def.type === "web";
|
|
1274
|
+
}
|
|
1275
|
+
var DEFAULT_STORE_DEFINITIONS_CONFIG = {
|
|
1276
|
+
version: 1,
|
|
1277
|
+
stores: []
|
|
1278
|
+
};
|
|
1279
|
+
|
|
1280
|
+
// src/services/store-definition.service.ts
|
|
1281
|
+
async function fileExists(path2) {
|
|
1282
|
+
try {
|
|
1283
|
+
await access(path2);
|
|
1284
|
+
return true;
|
|
1285
|
+
} catch {
|
|
1286
|
+
return false;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
var StoreDefinitionService = class {
|
|
1290
|
+
configPath;
|
|
1291
|
+
projectRoot;
|
|
1292
|
+
config = null;
|
|
1293
|
+
constructor(projectRoot) {
|
|
1294
|
+
this.projectRoot = projectRoot ?? ProjectRootService.resolve();
|
|
1295
|
+
this.configPath = join2(this.projectRoot, ".bluera/bluera-knowledge/stores.config.json");
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* Load store definitions from config file.
|
|
1299
|
+
* Returns empty config if file doesn't exist.
|
|
1300
|
+
* Throws on parse/validation errors (fail fast per CLAUDE.md).
|
|
1301
|
+
*/
|
|
1302
|
+
async load() {
|
|
1303
|
+
if (this.config !== null) {
|
|
1304
|
+
return this.config;
|
|
1305
|
+
}
|
|
1306
|
+
const exists = await fileExists(this.configPath);
|
|
1307
|
+
if (!exists) {
|
|
1308
|
+
this.config = {
|
|
1309
|
+
...DEFAULT_STORE_DEFINITIONS_CONFIG,
|
|
1310
|
+
stores: [...DEFAULT_STORE_DEFINITIONS_CONFIG.stores]
|
|
1311
|
+
};
|
|
1312
|
+
return this.config;
|
|
1313
|
+
}
|
|
1314
|
+
const content = await readFile(this.configPath, "utf-8");
|
|
1315
|
+
let parsed;
|
|
1316
|
+
try {
|
|
1317
|
+
parsed = JSON.parse(content);
|
|
1318
|
+
} catch (error) {
|
|
1319
|
+
throw new Error(
|
|
1320
|
+
`Failed to parse store definitions at ${this.configPath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1321
|
+
);
|
|
1322
|
+
}
|
|
1323
|
+
const result = StoreDefinitionsConfigSchema.safeParse(parsed);
|
|
1324
|
+
if (!result.success) {
|
|
1325
|
+
throw new Error(`Invalid store definitions at ${this.configPath}: ${result.error.message}`);
|
|
1326
|
+
}
|
|
1327
|
+
this.config = result.data;
|
|
1328
|
+
return this.config;
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* Save store definitions to config file.
|
|
1332
|
+
*/
|
|
1333
|
+
async save(config) {
|
|
1334
|
+
await mkdir(dirname(this.configPath), { recursive: true });
|
|
1335
|
+
await writeFile(this.configPath, JSON.stringify(config, null, 2));
|
|
1336
|
+
this.config = config;
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Add a store definition.
|
|
1340
|
+
* Throws if a definition with the same name already exists.
|
|
1341
|
+
*/
|
|
1342
|
+
async addDefinition(definition) {
|
|
1343
|
+
const config = await this.load();
|
|
1344
|
+
const existing = config.stores.find((s) => s.name === definition.name);
|
|
1345
|
+
if (existing !== void 0) {
|
|
1346
|
+
throw new Error(`Store definition "${definition.name}" already exists`);
|
|
1347
|
+
}
|
|
1348
|
+
config.stores.push(definition);
|
|
1349
|
+
await this.save(config);
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Remove a store definition by name.
|
|
1353
|
+
* Returns true if removed, false if not found.
|
|
1354
|
+
*/
|
|
1355
|
+
async removeDefinition(name) {
|
|
1356
|
+
const config = await this.load();
|
|
1357
|
+
const index = config.stores.findIndex((s) => s.name === name);
|
|
1358
|
+
if (index === -1) {
|
|
1359
|
+
return false;
|
|
1360
|
+
}
|
|
1361
|
+
config.stores.splice(index, 1);
|
|
1362
|
+
await this.save(config);
|
|
1363
|
+
return true;
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Update an existing store definition.
|
|
1367
|
+
* Only updates the provided fields, preserving others.
|
|
1368
|
+
* Throws if definition not found.
|
|
1369
|
+
*/
|
|
1370
|
+
async updateDefinition(name, updates) {
|
|
1371
|
+
const config = await this.load();
|
|
1372
|
+
const index = config.stores.findIndex((s) => s.name === name);
|
|
1373
|
+
if (index === -1) {
|
|
1374
|
+
throw new Error(`Store definition "${name}" not found`);
|
|
1375
|
+
}
|
|
1376
|
+
const existing = config.stores[index];
|
|
1377
|
+
if (existing === void 0) {
|
|
1378
|
+
throw new Error(`Store definition "${name}" not found at index ${String(index)}`);
|
|
1379
|
+
}
|
|
1380
|
+
if (updates.description !== void 0) {
|
|
1381
|
+
existing.description = updates.description;
|
|
1382
|
+
}
|
|
1383
|
+
if (updates.tags !== void 0) {
|
|
1384
|
+
existing.tags = updates.tags;
|
|
1385
|
+
}
|
|
1386
|
+
await this.save(config);
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Get a store definition by name.
|
|
1390
|
+
* Returns undefined if not found.
|
|
1391
|
+
*/
|
|
1392
|
+
async getByName(name) {
|
|
1393
|
+
const config = await this.load();
|
|
1394
|
+
return config.stores.find((s) => s.name === name);
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Check if any definitions exist.
|
|
1398
|
+
*/
|
|
1399
|
+
async hasDefinitions() {
|
|
1400
|
+
const config = await this.load();
|
|
1401
|
+
return config.stores.length > 0;
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Resolve a file store path relative to project root.
|
|
1405
|
+
*/
|
|
1406
|
+
resolvePath(path2) {
|
|
1407
|
+
if (isAbsolute(path2)) {
|
|
1408
|
+
return path2;
|
|
1409
|
+
}
|
|
1410
|
+
return resolve(this.projectRoot, path2);
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* Get the config file path.
|
|
1414
|
+
*/
|
|
1415
|
+
getConfigPath() {
|
|
1416
|
+
return this.configPath;
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Get the project root.
|
|
1420
|
+
*/
|
|
1421
|
+
getProjectRoot() {
|
|
1422
|
+
return this.projectRoot;
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Clear the cached config (useful for testing).
|
|
1426
|
+
*/
|
|
1427
|
+
clearCache() {
|
|
1428
|
+
this.config = null;
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1431
|
+
|
|
1432
|
+
// src/mcp/commands/sync.commands.ts
|
|
1433
|
+
async function handleStoresSync(args, context) {
|
|
1434
|
+
const { services, options } = context;
|
|
1435
|
+
const projectRoot = options.projectRoot;
|
|
1436
|
+
if (projectRoot === void 0) {
|
|
1437
|
+
throw new Error("Project root is required for stores:sync");
|
|
1438
|
+
}
|
|
1439
|
+
const defService = new StoreDefinitionService(projectRoot);
|
|
1440
|
+
const config = await defService.load();
|
|
1441
|
+
const result = {
|
|
1442
|
+
created: [],
|
|
1443
|
+
skipped: [],
|
|
1444
|
+
failed: [],
|
|
1445
|
+
orphans: []
|
|
1446
|
+
};
|
|
1447
|
+
if (args.dryRun === true) {
|
|
1448
|
+
result.dryRun = true;
|
|
1449
|
+
result.wouldCreate = [];
|
|
1450
|
+
result.wouldPrune = [];
|
|
1451
|
+
}
|
|
1452
|
+
const existingStores = await services.store.list();
|
|
1453
|
+
const existingNames = new Set(existingStores.map((s) => s.name));
|
|
1454
|
+
for (const def of config.stores) {
|
|
1455
|
+
if (existingNames.has(def.name)) {
|
|
1456
|
+
result.skipped.push(def.name);
|
|
1457
|
+
continue;
|
|
1458
|
+
}
|
|
1459
|
+
if (args.dryRun === true) {
|
|
1460
|
+
result.wouldCreate?.push(def.name);
|
|
1461
|
+
continue;
|
|
1462
|
+
}
|
|
1463
|
+
const createResult = await createStoreFromDefinition(def, defService, services, context);
|
|
1464
|
+
if (createResult.success) {
|
|
1465
|
+
result.created.push(def.name);
|
|
1466
|
+
} else {
|
|
1467
|
+
result.failed.push({ name: def.name, error: createResult.error });
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
const definedNames = new Set(config.stores.map((d) => d.name));
|
|
1471
|
+
for (const store of existingStores) {
|
|
1472
|
+
if (!definedNames.has(store.name)) {
|
|
1473
|
+
result.orphans.push(store.name);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
if (args.prune === true && result.orphans.length > 0) {
|
|
1477
|
+
if (args.dryRun === true) {
|
|
1478
|
+
result.wouldPrune = [...result.orphans];
|
|
1479
|
+
} else {
|
|
1480
|
+
result.pruned = [];
|
|
1481
|
+
for (const orphanName of result.orphans) {
|
|
1482
|
+
const store = await services.store.getByName(orphanName);
|
|
1483
|
+
if (store !== void 0) {
|
|
1484
|
+
const deleteResult = await services.store.delete(store.id, { skipDefinitionSync: true });
|
|
1485
|
+
if (deleteResult.success) {
|
|
1486
|
+
result.pruned.push(orphanName);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
return {
|
|
1493
|
+
content: [
|
|
1494
|
+
{
|
|
1495
|
+
type: "text",
|
|
1496
|
+
text: JSON.stringify(result, null, 2)
|
|
1497
|
+
}
|
|
1498
|
+
]
|
|
1499
|
+
};
|
|
1500
|
+
}
|
|
1501
|
+
async function createStoreFromDefinition(def, defService, services, _context) {
|
|
1502
|
+
try {
|
|
1503
|
+
if (isFileStoreDefinition(def)) {
|
|
1504
|
+
const resolvedPath = defService.resolvePath(def.path);
|
|
1505
|
+
const createResult = await services.store.create(
|
|
1506
|
+
{
|
|
1507
|
+
name: def.name,
|
|
1508
|
+
type: "file",
|
|
1509
|
+
path: resolvedPath,
|
|
1510
|
+
description: def.description,
|
|
1511
|
+
tags: def.tags
|
|
1512
|
+
},
|
|
1513
|
+
{ skipDefinitionSync: true }
|
|
1514
|
+
// Don't re-add to definitions
|
|
1515
|
+
);
|
|
1516
|
+
if (!createResult.success) {
|
|
1517
|
+
return { success: false, error: createResult.error.message };
|
|
1518
|
+
}
|
|
1519
|
+
return { success: true };
|
|
1520
|
+
}
|
|
1521
|
+
if (isRepoStoreDefinition(def)) {
|
|
1522
|
+
const createResult = await services.store.create(
|
|
1523
|
+
{
|
|
1524
|
+
name: def.name,
|
|
1525
|
+
type: "repo",
|
|
1526
|
+
url: def.url,
|
|
1527
|
+
branch: def.branch,
|
|
1528
|
+
depth: def.depth,
|
|
1529
|
+
description: def.description,
|
|
1530
|
+
tags: def.tags
|
|
1531
|
+
},
|
|
1532
|
+
{ skipDefinitionSync: true }
|
|
1533
|
+
);
|
|
1534
|
+
if (!createResult.success) {
|
|
1535
|
+
return { success: false, error: createResult.error.message };
|
|
1536
|
+
}
|
|
1537
|
+
return { success: true };
|
|
1538
|
+
}
|
|
1539
|
+
if (isWebStoreDefinition(def)) {
|
|
1540
|
+
const createResult = await services.store.create(
|
|
1541
|
+
{
|
|
1542
|
+
name: def.name,
|
|
1543
|
+
type: "web",
|
|
1544
|
+
url: def.url,
|
|
1545
|
+
depth: def.depth,
|
|
1546
|
+
description: def.description,
|
|
1547
|
+
tags: def.tags
|
|
1548
|
+
},
|
|
1549
|
+
{ skipDefinitionSync: true }
|
|
1550
|
+
);
|
|
1551
|
+
if (!createResult.success) {
|
|
1552
|
+
return { success: false, error: createResult.error.message };
|
|
1553
|
+
}
|
|
1554
|
+
return { success: true };
|
|
1555
|
+
}
|
|
1556
|
+
return { success: false, error: "Unknown store definition type" };
|
|
1557
|
+
} catch (error) {
|
|
1558
|
+
return {
|
|
1559
|
+
success: false,
|
|
1560
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
var syncCommands = [
|
|
1565
|
+
{
|
|
1566
|
+
name: "stores:sync",
|
|
1567
|
+
description: "Sync stores from definitions config (bootstrap on fresh clone)",
|
|
1568
|
+
argsSchema: z7.object({
|
|
1569
|
+
reindex: z7.boolean().optional().describe("Re-index existing stores after sync"),
|
|
1570
|
+
prune: z7.boolean().optional().describe("Remove stores not in definitions"),
|
|
1571
|
+
dryRun: z7.boolean().optional().describe("Show what would happen without making changes")
|
|
1572
|
+
}),
|
|
1573
|
+
handler: (args, context) => {
|
|
1574
|
+
const syncArgs = {};
|
|
1575
|
+
if (typeof args["reindex"] === "boolean") {
|
|
1576
|
+
syncArgs.reindex = args["reindex"];
|
|
1577
|
+
}
|
|
1578
|
+
if (typeof args["prune"] === "boolean") {
|
|
1579
|
+
syncArgs.prune = args["prune"];
|
|
1580
|
+
}
|
|
1581
|
+
if (typeof args["dryRun"] === "boolean") {
|
|
1582
|
+
syncArgs.dryRun = args["dryRun"];
|
|
1583
|
+
}
|
|
1584
|
+
return handleStoresSync(syncArgs, context);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
];
|
|
1588
|
+
|
|
602
1589
|
// src/mcp/commands/index.ts
|
|
603
1590
|
commandRegistry.registerAll(storeCommands);
|
|
604
1591
|
commandRegistry.registerAll(jobCommands);
|
|
605
1592
|
commandRegistry.registerAll(metaCommands);
|
|
1593
|
+
commandRegistry.registerAll(syncCommands);
|
|
606
1594
|
|
|
607
1595
|
// src/mcp/handlers/execute.handler.ts
|
|
608
1596
|
var handleExecute = async (args, context) => {
|
|
@@ -927,6 +1915,10 @@ var tools = [
|
|
|
927
1915
|
|
|
928
1916
|
// src/mcp/server.ts
|
|
929
1917
|
var logger2 = createLogger("mcp-server");
|
|
1918
|
+
var registry = AdapterRegistry.getInstance();
|
|
1919
|
+
if (!registry.hasExtension(".zil")) {
|
|
1920
|
+
registry.register(new ZilAdapter());
|
|
1921
|
+
}
|
|
930
1922
|
function createMCPServer(options) {
|
|
931
1923
|
const server = new Server(
|
|
932
1924
|
{
|
|
@@ -1092,7 +2084,12 @@ if (isMCPServerEntry) {
|
|
|
1092
2084
|
}
|
|
1093
2085
|
|
|
1094
2086
|
export {
|
|
2087
|
+
ZilAdapter,
|
|
2088
|
+
isFileStoreDefinition,
|
|
2089
|
+
isRepoStoreDefinition,
|
|
2090
|
+
isWebStoreDefinition,
|
|
2091
|
+
StoreDefinitionService,
|
|
1095
2092
|
createMCPServer,
|
|
1096
2093
|
runMCPServer
|
|
1097
2094
|
};
|
|
1098
|
-
//# sourceMappingURL=chunk-
|
|
2095
|
+
//# sourceMappingURL=chunk-565OVW3C.js.map
|