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.
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +103 -3
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +157 -1
- package/dist/commands/usage-metrics.d.ts.map +1 -1
- package/dist/commands/usage-metrics.js +60 -0
- package/dist/extractors/manifest.d.ts +2 -1
- package/dist/extractors/manifest.d.ts.map +1 -1
- package/dist/extractors/manifest.js +3 -0
- package/dist/extractors/markdown.d.ts +1 -1
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/prolog.d.ts +3 -0
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +43 -18
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +9 -0
- package/dist/public/skills/kibi-usage/SKILL.md +4 -0
- package/dist/schemas/entity.schema.json +9 -0
- package/dist/traceability/staged-diagnostics.d.ts +1 -1
- package/dist/traceability/staged-diagnostics.d.ts.map +1 -1
- package/dist/traceability/symbol-extract.d.ts +1 -1
- package/dist/traceability/symbol-extract.d.ts.map +1 -1
- package/dist/traceability/symbol-extract.js +38 -4
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +2 -6
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.js +1 -1
- package/package.json +1 -1
- package/src/public/schemas/entity.ts +9 -0
- package/src/public/skills/kibi-usage/SKILL.md +4 -0
- package/src/schemas/entity.schema.json +9 -0
|
@@ -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;
|
|
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"}
|
package/dist/commands/check.js
CHANGED
|
@@ -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 {
|
|
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":"
|
|
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"}
|
package/dist/commands/migrate.js
CHANGED
|
@@ -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,
|
|
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;
|
|
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;
|
|
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,
|
|
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;
|
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,cAAc,CACyC;IAC/D,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,aAAa,CAA6B;gBAEtC,OAAO,GAAE,aAAkB;IAKjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
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.
|
|
160
|
+
if (!this.isProcessUsable()) {
|
|
159
161
|
throw new Error("Prolog process not started");
|
|
160
162
|
}
|
|
161
163
|
const runInteractiveQuery = async () => {
|
|
162
|
-
this.
|
|
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.
|
|
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
|
|
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
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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 `
|
|
127
|
+
return `kb_assert_entity_no_audit(${entity.type}, [${props.join(", ")}])`;
|
|
128
128
|
}
|
|
129
129
|
function buildRelationshipAssertionGoal(relationship) {
|
|
130
|
-
return `
|
|
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 =
|
|
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;
|
package/package.json
CHANGED
|
@@ -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"]
|