kibi-cli 0.6.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/commands/check.d.ts.map +1 -1
  2. package/dist/commands/check.js +18 -0
  3. package/dist/commands/init-helpers.d.ts +1 -0
  4. package/dist/commands/init-helpers.d.ts.map +1 -1
  5. package/dist/commands/init-helpers.js +39 -6
  6. package/dist/commands/init.d.ts.map +1 -1
  7. package/dist/commands/init.js +2 -1
  8. package/dist/commands/sync/manifest.d.ts +1 -0
  9. package/dist/commands/sync/manifest.d.ts.map +1 -1
  10. package/dist/commands/sync/manifest.js +1 -1
  11. package/dist/commands/sync/persistence.d.ts.map +1 -1
  12. package/dist/commands/sync/persistence.js +4 -2
  13. package/dist/commands/sync/staging.d.ts +3 -0
  14. package/dist/commands/sync/staging.d.ts.map +1 -1
  15. package/dist/commands/sync/staging.js +58 -1
  16. package/dist/commands/sync.d.ts +18 -1
  17. package/dist/commands/sync.d.ts.map +1 -1
  18. package/dist/commands/sync.js +19 -4
  19. package/dist/extractors/markdown.d.ts +2 -0
  20. package/dist/extractors/markdown.d.ts.map +1 -1
  21. package/dist/extractors/symbols-coordinator.d.ts +34 -0
  22. package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
  23. package/dist/extractors/symbols-coordinator.js +70 -1
  24. package/dist/extractors/symbols-ts.d.ts +2 -0
  25. package/dist/extractors/symbols-ts.d.ts.map +1 -1
  26. package/dist/extractors/symbols-ts.js +108 -1
  27. package/dist/public/brief-config.d.ts +4 -0
  28. package/dist/public/brief-config.d.ts.map +1 -0
  29. package/dist/public/brief-config.js +21 -0
  30. package/dist/public/extractors/symbols-coordinator.d.ts +1 -1
  31. package/dist/public/extractors/symbols-coordinator.d.ts.map +1 -1
  32. package/dist/public/extractors/symbols-coordinator.js +1 -1
  33. package/dist/public/operational-artifacts.d.ts +2 -0
  34. package/dist/public/operational-artifacts.d.ts.map +1 -0
  35. package/dist/public/operational-artifacts.js +4 -0
  36. package/dist/search-ranking.d.ts.map +1 -1
  37. package/dist/search-ranking.js +132 -25
  38. package/dist/utils/config.d.ts +18 -3
  39. package/dist/utils/config.d.ts.map +1 -1
  40. package/dist/utils/config.js +39 -0
  41. package/dist/utils/rule-registry.d.ts.map +1 -1
  42. package/dist/utils/rule-registry.js +6 -0
  43. package/package.json +10 -2
  44. package/schema/config.json +73 -0
  45. package/schema/entities.pl +1 -0
  46. package/schema/relationships.pl +4 -0
  47. package/src/public/brief-config.ts +25 -0
  48. package/src/public/extractors/symbols-coordinator.ts +7 -0
  49. package/src/public/operational-artifacts.ts +5 -0
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAuDA,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;AA+GD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgR/B"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAuDA,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;AA+GD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkR/B"}
@@ -277,6 +277,7 @@ export async function checkCommand(options) {
277
277
  "deprecated-adr-no-successor",
278
278
  "domain-contradictions",
279
279
  "strict-fact-shape",
280
+ "strict-req-fact-pairing",
280
281
  ];
281
282
  const canUseAggregated = Array.from(effectiveRules).every((r) => supportedRules.includes(r));
282
283
  if (canUseAggregated) {
@@ -300,6 +301,7 @@ export async function checkCommand(options) {
300
301
  await runCheck("deprecated-adr-no-successor", checkDeprecatedAdrs);
301
302
  await runCheck("domain-contradictions", checkDomainContradictions);
302
303
  await runCheck("strict-fact-shape", checkStrictFactShape);
304
+ await runCheck("strict-req-fact-pairing", checkStrictReqFactPairing);
303
305
  }
304
306
  if (violations.length === 0) {
305
307
  console.log("✓ No violations found. KB is valid.");
@@ -640,6 +642,22 @@ async function checkStrictFactShape(prolog) {
640
642
  }
641
643
  return violations;
642
644
  }
645
+ async function checkStrictReqFactPairing(prolog) {
646
+ const violations = [];
647
+ const result = await prolog.query(`findall(violation(Rule, EntityId, Desc, Sugg, Src),
648
+ checks:strict_req_fact_pairing_violation(violation(Rule, EntityId, Desc, Sugg, Src)),
649
+ Violations)`);
650
+ if (!result.success || !result.bindings.Violations) {
651
+ return violations;
652
+ }
653
+ const violationsStr = result.bindings.Violations;
654
+ if (violationsStr && violationsStr !== "[]") {
655
+ for (const v of parseViolationRows(violationsStr)) {
656
+ violations.push(v);
657
+ }
658
+ }
659
+ return violations;
660
+ }
643
661
  async function checkSymbolCoverage(prolog) {
644
662
  const violations = [];
645
663
  const uncoveredResult = await prolog.query("setof(Symbol, symbol_no_req_coverage(Symbol, _), Symbols)");
@@ -2,6 +2,7 @@ export declare function getCurrentBranch(cwd?: string): Promise<string>;
2
2
  export declare function createKbDirectoryStructure(kbDir: string, currentBranch: string): void;
3
3
  export declare function createConfigFile(kbDir: string): void;
4
4
  export declare function updateGitIgnore(cwd: string): void;
5
+ export declare function ensureSymbolsManifestFile(cwd: string): void;
5
6
  export declare function copySchemaFiles(kbDir: string, schemaSourceDir: string): Promise<void>;
6
7
  export declare function installHook(hookPath: string, content: string): void;
7
8
  export declare function installGitHooks(gitDir: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"init-helpers.d.ts","sourceRoot":"","sources":["../../src/commands/init-helpers.ts"],"names":[],"mappings":"AAuFA,wBAAsB,gBAAgB,CACpC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,IAAI,CAQN;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAMpD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAajD;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAYf;AASD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAkCnE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAiBpD"}
1
+ {"version":3,"file":"init-helpers.d.ts","sourceRoot":"","sources":["../../src/commands/init-helpers.ts"],"names":[],"mappings":"AAuGA,wBAAsB,gBAAgB,CACpC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,IAAI,CAQN;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAMpD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAsBjD;AAGD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAU3D;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAYf;AASD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAkCnE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAiBpD"}
@@ -20,6 +20,7 @@ import * as path from "node:path";
20
20
  import fg from "fast-glob";
21
21
  import { getBranchDiagnostic, resolveActiveBranch, } from "../utils/branch-resolver.js";
22
22
  import { DEFAULT_CONFIG } from "../utils/config.js";
23
+ import { SYMBOLS_MANIFEST_COMMENT_BLOCK } from "./sync/manifest.js";
23
24
  const POST_CHECKOUT_HOOK = `#!/bin/sh
24
25
  # post-checkout hook for kibi
25
26
  # Parameters: old_ref new_ref branch_flag
@@ -67,6 +68,21 @@ const PRE_COMMIT_HOOK = `#!/bin/sh
67
68
  # The OpenCode plugin remains advisory and must not replace this gate.
68
69
 
69
70
  set -e
71
+
72
+ symbols_manifest="documentation/symbols.yaml"
73
+
74
+ if [ ! -f "$symbols_manifest" ]; then
75
+ echo "Kibi symbols manifest is missing: $symbols_manifest" >&2
76
+ echo "Run 'kibi init' to create it, then stage and commit it." >&2
77
+ exit 1
78
+ fi
79
+
80
+ if ! git diff --quiet -- "$symbols_manifest"; then
81
+ echo "Kibi symbols manifest has unstaged changes: $symbols_manifest" >&2
82
+ echo "Stage and commit documentation/symbols.yaml with the code changes that refreshed it." >&2
83
+ exit 1
84
+ fi
85
+
70
86
  kibi check --staged
71
87
  `;
72
88
  export async function getCurrentBranch(cwd = process.cwd()) {
@@ -91,17 +107,34 @@ export function createConfigFile(kbDir) {
91
107
  console.log("✓ Created config.json with default paths");
92
108
  }
93
109
  export function updateGitIgnore(cwd) {
110
+ // implements REQ-001
94
111
  const gitignorePath = path.join(cwd, ".gitignore");
95
112
  const gitignoreContent = existsSync(gitignorePath)
96
113
  ? readFileSync(gitignorePath, "utf8")
97
114
  : "";
98
- if (!gitignoreContent.includes(".kb/")) {
99
- const newContent = gitignoreContent
100
- ? `${gitignoreContent.trimEnd()}\n.kb/\n`
101
- : ".kb/\n";
102
- writeFileSync(gitignorePath, newContent);
103
- console.log("✓ Added .kb/ to .gitignore");
115
+ const ensureEntry = (current, entry) => {
116
+ if (current.includes(entry)) {
117
+ return current;
118
+ }
119
+ return current ? `${current.trimEnd()}\n${entry}\n` : `${entry}\n`;
120
+ };
121
+ const updatedWithKb = ensureEntry(gitignoreContent, ".kb/");
122
+ const updatedContent = ensureEntry(updatedWithKb, ".kb/briefs/");
123
+ if (updatedContent !== gitignoreContent) {
124
+ writeFileSync(gitignorePath, updatedContent);
125
+ console.log("✓ Added .kb/ and .kb/briefs/ to .gitignore");
126
+ }
127
+ }
128
+ // implements REQ-003
129
+ export function ensureSymbolsManifestFile(cwd) {
130
+ const symbolsRelPath = DEFAULT_CONFIG.paths.symbols ?? "documentation/symbols.yaml";
131
+ const symbolsPath = path.join(cwd, symbolsRelPath);
132
+ if (existsSync(symbolsPath)) {
133
+ return;
104
134
  }
135
+ mkdirSync(path.dirname(symbolsPath), { recursive: true });
136
+ writeFileSync(symbolsPath, `${SYMBOLS_MANIFEST_COMMENT_BLOCK}symbols: []\n`);
137
+ console.log(`✓ Created ${symbolsRelPath}`);
105
138
  }
106
139
  export async function copySchemaFiles(kbDir, schemaSourceDir) {
107
140
  const schemaFiles = await fg("*.pl", {
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAiCA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAGD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA6D/B"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAkCA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAGD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA+D/B"}
@@ -19,7 +19,7 @@ import { existsSync } from "node:fs";
19
19
  import * as path from "node:path";
20
20
  import { fileURLToPath } from "node:url";
21
21
  import { resolveActiveBranch } from "../utils/branch-resolver.js";
22
- import { copySchemaFiles, createConfigFile, createKbDirectoryStructure, installGitHooks, updateGitIgnore, } from "./init-helpers.js";
22
+ import { copySchemaFiles, createConfigFile, createKbDirectoryStructure, ensureSymbolsManifestFile, installGitHooks, updateGitIgnore, } from "./init-helpers.js";
23
23
  const __filename = fileURLToPath(import.meta.url);
24
24
  const __dirname = path.dirname(__filename);
25
25
  // implements REQ-003
@@ -58,6 +58,7 @@ export async function initCommand(options) {
58
58
  else {
59
59
  console.log("✓ .kb/ directory already exists, skipping creation");
60
60
  }
61
+ ensureSymbolsManifestFile(process.cwd());
61
62
  if (options.hooks) {
62
63
  const gitDir = path.join(process.cwd(), ".git");
63
64
  if (!existsSync(gitDir)) {
@@ -9,6 +9,7 @@ interface ManifestDeps {
9
9
  readFileSync: typeof readFileSync;
10
10
  writeFileSync: typeof writeFileSync;
11
11
  }
12
+ export declare const SYMBOLS_MANIFEST_COMMENT_BLOCK = "# symbols.yaml\n# AUTHORED fields (edit freely):\n# id, title, sourceFile, links, status, tags, owner, priority\n# GENERATED fields (never edit manually \u2014 overwritten by kibi sync and kb.symbols.refresh):\n# sourceLine, sourceColumn, sourceEndLine, sourceEndColumn, coordinatesGeneratedAt\n# Run `kibi sync` or call the `kb.symbols.refresh` MCP tool to refresh coordinates.\n";
12
13
  export declare function refreshManifestCoordinates(manifestPath: string, workspaceRoot: string, deps?: Partial<ManifestDeps>): Promise<void>;
13
14
  export declare function hasAllGeneratedCoordinates(entry: ManifestSymbolEntry): boolean;
14
15
  export declare function isEligibleForCoordinateRefresh(sourceFile: string | undefined, workspaceRoot: string, deps?: Partial<ManifestDeps>): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/manifest.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAElE,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EACL,KAAK,mBAAmB,EACxB,uBAAuB,EACxB,MAAM,yCAAyC,CAAC;AAEjD,UAAU,YAAY;IACpB,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,aAAa,EAAE,OAAO,aAAa,CAAC;CACrC;AAyCD,wBAAsB,0BAA0B,CAE9C,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,OAAO,CAAC,IAAI,CAAC,CA8Ef;AAED,wBAAgB,0BAA0B,CAExC,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAST;AAED,wBAAgB,8BAA8B,CAE5C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,OAAO,CAUT"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/manifest.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAElE,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EACL,KAAK,mBAAmB,EACxB,uBAAuB,EACxB,MAAM,yCAAyC,CAAC;AAEjD,UAAU,YAAY;IACpB,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,aAAa,EAAE,OAAO,aAAa,CAAC;CACrC;AAcD,eAAO,MAAM,8BAA8B,qYAM1C,CAAC;AAqBF,wBAAsB,0BAA0B,CAE9C,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,OAAO,CAAC,IAAI,CAAC,CA8Ef;AAED,wBAAgB,0BAA0B,CAExC,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAST;AAED,wBAAgB,8BAA8B,CAE5C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,OAAO,CAUT"}
@@ -30,7 +30,7 @@ function resolveDeps(overrides) {
30
30
  ...overrides,
31
31
  };
32
32
  }
33
- const SYMBOLS_MANIFEST_COMMENT_BLOCK = `# symbols.yaml
33
+ export const SYMBOLS_MANIFEST_COMMENT_BLOCK = `# symbols.yaml
34
34
  # AUTHORED fields (edit freely):
35
35
  # id, title, sourceFile, links, status, tags, owner, priority
36
36
  # GENERATED fields (never edit manually — overwritten by kibi sync and kb.symbols.refresh):
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/persistence.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAEV,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA0ErD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAsB,eAAe,CAEnC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GACrB,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAoEvD;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,kBAAkB,EAAE,qBAAqB,EAAE,GAC1C,OAAO,CAAC;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAiI7D"}
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/persistence.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAEV,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA0ErD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAsB,eAAe,CAEnC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GACrB,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAqEvD;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,kBAAkB,EAAE,qBAAqB,EAAE,GAC1C,OAAO,CAAC;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAiI7D"}
@@ -98,10 +98,10 @@ prolog, results, entityIds) {
98
98
  }
99
99
  }
100
100
  }
101
- for (const { entity } of results) {
101
+ for (const { entity, sourceFile } of results) {
102
102
  entityIds.add(entity.id);
103
103
  }
104
- for (const { entity } of results) {
104
+ for (const { entity, sourceFile } of results) {
105
105
  try {
106
106
  const props = [
107
107
  `id=${toPrologAtom(entity.id)}`,
@@ -123,6 +123,8 @@ prolog, results, entityIds) {
123
123
  props.push(`severity=${toPrologAtom(entity.severity)}`);
124
124
  if (entity.text_ref)
125
125
  props.push(`text_ref=${toPrologString(entity.text_ref)}`);
126
+ if (sourceFile)
127
+ props.push(`sourceFile=${toPrologString(sourceFile)}`);
126
128
  // Add typed fact fields for fact entities
127
129
  if (entity.type === "fact") {
128
130
  const factFields = serializeTypedFactFields(entity);
@@ -8,11 +8,14 @@ interface StagingDeps {
8
8
  cwd: () => string;
9
9
  existsSync: typeof existsSync;
10
10
  fg: typeof fg;
11
+ isProcessAlive: (pid: number) => boolean;
11
12
  mkdirSync: typeof mkdirSync;
12
13
  moduleDir: string;
13
14
  renameSync: typeof renameSync;
14
15
  rmSync: typeof rmSync;
15
16
  }
17
+ export declare function createUniqueStagingPath(currentBranch: string, rootDir: string, pid?: number, now?: number): string;
18
+ export declare function cleanupAbandonedStagingDirectories(stagingPath: string, deps?: Partial<StagingDeps>): Promise<void>;
16
19
  export declare function prepareStagingEnvironment(stagingPath: string, livePath: string, rebuild: boolean, deps?: Partial<StagingDeps>): Promise<void>;
17
20
  export declare function atomicPublish(stagingPath: string, livePath: string, deps?: Partial<StagingDeps>): void;
18
21
  export declare function cleanupStaging(stagingPath: string, deps?: Partial<StagingDeps>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"staging.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/staging.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,UAAU,WAAW;IACnB,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,EAAE,EAAE,OAAO,EAAE,CAAC;IACd,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,MAAM,EAAE,OAAO,MAAM,CAAC;CACvB;AAiBD,wBAAsB,yBAAyB,CAE7C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CAaf;AA0CD,wBAAgB,aAAa,CAE3B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC1B,IAAI,CAeN;AAED,wBAAgB,cAAc,CAE5B,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC1B,IAAI,CAKN"}
1
+ {"version":3,"file":"staging.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/staging.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,UAAU,WAAW;IACnB,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,EAAE,EAAE,OAAO,EAAE,CAAC;IACd,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,MAAM,EAAE,OAAO,MAAM,CAAC;CACvB;AA8BD,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACf,GAAG,SAAc,EACjB,GAAG,SAAa,GACf,MAAM,CAOR;AAGD,wBAAsB,kCAAkC,CACtD,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CAkDf;AAED,wBAAsB,yBAAyB,CAE7C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CAaf;AA0CD,wBAAgB,aAAa,CAE3B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC1B,IAAI,CAeN;AAED,wBAAgB,cAAc,CAE5B,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC1B,IAAI,CAKN"}
@@ -27,6 +27,17 @@ function resolveDeps(overrides) {
27
27
  cwd: () => process.cwd(),
28
28
  existsSync,
29
29
  fg,
30
+ isProcessAlive: (pid) => {
31
+ try {
32
+ process.kill(pid, 0);
33
+ return true;
34
+ }
35
+ catch (error) {
36
+ return !(error instanceof Error &&
37
+ "code" in error &&
38
+ error.code === "ESRCH");
39
+ }
40
+ },
30
41
  mkdirSync,
31
42
  moduleDir: import.meta.dirname,
32
43
  renameSync,
@@ -34,11 +45,54 @@ function resolveDeps(overrides) {
34
45
  ...overrides,
35
46
  };
36
47
  }
48
+ // implements REQ-003
49
+ export function createUniqueStagingPath(currentBranch, rootDir, pid = process.pid, now = Date.now()) {
50
+ return path.join(rootDir, ".kb", "branches", `${currentBranch}.staging.${pid}.${now}`);
51
+ }
52
+ // implements REQ-003
53
+ export async function cleanupAbandonedStagingDirectories(stagingPath, deps) {
54
+ const resolved = resolveDeps(deps);
55
+ const stagingDir = path.dirname(stagingPath);
56
+ const stagingBase = path.basename(stagingPath);
57
+ const match = /^(?<branch>.+)\.staging\.(?<pid>\d+)\.(?<timestamp>\d+)$/.exec(stagingBase);
58
+ if (!match?.groups) {
59
+ return;
60
+ }
61
+ const branch = match.groups.branch;
62
+ if (!branch) {
63
+ return;
64
+ }
65
+ const candidates = await resolved.fg(`${branch}.staging.*`, {
66
+ cwd: stagingDir,
67
+ absolute: true,
68
+ onlyDirectories: true,
69
+ suppressErrors: true,
70
+ });
71
+ for (const candidate of candidates) {
72
+ if (candidate === stagingPath) {
73
+ continue;
74
+ }
75
+ const candidateBase = path.basename(candidate);
76
+ const candidateMatch = new RegExp(`^${escapeRegex(branch)}\\.staging\\.(\\d+)\\.(\\d+)$`).exec(candidateBase);
77
+ if (!candidateMatch) {
78
+ continue;
79
+ }
80
+ const candidatePidText = candidateMatch[1];
81
+ if (!candidatePidText) {
82
+ continue;
83
+ }
84
+ const candidatePid = Number.parseInt(candidatePidText, 10);
85
+ if (!Number.isFinite(candidatePid) || resolved.isProcessAlive(candidatePid)) {
86
+ continue;
87
+ }
88
+ cleanupStaging(candidate, resolved);
89
+ }
90
+ }
37
91
  export async function prepareStagingEnvironment(
38
92
  // implements REQ-003
39
93
  stagingPath, livePath, rebuild, deps) {
40
94
  const resolved = resolveDeps(deps);
41
- // Cleanup any existing staging directory
95
+ await cleanupAbandonedStagingDirectories(stagingPath, resolved);
42
96
  cleanupStaging(stagingPath, resolved);
43
97
  resolved.mkdirSync(stagingPath, { recursive: true });
44
98
  if (!rebuild && resolved.existsSync(livePath)) {
@@ -107,3 +161,6 @@ stagingPath, deps) {
107
161
  resolved.rmSync(stagingPath, { recursive: true, force: true });
108
162
  }
109
163
  }
164
+ function escapeRegex(value) {
165
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
166
+ }
@@ -1,13 +1,30 @@
1
1
  import type { SyncSummary } from "../diagnostics.js";
2
+ import { PrologProcess } from "../prolog.js";
2
3
  export declare class SyncError extends Error {
3
4
  constructor(message: string);
4
5
  }
5
6
  export interface SyncResult extends SyncSummary {
6
7
  exitCode?: number;
7
8
  }
9
+ interface SyncCommandRuntimeContext {
10
+ currentBranch: string;
11
+ livePath: string;
12
+ rebuild: boolean;
13
+ stagingPath: string;
14
+ validateOnly: boolean;
15
+ }
16
+ interface SyncCommandRuntime {
17
+ afterAttach?: (context: SyncCommandRuntimeContext) => Promise<void> | void;
18
+ beforeSave?: (context: SyncCommandRuntimeContext & {
19
+ kbModified: boolean;
20
+ }) => Promise<void> | void;
21
+ createProlog?: (options: {
22
+ timeout: number;
23
+ }) => PrologProcess;
24
+ }
8
25
  export declare function syncCommand(options?: {
9
26
  validateOnly?: boolean;
10
27
  rebuild?: boolean;
11
- }): Promise<SyncResult>;
28
+ }, runtime?: SyncCommandRuntime): Promise<SyncResult>;
12
29
  export { normalizeMarkdownPath } from "./sync/discovery.js";
13
30
  //# sourceMappingURL=sync.d.ts.map
@@ -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;AA0CjE,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAGD,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAGD,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1D,OAAO,CAAC,UAAU,CAAC,CAqarB;AAED,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;AAejE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AA4B7C,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAGD,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,yBAAyB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,CACX,OAAO,EAAE,yBAAyB,GAAG;QAAE,UAAU,EAAE,OAAO,CAAA;KAAE,KACzD,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,aAAa,CAAC;CAChE;AAGD,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,EAC3D,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CAmbrB;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -29,7 +29,7 @@ import { discoverSourceFiles, } from "./sync/discovery.js";
29
29
  import { processExtractions } from "./sync/extraction.js";
30
30
  import { refreshManifestCoordinates } from "./sync/manifest.js";
31
31
  import { persistEntities, persistRelationships } from "./sync/persistence.js";
32
- import { atomicPublish, cleanupStaging, prepareStagingEnvironment, } from "./sync/staging.js";
32
+ import { atomicPublish, cleanupStaging, createUniqueStagingPath, prepareStagingEnvironment, } from "./sync/staging.js";
33
33
  export class SyncError extends Error {
34
34
  constructor(message) {
35
35
  super(message);
@@ -37,7 +37,7 @@ export class SyncError extends Error {
37
37
  }
38
38
  }
39
39
  // implements REQ-003, REQ-007
40
- export async function syncCommand(options = {}) {
40
+ export async function syncCommand(options = {}, runtime = {}) {
41
41
  const validateOnly = options.validateOnly ?? false;
42
42
  const rebuild = options.rebuild ?? false;
43
43
  const startTime = Date.now();
@@ -45,6 +45,7 @@ export async function syncCommand(options = {}) {
45
45
  const entityCounts = {};
46
46
  let published = false;
47
47
  let currentBranch;
48
+ let stagingPath;
48
49
  const getCurrentCommit = () => {
49
50
  try {
50
51
  return execSync("git rev-parse HEAD", {
@@ -199,16 +200,25 @@ export async function syncCommand(options = {}) {
199
200
  if (!kbExists && !rebuild) {
200
201
  diagnostics.push(createKbMissingDiagnostic(currentBranch, livePath));
201
202
  }
202
- const stagingPath = path.join(process.cwd(), `.kb/branches/${currentBranch}.staging`);
203
+ stagingPath = createUniqueStagingPath(currentBranch, process.cwd());
204
+ const runtimeContext = {
205
+ currentBranch,
206
+ livePath,
207
+ rebuild,
208
+ stagingPath,
209
+ validateOnly,
210
+ };
203
211
  await prepareStagingEnvironment(stagingPath, livePath, rebuild);
204
212
  try {
205
- const prolog = new PrologProcess({ timeout: 120000 });
213
+ const prolog = runtime.createProlog?.({ timeout: 120000 }) ??
214
+ new PrologProcess({ timeout: 120000 });
206
215
  await prolog.start();
207
216
  const attachResult = await prolog.query(`kb_attach('${stagingPath}')`);
208
217
  if (!attachResult.success) {
209
218
  await prolog.terminate();
210
219
  throw new SyncError(`Failed to attach to staging KB: ${attachResult.error || "Unknown error"}`);
211
220
  }
221
+ await runtime.afterAttach?.(runtimeContext);
212
222
  const entityIds = new Set();
213
223
  for (const { entity } of results) {
214
224
  entityCounts[entity.type] = (entityCounts[entity.type] || 0) + 1;
@@ -263,6 +273,7 @@ export async function syncCommand(options = {}) {
263
273
  if (kbModified) {
264
274
  prolog.invalidateCache();
265
275
  }
276
+ await runtime.beforeSave?.({ ...runtimeContext, kbModified });
266
277
  const saveResult = await prolog.query("kb_save");
267
278
  if (!saveResult.success) {
268
279
  throw new SyncError(`Failed to save staging KB: ${saveResult.error || "Unknown error"}`);
@@ -270,6 +281,7 @@ export async function syncCommand(options = {}) {
270
281
  await prolog.query("kb_detach");
271
282
  await prolog.terminate();
272
283
  atomicPublish(stagingPath, livePath);
284
+ cleanupStaging(stagingPath);
273
285
  const evictedHashes = {};
274
286
  const evictedSeenAt = {};
275
287
  for (const [key, hash] of Object.entries(nextHashes)) {
@@ -312,6 +324,9 @@ export async function syncCommand(options = {}) {
312
324
  }
313
325
  }
314
326
  catch (error) {
327
+ if (stagingPath) {
328
+ cleanupStaging(stagingPath);
329
+ }
315
330
  const errorMessage = error instanceof Error ? error.message : String(error);
316
331
  console.error(`Error: ${errorMessage}`);
317
332
  const commit = getCurrentCommit();
@@ -38,6 +38,8 @@ export interface ExtractedRelationship {
38
38
  export interface ExtractionResult {
39
39
  entity: ExtractedEntity;
40
40
  relationships: ExtractedRelationship[];
41
+ /** The per-symbol source code file, distinct from the manifest file path. */
42
+ sourceFile?: string;
41
43
  }
42
44
  export declare class FrontmatterError extends Error {
43
45
  filePath: string;
@@ -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;CACxC;AA2BD,qBAAa,gBAAiB,SAAQ,KAAK;IAOhC,QAAQ,EAAE,MAAM;IANlB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;gBAG5B,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE;QACR,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAYM,QAAQ;CAUlB;AA8DD,wBAAgB,sBAAsB,CAEpC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAkDV;AAmRD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,gBAAgB,CAElB;AAGD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAatE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjE;AASD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAQpE"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/extractors/markdown.ts"],"names":[],"mappings":"AAwDA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,YAAY,CAAC;IAC3D,wBAAwB,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IAEnD,SAAS,CAAC,EAAE,SAAS,GAAG,gBAAgB,GAAG,aAAa,GAAG,MAAM,CAAC;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,CAAC;IACtD,UAAU,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAChC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA2BD,qBAAa,gBAAiB,SAAQ,KAAK;IAOhC,QAAQ,EAAE,MAAM;IANlB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;gBAG5B,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE;QACR,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAYM,QAAQ;CAUlB;AA8DD,wBAAgB,sBAAsB,CAEpC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAkDV;AAmRD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,gBAAgB,CAElB;AAGD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAatE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjE;AASD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAQpE"}
@@ -1,7 +1,41 @@
1
1
  import { type ManifestSymbolEntry, enrichSymbolCoordinatesWithTsMorph } from "./symbols-ts.js";
2
2
  export type { ManifestSymbolEntry };
3
+ export type SourceAnalysisMode = "parser" | "fallback";
4
+ export type SourceSymbolKind = "function" | "class" | "interface" | "type" | "enum" | "variable" | "unknown";
5
+ export interface SourceSymbolAnalysis {
6
+ name: string;
7
+ kind: SourceSymbolKind;
8
+ startLine: number;
9
+ startColumn: number;
10
+ endLine: number;
11
+ endColumn: number;
12
+ directiveText?: string;
13
+ }
14
+ export interface SourceModuleAnalysis {
15
+ title: string;
16
+ language: string;
17
+ analysisMode: SourceAnalysisMode;
18
+ fallbackReason?: string;
19
+ }
20
+ export interface SourceAnalysisResult {
21
+ sourceFile: string;
22
+ language: string;
23
+ providerId: string | null;
24
+ module: SourceModuleAnalysis;
25
+ symbols: SourceSymbolAnalysis[];
26
+ }
27
+ export interface SourceAnalysisProvider {
28
+ id: string;
29
+ supportsFile(filePath: string): boolean;
30
+ analyzeText(filePath: string, content: string): SourceAnalysisResult;
31
+ }
32
+ export interface AnalyzeSourceTextOptions {
33
+ providers?: SourceAnalysisProvider[];
34
+ }
3
35
  interface EnrichSymbolCoordinatesDeps {
4
36
  enrichTsCoordinates: typeof enrichSymbolCoordinatesWithTsMorph;
5
37
  }
38
+ export declare function analyzeSourceText(entries: ManifestSymbolEntry[], workspaceRoot: string, deps?: Partial<EnrichSymbolCoordinatesDeps>): Promise<ManifestSymbolEntry[]>;
39
+ export declare function analyzeSourceText(filePath: string, content: string, options?: AnalyzeSourceTextOptions): SourceAnalysisResult;
6
40
  export declare function enrichSymbolCoordinates(entries: ManifestSymbolEntry[], workspaceRoot: string, deps?: Partial<EnrichSymbolCoordinatesDeps>): Promise<ManifestSymbolEntry[]>;
7
41
  //# sourceMappingURL=symbols-coordinator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"symbols-coordinator.d.ts","sourceRoot":"","sources":["../../src/extractors/symbols-coordinator.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,mBAAmB,EACxB,kCAAkC,EACnC,MAAM,iBAAiB,CAAC;AAazB,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,UAAU,2BAA2B;IACnC,mBAAmB,EAAE,OAAO,kCAAkC,CAAC;CAChE;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,mBAAmB,EAAE,EAC9B,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAC1C,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAqChC"}
1
+ {"version":3,"file":"symbols-coordinator.d.ts","sourceRoot":"","sources":["../../src/extractors/symbols-coordinator.ts"],"names":[],"mappings":"AAoBA,OAAO,EAEL,KAAK,mBAAmB,EACxB,kCAAkC,EACnC,MAAM,iBAAiB,CAAC;AAazB,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEvD,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,OAAO,GACP,WAAW,GACX,MAAM,GACN,MAAM,GACN,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,kBAAkB,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACxC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,oBAAoB,CAAC;CACtE;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACtC;AAED,UAAU,2BAA2B;IACnC,mBAAmB,EAAE,OAAO,kCAAkC,CAAC;CAChE;AA+BD,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,EAAE,EAC9B,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAC1C,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;AAClC,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,wBAAwB,GACjC,oBAAoB,CAAC;AAgCxB,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,mBAAmB,EAAE,EAC9B,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAC1C,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAqChC"}
@@ -17,7 +17,7 @@
17
17
  */
18
18
  import * as fs from "node:fs";
19
19
  import * as path from "node:path";
20
- import { enrichSymbolCoordinatesWithTsMorph, } from "./symbols-ts.js";
20
+ import { createTsMorphSourceAnalysisProvider, enrichSymbolCoordinatesWithTsMorph, } from "./symbols-ts.js";
21
21
  const TS_JS_EXTENSIONS = new Set([
22
22
  ".ts",
23
23
  ".tsx",
@@ -28,6 +28,52 @@ const TS_JS_EXTENSIONS = new Set([
28
28
  ".mjs",
29
29
  ".cjs",
30
30
  ]);
31
+ const SOURCE_LANGUAGE_EXTENSIONS = {
32
+ ".c": "c",
33
+ ".cc": "cpp",
34
+ ".cjs": "javascript",
35
+ ".cpp": "cpp",
36
+ ".cs": "csharp",
37
+ ".cts": "typescript",
38
+ ".go": "go",
39
+ ".h": "c",
40
+ ".hpp": "cpp",
41
+ ".java": "java",
42
+ ".js": "javascript",
43
+ ".jsx": "javascript",
44
+ ".kt": "kotlin",
45
+ ".mjs": "javascript",
46
+ ".mts": "typescript",
47
+ ".php": "php",
48
+ ".py": "python",
49
+ ".rb": "ruby",
50
+ ".rs": "rust",
51
+ ".swift": "swift",
52
+ ".ts": "typescript",
53
+ ".tsx": "typescript",
54
+ };
55
+ const DEFAULT_SOURCE_ANALYSIS_PROVIDERS = [
56
+ createTsMorphSourceAnalysisProvider(),
57
+ ];
58
+ // implements REQ-001
59
+ export function analyzeSourceText(filePathOrEntries, contentOrWorkspaceRoot, optionsOrDeps) {
60
+ if (Array.isArray(filePathOrEntries)) {
61
+ return enrichSymbolCoordinates(filePathOrEntries, contentOrWorkspaceRoot, optionsOrDeps);
62
+ }
63
+ const providers = optionsOrDeps?.providers ??
64
+ DEFAULT_SOURCE_ANALYSIS_PROVIDERS;
65
+ for (const provider of providers) {
66
+ if (!provider.supportsFile(filePathOrEntries))
67
+ continue;
68
+ try {
69
+ return provider.analyzeText(filePathOrEntries, contentOrWorkspaceRoot);
70
+ }
71
+ catch {
72
+ return createFallbackAnalysis(filePathOrEntries, "provider_error");
73
+ }
74
+ }
75
+ return createFallbackAnalysis(filePathOrEntries, "unsupported_language");
76
+ }
31
77
  export async function enrichSymbolCoordinates(entries, workspaceRoot, deps) {
32
78
  // implements REQ-vscode-traceability
33
79
  const enrichTsCoordinates = deps?.enrichTsCoordinates ?? enrichSymbolCoordinatesWithTsMorph;
@@ -106,3 +152,26 @@ function resolveSourcePath(sourceFile, workspaceRoot) {
106
152
  function escapeRegex(value) {
107
153
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
108
154
  }
155
+ function createFallbackAnalysis(filePath, fallbackReason) {
156
+ const language = detectSourceLanguage(filePath);
157
+ return {
158
+ sourceFile: filePath,
159
+ language,
160
+ providerId: null,
161
+ module: {
162
+ title: inferModuleTitle(filePath),
163
+ language,
164
+ analysisMode: "fallback",
165
+ fallbackReason,
166
+ },
167
+ symbols: [],
168
+ };
169
+ }
170
+ function detectSourceLanguage(filePath) {
171
+ return SOURCE_LANGUAGE_EXTENSIONS[path.extname(filePath).toLowerCase()] ?? "unknown";
172
+ }
173
+ function inferModuleTitle(filePath) {
174
+ const extension = path.extname(filePath);
175
+ const basename = path.basename(filePath, extension);
176
+ return basename.length > 0 ? basename : path.basename(filePath);
177
+ }
@@ -1,3 +1,4 @@
1
+ import type { SourceAnalysisProvider } from "./symbols-coordinator.js";
1
2
  export interface SymbolCoordinates {
2
3
  sourceLine: number;
3
4
  sourceColumn: number;
@@ -17,5 +18,6 @@ export interface ManifestSymbolEntry {
17
18
  links?: string[];
18
19
  [key: string]: unknown;
19
20
  }
21
+ export declare function createTsMorphSourceAnalysisProvider(): SourceAnalysisProvider;
20
22
  export declare function enrichSymbolCoordinatesWithTsMorph(entries: ManifestSymbolEntry[], workspaceRoot: string): Promise<ManifestSymbolEntry[]>;
21
23
  //# sourceMappingURL=symbols-ts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"symbols-ts.d.ts","sourceRoot":"","sources":["../../src/extractors/symbols-ts.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,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,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAaD,wBAAsB,kCAAkC,CACtD,OAAO,EAAE,mBAAmB,EAAE,EAC9B,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAuEhC"}
1
+ {"version":3,"file":"symbols-ts.d.ts","sourceRoot":"","sources":["../../src/extractors/symbols-ts.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EACV,sBAAsB,EAIvB,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,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,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAcD,wBAAgB,mCAAmC,IAAI,sBAAsB,CA6B5E;AAED,wBAAsB,kCAAkC,CACtD,OAAO,EAAE,mBAAmB,EAAE,EAC9B,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAuEhC"}