kibi-cli 0.12.5 → 0.12.8
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/check.d.ts.map +1 -1
- package/dist/commands/check.js +14 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +18 -0
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +59 -1
- package/dist/extractors/manifest.d.ts.map +1 -1
- package/dist/extractors/manifest.js +92 -2
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +92 -0
- package/dist/extractors/relationships.d.ts.map +1 -1
- package/dist/extractors/relationships.js +2 -0
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +37 -3
- package/dist/public/skills/kibi-usage/SKILL.md +7 -0
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +3 -0
- package/dist/types/relationships.d.ts +1 -1
- package/dist/types/relationships.d.ts.map +1 -1
- package/dist/utils/config.d.ts +1 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +6 -0
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.js +1 -1
- package/package.json +2 -2
- package/schema/config.json +9 -0
- package/src/public/skills/kibi-usage/SKILL.md +7 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAiFA,OAAO,EAGL,KAAK,SAAS,EAEf,MAAM,2BAA2B,CAAC;AAEnC,YAAY,EAAE,SAAS,EAAE,CAAC;AAI1B,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAiFA,OAAO,EAGL,KAAK,SAAS,EAEf,MAAM,2BAA2B,CAAC;AAEnC,YAAY,EAAE,SAAS,EAAE,CAAC;AAI1B,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA8bD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA0W/B"}
|
package/dist/commands/check.js
CHANGED
|
@@ -98,6 +98,9 @@ function buildManifestLookup(stagedFiles) {
|
|
|
98
98
|
manifestResults.push({
|
|
99
99
|
entity: entry.entity,
|
|
100
100
|
relationships: entry.relationships,
|
|
101
|
+
...(entry.sourceFile !== undefined
|
|
102
|
+
? { sourceFile: entry.sourceFile }
|
|
103
|
+
: {}),
|
|
101
104
|
});
|
|
102
105
|
const authoredSymbolResult = {
|
|
103
106
|
entity: entry.entity,
|
|
@@ -440,8 +443,11 @@ export async function checkCommand(options) {
|
|
|
440
443
|
}
|
|
441
444
|
}
|
|
442
445
|
const markdownResults = markdownFiles.map((file) => extractFromMarkdownString(file.content ?? "", file.path));
|
|
446
|
+
const stagedSourceFilePaths = new Set(sourceFiles.map((file) => file.path));
|
|
447
|
+
const scopedManifestResults = manifestResults.filter((result) => result.sourceFile !== undefined &&
|
|
448
|
+
stagedSourceFilePaths.has(result.sourceFile));
|
|
443
449
|
const stagedEntityResults = [
|
|
444
|
-
...
|
|
450
|
+
...scopedManifestResults,
|
|
445
451
|
...markdownResults,
|
|
446
452
|
];
|
|
447
453
|
const stagedKibiEvidence = buildStagedKibiImpactEvidence({
|
|
@@ -464,6 +470,13 @@ export async function checkCommand(options) {
|
|
|
464
470
|
sourceContentByFile,
|
|
465
471
|
}));
|
|
466
472
|
if (allSymbols.length === 0 && stagedEntityResults.length === 0) {
|
|
473
|
+
if (stagedKibiDiagnostics.length > 0) {
|
|
474
|
+
console.log(formatStagedKibiDiagnostics(stagedKibiDiagnostics));
|
|
475
|
+
if (options.dryRun) {
|
|
476
|
+
return { exitCode: 0 };
|
|
477
|
+
}
|
|
478
|
+
return { exitCode: 1 };
|
|
479
|
+
}
|
|
467
480
|
console.log("No exported symbols or staged entities found in staged files.");
|
|
468
481
|
return { exitCode: 0 };
|
|
469
482
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAqCA,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAqCA,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AA8WD,wBAAsB,cAAc,CAClC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA+I/B"}
|
package/dist/commands/migrate.js
CHANGED
|
@@ -110,12 +110,20 @@ function buildMigrationAuditRecord(args) {
|
|
|
110
110
|
configPath: args.configPath,
|
|
111
111
|
fromVersion: args.fromVersion,
|
|
112
112
|
migratedAt: args.migratedAt,
|
|
113
|
+
semanticAdvisorBackfill: args.semanticAdvisorBackfill,
|
|
113
114
|
status: "applied",
|
|
114
115
|
symbolGranularityLegacyLinks: args.symbolGranularityLegacyLinks,
|
|
115
116
|
toVersion: LATEST_KB_SCHEMA_VERSION,
|
|
116
117
|
warning: args.warning,
|
|
117
118
|
};
|
|
118
119
|
}
|
|
120
|
+
function normalizeSemanticAdvisorBackfill(value) {
|
|
121
|
+
return value === "pending" ||
|
|
122
|
+
value === "completed" ||
|
|
123
|
+
value === "not_applicable"
|
|
124
|
+
? value
|
|
125
|
+
: null;
|
|
126
|
+
}
|
|
119
127
|
const TRACEABILITY_RELATIONSHIP_TYPES = new Set([
|
|
120
128
|
"implements",
|
|
121
129
|
"covered_by",
|
|
@@ -305,12 +313,17 @@ export async function migrateCommand(options = {}) {
|
|
|
305
313
|
config,
|
|
306
314
|
dryRun: options.dryRun || !options.yes,
|
|
307
315
|
});
|
|
316
|
+
const semanticAdvisorBackfill = normalizeSemanticAdvisorBackfill(config.semanticAdvisorBackfill) ??
|
|
317
|
+
"pending";
|
|
308
318
|
if (options.dryRun) {
|
|
309
319
|
console.log(`dry run: would migrate ${configPathRelative} schemaVersion from ${fromVersionLabel} to ${LATEST_KB_SCHEMA_VERSION}.`);
|
|
310
320
|
console.log(`dry run: would write migration audit metadata to ${auditPathRelative}.`);
|
|
311
321
|
if (symbolGranularityMigration.count > 0) {
|
|
312
322
|
console.log(`dry run: would mark ${symbolGranularityMigration.count} legacy coarse symbol link(s) in ${toRelativePath(cwd, symbolGranularityMigration.manifestPath ?? "symbols.yaml")}.`);
|
|
313
323
|
}
|
|
324
|
+
if (semanticAdvisorBackfill === "pending") {
|
|
325
|
+
console.log(`dry run: would mark semantic advisor backfill as pending in ${configPathRelative}.`);
|
|
326
|
+
}
|
|
314
327
|
console.log("Re-run with --yes to apply these changes.");
|
|
315
328
|
return { exitCode: 0 };
|
|
316
329
|
}
|
|
@@ -323,6 +336,7 @@ export async function migrateCommand(options = {}) {
|
|
|
323
336
|
const nextConfig = {
|
|
324
337
|
...config,
|
|
325
338
|
schemaVersion: LATEST_KB_SCHEMA_VERSION,
|
|
339
|
+
semanticAdvisorBackfill,
|
|
326
340
|
};
|
|
327
341
|
const migratedAt = new Date().toISOString();
|
|
328
342
|
writeJsonAtomically(configPath, nextConfig);
|
|
@@ -331,6 +345,7 @@ export async function migrateCommand(options = {}) {
|
|
|
331
345
|
configPath: configPathRelative,
|
|
332
346
|
fromVersion: configStatus.currentVersion,
|
|
333
347
|
migratedAt,
|
|
348
|
+
semanticAdvisorBackfill,
|
|
334
349
|
symbolGranularityLegacyLinks: symbolGranularityMigration.count,
|
|
335
350
|
warning: migrationWarning,
|
|
336
351
|
}));
|
|
@@ -338,6 +353,9 @@ export async function migrateCommand(options = {}) {
|
|
|
338
353
|
if (symbolGranularityMigration.count > 0) {
|
|
339
354
|
console.log(`Marked ${symbolGranularityMigration.count} existing coarse symbol link(s) as legacy-link.`);
|
|
340
355
|
}
|
|
356
|
+
if (semanticAdvisorBackfill === "pending") {
|
|
357
|
+
console.log(`Marked semantic advisor backfill as pending in ${configPathRelative}.`);
|
|
358
|
+
}
|
|
341
359
|
console.log(`Wrote migration audit metadata to ${auditPathRelative}.`);
|
|
342
360
|
console.log("Migration complete. Future 'kibi migrate' runs will be a no-op.");
|
|
343
361
|
return { exitCode: 0 };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/persistence.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAEV,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA0ErD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/persistence.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAEV,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA0ErD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;AAmCD,wBAAsB,eAAe,CAEnC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GACrB,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAqEvD;AAGD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,kBAAkB,EAAE,qBAAqB,EAAE,GAC1C,OAAO,CAAC;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CA+K7D"}
|
|
@@ -80,6 +80,30 @@ function serializeTypedFactFields(entity) {
|
|
|
80
80
|
}
|
|
81
81
|
return fields;
|
|
82
82
|
}
|
|
83
|
+
function isQueryFailedError(error) {
|
|
84
|
+
const lowered = error.toLowerCase();
|
|
85
|
+
// Only match session-corruption errors that might benefit from a Prolog process restart.
|
|
86
|
+
// Data errors (entity missing, invalid relationship) are deterministic and should NOT
|
|
87
|
+
// trigger a restart — the error would persist and the restart would lose kb_attach state.
|
|
88
|
+
return (lowered.includes("query failed") ||
|
|
89
|
+
lowered.includes("query returned false") ||
|
|
90
|
+
lowered.includes("predicate or file not found"));
|
|
91
|
+
}
|
|
92
|
+
async function tryResetPrologProcess(prolog) {
|
|
93
|
+
const maybe = prolog;
|
|
94
|
+
if (typeof maybe.terminate !== "function" ||
|
|
95
|
+
typeof maybe.start !== "function") {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
await maybe.terminate();
|
|
100
|
+
await maybe.start();
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
83
107
|
export async function persistEntities(
|
|
84
108
|
// implements REQ-009
|
|
85
109
|
prolog, results, entityIds) {
|
|
@@ -146,6 +170,7 @@ prolog, results, entityIds) {
|
|
|
146
170
|
}
|
|
147
171
|
return { entityCount, kbModified };
|
|
148
172
|
}
|
|
173
|
+
// implements REQ-core-persistence
|
|
149
174
|
export async function persistRelationships(prolog, results, shardRelationships) {
|
|
150
175
|
let relCount = 0;
|
|
151
176
|
let kbModified = false;
|
|
@@ -216,6 +241,7 @@ export async function persistRelationships(prolog, results, shardRelationships)
|
|
|
216
241
|
}
|
|
217
242
|
// Retry failed relationships
|
|
218
243
|
const retryCount = 3;
|
|
244
|
+
let resetAttempted = false;
|
|
219
245
|
for (let pass = 0; pass < retryCount && failedRelationships.length > 0; pass++) {
|
|
220
246
|
const remainingFailed = [];
|
|
221
247
|
for (const { rel, fromId, toId } of failedRelationships) {
|
|
@@ -242,6 +268,17 @@ export async function persistRelationships(prolog, results, shardRelationships)
|
|
|
242
268
|
}
|
|
243
269
|
failedRelationships.length = 0;
|
|
244
270
|
failedRelationships.push(...remainingFailed);
|
|
271
|
+
const allLookLikeSessionFailures = remainingFailed.length > 0 &&
|
|
272
|
+
remainingFailed.every(({ error }) => isQueryFailedError(error));
|
|
273
|
+
// If every pending relationship fails with generic query errors, attempt one
|
|
274
|
+
// best-effort Prolog restart before the next retry pass to recover from a
|
|
275
|
+
// potentially poisoned interactive session.
|
|
276
|
+
if (allLookLikeSessionFailures &&
|
|
277
|
+
!resetAttempted &&
|
|
278
|
+
pass + 1 < retryCount) {
|
|
279
|
+
resetAttempted = true;
|
|
280
|
+
await tryResetPrologProcess(prolog);
|
|
281
|
+
}
|
|
245
282
|
}
|
|
246
283
|
// Log remaining failures
|
|
247
284
|
if (failedRelationships.length > 0) {
|
|
@@ -255,7 +292,28 @@ export async function persistRelationships(prolog, results, shardRelationships)
|
|
|
255
292
|
console.warn(` Error: ${error}`);
|
|
256
293
|
}
|
|
257
294
|
}
|
|
258
|
-
|
|
295
|
+
const missingEntities = failedRelationships.filter(({ error }) => error.toLowerCase().includes("entity does not exist"));
|
|
296
|
+
const invalidRels = failedRelationships.filter(({ error }) => error.includes("Invalid relationship"));
|
|
297
|
+
if (missingEntities.length > 0) {
|
|
298
|
+
// Collect unique missing entity IDs from error messages
|
|
299
|
+
const missingIds = new Set();
|
|
300
|
+
for (const { error } of missingEntities) {
|
|
301
|
+
const match = error.match(/does not exist: (.+)$/);
|
|
302
|
+
const missingId = match?.[1];
|
|
303
|
+
if (missingId !== undefined) {
|
|
304
|
+
missingIds.add(missingId.trim());
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
const idList = [...missingIds].sort().join(", ");
|
|
308
|
+
console.warn(`\nTip: ${missingEntities.length} relationship(s) reference ${missingIds.size} missing entity/ies: ${idList}.`);
|
|
309
|
+
console.warn(" Create the missing docs (e.g., docs/requirements/REQ-*.md) or remove stale relationships.");
|
|
310
|
+
}
|
|
311
|
+
else if (invalidRels.length > 0) {
|
|
312
|
+
console.warn("\nTip: Check that relationship types and directions match the allowed schema (e.g., implements symbol→req, verified_by req→test).");
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
console.warn("\nTip: Ensure target entities exist before creating relationships.");
|
|
316
|
+
}
|
|
259
317
|
}
|
|
260
318
|
return { relationshipCount: relCount, kbModified };
|
|
261
319
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/extractors/manifest.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/extractors/manifest.ts"],"names":[],"mappings":"AA6BA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA6JD,qBAAa,aAAc,SAAQ,KAAK;IAG7B,QAAQ,EAAE,MAAM;gBADvB,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM;CAK1B;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAqID,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,gBAAgB,EAAE,CAmBpB;AAED,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,oBAAoB,EAAE,CAmBxB;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAKxE;AAsCD,wBAAgB,iCAAiC,CAC/C,YAAY,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,GACvB,oBAAoB,EAAE,CAWxB"}
|
|
@@ -21,6 +21,92 @@ import * as path from "node:path";
|
|
|
21
21
|
import { load as parseYAML } from "js-yaml";
|
|
22
22
|
import { DEFAULT_COORDINATES_PATH } from "../utils/manifest-paths.js";
|
|
23
23
|
import { mergeCoordinatesWithManifest, readCoordinateArtifact, } from "./symbol-coordinates.js";
|
|
24
|
+
const VALID_RELATIONSHIP_TYPES = new Set([
|
|
25
|
+
"depends_on",
|
|
26
|
+
"executable_for",
|
|
27
|
+
"specified_by",
|
|
28
|
+
"verified_by",
|
|
29
|
+
"validates",
|
|
30
|
+
"implements",
|
|
31
|
+
"covered_by",
|
|
32
|
+
"constrained_by",
|
|
33
|
+
"constrains",
|
|
34
|
+
"requires_property",
|
|
35
|
+
"requires_predicate",
|
|
36
|
+
"guards",
|
|
37
|
+
"publishes",
|
|
38
|
+
"consumes",
|
|
39
|
+
"supersedes",
|
|
40
|
+
"relates_to",
|
|
41
|
+
]);
|
|
42
|
+
const VALID_RELATIONSHIP_DIRECTIONS = [
|
|
43
|
+
{ type: "depends_on", from: "req", to: "req" },
|
|
44
|
+
{ type: "executable_for", from: "symbol", to: "test" },
|
|
45
|
+
{ type: "specified_by", from: "req", to: "scenario" },
|
|
46
|
+
{ type: "verified_by", from: "req", to: "test" },
|
|
47
|
+
{ type: "verified_by", from: "scenario", to: "test" },
|
|
48
|
+
{ type: "validates", from: "test", to: "req" },
|
|
49
|
+
{ type: "validates", from: "test", to: "scenario" },
|
|
50
|
+
{ type: "implements", from: "symbol", to: "req" },
|
|
51
|
+
{ type: "covered_by", from: "symbol", to: "test" },
|
|
52
|
+
{ type: "constrained_by", from: "symbol", to: "adr" },
|
|
53
|
+
{ type: "constrains", from: "req", to: "fact" },
|
|
54
|
+
{ type: "requires_property", from: "req", to: "fact" },
|
|
55
|
+
{ type: "requires_predicate", from: "req", to: "fact" },
|
|
56
|
+
{ type: "guards", from: "flag", to: "symbol" },
|
|
57
|
+
{ type: "guards", from: "flag", to: "event" },
|
|
58
|
+
{ type: "guards", from: "flag", to: "req" },
|
|
59
|
+
{ type: "publishes", from: "symbol", to: "event" },
|
|
60
|
+
{ type: "consumes", from: "symbol", to: "event" },
|
|
61
|
+
{ type: "supersedes", from: "adr", to: "adr" },
|
|
62
|
+
{ type: "supersedes", from: "req", to: "req" },
|
|
63
|
+
];
|
|
64
|
+
const RELATIONSHIP_TYPE_DISPLAY_LIST = Array.from(VALID_RELATIONSHIP_TYPES)
|
|
65
|
+
.sort()
|
|
66
|
+
.join(", ");
|
|
67
|
+
function inferEntityTypeFromId(id) {
|
|
68
|
+
const upper = id.toUpperCase();
|
|
69
|
+
if (upper.startsWith("REQ-"))
|
|
70
|
+
return "req";
|
|
71
|
+
if (upper.startsWith("SCEN-"))
|
|
72
|
+
return "scenario";
|
|
73
|
+
if (upper.startsWith("TEST-"))
|
|
74
|
+
return "test";
|
|
75
|
+
if (upper.startsWith("ADR-"))
|
|
76
|
+
return "adr";
|
|
77
|
+
if (upper.startsWith("FLAG-"))
|
|
78
|
+
return "flag";
|
|
79
|
+
if (upper.startsWith("EVENT-"))
|
|
80
|
+
return "event";
|
|
81
|
+
if (upper.startsWith("SYM-"))
|
|
82
|
+
return "symbol";
|
|
83
|
+
if (upper.startsWith("FACT-"))
|
|
84
|
+
return "fact";
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
function validateRelationshipType(type, filePath) {
|
|
88
|
+
if (!VALID_RELATIONSHIP_TYPES.has(type)) {
|
|
89
|
+
throw new ManifestError(`Invalid relationship type \"${type}\". Allowed types: ${RELATIONSHIP_TYPE_DISPLAY_LIST}`, filePath);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function validateRelationshipDirection(type, from, to, filePath) {
|
|
93
|
+
if (type === "relates_to") {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const fromType = inferEntityTypeFromId(from);
|
|
97
|
+
const toType = inferEntityTypeFromId(to);
|
|
98
|
+
// If we cannot infer one side from ID prefix, defer to downstream existence/type checks.
|
|
99
|
+
if (!fromType || !toType) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const valid = VALID_RELATIONSHIP_DIRECTIONS.some((rule) => rule.type === type && rule.from === fromType && rule.to === toType);
|
|
103
|
+
if (!valid) {
|
|
104
|
+
const allowed = VALID_RELATIONSHIP_DIRECTIONS.filter((rule) => rule.type === type)
|
|
105
|
+
.map((rule) => `${rule.from} -> ${rule.to}`)
|
|
106
|
+
.join(", ");
|
|
107
|
+
throw new ManifestError(`Invalid relationship direction for \"${type}\": ${fromType} -> ${toType}. Allowed: ${allowed}`, filePath);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
24
110
|
export class ManifestError extends Error {
|
|
25
111
|
filePath;
|
|
26
112
|
constructor(message, filePath) {
|
|
@@ -35,7 +121,7 @@ function getManifestSymbols(manifest, filePath) {
|
|
|
35
121
|
}
|
|
36
122
|
return manifest.symbols;
|
|
37
123
|
}
|
|
38
|
-
function extractRelationships(id, symbol) {
|
|
124
|
+
function extractRelationships(id, symbol, filePath) {
|
|
39
125
|
const relationships = [];
|
|
40
126
|
if (Array.isArray(symbol.links)) {
|
|
41
127
|
for (const link of symbol.links) {
|
|
@@ -50,6 +136,8 @@ function extractRelationships(id, symbol) {
|
|
|
50
136
|
const typedLink = link;
|
|
51
137
|
if (typeof typedLink.type === "string" &&
|
|
52
138
|
typeof typedLink.target === "string") {
|
|
139
|
+
validateRelationshipType(typedLink.type, filePath);
|
|
140
|
+
validateRelationshipDirection(typedLink.type, id, typedLink.target, filePath);
|
|
53
141
|
relationships.push({
|
|
54
142
|
type: typedLink.type,
|
|
55
143
|
from: id,
|
|
@@ -64,6 +152,8 @@ function extractRelationships(id, symbol) {
|
|
|
64
152
|
if (rel &&
|
|
65
153
|
typeof rel.type === "string" &&
|
|
66
154
|
typeof rel.target === "string") {
|
|
155
|
+
validateRelationshipType(rel.type, filePath);
|
|
156
|
+
validateRelationshipDirection(rel.type, id, rel.target, filePath);
|
|
67
157
|
relationships.push({
|
|
68
158
|
type: rel.type,
|
|
69
159
|
from: id,
|
|
@@ -103,7 +193,7 @@ function extractFromManifestSymbolRecords(manifestSymbols, filePath) {
|
|
|
103
193
|
const sourceFile = symbol.sourceFile ?? symbol.source;
|
|
104
194
|
return {
|
|
105
195
|
entity,
|
|
106
|
-
relationships: extractRelationships(id, symbol),
|
|
196
|
+
relationships: extractRelationships(id, symbol, filePath),
|
|
107
197
|
...(sourceFile !== undefined ? { sourceFile } : {}),
|
|
108
198
|
};
|
|
109
199
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/extractors/markdown.ts"],"names":[],"mappings":"AAwDA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,YAAY,CAAC;IAC3D,wBAAwB,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IAEnD,SAAS,CAAC,EAAE,SAAS,GAAG,gBAAgB,GAAG,aAAa,GAAG,MAAM,CAAC;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,CAAC;IACtD,UAAU,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAChC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/extractors/markdown.ts"],"names":[],"mappings":"AAwDA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,YAAY,CAAC;IAC3D,wBAAwB,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IAEnD,SAAS,CAAC,EAAE,SAAS,GAAG,gBAAgB,GAAG,aAAa,GAAG,MAAM,CAAC;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,CAAC;IACtD,UAAU,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAChC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA2LD,qBAAa,gBAAiB,SAAQ,KAAK;IAOhC,QAAQ,EAAE,MAAM;IANlB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;gBAG5B,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE;QACR,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAYM,QAAQ;CAUlB;AA8DD,wBAAgB,sBAAsB,CAEpC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAkDV;AA0RD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,gBAAgB,CAElB;AAGD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAatE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjE;AASD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAQpE"}
|
|
@@ -58,6 +58,96 @@ const DEFAULT_STATUS_BY_TYPE = {
|
|
|
58
58
|
symbol: "active",
|
|
59
59
|
fact: "active",
|
|
60
60
|
};
|
|
61
|
+
const VALID_RELATIONSHIP_TYPES = new Set([
|
|
62
|
+
"depends_on",
|
|
63
|
+
"executable_for",
|
|
64
|
+
"specified_by",
|
|
65
|
+
"verified_by",
|
|
66
|
+
"validates",
|
|
67
|
+
"implements",
|
|
68
|
+
"covered_by",
|
|
69
|
+
"constrained_by",
|
|
70
|
+
"constrains",
|
|
71
|
+
"requires_property",
|
|
72
|
+
"requires_predicate",
|
|
73
|
+
"guards",
|
|
74
|
+
"publishes",
|
|
75
|
+
"consumes",
|
|
76
|
+
"supersedes",
|
|
77
|
+
"relates_to",
|
|
78
|
+
]);
|
|
79
|
+
const VALID_RELATIONSHIP_DIRECTIONS = [
|
|
80
|
+
{ type: "depends_on", from: "req", to: "req" },
|
|
81
|
+
{ type: "executable_for", from: "symbol", to: "test" },
|
|
82
|
+
{ type: "specified_by", from: "req", to: "scenario" },
|
|
83
|
+
{ type: "verified_by", from: "req", to: "test" },
|
|
84
|
+
{ type: "verified_by", from: "scenario", to: "test" },
|
|
85
|
+
{ type: "validates", from: "test", to: "req" },
|
|
86
|
+
{ type: "validates", from: "test", to: "scenario" },
|
|
87
|
+
{ type: "implements", from: "symbol", to: "req" },
|
|
88
|
+
{ type: "covered_by", from: "symbol", to: "test" },
|
|
89
|
+
{ type: "constrained_by", from: "symbol", to: "adr" },
|
|
90
|
+
{ type: "constrains", from: "req", to: "fact" },
|
|
91
|
+
{ type: "requires_property", from: "req", to: "fact" },
|
|
92
|
+
{ type: "requires_predicate", from: "req", to: "fact" },
|
|
93
|
+
{ type: "guards", from: "flag", to: "symbol" },
|
|
94
|
+
{ type: "guards", from: "flag", to: "event" },
|
|
95
|
+
{ type: "guards", from: "flag", to: "req" },
|
|
96
|
+
{ type: "publishes", from: "symbol", to: "event" },
|
|
97
|
+
{ type: "consumes", from: "symbol", to: "event" },
|
|
98
|
+
{ type: "supersedes", from: "adr", to: "adr" },
|
|
99
|
+
{ type: "supersedes", from: "req", to: "req" },
|
|
100
|
+
];
|
|
101
|
+
const RELATIONSHIP_TYPE_DISPLAY_LIST = Array.from(VALID_RELATIONSHIP_TYPES)
|
|
102
|
+
.sort()
|
|
103
|
+
.join(", ");
|
|
104
|
+
function inferEntityTypeFromId(id) {
|
|
105
|
+
const upper = id.toUpperCase();
|
|
106
|
+
if (upper.startsWith("REQ-"))
|
|
107
|
+
return "req";
|
|
108
|
+
if (upper.startsWith("SCEN-"))
|
|
109
|
+
return "scenario";
|
|
110
|
+
if (upper.startsWith("TEST-"))
|
|
111
|
+
return "test";
|
|
112
|
+
if (upper.startsWith("ADR-"))
|
|
113
|
+
return "adr";
|
|
114
|
+
if (upper.startsWith("FLAG-"))
|
|
115
|
+
return "flag";
|
|
116
|
+
if (upper.startsWith("EVENT-"))
|
|
117
|
+
return "event";
|
|
118
|
+
if (upper.startsWith("SYM-"))
|
|
119
|
+
return "symbol";
|
|
120
|
+
if (upper.startsWith("FACT-"))
|
|
121
|
+
return "fact";
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function validateRelationshipType(type, filePath) {
|
|
125
|
+
if (!VALID_RELATIONSHIP_TYPES.has(type)) {
|
|
126
|
+
throw new FrontmatterError(`Invalid relationship type \"${type}\". Allowed types: ${RELATIONSHIP_TYPE_DISPLAY_LIST}`, filePath, {
|
|
127
|
+
classification: "Invalid Relationship Type",
|
|
128
|
+
hint: "Use one of the supported relationship types from relationship.schema.json.",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function validateRelationshipDirection(type, fromType, toId, filePath) {
|
|
133
|
+
if (type === "relates_to") {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const toType = inferEntityTypeFromId(toId);
|
|
137
|
+
if (!toType) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const valid = VALID_RELATIONSHIP_DIRECTIONS.some((rule) => rule.type === type && rule.from === fromType && rule.to === toType);
|
|
141
|
+
if (!valid) {
|
|
142
|
+
const allowed = VALID_RELATIONSHIP_DIRECTIONS.filter((rule) => rule.type === type)
|
|
143
|
+
.map((rule) => `${rule.from} -> ${rule.to}`)
|
|
144
|
+
.join(", ");
|
|
145
|
+
throw new FrontmatterError(`Invalid relationship direction for \"${type}\": ${fromType} -> ${toType}. Allowed: ${allowed}`, filePath, {
|
|
146
|
+
classification: "Invalid Relationship Direction",
|
|
147
|
+
hint: "Reverse the link direction or use the correct relationship type for these entity kinds.",
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
61
151
|
export class FrontmatterError extends Error {
|
|
62
152
|
filePath;
|
|
63
153
|
classification;
|
|
@@ -224,6 +314,8 @@ function extractFromMarkdownContent(content, filePath) {
|
|
|
224
314
|
typeof link === "object" &&
|
|
225
315
|
typeof link.type === "string" &&
|
|
226
316
|
typeof link.target === "string") {
|
|
317
|
+
validateRelationshipType(link.type, filePath);
|
|
318
|
+
validateRelationshipDirection(link.type, type, link.target, filePath);
|
|
227
319
|
relationships.push({
|
|
228
320
|
type: link.type,
|
|
229
321
|
from: id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../src/extractors/relationships.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,qBAAqB,EAAE,CAAC;CACxC;
|
|
1
|
+
{"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../src/extractors/relationships.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,qBAAqB,EAAE,CAAC;CACxC;AAwBD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,gBAAgB,EAAE,MAAM,GACvB,qBAAqB,EAAE,CAyCzB;AAmDD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,qBAAqB,EAAE,GAC/B,qBAAqB,EAAE,CAEzB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,qBAAqB,EAAE,EACtC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B,KAAK,CAAC;IACP,YAAY,EAAE,qBAAqB,CAAC;IACpC,KAAK,EAAE,cAAc,GAAG,YAAY,CAAC;CACtC,CAAC,CAgBD"}
|
|
@@ -23,6 +23,7 @@ import { readShard } from "../relationships/shards.js";
|
|
|
23
23
|
*/
|
|
24
24
|
const VALID_RELATIONSHIP_TYPES = new Set([
|
|
25
25
|
"depends_on",
|
|
26
|
+
"executable_for",
|
|
26
27
|
"specified_by",
|
|
27
28
|
"verified_by",
|
|
28
29
|
"validates",
|
|
@@ -31,6 +32,7 @@ const VALID_RELATIONSHIP_TYPES = new Set([
|
|
|
31
32
|
"constrained_by",
|
|
32
33
|
"constrains",
|
|
33
34
|
"requires_property",
|
|
35
|
+
"requires_predicate",
|
|
34
36
|
"guards",
|
|
35
37
|
"publishes",
|
|
36
38
|
"consumes",
|
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,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,kBAAkB,CAA8B;IACxD,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;YAuCd,YAAY;
|
|
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,kBAAkB,CAA8B;IACxD,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;YAuCd,YAAY;IA2CpB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAyK1D,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,iBAAiB;IAMzB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,cAAc;IA6DtB,SAAS,IAAI,OAAO;IAMpB,MAAM,IAAI,MAAM;IAIV,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAwCjC"}
|
package/dist/prolog.js
CHANGED
|
@@ -133,6 +133,7 @@ export class PrologProcess {
|
|
|
133
133
|
this.outputBuffer = "";
|
|
134
134
|
this.errorBuffer = "";
|
|
135
135
|
}
|
|
136
|
+
// implements REQ-core-prolog-process-management
|
|
136
137
|
async query(goal) {
|
|
137
138
|
const isSingleGoal = typeof goal === "string";
|
|
138
139
|
const goalKey = isSingleGoal ? goal : null;
|
|
@@ -165,8 +166,8 @@ export class PrologProcess {
|
|
|
165
166
|
const debug = isPrologDebugEnabled();
|
|
166
167
|
const normalizedGoal = this.normalizeGoal(goal);
|
|
167
168
|
const wrappedGoal = /^once\s*\(/.test(normalizedGoal)
|
|
168
|
-
? normalizedGoal
|
|
169
|
-
: `once((${normalizedGoal}))`;
|
|
169
|
+
? `catch(${normalizedGoal}, _E, (print_message(error, _E), fail))`
|
|
170
|
+
: `catch(once((${normalizedGoal})), _E, (print_message(error, _E), fail))`;
|
|
170
171
|
const start = Date.now();
|
|
171
172
|
if (debug) {
|
|
172
173
|
console.error(`[prolog debug] start query: ${normalizedGoal}`);
|
|
@@ -240,10 +241,15 @@ export class PrologProcess {
|
|
|
240
241
|
if (debug) {
|
|
241
242
|
console.error(`[prolog debug] query failed (false): ${normalizedGoal}`);
|
|
242
243
|
}
|
|
244
|
+
// Check errorBuffer first — Prolog catch/3 writes ERROR to stderr
|
|
245
|
+
// then fail to stdout. If stderr has the real error, surface it.
|
|
246
|
+
const errorMessage = this.errorBuffer.length > 0 && this.errorBuffer.includes("ERROR")
|
|
247
|
+
? this.translateError(this.errorBuffer)
|
|
248
|
+
: "Query failed";
|
|
243
249
|
resolve({
|
|
244
250
|
success: false,
|
|
245
251
|
bindings: {},
|
|
246
|
-
error:
|
|
252
|
+
error: errorMessage,
|
|
247
253
|
});
|
|
248
254
|
return;
|
|
249
255
|
}
|
|
@@ -435,7 +441,35 @@ export class PrologProcess {
|
|
|
435
441
|
}
|
|
436
442
|
return bindings;
|
|
437
443
|
}
|
|
444
|
+
// implements REQ-core-prolog-process-management
|
|
438
445
|
translateError(errorText) {
|
|
446
|
+
// SWI-Prolog print_message/2 formats errors as human-readable messages,
|
|
447
|
+
// not raw Prolog terms. Match the actual output format.
|
|
448
|
+
if (errorText.includes("does not exist") &&
|
|
449
|
+
/entity [`'"].+?[`'"]/.test(errorText)) {
|
|
450
|
+
// SWI-Prolog doubles single quotes in formatted messages: ''REQ-TEST''
|
|
451
|
+
const entityIdMatch = errorText.match(/entity [`'"]+(.+?)[`'"]+ does not exist/);
|
|
452
|
+
const matchedEntityId = entityIdMatch?.[1];
|
|
453
|
+
const entityId = matchedEntityId !== undefined
|
|
454
|
+
? matchedEntityId.replace(/^`?'+|'+`?$/g, "")
|
|
455
|
+
: "unknown";
|
|
456
|
+
if (errorText.includes("Target entity does not exist")) {
|
|
457
|
+
return `Target entity does not exist: ${entityId}`;
|
|
458
|
+
}
|
|
459
|
+
if (errorText.includes("Source entity does not exist")) {
|
|
460
|
+
return `Source entity does not exist: ${entityId}`;
|
|
461
|
+
}
|
|
462
|
+
return `Entity does not exist: ${entityId}`;
|
|
463
|
+
}
|
|
464
|
+
if (errorText.includes("Type error: `relationship' expected")) {
|
|
465
|
+
const relMatch = errorText.match(/\(Invalid relationship: ([^)]+)\)/);
|
|
466
|
+
const invalidRelationship = relMatch?.[1];
|
|
467
|
+
if (invalidRelationship !== undefined) {
|
|
468
|
+
return `Invalid relationship: ${invalidRelationship.trim()}`;
|
|
469
|
+
}
|
|
470
|
+
return "Invalid relationship type or direction";
|
|
471
|
+
}
|
|
472
|
+
// Fallback: check for raw Prolog error terms (used by other tools)
|
|
439
473
|
if (errorText.includes("existence_error") ||
|
|
440
474
|
errorText.includes("Unknown procedure")) {
|
|
441
475
|
return "Predicate or file not found";
|
|
@@ -170,6 +170,12 @@ Anti-example: do not create a `flag` named `BUG-123` to track a defect. Create a
|
|
|
170
170
|
|
|
171
171
|
Always confirm or create endpoint entities before linking them. Query target IDs with `kb_query` first. If an endpoint does not exist, create it with `kb_upsert` before creating the relationship. Creating relationships to non-existent entities produces dangling references that `kb_check` will flag.
|
|
172
172
|
|
|
173
|
+
For `kb_upsert`, keep relationship rows anchored to the entity you are upserting: each row's `from` must equal the upserted entity ID. If you need a `SYM -> REQ` link, upsert the symbol endpoint first, then link that symbol to the requirement.
|
|
174
|
+
|
|
175
|
+
Keep symbol payloads minimal: include only the fields needed to identify the symbol, its status, and its source traceability. Put extra prose, examples, or audit notes in docs or evidence files instead of custom `kb_upsert.properties`; strict `kb_upsert.properties` rejects unknown fields.
|
|
176
|
+
|
|
177
|
+
When a generic `Query failed` appears, do not keep retrying the same payload. First call `kb_validate_upsert`, query or create the missing endpoints, reduce the payload to the minimum required fields, and retry once. If it still fails, report the blocker instead of looping.
|
|
178
|
+
|
|
173
179
|
## Sequential Upserts
|
|
174
180
|
|
|
175
181
|
Never fire `kb_upsert` calls in parallel. Execute them sequentially to avoid lock contention and ensure deterministic ordering. This is especially important when creating chains of related entities.
|
|
@@ -200,6 +206,7 @@ Call `kb_status` when you suspect the branch KB is stale or when switching conte
|
|
|
200
206
|
| Missing `kb_check` | Undetected dangling refs and violations | Run targeted checks during work, full check at completion |
|
|
201
207
|
| Tags as multi-ID lookup | Tags are metadata, not identifiers | Use `kb_query` with explicit `id` values |
|
|
202
208
|
| `relates_to` for strict modeling | Loses contradiction safety | Use `constrains` and `requires_property` instead |
|
|
209
|
+
| `status: implemented` on requirements | Not a valid lifecycle status | Use a valid status such as `closed`, add an `implemented` tag, and link evidence instead |
|
|
203
210
|
|
|
204
211
|
Before/after for reversed direction:
|
|
205
212
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temp-kb.d.ts","sourceRoot":"","sources":["../../src/traceability/temp-kb.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAGV,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;CACvB;AAMD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CASvC;AAOD;;;GAGG;AACH,wBAAgB,iBAAiB,CAE/B,OAAO,EAAE,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,KAAK,aAAa,GACpD,IAAI,CAEN;AA4ID,iBAAe,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB/D;AAED,OAAO,EAAE,cAAc,EAAE,CAAC;AAG1B,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"temp-kb.d.ts","sourceRoot":"","sources":["../../src/traceability/temp-kb.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAGV,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;CACvB;AAMD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CASvC;AAOD;;;GAGG;AACH,wBAAgB,iBAAiB,CAE/B,OAAO,EAAE,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,KAAK,aAAa,GACpD,IAAI,CAEN;AA4ID,iBAAe,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB/D;AAED,OAAO,EAAE,cAAc,EAAE,CAAC;AAG1B,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA6C7E;AAGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,MAAM,CAkBrE;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BlE"}
|
|
@@ -170,6 +170,9 @@ export { consultOverlay };
|
|
|
170
170
|
// implements REQ-014
|
|
171
171
|
export async function projectStagedEntities(prolog, results) {
|
|
172
172
|
for (const { entity } of results) {
|
|
173
|
+
// Retract stale relationships before re-asserting entity
|
|
174
|
+
// (kb_assert_entity_no_audit preserves relationships on upsert)
|
|
175
|
+
await prolog.query(`kb_retract_entity_relationships('${entity.id}')`);
|
|
173
176
|
const assertEntityResult = await prolog.query(buildEntityAssertionGoal(entity));
|
|
174
177
|
if (!assertEntityResult.success) {
|
|
175
178
|
throw new Error(`Failed to assert staged entity ${entity.id}: ${assertEntityResult.error || "unknown error"}`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface BaseRelationship {
|
|
2
|
-
type: "depends_on" | "specified_by" | "verified_by" | "implements" | "covered_by" | "constrained_by" | "constrains" | "requires_property" | "requires_predicate" | "guards" | "publishes" | "consumes" | "supersedes" | "relates_to";
|
|
2
|
+
type: "depends_on" | "specified_by" | "verified_by" | "validates" | "implements" | "covered_by" | "executable_for" | "constrained_by" | "constrains" | "requires_property" | "requires_predicate" | "guards" | "publishes" | "consumes" | "supersedes" | "relates_to";
|
|
3
3
|
from: string;
|
|
4
4
|
to: string;
|
|
5
5
|
created_at?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../src/types/relationships.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EACA,YAAY,GACZ,cAAc,GACd,aAAa,GACb,YAAY,GACZ,YAAY,GACZ,gBAAgB,GAChB,YAAY,GACZ,mBAAmB,GACnB,oBAAoB,GACpB,QAAQ,GACR,WAAW,GACX,UAAU,GACV,YAAY,GACZ,YAAY,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAe,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../src/types/relationships.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EACA,YAAY,GACZ,cAAc,GACd,aAAa,GACb,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,gBAAgB,GAChB,gBAAgB,GAChB,YAAY,GACZ,mBAAmB,GACnB,oBAAoB,GACpB,QAAQ,GACR,WAAW,GACX,UAAU,GACV,YAAY,GACZ,YAAY,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAe,gBAAgB,CAAC"}
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export interface KbConfigPaths {
|
|
|
19
19
|
export interface KbConfig {
|
|
20
20
|
paths: KbConfigPaths;
|
|
21
21
|
schemaVersion?: number | string;
|
|
22
|
+
semanticAdvisorBackfill?: "pending" | "completed" | "not_applicable";
|
|
22
23
|
/**
|
|
23
24
|
* @deprecated defaultBranch is deprecated. Branch lifecycle now follows git naturally
|
|
24
25
|
* without requiring a configured default. This field is ignored but kept for compatibility.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,YAAY,EAEjB,KAAK,yBAAyB,EAC/B,MAAM,oBAAoB,CAAC;AAG5B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,aAAa,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,YAAY,EAAE,YAAY,EAAE,yBAAyB,EAAE,CAAC;AAExD;;GAEG;AAEH,eAAO,MAAM,cAAc,EAAE,QAAQ,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAgBxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAUhC,CAAC;AA4BF;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,YAAY,EAEjB,KAAK,yBAAyB,EAC/B,MAAM,oBAAoB,CAAC;AAG5B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,aAAa,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,uBAAuB,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,gBAAgB,CAAC;IACrE;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,YAAY,EAAE,YAAY,EAAE,yBAAyB,EAAE,CAAC;AAExD;;GAEG;AAEH,eAAO,MAAM,cAAc,EAAE,QAAQ,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAgBxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAUhC,CAAC;AA4BF;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,QAAQ,CAmChE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,QAAQ,CAmCpE"}
|
package/dist/utils/config.js
CHANGED
|
@@ -98,6 +98,9 @@ export function loadConfig(cwd = process.cwd()) {
|
|
|
98
98
|
...(userConfig.defaultBranch !== undefined
|
|
99
99
|
? { defaultBranch: userConfig.defaultBranch }
|
|
100
100
|
: {}),
|
|
101
|
+
...(userConfig.semanticAdvisorBackfill !== undefined
|
|
102
|
+
? { semanticAdvisorBackfill: userConfig.semanticAdvisorBackfill }
|
|
103
|
+
: {}),
|
|
101
104
|
checks: userConfig.checks
|
|
102
105
|
? {
|
|
103
106
|
rules: {
|
|
@@ -137,6 +140,9 @@ export function loadSyncConfig(cwd = process.cwd()) {
|
|
|
137
140
|
...(userConfig.defaultBranch !== undefined
|
|
138
141
|
? { defaultBranch: userConfig.defaultBranch }
|
|
139
142
|
: {}),
|
|
143
|
+
...(userConfig.semanticAdvisorBackfill !== undefined
|
|
144
|
+
? { semanticAdvisorBackfill: userConfig.semanticAdvisorBackfill }
|
|
145
|
+
: {}),
|
|
140
146
|
checks: userConfig.checks
|
|
141
147
|
? {
|
|
142
148
|
rules: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { KbConfig } from "./config.js";
|
|
2
|
-
export declare const LATEST_KB_SCHEMA_VERSION =
|
|
2
|
+
export declare const LATEST_KB_SCHEMA_VERSION = 3;
|
|
3
3
|
export interface SchemaVersionStatus {
|
|
4
4
|
status: "missing" | "invalid" | "older" | "current" | "newer";
|
|
5
5
|
currentVersion: number | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-cli",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Kibi CLI for knowledge base management",
|
|
6
6
|
"engines": {
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"fast-glob": "^3.2.12",
|
|
100
100
|
"gray-matter": "^4.0.3",
|
|
101
101
|
"js-yaml": "^4.1.0",
|
|
102
|
-
"kibi-core": "^0.6.
|
|
102
|
+
"kibi-core": "^0.6.2",
|
|
103
103
|
"ts-morph": "^23.0.0",
|
|
104
104
|
"ignore": "^5.3.0"
|
|
105
105
|
},
|
package/schema/config.json
CHANGED
|
@@ -61,6 +61,15 @@
|
|
|
61
61
|
"description": "[DEPRECATED] No longer used. Branch lifecycle now follows git naturally without requiring a configured default. This field is ignored but kept for backward compatibility.",
|
|
62
62
|
"deprecated": true
|
|
63
63
|
},
|
|
64
|
+
"schemaVersion": {
|
|
65
|
+
"type": ["integer", "string"],
|
|
66
|
+
"description": "Kibi KB schema version used by the migration command"
|
|
67
|
+
},
|
|
68
|
+
"semanticAdvisorBackfill": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"enum": ["pending", "completed", "not_applicable"],
|
|
71
|
+
"description": "Review state for retroactive semantic-advisor modeling of existing requirements"
|
|
72
|
+
},
|
|
64
73
|
"checks": {
|
|
65
74
|
"type": "object",
|
|
66
75
|
"description": "Configuration for KB validation rules",
|
|
@@ -170,6 +170,12 @@ Anti-example: do not create a `flag` named `BUG-123` to track a defect. Create a
|
|
|
170
170
|
|
|
171
171
|
Always confirm or create endpoint entities before linking them. Query target IDs with `kb_query` first. If an endpoint does not exist, create it with `kb_upsert` before creating the relationship. Creating relationships to non-existent entities produces dangling references that `kb_check` will flag.
|
|
172
172
|
|
|
173
|
+
For `kb_upsert`, keep relationship rows anchored to the entity you are upserting: each row's `from` must equal the upserted entity ID. If you need a `SYM -> REQ` link, upsert the symbol endpoint first, then link that symbol to the requirement.
|
|
174
|
+
|
|
175
|
+
Keep symbol payloads minimal: include only the fields needed to identify the symbol, its status, and its source traceability. Put extra prose, examples, or audit notes in docs or evidence files instead of custom `kb_upsert.properties`; strict `kb_upsert.properties` rejects unknown fields.
|
|
176
|
+
|
|
177
|
+
When a generic `Query failed` appears, do not keep retrying the same payload. First call `kb_validate_upsert`, query or create the missing endpoints, reduce the payload to the minimum required fields, and retry once. If it still fails, report the blocker instead of looping.
|
|
178
|
+
|
|
173
179
|
## Sequential Upserts
|
|
174
180
|
|
|
175
181
|
Never fire `kb_upsert` calls in parallel. Execute them sequentially to avoid lock contention and ensure deterministic ordering. This is especially important when creating chains of related entities.
|
|
@@ -200,6 +206,7 @@ Call `kb_status` when you suspect the branch KB is stale or when switching conte
|
|
|
200
206
|
| Missing `kb_check` | Undetected dangling refs and violations | Run targeted checks during work, full check at completion |
|
|
201
207
|
| Tags as multi-ID lookup | Tags are metadata, not identifiers | Use `kb_query` with explicit `id` values |
|
|
202
208
|
| `relates_to` for strict modeling | Loses contradiction safety | Use `constrains` and `requires_property` instead |
|
|
209
|
+
| `status: implemented` on requirements | Not a valid lifecycle status | Use a valid status such as `closed`, add an `implemented` tag, and link evidence instead |
|
|
203
210
|
|
|
204
211
|
Before/after for reversed direction:
|
|
205
212
|
|