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/session.js
CHANGED
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
import fs from "node:fs";
|
|
19
19
|
import { createRequire } from "node:module";
|
|
20
20
|
import process from "node:process";
|
|
21
|
-
import { EngineClient } from "kibi-
|
|
22
|
-
import { PrologProcess } from "kibi-
|
|
23
|
-
import { copyCleanSnapshot, getBranchDiagnostic, isValidBranchName, resolveActiveBranch, } from "kibi-
|
|
21
|
+
import { EngineClient } from "kibi-runtime";
|
|
22
|
+
import { PrologProcess } from "kibi-runtime";
|
|
23
|
+
import { copyCleanSnapshot, ensureBranchStoreManifest, getBranchDiagnostic, isValidBranchName, resolveActiveBranch, resolveBranchAttachment, } from "kibi-runtime";
|
|
24
24
|
import { getBranchOverride, isMcpDebugEnabled } from "../env.js";
|
|
25
25
|
import { resolveKbPath, resolveWorkspaceRoot } from "../workspace.js";
|
|
26
26
|
import { KbRefreshError, describeBranchKbStamp, readBranchKbStamp, sameBranchKbStamp, } from "./kb-freshness.js";
|
|
@@ -32,39 +32,58 @@ const defaultSessionDeps = {
|
|
|
32
32
|
getBranchDiagnostic,
|
|
33
33
|
isValidBranchName,
|
|
34
34
|
resolveActiveBranch,
|
|
35
|
+
resolveBranchAttachment,
|
|
35
36
|
resolveKbPath,
|
|
36
37
|
resolveWorkspaceRoot,
|
|
37
38
|
};
|
|
38
39
|
let sessionDeps = { ...defaultSessionDeps };
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
const state = {
|
|
41
|
+
prologProcess: null,
|
|
42
|
+
isInitialized: false,
|
|
43
|
+
activeBranchName: "develop",
|
|
44
|
+
ensurePrologTail: Promise.resolve(),
|
|
45
|
+
prologResetGeneration: 0,
|
|
46
|
+
attachedBranchKbPath: null,
|
|
47
|
+
attachedBranchStamp: null,
|
|
48
|
+
isShuttingDown: false,
|
|
49
|
+
shutdownTimeout: null,
|
|
50
|
+
};
|
|
51
|
+
// implements REQ-008
|
|
52
|
+
export function getPrologProcess() {
|
|
53
|
+
return state.prologProcess;
|
|
54
|
+
}
|
|
55
|
+
// implements REQ-mcp-kb-freshness
|
|
56
|
+
export function getActiveBranchName() {
|
|
57
|
+
return state.activeBranchName;
|
|
58
|
+
}
|
|
59
|
+
// implements REQ-008
|
|
60
|
+
export function getAttachedBranchKbPath() {
|
|
61
|
+
return state.attachedBranchKbPath;
|
|
62
|
+
}
|
|
63
|
+
// implements REQ-008
|
|
64
|
+
export function getIsShuttingDown() {
|
|
65
|
+
return state.isShuttingDown;
|
|
66
|
+
}
|
|
67
|
+
export const inFlightRequests = new Map();
|
|
46
68
|
// implements REQ-mcp-kb-freshness
|
|
47
69
|
// covered_by TEST-mcp-kb-freshness
|
|
48
70
|
export function updateAttachedBranchStamp(stamp) {
|
|
49
|
-
attachedBranchStamp = stamp;
|
|
71
|
+
state.attachedBranchStamp = stamp;
|
|
50
72
|
}
|
|
51
|
-
export let isShuttingDown = false;
|
|
52
|
-
let shutdownTimeout = null;
|
|
53
|
-
export const inFlightRequests = new Map();
|
|
54
73
|
// implements REQ-008
|
|
55
74
|
export function resetSessionStateForTests() {
|
|
56
|
-
prologProcess = null;
|
|
57
|
-
isInitialized = false;
|
|
58
|
-
activeBranchName = "develop";
|
|
59
|
-
ensurePrologTail = Promise.resolve();
|
|
60
|
-
prologResetGeneration = 0;
|
|
61
|
-
attachedBranchKbPath = null;
|
|
62
|
-
attachedBranchStamp = null;
|
|
63
|
-
isShuttingDown = false;
|
|
75
|
+
state.prologProcess = null;
|
|
76
|
+
state.isInitialized = false;
|
|
77
|
+
state.activeBranchName = "develop";
|
|
78
|
+
state.ensurePrologTail = Promise.resolve();
|
|
79
|
+
state.prologResetGeneration = 0;
|
|
80
|
+
state.attachedBranchKbPath = null;
|
|
81
|
+
state.attachedBranchStamp = null;
|
|
82
|
+
state.isShuttingDown = false;
|
|
64
83
|
inFlightRequests.clear();
|
|
65
|
-
if (shutdownTimeout) {
|
|
66
|
-
clearTimeout(shutdownTimeout);
|
|
67
|
-
shutdownTimeout = null;
|
|
84
|
+
if (state.shutdownTimeout) {
|
|
85
|
+
clearTimeout(state.shutdownTimeout);
|
|
86
|
+
state.shutdownTimeout = null;
|
|
68
87
|
}
|
|
69
88
|
}
|
|
70
89
|
export function _setSessionDepsForTests(
|
|
@@ -76,6 +95,10 @@ export function _resetSessionDepsForTests() {
|
|
|
76
95
|
// implements REQ-008
|
|
77
96
|
sessionDeps = { ...defaultSessionDeps };
|
|
78
97
|
}
|
|
98
|
+
// implements REQ-008
|
|
99
|
+
export function _setPrologProcessForTests(process) {
|
|
100
|
+
state.prologProcess = process;
|
|
101
|
+
}
|
|
79
102
|
function debugLog(...args) {
|
|
80
103
|
if (isMcpDebugEnabled()) {
|
|
81
104
|
console.error(...args);
|
|
@@ -90,30 +113,30 @@ export function ensureBranchKbExists(workspaceRoot, branch) {
|
|
|
90
113
|
if (sessionDeps.fs.existsSync(branchPath)) {
|
|
91
114
|
return false;
|
|
92
115
|
}
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
116
|
+
// Branch initialization is intentionally empty. The compiled store is
|
|
117
|
+
// materialized from the current checkout's authored sources by sync; it is
|
|
118
|
+
// never copied from another branch.
|
|
119
|
+
// Unit/integration hosts can provide a virtual filesystem through the
|
|
120
|
+
// existing session dependency seam. Only the real Node filesystem needs
|
|
121
|
+
// the identity manifest writer; virtual hosts already model the resolved
|
|
122
|
+
// branch path and should not be forced to create that path on the host.
|
|
123
|
+
if (sessionDeps.fs === fs) {
|
|
124
|
+
ensureBranchStoreManifest(workspaceRoot, branch);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
sessionDeps.fs.mkdirSync(branchPath, { recursive: true });
|
|
103
128
|
}
|
|
104
|
-
// No previous branch available - create empty KB
|
|
105
|
-
sessionDeps.fs.mkdirSync(branchPath, { recursive: true });
|
|
106
129
|
debugLog(`[KIBI-MCP] Created empty branch KB for '${branch}'`);
|
|
107
130
|
return true;
|
|
108
131
|
}
|
|
109
132
|
export async function initiateGracefulShutdown(exitCode = 0) {
|
|
110
|
-
if (isShuttingDown) {
|
|
133
|
+
if (state.isShuttingDown) {
|
|
111
134
|
return;
|
|
112
135
|
}
|
|
113
|
-
isShuttingDown = true;
|
|
136
|
+
state.isShuttingDown = true;
|
|
114
137
|
debugLog(`[KIBI-MCP] Initiating graceful shutdown (exit code: ${exitCode})`);
|
|
115
|
-
const currentProlog = prologProcess;
|
|
116
|
-
prologProcess = null;
|
|
138
|
+
const currentProlog = state.prologProcess;
|
|
139
|
+
state.prologProcess = null;
|
|
117
140
|
if (currentProlog?.isRunning()) {
|
|
118
141
|
debugLog("[KIBI-MCP] Cancelling active Prolog work...");
|
|
119
142
|
try {
|
|
@@ -128,7 +151,7 @@ export async function initiateGracefulShutdown(exitCode = 0) {
|
|
|
128
151
|
if (inFlightRequests.size > 0) {
|
|
129
152
|
debugLog(`[KIBI-MCP] Waiting for ${inFlightRequests.size} in-flight requests to complete...`);
|
|
130
153
|
const timeoutPromise = new Promise((_, reject) => {
|
|
131
|
-
shutdownTimeout = setTimeout(() => {
|
|
154
|
+
state.shutdownTimeout = setTimeout(() => {
|
|
132
155
|
reject(new Error("Shutdown timeout"));
|
|
133
156
|
}, 10000); // 10 second timeout
|
|
134
157
|
});
|
|
@@ -143,9 +166,9 @@ export async function initiateGracefulShutdown(exitCode = 0) {
|
|
|
143
166
|
console.error("[KIBI-MCP] Shutdown timeout reached, forcing exit");
|
|
144
167
|
}
|
|
145
168
|
finally {
|
|
146
|
-
if (shutdownTimeout) {
|
|
147
|
-
clearTimeout(shutdownTimeout);
|
|
148
|
-
shutdownTimeout = null;
|
|
169
|
+
if (state.shutdownTimeout) {
|
|
170
|
+
clearTimeout(state.shutdownTimeout);
|
|
171
|
+
state.shutdownTimeout = null;
|
|
149
172
|
}
|
|
150
173
|
}
|
|
151
174
|
}
|
|
@@ -155,12 +178,12 @@ export async function initiateGracefulShutdown(exitCode = 0) {
|
|
|
155
178
|
// implements REQ-008
|
|
156
179
|
export async function resetProlog(reason) {
|
|
157
180
|
debugLog(`[KIBI-MCP] Resetting Prolog worker: ${reason}`);
|
|
158
|
-
prologResetGeneration += 1;
|
|
159
|
-
const current = prologProcess;
|
|
160
|
-
prologProcess = null;
|
|
161
|
-
isInitialized = false;
|
|
162
|
-
attachedBranchKbPath = null;
|
|
163
|
-
attachedBranchStamp = null;
|
|
181
|
+
state.prologResetGeneration += 1;
|
|
182
|
+
const current = state.prologProcess;
|
|
183
|
+
state.prologProcess = null;
|
|
184
|
+
state.isInitialized = false;
|
|
185
|
+
state.attachedBranchKbPath = null;
|
|
186
|
+
state.attachedBranchStamp = null;
|
|
164
187
|
if (current) {
|
|
165
188
|
try {
|
|
166
189
|
await current.terminate();
|
|
@@ -201,14 +224,14 @@ function usesBranchKbPath(kbPath) {
|
|
|
201
224
|
}
|
|
202
225
|
// implements REQ-008
|
|
203
226
|
async function ensurePrologUnsafe() {
|
|
204
|
-
const generationAtStart = prologResetGeneration;
|
|
227
|
+
const generationAtStart = state.prologResetGeneration;
|
|
205
228
|
const workspaceRoot = sessionDeps.resolveWorkspaceRoot();
|
|
206
229
|
const useEngine = sessionDeps.PrologProcess === defaultSessionDeps.PrologProcess;
|
|
207
230
|
const assertGeneration = async () => {
|
|
208
|
-
if (generationAtStart !== prologResetGeneration) {
|
|
209
|
-
const current = prologProcess;
|
|
210
|
-
prologProcess = null;
|
|
211
|
-
isInitialized = false;
|
|
231
|
+
if (generationAtStart !== state.prologResetGeneration) {
|
|
232
|
+
const current = state.prologProcess;
|
|
233
|
+
state.prologProcess = null;
|
|
234
|
+
state.isInitialized = false;
|
|
212
235
|
if (current) {
|
|
213
236
|
await current.terminate().catch((error) => {
|
|
214
237
|
console.error("[KIBI-MCP] Error terminating stale Prolog after reset generation change:", error);
|
|
@@ -228,32 +251,33 @@ async function ensurePrologUnsafe() {
|
|
|
228
251
|
targetBranch = envBranch;
|
|
229
252
|
}
|
|
230
253
|
else {
|
|
231
|
-
// No override - resolve
|
|
232
|
-
|
|
254
|
+
// No override - resolve the exact Git branch, with read-compatible legacy
|
|
255
|
+
// literal-path storage detection for bridge-release repositories.
|
|
256
|
+
const branchResult = sessionDeps.resolveBranchAttachment(workspaceRoot);
|
|
233
257
|
if ("error" in branchResult) {
|
|
234
258
|
const diagnostic = sessionDeps.getBranchDiagnostic(undefined, branchResult.error);
|
|
235
259
|
console.error(`[KIBI-MCP] ${diagnostic}`);
|
|
236
260
|
throw new Error(`Failed to resolve active branch: ${branchResult.error}`);
|
|
237
261
|
}
|
|
238
|
-
targetBranch = branchResult.
|
|
262
|
+
targetBranch = branchResult.kbBranch;
|
|
239
263
|
}
|
|
240
264
|
// Check if we need to switch branches
|
|
241
|
-
if (isInitialized && useEngine && prologProcess?.isRunning()) {
|
|
265
|
+
if (state.isInitialized && useEngine && state.prologProcess?.isRunning()) {
|
|
242
266
|
const kbPath = sessionDeps.resolveKbPath(workspaceRoot, targetBranch);
|
|
243
|
-
if (targetBranch === activeBranchName) {
|
|
244
|
-
attachedBranchKbPath = kbPath;
|
|
245
|
-
attachedBranchStamp = await readBranchKbStamp(kbPath);
|
|
246
|
-
return prologProcess;
|
|
267
|
+
if (targetBranch === state.activeBranchName) {
|
|
268
|
+
state.attachedBranchKbPath = kbPath;
|
|
269
|
+
state.attachedBranchStamp = await readBranchKbStamp(kbPath);
|
|
270
|
+
return state.prologProcess;
|
|
247
271
|
}
|
|
248
|
-
await prologProcess.terminate();
|
|
249
|
-
prologProcess = null;
|
|
250
|
-
isInitialized = false;
|
|
251
|
-
attachedBranchKbPath = null;
|
|
252
|
-
attachedBranchStamp = null;
|
|
272
|
+
await state.prologProcess.terminate();
|
|
273
|
+
state.prologProcess = null;
|
|
274
|
+
state.isInitialized = false;
|
|
275
|
+
state.attachedBranchKbPath = null;
|
|
276
|
+
state.attachedBranchStamp = null;
|
|
253
277
|
}
|
|
254
|
-
if (isInitialized && prologProcess?.isRunning()) {
|
|
278
|
+
if (state.isInitialized && state.prologProcess?.isRunning()) {
|
|
255
279
|
const kbPath = sessionDeps.resolveKbPath(workspaceRoot, targetBranch);
|
|
256
|
-
if (targetBranch === activeBranchName) {
|
|
280
|
+
if (targetBranch === state.activeBranchName) {
|
|
257
281
|
const currentStamp = await readBranchKbStamp(kbPath);
|
|
258
282
|
if (usesBranchKbPath(kbPath) &&
|
|
259
283
|
(currentStamp.rdfMissing ||
|
|
@@ -261,29 +285,29 @@ async function ensurePrologUnsafe() {
|
|
|
261
285
|
currentStamp.errorMessage !== null)) {
|
|
262
286
|
throw new KbRefreshError(`KB refresh failed: branch KB snapshot is unstable: ${describeBranchKbStamp(currentStamp)}`);
|
|
263
287
|
}
|
|
264
|
-
const shouldRefresh = attachedBranchKbPath === kbPath &&
|
|
265
|
-
attachedBranchStamp !== null &&
|
|
288
|
+
const shouldRefresh = state.attachedBranchKbPath === kbPath &&
|
|
289
|
+
state.attachedBranchStamp !== null &&
|
|
266
290
|
usesBranchKbPath(kbPath) &&
|
|
267
|
-
!sameBranchKbStamp(currentStamp, attachedBranchStamp);
|
|
291
|
+
!sameBranchKbStamp(currentStamp, state.attachedBranchStamp);
|
|
268
292
|
if (shouldRefresh) {
|
|
269
|
-
attachedBranchStamp = await refreshAttachedBranchKbWithRetry(prologProcess, kbPath, currentStamp, assertGeneration);
|
|
293
|
+
state.attachedBranchStamp = await refreshAttachedBranchKbWithRetry(state.prologProcess, kbPath, currentStamp, assertGeneration);
|
|
270
294
|
}
|
|
271
295
|
else {
|
|
272
|
-
attachedBranchKbPath = kbPath;
|
|
273
|
-
attachedBranchStamp = currentStamp;
|
|
296
|
+
state.attachedBranchKbPath = kbPath;
|
|
297
|
+
state.attachedBranchStamp = currentStamp;
|
|
274
298
|
}
|
|
275
|
-
attachedBranchKbPath = kbPath;
|
|
276
|
-
return prologProcess;
|
|
299
|
+
state.attachedBranchKbPath = kbPath;
|
|
300
|
+
return state.prologProcess;
|
|
277
301
|
}
|
|
278
302
|
// Branch changed - need to detach and re-attach
|
|
279
|
-
debugLog(`[KIBI-MCP] Branch changed: ${activeBranchName} -> ${targetBranch}`);
|
|
303
|
+
debugLog(`[KIBI-MCP] Branch changed: ${state.activeBranchName} -> ${targetBranch}`);
|
|
280
304
|
// Persist and detach from old KB
|
|
281
|
-
const saveResult = await prologProcess.query("kb_save");
|
|
305
|
+
const saveResult = await state.prologProcess.query("kb_save");
|
|
282
306
|
await assertGeneration();
|
|
283
307
|
if (!saveResult.success) {
|
|
284
308
|
throw new Error(`Failed to save old KB before detach: ${saveResult.error || "Unknown error"}`);
|
|
285
309
|
}
|
|
286
|
-
const detachResult = await prologProcess.query("kb_detach");
|
|
310
|
+
const detachResult = await state.prologProcess.query("kb_detach");
|
|
287
311
|
await assertGeneration();
|
|
288
312
|
if (!detachResult.success) {
|
|
289
313
|
debugLog(`[KIBI-MCP] Warning: failed to detach from old KB: ${detachResult.error || "Unknown error"}`);
|
|
@@ -292,100 +316,72 @@ async function ensurePrologUnsafe() {
|
|
|
292
316
|
// Ensure new branch KB exists
|
|
293
317
|
const createdEmptyBranch = ensureBranchKbExists(workspaceRoot, targetBranch);
|
|
294
318
|
// Attach to new branch KB
|
|
295
|
-
const attachResult = await prologProcess.query(`kb_attach('${kbPath}')`);
|
|
319
|
+
const attachResult = await state.prologProcess.query(`kb_attach('${kbPath}')`);
|
|
296
320
|
await assertGeneration();
|
|
297
321
|
if (!attachResult.success) {
|
|
298
322
|
throw new Error(`Failed to attach to new branch KB: ${attachResult.error || "Unknown error"}`);
|
|
299
323
|
}
|
|
300
324
|
if (createdEmptyBranch) {
|
|
301
|
-
const initialSaveResult = await prologProcess.query("kb_save");
|
|
325
|
+
const initialSaveResult = await state.prologProcess.query("kb_save");
|
|
302
326
|
await assertGeneration();
|
|
303
327
|
if (!initialSaveResult.success) {
|
|
304
328
|
throw new Error(`Failed to initialize empty branch KB: ${initialSaveResult.error || "Unknown error"}`);
|
|
305
329
|
}
|
|
306
330
|
}
|
|
307
|
-
activeBranchName = targetBranch;
|
|
308
|
-
attachedBranchKbPath = kbPath;
|
|
309
|
-
attachedBranchStamp = await readBranchKbStamp(kbPath);
|
|
331
|
+
state.activeBranchName = targetBranch;
|
|
332
|
+
state.attachedBranchKbPath = kbPath;
|
|
333
|
+
state.attachedBranchStamp = await readBranchKbStamp(kbPath);
|
|
310
334
|
debugLog(`[KIBI-MCP] Re-attached to branch: ${targetBranch}`);
|
|
311
335
|
debugLog(`[KIBI-MCP] KB path: ${kbPath}`);
|
|
312
|
-
return prologProcess;
|
|
336
|
+
return state.prologProcess;
|
|
313
337
|
}
|
|
314
338
|
// First initialization
|
|
315
339
|
debugLog("[KIBI-MCP] Initializing Prolog process...");
|
|
316
|
-
prologProcess = useEngine
|
|
340
|
+
state.prologProcess = useEngine
|
|
317
341
|
? new EngineClient({
|
|
318
342
|
workspaceRoot,
|
|
319
343
|
branch: targetBranch,
|
|
320
344
|
timeout: 120000,
|
|
321
345
|
})
|
|
322
346
|
: new sessionDeps.PrologProcess({ timeout: 120000 });
|
|
323
|
-
await prologProcess.start();
|
|
347
|
+
await state.prologProcess.start();
|
|
324
348
|
await assertGeneration();
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
try {
|
|
331
|
-
const resolved = req.resolve("kibi-cli/prolog");
|
|
332
|
-
debugLog(`[KIBI-MCP] require.resolve('kibi-cli/prolog') -> ${resolved}`);
|
|
333
|
-
}
|
|
334
|
-
catch (resolveErr) {
|
|
335
|
-
debugLog("[KIBI-MCP] require.resolve('kibi-cli/prolog') failed:", resolveErr.message);
|
|
336
|
-
}
|
|
337
|
-
// Try to read package.json for kibi-cli to get version. This may fail if
|
|
338
|
-
// the package uses exports blocking package.json access — log explicit failure.
|
|
339
|
-
try {
|
|
340
|
-
// prefer direct package.json require; createRequire makes this ESM-friendly
|
|
341
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
342
|
-
const pkg = req("kibi-cli/package.json");
|
|
343
|
-
if (pkg && typeof pkg.version === "string") {
|
|
344
|
-
debugLog(`[KIBI-MCP] kibi-cli version: ${pkg.version}`);
|
|
345
|
-
}
|
|
346
|
-
else {
|
|
347
|
-
debugLog("[KIBI-MCP] kibi-cli package.json read but no version field");
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
catch (pkgErr) {
|
|
351
|
-
debugLog("[KIBI-MCP] Failed to read kibi-cli package.json (exports may restrict access):", pkgErr.message);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
catch (err) {
|
|
355
|
-
debugLog("[KIBI-MCP] Failed to create require() for debug lookup:", err.message);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
349
|
+
// Adapters report the package that owns runtime execution. Do not resolve
|
|
350
|
+
// CLI implementation paths from the MCP process; the runtime package is
|
|
351
|
+
// the sole first-party execution boundary.
|
|
352
|
+
if (isMcpDebugEnabled())
|
|
353
|
+
debugLog("[KIBI-MCP] Runtime boundary: kibi-runtime");
|
|
358
354
|
debugLog("[KIBI-MCP] Branch selection:");
|
|
359
355
|
debugLog(`[KIBI-MCP] KIBI_BRANCH env: ${envBranch || "not set"}`);
|
|
360
356
|
debugLog(`[KIBI-MCP] Resolved branch: ${targetBranch}`);
|
|
361
|
-
activeBranchName = targetBranch;
|
|
357
|
+
state.activeBranchName = targetBranch;
|
|
362
358
|
const createdEmptyBranch = ensureBranchKbExists(workspaceRoot, targetBranch);
|
|
363
359
|
const kbPath = sessionDeps.resolveKbPath(workspaceRoot, targetBranch);
|
|
364
360
|
if (!useEngine) {
|
|
365
|
-
const attachResult = await prologProcess.query(`kb_attach('${kbPath}')`);
|
|
361
|
+
const attachResult = await state.prologProcess.query(`kb_attach('${kbPath}')`);
|
|
366
362
|
await assertGeneration();
|
|
367
363
|
if (!attachResult.success) {
|
|
368
364
|
throw new Error(`Failed to attach KB: ${attachResult.error || "Unknown error"}`);
|
|
369
365
|
}
|
|
370
366
|
if (createdEmptyBranch) {
|
|
371
|
-
const initialSaveResult = await prologProcess.query("kb_save");
|
|
367
|
+
const initialSaveResult = await state.prologProcess.query("kb_save");
|
|
372
368
|
await assertGeneration();
|
|
373
369
|
if (!initialSaveResult.success) {
|
|
374
370
|
throw new Error(`Failed to initialize empty branch KB: ${initialSaveResult.error || "Unknown error"}`);
|
|
375
371
|
}
|
|
376
372
|
}
|
|
377
373
|
}
|
|
378
|
-
attachedBranchKbPath = kbPath;
|
|
379
|
-
attachedBranchStamp = await readBranchKbStamp(kbPath);
|
|
380
|
-
isInitialized = true;
|
|
381
|
-
debugLog(`[KIBI-MCP] Prolog process started (PID: ${prologProcess.getPid()})`);
|
|
374
|
+
state.attachedBranchKbPath = kbPath;
|
|
375
|
+
state.attachedBranchStamp = await readBranchKbStamp(kbPath);
|
|
376
|
+
state.isInitialized = true;
|
|
377
|
+
debugLog(`[KIBI-MCP] Prolog process started (PID: ${state.prologProcess.getPid()})`);
|
|
382
378
|
debugLog(`[KIBI-MCP] KB attached: ${kbPath}`);
|
|
383
|
-
return prologProcess;
|
|
379
|
+
return state.prologProcess;
|
|
384
380
|
}
|
|
385
381
|
export async function ensureProlog() {
|
|
386
|
-
const previous = ensurePrologTail;
|
|
382
|
+
const previous = state.ensurePrologTail;
|
|
387
383
|
let release;
|
|
388
|
-
ensurePrologTail = new Promise((resolve) => {
|
|
384
|
+
state.ensurePrologTail = new Promise((resolve) => {
|
|
389
385
|
release = resolve;
|
|
390
386
|
});
|
|
391
387
|
await previous;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { getSpec } from "kibi-
|
|
1
|
+
import { getSpec, statusSpec } from "kibi-runtime";
|
|
2
|
+
import { executeApplyPlan, executeCompileIntent, executeDelete, executeIngestProof, executeUpsert, validateUpsertSpec, } from "kibi-runtime";
|
|
3
|
+
import { startJob } from "./jobs.js";
|
|
2
4
|
// implements REQ-002, REQ-013
|
|
3
5
|
export function registerConfiguredTools(server, runtime, registerTool) {
|
|
4
6
|
const toolDef = (name) => {
|
|
@@ -14,6 +16,10 @@ export function registerConfiguredTools(server, runtime, registerTool) {
|
|
|
14
16
|
}
|
|
15
17
|
return prolog;
|
|
16
18
|
};
|
|
19
|
+
const withSessionProlog = (context) => ({
|
|
20
|
+
...context,
|
|
21
|
+
prolog: prologFor(context),
|
|
22
|
+
});
|
|
17
23
|
const register = ({ name, execute }) => {
|
|
18
24
|
const definition = toolDef(name);
|
|
19
25
|
const publicSpec = getSpec(name);
|
|
@@ -23,7 +29,7 @@ export function registerConfiguredTools(server, runtime, registerTool) {
|
|
|
23
29
|
requiresProlog: publicSpec.requiresProlog,
|
|
24
30
|
execute: (args, context) => execute(context, args),
|
|
25
31
|
};
|
|
26
|
-
registerTool(server, name, definition.description, definition.inputSchema, async () => undefined, runtime, spec, definition.annotations);
|
|
32
|
+
registerTool(server, name, definition.description, definition.inputSchema, async () => undefined, runtime, spec, definition.annotations, definition.outputSchema);
|
|
27
33
|
};
|
|
28
34
|
// INTENTIONAL ARGUMENT CASTS: The `args as (unknown as)? XyzArgs` casts below
|
|
29
35
|
// bridge the generic ToolHandler (which receives Record<string, unknown>) to the
|
|
@@ -39,7 +45,11 @@ export function registerConfiguredTools(server, runtime, registerTool) {
|
|
|
39
45
|
});
|
|
40
46
|
register({
|
|
41
47
|
name: "kb_status",
|
|
42
|
-
execute: async (context, args) =>
|
|
48
|
+
execute: async (context, args) =>
|
|
49
|
+
// Status owns its non-mutating fallback. Do not require the session engine
|
|
50
|
+
// here: an absent or unreadable branch store is exactly the condition it
|
|
51
|
+
// must be able to describe.
|
|
52
|
+
statusSpec.execute(args, context),
|
|
43
53
|
});
|
|
44
54
|
register({
|
|
45
55
|
name: "kb_skills_list",
|
|
@@ -75,19 +85,28 @@ export function registerConfiguredTools(server, runtime, registerTool) {
|
|
|
75
85
|
});
|
|
76
86
|
register({
|
|
77
87
|
name: "kb_upsert",
|
|
78
|
-
execute: async (context, args) =>
|
|
88
|
+
execute: async (context, args) => executeUpsert(args, withSessionProlog(context)),
|
|
79
89
|
});
|
|
80
90
|
register({
|
|
81
91
|
name: "kb_validate_upsert",
|
|
82
|
-
execute: async (context, args) =>
|
|
92
|
+
execute: async (context, args) => validateUpsertSpec.execute(args, withSessionProlog(context)),
|
|
83
93
|
});
|
|
84
94
|
register({
|
|
85
95
|
name: "kb_delete",
|
|
86
|
-
execute: async (context, args) =>
|
|
96
|
+
execute: async (context, args) => executeDelete(args, withSessionProlog(context)),
|
|
87
97
|
});
|
|
88
98
|
register({
|
|
89
99
|
name: "kb_check",
|
|
90
|
-
execute: async (context, args) =>
|
|
100
|
+
execute: async (context, args) => {
|
|
101
|
+
const { async: asyncMode, ...checkArgs } = args;
|
|
102
|
+
if (asyncMode !== true) {
|
|
103
|
+
return runtime.handleKbCheck(prologFor(context), args);
|
|
104
|
+
}
|
|
105
|
+
// Long-KB full checks can exceed the tool timeout. Detach into a job
|
|
106
|
+
// and return the kibi.job.v1 receipt immediately; the agent polls
|
|
107
|
+
// kb_job_status for the terminal state and full result.
|
|
108
|
+
return startJob("kb_check", () => runtime.handleKbCheck(prologFor(context), checkArgs));
|
|
109
|
+
},
|
|
91
110
|
});
|
|
92
111
|
register({
|
|
93
112
|
name: "kb_model_requirement",
|
|
@@ -98,7 +117,25 @@ export function registerConfiguredTools(server, runtime, registerTool) {
|
|
|
98
117
|
execute: async (context, args) => runtime.handleKbSuggestPredicates(prologFor(context), args),
|
|
99
118
|
});
|
|
100
119
|
register({
|
|
101
|
-
name: "
|
|
102
|
-
execute: async (context, args) => runtime.
|
|
120
|
+
name: "kb_plan_bootstrap",
|
|
121
|
+
execute: async (context, args) => runtime.handleKbPlanBootstrap(args, context),
|
|
122
|
+
});
|
|
123
|
+
register({
|
|
124
|
+
name: "kb_compile_intent",
|
|
125
|
+
execute: async (context, args) => runtime.handleKbCompileIntent
|
|
126
|
+
? runtime.handleKbCompileIntent(args, context)
|
|
127
|
+
: executeCompileIntent(args, context),
|
|
128
|
+
});
|
|
129
|
+
register({
|
|
130
|
+
name: "kb_apply_plan",
|
|
131
|
+
execute: async (context, args) => runtime.handleKbApplyPlan
|
|
132
|
+
? runtime.handleKbApplyPlan(args, context)
|
|
133
|
+
: executeApplyPlan(args, context),
|
|
134
|
+
});
|
|
135
|
+
register({
|
|
136
|
+
name: "kb_ingest_proof",
|
|
137
|
+
execute: async (context, args) => runtime.handleKbIngestProof
|
|
138
|
+
? runtime.handleKbIngestProof(args, context)
|
|
139
|
+
: executeIngestProof(args, context),
|
|
103
140
|
});
|
|
104
141
|
}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { getSpec } from "kibi-
|
|
2
|
-
import { nodeGit } from "kibi-cli/operations/node-ports";
|
|
1
|
+
import { getSpec, nodeFilesystem, nodeGit } from "kibi-runtime";
|
|
3
2
|
import { DIAGNOSTIC_MODE_ENABLED, appendUsageLogLine, classifyDiagnosticError, deriveDiagnosticFields, extractToolCallPayload, } from "../diagnostics.js";
|
|
4
3
|
import { isMcpDebugEnabled } from "../env.js";
|
|
5
4
|
import { createMcpRuntime } from "../runtime/mcp-runtime.js";
|
|
6
5
|
import { TOOLS } from "../tools-config.js";
|
|
7
|
-
import { handleKbAutopilotGenerate } from "../tools/autopilot-generate.js";
|
|
8
6
|
import { handleKbCheck } from "../tools/check.js";
|
|
9
7
|
import { handleKbCoverage } from "../tools/coverage.js";
|
|
10
8
|
import { handleKbDelete } from "../tools/delete.js";
|
|
11
9
|
import { handleKbFindGaps } from "../tools/find-gaps.js";
|
|
12
10
|
import { handleKbGraph } from "../tools/graph.js";
|
|
13
11
|
import { handleKbModelRequirement } from "../tools/model-requirement.js";
|
|
12
|
+
import { handleKbPlanBootstrap } from "../tools/plan-bootstrap.js";
|
|
14
13
|
import { handleKbQuery } from "../tools/query.js";
|
|
15
14
|
import { handleKbSearch } from "../tools/search.js";
|
|
16
15
|
import { handleKbSemanticAdvisor } from "../tools/semantic-advisor.js";
|
|
@@ -92,15 +91,16 @@ function adaptProlog(prolog) {
|
|
|
92
91
|
}
|
|
93
92
|
const operationRuntime = createMcpRuntime({
|
|
94
93
|
workspaceRoot: resolveWorkspaceRoot(),
|
|
95
|
-
activeBranchName: async () => (await getSessionModule()).
|
|
96
|
-
attachedBranchKbPath: async () => (await getSessionModule()).
|
|
94
|
+
activeBranchName: async () => (await getSessionModule()).getActiveBranchName(),
|
|
95
|
+
attachedBranchKbPath: async () => (await getSessionModule()).getAttachedBranchKbPath(),
|
|
97
96
|
ensureProlog: async () => (await getSessionModule()).ensureProlog(),
|
|
98
97
|
adaptProlog,
|
|
98
|
+
fs: nodeFilesystem,
|
|
99
99
|
git: nodeGit,
|
|
100
100
|
net: { fetch: (input, init) => globalThis.fetch(input, init) },
|
|
101
101
|
refreshAttachedBranchStamp: async () => {
|
|
102
102
|
const session = await getSessionModule();
|
|
103
|
-
const kbPath = session.
|
|
103
|
+
const kbPath = session.getAttachedBranchKbPath();
|
|
104
104
|
if (kbPath) {
|
|
105
105
|
try {
|
|
106
106
|
session.updateAttachedBranchStamp(await readBranchKbStamp(kbPath));
|
|
@@ -124,12 +124,12 @@ export const DEFAULT_TOOLS_RUNTIME = {
|
|
|
124
124
|
// runtime interface with looser Record<string, unknown> inputSchema. The cast is safe
|
|
125
125
|
// because the tool definitions are statically authored and validated at startup.
|
|
126
126
|
tools: TOOLS,
|
|
127
|
-
activeBranchName: async () => (await getSessionModule()).
|
|
127
|
+
activeBranchName: async () => (await getSessionModule()).getActiveBranchName(),
|
|
128
128
|
ensureProlog: async () => (await getSessionModule()).ensureProlog(),
|
|
129
129
|
resetProlog: async (reason) => (await getSessionModule()).resetProlog(reason),
|
|
130
130
|
inFlightRequests: async () => (await getSessionModule()).inFlightRequests,
|
|
131
|
-
isShuttingDown: async () => (await getSessionModule()).
|
|
132
|
-
prologProcess: async () => (await getSessionModule()).
|
|
131
|
+
isShuttingDown: async () => (await getSessionModule()).getIsShuttingDown(),
|
|
132
|
+
prologProcess: async () => (await getSessionModule()).getPrologProcess(),
|
|
133
133
|
operationRuntime,
|
|
134
134
|
handleKbCheck,
|
|
135
135
|
handleKbCoverage,
|
|
@@ -148,5 +148,5 @@ export const DEFAULT_TOOLS_RUNTIME = {
|
|
|
148
148
|
handleKbValidateUpsert,
|
|
149
149
|
handleKbModelRequirement,
|
|
150
150
|
handleKbSuggestPredicates,
|
|
151
|
-
|
|
151
|
+
handleKbPlanBootstrap,
|
|
152
152
|
};
|