kibi-cli 0.12.0 → 0.12.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AA2EA,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;AAiVD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAmU/B"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AA2EA,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;AAgcD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA0V/B"}
@@ -15,7 +15,7 @@
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
- import { existsSync } from "node:fs";
18
+ import { existsSync, readFileSync } from "node:fs";
19
19
  import * as path from "node:path";
20
20
  import { getBranchOverride, isCliTraceOrDebugEnabled } from "../env.js";
21
21
  import { extractFromManifest, extractFromManifestString, } from "../extractors/manifest.js";
@@ -43,6 +43,8 @@ function getMatchGroup(match, index = 1) {
43
43
  function buildManifestLookup(stagedFiles) {
44
44
  const manifestLookup = new Map();
45
45
  const manifestResults = [];
46
+ const authoredSymbolResults = [];
47
+ const stagedAuthoredSymbolResults = [];
46
48
  // Pre-populate lookup from working-tree manifests so that code-only changes
47
49
  // (where symbols.yaml is not staged) still resolve to the correct symbol IDs
48
50
  // and relationships already defined on disk.
@@ -54,6 +56,7 @@ function buildManifestLookup(stagedFiles) {
54
56
  try {
55
57
  const entries = extractFromManifest(absSymbolsPath);
56
58
  for (const entry of entries) {
59
+ authoredSymbolResults.push(entry);
57
60
  const sourceFile = entry.sourceFile || entry.entity.source || absSymbolsPath;
58
61
  const key = `${sourceFile}:${entry.entity.title}`;
59
62
  manifestLookup.set(key, {
@@ -95,6 +98,15 @@ function buildManifestLookup(stagedFiles) {
95
98
  entity: entry.entity,
96
99
  relationships: entry.relationships,
97
100
  });
101
+ const authoredSymbolResult = {
102
+ entity: entry.entity,
103
+ relationships: entry.relationships,
104
+ ...(entry.sourceFile !== undefined
105
+ ? { sourceFile: entry.sourceFile }
106
+ : {}),
107
+ };
108
+ authoredSymbolResults.push(authoredSymbolResult);
109
+ stagedAuthoredSymbolResults.push(authoredSymbolResult);
98
110
  const sourceFile = entry.sourceFile || entry.entity.source || manifestFile.path;
99
111
  const key = `${sourceFile}:${entry.entity.title}`;
100
112
  manifestLookup.set(key, {
@@ -114,7 +126,81 @@ function buildManifestLookup(stagedFiles) {
114
126
  // Ignore manifest parsing errors
115
127
  }
116
128
  }
117
- return { manifestLookup, manifestResults };
129
+ return {
130
+ manifestLookup,
131
+ manifestResults,
132
+ authoredSymbolResults,
133
+ stagedAuthoredSymbolResults,
134
+ };
135
+ }
136
+ const GRANULARITY_RELATIONSHIP_TYPES = new Set([
137
+ "implements",
138
+ "covered_by",
139
+ "executable_for",
140
+ ]);
141
+ const ALLOWED_GRANULARITY_REASONS = new Set([
142
+ "config-artifact",
143
+ "module-level-behavior",
144
+ "extractor-miss",
145
+ "legacy-link",
146
+ ]);
147
+ function hasTraceabilityRelationship(result) {
148
+ return result.relationships.some((relationship) => GRANULARITY_RELATIONSHIP_TYPES.has(relationship.type));
149
+ }
150
+ function hasValidGranularityReason(result) {
151
+ const reason = result.entity.granularity_reason;
152
+ return typeof reason === "string" && ALLOWED_GRANULARITY_REASONS.has(reason);
153
+ }
154
+ function createSymbolGranularityDiagnostics(options) {
155
+ const diagnostics = [];
156
+ for (const result of options.manifestResults) {
157
+ if (!result.sourceFile)
158
+ continue;
159
+ if (!hasTraceabilityRelationship(result))
160
+ continue;
161
+ if (hasValidGranularityReason(result))
162
+ continue;
163
+ const granularSymbols = getGranularSymbolsForSourceFile(result.sourceFile, options.symbolsByFile, options.sourceContentByFile);
164
+ if (granularSymbols.length === 0)
165
+ continue;
166
+ const granularNames = [
167
+ ...new Set(granularSymbols.map((s) => s.name)),
168
+ ].sort();
169
+ if (granularNames.includes(result.entity.title))
170
+ continue;
171
+ diagnostics.push({
172
+ id: "symbol_granularity_violation",
173
+ severity: "error",
174
+ files: [result.entity.source, result.sourceFile],
175
+ docs: ["docs/symbol-traceability-taxonomy.md"],
176
+ message: `Symbol ${result.entity.id} links ${result.sourceFile} coarsely while granular symbols are available: ${granularNames.join(", ")}`,
177
+ suggestion: "Move ownership/coverage/test relationships to the narrow function/class/type symbol, or add granularity_reason with config-artifact, module-level-behavior, extractor-miss, or legacy-link when the coarse symbol is intentional.",
178
+ });
179
+ }
180
+ return diagnostics;
181
+ }
182
+ function getGranularSymbolsForSourceFile(sourceFile, symbolsByFile, sourceContentByFile) {
183
+ const stagedContent = sourceContentByFile.get(sourceFile);
184
+ if (stagedContent !== undefined) {
185
+ return extractSymbolsFromStagedFile({
186
+ path: sourceFile,
187
+ status: "M",
188
+ hunkRanges: [{ start: 1, end: Number.MAX_SAFE_INTEGER }],
189
+ content: stagedContent,
190
+ });
191
+ }
192
+ const absolutePath = path.isAbsolute(sourceFile)
193
+ ? sourceFile
194
+ : path.resolve(process.cwd(), sourceFile);
195
+ if (!existsSync(absolutePath)) {
196
+ return [];
197
+ }
198
+ return extractSymbolsFromStagedFile({
199
+ path: sourceFile,
200
+ status: "M",
201
+ hunkRanges: [{ start: 1, end: Number.MAX_SAFE_INTEGER }],
202
+ content: readFileSync(absolutePath, "utf8"),
203
+ });
118
204
  }
119
205
  const KIBI_ENTITY_TYPES = new Set([
120
206
  "req",
@@ -317,7 +403,7 @@ export async function checkCommand(options) {
317
403
  console.log("No staged files found.");
318
404
  return { exitCode: 0 };
319
405
  }
320
- const { manifestLookup, manifestResults } = buildManifestLookup(stagedFiles);
406
+ const { manifestLookup, manifestResults, authoredSymbolResults, stagedAuthoredSymbolResults, } = buildManifestLookup(stagedFiles);
321
407
  const symbolsManifestPath = loadConfig(process.cwd()).paths.symbols ?? KIBI_SYMBOLS_MANIFEST_PATH;
322
408
  const sourceFiles = stagedFiles.filter((file) => !file.path.endsWith(".md") && !isStagedManifestPath(file.path));
323
409
  const markdownFiles = stagedFiles.filter((f) => f.path.endsWith(".md"));
@@ -341,8 +427,12 @@ export async function checkCommand(options) {
341
427
  }
342
428
  const allSymbols = [];
343
429
  const symbolsByFile = new Map();
430
+ const sourceContentByFile = new Map();
344
431
  for (const f of sourceFiles) {
345
432
  try {
433
+ if (f.content !== undefined) {
434
+ sourceContentByFile.set(f.path, f.content);
435
+ }
346
436
  const symbols = extractSymbolsFromStagedFile(f, manifestLookup);
347
437
  symbolsByFile.set(f.path, symbols);
348
438
  if (symbols?.length) {
@@ -367,6 +457,16 @@ export async function checkCommand(options) {
367
457
  symbolsManifestPath,
368
458
  });
369
459
  const stagedKibiDiagnostics = collectStagedKibiDiagnostics(stagedKibiEvidence);
460
+ const stagedAuthoredSymbolSet = new Set(stagedAuthoredSymbolResults);
461
+ const stagedSourcePaths = new Set(sourceFiles.map((file) => file.path));
462
+ const activeGranularityResults = authoredSymbolResults.filter((result) => stagedAuthoredSymbolSet.has(result) ||
463
+ (result.sourceFile !== undefined &&
464
+ stagedSourcePaths.has(result.sourceFile)));
465
+ stagedKibiDiagnostics.push(...createSymbolGranularityDiagnostics({
466
+ manifestResults: activeGranularityResults,
467
+ symbolsByFile,
468
+ sourceContentByFile,
469
+ }));
370
470
  if (allSymbols.length === 0 && stagedEntityResults.length === 0) {
371
471
  console.log("No exported symbols or staged entities found in staged files.");
372
472
  return { exitCode: 0 };
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAkCA,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAsJD,wBAAsB,cAAc,CAClC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgH/B"}
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;AAiWD,wBAAsB,cAAc,CAClC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgI/B"}
@@ -17,7 +17,10 @@
17
17
  */
18
18
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from "node:fs";
19
19
  import * as path from "node:path";
20
+ import { load as parseYAML } from "js-yaml";
21
+ import { extractSymbolsFromStagedFile } from "../traceability/symbol-extract.js";
20
22
  import { resolveActiveBranch } from "../utils/branch-resolver.js";
23
+ import { DEFAULT_CONFIG } from "../utils/config.js";
21
24
  import { LATEST_KB_SCHEMA_VERSION, getSchemaVersionStatus, normalizeSchemaVersion, } from "../utils/schema-version.js";
22
25
  const MIGRATION_AUDIT_VERSION = 1;
23
26
  function printWarning(message) {
@@ -83,9 +86,12 @@ function loadRawConfigDocument(cwd) {
83
86
  }
84
87
  }
85
88
  function writeJsonAtomically(filePath, value) {
89
+ writeTextAtomically(filePath, `${JSON.stringify(value, null, 2)}\n`);
90
+ }
91
+ function writeTextAtomically(filePath, content) {
86
92
  mkdirSync(path.dirname(filePath), { recursive: true });
87
93
  const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
88
- writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
94
+ writeFileSync(tempPath, content, "utf8");
89
95
  renameSync(tempPath, filePath);
90
96
  }
91
97
  function formatSchemaVersion(rawSchemaVersion, normalized) {
@@ -105,10 +111,148 @@ function buildMigrationAuditRecord(args) {
105
111
  fromVersion: args.fromVersion,
106
112
  migratedAt: args.migratedAt,
107
113
  status: "applied",
114
+ symbolGranularityLegacyLinks: args.symbolGranularityLegacyLinks,
108
115
  toVersion: LATEST_KB_SCHEMA_VERSION,
109
116
  warning: args.warning,
110
117
  };
111
118
  }
119
+ const TRACEABILITY_RELATIONSHIP_TYPES = new Set([
120
+ "implements",
121
+ "covered_by",
122
+ "executable_for",
123
+ ]);
124
+ function hasTraceabilityRelationship(symbol) {
125
+ if (Array.isArray(symbol.links) && symbol.links.length > 0) {
126
+ return true;
127
+ }
128
+ if (!Array.isArray(symbol.relationships)) {
129
+ return false;
130
+ }
131
+ return symbol.relationships.some((relationship) => {
132
+ if (relationship === null ||
133
+ typeof relationship !== "object" ||
134
+ Array.isArray(relationship)) {
135
+ return false;
136
+ }
137
+ const type = relationship.type;
138
+ return (typeof type === "string" && TRACEABILITY_RELATIONSHIP_TYPES.has(type));
139
+ });
140
+ }
141
+ function getGranularNames(cwd, sourceFile) {
142
+ const absolutePath = path.isAbsolute(sourceFile)
143
+ ? sourceFile
144
+ : path.join(cwd, sourceFile);
145
+ if (!existsSync(absolutePath)) {
146
+ return new Set();
147
+ }
148
+ const symbols = extractSymbolsFromStagedFile({
149
+ path: sourceFile,
150
+ status: "M",
151
+ hunkRanges: [{ start: 1, end: Number.MAX_SAFE_INTEGER }],
152
+ content: readFileSync(absolutePath, "utf8"),
153
+ });
154
+ return new Set(symbols.map((symbol) => symbol.name));
155
+ }
156
+ function addLegacyReasonsToManifestText(content, symbolIds) {
157
+ if (symbolIds.size === 0)
158
+ return content;
159
+ const lines = content.split("\n");
160
+ const output = [];
161
+ let activeId = null;
162
+ let activeHasReason = false;
163
+ let activePropertyIndent = "";
164
+ const flushLegacyReason = () => {
165
+ if (activeId !== null &&
166
+ symbolIds.has(activeId) &&
167
+ !activeHasReason &&
168
+ activePropertyIndent.length > 0) {
169
+ output.push(`${activePropertyIndent}granularity_reason: legacy-link`);
170
+ activeHasReason = true;
171
+ }
172
+ };
173
+ for (const line of lines) {
174
+ const idMatch = line.match(/^(\s*)-\s+id:\s+(.+)\s*$/);
175
+ if (idMatch) {
176
+ flushLegacyReason();
177
+ activeId = idMatch[2]?.trim() ?? null;
178
+ activeHasReason = false;
179
+ activePropertyIndent = `${idMatch[1] ?? ""} `;
180
+ }
181
+ if (activeId !== null && /^\s+granularity_reason:\s+/.test(line)) {
182
+ activeHasReason = true;
183
+ }
184
+ if (activeId !== null &&
185
+ symbolIds.has(activeId) &&
186
+ !activeHasReason &&
187
+ /^\s+status:\s+/.test(line)) {
188
+ const indent = line.match(/^\s*/)?.[0] ?? "";
189
+ output.push(`${indent}granularity_reason: legacy-link`);
190
+ activeHasReason = true;
191
+ }
192
+ output.push(line);
193
+ }
194
+ flushLegacyReason();
195
+ return output.join("\n");
196
+ }
197
+ function migrateSymbolGranularity(options) {
198
+ const configuredSymbolsPath = options.config.paths?.symbols ?? DEFAULT_CONFIG.paths.symbols;
199
+ if (typeof configuredSymbolsPath !== "string") {
200
+ return { count: 0, manifestPath: null };
201
+ }
202
+ const manifestPath = path.isAbsolute(configuredSymbolsPath)
203
+ ? configuredSymbolsPath
204
+ : path.join(options.cwd, configuredSymbolsPath);
205
+ if (!existsSync(manifestPath)) {
206
+ return { count: 0, manifestPath };
207
+ }
208
+ const manifestContent = readFileSync(manifestPath, "utf8");
209
+ const parsed = parseYAML(manifestContent);
210
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
211
+ return { count: 0, manifestPath };
212
+ }
213
+ const manifest = parsed;
214
+ if (!Array.isArray(manifest.symbols)) {
215
+ return { count: 0, manifestPath };
216
+ }
217
+ let count = 0;
218
+ const migratedSymbolIds = new Set();
219
+ const granularNamesByFile = new Map();
220
+ for (const symbol of manifest.symbols) {
221
+ if (symbol === null ||
222
+ typeof symbol !== "object" ||
223
+ Array.isArray(symbol)) {
224
+ continue;
225
+ }
226
+ const record = symbol;
227
+ if (typeof record.sourceFile !== "string")
228
+ continue;
229
+ if (typeof record.title !== "string")
230
+ continue;
231
+ if (typeof record.id !== "string")
232
+ continue;
233
+ if (record.granularity_reason !== undefined)
234
+ continue;
235
+ if (!hasTraceabilityRelationship(record))
236
+ continue;
237
+ let granularNames = granularNamesByFile.get(record.sourceFile);
238
+ if (granularNames === undefined) {
239
+ granularNames = getGranularNames(options.cwd, record.sourceFile);
240
+ granularNamesByFile.set(record.sourceFile, granularNames);
241
+ }
242
+ if (granularNames.size === 0 || granularNames.has(record.title)) {
243
+ continue;
244
+ }
245
+ count += 1;
246
+ if (!options.dryRun) {
247
+ record.granularity_reason = "legacy-link";
248
+ migratedSymbolIds.add(record.id);
249
+ }
250
+ }
251
+ if (count > 0 && !options.dryRun) {
252
+ writeTextAtomically(manifestPath, addLegacyReasonsToManifestText(manifestContent, migratedSymbolIds));
253
+ }
254
+ return { count, manifestPath };
255
+ }
112
256
  // implements REQ-003
113
257
  export async function migrateCommand(options = {}) {
114
258
  const cwd = process.cwd();
@@ -156,9 +300,17 @@ export async function migrateCommand(options = {}) {
156
300
  return { exitCode: 0 };
157
301
  }
158
302
  const fromVersionLabel = formatSchemaVersion(rawSchemaVersion, normalizedVersion);
303
+ const symbolGranularityMigration = migrateSymbolGranularity({
304
+ cwd,
305
+ config,
306
+ dryRun: options.dryRun || !options.yes,
307
+ });
159
308
  if (options.dryRun) {
160
309
  console.log(`dry run: would migrate ${configPathRelative} schemaVersion from ${fromVersionLabel} to ${LATEST_KB_SCHEMA_VERSION}.`);
161
310
  console.log(`dry run: would write migration audit metadata to ${auditPathRelative}.`);
311
+ if (symbolGranularityMigration.count > 0) {
312
+ console.log(`dry run: would mark ${symbolGranularityMigration.count} legacy coarse symbol link(s) in ${toRelativePath(cwd, symbolGranularityMigration.manifestPath ?? "symbols.yaml")}.`);
313
+ }
162
314
  console.log("Re-run with --yes to apply these changes.");
163
315
  return { exitCode: 0 };
164
316
  }
@@ -179,9 +331,13 @@ export async function migrateCommand(options = {}) {
179
331
  configPath: configPathRelative,
180
332
  fromVersion: configStatus.currentVersion,
181
333
  migratedAt,
334
+ symbolGranularityLegacyLinks: symbolGranularityMigration.count,
182
335
  warning: migrationWarning,
183
336
  }));
184
337
  console.log(`Migrated ${configPathRelative} schemaVersion from ${fromVersionLabel} to ${LATEST_KB_SCHEMA_VERSION}.`);
338
+ if (symbolGranularityMigration.count > 0) {
339
+ console.log(`Marked ${symbolGranularityMigration.count} existing coarse symbol link(s) as legacy-link.`);
340
+ }
185
341
  console.log(`Wrote migration audit metadata to ${auditPathRelative}.`);
186
342
  console.log("Migration complete. Future 'kibi migrate' runs will be a no-op.");
187
343
  return { exitCode: 0 };
@@ -1 +1 @@
1
- {"version":3,"file":"usage-metrics.d.ts","sourceRoot":"","sources":["../../src/commands/usage-metrics.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,UAAU,mBAAmB;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAkED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAuBpC"}
1
+ {"version":3,"file":"usage-metrics.d.ts","sourceRoot":"","sources":["../../src/commands/usage-metrics.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,UAAU,mBAAmB;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAyED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAuBpC"}
@@ -54,6 +54,9 @@ function buildUsageMetricsReport(rows, limit) {
54
54
  const zeroResultToolCounts = new Map();
55
55
  const zeroResultSourceFileCounts = new Map();
56
56
  const upsertErrorCategories = new Map();
57
+ const errorCategories = new Map();
58
+ const errorStages = new Map();
59
+ const errorsByTool = new Map();
57
60
  const violationTrend = [];
58
61
  let successCount = 0;
59
62
  let errorCount = 0;
@@ -69,6 +72,10 @@ function buildUsageMetricsReport(rows, limit) {
69
72
  }
70
73
  if (outcome === "error") {
71
74
  errorCount += 1;
75
+ const category = row.error_category ?? categorizeError(row.error_message ?? row.error);
76
+ increment(errorCategories, category);
77
+ increment(errorStages, row.error_stage ?? inferErrorStage(row.error_message ?? row.error));
78
+ increment(errorsByTool, normalizeKey(row.tool, "unknown"));
72
79
  }
73
80
  if (hasCompleteTelemetry(row)) {
74
81
  telemetryCompleteCount += 1;
@@ -128,6 +135,11 @@ function buildUsageMetricsReport(rows, limit) {
128
135
  upsertErrors: {
129
136
  categories: mapToSortedObject(upsertErrorCategories),
130
137
  },
138
+ errors: {
139
+ categories: mapToSortedObject(errorCategories),
140
+ stages: mapToSortedObject(errorStages),
141
+ byTool: mapToSortedObject(errorsByTool),
142
+ },
131
143
  };
132
144
  }
133
145
  function hasCompleteTelemetry(row) {
@@ -180,9 +192,31 @@ function getSourceFile(row) {
180
192
  return null;
181
193
  }
182
194
  function categorizeUpsertError(errorMessage) {
195
+ return categorizeError(errorMessage);
196
+ }
197
+ function categorizeError(errorMessage) {
183
198
  if (!errorMessage) {
184
199
  return "Unknown error";
185
200
  }
201
+ const lower = errorMessage.toLowerCase();
202
+ if (lower.includes("stale_snapshot")) {
203
+ return "stale_snapshot";
204
+ }
205
+ if (lower.includes("unknown option") && lower.includes("h for help")) {
206
+ return "prolog_unknown_option";
207
+ }
208
+ if (lower.includes("prolog process not started")) {
209
+ return "prolog_process_not_started";
210
+ }
211
+ if (lower.includes("coarsely while granular symbols are available")) {
212
+ return "coarse_symbol_linkage";
213
+ }
214
+ if (lower.includes("module load failed")) {
215
+ return "prolog_module_load_failed";
216
+ }
217
+ if (lower.includes("query failed")) {
218
+ return "prolog_query_failed";
219
+ }
186
220
  if (errorMessage.startsWith("Entity validation failed:")) {
187
221
  return "Entity validation failed";
188
222
  }
@@ -199,6 +233,29 @@ function categorizeUpsertError(errorMessage) {
199
233
  }
200
234
  return errorMessage.trim() || "Unknown error";
201
235
  }
236
+ function inferErrorStage(errorMessage) {
237
+ if (!errorMessage) {
238
+ return "unknown";
239
+ }
240
+ const lower = errorMessage.toLowerCase();
241
+ if (lower.includes("stale_snapshot")) {
242
+ return "persistence";
243
+ }
244
+ if (lower.includes("unknown option") ||
245
+ lower.includes("module load failed") ||
246
+ lower.includes("query failed")) {
247
+ return "prolog_runtime";
248
+ }
249
+ if (lower.includes("prolog process not started")) {
250
+ return "prolog_lifecycle";
251
+ }
252
+ if (lower.includes("validation failed") ||
253
+ lower.includes("relationship source must match") ||
254
+ lower.includes("coarsely while granular symbols are available")) {
255
+ return "validation";
256
+ }
257
+ return "unknown";
258
+ }
202
259
  function increment(counts, key) {
203
260
  counts.set(key, (counts.get(key) ?? 0) + 1);
204
261
  }
@@ -221,6 +278,9 @@ function renderUsageMetricsReport(report) {
221
278
  renderZeroResultsTable(report),
222
279
  renderViolationTrendTable(report),
223
280
  renderCountsTable("Upsert Error Categories", "Category", report.upsertErrors.categories),
281
+ renderCountsTable("Error Categories", "Category", report.errors.categories),
282
+ renderCountsTable("Error Stages", "Stage", report.errors.stages),
283
+ renderCountsTable("Errors By Tool", "Tool", report.errors.byTool),
224
284
  ].filter(Boolean);
225
285
  return sections.join("\n\n");
226
286
  }
@@ -11,6 +11,7 @@ export interface ExtractedEntity {
11
11
  priority?: string;
12
12
  severity?: string;
13
13
  text_ref?: string;
14
+ granularity_reason?: string;
14
15
  }
15
16
  export interface ExtractedRelationship {
16
17
  type: string;
@@ -20,7 +21,6 @@ export interface ExtractedRelationship {
20
21
  export interface ExtractionResult {
21
22
  entity: ExtractedEntity;
22
23
  relationships: ExtractedRelationship[];
23
- /** The per-symbol source code file, distinct from the manifest file path. */
24
24
  sourceFile?: string;
25
25
  }
26
26
  export declare class ManifestError extends Error {
@@ -38,6 +38,7 @@ export interface ManifestSymbolRecord {
38
38
  priority?: string;
39
39
  severity?: string;
40
40
  text_ref?: string;
41
+ granularity_reason?: string;
41
42
  created_at?: string;
42
43
  updated_at?: string;
43
44
  links?: Array<string | {
@@ -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;CACnB;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,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,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,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;AAwHD,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"}
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;AAED,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;AA2HD,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"}
@@ -96,6 +96,9 @@ function extractFromManifestSymbolRecords(manifestSymbols, filePath) {
96
96
  ...(symbol.priority !== undefined ? { priority: symbol.priority } : {}),
97
97
  ...(symbol.severity !== undefined ? { severity: symbol.severity } : {}),
98
98
  ...(symbol.text_ref !== undefined ? { text_ref: symbol.text_ref } : {}),
99
+ ...(symbol.granularity_reason !== undefined
100
+ ? { granularity_reason: symbol.granularity_reason }
101
+ : {}),
99
102
  };
100
103
  const sourceFile = symbol.sourceFile ?? symbol.source;
101
104
  return {
@@ -11,6 +11,7 @@ export interface ExtractedEntity {
11
11
  priority?: string;
12
12
  severity?: string;
13
13
  text_ref?: string;
14
+ granularity_reason?: string;
14
15
  verification_scope?: "unit" | "integration" | "end_to_end";
15
16
  verification_perspective?: "internal" | "consumer";
16
17
  fact_kind?: "subject" | "property_value" | "observation" | "meta";
@@ -38,7 +39,6 @@ export interface ExtractedRelationship {
38
39
  export interface ExtractionResult {
39
40
  entity: ExtractedEntity;
40
41
  relationships: ExtractedRelationship[];
41
- /** The per-symbol source code file, distinct from the manifest file path. */
42
42
  sourceFile?: string;
43
43
  }
44
44
  export declare class FrontmatterError extends Error {
@@ -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,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,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA2BD,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;AAmRD,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"}
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;AA2BD,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;AAmRD,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"}
package/dist/prolog.d.ts CHANGED
@@ -16,6 +16,7 @@ export declare class PrologProcess {
16
16
  private errorBuffer;
17
17
  private cache;
18
18
  private interactiveQueryTail;
19
+ private terminationPromise;
19
20
  private useOneShotMode;
20
21
  private attachedKbPath;
21
22
  private onProcessExit;
@@ -30,6 +31,8 @@ export declare class PrologProcess {
30
31
  private queryOneShot;
31
32
  private execOneShot;
32
33
  private normalizeGoal;
34
+ private clearQueryBuffers;
35
+ private isProcessUsable;
33
36
  private extractBindings;
34
37
  private translateError;
35
38
  isRunning(): boolean;
@@ -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,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;IAoK1D,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"}
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;IA0CpB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAmK1D,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;IAiBvB,OAAO,CAAC,cAAc;IA+BtB,SAAS,IAAI,OAAO;IAMpB,MAAM,IAAI,MAAM;IAIV,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAwCjC"}
package/dist/prolog.js CHANGED
@@ -67,6 +67,7 @@ export class PrologProcess {
67
67
  errorBuffer = "";
68
68
  cache = new Map();
69
69
  interactiveQueryTail = Promise.resolve();
70
+ terminationPromise = null;
70
71
  useOneShotMode = typeof globalThis.Bun !== "undefined";
71
72
  attachedKbPath = null;
72
73
  onProcessExit = null;
@@ -84,6 +85,7 @@ export class PrologProcess {
84
85
  `use_module('${kbPath}'), use_module(library(semweb/rdf_db)), set_prolog_flag(answer_write_options, [max_depth(0), quoted(true)])`,
85
86
  "--quiet",
86
87
  ]);
88
+ this.clearQueryBuffers();
87
89
  if (!this.process.stdout || !this.process.stderr || !this.process.stdin) {
88
90
  throw new Error("Failed to spawn Prolog process");
89
91
  }
@@ -155,12 +157,11 @@ export class PrologProcess {
155
157
  const batchGoal = `(${goal.map((item) => this.normalizeGoal(item)).join(", ")})`;
156
158
  return this.query(batchGoal);
157
159
  }
158
- if (!this.process || !this.process.stdin) {
160
+ if (!this.isProcessUsable()) {
159
161
  throw new Error("Prolog process not started");
160
162
  }
161
163
  const runInteractiveQuery = async () => {
162
- this.outputBuffer = "";
163
- this.errorBuffer = "";
164
+ this.clearQueryBuffers();
164
165
  const debug = isPrologDebugEnabled();
165
166
  const normalizedGoal = this.normalizeGoal(goal);
166
167
  const wrappedGoal = /^once\s*\(/.test(normalizedGoal)
@@ -258,7 +259,7 @@ export class PrologProcess {
258
259
  });
259
260
  await previousQuery;
260
261
  try {
261
- if (!this.process || !this.process.stdin) {
262
+ if (!this.isProcessUsable()) {
262
263
  throw new Error("Prolog process not started");
263
264
  }
264
265
  return await runInteractiveQuery();
@@ -410,6 +411,16 @@ export class PrologProcess {
410
411
  normalizeGoal(goal) {
411
412
  return goal.trim().replace(/\.+\s*$/, "");
412
413
  }
414
+ clearQueryBuffers() {
415
+ this.outputBuffer = "";
416
+ this.errorBuffer = "";
417
+ }
418
+ // implements REQ-009
419
+ isProcessUsable() {
420
+ return Boolean(this.process?.stdin &&
421
+ !this.process?.killed &&
422
+ this.process?.exitCode === null);
423
+ }
413
424
  extractBindings(output) {
414
425
  const bindings = {};
415
426
  const lines = output.split("\n");
@@ -447,30 +458,44 @@ export class PrologProcess {
447
458
  return simpleError || "Unknown error";
448
459
  }
449
460
  isRunning() {
450
- return this.process !== null && !this.process.killed;
461
+ return Boolean(this.process && !this.process.killed && this.process?.exitCode === null);
451
462
  }
452
463
  getPid() {
453
464
  return this.process?.pid || 0;
454
465
  }
455
466
  async terminate() {
467
+ if (this.terminationPromise) {
468
+ await this.terminationPromise;
469
+ return;
470
+ }
456
471
  if (this.onProcessExit) {
457
472
  process.off("exit", this.onProcessExit);
458
473
  this.onProcessExit = null;
459
474
  }
460
- if (this.process) {
461
- this.process.stdin?.end();
462
- this.process.kill("SIGTERM");
463
- await new Promise((resolve) => {
464
- const timeout = setTimeout(() => {
465
- this.process?.kill("SIGKILL");
466
- resolve(undefined);
467
- }, 1000);
468
- this.process?.on("exit", () => {
469
- clearTimeout(timeout);
470
- resolve(undefined);
475
+ const current = this.process;
476
+ this.process = null;
477
+ this.clearQueryBuffers();
478
+ if (current) {
479
+ this.terminationPromise = (async () => {
480
+ current.stdin?.end();
481
+ current.kill("SIGTERM");
482
+ await new Promise((resolve) => {
483
+ const timeout = setTimeout(() => {
484
+ current.kill("SIGKILL");
485
+ resolve(undefined);
486
+ }, 1000);
487
+ current.on("exit", () => {
488
+ clearTimeout(timeout);
489
+ resolve(undefined);
490
+ });
471
491
  });
472
- });
473
- this.process = null;
492
+ })();
493
+ try {
494
+ await this.terminationPromise;
495
+ }
496
+ finally {
497
+ this.terminationPromise = null;
498
+ }
474
499
  }
475
500
  }
476
501
  }
@@ -1 +1 @@
1
- {"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/entity.ts"],"names":[],"mappings":"AA+EA,QAAA,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAkJzC,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/entity.ts"],"names":[],"mappings":"AA+EA,QAAA,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CA2JzC,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -104,6 +104,15 @@ const entitySchema = {
104
104
  links: { type: "array", items: { type: "string" } },
105
105
  text_ref: { type: "string" },
106
106
  sourceFile: { type: "string" },
107
+ granularity_reason: {
108
+ type: "string",
109
+ enum: [
110
+ "config-artifact",
111
+ "module-level-behavior",
112
+ "extractor-miss",
113
+ "legacy-link",
114
+ ],
115
+ },
107
116
  type: {
108
117
  type: "string",
109
118
  enum: [
@@ -24,6 +24,10 @@ Consult this skill before any Kibi knowledge base operation, on first interactio
24
24
 
25
25
  Interact with the knowledge base exclusively through MCP tools. Do not read or edit files inside `.kb/` directly. Do not run any `kibi` CLI commands from the agent session. The MCP surface is the only sanctioned interface for agents.
26
26
 
27
+ ### Tool Name Prefixes
28
+
29
+ Kibi's canonical MCP names are `kb_search`, `kb_query`, `kb_upsert`, `kb_check`, and related `kb_*` tools. Some hosts add a server prefix when exposing tools to agents. In OpenCode, use the visible `kibi_kb_search`, `kibi_kb_query`, `kibi_kb_upsert`, and `kibi_kb_check` names when exact tool identifiers are required; they map to the same canonical MCP names.
30
+
27
31
  ## Discovery-First Workflow
28
32
 
29
33
  Always discover before you mutate. Start with `kb_search` for exploratory discovery across metadata and markdown body text. Split broad queries into 1-3 focused probes. Review top hits for relevance before concluding the KB lacks knowledge.
@@ -39,6 +39,15 @@
39
39
  "links": { "type": "array", "items": { "type": "string" } },
40
40
  "text_ref": { "type": "string" },
41
41
  "sourceFile": { "type": "string" },
42
+ "granularity_reason": {
43
+ "type": "string",
44
+ "enum": [
45
+ "config-artifact",
46
+ "module-level-behavior",
47
+ "extractor-miss",
48
+ "legacy-link"
49
+ ]
50
+ },
42
51
  "verification_scope": {
43
52
  "type": "string",
44
53
  "enum": ["unit", "integration", "end_to_end"]
@@ -1,5 +1,5 @@
1
1
  import { type KibiImpactEvidence } from "./evidence-model.js";
2
- export type KibiImpactDiagnosticId = "kibi_impact_evidence_missing" | "symbols_manifest_stale" | "kibi_impact_override_missing_rationale";
2
+ export type KibiImpactDiagnosticId = "kibi_impact_evidence_missing" | "symbols_manifest_stale" | "symbol_granularity_violation" | "kibi_impact_override_missing_rationale";
3
3
  export interface KibiImpactDiagnostic {
4
4
  /** Stable staged-enforcement diagnostic identifier. */
5
5
  id: KibiImpactDiagnosticId;
@@ -1 +1 @@
1
- {"version":3,"file":"staged-diagnostics.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,kBAAkB,EAIxB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,sBAAsB,GAC9B,8BAA8B,GAC9B,wBAAwB,GACxB,wCAAwC,CAAC;AAE7C,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,EAAE,EAAE,sBAAsB,CAAC;IAC3B,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gDAAgD;IAChD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;CACpB;AAsDD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,kBAAkB,GAC3B,oBAAoB,EAAE,CAoCxB"}
1
+ {"version":3,"file":"staged-diagnostics.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,kBAAkB,EAIxB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,sBAAsB,GAC9B,8BAA8B,GAC9B,wBAAwB,GACxB,8BAA8B,GAC9B,wCAAwC,CAAC;AAE7C,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,EAAE,EAAE,sBAAsB,CAAC;IAC3B,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gDAAgD;IAChD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;CACpB;AAsDD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,kBAAkB,GAC3B,oBAAoB,EAAE,CAoCxB"}
@@ -6,7 +6,7 @@ type TraceabilityRelationship = {
6
6
  export interface ExtractedSymbol {
7
7
  id: string;
8
8
  name: string;
9
- kind: "function" | "class" | "variable" | "enum" | "unknown";
9
+ kind: "function" | "class" | "interface" | "type" | "variable" | "enum" | "unknown";
10
10
  location: {
11
11
  file: string;
12
12
  startLine: number;
@@ -1 +1 @@
1
- {"version":3,"file":"symbol-extract.d.ts","sourceRoot":"","sources":["../../src/traceability/symbol-extract.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7D,KAAK,wBAAwB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAU7D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;IAC7D,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;CAC5C;AAED,MAAM,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAE9D,wBAAgB,+BAA+B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAG5E;AAkOD,wBAAgB,4BAA4B,CAE1C,UAAU,EAAE,UAAU,EACtB,cAAc,CAAC,EAAE,cAAc,GAC9B,eAAe,EAAE,CA+JnB"}
1
+ {"version":3,"file":"symbol-extract.d.ts","sourceRoot":"","sources":["../../src/traceability/symbol-extract.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7D,KAAK,wBAAwB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAU7D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EACA,UAAU,GACV,OAAO,GACP,WAAW,GACX,MAAM,GACN,UAAU,GACV,MAAM,GACN,SAAS,CAAC;IACd,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;CAC5C;AAED,MAAM,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAE9D,wBAAgB,+BAA+B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAG5E;AAkOD,wBAAgB,4BAA4B,CAE1C,UAAU,EAAE,UAAU,EACtB,cAAc,CAAC,EAAE,cAAc,GAC9B,eAAe,EAAE,CAiNnB"}
@@ -217,7 +217,7 @@ stagedFile, manifestLookup) {
217
217
  results.push(buildSymbolResult(stagedFile, name, "function", span, reqLinks, manifestLookup));
218
218
  }
219
219
  catch {
220
- // skip: individual declaration extraction may fail on malformed AST nodes
220
+ void stagedFile.path;
221
221
  }
222
222
  }
223
223
  // Classes
@@ -236,7 +236,7 @@ stagedFile, manifestLookup) {
236
236
  results.push(buildSymbolResult(stagedFile, name, "class", span, reqLinks, manifestLookup));
237
237
  }
238
238
  catch {
239
- // skip: individual declaration extraction may fail on malformed AST nodes
239
+ void stagedFile.path;
240
240
  }
241
241
  }
242
242
  // Enums
@@ -252,7 +252,41 @@ stagedFile, manifestLookup) {
252
252
  results.push(buildSymbolResult(stagedFile, name, "enum", span, reqLinks, manifestLookup));
253
253
  }
254
254
  catch {
255
- // skip: individual declaration extraction may fail on malformed AST nodes
255
+ void stagedFile.path;
256
+ }
257
+ }
258
+ for (const iface of typeof sf.getInterfaces === "function"
259
+ ? sf.getInterfaces()
260
+ : []) {
261
+ if (!iface.isExported())
262
+ continue;
263
+ try {
264
+ const name = iface.getName();
265
+ const start = iface.getNameNode().getStart();
266
+ const end = iface.getEnd();
267
+ const span = getSpan(start, end);
268
+ const reqLinks = parseReqDirectives(iface.getText());
269
+ results.push(buildSymbolResult(stagedFile, name, "interface", span, reqLinks, manifestLookup));
270
+ }
271
+ catch {
272
+ void stagedFile.path;
273
+ }
274
+ }
275
+ for (const alias of typeof sf.getTypeAliases === "function"
276
+ ? sf.getTypeAliases()
277
+ : []) {
278
+ if (!alias.isExported())
279
+ continue;
280
+ try {
281
+ const name = alias.getName();
282
+ const start = alias.getNameNode().getStart();
283
+ const end = alias.getEnd();
284
+ const span = getSpan(start, end);
285
+ const reqLinks = parseReqDirectives(alias.getText());
286
+ results.push(buildSymbolResult(stagedFile, name, "type", span, reqLinks, manifestLookup));
287
+ }
288
+ catch {
289
+ void stagedFile.path;
256
290
  }
257
291
  }
258
292
  // Variable statements (exported)
@@ -269,7 +303,7 @@ stagedFile, manifestLookup) {
269
303
  results.push(buildSymbolResult(stagedFile, name, "variable", span, reqLinks, manifestLookup));
270
304
  }
271
305
  catch {
272
- // skip: individual declaration extraction may fail on malformed AST nodes
306
+ void stagedFile.path;
273
307
  }
274
308
  }
275
309
  }
@@ -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,CAiCf;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"}
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,CAwBf;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"}
@@ -124,10 +124,10 @@ function buildEntityAssertionGoal(entity) {
124
124
  if (entity.type === "fact") {
125
125
  props.push(...serializeTypedFactFields(entity));
126
126
  }
127
- return `kb_assert_entity(${entity.type}, [${props.join(", ")}])`;
127
+ return `kb_assert_entity_no_audit(${entity.type}, [${props.join(", ")}])`;
128
128
  }
129
129
  function buildRelationshipAssertionGoal(relationship) {
130
- return `kb_assert_relationship(${toPrologAtom(relationship.type)}, ${toPrologAtom(relationship.from)}, ${toPrologAtom(relationship.to)}, [])`;
130
+ return `kb_assert_relationship_no_audit(${toPrologAtom(relationship.type)}, ${toPrologAtom(relationship.from)}, ${toPrologAtom(relationship.to)}, [])`;
131
131
  }
132
132
  function createCleanupHandler(tempDir) {
133
133
  let inProgress = false;
@@ -170,10 +170,6 @@ export { consultOverlay };
170
170
  // implements REQ-014
171
171
  export async function projectStagedEntities(prolog, results) {
172
172
  for (const { entity } of results) {
173
- const retractResult = await prolog.query(`kb_retract_entity(${toPrologAtom(entity.id)})`);
174
- if (!retractResult.success) {
175
- throw new Error(`Failed to retract staged entity ${entity.id}: ${retractResult.error || "unknown error"}`);
176
- }
177
173
  const assertEntityResult = await prolog.query(buildEntityAssertionGoal(entity));
178
174
  if (!assertEntityResult.success) {
179
175
  throw new Error(`Failed to assert staged entity ${entity.id}: ${assertEntityResult.error || "unknown error"}`);
@@ -1,5 +1,5 @@
1
1
  import type { KbConfig } from "./config.js";
2
- export declare const LATEST_KB_SCHEMA_VERSION = 1;
2
+ export declare const LATEST_KB_SCHEMA_VERSION = 2;
3
3
  export interface SchemaVersionStatus {
4
4
  status: "missing" | "invalid" | "older" | "current" | "newer";
5
5
  currentVersion: number | null;
@@ -1,5 +1,5 @@
1
1
  // implements REQ-003
2
- export const LATEST_KB_SCHEMA_VERSION = 1;
2
+ export const LATEST_KB_SCHEMA_VERSION = 2;
3
3
  // implements REQ-003
4
4
  export function normalizeSchemaVersion(schemaVersion) {
5
5
  if (schemaVersion === undefined || schemaVersion === null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-cli",
3
- "version": "0.12.0",
3
+ "version": "0.12.3",
4
4
  "type": "module",
5
5
  "description": "Kibi CLI for knowledge base management",
6
6
  "engines": {
@@ -118,6 +118,15 @@ const entitySchema: Record<string, unknown> = {
118
118
  links: { type: "array", items: { type: "string" } },
119
119
  text_ref: { type: "string" },
120
120
  sourceFile: { type: "string" },
121
+ granularity_reason: {
122
+ type: "string",
123
+ enum: [
124
+ "config-artifact",
125
+ "module-level-behavior",
126
+ "extractor-miss",
127
+ "legacy-link",
128
+ ],
129
+ },
121
130
  type: {
122
131
  type: "string",
123
132
  enum: [
@@ -24,6 +24,10 @@ Consult this skill before any Kibi knowledge base operation, on first interactio
24
24
 
25
25
  Interact with the knowledge base exclusively through MCP tools. Do not read or edit files inside `.kb/` directly. Do not run any `kibi` CLI commands from the agent session. The MCP surface is the only sanctioned interface for agents.
26
26
 
27
+ ### Tool Name Prefixes
28
+
29
+ Kibi's canonical MCP names are `kb_search`, `kb_query`, `kb_upsert`, `kb_check`, and related `kb_*` tools. Some hosts add a server prefix when exposing tools to agents. In OpenCode, use the visible `kibi_kb_search`, `kibi_kb_query`, `kibi_kb_upsert`, and `kibi_kb_check` names when exact tool identifiers are required; they map to the same canonical MCP names.
30
+
27
31
  ## Discovery-First Workflow
28
32
 
29
33
  Always discover before you mutate. Start with `kb_search` for exploratory discovery across metadata and markdown body text. Split broad queries into 1-3 focused probes. Review top hits for relevance before concluding the KB lacks knowledge.
@@ -39,6 +39,15 @@
39
39
  "links": { "type": "array", "items": { "type": "string" } },
40
40
  "text_ref": { "type": "string" },
41
41
  "sourceFile": { "type": "string" },
42
+ "granularity_reason": {
43
+ "type": "string",
44
+ "enum": [
45
+ "config-artifact",
46
+ "module-level-behavior",
47
+ "extractor-miss",
48
+ "legacy-link"
49
+ ]
50
+ },
42
51
  "verification_scope": {
43
52
  "type": "string",
44
53
  "enum": ["unit", "integration", "end_to_end"]