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.
- package/dist/cli.d.ts +4 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +91 -14
- package/dist/commands/check.d.ts +5 -8
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +41 -62
- package/dist/commands/coverage.d.ts +12 -0
- package/dist/commands/coverage.d.ts.map +1 -0
- package/dist/commands/coverage.js +24 -0
- package/dist/commands/discovery-shared.d.ts +11 -0
- package/dist/commands/discovery-shared.d.ts.map +1 -0
- package/dist/commands/discovery-shared.js +281 -0
- package/dist/commands/doctor.d.ts +3 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +12 -13
- package/dist/commands/gaps.d.ts +12 -0
- package/dist/commands/gaps.d.ts.map +1 -0
- package/dist/commands/gaps.js +28 -0
- package/dist/commands/graph.d.ts +13 -0
- package/dist/commands/graph.d.ts.map +1 -0
- package/dist/commands/graph.js +35 -0
- package/dist/commands/init.d.ts +3 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +4 -3
- package/dist/commands/query.d.ts +3 -1
- package/dist/commands/query.d.ts.map +1 -1
- package/dist/commands/query.js +9 -20
- package/dist/commands/search.d.ts +9 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +38 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +9 -0
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +79 -12
- package/dist/commands/sync.d.ts +4 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +79 -31
- package/dist/extractors/markdown.d.ts +17 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +104 -14
- package/dist/prolog/codec.d.ts +32 -5
- package/dist/prolog/codec.d.ts.map +1 -1
- package/dist/prolog/codec.js +95 -58
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +12 -2
- package/dist/public/check-types.d.ts +7 -0
- package/dist/public/check-types.d.ts.map +1 -0
- package/dist/public/check-types.js +18 -0
- package/dist/public/schemas/entity.d.ts +68 -0
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +52 -0
- package/dist/relationships/shards.d.ts.map +1 -1
- package/dist/relationships/shards.js +6 -3
- package/dist/schemas/entity.schema.json +120 -0
- package/dist/search-ranking.d.ts +9 -0
- package/dist/search-ranking.d.ts.map +1 -0
- package/dist/search-ranking.js +149 -0
- package/dist/traceability/symbol-extract.d.ts.map +1 -1
- package/dist/traceability/symbol-extract.js +16 -8
- package/dist/types/entities.d.ts +19 -1
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/utils/prolog-cleanup.d.ts +10 -0
- package/dist/utils/prolog-cleanup.d.ts.map +1 -0
- package/dist/utils/prolog-cleanup.js +39 -0
- package/dist/utils/rule-registry.d.ts +8 -0
- package/dist/utils/rule-registry.d.ts.map +1 -1
- package/dist/utils/rule-registry.js +14 -12
- package/package.json +10 -2
- package/schema/config.json +7 -1
- package/schema/entities.pl +18 -0
- package/schema/validation.pl +115 -4
- package/src/public/check-types.ts +37 -0
- package/src/public/schemas/entity.ts +58 -0
- package/src/schemas/entity.schema.json +56 -1
- package/dist/kb/target-resolver.d.ts +0 -80
- package/dist/kb/target-resolver.d.ts.map +0 -1
- package/dist/kb/target-resolver.js +0 -313
package/dist/cli.d.ts
CHANGED
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
+
});
|
package/dist/commands/check.d.ts
CHANGED
|
@@ -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
|
|
10
|
-
|
|
11
|
-
|
|
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":"
|
|
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"}
|
package/dist/commands/check.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
105
|
+
return { exitCode: 0 };
|
|
105
106
|
}
|
|
106
|
-
|
|
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
|
-
|
|
123
|
+
return { exitCode: 0 };
|
|
123
124
|
}
|
|
124
125
|
if (allSymbols.length === 0) {
|
|
125
126
|
console.log("✓ No violations found in staged files.");
|
|
126
|
-
|
|
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
|
-
|
|
144
|
+
return { exitCode: 0 };
|
|
144
145
|
}
|
|
145
|
-
|
|
146
|
+
return { exitCode: 1 };
|
|
146
147
|
}
|
|
147
148
|
console.log("✓ No violations found in staged symbols.");
|
|
148
149
|
await cleanupTempKb(tempCtx.tempDir);
|
|
149
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
254
|
+
return { exitCode: 1 };
|
|
250
255
|
}
|
|
251
256
|
finally {
|
|
252
|
-
|
|
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 =
|
|
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
|
|
595
|
-
|
|
596
|
-
|
|
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"}
|