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
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import Table from "cli-table3";
|
|
3
|
+
import { PrologProcess, resolveKbPlPath } from "../prolog.js";
|
|
4
|
+
import { escapeAtom } from "../prolog/codec.js";
|
|
5
|
+
import { safeCleanupProlog } from "../utils/prolog-cleanup.js";
|
|
6
|
+
import { getCurrentBranch } from "./init-helpers.js";
|
|
7
|
+
// implements REQ-003
|
|
8
|
+
export async function withAttachedBranchProlog(callback) {
|
|
9
|
+
let prolog = null;
|
|
10
|
+
let attached = false;
|
|
11
|
+
try {
|
|
12
|
+
prolog = new PrologProcess({ timeout: 120000 });
|
|
13
|
+
await prolog.start();
|
|
14
|
+
await prolog.query("set_prolog_flag(answer_write_options, [max_depth(0), spacing(next_argument)])");
|
|
15
|
+
let branch;
|
|
16
|
+
try {
|
|
17
|
+
branch =
|
|
18
|
+
process.env.KIBI_BRANCH || (await getCurrentBranch(process.cwd()));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
branch = process.env.KIBI_BRANCH || "main";
|
|
22
|
+
}
|
|
23
|
+
const kbPath = path.join(process.cwd(), ".kb/branches", branch);
|
|
24
|
+
const attachResult = await prolog.query(`kb_attach('${escapeAtom(kbPath)}')`);
|
|
25
|
+
if (!attachResult.success) {
|
|
26
|
+
throw new Error(`Failed to attach KB: ${attachResult.error || "Unknown error"}`);
|
|
27
|
+
}
|
|
28
|
+
attached = true;
|
|
29
|
+
return await callback(prolog);
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
await safeCleanupProlog(prolog);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// implements REQ-003
|
|
36
|
+
export async function withPrologProcess(callback) {
|
|
37
|
+
const prolog = new PrologProcess({ timeout: 120000 });
|
|
38
|
+
try {
|
|
39
|
+
await prolog.start();
|
|
40
|
+
prolog.useOneShotMode = true;
|
|
41
|
+
await prolog.query("set_prolog_flag(answer_write_options, [max_depth(0), spacing(next_argument)])");
|
|
42
|
+
return await callback(prolog);
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
await safeCleanupProlog(prolog);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// implements REQ-003
|
|
49
|
+
export async function resolveCurrentKbPath() {
|
|
50
|
+
let branch;
|
|
51
|
+
try {
|
|
52
|
+
branch = process.env.KIBI_BRANCH || (await getCurrentBranch(process.cwd()));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
branch = process.env.KIBI_BRANCH || "main";
|
|
56
|
+
}
|
|
57
|
+
return path.join(process.cwd(), ".kb/branches", branch);
|
|
58
|
+
}
|
|
59
|
+
// implements REQ-003
|
|
60
|
+
export function resolveCoreModulePath(fileName) {
|
|
61
|
+
return path.join(path.dirname(resolveKbPlPath()), fileName);
|
|
62
|
+
}
|
|
63
|
+
// implements REQ-003
|
|
64
|
+
export async function runJsonModuleQuery(prolog, fileName, goal, errorLabel, kbPath) {
|
|
65
|
+
const modulePath = escapeAtom(resolveCoreModulePath(fileName).replace(/\\/g, "/"));
|
|
66
|
+
const wrappedGoal = kbPath
|
|
67
|
+
? `(use_module('${modulePath}'), kb_attach('${escapeAtom(kbPath)}'), ${goal}, kb_detach)`
|
|
68
|
+
: `(use_module('${modulePath}'), ${goal})`;
|
|
69
|
+
const result = await prolog.query(wrappedGoal);
|
|
70
|
+
if (!result.success) {
|
|
71
|
+
throw new Error(`${errorLabel}: ${result.error || "Unknown error"}`);
|
|
72
|
+
}
|
|
73
|
+
const rawJson = result.bindings.JsonString;
|
|
74
|
+
if (!rawJson) {
|
|
75
|
+
throw new Error(`${errorLabel}: missing JsonString binding`);
|
|
76
|
+
}
|
|
77
|
+
let parsed = JSON.parse(rawJson);
|
|
78
|
+
if (typeof parsed === "string") {
|
|
79
|
+
parsed = JSON.parse(parsed);
|
|
80
|
+
}
|
|
81
|
+
return parsed;
|
|
82
|
+
}
|
|
83
|
+
// implements REQ-003
|
|
84
|
+
export function printDiscoveryResult(format, structured, fallbackText) {
|
|
85
|
+
if (format === "json") {
|
|
86
|
+
console.log(JSON.stringify(structured, null, 2));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const rendered = renderDiscoveryTable(structured);
|
|
90
|
+
console.log(rendered || fallbackText);
|
|
91
|
+
}
|
|
92
|
+
function renderDiscoveryTable(structured) {
|
|
93
|
+
if (!structured || typeof structured !== "object") {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const payload = structured;
|
|
97
|
+
if (Array.isArray(payload.results)) {
|
|
98
|
+
return renderSearchTable(payload);
|
|
99
|
+
}
|
|
100
|
+
if (typeof payload.branch === "string" &&
|
|
101
|
+
typeof payload.syncState === "string") {
|
|
102
|
+
return renderStatusTable(payload);
|
|
103
|
+
}
|
|
104
|
+
if (Array.isArray(payload.nodes) && Array.isArray(payload.edges)) {
|
|
105
|
+
return renderGraphTable(payload);
|
|
106
|
+
}
|
|
107
|
+
if (Array.isArray(payload.rows) &&
|
|
108
|
+
payload.summary &&
|
|
109
|
+
typeof payload.summary === "object") {
|
|
110
|
+
return renderCoverageTable(payload);
|
|
111
|
+
}
|
|
112
|
+
if (Array.isArray(payload.rows)) {
|
|
113
|
+
return renderGapsTable(payload);
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
function renderSearchTable(payload) {
|
|
118
|
+
const rows = Array.isArray(payload.results) ? payload.results : [];
|
|
119
|
+
const table = new Table({
|
|
120
|
+
head: ["ID", "Type", "Title", "Score", "Reasons", "Snippet"],
|
|
121
|
+
wordWrap: true,
|
|
122
|
+
colWidths: [20, 10, 32, 8, 28, 44],
|
|
123
|
+
});
|
|
124
|
+
for (const row of rows) {
|
|
125
|
+
const match = row;
|
|
126
|
+
const entity = (match.entity ?? {});
|
|
127
|
+
const reasons = Array.isArray(match.reasons)
|
|
128
|
+
? match.reasons.join(", ")
|
|
129
|
+
: "";
|
|
130
|
+
table.push([
|
|
131
|
+
stringifyCell(entity.id),
|
|
132
|
+
stringifyCell(entity.type),
|
|
133
|
+
stringifyCell(entity.title),
|
|
134
|
+
stringifyCell(match.score),
|
|
135
|
+
reasons,
|
|
136
|
+
stringifyCell(match.snippet),
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
139
|
+
return [
|
|
140
|
+
`Search results: ${stringifyCell(payload.count)} total`,
|
|
141
|
+
table.toString(),
|
|
142
|
+
].join("\n");
|
|
143
|
+
}
|
|
144
|
+
function renderStatusTable(payload) {
|
|
145
|
+
const table = new Table({
|
|
146
|
+
head: ["Field", "Value"],
|
|
147
|
+
colWidths: [18, 72],
|
|
148
|
+
wordWrap: true,
|
|
149
|
+
});
|
|
150
|
+
table.push(["Branch", stringifyCell(payload.branch)], ["Sync State", stringifyCell(payload.syncState)], ["Dirty", stringifyCell(payload.dirty)], ["Snapshot", stringifyCell(payload.snapshotId)], ["Synced At", stringifyCell(payload.syncedAt)], ["KB Path", stringifyCell(payload.kbPath)]);
|
|
151
|
+
return table.toString();
|
|
152
|
+
}
|
|
153
|
+
function renderGapsTable(payload) {
|
|
154
|
+
const rows = Array.isArray(payload.rows) ? payload.rows : [];
|
|
155
|
+
const table = new Table({
|
|
156
|
+
head: ["ID", "Type", "Status", "Missing", "Present", "Source"],
|
|
157
|
+
colWidths: [20, 10, 12, 24, 24, 40],
|
|
158
|
+
wordWrap: true,
|
|
159
|
+
});
|
|
160
|
+
for (const row of rows) {
|
|
161
|
+
const item = row;
|
|
162
|
+
table.push([
|
|
163
|
+
stringifyCell(item.id),
|
|
164
|
+
stringifyCell(item.type),
|
|
165
|
+
stringifyCell(item.status),
|
|
166
|
+
joinCells(item.missingRelationships),
|
|
167
|
+
joinCells(item.presentRelationships),
|
|
168
|
+
stringifyCell(item.source),
|
|
169
|
+
]);
|
|
170
|
+
}
|
|
171
|
+
return [`Gap rows: ${stringifyCell(payload.count)}`, table.toString()].join("\n");
|
|
172
|
+
}
|
|
173
|
+
function renderCoverageTable(payload) {
|
|
174
|
+
const summary = (payload.summary ?? {});
|
|
175
|
+
const rows = Array.isArray(payload.rows) ? payload.rows : [];
|
|
176
|
+
const summaryTable = new Table({
|
|
177
|
+
head: ["Metric", "Value"],
|
|
178
|
+
colWidths: [24, 16],
|
|
179
|
+
});
|
|
180
|
+
for (const [key, value] of Object.entries(summary)) {
|
|
181
|
+
summaryTable.push([key, stringifyCell(value)]);
|
|
182
|
+
}
|
|
183
|
+
const firstRow = rows[0];
|
|
184
|
+
const isRequirementCoverage = firstRow && Object.hasOwn(firstRow, "scenarioCount");
|
|
185
|
+
const table = isRequirementCoverage
|
|
186
|
+
? new Table({
|
|
187
|
+
head: [
|
|
188
|
+
"ID",
|
|
189
|
+
"Status",
|
|
190
|
+
"Priority",
|
|
191
|
+
"Coverage",
|
|
192
|
+
"Scen",
|
|
193
|
+
"Tests",
|
|
194
|
+
"Symbols",
|
|
195
|
+
"Gaps",
|
|
196
|
+
],
|
|
197
|
+
colWidths: [20, 12, 12, 18, 8, 8, 10, 28],
|
|
198
|
+
wordWrap: true,
|
|
199
|
+
})
|
|
200
|
+
: new Table({
|
|
201
|
+
head: ["ID", "Type", "Coverage", "Details", "Gaps"],
|
|
202
|
+
colWidths: [20, 10, 18, 28, 28],
|
|
203
|
+
wordWrap: true,
|
|
204
|
+
});
|
|
205
|
+
for (const row of rows) {
|
|
206
|
+
const item = row;
|
|
207
|
+
if (isRequirementCoverage) {
|
|
208
|
+
table.push([
|
|
209
|
+
stringifyCell(item.id),
|
|
210
|
+
stringifyCell(item.status),
|
|
211
|
+
stringifyCell(item.priority),
|
|
212
|
+
stringifyCell(item.coverageStatus),
|
|
213
|
+
stringifyCell(item.scenarioCount),
|
|
214
|
+
stringifyCell(item.testCount),
|
|
215
|
+
stringifyCell(item.transitiveSymbolCount),
|
|
216
|
+
joinCells(item.gaps),
|
|
217
|
+
]);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
table.push([
|
|
221
|
+
stringifyCell(item.id),
|
|
222
|
+
stringifyCell(item.type),
|
|
223
|
+
stringifyCell(item.coverageStatus),
|
|
224
|
+
`req=${stringifyCell(item.directRequirementCount)} test=${stringifyCell(item.testCount)} count=${stringifyCell(item.count)}`,
|
|
225
|
+
joinCells(item.gaps),
|
|
226
|
+
]);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return [summaryTable.toString(), table.toString()].join("\n\n");
|
|
230
|
+
}
|
|
231
|
+
function renderGraphTable(payload) {
|
|
232
|
+
const nodes = Array.isArray(payload.nodes) ? payload.nodes : [];
|
|
233
|
+
const edges = Array.isArray(payload.edges) ? payload.edges : [];
|
|
234
|
+
const nodeTable = new Table({
|
|
235
|
+
head: ["Node ID", "Type", "Title", "Status"],
|
|
236
|
+
colWidths: [22, 10, 36, 12],
|
|
237
|
+
wordWrap: true,
|
|
238
|
+
});
|
|
239
|
+
for (const row of nodes) {
|
|
240
|
+
const item = row;
|
|
241
|
+
nodeTable.push([
|
|
242
|
+
stringifyCell(item.id),
|
|
243
|
+
stringifyCell(item.type),
|
|
244
|
+
stringifyCell(item.title),
|
|
245
|
+
stringifyCell(item.status),
|
|
246
|
+
]);
|
|
247
|
+
}
|
|
248
|
+
const edgeTable = new Table({
|
|
249
|
+
head: ["Relationship", "From", "To"],
|
|
250
|
+
colWidths: [18, 22, 22],
|
|
251
|
+
wordWrap: true,
|
|
252
|
+
});
|
|
253
|
+
for (const row of edges) {
|
|
254
|
+
const item = row;
|
|
255
|
+
edgeTable.push([
|
|
256
|
+
stringifyCell(item.type),
|
|
257
|
+
stringifyCell(item.from),
|
|
258
|
+
stringifyCell(item.to),
|
|
259
|
+
]);
|
|
260
|
+
}
|
|
261
|
+
return [
|
|
262
|
+
`Nodes: ${nodes.length} Edges: ${edges.length} Truncated: ${stringifyCell(payload.truncated)}`,
|
|
263
|
+
nodeTable.toString(),
|
|
264
|
+
edgeTable.toString(),
|
|
265
|
+
].join("\n\n");
|
|
266
|
+
}
|
|
267
|
+
function stringifyCell(value) {
|
|
268
|
+
if (value === null || value === undefined || value === "") {
|
|
269
|
+
return "-";
|
|
270
|
+
}
|
|
271
|
+
if (typeof value === "string") {
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
return String(value);
|
|
275
|
+
}
|
|
276
|
+
function joinCells(value) {
|
|
277
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
278
|
+
return "-";
|
|
279
|
+
}
|
|
280
|
+
return value.map((item) => stringifyCell(item)).join(", ");
|
|
281
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AA4BA,wBAAsB,aAAa,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAyDnE"}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { execSync } from "node:child_process";
|
|
19
19
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
20
20
|
import * as path from "node:path";
|
|
21
|
+
// implements REQ-003
|
|
21
22
|
export async function doctorCommand() {
|
|
22
23
|
const checks = [
|
|
23
24
|
{
|
|
@@ -65,12 +66,10 @@ export async function doctorCommand() {
|
|
|
65
66
|
console.log();
|
|
66
67
|
if (allPassed) {
|
|
67
68
|
console.log("All checks passed! Your environment is ready.");
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
console.log("Some checks failed. Please address the issues above.");
|
|
72
|
-
process.exit(1);
|
|
69
|
+
return { exitCode: 0 };
|
|
73
70
|
}
|
|
71
|
+
console.log("Some checks failed. Please address the issues above.");
|
|
72
|
+
return { exitCode: 1 };
|
|
74
73
|
}
|
|
75
74
|
function checkSWIProlog() {
|
|
76
75
|
try {
|
|
@@ -198,7 +197,7 @@ function checkGitHooks() {
|
|
|
198
197
|
return {
|
|
199
198
|
passed: false,
|
|
200
199
|
message: "Partially installed",
|
|
201
|
-
remediation: "Run: kibi init
|
|
200
|
+
remediation: "Run: kibi init",
|
|
202
201
|
};
|
|
203
202
|
}
|
|
204
203
|
function checkPreCommitHook() {
|
|
@@ -218,7 +217,7 @@ function checkPreCommitHook() {
|
|
|
218
217
|
return {
|
|
219
218
|
passed: false,
|
|
220
219
|
message: "Not installed",
|
|
221
|
-
remediation: "Run: kibi init
|
|
220
|
+
remediation: "Run: kibi init",
|
|
222
221
|
};
|
|
223
222
|
}
|
|
224
223
|
try {
|
|
@@ -233,7 +232,7 @@ function checkPreCommitHook() {
|
|
|
233
232
|
return {
|
|
234
233
|
passed: false,
|
|
235
234
|
message: "pre-commit hook installed but does not invoke kibi",
|
|
236
|
-
remediation: "Run: kibi init
|
|
235
|
+
remediation: "Run: kibi init to install recommended hooks",
|
|
237
236
|
};
|
|
238
237
|
}
|
|
239
238
|
if (preCommitExecutable) {
|
|
@@ -247,7 +246,7 @@ function checkPreCommitHook() {
|
|
|
247
246
|
return {
|
|
248
247
|
passed: true,
|
|
249
248
|
message: "Installed and executable (uses legacy 'kibi check' — consider running 'kibi init' to update hooks to use '--staged')",
|
|
250
|
-
remediation: "Run: kibi init
|
|
249
|
+
remediation: "Run: kibi init to update git hooks to the latest template",
|
|
251
250
|
};
|
|
252
251
|
}
|
|
253
252
|
return {
|
|
@@ -260,7 +259,7 @@ function checkPreCommitHook() {
|
|
|
260
259
|
return {
|
|
261
260
|
passed: false,
|
|
262
261
|
message: "Unable to check hook permissions or read content",
|
|
263
|
-
remediation: "Run: kibi init
|
|
262
|
+
remediation: "Run: kibi init",
|
|
264
263
|
};
|
|
265
264
|
}
|
|
266
265
|
}
|
|
@@ -281,7 +280,7 @@ function checkPostRewriteHook() {
|
|
|
281
280
|
return {
|
|
282
281
|
passed: false,
|
|
283
282
|
message: "Not installed",
|
|
284
|
-
remediation: "Run: kibi init
|
|
283
|
+
remediation: "Run: kibi init",
|
|
285
284
|
};
|
|
286
285
|
}
|
|
287
286
|
try {
|
|
@@ -294,7 +293,7 @@ function checkPostRewriteHook() {
|
|
|
294
293
|
return {
|
|
295
294
|
passed: false,
|
|
296
295
|
message: "post-rewrite hook installed but does not invoke kibi",
|
|
297
|
-
remediation: "Run: kibi init
|
|
296
|
+
remediation: "Run: kibi init to install recommended hooks",
|
|
298
297
|
};
|
|
299
298
|
}
|
|
300
299
|
if (postRewriteExecutable) {
|
|
@@ -313,7 +312,7 @@ function checkPostRewriteHook() {
|
|
|
313
312
|
return {
|
|
314
313
|
passed: false,
|
|
315
314
|
message: "Unable to check hook permissions or read content",
|
|
316
|
-
remediation: "Run: kibi init
|
|
315
|
+
remediation: "Run: kibi init",
|
|
317
316
|
};
|
|
318
317
|
}
|
|
319
318
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface GapsOptions {
|
|
2
|
+
missingRel?: string;
|
|
3
|
+
presentRel?: string;
|
|
4
|
+
tag?: string;
|
|
5
|
+
source?: string;
|
|
6
|
+
limit?: string;
|
|
7
|
+
offset?: string;
|
|
8
|
+
format?: "json" | "table";
|
|
9
|
+
}
|
|
10
|
+
export declare function gapsCommand(type: string | undefined, options: GapsOptions): Promise<void>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=gaps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gaps.d.ts","sourceRoot":"","sources":["../../src/commands/gaps.ts"],"names":[],"mappings":"AAQA,UAAU,WAAW;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAGD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAyBf"}
|
|
@@ -0,0 +1,28 @@
|
|
|
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 gapsCommand(type, options) {
|
|
5
|
+
await withPrologProcess(async (prolog) => {
|
|
6
|
+
const kbPath = await resolveCurrentKbPath();
|
|
7
|
+
const missing = csvToPrologList(options.missingRel);
|
|
8
|
+
const present = csvToPrologList(options.presentRel);
|
|
9
|
+
const tags = csvToPrologList(options.tag);
|
|
10
|
+
const source = options.source ? `'${escapeAtom(options.source)}'` : "none";
|
|
11
|
+
const limit = Number.parseInt(options.limit || "100", 10);
|
|
12
|
+
const offset = Number.parseInt(options.offset || "0", 10);
|
|
13
|
+
const typeArg = type ? `'${escapeAtom(type)}'` : "none";
|
|
14
|
+
const result = await runJsonModuleQuery(prolog, "discovery.pl", `discovery:find_gaps_json(${typeArg}, ${missing}, ${present}, ${tags}, ${source}, ${limit}, ${offset}, JsonString)`, "gaps query failed", kbPath);
|
|
15
|
+
printDiscoveryResult(options.format, result, `Found ${result.count ?? 0} gap rows.`);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function csvToPrologList(value) {
|
|
19
|
+
if (!value?.trim()) {
|
|
20
|
+
return "[]";
|
|
21
|
+
}
|
|
22
|
+
return `[${value
|
|
23
|
+
.split(",")
|
|
24
|
+
.map((item) => item.trim())
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.map((item) => `'${escapeAtom(item)}'`)
|
|
27
|
+
.join(",")}]`;
|
|
28
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface GraphOptions {
|
|
2
|
+
from?: string;
|
|
3
|
+
relationships?: string;
|
|
4
|
+
direction?: "outgoing" | "incoming" | "both";
|
|
5
|
+
depth?: string;
|
|
6
|
+
entityTypes?: string;
|
|
7
|
+
maxNodes?: string;
|
|
8
|
+
maxEdges?: string;
|
|
9
|
+
format?: "json" | "table";
|
|
10
|
+
}
|
|
11
|
+
export declare function graphCommand(options: GraphOptions): Promise<void>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/commands/graph.ts"],"names":[],"mappings":"AAQA,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAGD,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAiCvE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
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 graphCommand(options) {
|
|
5
|
+
if (!options.from?.trim()) {
|
|
6
|
+
console.error("Error: --from is required");
|
|
7
|
+
process.exitCode = 1;
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
await withPrologProcess(async (prolog) => {
|
|
11
|
+
const kbPath = await resolveCurrentKbPath();
|
|
12
|
+
const seedIds = csvToPrologList(options.from);
|
|
13
|
+
const relationships = csvToPrologList(options.relationships);
|
|
14
|
+
const direction = options.direction || "outgoing";
|
|
15
|
+
const depth = Number.parseInt(options.depth || "1", 10);
|
|
16
|
+
const entityTypes = csvToPrologList(options.entityTypes);
|
|
17
|
+
const maxNodes = Number.parseInt(options.maxNodes || "200", 10);
|
|
18
|
+
const maxEdges = Number.parseInt(options.maxEdges || "500", 10);
|
|
19
|
+
const result = await runJsonModuleQuery(prolog, "discovery.pl", `discovery:graph_expand_json(${seedIds}, ${relationships}, '${direction}', ${depth}, ${entityTypes}, ${maxNodes}, ${maxEdges}, JsonString)`, "graph query failed", kbPath);
|
|
20
|
+
const nodes = Array.isArray(result.nodes) ? result.nodes.length : 0;
|
|
21
|
+
const edges = Array.isArray(result.edges) ? result.edges.length : 0;
|
|
22
|
+
printDiscoveryResult(options.format, result, `Graph traversal returned ${nodes} nodes and ${edges} edges.`);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function csvToPrologList(value) {
|
|
26
|
+
if (!value?.trim()) {
|
|
27
|
+
return "[]";
|
|
28
|
+
}
|
|
29
|
+
return `[${value
|
|
30
|
+
.split(",")
|
|
31
|
+
.map((item) => item.trim())
|
|
32
|
+
.filter(Boolean)
|
|
33
|
+
.map((item) => `'${escapeAtom(item)}'`)
|
|
34
|
+
.join(",")}]`;
|
|
35
|
+
}
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
interface InitOptions {
|
|
2
2
|
hooks?: boolean;
|
|
3
3
|
}
|
|
4
|
-
export declare function initCommand(options: InitOptions): Promise<
|
|
4
|
+
export declare function initCommand(options: InitOptions): Promise<{
|
|
5
|
+
exitCode: number;
|
|
6
|
+
}>;
|
|
5
7
|
export {};
|
|
6
8
|
//# sourceMappingURL=init.d.ts.map
|
|
@@ -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;
|
|
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"}
|
package/dist/commands/init.js
CHANGED
|
@@ -22,6 +22,7 @@ import { resolveActiveBranch } from "../utils/branch-resolver.js";
|
|
|
22
22
|
import { copySchemaFiles, createConfigFile, createKbDirectoryStructure, installGitHooks, updateGitIgnore, } from "./init-helpers.js";
|
|
23
23
|
const __filename = fileURLToPath(import.meta.url);
|
|
24
24
|
const __dirname = path.dirname(__filename);
|
|
25
|
+
// implements REQ-003
|
|
25
26
|
export async function initCommand(options) {
|
|
26
27
|
const kbDir = path.join(process.cwd(), ".kb");
|
|
27
28
|
const kbExists = existsSync(kbDir);
|
|
@@ -40,7 +41,7 @@ export async function initCommand(options) {
|
|
|
40
41
|
else {
|
|
41
42
|
console.error("Error: Failed to resolve the active git branch.");
|
|
42
43
|
console.error(result.error);
|
|
43
|
-
|
|
44
|
+
return { exitCode: 1 };
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
else {
|
|
@@ -70,10 +71,10 @@ export async function initCommand(options) {
|
|
|
70
71
|
console.log("Next steps:");
|
|
71
72
|
console.log(" 1. Run 'kibi doctor' to verify setup");
|
|
72
73
|
console.log(" 2. Run 'kibi sync' to extract entities from documents");
|
|
73
|
-
|
|
74
|
+
return { exitCode: 0 };
|
|
74
75
|
}
|
|
75
76
|
catch (error) {
|
|
76
77
|
console.error("Error during initialization:", error);
|
|
77
|
-
|
|
78
|
+
return { exitCode: 1 };
|
|
78
79
|
}
|
|
79
80
|
}
|
package/dist/commands/query.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ interface QueryOptions {
|
|
|
7
7
|
limit?: string;
|
|
8
8
|
offset?: string;
|
|
9
9
|
}
|
|
10
|
-
export declare function queryCommand(type: string | undefined, options: QueryOptions): Promise<
|
|
10
|
+
export declare function queryCommand(type: string | undefined, options: QueryOptions): Promise<{
|
|
11
|
+
exitCode: number;
|
|
12
|
+
}>;
|
|
11
13
|
export {};
|
|
12
14
|
//# sourceMappingURL=query.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AA4CA,UAAU,YAAY;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA+J/B"}
|
package/dist/commands/query.js
CHANGED
|
@@ -22,6 +22,7 @@ import { parseEntityFromBinding, parseEntityFromList, parseListOfLists, parsePro
|
|
|
22
22
|
import relationshipSchema from "../public/schemas/relationship.js";
|
|
23
23
|
import { VALID_ENTITY_TYPES } from "../query/service.js";
|
|
24
24
|
import { resolveActiveBranch } from "../utils/branch-resolver.js";
|
|
25
|
+
import { safeCleanupProlog } from "../utils/prolog-cleanup.js";
|
|
25
26
|
const REL_TYPES = relationshipSchema.properties.type.enum;
|
|
26
27
|
// implements REQ-003
|
|
27
28
|
export async function queryCommand(type, options) {
|
|
@@ -45,7 +46,7 @@ export async function queryCommand(type, options) {
|
|
|
45
46
|
else {
|
|
46
47
|
console.error(`Error: Failed to resolve active branch:\n${branchResult.error}`);
|
|
47
48
|
await prolog.terminate();
|
|
48
|
-
|
|
49
|
+
return { exitCode: 1 };
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
else {
|
|
@@ -56,7 +57,7 @@ export async function queryCommand(type, options) {
|
|
|
56
57
|
if (!attachResult.success) {
|
|
57
58
|
await prolog.terminate();
|
|
58
59
|
console.error(`Error: Failed to attach KB: ${attachResult.error || "Unknown error"}`);
|
|
59
|
-
|
|
60
|
+
return { exitCode: 1 };
|
|
60
61
|
}
|
|
61
62
|
attached = true;
|
|
62
63
|
let results = [];
|
|
@@ -86,8 +87,7 @@ export async function queryCommand(type, options) {
|
|
|
86
87
|
else if (type || options.source) {
|
|
87
88
|
if (type && !VALID_ENTITY_TYPES.includes(type)) {
|
|
88
89
|
console.error(`Error: Invalid type '${type}'. Valid types: ${VALID_ENTITY_TYPES.join(", ")}`);
|
|
89
|
-
|
|
90
|
-
return;
|
|
90
|
+
return { exitCode: 1 };
|
|
91
91
|
}
|
|
92
92
|
let goal;
|
|
93
93
|
if (options.source) {
|
|
@@ -133,8 +133,7 @@ export async function queryCommand(type, options) {
|
|
|
133
133
|
}
|
|
134
134
|
else {
|
|
135
135
|
console.error("Error: Must specify entity type, --source, or --relationships option");
|
|
136
|
-
|
|
137
|
-
return;
|
|
136
|
+
return { exitCode: 1 };
|
|
138
137
|
}
|
|
139
138
|
const limit = Number.parseInt(options.limit || "100");
|
|
140
139
|
const offset = Number.parseInt(options.offset || "0");
|
|
@@ -146,7 +145,7 @@ export async function queryCommand(type, options) {
|
|
|
146
145
|
else {
|
|
147
146
|
console.log("No entities found");
|
|
148
147
|
}
|
|
149
|
-
return;
|
|
148
|
+
return { exitCode: 0 };
|
|
150
149
|
}
|
|
151
150
|
// Format output
|
|
152
151
|
if (options.format === "table") {
|
|
@@ -155,25 +154,15 @@ export async function queryCommand(type, options) {
|
|
|
155
154
|
else {
|
|
156
155
|
console.log(JSON.stringify(paginated, null, 2));
|
|
157
156
|
}
|
|
157
|
+
return { exitCode: 0 };
|
|
158
158
|
}
|
|
159
159
|
catch (error) {
|
|
160
160
|
const message = error instanceof Error ? error.message : String(error);
|
|
161
161
|
console.error(`Error: ${message}`);
|
|
162
|
-
|
|
162
|
+
return { exitCode: 1 };
|
|
163
163
|
}
|
|
164
164
|
finally {
|
|
165
|
-
|
|
166
|
-
if (attached) {
|
|
167
|
-
try {
|
|
168
|
-
await prolog.query("kb_detach");
|
|
169
|
-
}
|
|
170
|
-
catch { }
|
|
171
|
-
}
|
|
172
|
-
try {
|
|
173
|
-
await prolog.terminate();
|
|
174
|
-
}
|
|
175
|
-
catch { }
|
|
176
|
-
}
|
|
165
|
+
await safeCleanupProlog(prolog);
|
|
177
166
|
}
|
|
178
167
|
}
|
|
179
168
|
/**
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface SearchOptions {
|
|
2
|
+
type?: string;
|
|
3
|
+
format?: "json" | "table";
|
|
4
|
+
limit?: string;
|
|
5
|
+
offset?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function searchCommand(query: string | undefined, options: SearchOptions): Promise<void>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AASA,UAAU,aAAa;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
|