kibi-cli 0.6.2 → 0.7.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 (37) 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/extractors/markdown.d.ts +2 -0
  14. package/dist/extractors/markdown.d.ts.map +1 -1
  15. package/dist/extractors/symbols-coordinator.d.ts +34 -0
  16. package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
  17. package/dist/extractors/symbols-coordinator.js +70 -1
  18. package/dist/extractors/symbols-ts.d.ts +2 -0
  19. package/dist/extractors/symbols-ts.d.ts.map +1 -1
  20. package/dist/extractors/symbols-ts.js +108 -1
  21. package/dist/public/brief-config.d.ts +4 -0
  22. package/dist/public/brief-config.d.ts.map +1 -0
  23. package/dist/public/brief-config.js +21 -0
  24. package/dist/public/extractors/symbols-coordinator.d.ts +1 -1
  25. package/dist/public/extractors/symbols-coordinator.d.ts.map +1 -1
  26. package/dist/public/extractors/symbols-coordinator.js +1 -1
  27. package/dist/utils/config.d.ts +18 -3
  28. package/dist/utils/config.d.ts.map +1 -1
  29. package/dist/utils/config.js +39 -0
  30. package/dist/utils/rule-registry.d.ts.map +1 -1
  31. package/dist/utils/rule-registry.js +6 -0
  32. package/package.json +6 -2
  33. package/schema/config.json +73 -0
  34. package/schema/entities.pl +1 -0
  35. package/schema/relationships.pl +4 -0
  36. package/src/public/brief-config.ts +25 -0
  37. package/src/public/extractors/symbols-coordinator.ts +7 -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);
@@ -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"}
@@ -17,7 +17,7 @@
17
17
  */
18
18
  import { access, readFile } from "node:fs/promises";
19
19
  import * as path from "node:path";
20
- import { Project, } from "ts-morph";
20
+ import { Project, ScriptKind, } from "ts-morph";
21
21
  const SUPPORTED_SOURCE_EXTENSIONS = new Set([
22
22
  ".ts",
23
23
  ".tsx",
@@ -28,6 +28,35 @@ const SUPPORTED_SOURCE_EXTENSIONS = new Set([
28
28
  ".mjs",
29
29
  ".cjs",
30
30
  ]);
31
+ // implements REQ-001
32
+ export function createTsMorphSourceAnalysisProvider() {
33
+ const project = new Project({
34
+ skipAddingFilesFromTsConfig: true,
35
+ });
36
+ return {
37
+ id: "ts-morph",
38
+ supportsFile(filePath) {
39
+ return SUPPORTED_SOURCE_EXTENSIONS.has(path.extname(filePath).toLowerCase());
40
+ },
41
+ analyzeText(filePath, content) {
42
+ const sourceFile = project.createSourceFile(filePath, content, {
43
+ overwrite: true,
44
+ scriptKind: chooseScriptKind(filePath),
45
+ });
46
+ return {
47
+ sourceFile: filePath,
48
+ language: inferSourceLanguage(filePath),
49
+ providerId: "ts-morph",
50
+ module: {
51
+ title: inferModuleTitle(filePath),
52
+ language: inferSourceLanguage(filePath),
53
+ analysisMode: "parser",
54
+ },
55
+ symbols: collectSourceSymbols(sourceFile),
56
+ };
57
+ },
58
+ };
59
+ }
31
60
  export async function enrichSymbolCoordinatesWithTsMorph(entries, workspaceRoot) {
32
61
  // implements REQ-vscode-traceability
33
62
  const project = new Project({
@@ -142,6 +171,84 @@ async function enrichWithTextFallbackInternal(entry, absolutePath) {
142
171
  return entry;
143
172
  }
144
173
  }
174
+ function collectSourceSymbols(sourceFile) {
175
+ const symbols = [];
176
+ for (const decl of sourceFile.getFunctions()) {
177
+ if (!decl.isExported())
178
+ continue;
179
+ symbols.push(toSourceSymbolAnalysis(sourceFile, decl.getName() ?? "<anonymous>", "function", decl.getNameNode() ?? decl, decl, `${decl.getFullText()}\n${decl
180
+ .getJsDocs()
181
+ .map((doc) => doc.getFullText())
182
+ .join("\n")}`));
183
+ }
184
+ for (const decl of sourceFile.getClasses()) {
185
+ if (!decl.isExported())
186
+ continue;
187
+ symbols.push(toSourceSymbolAnalysis(sourceFile, decl.getName() ?? "<anonymous>", "class", decl.getNameNode() ?? decl, decl, `${decl.getText()}\n${decl
188
+ .getJsDocs()
189
+ .map((doc) => doc.getFullText())
190
+ .join("\n")}`));
191
+ }
192
+ for (const decl of sourceFile.getInterfaces()) {
193
+ if (!decl.isExported())
194
+ continue;
195
+ symbols.push(toSourceSymbolAnalysis(sourceFile, decl.getName() ?? "<anonymous>", "interface", decl.getNameNode() ?? decl, decl, decl.getText()));
196
+ }
197
+ for (const decl of sourceFile.getTypeAliases()) {
198
+ if (!decl.isExported())
199
+ continue;
200
+ symbols.push(toSourceSymbolAnalysis(sourceFile, decl.getName() ?? "<anonymous>", "type", decl.getNameNode() ?? decl, decl, decl.getText()));
201
+ }
202
+ for (const decl of sourceFile.getEnums()) {
203
+ if (!decl.isExported())
204
+ continue;
205
+ symbols.push(toSourceSymbolAnalysis(sourceFile, decl.getName() ?? "<anonymous>", "enum", decl.getNameNode() ?? decl, decl, decl.getText()));
206
+ }
207
+ for (const statement of sourceFile.getVariableStatements()) {
208
+ if (!statement.isExported())
209
+ continue;
210
+ for (const declaration of statement.getDeclarations()) {
211
+ symbols.push(toSourceSymbolAnalysis(sourceFile, declaration.getName(), "variable", declaration.getNameNode() ?? declaration, declaration, declaration.getText()));
212
+ }
213
+ }
214
+ return symbols;
215
+ }
216
+ function toSourceSymbolAnalysis(sourceFile, name, kind, startNode, endNode, directiveText) {
217
+ const start = sourceFile.getLineAndColumnAtPos(startNode.getStart());
218
+ const end = sourceFile.getLineAndColumnAtPos(endNode.getEnd());
219
+ return {
220
+ name,
221
+ kind,
222
+ startLine: start.line,
223
+ startColumn: Math.max(0, start.column - 1),
224
+ endLine: end.line,
225
+ endColumn: Math.max(0, end.column - 1),
226
+ directiveText,
227
+ };
228
+ }
229
+ function chooseScriptKind(filePath) {
230
+ const lower = filePath.toLowerCase();
231
+ if (lower.endsWith(".tsx"))
232
+ return ScriptKind.TSX;
233
+ if (lower.endsWith(".ts") || lower.endsWith(".mts") || lower.endsWith(".cts")) {
234
+ return ScriptKind.TS;
235
+ }
236
+ if (lower.endsWith(".jsx"))
237
+ return ScriptKind.JSX;
238
+ return ScriptKind.JS;
239
+ }
240
+ function inferSourceLanguage(filePath) {
241
+ const extension = path.extname(filePath).toLowerCase();
242
+ if ([".ts", ".tsx", ".mts", ".cts"].includes(extension)) {
243
+ return "typescript";
244
+ }
245
+ return "javascript";
246
+ }
247
+ function inferModuleTitle(filePath) {
248
+ const extension = path.extname(filePath);
249
+ const basename = path.basename(filePath, extension);
250
+ return basename.length > 0 ? basename : path.basename(filePath);
251
+ }
145
252
  function findNamedDeclaration(sourceFile, title) {
146
253
  const candidates = [];
147
254
  for (const decl of sourceFile.getFunctions()) {
@@ -0,0 +1,4 @@
1
+ import { type BriefsConfig } from "../utils/config.js";
2
+ export type { BriefsConfig } from "../utils/config.js";
3
+ export declare function loadBriefConfig(cwd?: string): BriefsConfig;
4
+ //# sourceMappingURL=brief-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brief-config.d.ts","sourceRoot":"","sources":["../../src/public/brief-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEnE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAsB,GAAG,YAAY,CAoBzE"}
@@ -0,0 +1,21 @@
1
+ import { loadConfig } from "../utils/config.js";
2
+ export function loadBriefConfig(cwd = process.cwd()) {
3
+ const briefs = loadConfig(cwd).briefs;
4
+ return {
5
+ enabled: briefs?.enabled ?? true,
6
+ retention: {
7
+ maxPerBranch: briefs?.retention?.maxPerBranch ?? 200,
8
+ maxAgeDays: briefs?.retention?.maxAgeDays ?? 14,
9
+ keepUnread: briefs?.retention?.keepUnread ?? true,
10
+ },
11
+ channels: {
12
+ vscode: briefs?.channels?.vscode ?? true,
13
+ tui: briefs?.channels?.tui ?? true,
14
+ },
15
+ tui: {
16
+ toast: briefs?.tui?.toast ?? true,
17
+ appendPrompt: briefs?.tui?.appendPrompt ?? true,
18
+ idleDelayMs: briefs?.tui?.idleDelayMs ?? 1500,
19
+ },
20
+ };
21
+ }
@@ -1,2 +1,2 @@
1
- export { enrichSymbolCoordinates, type ManifestSymbolEntry, } from "../../extractors/symbols-coordinator.js";
1
+ export { analyzeSourceText, enrichSymbolCoordinates, type ManifestSymbolEntry, type AnalyzeSourceTextOptions, type SourceAnalysisProvider, type SourceAnalysisResult, type SourceModuleAnalysis, type SourceSymbolAnalysis, type SourceSymbolKind, } from "../../extractors/symbols-coordinator.js";
2
2
  //# sourceMappingURL=symbols-coordinator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"symbols-coordinator.d.ts","sourceRoot":"","sources":["../../../src/public/extractors/symbols-coordinator.ts"],"names":[],"mappings":"AAkBA,OAAO,EACL,uBAAuB,EACvB,KAAK,mBAAmB,GACzB,MAAM,yCAAyC,CAAC"}
1
+ {"version":3,"file":"symbols-coordinator.d.ts","sourceRoot":"","sources":["../../../src/public/extractors/symbols-coordinator.ts"],"names":[],"mappings":"AAkBA,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,GACtB,MAAM,yCAAyC,CAAC"}
@@ -15,4 +15,4 @@
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
- export { enrichSymbolCoordinates, } from "../../extractors/symbols-coordinator.js";
18
+ export { analyzeSourceText, enrichSymbolCoordinates, } from "../../extractors/symbols-coordinator.js";
@@ -12,12 +12,30 @@ export interface KbConfigPaths {
12
12
  facts?: string;
13
13
  symbols?: string;
14
14
  }
15
+ export interface BriefsConfig {
16
+ enabled: boolean;
17
+ retention?: {
18
+ maxPerBranch?: number;
19
+ maxAgeDays?: number;
20
+ keepUnread?: boolean;
21
+ };
22
+ channels: {
23
+ vscode: boolean;
24
+ tui: boolean;
25
+ };
26
+ tui: {
27
+ toast: boolean;
28
+ appendPrompt: boolean;
29
+ idleDelayMs?: number;
30
+ };
31
+ }
15
32
  /**
16
33
  * Shared configuration for Kibi.
17
34
  * Stored in .kb/config.json
18
35
  */
19
36
  export interface KbConfig {
20
37
  paths: KbConfigPaths;
38
+ briefs?: BriefsConfig;
21
39
  /**
22
40
  * @deprecated defaultBranch is deprecated. Branch lifecycle now follows git naturally
23
41
  * without requiring a configured default. This field is ignored but kept for compatibility.
@@ -26,9 +44,6 @@ export interface KbConfig {
26
44
  checks?: ChecksConfig;
27
45
  }
28
46
  export type { ChecksConfig, SymbolTraceabilityOptions };
29
- /**
30
- * Default configuration values for new repositories.
31
- */
32
47
  export declare const DEFAULT_CONFIG: KbConfig & {
33
48
  $schema: string;
34
49
  };
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,YAAY,EAEjB,KAAK,yBAAyB,EAC/B,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,aAAa,CAAC;IACrB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,YAAY,EAAE,YAAY,EAAE,yBAAyB,EAAE,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,QAAQ,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAcxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAShC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,QAAQ,CAoChE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,QAAQ,CAoCpE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,YAAY,EAEjB,KAAK,yBAAyB,EAC/B,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE;QACV,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC;IACF,QAAQ,EAAE;QACR,MAAM,EAAE,OAAO,CAAC;QAChB,GAAG,EAAE,OAAO,CAAC;KACd,CAAC;IACF,GAAG,EAAE;QACH,KAAK,EAAE,OAAO,CAAC;QACf,YAAY,EAAE,OAAO,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,YAAY,EAAE,YAAY,EAAE,yBAAyB,EAAE,CAAC;AAwBxD,eAAO,MAAM,cAAc,EAAE,QAAQ,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAexD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAShC,CAAC;AAqBF;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,QAAQ,CAqChE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,QAAQ,CAqCpE"}
@@ -21,6 +21,24 @@ import { DEFAULT_CHECKS_CONFIG, } from "./rule-registry.js";
21
21
  /**
22
22
  * Default configuration values for new repositories.
23
23
  */
24
+ const DEFAULT_BRIEFS_CONFIG = {
25
+ enabled: true,
26
+ retention: {
27
+ maxPerBranch: 200,
28
+ maxAgeDays: 14,
29
+ keepUnread: true,
30
+ },
31
+ channels: {
32
+ vscode: true,
33
+ tui: true,
34
+ },
35
+ tui: {
36
+ toast: true,
37
+ appendPrompt: true,
38
+ idleDelayMs: 1500,
39
+ },
40
+ };
41
+ // implements REQ-003
24
42
  export const DEFAULT_CONFIG = {
25
43
  $schema: "https://raw.githubusercontent.com/Looted/kibi/master/packages/cli/schema/config.json",
26
44
  paths: {
@@ -33,6 +51,7 @@ export const DEFAULT_CONFIG = {
33
51
  facts: "documentation/facts",
34
52
  symbols: "documentation/symbols.yaml",
35
53
  },
54
+ briefs: DEFAULT_BRIEFS_CONFIG,
36
55
  checks: DEFAULT_CHECKS_CONFIG,
37
56
  };
38
57
  /**
@@ -48,6 +67,24 @@ export const DEFAULT_SYNC_PATHS = {
48
67
  facts: "facts/**/*.md",
49
68
  symbols: "symbols.yaml",
50
69
  };
70
+ function mergeBriefsConfig(userBriefs) {
71
+ return {
72
+ ...DEFAULT_BRIEFS_CONFIG,
73
+ ...userBriefs,
74
+ channels: {
75
+ ...DEFAULT_BRIEFS_CONFIG.channels,
76
+ ...userBriefs?.channels,
77
+ },
78
+ tui: {
79
+ ...DEFAULT_BRIEFS_CONFIG.tui,
80
+ ...userBriefs?.tui,
81
+ },
82
+ retention: {
83
+ ...DEFAULT_BRIEFS_CONFIG.retention,
84
+ ...userBriefs?.retention,
85
+ },
86
+ };
87
+ }
51
88
  /**
52
89
  * Load and parse the Kibi configuration from .kb/config.json.
53
90
  * Falls back to DEFAULT_CONFIG if the file doesn't exist or is invalid.
@@ -74,6 +111,7 @@ export function loadConfig(cwd = process.cwd()) {
74
111
  ...DEFAULT_CONFIG.paths,
75
112
  ...userConfig.paths,
76
113
  },
114
+ briefs: mergeBriefsConfig(userConfig.briefs),
77
115
  ...(userConfig.defaultBranch !== undefined
78
116
  ? { defaultBranch: userConfig.defaultBranch }
79
117
  : {}),
@@ -118,6 +156,7 @@ export function loadSyncConfig(cwd = process.cwd()) {
118
156
  ...DEFAULT_SYNC_PATHS,
119
157
  ...userConfig.paths,
120
158
  },
159
+ briefs: mergeBriefsConfig(userConfig.briefs),
121
160
  ...(userConfig.defaultBranch !== undefined
122
161
  ? { defaultBranch: userConfig.defaultBranch }
123
162
  : {}),
@@ -1 +1 @@
1
- {"version":3,"file":"rule-registry.d.ts","sourceRoot":"","sources":["../../src/utils/rule-registry.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AAEH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,UAAU,GAAG,WAAW,GAAG,WAAW,GAAG,cAAc,CAAC;CACnE;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,mCAAmC;AACnC,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,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,kBAAkB,EAAE,yBAAyB,CAAC;CAC/C;AAED;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,SAAS,cAAc,EA8DjC,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,UAAU,aAAoC,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,YAKnC,CAAC;AAEF;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAC/B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,QAAQ,CAAC,EAAE,MAAM,GAChB,GAAG,CAAC,MAAM,CAAC,CAsBb;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC9B,YAAY,CAWd"}
1
+ {"version":3,"file":"rule-registry.d.ts","sourceRoot":"","sources":["../../src/utils/rule-registry.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AAEH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,UAAU,GAAG,WAAW,GAAG,WAAW,GAAG,cAAc,CAAC;CACnE;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,mCAAmC;AACnC,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,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,kBAAkB,EAAE,yBAAyB,CAAC;CAC/C;AAED;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,SAAS,cAAc,EAqEjC,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,UAAU,aAAoC,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,YAKnC,CAAC;AAEF;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAC/B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,QAAQ,CAAC,EAAE,MAAM,GAChB,GAAG,CAAC,MAAM,CAAC,CAsBb;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC9B,YAAY,CAWd"}
@@ -75,6 +75,12 @@ export const RULES = [
75
75
  defaultEnabled: false,
76
76
  category: "integrity",
77
77
  },
78
+ {
79
+ name: "strict-req-fact-pairing",
80
+ description: "Detect requirements with incomplete strict subject/property fact pairing for contradiction-safe semantics",
81
+ defaultEnabled: false,
82
+ category: "integrity",
83
+ },
78
84
  ];
79
85
  /**
80
86
  * Set of all rule names for quick lookups.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-cli",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "description": "Kibi CLI for knowledge base management",
6
6
  "engines": {
@@ -74,6 +74,10 @@
74
74
  "./public/check-types": {
75
75
  "types": "./dist/public/check-types.d.ts",
76
76
  "default": "./dist/public/check-types.js"
77
+ },
78
+ "./brief-config": {
79
+ "types": "./dist/public/brief-config.d.ts",
80
+ "default": "./dist/public/brief-config.js"
77
81
  }
78
82
  },
79
83
  "types": "./dist/cli.d.ts",
@@ -84,7 +88,7 @@
84
88
  "fast-glob": "^3.2.12",
85
89
  "gray-matter": "^4.0.3",
86
90
  "js-yaml": "^4.1.0",
87
- "kibi-core": "^0.5.1",
91
+ "kibi-core": "^0.5.2",
88
92
  "ts-morph": "^23.0.0"
89
93
  },
90
94
  "devDependencies": {
@@ -61,6 +61,74 @@
61
61
  "description": "[DEPRECATED] No longer used. Branch lifecycle now follows git naturally without requiring a configured default. This field is ignored but kept for backward compatibility.",
62
62
  "deprecated": true
63
63
  },
64
+ "briefs": {
65
+ "type": "object",
66
+ "description": "Configuration for shared brief delivery defaults",
67
+ "properties": {
68
+ "enabled": {
69
+ "type": "boolean",
70
+ "default": true
71
+ },
72
+ "retention": {
73
+ "type": "object",
74
+ "properties": {
75
+ "maxPerBranch": {
76
+ "type": "integer",
77
+ "minimum": 1,
78
+ "maximum": 10000,
79
+ "default": 200
80
+ },
81
+ "maxAgeDays": {
82
+ "type": "integer",
83
+ "minimum": 1,
84
+ "maximum": 3650,
85
+ "default": 14
86
+ },
87
+ "keepUnread": {
88
+ "type": "boolean",
89
+ "default": true
90
+ }
91
+ },
92
+ "additionalProperties": false
93
+ },
94
+ "channels": {
95
+ "type": "object",
96
+ "properties": {
97
+ "vscode": {
98
+ "type": "boolean",
99
+ "default": true
100
+ },
101
+ "tui": {
102
+ "type": "boolean",
103
+ "default": true
104
+ }
105
+ },
106
+ "additionalProperties": false
107
+ },
108
+ "tui": {
109
+ "type": "object",
110
+ "properties": {
111
+ "toast": {
112
+ "type": "boolean",
113
+ "default": true
114
+ },
115
+ "appendPrompt": {
116
+ "type": "boolean",
117
+ "default": true
118
+ },
119
+ "idleDelayMs": {
120
+ "type": "integer",
121
+ "minimum": 0,
122
+ "maximum": 60000,
123
+ "default": 1500,
124
+ "description": "Delay in milliseconds after session.idle before idle-brief generation is attempted"
125
+ }
126
+ },
127
+ "additionalProperties": false
128
+ }
129
+ },
130
+ "additionalProperties": false
131
+ },
64
132
  "checks": {
65
133
  "type": "object",
66
134
  "description": "Configuration for KB validation rules",
@@ -113,6 +181,11 @@
113
181
  "type": "boolean",
114
182
  "description": "Detect malformed strict facts (facts with fact_kind that are missing required fields)",
115
183
  "default": false
184
+ },
185
+ "strict-req-fact-pairing": {
186
+ "type": "boolean",
187
+ "description": "Detect requirements with incomplete strict subject/property fact pairing for contradiction-safe semantics",
188
+ "default": false
116
189
  }
117
190
  },
118
191
  "additionalProperties": false
@@ -20,6 +20,7 @@ entity_property(_, status, atom).
20
20
  entity_property(_, created_at, datetime).
21
21
  entity_property(_, updated_at, datetime).
22
22
  entity_property(_, source, uri).
23
+ entity_property(_, sourceFile, uri).
23
24
 
24
25
  % Optional properties
25
26
  entity_property(_, tags, list).
@@ -9,6 +9,7 @@ relationship_type(verified_by).
9
9
  relationship_type(validates).
10
10
  relationship_type(implements).
11
11
  relationship_type(covered_by).
12
+ relationship_type(executable_for).
12
13
  relationship_type(constrained_by).
13
14
  relationship_type(guards).
14
15
  relationship_type(publishes).
@@ -25,6 +26,9 @@ valid_relationship(verified_by, req, test).
25
26
  valid_relationship(validates, test, req).
26
27
  valid_relationship(implements, symbol, req).
27
28
  valid_relationship(covered_by, symbol, test).
29
+ valid_relationship(executable_for, symbol, test).
30
+ valid_relationship(verified_by, scenario, test).
31
+ valid_relationship(validates, test, scenario).
28
32
  valid_relationship(constrained_by, symbol, adr).
29
33
  % guards can target symbol, event, or req
30
34
  valid_relationship(guards, flag, symbol).
@@ -0,0 +1,25 @@
1
+ import { loadConfig, type BriefsConfig } from "../utils/config.js";
2
+
3
+ export type { BriefsConfig } from "../utils/config.js";
4
+
5
+ export function loadBriefConfig(cwd: string = process.cwd()): BriefsConfig { // implements REQ-003
6
+ const briefs = loadConfig(cwd).briefs;
7
+
8
+ return {
9
+ enabled: briefs?.enabled ?? true,
10
+ retention: {
11
+ maxPerBranch: briefs?.retention?.maxPerBranch ?? 200,
12
+ maxAgeDays: briefs?.retention?.maxAgeDays ?? 14,
13
+ keepUnread: briefs?.retention?.keepUnread ?? true,
14
+ },
15
+ channels: {
16
+ vscode: briefs?.channels?.vscode ?? true,
17
+ tui: briefs?.channels?.tui ?? true,
18
+ },
19
+ tui: {
20
+ toast: briefs?.tui?.toast ?? true,
21
+ appendPrompt: briefs?.tui?.appendPrompt ?? true,
22
+ idleDelayMs: briefs?.tui?.idleDelayMs ?? 1500,
23
+ },
24
+ };
25
+ }
@@ -17,6 +17,13 @@
17
17
  */
18
18
 
19
19
  export {
20
+ analyzeSourceText,
20
21
  enrichSymbolCoordinates,
21
22
  type ManifestSymbolEntry,
23
+ type AnalyzeSourceTextOptions,
24
+ type SourceAnalysisProvider,
25
+ type SourceAnalysisResult,
26
+ type SourceModuleAnalysis,
27
+ type SourceSymbolAnalysis,
28
+ type SourceSymbolKind,
22
29
  } from "../../extractors/symbols-coordinator.js";