kibi-mcp 0.22.0 → 2.0.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/bin/kibi-mcp +12 -11
- package/dist/diagnostics.js +68 -8
- package/dist/env.js +5 -1
- package/dist/runtime/mcp-runtime.js +39 -3
- package/dist/server/docs.js +31 -42
- package/dist/server/icons.js +27 -0
- package/dist/server/jobs.js +107 -0
- package/dist/server/json-schema-to-zod.js +33 -9
- package/dist/server/session.js +129 -133
- package/dist/server/tool-registration.js +46 -9
- package/dist/server/tools-runtime.js +10 -10
- package/dist/server/tools.js +143 -7
- package/dist/server.js +16 -1
- package/dist/startup-resolution.js +15 -17
- package/dist/tools/check-impact.js +1 -1
- package/dist/tools/check.js +1 -1
- package/dist/tools/core-module.js +19 -8
- package/dist/tools/coverage.js +1 -1
- package/dist/tools/delete.js +1 -1
- package/dist/tools/discovery-adapter.js +5 -0
- package/dist/tools/entity-query.js +1 -1
- package/dist/tools/find-gaps.js +9 -1
- package/dist/tools/graph.js +9 -1
- package/dist/tools/model-requirement.js +2 -2
- package/dist/tools/mutation-context.js +15 -9
- package/dist/tools/plan-bootstrap.js +21 -0
- package/dist/tools/prolog-list.js +1 -1
- package/dist/tools/query.js +1 -1
- package/dist/tools/relationship-validation.js +1 -1
- package/dist/tools/search.js +1 -1
- package/dist/tools/semantic-advisor.js +1 -1
- package/dist/tools/skills.js +2 -2
- package/dist/tools/sparql.js +1 -1
- package/dist/tools/status.js +1 -1
- package/dist/tools/suggest-predicates.js +1 -1
- package/dist/tools/symbols.js +310 -68
- package/dist/tools/upsert.js +3 -3
- package/dist/tools/validate-upsert.js +1 -1
- package/dist/tools-config.js +77 -3
- package/dist/workspace.js +10 -8
- package/package.json +15 -9
- package/dist/tools/autopilot-candidates.js +0 -554
- package/dist/tools/autopilot-discovery.js +0 -898
- package/dist/tools/autopilot-generate.js +0 -47
- package/dist/tools/autopilot-test-compat.js +0 -88
- package/dist/tools/autopilot-test-parsers.js +0 -120
- package/dist/tools/check-config.js +0 -67
package/dist/server/tools.js
CHANGED
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
import process from "node:process";
|
|
19
|
-
import { executeOperation
|
|
19
|
+
import { executeOperation } from "kibi-runtime";
|
|
20
|
+
import { operationData, toKibiResult } from "kibi-runtime";
|
|
20
21
|
import { isMcpDebugEnabled } from "../env.js";
|
|
21
22
|
import { appendDiagnosticErrorUsage, appendDiagnosticSuccessUsage, } from "./diagnostic-usage.js";
|
|
23
|
+
import { getJob, jobSnapshot } from "./jobs.js";
|
|
22
24
|
import { jsonSchemaToZod } from "./json-schema-to-zod.js";
|
|
23
25
|
import { registerConfiguredTools } from "./tool-registration.js";
|
|
24
26
|
import { DEFAULT_TOOLS_RUNTIME, _resetSessionModulePromise, _setToolsServerDepsForTests, } from "./tools-runtime.js";
|
|
@@ -26,6 +28,10 @@ export { jsonSchemaToZod } from "./json-schema-to-zod.js";
|
|
|
26
28
|
export { _resetSessionModulePromise, _setToolsServerDepsForTests };
|
|
27
29
|
const DEFAULT_TOOL_TIMEOUT_MS = 90_000;
|
|
28
30
|
const TOOL_TIMEOUT_ENV = "KIBI_MCP_TOOL_TIMEOUT_MS";
|
|
31
|
+
// Give cancellation and the Prolog reset a short bounded grace period, but do
|
|
32
|
+
// not hold the MCP request open for the full five-second shutdown budget when
|
|
33
|
+
// a handler never observes AbortSignal.
|
|
34
|
+
const TOOL_TIMEOUT_GRACE_MS = 100;
|
|
29
35
|
// implements REQ-008
|
|
30
36
|
function debugLog(...args) {
|
|
31
37
|
if (isMcpDebugEnabled()) {
|
|
@@ -45,7 +51,13 @@ function getToolTimeoutMs() {
|
|
|
45
51
|
}
|
|
46
52
|
// implements REQ-002
|
|
47
53
|
function createToolTimeoutError(toolName, timeoutMs) {
|
|
48
|
-
|
|
54
|
+
const error = new Error(`Tool ${toolName} timed out after ${timeoutMs}ms`);
|
|
55
|
+
Object.assign(error, { code: "KIBI_TOOL_TIMEOUT", toolName, timeoutMs });
|
|
56
|
+
return error;
|
|
57
|
+
}
|
|
58
|
+
function isToolTimeoutError(value) {
|
|
59
|
+
return (value instanceof Error &&
|
|
60
|
+
value.code === "KIBI_TOOL_TIMEOUT");
|
|
49
61
|
}
|
|
50
62
|
// implements REQ-002
|
|
51
63
|
async function withToolTimeout(toolName, operation, onTimeout) {
|
|
@@ -57,8 +69,19 @@ async function withToolTimeout(toolName, operation, onTimeout) {
|
|
|
57
69
|
new Promise((_, reject) => {
|
|
58
70
|
timeout = setTimeout(() => {
|
|
59
71
|
const error = createToolTimeoutError(toolName, timeoutMs);
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
// Do not report the timeout until cancellation/reset has completed
|
|
73
|
+
// and the original request has reached a terminal state. This is
|
|
74
|
+
// especially important for source-first mutations: a caller must
|
|
75
|
+
// never retry while the authoritative journal is still deciding its
|
|
76
|
+
// outcome.
|
|
77
|
+
void onTimeout(error, timeoutMs)
|
|
78
|
+
.then(async () => {
|
|
79
|
+
await Promise.race([
|
|
80
|
+
operation.then(() => undefined, () => undefined),
|
|
81
|
+
new Promise((resolve) => setTimeout(resolve, TOOL_TIMEOUT_GRACE_MS)),
|
|
82
|
+
]);
|
|
83
|
+
})
|
|
84
|
+
.finally(() => reject(error));
|
|
62
85
|
}, timeoutMs);
|
|
63
86
|
}),
|
|
64
87
|
]);
|
|
@@ -74,7 +97,7 @@ export function addTool(server, name, description, inputSchema, handler,
|
|
|
74
97
|
// INTENTIONAL: DEFAULT_TOOLS_RUNTIME is typed as ToolsRuntime<PrologProcess>; the
|
|
75
98
|
// generic TProlog parameter exists so tests can inject a mock type. The cast is safe
|
|
76
99
|
// because the runtime object satisfies the full ToolsRuntime contract at runtime.
|
|
77
|
-
runtime = DEFAULT_TOOLS_RUNTIME, spec, annotations) {
|
|
100
|
+
runtime = DEFAULT_TOOLS_RUNTIME, spec, annotations, outputSchema) {
|
|
78
101
|
const wrappedHandler = async (args) => {
|
|
79
102
|
const startedAt = new Date();
|
|
80
103
|
const diagnosticModeEnabled = runtime.diagnosticModeEnabled();
|
|
@@ -127,6 +150,8 @@ runtime = DEFAULT_TOOLS_RUNTIME, spec, annotations) {
|
|
|
127
150
|
error instanceof Error ? error.message : String(error);
|
|
128
151
|
}
|
|
129
152
|
});
|
|
153
|
+
const data = operationData(result);
|
|
154
|
+
const envelope = toKibiResult(operationSpec, data);
|
|
130
155
|
// Log usage in diagnostic mode
|
|
131
156
|
if (diagnosticModeEnabled) {
|
|
132
157
|
await appendDiagnosticSuccessUsage({
|
|
@@ -137,10 +162,22 @@ runtime = DEFAULT_TOOLS_RUNTIME, spec, annotations) {
|
|
|
137
162
|
businessArgs,
|
|
138
163
|
telemetry,
|
|
139
164
|
startedAt,
|
|
140
|
-
result,
|
|
165
|
+
result: envelope,
|
|
141
166
|
});
|
|
142
167
|
}
|
|
143
|
-
|
|
168
|
+
if (result !== null &&
|
|
169
|
+
typeof result === "object" &&
|
|
170
|
+
!Array.isArray(result) &&
|
|
171
|
+
"content" in result) {
|
|
172
|
+
return {
|
|
173
|
+
...result,
|
|
174
|
+
structuredContent: envelope,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
content: [{ type: "text", text: JSON.stringify(envelope) }],
|
|
179
|
+
structuredContent: envelope,
|
|
180
|
+
};
|
|
144
181
|
}
|
|
145
182
|
catch (error) {
|
|
146
183
|
// Log error in diagnostic mode
|
|
@@ -157,6 +194,48 @@ runtime = DEFAULT_TOOLS_RUNTIME, spec, annotations) {
|
|
|
157
194
|
resetState: { resetAttempted, resetSucceeded, resetError },
|
|
158
195
|
});
|
|
159
196
|
}
|
|
197
|
+
if (isToolTimeoutError(error) &&
|
|
198
|
+
operationSpec.effects.some((effect) => effect === "kb-write" || effect === "workspace-write")) {
|
|
199
|
+
const recoveryActions = [
|
|
200
|
+
{
|
|
201
|
+
operation: "kb_status",
|
|
202
|
+
reason: "Determine whether the mutation crossed the authoritative source/journal commit boundary before taking any further action.",
|
|
203
|
+
required: true,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
operation: "kb_apply_plan",
|
|
207
|
+
reason: "If status exposes a recovery journal, replay that typed journal action; never retry the timed-out mutation request.",
|
|
208
|
+
required: true,
|
|
209
|
+
},
|
|
210
|
+
];
|
|
211
|
+
const timeoutData = {
|
|
212
|
+
effectFailures: [
|
|
213
|
+
{
|
|
214
|
+
kind: "mutation",
|
|
215
|
+
errorCode: "MUTATION_OUTCOME_UNKNOWN",
|
|
216
|
+
detail: {
|
|
217
|
+
requestId,
|
|
218
|
+
timeoutMs: error.timeoutMs,
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
nextActions: recoveryActions,
|
|
223
|
+
};
|
|
224
|
+
const envelope = toKibiResult(operationSpec, timeoutData, {
|
|
225
|
+
status: "error",
|
|
226
|
+
nextActions: recoveryActions,
|
|
227
|
+
error: {
|
|
228
|
+
code: "MUTATION_OUTCOME_UNKNOWN",
|
|
229
|
+
message: "The mutation timed out after cancellation; its commit state is indeterminate. Inspect status and replay the typed recovery action if required.",
|
|
230
|
+
retryable: false,
|
|
231
|
+
details: { requestId, tool: name },
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
return {
|
|
235
|
+
content: [{ type: "text", text: JSON.stringify(envelope) }],
|
|
236
|
+
structuredContent: envelope,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
160
239
|
throw error;
|
|
161
240
|
}
|
|
162
241
|
finally {
|
|
@@ -176,6 +255,7 @@ runtime = DEFAULT_TOOLS_RUNTIME, spec, annotations) {
|
|
|
176
255
|
server.registerTool(name, {
|
|
177
256
|
description,
|
|
178
257
|
inputSchema: jsonSchemaToZod(inputSchema),
|
|
258
|
+
...(outputSchema ? { outputSchema: jsonSchemaToZod(outputSchema) } : {}),
|
|
179
259
|
...(annotations ? { annotations } : {}),
|
|
180
260
|
}, wrappedHandler);
|
|
181
261
|
}
|
|
@@ -184,4 +264,60 @@ export function registerAllTools(server,
|
|
|
184
264
|
// INTENTIONAL: same generic bridge cast as addTool — see comment there.
|
|
185
265
|
runtime = DEFAULT_TOOLS_RUNTIME) {
|
|
186
266
|
registerConfiguredTools(server, runtime, addTool);
|
|
267
|
+
registerJobStatusTool(server);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* kb_job_status polls background jobs started by long-running operations
|
|
271
|
+
* (currently `kb_check` with `async: true`). This is an MCP-server-native
|
|
272
|
+
* companion to the job receipts, not part of the canonical CLI operation
|
|
273
|
+
* catalog: jobs live in the server process and have no CLI counterpart.
|
|
274
|
+
*/
|
|
275
|
+
function registerJobStatusTool(server) {
|
|
276
|
+
addTool(server, "kb_job_status", "Poll a background job started with async:true (e.g. kb_check async jobs). Returns the kibi.job.v1 state: running, succeeded (with the full result), or failed (with the error).", {
|
|
277
|
+
type: "object",
|
|
278
|
+
properties: {
|
|
279
|
+
jobId: {
|
|
280
|
+
type: "string",
|
|
281
|
+
description: "The jobId from the kibi.job.v1 receipt.",
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
required: ["jobId"],
|
|
285
|
+
}, async (args) => {
|
|
286
|
+
const jobId = typeof args.jobId === "string" ? args.jobId : "";
|
|
287
|
+
const job = jobId === "" ? undefined : getJob(jobId);
|
|
288
|
+
if (job === undefined) {
|
|
289
|
+
return {
|
|
290
|
+
content: [
|
|
291
|
+
{
|
|
292
|
+
type: "text",
|
|
293
|
+
text: JSON.stringify({
|
|
294
|
+
kibiProtocol: 1,
|
|
295
|
+
jobVersion: "kibi.job.v1",
|
|
296
|
+
jobId,
|
|
297
|
+
status: "unknown",
|
|
298
|
+
error: "No such job. Jobs are process-local and dropped on server restart; check the jobId or re-run the operation with async:true.",
|
|
299
|
+
}),
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
structuredContent: {
|
|
303
|
+
kibiProtocol: 1,
|
|
304
|
+
jobVersion: "kibi.job.v1",
|
|
305
|
+
jobId,
|
|
306
|
+
status: "unknown",
|
|
307
|
+
error: "No such job. Jobs are process-local and dropped on server restart; check the jobId or re-run the operation with async:true.",
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const snapshot = jobSnapshot(job);
|
|
312
|
+
return {
|
|
313
|
+
content: [{ type: "text", text: JSON.stringify(snapshot) }],
|
|
314
|
+
structuredContent: snapshot,
|
|
315
|
+
};
|
|
316
|
+
}, undefined, undefined, undefined, {
|
|
317
|
+
title: "Poll a Kibi background job",
|
|
318
|
+
readOnlyHint: true,
|
|
319
|
+
destructiveHint: false,
|
|
320
|
+
idempotentHint: true,
|
|
321
|
+
openWorldHint: false,
|
|
322
|
+
});
|
|
187
323
|
}
|
package/dist/server.js
CHANGED
|
@@ -21,18 +21,33 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
21
21
|
import { initializeDiagnosticMode } from "./diagnostics.js";
|
|
22
22
|
import { loadDefaultEnvFile } from "./env.js";
|
|
23
23
|
import { setupDocsAndPrompts } from "./server/docs.js";
|
|
24
|
+
import { KIBI_ICONS } from "./server/icons.js";
|
|
24
25
|
import { registerAllTools } from "./server/tools.js";
|
|
25
26
|
import { connectTransport, setupTransportHandlers, } from "./server/transport.js";
|
|
26
27
|
// Read version from package.json to prevent drift
|
|
27
28
|
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
28
29
|
const VERSION = packageJson.version ?? "0.1.0";
|
|
30
|
+
const SERVER_INSTRUCTIONS = [
|
|
31
|
+
"Kibi is a branch-local requirements knowledge base for software traceability.",
|
|
32
|
+
"Start with kb_search for discovery, then kb_query for exact lookups before any mutation.",
|
|
33
|
+
"Model requirements as linked facts via kb_model_requirement or kb_upsert (create endpoints before linking them).",
|
|
34
|
+
"Mutate sequentially with kb_upsert and kb_delete; validate with kb_check during iteration and run an unfiltered kb_check before completion.",
|
|
35
|
+
"Confirm branch freshness with kb_status. For first-time repository setup, use the kibi-bootstrap prompt.",
|
|
36
|
+
].join(" ");
|
|
29
37
|
export async function startServer() {
|
|
30
38
|
// Load environment configuration
|
|
31
39
|
loadDefaultEnvFile();
|
|
32
40
|
// Initialize diagnostic mode if --diagnostic-mode flag is present
|
|
33
41
|
initializeDiagnosticMode();
|
|
34
42
|
// Create MCP server
|
|
35
|
-
const server = new McpServer({
|
|
43
|
+
const server = new McpServer({
|
|
44
|
+
name: "kibi-mcp",
|
|
45
|
+
title: "Kibi MCP",
|
|
46
|
+
description: "Agent-native requirements compiler: branch-local knowledge base for requirements, scenarios, tests, facts, and code-symbol traceability.",
|
|
47
|
+
websiteUrl: "https://github.com/Looted/kibi",
|
|
48
|
+
version: VERSION,
|
|
49
|
+
icons: KIBI_ICONS,
|
|
50
|
+
}, { instructions: SERVER_INSTRUCTIONS });
|
|
36
51
|
// Setup documentation resources and prompts
|
|
37
52
|
setupDocsAndPrompts(server);
|
|
38
53
|
// Register all KB tools
|
|
@@ -15,7 +15,7 @@
|
|
|
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
|
-
import
|
|
18
|
+
import * as fs from "node:fs";
|
|
19
19
|
import { createRequire } from "node:module";
|
|
20
20
|
import path from "node:path";
|
|
21
21
|
import { fileURLToPath } from "node:url";
|
|
@@ -28,35 +28,33 @@ function toEntrypointPath(entrypointUrl) {
|
|
|
28
28
|
return path.resolve(entrypointUrl);
|
|
29
29
|
}
|
|
30
30
|
function readJson(filePath) {
|
|
31
|
-
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
31
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
32
|
+
}
|
|
33
|
+
export function nextAncestorDirectory(current) {
|
|
34
|
+
const parent = path.dirname(current);
|
|
35
|
+
return parent === current ? undefined : parent;
|
|
32
36
|
}
|
|
33
37
|
function nearestPackageJson(startPath) {
|
|
34
38
|
let current = path.dirname(startPath);
|
|
35
|
-
while (
|
|
39
|
+
while (current !== undefined) {
|
|
36
40
|
const candidate = path.join(current, "package.json");
|
|
37
|
-
if (existsSync(candidate)) {
|
|
41
|
+
if (fs.existsSync(candidate)) {
|
|
38
42
|
return candidate;
|
|
39
43
|
}
|
|
40
|
-
|
|
41
|
-
if (parent === current) {
|
|
42
|
-
throw new Error(`Unable to find package.json for ${startPath}`);
|
|
43
|
-
}
|
|
44
|
-
current = parent;
|
|
44
|
+
current = nextAncestorDirectory(current);
|
|
45
45
|
}
|
|
46
|
+
throw new Error(`Unable to find package.json for ${startPath}`);
|
|
46
47
|
}
|
|
47
48
|
function nearestPackageJsonFromDirectory(startPath) {
|
|
48
49
|
let current = path.resolve(startPath);
|
|
49
|
-
while (
|
|
50
|
+
while (current !== undefined) {
|
|
50
51
|
const candidate = path.join(current, "package.json");
|
|
51
|
-
if (existsSync(candidate)) {
|
|
52
|
+
if (fs.existsSync(candidate)) {
|
|
52
53
|
return candidate;
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
-
if (parent === current) {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
current = parent;
|
|
55
|
+
current = nextAncestorDirectory(current);
|
|
59
56
|
}
|
|
57
|
+
return null;
|
|
60
58
|
}
|
|
61
59
|
function packageInfoFromEntrypoint(entrypoint) {
|
|
62
60
|
const normalizedEntrypoint = path.resolve(entrypoint);
|
|
@@ -82,7 +80,7 @@ export function resolveProjectLocalMcp(cwd) {
|
|
|
82
80
|
}
|
|
83
81
|
const projectRequire = createRequire(projectPackageJson);
|
|
84
82
|
const resolved = projectRequire.resolve(PACKAGE_NAME);
|
|
85
|
-
const entrypoint = realpathSync.native?.(resolved) ?? realpathSync(resolved);
|
|
83
|
+
const entrypoint = fs.realpathSync.native?.(resolved) ?? fs.realpathSync(resolved);
|
|
86
84
|
return packageInfoFromEntrypoint(entrypoint);
|
|
87
85
|
}
|
|
88
86
|
catch (error) {
|
|
@@ -15,7 +15,7 @@
|
|
|
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
|
-
import { analyzeChangedFileImpact, } from "kibi-
|
|
18
|
+
import { analyzeChangedFileImpact, } from "kibi-runtime";
|
|
19
19
|
export function hasImpactOptions(args) {
|
|
20
20
|
return Boolean(args.includeImpactDiagnostics ||
|
|
21
21
|
args.staged ||
|
package/dist/tools/check.js
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { PrologProcess, resolveKbPlPath } from "kibi-
|
|
3
|
-
import { escapeAtomContent } from "kibi-
|
|
2
|
+
import { PrologProcess, resolveKbPlPath } from "kibi-runtime";
|
|
3
|
+
import { escapeAtomContent } from "kibi-runtime";
|
|
4
4
|
import { getCoreModulePathOverride, getKbPlPathOverride } from "../env.js";
|
|
5
|
+
export function parseMaybeDoubleEncodedJson(rawJson) {
|
|
6
|
+
let parsed = JSON.parse(rawJson);
|
|
7
|
+
if (typeof parsed === "string") {
|
|
8
|
+
parsed = JSON.parse(parsed);
|
|
9
|
+
}
|
|
10
|
+
return parsed;
|
|
11
|
+
}
|
|
12
|
+
function isPrologProcess(value) {
|
|
13
|
+
return (value instanceof PrologProcess ||
|
|
14
|
+
(value !== null &&
|
|
15
|
+
typeof value === "object" &&
|
|
16
|
+
typeof value.query === "function" &&
|
|
17
|
+
typeof value.invalidateCache ===
|
|
18
|
+
"function"));
|
|
19
|
+
}
|
|
5
20
|
// implements REQ-002, REQ-013
|
|
6
21
|
export function resolveCorePlPath(fileName) {
|
|
7
22
|
const override = getCoreModulePathOverride(fileName);
|
|
@@ -20,7 +35,7 @@ export function resolveCorePlPath(fileName) {
|
|
|
20
35
|
// implements REQ-002, REQ-013
|
|
21
36
|
export async function runJsonModuleQuery(prolog, fileName, goal, errorLabel) {
|
|
22
37
|
const modulePath = escapeAtomContent(resolveCorePlPath(fileName).replace(/\\/g, "/"));
|
|
23
|
-
if (!(prolog
|
|
38
|
+
if (!isPrologProcess(prolog)) {
|
|
24
39
|
const mockedResult = await prolog.query(`(use_module('${modulePath}'), ${goal})`);
|
|
25
40
|
if (!mockedResult.success) {
|
|
26
41
|
throw new Error(`${errorLabel} query failed: ${mockedResult.error || "Unknown error"}`);
|
|
@@ -52,11 +67,7 @@ export async function runJsonModuleQuery(prolog, fileName, goal, errorLabel) {
|
|
|
52
67
|
if (!rawJson) {
|
|
53
68
|
throw new Error(`${errorLabel} query returned no JsonString binding`);
|
|
54
69
|
}
|
|
55
|
-
|
|
56
|
-
if (typeof parsed === "string") {
|
|
57
|
-
parsed = JSON.parse(parsed);
|
|
58
|
-
}
|
|
59
|
-
return parsed;
|
|
70
|
+
return parseMaybeDoubleEncodedJson(rawJson);
|
|
60
71
|
}
|
|
61
72
|
async function runInteractiveModuleQuery(prolog, modulePath, goal, errorLabel) {
|
|
62
73
|
const loadResult = await prolog.query(`use_module('${modulePath}')`);
|
package/dist/tools/coverage.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { executeCoverage, } from "kibi-
|
|
1
|
+
import { executeCoverage, } from "kibi-runtime";
|
|
2
2
|
import { createDiscoveryContext } from "./discovery-adapter.js";
|
|
3
3
|
// implements REQ-002, REQ-013
|
|
4
4
|
export async function handleKbCoverage(prolog, args, context) {
|
package/dist/tools/delete.js
CHANGED
|
@@ -2,11 +2,16 @@ import { resolveWorkspaceRoot } from "../workspace.js";
|
|
|
2
2
|
export function createDiscoveryContext(prolog, baseContext) {
|
|
3
3
|
// implements REQ-kibi-operation-interface-parity
|
|
4
4
|
let lastResult = null;
|
|
5
|
+
const mode = prolog
|
|
6
|
+
.useOneShotMode;
|
|
5
7
|
const port = {
|
|
6
8
|
query: async (goal) => {
|
|
7
9
|
lastResult = await prolog.query(goal);
|
|
8
10
|
return lastResult;
|
|
9
11
|
},
|
|
12
|
+
oneShotMode: mode === undefined
|
|
13
|
+
? typeof globalThis.Bun !== "undefined"
|
|
14
|
+
: Boolean(mode),
|
|
10
15
|
nextSolution: async () => {
|
|
11
16
|
const result = lastResult;
|
|
12
17
|
lastResult = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { VALID_ENTITY_TYPES, buildEntityGoal, dedupeEntities, loadEntities, paginateResults, validateEntityType, } from "kibi-
|
|
1
|
+
export { VALID_ENTITY_TYPES, buildEntityGoal, dedupeEntities, loadEntities, paginateResults, validateEntityType, } from "kibi-runtime";
|
package/dist/tools/find-gaps.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import { executeFindGaps } from "kibi-
|
|
1
|
+
import { executeFindGaps } from "kibi-runtime";
|
|
2
|
+
function oneShotMode(prolog) {
|
|
3
|
+
const mode = prolog
|
|
4
|
+
.useOneShotMode;
|
|
5
|
+
return mode === undefined
|
|
6
|
+
? typeof globalThis.Bun !== "undefined"
|
|
7
|
+
: Boolean(mode);
|
|
8
|
+
}
|
|
2
9
|
// implements REQ-002, REQ-013
|
|
3
10
|
export async function handleKbFindGaps(prolog, args) {
|
|
4
11
|
return executeFindGaps({ ...args }, {
|
|
@@ -7,6 +14,7 @@ export async function handleKbFindGaps(prolog, args) {
|
|
|
7
14
|
clock: () => new Date(),
|
|
8
15
|
prolog: {
|
|
9
16
|
query: (goal) => prolog.query(goal),
|
|
17
|
+
oneShotMode: oneShotMode(prolog),
|
|
10
18
|
nextSolution: async () => null,
|
|
11
19
|
save: () => prolog.query("kb_save"),
|
|
12
20
|
},
|
package/dist/tools/graph.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import { executeGraph } from "kibi-
|
|
1
|
+
import { executeGraph } from "kibi-runtime";
|
|
2
|
+
function oneShotMode(prolog) {
|
|
3
|
+
const mode = prolog
|
|
4
|
+
.useOneShotMode;
|
|
5
|
+
return mode === undefined
|
|
6
|
+
? typeof globalThis.Bun !== "undefined"
|
|
7
|
+
: Boolean(mode);
|
|
8
|
+
}
|
|
2
9
|
// implements REQ-002, REQ-013
|
|
3
10
|
export async function handleKbGraph(prolog, args) {
|
|
4
11
|
return executeGraph({ ...args }, {
|
|
@@ -7,6 +14,7 @@ export async function handleKbGraph(prolog, args) {
|
|
|
7
14
|
clock: () => new Date(),
|
|
8
15
|
prolog: {
|
|
9
16
|
query: (goal) => prolog.query(goal),
|
|
17
|
+
oneShotMode: oneShotMode(prolog),
|
|
10
18
|
nextSolution: async () => null,
|
|
11
19
|
save: () => prolog.query("kb_save"),
|
|
12
20
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { modelRequirementSpec
|
|
2
|
-
import { estimateNormativeSignalConfidence, extractRequirementClaim, getWorkspaceMigrationWarning, strictWriteSetToApplyPlan, writeSetPrimaryEntityId, } from "kibi-
|
|
1
|
+
import { modelRequirementSpec } from "kibi-runtime";
|
|
2
|
+
import { estimateNormativeSignalConfidence, extractRequirementClaim, getWorkspaceMigrationWarning, strictWriteSetToApplyPlan, writeSetPrimaryEntityId, } from "kibi-runtime";
|
|
3
3
|
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
4
4
|
export { estimateNormativeSignalConfidence, extractRequirementClaim, getWorkspaceMigrationWarning, strictWriteSetToApplyPlan, writeSetPrimaryEntityId, };
|
|
5
5
|
export async function handleKbModelRequirement(_prolog, args) {
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
3
|
-
const filesystem = {
|
|
4
|
-
readFile: (filePath) => fs.readFile(filePath, "utf8"),
|
|
5
|
-
writeFile: (filePath, data) => fs.writeFile(filePath, data, "utf8"),
|
|
6
|
-
mkdir: async (directoryPath) => {
|
|
7
|
-
await fs.mkdir(directoryPath, { recursive: true });
|
|
8
|
-
},
|
|
9
|
-
stat: (filePath) => fs.stat(filePath),
|
|
10
|
-
};
|
|
11
3
|
// implements REQ-kibi-operation-interface-parity
|
|
12
4
|
export function createMutationContext(prolog) {
|
|
13
5
|
const port = prolog === undefined
|
|
@@ -22,7 +14,21 @@ export function createMutationContext(prolog) {
|
|
|
22
14
|
workspaceRoot: resolveWorkspaceRoot(),
|
|
23
15
|
signal: new AbortController().signal,
|
|
24
16
|
clock: () => new Date(),
|
|
25
|
-
|
|
17
|
+
// The thin direct handler remains a compiled-KB compatibility surface.
|
|
18
|
+
// Production MCP registration supplies sourceFirst through the shared
|
|
19
|
+
// operation runtime while this adapter still exposes filesystem reads for
|
|
20
|
+
// symbol-granularity validation.
|
|
21
|
+
sourceFirst: false,
|
|
22
|
+
...(process.env.KIBI_WORKSPACE !== undefined ? { fs: filesystem } : {}),
|
|
26
23
|
...(port === undefined ? {} : { prolog: port }),
|
|
27
24
|
};
|
|
28
25
|
}
|
|
26
|
+
const filesystem = {
|
|
27
|
+
readFile: (filePath) => fs.readFile(filePath, "utf8"),
|
|
28
|
+
writeFile: (filePath, data) => fs.writeFile(filePath, data, "utf8"),
|
|
29
|
+
mkdir: async (directoryPath) => {
|
|
30
|
+
await fs.mkdir(directoryPath, { recursive: true });
|
|
31
|
+
},
|
|
32
|
+
stat: (filePath) => fs.stat(filePath),
|
|
33
|
+
unlink: (filePath) => fs.unlink(filePath),
|
|
34
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { executePlanBootstrap, } from "kibi-runtime";
|
|
2
|
+
import { nodeFilesystem, nodeGit } from "kibi-runtime";
|
|
3
|
+
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
4
|
+
function isOperationContext(value) {
|
|
5
|
+
return (value !== null &&
|
|
6
|
+
typeof value === "object" &&
|
|
7
|
+
"workspaceRoot" in value &&
|
|
8
|
+
"signal" in value);
|
|
9
|
+
}
|
|
10
|
+
// implements REQ-mcp-kibi-bootstrap-bootstrap-v1, REQ-kibi-operation-interface-parity
|
|
11
|
+
// implements REQ-KIBI-BOOTSTRAP-PLAN
|
|
12
|
+
export async function handleKbPlanBootstrap(input, context) {
|
|
13
|
+
if (!isOperationContext(context))
|
|
14
|
+
throw new TypeError("Invalid bootstrap adapter invocation");
|
|
15
|
+
return executePlanBootstrap(input, {
|
|
16
|
+
...context,
|
|
17
|
+
workspaceRoot: context.workspaceRoot || resolveWorkspaceRoot(),
|
|
18
|
+
fs: context.fs ?? nodeFilesystem,
|
|
19
|
+
git: context.git ?? nodeGit,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
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
|
-
import { splitTopLevel } from "kibi-
|
|
18
|
+
import { splitTopLevel } from "kibi-runtime";
|
|
19
19
|
// implements REQ-002
|
|
20
20
|
export function parseAtomList(raw) {
|
|
21
21
|
const trimmed = raw.trim();
|
package/dist/tools/query.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VALID_ENTITY_TYPES, querySpec } from "kibi-
|
|
1
|
+
import { VALID_ENTITY_TYPES, querySpec } from "kibi-runtime";
|
|
2
2
|
import { createDiscoveryContext } from "./discovery-adapter.js";
|
|
3
3
|
export { VALID_ENTITY_TYPES };
|
|
4
4
|
export async function handleKbQuery(prolog, args) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatInvalidRelationshipError, formatInvalidRelationshipTuple, formatRelationshipSourceMismatch, validateLiveRelationshipTargets as validateSharedTargets, } from "kibi-
|
|
1
|
+
import { formatInvalidRelationshipError, formatInvalidRelationshipTuple, formatRelationshipSourceMismatch, validateLiveRelationshipTargets as validateSharedTargets, } from "kibi-runtime";
|
|
2
2
|
export { formatInvalidRelationshipError, formatInvalidRelationshipTuple, formatRelationshipSourceMismatch, };
|
|
3
3
|
export async function validateLiveRelationshipTargets(prolog, entity, relationships) {
|
|
4
4
|
const port = {
|
package/dist/tools/search.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { searchSpec } from "kibi-
|
|
1
|
+
import { searchSpec } from "kibi-runtime";
|
|
2
2
|
import { createDiscoveryContext } from "./discovery-adapter.js";
|
|
3
3
|
export async function handleKbSearch(prolog, args) {
|
|
4
4
|
// implements REQ-kibi-operation-interface-parity, REQ-mcp-search-discovery
|
package/dist/tools/skills.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { skillsListSpec, skillsLoadSpec, skillsReadSpec, } from "kibi-
|
|
2
|
-
import { loadBundledSkill } from "kibi-
|
|
1
|
+
import { skillsListSpec, skillsLoadSpec, skillsReadSpec, } from "kibi-runtime";
|
|
2
|
+
import { loadBundledSkill } from "kibi-runtime";
|
|
3
3
|
function runtimeContext() {
|
|
4
4
|
return {
|
|
5
5
|
workspaceRoot: process.cwd(),
|
package/dist/tools/sparql.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sparqlRemoteSpec } from "kibi-
|
|
1
|
+
import { sparqlRemoteSpec } from "kibi-runtime";
|
|
2
2
|
// implements REQ-002, REQ-013, REQ-kibi-operation-interface-parity
|
|
3
3
|
export async function handleSparql(prologOrArgs, legacyArgs) {
|
|
4
4
|
const args = legacyArgs ?? ("endpoint" in prologOrArgs ? prologOrArgs : undefined);
|
package/dist/tools/status.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { statusSpec } from "kibi-
|
|
1
|
+
import { statusSpec } from "kibi-runtime";
|
|
2
2
|
import { createDiscoveryContext } from "./discovery-adapter.js";
|
|
3
3
|
export async function handleKbStatus(prolog, args, context) {
|
|
4
4
|
// implements REQ-kibi-operation-interface-parity
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { suggestPredicatesSpec
|
|
1
|
+
import { suggestPredicatesSpec } from "kibi-runtime";
|
|
2
2
|
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
3
3
|
import { createDiscoveryContext } from "./discovery-adapter.js";
|
|
4
4
|
export async function handleKbSuggestPredicates(prolog, args) {
|