kibi-cli 0.2.3 → 0.2.5
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/cli.js +3 -28
- package/dist/commands/aggregated-checks.d.ts +4 -1
- package/dist/commands/aggregated-checks.d.ts.map +1 -1
- package/dist/commands/aggregated-checks.js +13 -3
- package/dist/commands/branch.d.ts.map +1 -1
- package/dist/commands/branch.js +3 -41
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +54 -44
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +0 -27
- package/dist/commands/gc.d.ts.map +1 -1
- package/dist/commands/gc.js +2 -51
- package/dist/commands/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +23 -36
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +0 -27
- package/dist/commands/query.d.ts.map +1 -1
- package/dist/commands/query.js +7 -288
- package/dist/commands/sync/cache.d.ts +13 -0
- package/dist/commands/sync/cache.d.ts.map +1 -0
- package/dist/commands/sync/cache.js +76 -0
- package/dist/commands/sync/discovery.d.ts +8 -0
- package/dist/commands/sync/discovery.d.ts.map +1 -0
- package/dist/commands/sync/discovery.js +50 -0
- package/dist/commands/sync/extraction.d.ts +11 -0
- package/dist/commands/sync/extraction.d.ts.map +1 -0
- package/dist/commands/sync/extraction.js +69 -0
- package/dist/commands/sync/manifest.d.ts +5 -0
- package/dist/commands/sync/manifest.d.ts.map +1 -0
- package/dist/commands/sync/manifest.js +118 -0
- package/dist/commands/sync/persistence.d.ts +16 -0
- package/dist/commands/sync/persistence.d.ts.map +1 -0
- package/dist/commands/sync/persistence.js +188 -0
- package/dist/commands/sync/staging.d.ts +4 -0
- package/dist/commands/sync/staging.d.ts.map +1 -0
- package/dist/commands/sync/staging.js +86 -0
- package/dist/commands/sync.d.ts +2 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +69 -501
- package/dist/extractors/manifest.d.ts +0 -1
- package/dist/extractors/manifest.d.ts.map +1 -1
- package/dist/extractors/manifest.js +39 -48
- package/dist/extractors/markdown.d.ts +0 -1
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +16 -49
- package/dist/extractors/relationships.d.ts +39 -0
- package/dist/extractors/relationships.d.ts.map +1 -0
- package/dist/extractors/relationships.js +137 -0
- package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
- package/dist/extractors/symbols-coordinator.js +0 -27
- package/dist/extractors/symbols-ts.d.ts.map +1 -1
- package/dist/extractors/symbols-ts.js +0 -27
- package/dist/kb/target-resolver.d.ts +80 -0
- package/dist/kb/target-resolver.d.ts.map +1 -0
- package/dist/kb/target-resolver.js +313 -0
- package/dist/prolog/codec.d.ts +63 -0
- package/dist/prolog/codec.d.ts.map +1 -0
- package/dist/prolog/codec.js +434 -0
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +0 -27
- package/dist/public/extractors/symbols-coordinator.d.ts.map +1 -1
- package/dist/public/extractors/symbols-coordinator.js +0 -27
- package/dist/public/prolog/index.d.ts.map +1 -1
- package/dist/public/prolog/index.js +0 -27
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +0 -27
- package/dist/public/schemas/relationship.d.ts.map +1 -1
- package/dist/public/schemas/relationship.js +0 -27
- package/dist/query/service.d.ts +35 -0
- package/dist/query/service.d.ts.map +1 -0
- package/dist/query/service.js +149 -0
- package/dist/relationships/shards.d.ts +68 -0
- package/dist/relationships/shards.d.ts.map +1 -0
- package/dist/relationships/shards.js +263 -0
- package/dist/traceability/git-staged.d.ts +4 -1
- package/dist/traceability/git-staged.d.ts.map +1 -1
- package/dist/traceability/git-staged.js +24 -11
- package/dist/types/changeset.d.ts.map +1 -1
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/types/relationships.d.ts.map +1 -1
- package/dist/utils/branch-resolver.d.ts +4 -0
- package/dist/utils/branch-resolver.d.ts.map +1 -1
- package/dist/utils/branch-resolver.js +4 -0
- package/dist/utils/config.d.ts +10 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +27 -1
- package/dist/utils/rule-registry.d.ts +47 -0
- package/dist/utils/rule-registry.d.ts.map +1 -0
- package/dist/utils/rule-registry.js +139 -0
- package/package.json +5 -1
- package/schema/config.json +156 -0
- package/src/public/extractors/symbols-coordinator.ts +0 -27
- package/src/public/prolog/index.ts +0 -27
- package/src/public/schemas/entity.ts +0 -27
- package/src/public/schemas/relationship.ts +0 -27
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
* Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
* (at your option) any later version.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Prolog codec utilities for escaping atoms, parsing responses, and handling
|
|
12
|
+
* Prolog list/property structures.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Escape a string for use as a Prolog atom.
|
|
16
|
+
* Doubles single-quote characters per ISO Prolog standard.
|
|
17
|
+
*/
|
|
18
|
+
export function escapeAtom(value) {
|
|
19
|
+
return value.replace(/'/g, "''");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Convert a string to a Prolog atom, quoting if necessary.
|
|
23
|
+
* Simple atoms (lowercase start, alphanumeric + underscore) pass through.
|
|
24
|
+
*/
|
|
25
|
+
export function toPrologAtom(value) {
|
|
26
|
+
const simplePrologAtom = /^[a-z][a-zA-Z0-9_]*$/;
|
|
27
|
+
return simplePrologAtom.test(value)
|
|
28
|
+
? value
|
|
29
|
+
: `'${value.replace(/'/g, "''")}'`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Escape a string for embedding inside a single-quoted Prolog atom.
|
|
33
|
+
* Alias for escapeAtom for semantic clarity.
|
|
34
|
+
*/
|
|
35
|
+
export function escapeAtomContent(value) {
|
|
36
|
+
return value.replace(/'/g, "''");
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Split a string by delimiter at the top level (not inside brackets or quotes).
|
|
40
|
+
* This is the general-purpose version that splits at depth 0.
|
|
41
|
+
*/
|
|
42
|
+
export function splitTopLevel(str, delimiter) {
|
|
43
|
+
const results = [];
|
|
44
|
+
let current = "";
|
|
45
|
+
let depth = 0;
|
|
46
|
+
let inDoubleQuotes = false;
|
|
47
|
+
let inSingleQuotes = false;
|
|
48
|
+
for (let i = 0; i < str.length; i++) {
|
|
49
|
+
const char = str[i];
|
|
50
|
+
const prev = i > 0 ? str[i - 1] : "";
|
|
51
|
+
if (char === '"' && !inSingleQuotes && prev !== "\\") {
|
|
52
|
+
inDoubleQuotes = !inDoubleQuotes;
|
|
53
|
+
current += char;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (char === "'" && !inDoubleQuotes && prev !== "\\") {
|
|
57
|
+
inSingleQuotes = !inSingleQuotes;
|
|
58
|
+
current += char;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (!inSingleQuotes && !inDoubleQuotes && (char === "[" || char === "(")) {
|
|
62
|
+
depth++;
|
|
63
|
+
current += char;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (!inSingleQuotes && !inDoubleQuotes && (char === "]" || char === ")")) {
|
|
67
|
+
depth--;
|
|
68
|
+
current += char;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (!inSingleQuotes &&
|
|
72
|
+
!inDoubleQuotes &&
|
|
73
|
+
depth === 0 &&
|
|
74
|
+
char === delimiter) {
|
|
75
|
+
if (current.length > 0) {
|
|
76
|
+
results.push(current);
|
|
77
|
+
}
|
|
78
|
+
current = "";
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
current += char;
|
|
82
|
+
}
|
|
83
|
+
if (current.length > 0) {
|
|
84
|
+
results.push(current);
|
|
85
|
+
}
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Parse a Prolog list of lists into a JavaScript array.
|
|
90
|
+
* Input: "[[a,b,c],[d,e,f]]"
|
|
91
|
+
* Output: [["a", "b", "c"], ["d", "e", "f"]]
|
|
92
|
+
*/
|
|
93
|
+
export function parseListOfLists(listStr) {
|
|
94
|
+
const cleaned = listStr.trim().replace(/^\[/, "").replace(/\]$/, "");
|
|
95
|
+
if (cleaned === "") {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
const results = [];
|
|
99
|
+
let depth = 0;
|
|
100
|
+
let current = "";
|
|
101
|
+
let currentList = [];
|
|
102
|
+
for (let i = 0; i < cleaned.length; i++) {
|
|
103
|
+
const char = cleaned[i];
|
|
104
|
+
if (char === "[") {
|
|
105
|
+
depth++;
|
|
106
|
+
if (depth > 1)
|
|
107
|
+
current += char;
|
|
108
|
+
}
|
|
109
|
+
else if (char === "]") {
|
|
110
|
+
depth--;
|
|
111
|
+
if (depth === 0) {
|
|
112
|
+
if (current) {
|
|
113
|
+
currentList.push(current.trim());
|
|
114
|
+
current = "";
|
|
115
|
+
}
|
|
116
|
+
if (currentList.length > 0) {
|
|
117
|
+
results.push(currentList);
|
|
118
|
+
currentList = [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
current += char;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else if (char === "," && depth === 1) {
|
|
126
|
+
if (current) {
|
|
127
|
+
currentList.push(current.trim());
|
|
128
|
+
current = "";
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (char === "," && depth === 0) {
|
|
132
|
+
// Skip comma between lists
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
current += char;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return results;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Parse a single entity from Prolog binding format.
|
|
142
|
+
* Input: "[abc123, req, [id=abc123, title=\"Test\", ...]]"
|
|
143
|
+
*/
|
|
144
|
+
export function parseEntityFromBinding(bindingStr) {
|
|
145
|
+
const cleaned = bindingStr.trim().replace(/^\[/, "").replace(/\]$/, "");
|
|
146
|
+
const parts = splitTopLevelGeneral(cleaned, ",");
|
|
147
|
+
if (parts.length < 3) {
|
|
148
|
+
return {};
|
|
149
|
+
}
|
|
150
|
+
const id = parts[0].trim();
|
|
151
|
+
const type = parts[1].trim();
|
|
152
|
+
const propsStr = parts.slice(2).join(",").trim();
|
|
153
|
+
const props = parsePropertyList(propsStr);
|
|
154
|
+
return { ...props, id: normalizeEntityId(stripOuterQuotes(id)), type };
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Parse entity from array returned by parseListOfLists.
|
|
158
|
+
* Input: ["abc123", "req", "[id=abc123, title=\"Test\", ...]"]
|
|
159
|
+
*/
|
|
160
|
+
export function parseEntityFromList(data) {
|
|
161
|
+
if (data.length < 3) {
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
const id = data[0].trim();
|
|
165
|
+
const type = data[1].trim();
|
|
166
|
+
const propsStr = data[2].trim();
|
|
167
|
+
const props = parsePropertyList(propsStr);
|
|
168
|
+
return { ...props, id: normalizeEntityId(stripOuterQuotes(id)), type };
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Parse Prolog property list into JavaScript object.
|
|
172
|
+
* Input: "[id=abc123, title=\"Test\"]"
|
|
173
|
+
*/
|
|
174
|
+
export function parsePropertyList(propsStr) {
|
|
175
|
+
const props = {};
|
|
176
|
+
let cleaned = propsStr.trim();
|
|
177
|
+
if (cleaned.startsWith("[")) {
|
|
178
|
+
cleaned = cleaned.substring(1);
|
|
179
|
+
}
|
|
180
|
+
if (cleaned.endsWith("]")) {
|
|
181
|
+
cleaned = cleaned.substring(0, cleaned.length - 1);
|
|
182
|
+
}
|
|
183
|
+
const pairs = splitTopLevelGeneral(cleaned, ",");
|
|
184
|
+
for (const pair of pairs) {
|
|
185
|
+
const eqIndex = pair.indexOf("=");
|
|
186
|
+
if (eqIndex === -1)
|
|
187
|
+
continue;
|
|
188
|
+
const key = pair.substring(0, eqIndex).trim();
|
|
189
|
+
const value = pair.substring(eqIndex + 1).trim();
|
|
190
|
+
if (key === "..." || value === "..." || value === "...|...") {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const parsed = parsePrologValue(value);
|
|
194
|
+
props[key] = parsed;
|
|
195
|
+
}
|
|
196
|
+
return props;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Parse a single Prolog value, handling typed literals and URIs.
|
|
200
|
+
*/
|
|
201
|
+
export function parsePrologValue(valueInput) {
|
|
202
|
+
const value = valueInput.trim();
|
|
203
|
+
// Handle typed literal: ^^("value", type)
|
|
204
|
+
if (value.startsWith("^^(")) {
|
|
205
|
+
const innerStart = value.indexOf("(") + 1;
|
|
206
|
+
let depth = 1;
|
|
207
|
+
let innerEnd = innerStart;
|
|
208
|
+
for (let i = innerStart; i < value.length; i++) {
|
|
209
|
+
if (value[i] === "(")
|
|
210
|
+
depth++;
|
|
211
|
+
if (value[i] === ")") {
|
|
212
|
+
depth--;
|
|
213
|
+
if (depth === 0) {
|
|
214
|
+
innerEnd = i;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const innerContent = value.substring(innerStart, innerEnd);
|
|
220
|
+
const parts = splitTopLevelGeneral(innerContent, ",");
|
|
221
|
+
if (parts.length >= 2) {
|
|
222
|
+
let literalValue = parts[0].trim();
|
|
223
|
+
if (literalValue.startsWith('"') && literalValue.endsWith('"')) {
|
|
224
|
+
literalValue = literalValue.substring(1, literalValue.length - 1);
|
|
225
|
+
}
|
|
226
|
+
// Handle array notation
|
|
227
|
+
if (literalValue.startsWith("[") && literalValue.endsWith("]")) {
|
|
228
|
+
const listContent = literalValue.substring(1, literalValue.length - 1);
|
|
229
|
+
if (listContent === "") {
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
return splitTopLevelGeneral(listContent, ",").map((item) => item.trim());
|
|
233
|
+
}
|
|
234
|
+
return literalValue;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Handle URI
|
|
238
|
+
if (value.startsWith("file:///")) {
|
|
239
|
+
const lastSlash = value.lastIndexOf("/");
|
|
240
|
+
if (lastSlash !== -1) {
|
|
241
|
+
return value.substring(lastSlash + 1);
|
|
242
|
+
}
|
|
243
|
+
return value;
|
|
244
|
+
}
|
|
245
|
+
// Handle quoted string
|
|
246
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
247
|
+
return value.substring(1, value.length - 1);
|
|
248
|
+
}
|
|
249
|
+
// Handle quoted atom
|
|
250
|
+
if (value.startsWith("'") && value.endsWith("'")) {
|
|
251
|
+
return value.substring(1, value.length - 1);
|
|
252
|
+
}
|
|
253
|
+
// Handle list
|
|
254
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
255
|
+
const listContent = value.substring(1, value.length - 1);
|
|
256
|
+
if (listContent === "") {
|
|
257
|
+
return [];
|
|
258
|
+
}
|
|
259
|
+
const items = splitTopLevelGeneral(listContent, ",").map((item) => {
|
|
260
|
+
return parsePrologValue(item.trim());
|
|
261
|
+
});
|
|
262
|
+
return items;
|
|
263
|
+
}
|
|
264
|
+
return value;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* General-purpose split at top level (not inside brackets or quotes).
|
|
268
|
+
* More robust version used by property parsing.
|
|
269
|
+
*/
|
|
270
|
+
function splitTopLevelGeneral(str, delimiter) {
|
|
271
|
+
const results = [];
|
|
272
|
+
let current = "";
|
|
273
|
+
let depth = 0;
|
|
274
|
+
let inQuotes = false;
|
|
275
|
+
for (let i = 0; i < str.length; i++) {
|
|
276
|
+
const char = str[i];
|
|
277
|
+
const prevChar = i > 0 ? str[i - 1] : "";
|
|
278
|
+
if (char === '"' && prevChar !== "\\") {
|
|
279
|
+
inQuotes = !inQuotes;
|
|
280
|
+
current += char;
|
|
281
|
+
}
|
|
282
|
+
else if (!inQuotes && (char === "[" || char === "(")) {
|
|
283
|
+
depth++;
|
|
284
|
+
current += char;
|
|
285
|
+
}
|
|
286
|
+
else if (!inQuotes && (char === "]" || char === ")")) {
|
|
287
|
+
depth--;
|
|
288
|
+
current += char;
|
|
289
|
+
}
|
|
290
|
+
else if (!inQuotes && depth === 0 && char === delimiter) {
|
|
291
|
+
if (current) {
|
|
292
|
+
results.push(current);
|
|
293
|
+
current = "";
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
current += char;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (current) {
|
|
301
|
+
results.push(current);
|
|
302
|
+
}
|
|
303
|
+
return results;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Strip outer quotes from a string value.
|
|
307
|
+
*/
|
|
308
|
+
function stripOuterQuotes(value) {
|
|
309
|
+
if (value.startsWith("'") && value.endsWith("'")) {
|
|
310
|
+
return value.slice(1, -1);
|
|
311
|
+
}
|
|
312
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
313
|
+
return value.slice(1, -1);
|
|
314
|
+
}
|
|
315
|
+
return value;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Normalize entity ID by extracting filename from file:// URI.
|
|
319
|
+
*/
|
|
320
|
+
function normalizeEntityId(value) {
|
|
321
|
+
if (!value.startsWith("file:///")) {
|
|
322
|
+
return value;
|
|
323
|
+
}
|
|
324
|
+
const idx = value.lastIndexOf("/");
|
|
325
|
+
return idx === -1 ? value : value.slice(idx + 1);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Parse an atom list from Prolog response.
|
|
329
|
+
* Input: "[a, b, c]" or atom string
|
|
330
|
+
*/
|
|
331
|
+
export function parseAtomList(raw) {
|
|
332
|
+
const trimmed = raw.trim();
|
|
333
|
+
if (trimmed === "[]" || trimmed.length === 0) {
|
|
334
|
+
return [];
|
|
335
|
+
}
|
|
336
|
+
const content = unwrapList(trimmed);
|
|
337
|
+
if (content.length === 0) {
|
|
338
|
+
return [];
|
|
339
|
+
}
|
|
340
|
+
return splitTopLevelGeneral(content, ",")
|
|
341
|
+
.map((token) => stripQuotes(token.trim()))
|
|
342
|
+
.filter((token) => token.length > 0);
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Parse a list of pairs from Prolog response.
|
|
346
|
+
*/
|
|
347
|
+
export function parsePairList(raw) {
|
|
348
|
+
const rows = parseListRows(raw);
|
|
349
|
+
const pairs = [];
|
|
350
|
+
for (const row of rows) {
|
|
351
|
+
const parts = splitTopLevelGeneral(row, ",").map((part) => stripQuotes(part.trim()));
|
|
352
|
+
if (parts.length >= 2) {
|
|
353
|
+
pairs.push([parts[0], parts[1]]);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return pairs;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Parse a list of triples from Prolog response.
|
|
360
|
+
*/
|
|
361
|
+
export function parseTriples(raw) {
|
|
362
|
+
const rows = parseListRows(raw);
|
|
363
|
+
const triples = [];
|
|
364
|
+
for (const row of rows) {
|
|
365
|
+
const parts = splitTopLevelGeneral(row, ",").map((part) => stripQuotes(part.trim()));
|
|
366
|
+
if (parts.length >= 3) {
|
|
367
|
+
triples.push([parts[0], parts[1], parts[2]]);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return triples;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Parse list rows from Prolog response.
|
|
374
|
+
*/
|
|
375
|
+
function parseListRows(raw) {
|
|
376
|
+
const trimmed = raw.trim();
|
|
377
|
+
if (trimmed === "[]" || trimmed.length === 0) {
|
|
378
|
+
return [];
|
|
379
|
+
}
|
|
380
|
+
const content = unwrapList(trimmed);
|
|
381
|
+
if (content.length === 0) {
|
|
382
|
+
return [];
|
|
383
|
+
}
|
|
384
|
+
const rows = [];
|
|
385
|
+
let depth = 0;
|
|
386
|
+
let current = "";
|
|
387
|
+
for (let i = 0; i < content.length; i++) {
|
|
388
|
+
const ch = content[i];
|
|
389
|
+
if (ch === "[") {
|
|
390
|
+
depth++;
|
|
391
|
+
if (depth > 1) {
|
|
392
|
+
current += ch;
|
|
393
|
+
}
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (ch === "]") {
|
|
397
|
+
depth--;
|
|
398
|
+
if (depth === 0) {
|
|
399
|
+
rows.push(current.trim());
|
|
400
|
+
current = "";
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
current += ch;
|
|
404
|
+
}
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
if (ch === "," && depth === 0) {
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
current += ch;
|
|
411
|
+
}
|
|
412
|
+
return rows;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Unwrap outer list brackets.
|
|
416
|
+
*/
|
|
417
|
+
function unwrapList(value) {
|
|
418
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
419
|
+
return value.slice(1, -1).trim();
|
|
420
|
+
}
|
|
421
|
+
return value;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Strip quotes from a value (single or double).
|
|
425
|
+
*/
|
|
426
|
+
function stripQuotes(value) {
|
|
427
|
+
if (value.startsWith("'") && value.endsWith("'")) {
|
|
428
|
+
return value.slice(1, -1);
|
|
429
|
+
}
|
|
430
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
431
|
+
return value.slice(1, -1);
|
|
432
|
+
}
|
|
433
|
+
return value;
|
|
434
|
+
}
|
package/dist/prolog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prolog.d.ts","sourceRoot":"","sources":["../src/prolog.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prolog.d.ts","sourceRoot":"","sources":["../src/prolog.ts"],"names":[],"mappings":"AA4BA,wBAAgB,eAAe,IAAI,MAAM,CAsCxC;AACD,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,oBAAoB,CAAoC;IAChE,OAAO,CAAC,cAAc,CACyC;IAC/D,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,aAAa,CAA6B;gBAEtC,OAAO,GAAE,aAAkB;IAKjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAoCd,YAAY;IAyCpB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAuJ1D,eAAe,IAAI,IAAI;IAIvB,OAAO,CAAC,eAAe;YAYT,YAAY;IA0B1B,OAAO,CAAC,WAAW;IA8EnB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,cAAc;IA8BtB,SAAS,IAAI,OAAO;IAIpB,MAAM,IAAI,MAAM;IAIV,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAyBjC"}
|
package/dist/prolog.js
CHANGED
|
@@ -15,33 +15,6 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
/*
|
|
19
|
-
How to apply this header to source files (examples)
|
|
20
|
-
|
|
21
|
-
1) Prepend header to a single file (POSIX shells):
|
|
22
|
-
|
|
23
|
-
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
-
|
|
25
|
-
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
-
|
|
27
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
-
if [ -f "$f" ]; then
|
|
29
|
-
cp "$f" "$f".bak
|
|
30
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
-
fi
|
|
32
|
-
done
|
|
33
|
-
|
|
34
|
-
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
-
|
|
36
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
-
if [ -f "$f" ]; then
|
|
38
|
-
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
-
cp "$f" "$f".bak
|
|
40
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
-
fi
|
|
42
|
-
fi
|
|
43
|
-
done
|
|
44
|
-
*/
|
|
45
18
|
import { spawn, spawnSync } from "node:child_process";
|
|
46
19
|
import { existsSync } from "node:fs";
|
|
47
20
|
import { createRequire } from "node:module";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbols-coordinator.d.ts","sourceRoot":"","sources":["../../../src/public/extractors/symbols-coordinator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"symbols-coordinator.d.ts","sourceRoot":"","sources":["../../../src/public/extractors/symbols-coordinator.ts"],"names":[],"mappings":"AAmBA,OAAO,EACL,uBAAuB,EACvB,KAAK,mBAAmB,GACzB,MAAM,yCAAyC,CAAC"}
|
|
@@ -15,32 +15,5 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
/*
|
|
19
|
-
How to apply this header to source files (examples)
|
|
20
|
-
|
|
21
|
-
1) Prepend header to a single file (POSIX shells):
|
|
22
|
-
|
|
23
|
-
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
-
|
|
25
|
-
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
-
|
|
27
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
-
if [ -f "$f" ]; then
|
|
29
|
-
cp "$f" "$f".bak
|
|
30
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
-
fi
|
|
32
|
-
done
|
|
33
|
-
|
|
34
|
-
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
-
|
|
36
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
-
if [ -f "$f" ]; then
|
|
38
|
-
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
-
cp "$f" "$f".bak
|
|
40
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
-
fi
|
|
42
|
-
fi
|
|
43
|
-
done
|
|
44
|
-
*/
|
|
45
18
|
// Public re-export of symbols coordinator
|
|
46
19
|
export { enrichSymbolCoordinates, } from "../../extractors/symbols-coordinator.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/public/prolog/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/public/prolog/index.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -15,32 +15,5 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
/*
|
|
19
|
-
How to apply this header to source files (examples)
|
|
20
|
-
|
|
21
|
-
1) Prepend header to a single file (POSIX shells):
|
|
22
|
-
|
|
23
|
-
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
-
|
|
25
|
-
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
-
|
|
27
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
-
if [ -f "$f" ]; then
|
|
29
|
-
cp "$f" "$f".bak
|
|
30
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
-
fi
|
|
32
|
-
done
|
|
33
|
-
|
|
34
|
-
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
-
|
|
36
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
-
if [ -f "$f" ]; then
|
|
38
|
-
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
-
cp "$f" "$f".bak
|
|
40
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
-
fi
|
|
42
|
-
fi
|
|
43
|
-
done
|
|
44
|
-
*/
|
|
45
18
|
// Public re-export of PrologProcess
|
|
46
19
|
export { PrologProcess } from "../../prolog.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/entity.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/entity.ts"],"names":[],"mappings":"AAoBA,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDjB,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -15,33 +15,6 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
/*
|
|
19
|
-
How to apply this header to source files (examples)
|
|
20
|
-
|
|
21
|
-
1) Prepend header to a single file (POSIX shells):
|
|
22
|
-
|
|
23
|
-
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
-
|
|
25
|
-
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
-
|
|
27
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
-
if [ -f "$f" ]; then
|
|
29
|
-
cp "$f" "$f".bak
|
|
30
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
-
fi
|
|
32
|
-
done
|
|
33
|
-
|
|
34
|
-
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
-
|
|
36
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
-
if [ -f "$f" ]; then
|
|
38
|
-
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
-
cp "$f" "$f".bak
|
|
40
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
-
fi
|
|
42
|
-
fi
|
|
43
|
-
done
|
|
44
|
-
*/
|
|
45
18
|
// Public export of entity schema
|
|
46
19
|
// Generated from entity.schema.json
|
|
47
20
|
const entitySchema = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relationship.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/relationship.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"relationship.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/relationship.ts"],"names":[],"mappings":"AAoBA,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCvB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -15,33 +15,6 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
/*
|
|
19
|
-
How to apply this header to source files (examples)
|
|
20
|
-
|
|
21
|
-
1) Prepend header to a single file (POSIX shells):
|
|
22
|
-
|
|
23
|
-
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
-
|
|
25
|
-
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
-
|
|
27
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
-
if [ -f "$f" ]; then
|
|
29
|
-
cp "$f" "$f".bak
|
|
30
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
-
fi
|
|
32
|
-
done
|
|
33
|
-
|
|
34
|
-
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
-
|
|
36
|
-
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
-
if [ -f "$f" ]; then
|
|
38
|
-
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
-
cp "$f" "$f".bak
|
|
40
|
-
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
-
fi
|
|
42
|
-
fi
|
|
43
|
-
done
|
|
44
|
-
*/
|
|
45
18
|
// Public export of relationship schema
|
|
46
19
|
// Generated from relationship.schema.json
|
|
47
20
|
const relationshipSchema = {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { PrologProcess } from "../prolog.js";
|
|
2
|
+
export interface QueryFilters {
|
|
3
|
+
type?: string;
|
|
4
|
+
id?: string;
|
|
5
|
+
tags?: string[];
|
|
6
|
+
sourceFile?: string;
|
|
7
|
+
limit?: number;
|
|
8
|
+
offset?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface QueryResult {
|
|
11
|
+
entities: Array<Record<string, unknown>>;
|
|
12
|
+
totalCount: number;
|
|
13
|
+
}
|
|
14
|
+
export declare const VALID_ENTITY_TYPES: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Build a Prolog query goal from filters.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildEntityQueryGoal(filters: QueryFilters): string;
|
|
19
|
+
/**
|
|
20
|
+
* Execute a filtered entity query against the KB.
|
|
21
|
+
*/
|
|
22
|
+
export declare function queryEntities(prolog: PrologProcess, filters: QueryFilters): Promise<QueryResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Validate entity type.
|
|
25
|
+
*/
|
|
26
|
+
export declare function validateEntityType(type: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Get validation error message for invalid type.
|
|
29
|
+
*/
|
|
30
|
+
export declare function getInvalidTypeError(type: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Build human-readable summary text for query results.
|
|
33
|
+
*/
|
|
34
|
+
export declare function buildQuerySummaryText(result: QueryResult, filters: QueryFilters): string;
|
|
35
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/query/service.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAQlD,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,kBAAkB,UAS9B,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAqClE;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,WAAW,CAAC,CAmCtB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,YAAY,GACpB,MAAM,CAkBR"}
|