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.
Files changed (47) hide show
  1. package/bin/kibi-mcp +12 -11
  2. package/dist/diagnostics.js +68 -8
  3. package/dist/env.js +5 -1
  4. package/dist/runtime/mcp-runtime.js +39 -3
  5. package/dist/server/docs.js +31 -42
  6. package/dist/server/icons.js +27 -0
  7. package/dist/server/jobs.js +107 -0
  8. package/dist/server/json-schema-to-zod.js +33 -9
  9. package/dist/server/session.js +129 -133
  10. package/dist/server/tool-registration.js +46 -9
  11. package/dist/server/tools-runtime.js +10 -10
  12. package/dist/server/tools.js +143 -7
  13. package/dist/server.js +16 -1
  14. package/dist/startup-resolution.js +15 -17
  15. package/dist/tools/check-impact.js +1 -1
  16. package/dist/tools/check.js +1 -1
  17. package/dist/tools/core-module.js +19 -8
  18. package/dist/tools/coverage.js +1 -1
  19. package/dist/tools/delete.js +1 -1
  20. package/dist/tools/discovery-adapter.js +5 -0
  21. package/dist/tools/entity-query.js +1 -1
  22. package/dist/tools/find-gaps.js +9 -1
  23. package/dist/tools/graph.js +9 -1
  24. package/dist/tools/model-requirement.js +2 -2
  25. package/dist/tools/mutation-context.js +15 -9
  26. package/dist/tools/plan-bootstrap.js +21 -0
  27. package/dist/tools/prolog-list.js +1 -1
  28. package/dist/tools/query.js +1 -1
  29. package/dist/tools/relationship-validation.js +1 -1
  30. package/dist/tools/search.js +1 -1
  31. package/dist/tools/semantic-advisor.js +1 -1
  32. package/dist/tools/skills.js +2 -2
  33. package/dist/tools/sparql.js +1 -1
  34. package/dist/tools/status.js +1 -1
  35. package/dist/tools/suggest-predicates.js +1 -1
  36. package/dist/tools/symbols.js +310 -68
  37. package/dist/tools/upsert.js +3 -3
  38. package/dist/tools/validate-upsert.js +1 -1
  39. package/dist/tools-config.js +77 -3
  40. package/dist/workspace.js +10 -8
  41. package/package.json +15 -9
  42. package/dist/tools/autopilot-candidates.js +0 -554
  43. package/dist/tools/autopilot-discovery.js +0 -898
  44. package/dist/tools/autopilot-generate.js +0 -47
  45. package/dist/tools/autopilot-test-compat.js +0 -88
  46. package/dist/tools/autopilot-test-parsers.js +0 -120
  47. package/dist/tools/check-config.js +0 -67
@@ -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-cli/engine";
22
- import { PrologProcess } from "kibi-cli/prolog";
23
- import { copyCleanSnapshot, getBranchDiagnostic, isValidBranchName, resolveActiveBranch, } from "kibi-cli/public/branch-resolver";
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
- export let prologProcess = null;
40
- let isInitialized = false;
41
- export let activeBranchName = "develop";
42
- let ensurePrologTail = Promise.resolve();
43
- let prologResetGeneration = 0;
44
- export let attachedBranchKbPath = null;
45
- let attachedBranchStamp = null;
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
- // Try to copy from the previously active branch if available
94
- const previousBranch = activeBranchName;
95
- const previousBranchPath = sessionDeps.resolveKbPath(workspaceRoot, previousBranch);
96
- if (previousBranch !== branch &&
97
- previousBranch !== "develop" &&
98
- sessionDeps.fs.existsSync(previousBranchPath)) {
99
- // Copy from previous branch for continuity
100
- sessionDeps.copyCleanSnapshot(previousBranchPath, branchPath);
101
- debugLog(`[KIBI-MCP] Created branch KB for '${branch}' from '${previousBranch}'`);
102
- return false;
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 active branch from git (may change between requests)
232
- const branchResult = sessionDeps.resolveActiveBranch(workspaceRoot);
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.branch;
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
- // Startup debug: resolve which kibi-cli is being used and its version (best-effort).
326
- // Gate all output under KIBI_MCP_DEBUG and write only to stderr via debugLog.
327
- if (isMcpDebugEnabled()) {
328
- try {
329
- const req = sessionDeps.createRequire(import.meta.url);
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-cli/operations";
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) => runtime.handleKbStatus(prologFor(context), args, context),
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) => runtime.handleKbUpsert(prologFor(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) => runtime.handleKbValidateUpsert(prologFor(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) => runtime.handleKbDelete(prologFor(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) => runtime.handleKbCheck(prologFor(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: "kb_autopilot_generate",
102
- execute: async (context, args) => runtime.handleKbAutopilotGenerate(args, context),
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-cli/operations";
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()).activeBranchName,
96
- attachedBranchKbPath: async () => (await getSessionModule()).attachedBranchKbPath,
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.attachedBranchKbPath;
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()).activeBranchName,
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()).isShuttingDown,
132
- prologProcess: async () => (await getSessionModule()).prologProcess,
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
- handleKbAutopilotGenerate,
151
+ handleKbPlanBootstrap,
152
152
  };