kibi-cli 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/aggregated-checks.d.ts.map +1 -1
- package/dist/commands/aggregated-checks.js +3 -2
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +97 -51
- package/dist/commands/discovery-shared.d.ts +12 -5
- package/dist/commands/discovery-shared.d.ts.map +1 -1
- package/dist/commands/discovery-shared.js +21 -13
- package/dist/commands/doctor.js +9 -1
- package/dist/commands/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +2 -3
- package/dist/commands/query.d.ts.map +1 -1
- package/dist/commands/query.js +15 -5
- package/dist/commands/search.js +1 -1
- package/dist/commands/sync/cache.d.ts +14 -4
- package/dist/commands/sync/cache.d.ts.map +1 -1
- package/dist/commands/sync/cache.js +36 -14
- package/dist/commands/sync/extraction.d.ts.map +1 -1
- package/dist/commands/sync/extraction.js +4 -9
- package/dist/commands/sync/manifest.d.ts +14 -3
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +29 -10
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +9 -5
- package/dist/commands/sync/staging.d.ts +19 -3
- package/dist/commands/sync/staging.d.ts.map +1 -1
- package/dist/commands/sync/staging.js +50 -27
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +16 -20
- package/dist/diagnostics.d.ts +1 -10
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +6 -12
- package/dist/env.d.ts +7 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +41 -0
- package/dist/extractors/manifest.d.ts.map +1 -1
- package/dist/extractors/manifest.js +17 -15
- package/dist/extractors/markdown.d.ts +2 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +124 -30
- package/dist/extractors/relationships.d.ts.map +1 -1
- package/dist/extractors/relationships.js +10 -4
- package/dist/extractors/symbols-coordinator.d.ts +5 -2
- package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
- package/dist/extractors/symbols-coordinator.js +5 -2
- package/dist/extractors/symbols-ts.d.ts.map +1 -1
- package/dist/extractors/symbols-ts.js +56 -10
- package/dist/prolog/codec.d.ts +0 -43
- package/dist/prolog/codec.d.ts.map +1 -1
- package/dist/prolog/codec.js +68 -74
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +45 -29
- package/dist/public/schemas/entity.d.ts +3 -0
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +1 -0
- package/dist/public/schemas/relationship.d.ts.map +1 -1
- package/dist/public/schemas/relationship.js +1 -0
- package/dist/query/service.d.ts +9 -0
- package/dist/query/service.d.ts.map +1 -1
- package/dist/query/service.js +27 -10
- package/dist/schemas/entity.schema.json +23 -0
- package/dist/search-ranking.d.ts.map +1 -1
- package/dist/search-ranking.js +19 -3
- package/dist/traceability/git-staged.d.ts.map +1 -1
- package/dist/traceability/git-staged.js +22 -6
- package/dist/traceability/symbol-extract.d.ts.map +1 -1
- package/dist/traceability/symbol-extract.js +10 -4
- package/dist/traceability/temp-kb.d.ts +12 -0
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +42 -17
- package/dist/traceability/validate.d.ts.map +1 -1
- package/dist/traceability/validate.js +11 -2
- 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 +29 -12
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +8 -2
- package/dist/utils/rule-registry.js +2 -2
- package/package.json +3 -9
- package/src/public/schemas/entity.ts +1 -0
- package/src/public/schemas/relationship.ts +1 -0
- package/src/schemas/entity.schema.json +23 -0
- package/src/schemas/relationship.schema.json +1 -0
package/dist/prolog/codec.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* Doubles single-quote characters per ISO Prolog standard.
|
|
17
17
|
*/
|
|
18
18
|
export function escapeAtom(value) {
|
|
19
|
+
// implements REQ-009
|
|
19
20
|
return value.replace(/'/g, "''");
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
@@ -23,6 +24,7 @@ export function escapeAtom(value) {
|
|
|
23
24
|
* Simple atoms (lowercase start, alphanumeric + underscore) pass through.
|
|
24
25
|
*/
|
|
25
26
|
export function toPrologAtom(value) {
|
|
27
|
+
// implements REQ-009
|
|
26
28
|
const simplePrologAtom = /^[a-z][a-zA-Z0-9_]*$/;
|
|
27
29
|
return simplePrologAtom.test(value)
|
|
28
30
|
? value
|
|
@@ -48,14 +50,11 @@ export function toPrologString(value) {
|
|
|
48
50
|
* Alias for escapeAtom for semantic clarity.
|
|
49
51
|
*/
|
|
50
52
|
export function escapeAtomContent(value) {
|
|
53
|
+
// implements REQ-009
|
|
51
54
|
return value.replace(/'/g, "''");
|
|
52
55
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Parse a Prolog list of lists into a JavaScript array.
|
|
55
|
-
* Input: "[[a,b,c],[d,e,f]]"
|
|
56
|
-
* Output: [["a", "b", "c"], ["d", "e", "f"]]
|
|
57
|
-
*/
|
|
58
56
|
export function parseListOfLists(listStr) {
|
|
57
|
+
// implements REQ-009
|
|
59
58
|
const cleaned = listStr.trim().replace(/^\[/, "").replace(/\]$/, "");
|
|
60
59
|
if (cleaned === "") {
|
|
61
60
|
return [];
|
|
@@ -102,41 +101,44 @@ export function parseListOfLists(listStr) {
|
|
|
102
101
|
}
|
|
103
102
|
return results;
|
|
104
103
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
*/
|
|
109
|
-
export function parseEntityFromBinding(bindingStr) {
|
|
104
|
+
export function parseEntityFromBinding(
|
|
105
|
+
// implements REQ-009
|
|
106
|
+
bindingStr) {
|
|
110
107
|
const cleaned = bindingStr.trim().replace(/^\[/, "").replace(/\]$/, "");
|
|
111
108
|
const parts = splitTopLevelGeneral(cleaned, ",");
|
|
112
109
|
if (parts.length < 3) {
|
|
113
110
|
return {};
|
|
114
111
|
}
|
|
115
|
-
const
|
|
116
|
-
const
|
|
112
|
+
const idPart = parts[0];
|
|
113
|
+
const typePart = parts[1];
|
|
114
|
+
if (idPart === undefined || typePart === undefined) {
|
|
115
|
+
return {};
|
|
116
|
+
}
|
|
117
|
+
const id = idPart.trim();
|
|
118
|
+
const type = typePart.trim();
|
|
117
119
|
const propsStr = parts.slice(2).join(",").trim();
|
|
118
120
|
const props = parsePropertyList(propsStr);
|
|
119
121
|
return { ...props, id: normalizeEntityId(stripOuterQuotes(id)), type };
|
|
120
122
|
}
|
|
121
|
-
/**
|
|
122
|
-
* Parse entity from array returned by parseListOfLists.
|
|
123
|
-
* Input: ["abc123", "req", "[id=abc123, title=\"Test\", ...]"]
|
|
124
|
-
*/
|
|
125
123
|
export function parseEntityFromList(data) {
|
|
124
|
+
// implements REQ-009
|
|
126
125
|
if (data.length < 3) {
|
|
127
126
|
return {};
|
|
128
127
|
}
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
const [idPart, typePart, propsPart] = data;
|
|
129
|
+
if (idPart === undefined ||
|
|
130
|
+
typePart === undefined ||
|
|
131
|
+
propsPart === undefined) {
|
|
132
|
+
return {};
|
|
133
|
+
}
|
|
134
|
+
const id = idPart.trim();
|
|
135
|
+
const type = typePart.trim();
|
|
136
|
+
const propsStr = propsPart.trim();
|
|
132
137
|
const props = parsePropertyList(propsStr);
|
|
133
138
|
return { ...props, id: normalizeEntityId(stripOuterQuotes(id)), type };
|
|
134
139
|
}
|
|
135
|
-
/**
|
|
136
|
-
* Parse Prolog property list into JavaScript object.
|
|
137
|
-
* Input: "[id=abc123, title=\"Test\"]"
|
|
138
|
-
*/
|
|
139
140
|
export function parsePropertyList(propsStr) {
|
|
141
|
+
// implements REQ-009
|
|
140
142
|
const props = {};
|
|
141
143
|
let cleaned = propsStr.trim();
|
|
142
144
|
if (cleaned.startsWith("[")) {
|
|
@@ -160,9 +162,6 @@ export function parsePropertyList(propsStr) {
|
|
|
160
162
|
}
|
|
161
163
|
return props;
|
|
162
164
|
}
|
|
163
|
-
/**
|
|
164
|
-
* Parse a single Prolog value, handling typed literals and URIs.
|
|
165
|
-
*/
|
|
166
165
|
export function parsePrologValue(valueInput) {
|
|
167
166
|
// implements REQ-009
|
|
168
167
|
const value = valueInput.trim();
|
|
@@ -185,8 +184,13 @@ export function parsePrologValue(valueInput) {
|
|
|
185
184
|
const innerContent = value.substring(innerStart, innerEnd);
|
|
186
185
|
const parts = splitTopLevelGeneral(innerContent, ",");
|
|
187
186
|
if (parts.length >= 2) {
|
|
188
|
-
|
|
189
|
-
const
|
|
187
|
+
const literalPart = parts[0];
|
|
188
|
+
const datatypePart = parts[1];
|
|
189
|
+
if (literalPart === undefined || datatypePart === undefined) {
|
|
190
|
+
return value;
|
|
191
|
+
}
|
|
192
|
+
let literalValue = literalPart.trim();
|
|
193
|
+
const datatype = datatypePart.trim();
|
|
190
194
|
if (literalValue.startsWith('"') && literalValue.endsWith('"')) {
|
|
191
195
|
literalValue = literalValue.substring(1, literalValue.length - 1);
|
|
192
196
|
}
|
|
@@ -240,10 +244,6 @@ export function parsePrologValue(valueInput) {
|
|
|
240
244
|
}
|
|
241
245
|
return value;
|
|
242
246
|
}
|
|
243
|
-
/**
|
|
244
|
-
* General-purpose split at top level (not inside brackets or quotes).
|
|
245
|
-
* More robust version used by property parsing.
|
|
246
|
-
*/
|
|
247
247
|
export function splitTopLevelGeneral(str, delimiter) {
|
|
248
248
|
// implements REQ-009
|
|
249
249
|
const results = [];
|
|
@@ -292,17 +292,10 @@ export function splitTopLevelGeneral(str, delimiter) {
|
|
|
292
292
|
}
|
|
293
293
|
return results;
|
|
294
294
|
}
|
|
295
|
-
/**
|
|
296
|
-
* Split a string by delimiter at the top level (not inside brackets or quotes).
|
|
297
|
-
* @see splitTopLevelGeneral
|
|
298
|
-
*/
|
|
299
295
|
export function splitTopLevel(str, delimiter) {
|
|
300
296
|
// implements REQ-009
|
|
301
297
|
return splitTopLevelGeneral(str, delimiter);
|
|
302
298
|
}
|
|
303
|
-
/**
|
|
304
|
-
* Strip outer quotes from a string value.
|
|
305
|
-
*/
|
|
306
299
|
function stripOuterQuotes(value) {
|
|
307
300
|
if (value.startsWith("'") && value.endsWith("'")) {
|
|
308
301
|
return value.slice(1, -1);
|
|
@@ -312,9 +305,6 @@ function stripOuterQuotes(value) {
|
|
|
312
305
|
}
|
|
313
306
|
return value;
|
|
314
307
|
}
|
|
315
|
-
/**
|
|
316
|
-
* Normalize entity ID by extracting filename from file:// URI.
|
|
317
|
-
*/
|
|
318
308
|
function normalizeEntityId(value) {
|
|
319
309
|
if (!value.startsWith("file:///")) {
|
|
320
310
|
return value;
|
|
@@ -322,11 +312,8 @@ function normalizeEntityId(value) {
|
|
|
322
312
|
const idx = value.lastIndexOf("/");
|
|
323
313
|
return idx === -1 ? value : value.slice(idx + 1);
|
|
324
314
|
}
|
|
325
|
-
/**
|
|
326
|
-
* Parse an atom list from Prolog response.
|
|
327
|
-
* Input: "[a, b, c]" or atom string
|
|
328
|
-
*/
|
|
329
315
|
export function parseAtomList(raw) {
|
|
316
|
+
// implements REQ-009
|
|
330
317
|
const trimmed = raw.trim();
|
|
331
318
|
if (trimmed === "[]" || trimmed.length === 0) {
|
|
332
319
|
return [];
|
|
@@ -339,37 +326,39 @@ export function parseAtomList(raw) {
|
|
|
339
326
|
.map((token) => stripQuotes(token.trim()))
|
|
340
327
|
.filter((token) => token.length > 0);
|
|
341
328
|
}
|
|
342
|
-
/**
|
|
343
|
-
* Parse a list of pairs from Prolog response.
|
|
344
|
-
*/
|
|
345
329
|
export function parsePairList(raw) {
|
|
330
|
+
// implements REQ-009
|
|
346
331
|
const rows = parseListRows(raw);
|
|
347
332
|
const pairs = [];
|
|
348
333
|
for (const row of rows) {
|
|
349
334
|
const parts = splitTopLevelGeneral(row, ",").map((part) => stripQuotes(part.trim()));
|
|
350
335
|
if (parts.length >= 2) {
|
|
351
|
-
|
|
336
|
+
const first = parts[0];
|
|
337
|
+
const second = parts[1];
|
|
338
|
+
if (first !== undefined && second !== undefined) {
|
|
339
|
+
pairs.push([first, second]);
|
|
340
|
+
}
|
|
352
341
|
}
|
|
353
342
|
}
|
|
354
343
|
return pairs;
|
|
355
344
|
}
|
|
356
|
-
/**
|
|
357
|
-
* Parse a list of triples from Prolog response.
|
|
358
|
-
*/
|
|
359
345
|
export function parseTriples(raw) {
|
|
346
|
+
// implements REQ-009
|
|
360
347
|
const rows = parseListRows(raw);
|
|
361
348
|
const triples = [];
|
|
362
349
|
for (const row of rows) {
|
|
363
350
|
const parts = splitTopLevelGeneral(row, ",").map((part) => stripQuotes(part.trim()));
|
|
364
351
|
if (parts.length >= 3) {
|
|
365
|
-
|
|
352
|
+
const first = parts[0];
|
|
353
|
+
const second = parts[1];
|
|
354
|
+
const third = parts[2];
|
|
355
|
+
if (first !== undefined && second !== undefined && third !== undefined) {
|
|
356
|
+
triples.push([first, second, third]);
|
|
357
|
+
}
|
|
366
358
|
}
|
|
367
359
|
}
|
|
368
360
|
return triples;
|
|
369
361
|
}
|
|
370
|
-
/**
|
|
371
|
-
* Parse list rows from Prolog response.
|
|
372
|
-
*/
|
|
373
362
|
function parseListRows(raw) {
|
|
374
363
|
const trimmed = raw.trim();
|
|
375
364
|
if (trimmed === "[]" || trimmed.length === 0) {
|
|
@@ -409,20 +398,12 @@ function parseListRows(raw) {
|
|
|
409
398
|
}
|
|
410
399
|
return rows;
|
|
411
400
|
}
|
|
412
|
-
/**
|
|
413
|
-
* Unwrap outer list brackets.
|
|
414
|
-
*/
|
|
415
401
|
function unwrapList(value) {
|
|
416
402
|
if (value.startsWith("[") && value.endsWith("]")) {
|
|
417
403
|
return value.slice(1, -1).trim();
|
|
418
404
|
}
|
|
419
405
|
return value;
|
|
420
406
|
}
|
|
421
|
-
/**
|
|
422
|
-
* Parse a Prolog list of violation/5 terms into JavaScript objects.
|
|
423
|
-
* Handles descriptions and suggestions that contain commas or nested parens.
|
|
424
|
-
* Input: "[violation(rule,'EntityId',\"Desc\",\"Sugg\",'src')]"
|
|
425
|
-
*/
|
|
426
407
|
export function parseViolationRows(raw) {
|
|
427
408
|
// implements REQ-006
|
|
428
409
|
const trimmed = raw.trim();
|
|
@@ -446,20 +427,33 @@ export function parseViolationRows(raw) {
|
|
|
446
427
|
const parts = splitTopLevelGeneral(inner, ",");
|
|
447
428
|
if (parts.length < 4)
|
|
448
429
|
continue;
|
|
449
|
-
const
|
|
450
|
-
const
|
|
451
|
-
const
|
|
452
|
-
const
|
|
430
|
+
const rulePart = parts[0];
|
|
431
|
+
const entityIdPart = parts[1];
|
|
432
|
+
const descriptionPart = parts[2];
|
|
433
|
+
const suggestionPart = parts[3];
|
|
434
|
+
if (rulePart === undefined ||
|
|
435
|
+
entityIdPart === undefined ||
|
|
436
|
+
descriptionPart === undefined ||
|
|
437
|
+
suggestionPart === undefined) {
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
const rule = rulePart.trim().replace(/^'|'$/g, "");
|
|
441
|
+
const entityId = entityIdPart.trim().replace(/^'|'$/g, "");
|
|
442
|
+
const description = descriptionPart.trim().replace(/^"|"$/g, "");
|
|
443
|
+
const suggestion = suggestionPart.trim().replace(/^"|"$/g, "");
|
|
453
444
|
const source = parts.length >= 5
|
|
454
|
-
? parts[4]
|
|
445
|
+
? parts[4]?.trim().replace(/^'|'$/g, "") || undefined
|
|
455
446
|
: undefined;
|
|
456
|
-
violations.push({
|
|
447
|
+
violations.push({
|
|
448
|
+
rule,
|
|
449
|
+
entityId,
|
|
450
|
+
description,
|
|
451
|
+
suggestion,
|
|
452
|
+
...(source !== undefined ? { source } : {}),
|
|
453
|
+
});
|
|
457
454
|
}
|
|
458
455
|
return violations;
|
|
459
456
|
}
|
|
460
|
-
/**
|
|
461
|
-
* Strip quotes from a value (single or double).
|
|
462
|
-
*/
|
|
463
457
|
function stripQuotes(value) {
|
|
464
458
|
if (value.startsWith("'") && value.endsWith("'")) {
|
|
465
459
|
return value.slice(1, -1);
|
package/dist/prolog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prolog.d.ts","sourceRoot":"","sources":["../src/prolog.ts"],"names":[],"mappings":"AA4BA,wBAAgB,eAAe,IAAI,MAAM,
|
|
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;YAsCd,YAAY;IA0CpB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAuJ1D,eAAe,IAAI,IAAI;IAIvB,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,kBAAkB;YAIZ,YAAY;IA2C1B,OAAO,CAAC,WAAW;IAsGnB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,cAAc;IA+BtB,SAAS,IAAI,OAAO;IAIpB,MAAM,IAAI,MAAM;IAIV,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAyBjC"}
|
package/dist/prolog.js
CHANGED
|
@@ -20,36 +20,41 @@ import { existsSync } from "node:fs";
|
|
|
20
20
|
import { createRequire } from "node:module";
|
|
21
21
|
import path from "node:path";
|
|
22
22
|
import { fileURLToPath } from "node:url";
|
|
23
|
+
import { getKbPlPathOverride, isPrologDebugEnabled } from "./env.js";
|
|
23
24
|
const importMetaDir = path.dirname(fileURLToPath(import.meta.url));
|
|
24
25
|
const require = createRequire(import.meta.url);
|
|
25
26
|
export function resolveKbPlPath() {
|
|
26
27
|
// implements REQ-009
|
|
27
|
-
const overrideKbPath =
|
|
28
|
-
if (overrideKbPath
|
|
28
|
+
const overrideKbPath = getKbPlPathOverride();
|
|
29
|
+
if (overrideKbPath) {
|
|
29
30
|
return overrideKbPath;
|
|
30
31
|
}
|
|
32
|
+
// Strategy 1: Resolve kibi-core package and derive the source file path.
|
|
33
|
+
// This works in npm workspaces where kibi-core is a direct dependency of kibi-cli.
|
|
31
34
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return
|
|
35
|
+
try {
|
|
36
|
+
// First try: resolve as a file within the package
|
|
37
|
+
return require.resolve("kibi-core/src/kb.pl");
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Fall back: resolve package entry point and derive path
|
|
41
|
+
const coreMain = require.resolve("kibi-core");
|
|
42
|
+
const coreDir = path.dirname(coreMain);
|
|
43
|
+
return path.join(coreDir, "src", "kb.pl");
|
|
44
|
+
}
|
|
35
45
|
}
|
|
36
46
|
catch {
|
|
37
|
-
//
|
|
47
|
+
// Both resolution strategies failed
|
|
38
48
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
const parentDir = path.dirname(currentDir);
|
|
48
|
-
if (parentDir === currentDir) {
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
currentDir = parentDir;
|
|
49
|
+
// Strategy 2: Walk up from importMetaDir looking for packages/core/src/kb.pl.
|
|
50
|
+
// This works when running from the source tree (e.g., during development).
|
|
51
|
+
let currentDir = importMetaDir;
|
|
52
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
53
|
+
const candidate = path.join(currentDir, "packages", "core", "src", "kb.pl");
|
|
54
|
+
if (existsSync(candidate)) {
|
|
55
|
+
return candidate;
|
|
52
56
|
}
|
|
57
|
+
currentDir = path.dirname(currentDir);
|
|
53
58
|
}
|
|
54
59
|
throw new Error("Unable to resolve kb.pl. Expected kibi-core to be installed (node_modules) " +
|
|
55
60
|
"or to be running inside the monorepo checkout.");
|
|
@@ -88,6 +93,7 @@ export class PrologProcess {
|
|
|
88
93
|
this.process.stderr.on("data", (chunk) => {
|
|
89
94
|
this.errorBuffer += chunk.toString();
|
|
90
95
|
});
|
|
96
|
+
this.process.stdin.write("true.\n");
|
|
91
97
|
if (!this.onProcessExit) {
|
|
92
98
|
this.onProcessExit = () => {
|
|
93
99
|
void this.terminate();
|
|
@@ -109,13 +115,14 @@ export class PrologProcess {
|
|
|
109
115
|
if (this.errorBuffer.includes("ERROR")) {
|
|
110
116
|
throw new Error(`Failed to load kb module: ${this.translateError(this.errorBuffer)}`);
|
|
111
117
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
118
|
+
if (this.outputBuffer.includes("true.")) {
|
|
119
|
+
this.outputBuffer = "";
|
|
120
|
+
this.errorBuffer = "";
|
|
121
|
+
return;
|
|
115
122
|
}
|
|
116
123
|
// brief pause
|
|
117
124
|
// eslint-disable-next-line no-await-in-loop
|
|
118
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
125
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
119
126
|
}
|
|
120
127
|
// Final sanity check
|
|
121
128
|
if (this.errorBuffer.includes("ERROR")) {
|
|
@@ -154,7 +161,7 @@ export class PrologProcess {
|
|
|
154
161
|
const runInteractiveQuery = async () => {
|
|
155
162
|
this.outputBuffer = "";
|
|
156
163
|
this.errorBuffer = "";
|
|
157
|
-
const debug =
|
|
164
|
+
const debug = isPrologDebugEnabled();
|
|
158
165
|
const normalizedGoal = this.normalizeGoal(goal);
|
|
159
166
|
const wrappedGoal = /^once\s*\(/.test(normalizedGoal)
|
|
160
167
|
? normalizedGoal
|
|
@@ -282,6 +289,14 @@ export class PrologProcess {
|
|
|
282
289
|
}
|
|
283
290
|
const attachMatch = trimmedGoal.match(/^kb_attach\('(.+)'\)$/);
|
|
284
291
|
if (attachMatch) {
|
|
292
|
+
const attachPath = attachMatch[1] ?? null;
|
|
293
|
+
if (!attachPath) {
|
|
294
|
+
return {
|
|
295
|
+
success: false,
|
|
296
|
+
bindings: {},
|
|
297
|
+
error: "Invalid KB attach path",
|
|
298
|
+
};
|
|
299
|
+
}
|
|
285
300
|
if (this.attachedKbPath !== null) {
|
|
286
301
|
return {
|
|
287
302
|
success: false,
|
|
@@ -291,7 +306,7 @@ export class PrologProcess {
|
|
|
291
306
|
}
|
|
292
307
|
const attachResult = this.execOneShot(trimmedGoal, null);
|
|
293
308
|
if (attachResult.success) {
|
|
294
|
-
this.attachedKbPath =
|
|
309
|
+
this.attachedKbPath = attachPath;
|
|
295
310
|
}
|
|
296
311
|
return attachResult;
|
|
297
312
|
}
|
|
@@ -389,7 +404,9 @@ export class PrologProcess {
|
|
|
389
404
|
const match = line.match(/^([A-Z_][A-Za-z0-9_]*)\s*=\s*(.+)\.?\s*$/);
|
|
390
405
|
if (match) {
|
|
391
406
|
const [, varName, value] = match;
|
|
392
|
-
|
|
407
|
+
if (varName !== undefined && value !== undefined) {
|
|
408
|
+
bindings[varName] = value.trim().replace(/\.$/, "").replace(/,$/, "");
|
|
409
|
+
}
|
|
393
410
|
}
|
|
394
411
|
}
|
|
395
412
|
return bindings;
|
|
@@ -409,12 +426,11 @@ export class PrologProcess {
|
|
|
409
426
|
if (errorText.includes("timeout_error")) {
|
|
410
427
|
return `Operation exceeded ${this.timeout / 1000}s timeout`;
|
|
411
428
|
}
|
|
412
|
-
const simpleError = errorText
|
|
429
|
+
const simpleError = (errorText
|
|
413
430
|
.replace(/ERROR:\s*/g, "")
|
|
414
431
|
.replace(/^\*\*.*\*\*$/gm, "")
|
|
415
432
|
.replace(/^\s+/gm, "")
|
|
416
|
-
.split("\n")[0]
|
|
417
|
-
.trim();
|
|
433
|
+
.split("\n")[0] ?? "").trim();
|
|
418
434
|
return simpleError || "Unknown error";
|
|
419
435
|
}
|
|
420
436
|
isRunning() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/entity.ts"],"names":[],"mappings":"AAwBA,QAAA,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/entity.ts"],"names":[],"mappings":"AAwBA,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqHjB,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relationship.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/relationship.ts"],"names":[],"mappings":"AAkBA,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"relationship.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/relationship.ts"],"names":[],"mappings":"AAkBA,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCvB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
package/dist/query/service.d.ts
CHANGED
|
@@ -11,6 +11,14 @@ export interface QueryResult {
|
|
|
11
11
|
entities: Array<Record<string, unknown>>;
|
|
12
12
|
totalCount: number;
|
|
13
13
|
}
|
|
14
|
+
interface QueryCodecDeps {
|
|
15
|
+
escapeAtom: (value: string) => string;
|
|
16
|
+
parseListOfLists: (value: string) => string[][];
|
|
17
|
+
parseEntityFromList: (value: string[]) => Record<string, unknown>;
|
|
18
|
+
parseEntityFromBinding: (value: string) => Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export declare function _setQueryCodecDepsForTests(deps: QueryCodecDeps): void;
|
|
21
|
+
export declare function _resetQueryCodecDepsForTests(): void;
|
|
14
22
|
export declare const VALID_ENTITY_TYPES: string[];
|
|
15
23
|
/**
|
|
16
24
|
* Build a Prolog query goal from filters.
|
|
@@ -32,4 +40,5 @@ export declare function getInvalidTypeError(type: string): string;
|
|
|
32
40
|
* Build human-readable summary text for query results.
|
|
33
41
|
*/
|
|
34
42
|
export declare function buildQuerySummaryText(result: QueryResult, filters: QueryFilters): string;
|
|
43
|
+
export {};
|
|
35
44
|
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1 +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,
|
|
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,UAAU,cAAc;IACtB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,EAAE,CAAC;IAChD,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClE,sBAAsB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpE;AAWD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAGrE;AAED,wBAAgB,4BAA4B,IAAI,IAAI,CAGnD;AAED,eAAO,MAAM,kBAAkB,UAS9B,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAsClE;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,WAAW,CAAC,CAwCtB;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"}
|
package/dist/query/service.js
CHANGED
|
@@ -8,6 +8,21 @@
|
|
|
8
8
|
* (at your option) any later version.
|
|
9
9
|
*/
|
|
10
10
|
import { escapeAtom, parseEntityFromBinding, parseEntityFromList, parseListOfLists, } from "../prolog/codec.js";
|
|
11
|
+
const defaultCodecDeps = {
|
|
12
|
+
escapeAtom,
|
|
13
|
+
parseListOfLists,
|
|
14
|
+
parseEntityFromList,
|
|
15
|
+
parseEntityFromBinding,
|
|
16
|
+
};
|
|
17
|
+
let codecDeps = defaultCodecDeps;
|
|
18
|
+
export function _setQueryCodecDepsForTests(deps) {
|
|
19
|
+
// implements REQ-003
|
|
20
|
+
codecDeps = deps;
|
|
21
|
+
}
|
|
22
|
+
export function _resetQueryCodecDepsForTests() {
|
|
23
|
+
// implements REQ-003
|
|
24
|
+
codecDeps = defaultCodecDeps;
|
|
25
|
+
}
|
|
11
26
|
export const VALID_ENTITY_TYPES = [
|
|
12
27
|
"req",
|
|
13
28
|
"scenario",
|
|
@@ -22,33 +37,34 @@ export const VALID_ENTITY_TYPES = [
|
|
|
22
37
|
* Build a Prolog query goal from filters.
|
|
23
38
|
*/
|
|
24
39
|
export function buildEntityQueryGoal(filters) {
|
|
40
|
+
// implements REQ-003
|
|
25
41
|
const { type, id, sourceFile, tags } = filters;
|
|
26
42
|
if (sourceFile) {
|
|
27
|
-
const safeSource = escapeAtom(sourceFile);
|
|
43
|
+
const safeSource = codecDeps.escapeAtom(sourceFile);
|
|
28
44
|
if (type) {
|
|
29
|
-
const safeType = escapeAtom(type);
|
|
45
|
+
const safeType = codecDeps.escapeAtom(type);
|
|
30
46
|
return `findall([Id,'${safeType}',Props], (kb_entities_by_source('${safeSource}', SourceIds), member(Id, SourceIds), kb_entity(Id, '${safeType}', Props)), Results)`;
|
|
31
47
|
}
|
|
32
48
|
return `findall([Id,Type,Props], (kb_entities_by_source('${safeSource}', SourceIds), member(Id, SourceIds), kb_entity(Id, Type, Props)), Results)`;
|
|
33
49
|
}
|
|
34
50
|
if (id && type) {
|
|
35
|
-
const safeId = escapeAtom(id);
|
|
36
|
-
const safeType = escapeAtom(type);
|
|
51
|
+
const safeId = codecDeps.escapeAtom(id);
|
|
52
|
+
const safeType = codecDeps.escapeAtom(type);
|
|
37
53
|
return `findall(['${safeId}','${safeType}',Props], kb_entity('${safeId}', '${safeType}', Props), Results)`;
|
|
38
54
|
}
|
|
39
55
|
if (id) {
|
|
40
|
-
const safeId = escapeAtom(id);
|
|
56
|
+
const safeId = codecDeps.escapeAtom(id);
|
|
41
57
|
return `findall(['${safeId}',Type,Props], kb_entity('${safeId}', Type, Props), Results)`;
|
|
42
58
|
}
|
|
43
59
|
if (tags && tags.length > 0) {
|
|
44
60
|
if (type) {
|
|
45
|
-
const safeType = escapeAtom(type);
|
|
61
|
+
const safeType = codecDeps.escapeAtom(type);
|
|
46
62
|
return `findall([Id,'${safeType}',Props], kb_entity(Id, '${safeType}', Props), Results)`;
|
|
47
63
|
}
|
|
48
64
|
return "findall([Id,Type,Props], kb_entity(Id, Type, Props), Results)";
|
|
49
65
|
}
|
|
50
66
|
if (type) {
|
|
51
|
-
const safeType = escapeAtom(type);
|
|
67
|
+
const safeType = codecDeps.escapeAtom(type);
|
|
52
68
|
return `findall([Id,'${safeType}',Props], kb_entity(Id, '${safeType}', Props), Results)`;
|
|
53
69
|
}
|
|
54
70
|
return "findall([Id,Type,Props], kb_entity(Id, Type, Props), Results)";
|
|
@@ -57,20 +73,21 @@ export function buildEntityQueryGoal(filters) {
|
|
|
57
73
|
* Execute a filtered entity query against the KB.
|
|
58
74
|
*/
|
|
59
75
|
export async function queryEntities(prolog, filters) {
|
|
76
|
+
// implements REQ-003
|
|
60
77
|
const { tags, limit = 100, offset = 0 } = filters;
|
|
61
78
|
const goal = buildEntityQueryGoal(filters);
|
|
62
79
|
const queryResult = await prolog.query(goal);
|
|
63
80
|
let entities = [];
|
|
64
81
|
if (queryResult.success) {
|
|
65
82
|
if (queryResult.bindings.Results) {
|
|
66
|
-
const entitiesData = parseListOfLists(queryResult.bindings.Results);
|
|
83
|
+
const entitiesData = codecDeps.parseListOfLists(queryResult.bindings.Results);
|
|
67
84
|
for (const data of entitiesData) {
|
|
68
|
-
const entity = parseEntityFromList(data);
|
|
85
|
+
const entity = codecDeps.parseEntityFromList(data);
|
|
69
86
|
entities.push(entity);
|
|
70
87
|
}
|
|
71
88
|
}
|
|
72
89
|
else if (queryResult.bindings.Result) {
|
|
73
|
-
const entity = parseEntityFromBinding(queryResult.bindings.Result);
|
|
90
|
+
const entity = codecDeps.parseEntityFromBinding(queryResult.bindings.Result);
|
|
74
91
|
entities = [entity];
|
|
75
92
|
}
|
|
76
93
|
}
|
|
@@ -38,6 +38,15 @@
|
|
|
38
38
|
"severity": { "type": "string" },
|
|
39
39
|
"links": { "type": "array", "items": { "type": "string" } },
|
|
40
40
|
"text_ref": { "type": "string" },
|
|
41
|
+
"sourceFile": { "type": "string" },
|
|
42
|
+
"verification_scope": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"enum": ["unit", "integration", "end_to_end"]
|
|
45
|
+
},
|
|
46
|
+
"verification_perspective": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"enum": ["internal", "consumer"]
|
|
49
|
+
},
|
|
41
50
|
"type": {
|
|
42
51
|
"type": "string",
|
|
43
52
|
"enum": [
|
|
@@ -87,6 +96,20 @@
|
|
|
87
96
|
"type"
|
|
88
97
|
],
|
|
89
98
|
"allOf": [
|
|
99
|
+
{
|
|
100
|
+
"if": {
|
|
101
|
+
"properties": { "type": { "const": "test" } }
|
|
102
|
+
},
|
|
103
|
+
"then": {},
|
|
104
|
+
"else": {
|
|
105
|
+
"not": {
|
|
106
|
+
"anyOf": [
|
|
107
|
+
{ "required": ["verification_scope"] },
|
|
108
|
+
{ "required": ["verification_perspective"] }
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
90
113
|
{
|
|
91
114
|
"if": {
|
|
92
115
|
"properties": { "type": { "const": "fact" } }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-ranking.d.ts","sourceRoot":"","sources":["../src/search-ranking.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search-ranking.d.ts","sourceRoot":"","sources":["../src/search-ranking.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAGD,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACnC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,WAAW,EAAE,CAAC,CAyBxB;AA+FD,wBAAsB,gBAAgB,CAEpC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6BxB"}
|