kibi-cli 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/commands/aggregated-checks.js +4 -6
  2. package/dist/commands/check.d.ts.map +1 -1
  3. package/dist/commands/check.js +55 -30
  4. package/dist/commands/query.d.ts.map +1 -1
  5. package/dist/commands/query.js +46 -28
  6. package/dist/commands/sync.d.ts.map +1 -1
  7. package/dist/commands/sync.js +19 -26
  8. package/dist/diagnostics.d.ts.map +1 -1
  9. package/dist/diagnostics.js +0 -2
  10. package/dist/extractors/manifest.d.ts +2 -0
  11. package/dist/extractors/manifest.d.ts.map +1 -1
  12. package/dist/extractors/manifest.js +1 -0
  13. package/dist/extractors/markdown.d.ts.map +1 -1
  14. package/dist/extractors/markdown.js +9 -1
  15. package/dist/prolog.d.ts +2 -0
  16. package/dist/prolog.d.ts.map +1 -1
  17. package/dist/prolog.js +45 -12
  18. package/dist/public/extractors/symbols-coordinator.d.ts.map +1 -1
  19. package/dist/public/extractors/symbols-coordinator.js +1 -2
  20. package/dist/public/prolog/index.d.ts.map +1 -1
  21. package/dist/public/prolog/index.js +1 -2
  22. package/dist/public/schemas/entity.d.ts.map +1 -1
  23. package/dist/public/schemas/entity.js +1 -3
  24. package/dist/public/schemas/relationship.d.ts.map +1 -1
  25. package/dist/public/schemas/relationship.js +1 -3
  26. package/dist/traceability/git-staged.d.ts.map +1 -1
  27. package/dist/traceability/git-staged.js +33 -7
  28. package/dist/traceability/symbol-extract.d.ts +6 -1
  29. package/dist/traceability/symbol-extract.d.ts.map +1 -1
  30. package/dist/traceability/symbol-extract.js +62 -34
  31. package/dist/traceability/temp-kb.d.ts.map +1 -1
  32. package/dist/traceability/temp-kb.js +4 -3
  33. package/dist/traceability/validate.d.ts.map +1 -1
  34. package/dist/traceability/validate.js +8 -7
  35. package/package.json +5 -1
  36. package/src/public/extractors/symbols-coordinator.ts +1 -2
  37. package/src/public/prolog/index.ts +1 -2
  38. package/src/public/schemas/entity.ts +1 -3
  39. package/src/public/schemas/relationship.ts +1 -3
@@ -23,8 +23,7 @@ export async function runAggregatedChecks(prolog, rulesAllowlist, requireAdr = f
23
23
  try {
24
24
  const result = await prolog.query(query);
25
25
  if (!result.success) {
26
- console.warn("Aggregated checks query failed, falling back to individual checks");
27
- return [];
26
+ throw new Error(`Aggregated checks query failed: ${result.error || "Unknown error"}`);
28
27
  }
29
28
  let violationsDict;
30
29
  try {
@@ -39,8 +38,7 @@ export async function runAggregatedChecks(prolog, rulesAllowlist, requireAdr = f
39
38
  violationsDict = parsed;
40
39
  }
41
40
  catch (parseError) {
42
- console.warn("Failed to parse violations JSON:", parseError);
43
- return [];
41
+ throw new Error(`Failed to parse violations JSON: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
44
42
  }
45
43
  for (const ruleViolations of Object.values(violationsDict)) {
46
44
  for (const v of ruleViolations) {
@@ -59,7 +57,7 @@ export async function runAggregatedChecks(prolog, rulesAllowlist, requireAdr = f
59
57
  return violations;
60
58
  }
61
59
  catch (error) {
62
- console.warn("Error running aggregated checks:", error);
63
- return [];
60
+ const message = error instanceof Error ? error.message : String(error);
61
+ throw new Error(`Error running aggregated checks: ${message}`);
64
62
  }
65
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AA2CA,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;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAuPvE"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAgDA,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;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+RvE"}
@@ -16,21 +16,24 @@
16
16
  along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
  */
18
18
  import * as path from "node:path";
19
+ import { extractFromManifest } from "../extractors/manifest.js";
19
20
  import { PrologProcess } from "../prolog.js";
20
21
  import { escapeAtom } from "../prolog/codec.js";
21
22
  import { getStagedFiles } from "../traceability/git-staged.js";
22
23
  import { validateStagedMarkdown } from "../traceability/markdown-validate.js";
23
- import { extractSymbolsFromStagedFile } from "../traceability/symbol-extract.js";
24
+ import { extractSymbolsFromStagedFile, } from "../traceability/symbol-extract.js";
24
25
  import { cleanupTempKb, consultOverlay, createOverlayFacts, createTempKb, } from "../traceability/temp-kb.js";
25
26
  import { formatViolations as formatStagedViolations, validateStagedSymbols, } from "../traceability/validate.js";
26
27
  import { loadConfig } from "../utils/config.js";
27
28
  import { RULES, getEffectiveRules, } from "../utils/rule-registry.js";
28
29
  import { runAggregatedChecks } from "./aggregated-checks.js";
29
30
  import { getCurrentBranch } from "./init-helpers.js";
31
+ import { discoverSourceFiles } from "./sync/discovery.js";
32
+ // implements REQ-006
30
33
  export async function checkCommand(options) {
34
+ let prolog = null;
35
+ let attached = false;
31
36
  try {
32
- // Resolve KB path with priority:
33
- // --kb-path > git branch --show-current > KIBI_BRANCH env > develop > main
34
37
  let resolvedKbPath = "";
35
38
  if (options.kbPath) {
36
39
  resolvedKbPath = options.kbPath;
@@ -51,13 +54,32 @@ export async function checkCommand(options) {
51
54
  // fallback to main if develop isn't present? keep path consistent
52
55
  resolvedKbPath = path.join(process.cwd(), ".kb/branches", branch || "main");
53
56
  }
54
- // If --staged mode requested, run staged-symbol traceability gate.
55
- // We skip creating the main prolog session entirely in this path.
56
57
  if (options.staged) {
57
58
  const minLinks = options.minLinks ? Number(options.minLinks) : 1;
58
59
  let tempCtx = null;
59
60
  try {
60
- // Get staged files
61
+ const config = loadConfig(process.cwd());
62
+ const manifestLookup = new Map();
63
+ const { manifestFiles } = await discoverSourceFiles(process.cwd(), config.paths);
64
+ for (const manifestPath of manifestFiles) {
65
+ try {
66
+ const entries = extractFromManifest(manifestPath);
67
+ for (const entry of entries) {
68
+ // Prefer the per-symbol sourceFile; fall back to entity.source or manifest path
69
+ const sourceFile = entry.sourceFile || entry.entity.source || manifestPath;
70
+ const key = `${sourceFile}:${entry.entity.title}`;
71
+ // Extract requirement links (implements relationships to REQ-*)
72
+ const links = entry.relationships
73
+ .filter((r) => r.type === "implements" &&
74
+ r.to.match(/^[A-Z][A-Z0-9\-_]*$/))
75
+ .map((r) => r.to);
76
+ manifestLookup.set(key, { id: entry.entity.id, links });
77
+ }
78
+ }
79
+ catch {
80
+ // Ignore manifest parsing errors
81
+ }
82
+ }
61
83
  const stagedFiles = getStagedFiles();
62
84
  if (!stagedFiles || stagedFiles.length === 0) {
63
85
  console.log("No staged files found.");
@@ -86,7 +108,7 @@ export async function checkCommand(options) {
86
108
  const allSymbols = [];
87
109
  for (const f of codeFiles) {
88
110
  try {
89
- const symbols = extractSymbolsFromStagedFile(f);
111
+ const symbols = extractSymbolsFromStagedFile(f, manifestLookup);
90
112
  if (symbols?.length) {
91
113
  allSymbols.push(...symbols);
92
114
  }
@@ -105,12 +127,10 @@ export async function checkCommand(options) {
105
127
  }
106
128
  // Create temp KB
107
129
  tempCtx = await createTempKb(resolvedKbPath);
108
- // Write overlay facts THEN consult so Prolog sees the changed_symbol facts
109
130
  const overlayFacts = createOverlayFacts(allSymbols);
110
131
  const fs = await import("node:fs/promises");
111
132
  await fs.writeFile(tempCtx.overlayPath, overlayFacts, "utf8");
112
133
  await consultOverlay(tempCtx);
113
- // Validate staged symbols using the temp KB prolog session
114
134
  const violationsRaw = await validateStagedSymbols({
115
135
  minLinks,
116
136
  prolog: tempCtx.prolog,
@@ -139,7 +159,7 @@ export async function checkCommand(options) {
139
159
  process.exit(1);
140
160
  }
141
161
  }
142
- const prolog = new PrologProcess({ timeout: 120000 });
162
+ prolog = new PrologProcess({ timeout: 120000 });
143
163
  await prolog.start();
144
164
  const kbPathEscaped = escapeAtom(resolvedKbPath);
145
165
  const attachResult = await prolog.query(`kb_attach('${kbPathEscaped}')`);
@@ -148,23 +168,29 @@ export async function checkCommand(options) {
148
168
  console.error(`Error: Failed to attach KB: ${attachResult.error}`);
149
169
  process.exit(1);
150
170
  }
171
+ attached = true;
151
172
  const violations = [];
152
- // Load config to get rule enablement settings
153
173
  const config = loadConfig(process.cwd());
154
174
  const checksConfig = config.checks ?? {
155
175
  rules: Object.fromEntries(RULES.map((r) => [r.name, true])),
156
176
  symbolTraceability: { requireAdr: false },
157
177
  };
158
- // Get effective rules based on config and CLI --rules filter
159
178
  const effectiveRules = getEffectiveRules(checksConfig.rules, options.rules);
160
179
  // Helper to conditionally run a check by name
161
180
  async function runCheck(name, fn, ...args) {
162
181
  if (!effectiveRules.has(name))
163
182
  return;
183
+ if (!prolog) {
184
+ throw new Error("Prolog process not initialized");
185
+ }
164
186
  const res = await fn(prolog, ...args);
165
187
  if (res?.length)
166
188
  violations.push(...res);
167
189
  }
190
+ if (!prolog) {
191
+ throw new Error("Prolog process not initialized");
192
+ }
193
+ const activeProlog = prolog;
168
194
  // Use aggregated checks (single Prolog call) when possible for better performance
169
195
  // This is significantly faster in Bun/Docker environments where one-shot mode
170
196
  // spawns a new Prolog process for each query
@@ -182,7 +208,7 @@ export async function checkCommand(options) {
182
208
  if (canUseAggregated) {
183
209
  // Fast path: single Prolog call returning all violations
184
210
  // Pass the requireAdr option for symbol-traceability
185
- const aggregatedViolations = await runAggregatedChecks(prolog, effectiveRules, checksConfig.symbolTraceability?.requireAdr ?? false);
211
+ const aggregatedViolations = await runAggregatedChecks(activeProlog, effectiveRules, checksConfig.symbolTraceability?.requireAdr ?? false);
186
212
  violations.push(...aggregatedViolations);
187
213
  }
188
214
  else {
@@ -192,16 +218,14 @@ export async function checkCommand(options) {
192
218
  await runCheck("symbol-traceability", (p) => checkSymbolTraceability(p, checksConfig.symbolTraceability?.requireAdr ?? false));
193
219
  await runCheck("no-dangling-refs", checkNoDanglingRefs);
194
220
  await runCheck("no-cycles", checkNoCycles);
195
- const allEntityIds = await getAllEntityIds(prolog);
221
+ const allEntityIds = await getAllEntityIds(activeProlog);
196
222
  if (effectiveRules.has("required-fields")) {
197
- const requiredViolations = await checkRequiredFields(prolog, allEntityIds);
223
+ const requiredViolations = await checkRequiredFields(activeProlog, allEntityIds);
198
224
  violations.push(...requiredViolations);
199
225
  }
200
226
  await runCheck("deprecated-adr-no-successor", checkDeprecatedAdrs);
201
227
  await runCheck("domain-contradictions", checkDomainContradictions);
202
228
  }
203
- await prolog.query("kb_detach");
204
- await prolog.terminate();
205
229
  if (violations.length === 0) {
206
230
  console.log("✓ No violations found. KB is valid.");
207
231
  process.exit(0);
@@ -224,10 +248,23 @@ export async function checkCommand(options) {
224
248
  console.error(`Error: ${message}`);
225
249
  process.exit(1);
226
250
  }
251
+ finally {
252
+ if (prolog) {
253
+ if (attached) {
254
+ try {
255
+ await prolog.query("kb_detach");
256
+ }
257
+ catch { }
258
+ }
259
+ try {
260
+ await prolog.terminate();
261
+ }
262
+ catch { }
263
+ }
264
+ }
227
265
  }
228
266
  async function checkMustPriorityCoverage(prolog) {
229
267
  const violations = [];
230
- // Find all must-priority requirements
231
268
  const mustReqs = await findMustPriorityReqs(prolog);
232
269
  for (const reqId of mustReqs) {
233
270
  const entityResult = await prolog.query(`kb_entity('${reqId}', req, Props)`);
@@ -301,9 +338,7 @@ async function getAllEntityIds(prolog, type) {
301
338
  }
302
339
  async function checkNoDanglingRefs(prolog) {
303
340
  const violations = [];
304
- // Get all entity IDs once
305
341
  const allEntityIds = new Set(await getAllEntityIds(prolog));
306
- // Get all relationships by querying all known relationship types
307
342
  const relTypes = [
308
343
  "depends_on",
309
344
  "verified_by",
@@ -356,7 +391,6 @@ async function checkNoDanglingRefs(prolog) {
356
391
  }
357
392
  async function checkNoCycles(prolog) {
358
393
  const violations = [];
359
- // Get all depends_on relationships
360
394
  const depsResult = await prolog.query("findall([From,To], kb_relationship(depends_on, From, To), Deps)");
361
395
  if (!depsResult.success || !depsResult.bindings.Deps) {
362
396
  return violations;
@@ -370,7 +404,6 @@ async function checkNoCycles(prolog) {
370
404
  if (!content) {
371
405
  return violations;
372
406
  }
373
- // Build adjacency map
374
407
  const graph = new Map();
375
408
  const depMatches = content.matchAll(/\[([^,]+),([^\]]+)\]/g);
376
409
  for (const depMatch of depMatches) {
@@ -384,7 +417,6 @@ async function checkNoCycles(prolog) {
384
417
  fromList.push(to);
385
418
  }
386
419
  }
387
- // DFS to detect cycles
388
420
  const visited = new Set();
389
421
  const recStack = new Set();
390
422
  function hasCycleDFS(node, path) {
@@ -406,7 +438,6 @@ async function checkNoCycles(prolog) {
406
438
  recStack.delete(node);
407
439
  return null;
408
440
  }
409
- // Check each node for cycles
410
441
  for (const node of graph.keys()) {
411
442
  if (!visited.has(node)) {
412
443
  const cyclePath = hasCycleDFS(node, []);
@@ -449,15 +480,12 @@ async function checkRequiredFields(prolog, allEntityIds) {
449
480
  for (const entityId of allEntityIds) {
450
481
  const result = await prolog.query(`kb_entity('${entityId}', Type, Props)`);
451
482
  if (result.success && result.bindings.Props) {
452
- // Parse properties list: [key1=value1, key2=value2, ...]
453
483
  const propsStr = result.bindings.Props;
454
484
  const propKeys = new Set();
455
- // Extract keys from Props
456
485
  const keyMatches = propsStr.matchAll(/(\w+)\s*=/g);
457
486
  for (const match of keyMatches) {
458
487
  propKeys.add(match[1]);
459
488
  }
460
- // Check for missing required fields
461
489
  for (const field of required) {
462
490
  if (!propKeys.has(field)) {
463
491
  violations.push({
@@ -492,7 +520,6 @@ async function checkDeprecatedAdrs(prolog) {
492
520
  .split(",")
493
521
  .map((id) => id.trim().replace(/^'|'$/g, ""));
494
522
  for (const adrId of adrIds) {
495
- // Get source for better error message
496
523
  const entityResult = await prolog.query(`kb_entity('${adrId}', adr, Props)`);
497
524
  let source = "";
498
525
  if (entityResult.success && entityResult.bindings.Props) {
@@ -562,10 +589,8 @@ async function checkSymbolTraceability(prolog, requireAdr) {
562
589
  if (!result.success || !result.bindings.Violations) {
563
590
  return violations;
564
591
  }
565
- // Parse the violations from Prolog format
566
592
  const violationsStr = result.bindings.Violations;
567
593
  if (violationsStr && violationsStr !== "[]") {
568
- // Parse each violation term
569
594
  const violationRegex = /violation\(([^,]+),'?([^',]+)'?,([^,]+),([^,]+),'?([^']*)'?\)/g;
570
595
  let match;
571
596
  do {
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AAmCA,UAAU,YAAY;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CAyKf"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AA2CA,UAAU,YAAY;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CAyKf"}
@@ -23,12 +23,14 @@ import relationshipSchema from "../public/schemas/relationship.js";
23
23
  import { VALID_ENTITY_TYPES } from "../query/service.js";
24
24
  import { resolveActiveBranch } from "../utils/branch-resolver.js";
25
25
  const REL_TYPES = relationshipSchema.properties.type.enum;
26
+ // implements REQ-003
26
27
  export async function queryCommand(type, options) {
28
+ let prolog = null;
29
+ let attached = false;
27
30
  try {
28
- const prolog = new PrologProcess({ timeout: 120000 });
31
+ prolog = new PrologProcess({ timeout: 120000 });
29
32
  await prolog.start();
30
33
  await prolog.query("set_prolog_flag(answer_write_options, [max_depth(0), spacing(next_argument)])");
31
- // Resolve branch: allow non-git repos to use default "main" for query
32
34
  let currentBranch;
33
35
  const branchResult = resolveActiveBranch();
34
36
  if ("error" in branchResult) {
@@ -56,13 +58,13 @@ export async function queryCommand(type, options) {
56
58
  console.error(`Error: Failed to attach KB: ${attachResult.error || "Unknown error"}`);
57
59
  process.exit(1);
58
60
  }
61
+ attached = true;
59
62
  let results = [];
60
- // Query relationships mode
61
63
  if (options.relationships) {
62
64
  const fromId = String(options.relationships);
63
65
  const safeFromId = fromId.replace(/'/g, "''");
64
- // Query all relationship types for the given source ID
65
- const goal = `findall([Type,From,To], (From='${safeFromId}', kb_relationship(Type, From, To)), Results)`;
66
+ const relTypesList = REL_TYPES.join(", ");
67
+ const goal = `findall([Type,From,To], (member(Type, [${relTypesList}]), kb_relationship(Type, '${safeFromId}', To), From='${safeFromId}'), Results)`;
66
68
  const queryResult = await prolog.query(goal);
67
69
  if (queryResult.success && queryResult.bindings.Results) {
68
70
  const rows = parseListOfLists(queryResult.bindings.Results);
@@ -81,18 +83,14 @@ export async function queryCommand(type, options) {
81
83
  REL_TYPES.includes(rel.type));
82
84
  }
83
85
  }
84
- // Query entities mode
85
86
  else if (type || options.source) {
86
- // Validate type if provided
87
87
  if (type && !VALID_ENTITY_TYPES.includes(type)) {
88
- await prolog.query("kb_detach");
89
- await prolog.terminate();
90
88
  console.error(`Error: Invalid type '${type}'. Valid types: ${VALID_ENTITY_TYPES.join(", ")}`);
91
- process.exit(1);
89
+ process.exitCode = 1;
90
+ return;
92
91
  }
93
92
  let goal;
94
93
  if (options.source) {
95
- // Query by source path (substring match)
96
94
  const safeSource = String(options.source).replace(/'/g, "\\'");
97
95
  if (type) {
98
96
  goal = `findall([Id,'${type}',Props], (kb_entities_by_source('${safeSource}', SourceIds), member(Id, SourceIds), kb_entity(Id, '${type}', Props)), Results)`;
@@ -134,14 +132,10 @@ export async function queryCommand(type, options) {
134
132
  }
135
133
  }
136
134
  else {
137
- await prolog.query("kb_detach");
138
- await prolog.terminate();
139
135
  console.error("Error: Must specify entity type, --source, or --relationships option");
140
- process.exit(1);
136
+ process.exitCode = 1;
137
+ return;
141
138
  }
142
- await prolog.query("kb_detach");
143
- await prolog.terminate();
144
- // Apply pagination
145
139
  const limit = Number.parseInt(options.limit || "100");
146
140
  const offset = Number.parseInt(options.offset || "0");
147
141
  const paginated = results.slice(offset, offset + limit);
@@ -152,7 +146,7 @@ export async function queryCommand(type, options) {
152
146
  else {
153
147
  console.log("No entities found");
154
148
  }
155
- process.exit(0);
149
+ return;
156
150
  }
157
151
  // Format output
158
152
  if (options.format === "table") {
@@ -161,12 +155,25 @@ export async function queryCommand(type, options) {
161
155
  else {
162
156
  console.log(JSON.stringify(paginated, null, 2));
163
157
  }
164
- process.exit(0);
165
158
  }
166
159
  catch (error) {
167
160
  const message = error instanceof Error ? error.message : String(error);
168
161
  console.error(`Error: ${message}`);
169
- process.exit(1);
162
+ process.exitCode = 1;
163
+ }
164
+ finally {
165
+ if (prolog) {
166
+ if (attached) {
167
+ try {
168
+ await prolog.query("kb_detach");
169
+ }
170
+ catch { }
171
+ }
172
+ try {
173
+ await prolog.terminate();
174
+ }
175
+ catch { }
176
+ }
170
177
  }
171
178
  }
172
179
  /**
@@ -183,10 +190,11 @@ function outputTable(items, isRelationships) {
183
190
  colWidths: [20, 18, 18],
184
191
  });
185
192
  for (const item of items) {
193
+ const rel = item;
186
194
  table.push([
187
- item.type || "N/A",
188
- item.from?.substring(0, 16) || "N/A",
189
- item.to?.substring(0, 16) || "N/A",
195
+ rel.type || "N/A",
196
+ rel.from.substring(0, 16) || "N/A",
197
+ rel.to.substring(0, 16) || "N/A",
190
198
  ]);
191
199
  }
192
200
  console.log(table.toString());
@@ -197,12 +205,22 @@ function outputTable(items, isRelationships) {
197
205
  colWidths: [18, 10, 40, 12, 30],
198
206
  });
199
207
  for (const entity of items) {
208
+ const record = entity;
209
+ const id = typeof record.id === "string" ? record.id : "N/A";
210
+ const entityType = typeof record.type === "string" ? record.type : "N/A";
211
+ const title = typeof record.title === "string" ? record.title : "N/A";
212
+ const status = typeof record.status === "string" ? record.status : "N/A";
213
+ const tags = Array.isArray(record.tags)
214
+ ? record.tags
215
+ .filter((tag) => typeof tag === "string")
216
+ .join(", ")
217
+ : "";
200
218
  table.push([
201
- entity.id?.substring(0, 16) || "N/A",
202
- entity.type || "N/A",
203
- (entity.title || "N/A").substring(0, 38),
204
- entity.status || "N/A",
205
- (entity.tags || []).join(", ").substring(0, 28) || "",
219
+ id.substring(0, 16),
220
+ entityType,
221
+ title.substring(0, 38),
222
+ status,
223
+ tags.substring(0, 28),
206
224
  ]);
207
225
  }
208
226
  console.log(table.toString());
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAyCjE,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACd,GACL,OAAO,CAAC,WAAW,CAAC,CA4VtB;AAGD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAyCjE,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAGD,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACd,GACL,OAAO,CAAC,WAAW,CAAC,CA4VtB;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -35,6 +35,7 @@ export class SyncError extends Error {
35
35
  this.name = "SyncError";
36
36
  }
37
37
  }
38
+ // implements REQ-003, REQ-007
38
39
  export async function syncCommand(options = {}) {
39
40
  const validateOnly = options.validateOnly ?? false;
40
41
  const rebuild = options.rebuild ?? false;
@@ -73,10 +74,8 @@ export async function syncCommand(options = {}) {
73
74
  }
74
75
  catch { }
75
76
  }
76
- // Load config
77
77
  const config = loadSyncConfig(process.cwd());
78
78
  const paths = config.paths;
79
- // File discovery
80
79
  const { markdownFiles, manifestFiles, relationshipsDir } = await discoverSourceFiles(process.cwd(), paths);
81
80
  if (process.env.KIBI_DEBUG) {
82
81
  try {
@@ -94,21 +93,19 @@ export async function syncCommand(options = {}) {
94
93
  const nowMs = Date.now();
95
94
  const nextHashes = {};
96
95
  const nextSeenAt = {};
97
- // Extract relationships from shard files
98
96
  const shardResults = extractFromRelationshipShards(relationshipsDir);
99
97
  const allRelationships = flattenRelationships(shardResults);
100
98
  const changedMarkdownFiles = [];
101
99
  const changedManifestFiles = [];
102
- // Detect changed files
103
100
  for (const file of sourceFiles) {
104
101
  try {
105
102
  const key = toCacheKey(file);
106
103
  const hash = hashFile(file);
107
104
  const lastSeen = syncCache.seenAt[key];
108
105
  const lastSeenMs = lastSeen ? Date.parse(lastSeen) : Number.NaN;
109
- const expired = Number.isNaN(lastSeenMs)
110
- ? false
111
- : nowMs - lastSeenMs > SYNC_CACHE_TTL_MS;
106
+ const expired = !lastSeen ||
107
+ Number.isNaN(lastSeenMs) ||
108
+ nowMs - lastSeenMs > SYNC_CACHE_TTL_MS;
112
109
  nextHashes[key] = hash;
113
110
  nextSeenAt[key] = nowIso;
114
111
  const isChanged = expired || syncCache.hashes[key] !== hash || validateOnly || rebuild;
@@ -126,7 +123,8 @@ export async function syncCommand(options = {}) {
126
123
  console.warn(`Warning: Failed to hash ${file}: ${message}`);
127
124
  }
128
125
  }
129
- // Content extraction
126
+ const performedFullReindex = changedMarkdownFiles.length === markdownFiles.length &&
127
+ changedManifestFiles.length === manifestFiles.length;
130
128
  const { results, failedCacheKeys, errors } = await processExtractions(changedMarkdownFiles, changedManifestFiles, validateOnly);
131
129
  // Collect INVALID_AUTHORING diagnostics
132
130
  for (const err of errors) {
@@ -157,7 +155,6 @@ export async function syncCommand(options = {}) {
157
155
  process.exit(0);
158
156
  }
159
157
  }
160
- // Refresh symbol manifest coordinates
161
158
  for (const file of manifestFiles) {
162
159
  try {
163
160
  await refreshManifestCoordinates(file, process.cwd());
@@ -167,7 +164,6 @@ export async function syncCommand(options = {}) {
167
164
  console.warn(`Warning: Failed to refresh symbol coordinates in ${file}: ${message}`);
168
165
  }
169
166
  }
170
- // Early exit if no changes
171
167
  if (results.length === 0 && allRelationships.length === 0 && !rebuild) {
172
168
  const evictedHashes = {};
173
169
  const evictedSeenAt = {};
@@ -176,7 +172,7 @@ export async function syncCommand(options = {}) {
176
172
  continue;
177
173
  }
178
174
  evictedHashes[key] = hash;
179
- evictedSeenAt[key] = nextHashes[key] ?? nowIso;
175
+ evictedSeenAt[key] = nextSeenAt[key] ?? nowIso;
180
176
  }
181
177
  writeSyncCache(cachePath, {
182
178
  version: SYNC_CACHE_VERSION,
@@ -186,7 +182,6 @@ export async function syncCommand(options = {}) {
186
182
  console.log("✓ Imported 0 entities, 0 relationships (no changes)");
187
183
  process.exit(0);
188
184
  }
189
- // Staging setup
190
185
  const livePath = path.join(process.cwd(), `.kb/branches/${currentBranch}`);
191
186
  const kbExists = existsSync(livePath);
192
187
  if (!kbExists && !rebuild) {
@@ -194,7 +189,6 @@ export async function syncCommand(options = {}) {
194
189
  }
195
190
  const stagingPath = path.join(process.cwd(), `.kb/branches/${currentBranch}.staging`);
196
191
  await prepareStagingEnvironment(stagingPath, livePath, rebuild);
197
- // Persistence to KB
198
192
  try {
199
193
  const prolog = new PrologProcess({ timeout: 120000 });
200
194
  await prolog.start();
@@ -204,7 +198,10 @@ export async function syncCommand(options = {}) {
204
198
  throw new SyncError(`Failed to attach to staging KB: ${attachResult.error || "Unknown error"}`);
205
199
  }
206
200
  const entityIds = new Set();
207
- // Validate and filter dangling relationships
201
+ for (const { entity } of results) {
202
+ entityCounts[entity.type] = (entityCounts[entity.type] || 0) + 1;
203
+ }
204
+ const { entityCount, kbModified: entitiesModified } = await persistEntities(prolog, results, entityIds);
208
205
  const validationErrors = validateRelationships(allRelationships, entityIds);
209
206
  if (validationErrors.length > 0) {
210
207
  console.warn(`Warning: ${validationErrors.length} dangling relationship(s) found`);
@@ -214,24 +211,19 @@ export async function syncCommand(options = {}) {
214
211
  }
215
212
  const danglingKeys = new Set(validationErrors.map(({ relationship: r }) => `${r.type}|${r.from}|${r.to}`));
216
213
  const validRelationships = allRelationships.filter((r) => !danglingKeys.has(`${r.type}|${r.from}|${r.to}`));
217
- // Track entity counts by type
218
- for (const { entity } of results) {
219
- entityCounts[entity.type] = (entityCounts[entity.type] || 0) + 1;
220
- }
221
- // Persist entities
222
- const { entityCount, kbModified: entitiesModified } = await persistEntities(prolog, results, entityIds);
223
214
  // Persist relationships
224
215
  const { relationshipCount, kbModified: relationshipsModified } = await persistRelationships(prolog, results, validRelationships);
225
216
  const kbModified = entitiesModified || relationshipsModified;
226
217
  if (kbModified) {
227
218
  prolog.invalidateCache();
228
219
  }
229
- await prolog.query("kb_save");
220
+ const saveResult = await prolog.query("kb_save");
221
+ if (!saveResult.success) {
222
+ throw new SyncError(`Failed to save staging KB: ${saveResult.error || "Unknown error"}`);
223
+ }
230
224
  await prolog.query("kb_detach");
231
225
  await prolog.terminate();
232
- // Publish staging to live
233
226
  atomicPublish(stagingPath, livePath);
234
- // Update cache
235
227
  const evictedHashes = {};
236
228
  const evictedSeenAt = {};
237
229
  for (const [key, hash] of Object.entries(nextHashes)) {
@@ -239,7 +231,7 @@ export async function syncCommand(options = {}) {
239
231
  continue;
240
232
  }
241
233
  evictedHashes[key] = hash;
242
- evictedSeenAt[key] = nextHashes[key] ?? nowIso;
234
+ evictedSeenAt[key] = nextSeenAt[key] ?? nowIso;
243
235
  }
244
236
  const liveCachePath = path.join(livePath, "sync-cache.json");
245
237
  writeSyncCache(liveCachePath, {
@@ -248,7 +240,9 @@ export async function syncCommand(options = {}) {
248
240
  seenAt: evictedSeenAt,
249
241
  });
250
242
  published = true;
251
- if (markdownFiles.length > 0 && entityCount < markdownFiles.length) {
243
+ if (performedFullReindex &&
244
+ markdownFiles.length > 0 &&
245
+ entityCount < markdownFiles.length) {
252
246
  diagnostics.push(createDocsNotIndexedDiagnostic(markdownFiles.length, entityCount));
253
247
  }
254
248
  console.log(`✓ Imported ${entityCount} entities, ${relationshipCount} relationships`);
@@ -296,5 +290,4 @@ export async function syncCommand(options = {}) {
296
290
  throw error;
297
291
  }
298
292
  }
299
- // Export for use by modules that need these functions
300
293
  export { normalizeMarkdownPath } from "./sync/discovery.js";
@@ -1 +1 @@
1
- {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,kBAAkB,GAC1B,2BAA2B,GAC3B,YAAY,GACZ,kBAAkB,GAClB,mBAAmB,GACnB,YAAY,GACZ,kBAAkB,GAClB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,eAAe,GACf,eAAe,GACf,mBAAmB,GACnB,gBAAgB,GAChB,cAAc,GACd,eAAe,CAAC;AAEpB;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,GACd,UAAU,CASZ;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,UAAU,CAOZ;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,UAAU,CAQZ;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EAAE,GACtB,UAAU,CAQZ;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAmD9D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,UAAU,EAAE,GACxB,KAAK,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,CAQD"}
1
+ {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,kBAAkB,GAC1B,2BAA2B,GAC3B,YAAY,GACZ,kBAAkB,GAClB,mBAAmB,GACnB,YAAY,GACZ,kBAAkB,GAClB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,eAAe,GACf,eAAe,GACf,mBAAmB,GACnB,gBAAgB,GAChB,cAAc,GACd,eAAe,CAAC;AAEpB;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,GACd,UAAU,CASZ;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,UAAU,CAOZ;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,UAAU,CAQZ;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EAAE,GACtB,UAAU,CAQZ;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAiD9D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,CAQD"}
@@ -77,13 +77,11 @@ export function formatSyncSummary(summary) {
77
77
  }
78
78
  lines.push(`Total Relationships: ${summary.relationshipCount}`);
79
79
  lines.push("");
80
- // Status
81
80
  lines.push(`Status: ${summary.success ? "✓ Success" : "✗ Failed"}`);
82
81
  lines.push(`Published: ${summary.published ? "Yes" : "No"}`);
83
82
  if (summary.durationMs !== undefined) {
84
83
  lines.push(`Duration: ${summary.durationMs}ms`);
85
84
  }
86
- // Failures
87
85
  if (summary.failures.length > 0) {
88
86
  lines.push("");
89
87
  lines.push(`Failures (${summary.failures.length}):`);
@@ -20,6 +20,8 @@ export interface ExtractedRelationship {
20
20
  export interface ExtractionResult {
21
21
  entity: ExtractedEntity;
22
22
  relationships: ExtractedRelationship[];
23
+ /** The per-symbol source code file, distinct from the manifest file path. */
24
+ sourceFile?: string;
23
25
  }
24
26
  export declare class ManifestError extends Error {
25
27
  filePath: string;
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/extractors/manifest.ts"],"names":[],"mappings":"AAsBA,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;CACxC;AAED,qBAAa,aAAc,SAAQ,KAAK;IAG7B,QAAQ,EAAE,MAAM;gBADvB,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM;CAK1B;AAuBD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA4FxE"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/extractors/manifest.ts"],"names":[],"mappings":"AAsBA,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;AAwBD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA6FxE"}
@@ -94,6 +94,7 @@ export function extractFromManifest(filePath) {
94
94
  text_ref: symbol.text_ref,
95
95
  },
96
96
  relationships,
97
+ sourceFile: symbol.sourceFile ?? symbol.source,
97
98
  };
98
99
  });
99
100
  }