kibi-cli 0.2.8 → 0.4.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 (78) hide show
  1. package/dist/cli.d.ts +4 -1
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +91 -14
  4. package/dist/commands/check.d.ts +5 -8
  5. package/dist/commands/check.d.ts.map +1 -1
  6. package/dist/commands/check.js +41 -62
  7. package/dist/commands/coverage.d.ts +12 -0
  8. package/dist/commands/coverage.d.ts.map +1 -0
  9. package/dist/commands/coverage.js +24 -0
  10. package/dist/commands/discovery-shared.d.ts +11 -0
  11. package/dist/commands/discovery-shared.d.ts.map +1 -0
  12. package/dist/commands/discovery-shared.js +281 -0
  13. package/dist/commands/doctor.d.ts +3 -1
  14. package/dist/commands/doctor.d.ts.map +1 -1
  15. package/dist/commands/doctor.js +12 -13
  16. package/dist/commands/gaps.d.ts +12 -0
  17. package/dist/commands/gaps.d.ts.map +1 -0
  18. package/dist/commands/gaps.js +28 -0
  19. package/dist/commands/graph.d.ts +13 -0
  20. package/dist/commands/graph.d.ts.map +1 -0
  21. package/dist/commands/graph.js +35 -0
  22. package/dist/commands/init.d.ts +3 -1
  23. package/dist/commands/init.d.ts.map +1 -1
  24. package/dist/commands/init.js +4 -3
  25. package/dist/commands/query.d.ts +3 -1
  26. package/dist/commands/query.d.ts.map +1 -1
  27. package/dist/commands/query.js +9 -20
  28. package/dist/commands/search.d.ts +9 -0
  29. package/dist/commands/search.d.ts.map +1 -0
  30. package/dist/commands/search.js +38 -0
  31. package/dist/commands/status.d.ts +6 -0
  32. package/dist/commands/status.d.ts.map +1 -0
  33. package/dist/commands/status.js +9 -0
  34. package/dist/commands/sync/persistence.d.ts.map +1 -1
  35. package/dist/commands/sync/persistence.js +79 -12
  36. package/dist/commands/sync.d.ts +4 -1
  37. package/dist/commands/sync.d.ts.map +1 -1
  38. package/dist/commands/sync.js +79 -31
  39. package/dist/extractors/markdown.d.ts +17 -0
  40. package/dist/extractors/markdown.d.ts.map +1 -1
  41. package/dist/extractors/markdown.js +104 -14
  42. package/dist/prolog/codec.d.ts +32 -5
  43. package/dist/prolog/codec.d.ts.map +1 -1
  44. package/dist/prolog/codec.js +95 -58
  45. package/dist/prolog.d.ts.map +1 -1
  46. package/dist/prolog.js +12 -2
  47. package/dist/public/check-types.d.ts +7 -0
  48. package/dist/public/check-types.d.ts.map +1 -0
  49. package/dist/public/check-types.js +18 -0
  50. package/dist/public/schemas/entity.d.ts +68 -0
  51. package/dist/public/schemas/entity.d.ts.map +1 -1
  52. package/dist/public/schemas/entity.js +52 -0
  53. package/dist/relationships/shards.d.ts.map +1 -1
  54. package/dist/relationships/shards.js +6 -3
  55. package/dist/schemas/entity.schema.json +120 -0
  56. package/dist/search-ranking.d.ts +9 -0
  57. package/dist/search-ranking.d.ts.map +1 -0
  58. package/dist/search-ranking.js +149 -0
  59. package/dist/traceability/symbol-extract.d.ts.map +1 -1
  60. package/dist/traceability/symbol-extract.js +16 -8
  61. package/dist/types/entities.d.ts +19 -1
  62. package/dist/types/entities.d.ts.map +1 -1
  63. package/dist/utils/prolog-cleanup.d.ts +10 -0
  64. package/dist/utils/prolog-cleanup.d.ts.map +1 -0
  65. package/dist/utils/prolog-cleanup.js +39 -0
  66. package/dist/utils/rule-registry.d.ts +8 -0
  67. package/dist/utils/rule-registry.d.ts.map +1 -1
  68. package/dist/utils/rule-registry.js +14 -12
  69. package/package.json +10 -2
  70. package/schema/config.json +7 -1
  71. package/schema/entities.pl +18 -0
  72. package/schema/validation.pl +115 -4
  73. package/src/public/check-types.ts +37 -0
  74. package/src/public/schemas/entity.ts +58 -0
  75. package/src/schemas/entity.schema.json +56 -1
  76. package/dist/kb/target-resolver.d.ts +0 -80
  77. package/dist/kb/target-resolver.d.ts.map +0 -1
  78. package/dist/kb/target-resolver.js +0 -313
package/dist/cli.d.ts CHANGED
@@ -1,2 +1,5 @@
1
- export {};
1
+ /** All command handlers return this instead of calling process.exit(). */
2
+ export interface CommandResult {
3
+ exitCode?: number;
4
+ }
2
5
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAsCA,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
package/dist/cli.js CHANGED
@@ -19,13 +19,28 @@ import { readFileSync } from "node:fs";
19
19
  import { Command } from "commander";
20
20
  import { branchEnsureCommand } from "./commands/branch.js";
21
21
  import { checkCommand } from "./commands/check.js";
22
+ import { coverageCommand } from "./commands/coverage.js";
22
23
  import { doctorCommand } from "./commands/doctor.js";
24
+ import { gapsCommand } from "./commands/gaps.js";
23
25
  import { gcCommand } from "./commands/gc.js";
26
+ import { graphCommand } from "./commands/graph.js";
24
27
  import { initCommand } from "./commands/init.js";
25
28
  import { queryCommand } from "./commands/query.js";
29
+ import { searchCommand } from "./commands/search.js";
30
+ import { statusCommand } from "./commands/status.js";
26
31
  import { syncCommand } from "./commands/sync.js";
27
32
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
28
33
  const VERSION = packageJson.version ?? "0.1.0";
34
+ // implements REQ-003
35
+ /** Wraps an async command handler to apply its returned exitCode to process.exitCode. */
36
+ function withExitCode(fn) {
37
+ return async (...args) => {
38
+ const result = await fn(...args);
39
+ if (result && typeof result.exitCode === "number") {
40
+ process.exitCode = result.exitCode;
41
+ }
42
+ };
43
+ }
29
44
  const program = new Command();
30
45
  program
31
46
  .name("kibi")
@@ -35,17 +50,17 @@ program
35
50
  .command("init")
36
51
  .description("Initialize .kb/ directory")
37
52
  .option("--no-hooks", "Do not install git hooks (hooks installed by default)")
38
- .action(async (options) => {
39
- await initCommand(options);
40
- });
53
+ .action(withExitCode(async (options) => {
54
+ return initCommand(options);
55
+ }));
41
56
  program
42
57
  .command("sync")
43
58
  .description("Sync entities from documents")
44
59
  .option("--validate-only", "Perform validation without mutations")
45
60
  .option("--rebuild", "Rebuild branch snapshot from scratch (discards current KB)")
46
- .action(async (options) => {
47
- await syncCommand(options);
48
- });
61
+ .action(withExitCode(async (options) => {
62
+ return syncCommand(options);
63
+ }));
49
64
  program
50
65
  .command("query [type]")
51
66
  .description("Query knowledge base")
@@ -56,8 +71,65 @@ program
56
71
  .option("--format <format>", "Output format: json|table", "json")
57
72
  .option("--limit <n>", "Limit results", "100")
58
73
  .option("--offset <n>", "Skip results", "0")
74
+ .action(withExitCode(async (type, options) => {
75
+ return queryCommand(type, options);
76
+ }));
77
+ program
78
+ .command("search [query]")
79
+ .description("Search knowledge base metadata and markdown content")
80
+ .option("--type <type>", "Filter by entity type")
81
+ .option("--format <format>", "Output format: json|table", "table")
82
+ .option("--limit <n>", "Limit results", "20")
83
+ .option("--offset <n>", "Skip results", "0")
84
+ .action(async (query, options) => {
85
+ await searchCommand(query, options);
86
+ });
87
+ program
88
+ .command("status")
89
+ .description("Show KB snapshot and freshness metadata")
90
+ .option("--format <format>", "Output format: json|table", "table")
91
+ .action(async (options) => {
92
+ await statusCommand(options);
93
+ });
94
+ program
95
+ .command("gaps [type]")
96
+ .description("Find entities missing or present on selected relationships")
97
+ .option("--missing-rel <rels>", "Comma-separated missing relationship filters")
98
+ .option("--present-rel <rels>", "Comma-separated present relationship filters")
99
+ .option("--tag <tags>", "Comma-separated tag filter")
100
+ .option("--source <path>", "Source file substring filter")
101
+ .option("--limit <n>", "Limit results", "100")
102
+ .option("--offset <n>", "Skip results", "0")
103
+ .option("--format <format>", "Output format: json|table", "table")
59
104
  .action(async (type, options) => {
60
- await queryCommand(type, options);
105
+ await gapsCommand(type, options);
106
+ });
107
+ program
108
+ .command("coverage")
109
+ .description("Generate curated coverage reports")
110
+ .option("--by <group>", "Coverage mode: req|symbol|type", "req")
111
+ .option("--tag <tags>", "Comma-separated tag filter")
112
+ .option("--include-passing", "Include passing rows", false)
113
+ .option("--no-include-transitive", "Disable transitive symbol coverage")
114
+ .option("--limit <n>", "Limit results", "100")
115
+ .option("--offset <n>", "Skip results", "0")
116
+ .option("--format <format>", "Output format: json|table", "table")
117
+ .action(async (options) => {
118
+ await coverageCommand(options);
119
+ });
120
+ program
121
+ .command("graph")
122
+ .description("Traverse the KB graph from one or more seed IDs")
123
+ .option("--from <ids>", "Comma-separated seed IDs")
124
+ .option("--relationships <rels>", "Comma-separated relationship filter")
125
+ .option("--direction <direction>", "Direction: outgoing|incoming|both", "outgoing")
126
+ .option("--depth <n>", "Traversal depth", "1")
127
+ .option("--entity-types <types>", "Comma-separated entity type filter")
128
+ .option("--max-nodes <n>", "Maximum node count", "200")
129
+ .option("--max-edges <n>", "Maximum edge count", "500")
130
+ .option("--format <format>", "Output format: json|table", "table")
131
+ .action(async (options) => {
132
+ await graphCommand(options);
61
133
  });
62
134
  program
63
135
  .command("check")
@@ -68,9 +140,9 @@ program
68
140
  .option("--staged", "Run check only against staged changes (experimental)")
69
141
  .option("--min-links <n>", "Minimum number of links required for symbol coverage", "1")
70
142
  .option("--dry-run", "Do not modify files; only print what would happen")
71
- .action(async (options) => {
72
- await checkCommand(options);
73
- });
143
+ .action(withExitCode(async (options) => {
144
+ return checkCommand(options);
145
+ }));
74
146
  program
75
147
  .command("gc")
76
148
  .description("Garbage collect stale branch KBs")
@@ -83,9 +155,7 @@ program
83
155
  program
84
156
  .command("doctor")
85
157
  .description("Diagnose KB setup and configuration")
86
- .action(async () => {
87
- await doctorCommand();
88
- });
158
+ .action(withExitCode(async () => doctorCommand()));
89
159
  program
90
160
  .command("branch")
91
161
  .description("Manage branch KBs")
@@ -96,4 +166,11 @@ program
96
166
  await branchEnsureCommand(options);
97
167
  }
98
168
  });
99
- program.parse(process.argv);
169
+ program
170
+ .parseAsync(process.argv)
171
+ .then(() => process.exit(process.exitCode ?? 0))
172
+ .catch((error) => {
173
+ const message = error instanceof Error ? error.message : String(error);
174
+ console.error(message);
175
+ process.exit(1);
176
+ });
@@ -1,3 +1,5 @@
1
+ import { type Violation } from "../utils/rule-registry.js";
2
+ export type { Violation };
1
3
  export interface CheckOptions {
2
4
  fix?: boolean;
3
5
  kbPath?: string;
@@ -6,12 +8,7 @@ export interface CheckOptions {
6
8
  minLinks?: string | number;
7
9
  dryRun?: boolean;
8
10
  }
9
- export interface Violation {
10
- rule: string;
11
- entityId: string;
12
- description: string;
13
- suggestion?: string;
14
- source?: string;
15
- }
16
- export declare function checkCommand(options: CheckOptions): Promise<void>;
11
+ export declare function checkCommand(options: CheckOptions): Promise<{
12
+ exitCode: number;
13
+ }>;
17
14
  //# sourceMappingURL=check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAgDA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+RvE"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AA4CA,OAAO,EAGL,KAAK,SAAS,EAEf,MAAM,2BAA2B,CAAC;AAEnC,YAAY,EAAE,SAAS,EAAE,CAAC;AAK1B,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;AAGD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA0R/B"}
@@ -18,13 +18,14 @@
18
18
  import * as path from "node:path";
19
19
  import { extractFromManifest } from "../extractors/manifest.js";
20
20
  import { PrologProcess } from "../prolog.js";
21
- import { escapeAtom } from "../prolog/codec.js";
21
+ import { escapeAtom, parseTriples, parseViolationRows, } from "../prolog/codec.js";
22
22
  import { getStagedFiles } from "../traceability/git-staged.js";
23
23
  import { validateStagedMarkdown } from "../traceability/markdown-validate.js";
24
24
  import { extractSymbolsFromStagedFile, } from "../traceability/symbol-extract.js";
25
25
  import { cleanupTempKb, consultOverlay, createOverlayFacts, createTempKb, } from "../traceability/temp-kb.js";
26
26
  import { formatViolations as formatStagedViolations, validateStagedSymbols, } from "../traceability/validate.js";
27
27
  import { loadConfig } from "../utils/config.js";
28
+ import { safeCleanupProlog } from "../utils/prolog-cleanup.js";
28
29
  import { RULES, getEffectiveRules, } from "../utils/rule-registry.js";
29
30
  import { runAggregatedChecks } from "./aggregated-checks.js";
30
31
  import { getCurrentBranch } from "./init-helpers.js";
@@ -83,7 +84,7 @@ export async function checkCommand(options) {
83
84
  const stagedFiles = getStagedFiles();
84
85
  if (!stagedFiles || stagedFiles.length === 0) {
85
86
  console.log("No staged files found.");
86
- process.exit(0);
87
+ return { exitCode: 0 };
87
88
  }
88
89
  const codeFiles = stagedFiles.filter((f) => !f.path.endsWith(".md"));
89
90
  const markdownFiles = stagedFiles.filter((f) => f.path.endsWith(".md"));
@@ -101,9 +102,9 @@ export async function checkCommand(options) {
101
102
  console.log();
102
103
  }
103
104
  if (options.dryRun) {
104
- process.exit(0);
105
+ return { exitCode: 0 };
105
106
  }
106
- process.exit(1);
107
+ return { exitCode: 1 };
107
108
  }
108
109
  const allSymbols = [];
109
110
  for (const f of codeFiles) {
@@ -119,11 +120,11 @@ export async function checkCommand(options) {
119
120
  }
120
121
  if (allSymbols.length === 0 && markdownFiles.length === 0) {
121
122
  console.log("No exported symbols or markdown entities found in staged files.");
122
- process.exit(0);
123
+ return { exitCode: 0 };
123
124
  }
124
125
  if (allSymbols.length === 0) {
125
126
  console.log("✓ No violations found in staged files.");
126
- process.exit(0);
127
+ return { exitCode: 0 };
127
128
  }
128
129
  // Create temp KB
129
130
  tempCtx = await createTempKb(resolvedKbPath);
@@ -140,13 +141,13 @@ export async function checkCommand(options) {
140
141
  console.log(violationsFormatted);
141
142
  await cleanupTempKb(tempCtx.tempDir);
142
143
  if (options.dryRun) {
143
- process.exit(0);
144
+ return { exitCode: 0 };
144
145
  }
145
- process.exit(1);
146
+ return { exitCode: 1 };
146
147
  }
147
148
  console.log("✓ No violations found in staged symbols.");
148
149
  await cleanupTempKb(tempCtx.tempDir);
149
- process.exit(0);
150
+ return { exitCode: 0 };
150
151
  }
151
152
  catch (err) {
152
153
  console.error(`Error running staged validation: ${err instanceof Error ? err.message : String(err)}`);
@@ -154,9 +155,11 @@ export async function checkCommand(options) {
154
155
  try {
155
156
  await cleanupTempKb(tempCtx.tempDir);
156
157
  }
157
- catch { }
158
+ catch {
159
+ // best-effort: temp directory may already be cleaned up
160
+ }
158
161
  }
159
- process.exit(1);
162
+ return { exitCode: 1 };
160
163
  }
161
164
  }
162
165
  prolog = new PrologProcess({ timeout: 120000 });
@@ -166,7 +169,7 @@ export async function checkCommand(options) {
166
169
  if (!attachResult.success) {
167
170
  await prolog.terminate();
168
171
  console.error(`Error: Failed to attach KB: ${attachResult.error}`);
169
- process.exit(1);
172
+ return { exitCode: 1 };
170
173
  }
171
174
  attached = true;
172
175
  const violations = [];
@@ -203,6 +206,7 @@ export async function checkCommand(options) {
203
206
  "required-fields",
204
207
  "deprecated-adr-no-successor",
205
208
  "domain-contradictions",
209
+ "strict-fact-shape",
206
210
  ];
207
211
  const canUseAggregated = Array.from(effectiveRules).every((r) => supportedRules.includes(r));
208
212
  if (canUseAggregated) {
@@ -225,10 +229,11 @@ export async function checkCommand(options) {
225
229
  }
226
230
  await runCheck("deprecated-adr-no-successor", checkDeprecatedAdrs);
227
231
  await runCheck("domain-contradictions", checkDomainContradictions);
232
+ await runCheck("strict-fact-shape", checkStrictFactShape);
228
233
  }
229
234
  if (violations.length === 0) {
230
235
  console.log("✓ No violations found. KB is valid.");
231
- process.exit(0);
236
+ return { exitCode: 0 };
232
237
  }
233
238
  console.log(`Found ${violations.length} violation(s):`);
234
239
  console.log();
@@ -241,26 +246,15 @@ export async function checkCommand(options) {
241
246
  }
242
247
  console.log();
243
248
  }
244
- process.exit(1);
249
+ return { exitCode: 1 };
245
250
  }
246
251
  catch (error) {
247
252
  const message = error instanceof Error ? error.message : String(error);
248
253
  console.error(`Error: ${message}`);
249
- process.exit(1);
254
+ return { exitCode: 1 };
250
255
  }
251
256
  finally {
252
- if (prolog) {
253
- if (attached) {
254
- try {
255
- await prolog.query("kb_detach");
256
- }
257
- catch { }
258
- }
259
- try {
260
- await prolog.terminate();
261
- }
262
- catch { }
263
- }
257
+ await safeCleanupProlog(prolog);
264
258
  }
265
259
  }
266
260
  async function checkMustPriorityCoverage(prolog) {
@@ -545,7 +539,7 @@ async function checkDomainContradictions(prolog) {
545
539
  if (!result.success || !result.bindings.Rows) {
546
540
  return violations;
547
541
  }
548
- const rows = parseTripleRows(result.bindings.Rows);
542
+ const rows = parseTriples(result.bindings.Rows);
549
543
  for (const [reqA, reqB, reason] of rows) {
550
544
  violations.push({
551
545
  rule: "domain-contradictions",
@@ -556,6 +550,22 @@ async function checkDomainContradictions(prolog) {
556
550
  }
557
551
  return violations;
558
552
  }
553
+ async function checkStrictFactShape(prolog) {
554
+ const violations = [];
555
+ const result = await prolog.query(`findall(violation(Rule, EntityId, Desc, Sugg, Src),
556
+ checks:strict_fact_shape_violation(violation(Rule, EntityId, Desc, Sugg, Src)),
557
+ Violations)`);
558
+ if (!result.success || !result.bindings.Violations) {
559
+ return violations;
560
+ }
561
+ const violationsStr = result.bindings.Violations;
562
+ if (violationsStr && violationsStr !== "[]") {
563
+ for (const v of parseViolationRows(violationsStr)) {
564
+ violations.push(v);
565
+ }
566
+ }
567
+ return violations;
568
+ }
559
569
  async function checkSymbolCoverage(prolog) {
560
570
  const violations = [];
561
571
  const uncoveredResult = await prolog.query("setof(Symbol, symbol_no_req_coverage(Symbol, _), Symbols)");
@@ -591,40 +601,9 @@ async function checkSymbolTraceability(prolog, requireAdr) {
591
601
  }
592
602
  const violationsStr = result.bindings.Violations;
593
603
  if (violationsStr && violationsStr !== "[]") {
594
- const violationRegex = /violation\(([^,]+),'?([^',]+)'?,([^,]+),([^,]+),'?([^']*)'?\)/g;
595
- let match;
596
- do {
597
- match = violationRegex.exec(violationsStr);
598
- if (match) {
599
- violations.push({
600
- rule: match[1].trim().replace(/^'|'$/g, ""),
601
- entityId: match[2].trim(),
602
- description: match[3].trim().replace(/^"|"$/g, ""),
603
- suggestion: match[4].trim().replace(/^"|"$/g, ""),
604
- source: match[5].trim() || undefined,
605
- });
606
- }
607
- } while (match);
604
+ for (const v of parseViolationRows(violationsStr)) {
605
+ violations.push(v);
606
+ }
608
607
  }
609
608
  return violations;
610
609
  }
611
- function parseTripleRows(raw) {
612
- const cleaned = raw.trim();
613
- if (cleaned === "[]" || cleaned.length === 0) {
614
- return [];
615
- }
616
- const rows = [];
617
- const rowRegex = /\[([^,]+),([^,]+),([^\]]+)\]/g;
618
- let match;
619
- do {
620
- match = rowRegex.exec(cleaned);
621
- if (match) {
622
- rows.push([
623
- match[1].trim().replace(/^'|'$/g, ""),
624
- match[2].trim().replace(/^'|'$/g, ""),
625
- match[3].trim().replace(/^'|'$/g, ""),
626
- ]);
627
- }
628
- } while (match);
629
- return rows;
630
- }
@@ -0,0 +1,12 @@
1
+ interface CoverageOptions {
2
+ by?: "req" | "symbol" | "type";
3
+ tag?: string;
4
+ includePassing?: boolean;
5
+ includeTransitive?: boolean;
6
+ limit?: string;
7
+ offset?: string;
8
+ format?: "json" | "table";
9
+ }
10
+ export declare function coverageCommand(options: CoverageOptions): Promise<void>;
11
+ export {};
12
+ //# sourceMappingURL=coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/commands/coverage.ts"],"names":[],"mappings":"AAQA,UAAU,eAAe;IACvB,EAAE,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAGD,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC7E"}
@@ -0,0 +1,24 @@
1
+ import { escapeAtom } from "../prolog/codec.js";
2
+ import { printDiscoveryResult, resolveCurrentKbPath, runJsonModuleQuery, withPrologProcess, } from "./discovery-shared.js";
3
+ // implements REQ-002, REQ-003
4
+ export async function coverageCommand(options) {
5
+ await withPrologProcess(async (prolog) => {
6
+ const kbPath = await resolveCurrentKbPath();
7
+ const by = options.by || "req";
8
+ const tags = options.tag
9
+ ? `[${options.tag
10
+ .split(",")
11
+ .map((item) => item.trim())
12
+ .filter(Boolean)
13
+ .map((item) => `'${escapeAtom(item)}'`)
14
+ .join(",")}]`
15
+ : "[]";
16
+ const includePassing = options.includePassing ?? false;
17
+ const includeTransitive = options.includeTransitive ?? true;
18
+ const limit = Number.parseInt(options.limit || "100", 10);
19
+ const offset = Number.parseInt(options.offset || "0", 10);
20
+ const result = await runJsonModuleQuery(prolog, "discovery.pl", `discovery:coverage_report_json('${by}', ${tags}, ${includePassing}, ${includeTransitive}, ${limit}, ${offset}, JsonString)`, "coverage query failed", kbPath);
21
+ const summary = (result.summary ?? {});
22
+ printDiscoveryResult(options.format, result, `Coverage summary: ${summary.fullyCovered ?? 0} fully covered out of ${summary.total ?? 0}.`);
23
+ });
24
+ }
@@ -0,0 +1,11 @@
1
+ import { PrologProcess } from "../prolog.js";
2
+ export interface DiscoveryCommandOptions {
3
+ format?: "json" | "table";
4
+ }
5
+ export declare function withAttachedBranchProlog<T>(callback: (prolog: PrologProcess) => Promise<T>): Promise<T>;
6
+ export declare function withPrologProcess<T>(callback: (prolog: PrologProcess) => Promise<T>): Promise<T>;
7
+ export declare function resolveCurrentKbPath(): Promise<string>;
8
+ export declare function resolveCoreModulePath(fileName: string): string;
9
+ export declare function runJsonModuleQuery<T>(prolog: PrologProcess, fileName: string, goal: string, errorLabel: string, kbPath?: string): Promise<T>;
10
+ export declare function printDiscoveryResult(format: "json" | "table" | undefined, structured: unknown, fallbackText: string): void;
11
+ //# sourceMappingURL=discovery-shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery-shared.d.ts","sourceRoot":"","sources":["../../src/commands/discovery-shared.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAmB,MAAM,cAAc,CAAC;AAK9D,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAGD,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAC9C,OAAO,CAAC,CAAC,CAAC,CAkCZ;AAGD,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAC9C,OAAO,CAAC,CAAC,CAAC,CAYZ;AAGD,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC,CAS5D;AAGD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE9D;AAGD,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,CAAC,CAAC,CAwBZ;AAGD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,EACpC,UAAU,EAAE,OAAO,EACnB,YAAY,EAAE,MAAM,GACnB,IAAI,CAQN"}