kibi-mcp 0.17.4 → 0.19.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.
@@ -0,0 +1,104 @@
1
+ import { z } from "zod";
2
+ // implements REQ-002
3
+ export function jsonSchemaToZod(schema) {
4
+ if (!schema || typeof schema !== "object") {
5
+ return z.any();
6
+ }
7
+ const obj = schema;
8
+ if (Array.isArray(obj.enum) && obj.enum.length > 0) {
9
+ const description = typeof obj.description === "string" ? obj.description : undefined;
10
+ const literals = obj.enum.filter((value) => typeof value === "string" ||
11
+ typeof value === "number" ||
12
+ typeof value === "boolean" ||
13
+ value === null);
14
+ if (literals.length === 0) {
15
+ return description ? z.any().describe(description) : z.any();
16
+ }
17
+ const literalSchemas = literals.map((value) => z.literal(value));
18
+ if (literalSchemas.length === 1) {
19
+ const single = literalSchemas[0];
20
+ if (!single) {
21
+ return description ? z.any().describe(description) : z.any();
22
+ }
23
+ return description ? single.describe(description) : single;
24
+ }
25
+ const union = z.union(literalSchemas);
26
+ return description ? union.describe(description) : union;
27
+ }
28
+ const schemaType = typeof obj.type === "string" ? obj.type : undefined;
29
+ switch (schemaType) {
30
+ case "object": {
31
+ const properties = obj.properties && typeof obj.properties === "object"
32
+ ? obj.properties
33
+ : {};
34
+ const required = new Set(Array.isArray(obj.required)
35
+ ? obj.required.filter((k) => typeof k === "string" && k.length > 0)
36
+ : []);
37
+ const shape = {};
38
+ for (const [key, value] of Object.entries(properties)) {
39
+ const propSchema = jsonSchemaToZod(value);
40
+ shape[key] = required.has(key) ? propSchema : propSchema.optional();
41
+ }
42
+ const objectSchema = obj.additionalProperties === false
43
+ ? z.object(shape)
44
+ : z.looseObject(shape);
45
+ const description = typeof obj.description === "string" ? obj.description : undefined;
46
+ return description ? objectSchema.describe(description) : objectSchema;
47
+ }
48
+ case "array": {
49
+ const itemSchema = jsonSchemaToZod(obj.items);
50
+ let arraySchema = z.array(itemSchema);
51
+ const description = typeof obj.description === "string" ? obj.description : undefined;
52
+ if (typeof obj.minItems === "number") {
53
+ arraySchema = arraySchema.min(obj.minItems);
54
+ }
55
+ if (typeof obj.maxItems === "number") {
56
+ arraySchema = arraySchema.max(obj.maxItems);
57
+ }
58
+ return description ? arraySchema.describe(description) : arraySchema;
59
+ }
60
+ case "string": {
61
+ let s = z.string();
62
+ const description = typeof obj.description === "string" ? obj.description : undefined;
63
+ if (typeof obj.minLength === "number") {
64
+ s = s.min(obj.minLength);
65
+ }
66
+ if (typeof obj.maxLength === "number") {
67
+ s = s.max(obj.maxLength);
68
+ }
69
+ return description ? s.describe(description) : s;
70
+ }
71
+ case "number": {
72
+ let n = z.number();
73
+ const description = typeof obj.description === "string" ? obj.description : undefined;
74
+ if (typeof obj.minimum === "number") {
75
+ n = n.min(obj.minimum);
76
+ }
77
+ if (typeof obj.maximum === "number") {
78
+ n = n.max(obj.maximum);
79
+ }
80
+ return description ? n.describe(description) : n;
81
+ }
82
+ case "integer": {
83
+ let n = z.number().int();
84
+ const description = typeof obj.description === "string" ? obj.description : undefined;
85
+ if (typeof obj.minimum === "number") {
86
+ n = n.min(obj.minimum);
87
+ }
88
+ if (typeof obj.maximum === "number") {
89
+ n = n.max(obj.maximum);
90
+ }
91
+ return description ? n.describe(description) : n;
92
+ }
93
+ case "boolean": {
94
+ const b = z.boolean();
95
+ const description = typeof obj.description === "string" ? obj.description : undefined;
96
+ return description ? b.describe(description) : b;
97
+ }
98
+ default: {
99
+ const anySchema = z.any();
100
+ const description = typeof obj.description === "string" ? obj.description : undefined;
101
+ return description ? anySchema.describe(description) : anySchema;
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,131 @@
1
+ // implements REQ-002, REQ-013
2
+ export function registerConfiguredTools(server, runtime, registerTool) {
3
+ const toolDef = (name) => {
4
+ const t = runtime.tools.find((tool) => tool.name === name);
5
+ if (!t)
6
+ throw new Error(`Unknown tool: ${name}`);
7
+ return t;
8
+ };
9
+ const register = ({ name, handler }) => {
10
+ const definition = toolDef(name);
11
+ registerTool(server, name, definition.description, definition.inputSchema, handler, runtime);
12
+ };
13
+ // INTENTIONAL ARGUMENT CASTS: The `args as (unknown as)? XyzArgs` casts below
14
+ // bridge the generic ToolHandler (which receives Record<string, unknown>) to the
15
+ // specific handler argument types. Argument shapes are validated by Zod schemas
16
+ // (via jsonSchemaToZod) before the handler is invoked, so the casts are safe at runtime.
17
+ register({
18
+ name: "kb_query",
19
+ handler: async (args) => {
20
+ const prolog = await runtime.ensureProlog();
21
+ return runtime.handleKbQuery(prolog, args);
22
+ },
23
+ });
24
+ register({
25
+ name: "kb_search",
26
+ handler: async (args) => {
27
+ const prolog = await runtime.ensureProlog();
28
+ return runtime.handleKbSearch(prolog, args);
29
+ },
30
+ });
31
+ register({
32
+ name: "kb_status",
33
+ handler: async (args) => {
34
+ const prolog = await runtime.ensureProlog();
35
+ return runtime.handleKbStatus(prolog, args);
36
+ },
37
+ });
38
+ register({
39
+ name: "kb_skills_list",
40
+ handler: async (args) => runtime.handleKbSkillsList(args),
41
+ });
42
+ register({
43
+ name: "kb_skills_load",
44
+ handler: async (args) => runtime.handleKbSkillsLoad(args),
45
+ });
46
+ register({
47
+ name: "kb_skills_read",
48
+ handler: async (args) => runtime.handleKbSkillsRead(args),
49
+ });
50
+ register({
51
+ name: "kb_find_gaps",
52
+ handler: async (args) => {
53
+ const prolog = await runtime.ensureProlog();
54
+ return runtime.handleKbFindGaps(prolog, args);
55
+ },
56
+ });
57
+ register({
58
+ name: "kb_coverage",
59
+ handler: async (args) => {
60
+ const prolog = await runtime.ensureProlog();
61
+ return runtime.handleKbCoverage(prolog, args);
62
+ },
63
+ });
64
+ register({
65
+ name: "kb_graph",
66
+ handler: async (args) => {
67
+ const prolog = await runtime.ensureProlog();
68
+ return runtime.handleKbGraph(prolog, args);
69
+ },
70
+ });
71
+ register({
72
+ name: "kb_sparql_remote",
73
+ handler: async (args) => {
74
+ const prolog = await runtime.ensureProlog();
75
+ return runtime.handleSparql(prolog, args);
76
+ },
77
+ });
78
+ register({
79
+ name: "kb_semantic_advisor",
80
+ handler: async (args) => runtime.handleKbSemanticAdvisor(args),
81
+ });
82
+ register({
83
+ name: "kb_upsert",
84
+ handler: async (args) => {
85
+ const prolog = await runtime.ensureProlog();
86
+ return runtime.handleKbUpsert(prolog, args);
87
+ },
88
+ });
89
+ register({
90
+ name: "kb_validate_upsert",
91
+ handler: async (args) => {
92
+ const prolog = await runtime.ensureProlog();
93
+ return runtime.handleKbValidateUpsert(prolog, args);
94
+ },
95
+ });
96
+ register({
97
+ name: "kb_delete",
98
+ handler: async (args) => {
99
+ const prolog = await runtime.ensureProlog();
100
+ return runtime.handleKbDelete(prolog, args);
101
+ },
102
+ });
103
+ register({
104
+ name: "kb_check",
105
+ handler: async (args) => {
106
+ const prolog = await runtime.ensureProlog();
107
+ return runtime.handleKbCheck(prolog, args);
108
+ },
109
+ });
110
+ register({
111
+ name: "kb_model_requirement",
112
+ handler: async (args) => {
113
+ const prolog = await runtime.ensureProlog();
114
+ return runtime.handleKbModelRequirement(prolog, args);
115
+ },
116
+ });
117
+ register({
118
+ name: "kb_suggest_predicates",
119
+ handler: async (args) => {
120
+ const prolog = await runtime.ensureProlog();
121
+ return runtime.handleKbSuggestPredicates(prolog, args);
122
+ },
123
+ });
124
+ register({
125
+ name: "kb_autopilot_generate",
126
+ handler: async (args) => {
127
+ const prolog = await runtime.ensureProlog();
128
+ return runtime.handleKbAutopilotGenerate(prolog, args);
129
+ },
130
+ });
131
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,76 @@
1
+ import { DIAGNOSTIC_MODE_ENABLED, appendUsageLogLine, classifyDiagnosticError, deriveDiagnosticFields, extractToolCallPayload, } from "../diagnostics.js";
2
+ import { TOOLS } from "../tools-config.js";
3
+ import { handleKbAutopilotGenerate } from "../tools/autopilot-generate.js";
4
+ import { handleKbCheck } from "../tools/check.js";
5
+ import { handleKbCoverage } from "../tools/coverage.js";
6
+ import { handleKbDelete } from "../tools/delete.js";
7
+ import { handleKbFindGaps } from "../tools/find-gaps.js";
8
+ import { handleKbGraph } from "../tools/graph.js";
9
+ import { handleKbModelRequirement } from "../tools/model-requirement.js";
10
+ import { handleKbQuery } from "../tools/query.js";
11
+ import { handleKbSearch } from "../tools/search.js";
12
+ import { handleKbSemanticAdvisor } from "../tools/semantic-advisor.js";
13
+ import { handleKbSkillsList, handleKbSkillsLoad, handleKbSkillsRead, } from "../tools/skills.js";
14
+ import { handleSparql } from "../tools/sparql.js";
15
+ import { handleKbStatus } from "../tools/status.js";
16
+ import { handleKbSuggestPredicates } from "../tools/suggest-predicates.js";
17
+ import { handleKbUpsert } from "../tools/upsert.js";
18
+ import { handleKbValidateUpsert } from "../tools/validate-upsert.js";
19
+ const defaultToolsServerDeps = {
20
+ getSessionModule: () => import("./session.js"),
21
+ };
22
+ let sessionModulePromise = null;
23
+ // implements REQ-008
24
+ export function _setToolsServerDepsForTests(deps, resetPromise = false) {
25
+ defaultToolsServerDeps.getSessionModule =
26
+ deps.getSessionModule ?? defaultToolsServerDeps.getSessionModule;
27
+ if (resetPromise) {
28
+ sessionModulePromise = null;
29
+ }
30
+ }
31
+ // implements REQ-012
32
+ export function _resetSessionModulePromise() {
33
+ sessionModulePromise = null;
34
+ }
35
+ /* v8 ignore next (3 lines) — lazy async module loader; body only executes once per process
36
+ * when DEFAULT_TOOLS_RUNTIME.activeBranchName/ensureProlog/etc. are first called.
37
+ * Cannot be re-triggered without process restart (sessionModulePromise is module-level). */
38
+ async function getSessionModule() {
39
+ sessionModulePromise ??= defaultToolsServerDeps.getSessionModule();
40
+ return sessionModulePromise;
41
+ }
42
+ export const DEFAULT_TOOLS_RUNTIME = {
43
+ diagnosticModeEnabled: () => DIAGNOSTIC_MODE_ENABLED,
44
+ appendUsageLogLine,
45
+ classifyDiagnosticError,
46
+ deriveDiagnosticFields,
47
+ extractToolCallPayload,
48
+ // INTENTIONAL: TOOLS is imported as a Zod-inferred schema type; ToolConfig is the
49
+ // runtime interface with looser Record<string, unknown> inputSchema. The cast is safe
50
+ // because the tool definitions are statically authored and validated at startup.
51
+ tools: TOOLS,
52
+ activeBranchName: async () => (await getSessionModule()).activeBranchName,
53
+ ensureProlog: async () => (await getSessionModule()).ensureProlog(),
54
+ resetProlog: async (reason) => (await getSessionModule()).resetProlog(reason),
55
+ inFlightRequests: async () => (await getSessionModule()).inFlightRequests,
56
+ isShuttingDown: async () => (await getSessionModule()).isShuttingDown,
57
+ prologProcess: async () => (await getSessionModule()).prologProcess,
58
+ handleKbCheck,
59
+ handleKbCoverage,
60
+ handleKbDelete,
61
+ handleKbFindGaps,
62
+ handleKbGraph,
63
+ handleSparql,
64
+ handleKbQuery,
65
+ handleKbSearch,
66
+ handleKbStatus,
67
+ handleKbSemanticAdvisor,
68
+ handleKbSkillsList,
69
+ handleKbSkillsLoad,
70
+ handleKbSkillsRead,
71
+ handleKbUpsert,
72
+ handleKbValidateUpsert,
73
+ handleKbModelRequirement,
74
+ handleKbSuggestPredicates,
75
+ handleKbAutopilotGenerate,
76
+ };
@@ -16,86 +16,15 @@
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 { z } from "zod";
20
- import { DIAGNOSTIC_MODE_ENABLED, appendUsageLogLine, classifyDiagnosticError, deriveDiagnosticFields, extractToolCallPayload, } from "../diagnostics.js";
21
19
  import { isMcpDebugEnabled } from "../env.js";
22
- import { TOOLS } from "../tools-config.js";
23
- import { handleKbAutopilotGenerate, } from "../tools/autopilot-generate.js";
24
- import { handleKbCheck } from "../tools/check.js";
25
- import { handleKbCoverage } from "../tools/coverage.js";
26
- import { handleKbDelete } from "../tools/delete.js";
27
- import { handleKbFindGaps } from "../tools/find-gaps.js";
28
- import { handleKbGraph } from "../tools/graph.js";
29
- import { handleKbModelRequirement, } from "../tools/model-requirement.js";
30
- import { handleKbQuery } from "../tools/query.js";
31
- import { handleKbSearch } from "../tools/search.js";
32
- import { handleKbSemanticAdvisor, } from "../tools/semantic-advisor.js";
33
- import { handleKbSkillsList, handleKbSkillsLoad, handleKbSkillsRead, } from "../tools/skills.js";
34
- import { handleSparql } from "../tools/sparql.js";
35
- import { handleKbStatus } from "../tools/status.js";
36
- import { handleKbSuggestPredicates, } from "../tools/suggest-predicates.js";
37
- import { handleKbUpsert } from "../tools/upsert.js";
38
- import { handleKbValidateUpsert } from "../tools/validate-upsert.js";
20
+ import { appendDiagnosticErrorUsage, appendDiagnosticSuccessUsage, } from "./diagnostic-usage.js";
21
+ import { jsonSchemaToZod } from "./json-schema-to-zod.js";
22
+ import { registerConfiguredTools } from "./tool-registration.js";
23
+ import { DEFAULT_TOOLS_RUNTIME, _resetSessionModulePromise, _setToolsServerDepsForTests, } from "./tools-runtime.js";
24
+ export { jsonSchemaToZod } from "./json-schema-to-zod.js";
25
+ export { _resetSessionModulePromise, _setToolsServerDepsForTests };
39
26
  const DEFAULT_TOOL_TIMEOUT_MS = 90_000;
40
27
  const TOOL_TIMEOUT_ENV = "KIBI_MCP_TOOL_TIMEOUT_MS";
41
- const defaultToolsServerDeps = {
42
- getSessionModule: () => import("./session.js"),
43
- };
44
- // implements REQ-008
45
- export function _setToolsServerDepsForTests(deps, resetPromise = false) {
46
- defaultToolsServerDeps.getSessionModule =
47
- deps.getSessionModule ?? defaultToolsServerDeps.getSessionModule;
48
- if (resetPromise) {
49
- sessionModulePromise = null;
50
- }
51
- }
52
- // implements REQ-012
53
- export function _resetSessionModulePromise() {
54
- sessionModulePromise = null;
55
- }
56
- let sessionModulePromise = null;
57
- /* v8 ignore next (3 lines) — lazy async module loader; body only executes once per process
58
- * when DEFAULT_TOOLS_RUNTIME.activeBranchName/ensureProlog/etc. are first called.
59
- * Cannot be re-triggered without process restart (sessionModulePromise is module-level). */
60
- async function getSessionModule() {
61
- sessionModulePromise ??= defaultToolsServerDeps.getSessionModule();
62
- return sessionModulePromise;
63
- }
64
- const DEFAULT_TOOLS_RUNTIME = {
65
- diagnosticModeEnabled: () => DIAGNOSTIC_MODE_ENABLED,
66
- appendUsageLogLine,
67
- classifyDiagnosticError,
68
- deriveDiagnosticFields,
69
- extractToolCallPayload,
70
- // INTENTIONAL: TOOLS is imported as a Zod-inferred schema type; ToolConfig is the
71
- // runtime interface with looser Record<string, unknown> inputSchema. The cast is safe
72
- // because the tool definitions are statically authored and validated at startup.
73
- tools: TOOLS,
74
- activeBranchName: async () => (await getSessionModule()).activeBranchName,
75
- ensureProlog: async () => (await getSessionModule()).ensureProlog(),
76
- resetProlog: async (reason) => (await getSessionModule()).resetProlog(reason),
77
- inFlightRequests: async () => (await getSessionModule()).inFlightRequests,
78
- isShuttingDown: async () => (await getSessionModule()).isShuttingDown,
79
- prologProcess: async () => (await getSessionModule()).prologProcess,
80
- handleKbCheck,
81
- handleKbCoverage,
82
- handleKbDelete,
83
- handleKbFindGaps,
84
- handleKbGraph,
85
- handleSparql,
86
- handleKbQuery,
87
- handleKbSearch,
88
- handleKbStatus,
89
- handleKbSemanticAdvisor,
90
- handleKbSkillsList,
91
- handleKbSkillsLoad,
92
- handleKbSkillsRead,
93
- handleKbUpsert,
94
- handleKbValidateUpsert,
95
- handleKbModelRequirement,
96
- handleKbSuggestPredicates,
97
- handleKbAutopilotGenerate,
98
- };
99
28
  // implements REQ-008
100
29
  function debugLog(...args) {
101
30
  if (isMcpDebugEnabled()) {
@@ -140,109 +69,6 @@ async function withToolTimeout(toolName, operation, onTimeout) {
140
69
  }
141
70
  }
142
71
  // implements REQ-002
143
- export function jsonSchemaToZod(schema) {
144
- if (!schema || typeof schema !== "object") {
145
- return z.any();
146
- }
147
- const obj = schema;
148
- if (Array.isArray(obj.enum) && obj.enum.length > 0) {
149
- const description = typeof obj.description === "string" ? obj.description : undefined;
150
- const literals = obj.enum.filter((value) => typeof value === "string" ||
151
- typeof value === "number" ||
152
- typeof value === "boolean" ||
153
- value === null);
154
- if (literals.length === 0) {
155
- return description ? z.any().describe(description) : z.any();
156
- }
157
- const literalSchemas = literals.map((value) => z.literal(value));
158
- if (literalSchemas.length === 1) {
159
- const single = literalSchemas[0];
160
- if (!single) {
161
- return description ? z.any().describe(description) : z.any();
162
- }
163
- return description ? single.describe(description) : single;
164
- }
165
- const union = z.union(literalSchemas);
166
- return description ? union.describe(description) : union;
167
- }
168
- const schemaType = typeof obj.type === "string" ? obj.type : undefined;
169
- switch (schemaType) {
170
- case "object": {
171
- const properties = obj.properties && typeof obj.properties === "object"
172
- ? obj.properties
173
- : {};
174
- const required = new Set(Array.isArray(obj.required)
175
- ? obj.required.filter((k) => typeof k === "string" && k.length > 0)
176
- : []);
177
- const shape = {};
178
- for (const [key, value] of Object.entries(properties)) {
179
- const propSchema = jsonSchemaToZod(value);
180
- shape[key] = required.has(key) ? propSchema : propSchema.optional();
181
- }
182
- const objectSchema = obj.additionalProperties === false
183
- ? z.object(shape)
184
- : z.looseObject(shape);
185
- const description = typeof obj.description === "string" ? obj.description : undefined;
186
- return description ? objectSchema.describe(description) : objectSchema;
187
- }
188
- case "array": {
189
- const itemSchema = jsonSchemaToZod(obj.items);
190
- let arraySchema = z.array(itemSchema);
191
- const description = typeof obj.description === "string" ? obj.description : undefined;
192
- if (typeof obj.minItems === "number") {
193
- arraySchema = arraySchema.min(obj.minItems);
194
- }
195
- if (typeof obj.maxItems === "number") {
196
- arraySchema = arraySchema.max(obj.maxItems);
197
- }
198
- return description ? arraySchema.describe(description) : arraySchema;
199
- }
200
- case "string": {
201
- let s = z.string();
202
- const description = typeof obj.description === "string" ? obj.description : undefined;
203
- if (typeof obj.minLength === "number") {
204
- s = s.min(obj.minLength);
205
- }
206
- if (typeof obj.maxLength === "number") {
207
- s = s.max(obj.maxLength);
208
- }
209
- return description ? s.describe(description) : s;
210
- }
211
- case "number": {
212
- let n = z.number();
213
- const description = typeof obj.description === "string" ? obj.description : undefined;
214
- if (typeof obj.minimum === "number") {
215
- n = n.min(obj.minimum);
216
- }
217
- if (typeof obj.maximum === "number") {
218
- n = n.max(obj.maximum);
219
- }
220
- return description ? n.describe(description) : n;
221
- }
222
- case "integer": {
223
- let n = z.number().int();
224
- const description = typeof obj.description === "string" ? obj.description : undefined;
225
- if (typeof obj.minimum === "number") {
226
- n = n.min(obj.minimum);
227
- }
228
- if (typeof obj.maximum === "number") {
229
- n = n.max(obj.maximum);
230
- }
231
- return description ? n.describe(description) : n;
232
- }
233
- case "boolean": {
234
- const b = z.boolean();
235
- const description = typeof obj.description === "string" ? obj.description : undefined;
236
- return description ? b.describe(description) : b;
237
- }
238
- default: {
239
- const anySchema = z.any();
240
- const description = typeof obj.description === "string" ? obj.description : undefined;
241
- return description ? anySchema.describe(description) : anySchema;
242
- }
243
- }
244
- }
245
- // implements REQ-002
246
72
  export function addTool(server, name, description, inputSchema, handler,
247
73
  // INTENTIONAL: DEFAULT_TOOLS_RUNTIME is typed as ToolsRuntime<PrologProcess>; the
248
74
  // generic TProlog parameter exists so tests can inject a mock type. The cast is safe
@@ -293,23 +119,15 @@ runtime = DEFAULT_TOOLS_RUNTIME) {
293
119
  });
294
120
  // Log usage in diagnostic mode
295
121
  if (diagnosticModeEnabled) {
296
- const finishedAt = new Date();
297
- const diagnosticFields = runtime.deriveDiagnosticFields(name, businessArgs, telemetry, result);
298
- const processHandle = await runtime.prologProcess();
299
- const branchName = await runtime.activeBranchName();
300
- runtime.appendUsageLogLine({
301
- timestamp: finishedAt.toISOString(),
302
- request_id: requestId,
303
- tool: name,
122
+ await appendDiagnosticSuccessUsage({
123
+ runtime,
124
+ toolName: name,
125
+ requestId,
126
+ args,
127
+ businessArgs,
304
128
  telemetry,
305
- business_args: businessArgs,
306
- status: "success",
307
- started_at: startedAt.toISOString(),
308
- finished_at: finishedAt.toISOString(),
309
- duration_ms: finishedAt.getTime() - startedAt.getTime(),
310
- prolog_pid: processHandle?.getPid() ?? null,
311
- active_branch: branchName,
312
- ...diagnosticFields,
129
+ startedAt,
130
+ result,
313
131
  });
314
132
  }
315
133
  return result;
@@ -317,27 +135,16 @@ runtime = DEFAULT_TOOLS_RUNTIME) {
317
135
  catch (error) {
318
136
  // Log error in diagnostic mode
319
137
  if (diagnosticModeEnabled) {
320
- const finishedAt = new Date();
321
- const err = error instanceof Error ? error : new Error(String(error));
322
- const diagnosticErrorFields = runtime.classifyDiagnosticError(err);
323
- const processHandle = await runtime.prologProcess();
324
- const branchName = await runtime.activeBranchName();
325
- runtime.appendUsageLogLine({
326
- timestamp: finishedAt.toISOString(),
327
- request_id: requestId,
328
- tool: name,
138
+ await appendDiagnosticErrorUsage({
139
+ runtime,
140
+ toolName: name,
141
+ requestId,
142
+ args,
143
+ businessArgs,
329
144
  telemetry,
330
- business_args: businessArgs,
331
- status: "error",
332
- started_at: startedAt.toISOString(),
333
- finished_at: finishedAt.toISOString(),
334
- duration_ms: finishedAt.getTime() - startedAt.getTime(),
335
- prolog_pid: processHandle?.getPid() ?? null,
336
- active_branch: branchName,
337
- reset_attempted: resetAttempted,
338
- reset_succeeded: resetSucceeded,
339
- reset_error: resetError,
340
- ...diagnosticErrorFields,
145
+ startedAt,
146
+ error,
147
+ resetState: { resetAttempted, resetSucceeded, resetError },
341
148
  });
342
149
  }
343
150
  throw error;
@@ -362,75 +169,5 @@ runtime = DEFAULT_TOOLS_RUNTIME) {
362
169
  export function registerAllTools(server,
363
170
  // INTENTIONAL: same generic bridge cast as addTool — see comment there.
364
171
  runtime = DEFAULT_TOOLS_RUNTIME) {
365
- const toolDef = (name) => {
366
- const t = runtime.tools.find((tool) => tool.name === name);
367
- if (!t)
368
- throw new Error(`Unknown tool: ${name}`);
369
- return t;
370
- };
371
- // INTENTIONAL ARGUMENT CASTS: The `args as (unknown as)? XyzArgs` casts below
372
- // bridge the generic ToolHandler (which receives Record<string, unknown>) to the
373
- // specific handler argument types. Argument shapes are validated by Zod schemas
374
- // (via jsonSchemaToZod) before the handler is invoked, so the casts are safe at runtime.
375
- addTool(server, "kb_query", toolDef("kb_query").description, toolDef("kb_query").inputSchema, async (args) => {
376
- const prolog = await runtime.ensureProlog();
377
- return runtime.handleKbQuery(prolog, args);
378
- }, runtime);
379
- addTool(server, "kb_search", toolDef("kb_search").description, toolDef("kb_search").inputSchema, async (args) => {
380
- const prolog = await runtime.ensureProlog();
381
- return runtime.handleKbSearch(prolog, args);
382
- }, runtime);
383
- addTool(server, "kb_status", toolDef("kb_status").description, toolDef("kb_status").inputSchema, async (args) => {
384
- const prolog = await runtime.ensureProlog();
385
- return runtime.handleKbStatus(prolog, args);
386
- }, runtime);
387
- addTool(server, "kb_skills_list", toolDef("kb_skills_list").description, toolDef("kb_skills_list").inputSchema, async (args) => runtime.handleKbSkillsList(args), runtime);
388
- addTool(server, "kb_skills_load", toolDef("kb_skills_load").description, toolDef("kb_skills_load").inputSchema, async (args) => runtime.handleKbSkillsLoad(args), runtime);
389
- addTool(server, "kb_skills_read", toolDef("kb_skills_read").description, toolDef("kb_skills_read").inputSchema, async (args) => runtime.handleKbSkillsRead(args), runtime);
390
- addTool(server, "kb_find_gaps", toolDef("kb_find_gaps").description, toolDef("kb_find_gaps").inputSchema, async (args) => {
391
- const prolog = await runtime.ensureProlog();
392
- return runtime.handleKbFindGaps(prolog, args);
393
- }, runtime);
394
- addTool(server, "kb_coverage", toolDef("kb_coverage").description, toolDef("kb_coverage").inputSchema, async (args) => {
395
- const prolog = await runtime.ensureProlog();
396
- return runtime.handleKbCoverage(prolog, args);
397
- }, runtime);
398
- addTool(server, "kb_graph", toolDef("kb_graph").description, toolDef("kb_graph").inputSchema, async (args) => {
399
- const prolog = await runtime.ensureProlog();
400
- return runtime.handleKbGraph(prolog, args);
401
- }, runtime);
402
- addTool(server, "kb_sparql_remote", toolDef("kb_sparql_remote").description, toolDef("kb_sparql_remote").inputSchema, async (args) => {
403
- const prolog = await runtime.ensureProlog();
404
- return runtime.handleSparql(prolog, args);
405
- }, runtime);
406
- addTool(server, "kb_semantic_advisor", toolDef("kb_semantic_advisor").description, toolDef("kb_semantic_advisor").inputSchema, async (args) => {
407
- return runtime.handleKbSemanticAdvisor(args);
408
- }, runtime);
409
- addTool(server, "kb_upsert", toolDef("kb_upsert").description, toolDef("kb_upsert").inputSchema, async (args) => {
410
- const prolog = await runtime.ensureProlog();
411
- return runtime.handleKbUpsert(prolog, args);
412
- }, runtime);
413
- addTool(server, "kb_validate_upsert", toolDef("kb_validate_upsert").description, toolDef("kb_validate_upsert").inputSchema, async (args) => {
414
- return runtime.handleKbValidateUpsert(args);
415
- }, runtime);
416
- addTool(server, "kb_delete", toolDef("kb_delete").description, toolDef("kb_delete").inputSchema, async (args) => {
417
- const prolog = await runtime.ensureProlog();
418
- return runtime.handleKbDelete(prolog, args);
419
- }, runtime);
420
- addTool(server, "kb_check", toolDef("kb_check").description, toolDef("kb_check").inputSchema, async (args) => {
421
- const prolog = await runtime.ensureProlog();
422
- return runtime.handleKbCheck(prolog, args);
423
- }, runtime);
424
- addTool(server, "kb_model_requirement", toolDef("kb_model_requirement").description, toolDef("kb_model_requirement").inputSchema, async (args) => {
425
- const prolog = await runtime.ensureProlog();
426
- return runtime.handleKbModelRequirement(prolog, args);
427
- }, runtime);
428
- addTool(server, "kb_suggest_predicates", toolDef("kb_suggest_predicates").description, toolDef("kb_suggest_predicates").inputSchema, async (args) => {
429
- const prolog = await runtime.ensureProlog();
430
- return runtime.handleKbSuggestPredicates(prolog, args);
431
- }, runtime);
432
- addTool(server, "kb_autopilot_generate", toolDef("kb_autopilot_generate").description, toolDef("kb_autopilot_generate").inputSchema, async (args) => {
433
- const prolog = await runtime.ensureProlog();
434
- return runtime.handleKbAutopilotGenerate(prolog, args);
435
- }, runtime);
172
+ registerConfiguredTools(server, runtime, addTool);
436
173
  }