kibi-mcp 0.19.0 → 0.19.2

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 (36) hide show
  1. package/bin/kibi-mcp +1 -1
  2. package/dist/runtime/mcp-runtime.js +43 -0
  3. package/dist/server/docs.js +4 -4
  4. package/dist/server/json-schema-to-zod.js +73 -2
  5. package/dist/server/session.js +33 -15
  6. package/dist/server/tool-registration.js +35 -62
  7. package/dist/server/tools-runtime.js +52 -2
  8. package/dist/server/tools.js +19 -5
  9. package/dist/server/transport.js +9 -5
  10. package/dist/tools/autopilot-generate.js +37 -646
  11. package/dist/tools/autopilot-test-compat.js +88 -0
  12. package/dist/tools/autopilot-test-parsers.js +120 -0
  13. package/dist/tools/check.js +13 -106
  14. package/dist/tools/coverage.js +11 -25
  15. package/dist/tools/delete.js +5 -112
  16. package/dist/tools/discovery-adapter.js +23 -0
  17. package/dist/tools/entity-query.js +1 -111
  18. package/dist/tools/find-gaps.js +11 -26
  19. package/dist/tools/graph.js +11 -24
  20. package/dist/tools/model-requirement.js +8 -347
  21. package/dist/tools/mutation-context.js +28 -0
  22. package/dist/tools/query.js +5 -50
  23. package/dist/tools/relationship-validation.js +9 -116
  24. package/dist/tools/search.js +4 -37
  25. package/dist/tools/semantic-advisor.js +2 -40
  26. package/dist/tools/skills.js +17 -57
  27. package/dist/tools/sparql.js +12 -93
  28. package/dist/tools/status.js +5 -19
  29. package/dist/tools/suggest-predicates.js +11 -2448
  30. package/dist/tools/upsert.js +21 -816
  31. package/dist/tools/validate-upsert.js +12 -48
  32. package/dist/tools-config.js +75 -802
  33. package/package.json +4 -3
  34. package/dist/semantic-advisor/analyze-prose.js +0 -1392
  35. package/dist/semantic-advisor/prose-coverage-evaluator.js +0 -66
  36. package/dist/semantic-advisor/types.js +0 -1
@@ -1,42 +1,4 @@
1
- import { analyzeSemanticAdvisorInput } from "../semantic-advisor/analyze-prose.js";
2
- function normalizeText(value) {
3
- const text = typeof value === "string" ? value.trim() : "";
4
- if (!text) {
5
- throw new Error("Semantic advisor failed: text must be a non-empty string");
6
- }
7
- return text;
8
- }
9
- function optionalString(value) {
10
- const text = typeof value === "string" ? value.trim() : "";
11
- return text.length > 0 ? text : undefined;
12
- }
1
+ import { executeSemanticAdvisor } from "kibi-cli/operations";
13
2
  export async function handleKbSemanticAdvisor(args) {
14
- const text = normalizeText(args.text);
15
- const id = optionalString(args.id) ?? "REQ-SEMANTIC-ADVISOR-PREVIEW";
16
- const title = optionalString(args.title) ?? text.split(/[.!?]/, 1)[0] ?? text;
17
- const source = optionalString(args.source) ?? "mcp://kibi/semantic-advisor";
18
- const result = analyzeSemanticAdvisorInput({
19
- payload: {
20
- type: optionalString(args.type) ?? "req",
21
- id,
22
- properties: {
23
- title,
24
- status: optionalString(args.status) ?? "open",
25
- source,
26
- text_ref: text,
27
- },
28
- },
29
- });
30
- return {
31
- content: [
32
- {
33
- type: "text",
34
- text: `kb_semantic_advisor: ${result.receipt.summary} Suggestions: ${result.receipt.suggestions.map((suggestion) => suggestion.kind).join(", ") || "none"}.`,
35
- },
36
- ],
37
- structuredContent: {
38
- receipt: result.receipt,
39
- warnings: result.warnings,
40
- },
41
- };
3
+ return executeSemanticAdvisor(args);
42
4
  }
@@ -1,16 +1,16 @@
1
- import { createHash } from "node:crypto";
2
- import { listBundledSkills, loadBundledSkill, readBundledSkillResource, } from "kibi-cli/skills";
1
+ import { skillsListSpec, skillsLoadSpec, skillsReadSpec, } from "kibi-cli/operations";
2
+ import { loadBundledSkill } from "kibi-cli/skills";
3
+ function runtimeContext() {
4
+ return {
5
+ workspaceRoot: process.cwd(),
6
+ signal: new AbortController().signal,
7
+ clock: () => new Date(),
8
+ };
9
+ }
3
10
  // implements REQ-001
4
11
  export async function handleKbSkillsList(_args) {
5
12
  try {
6
- const skills = listBundledSkills();
7
- const ids = skills.map((skill) => skill.id).join(", ") || "none";
8
- return {
9
- content: [
10
- { type: "text", text: `Found ${skills.length} bundled skills: ${ids}` },
11
- ],
12
- structuredContent: { skills },
13
- };
13
+ return await skillsListSpec.execute({}, runtimeContext());
14
14
  }
15
15
  catch (error) {
16
16
  const message = error instanceof Error ? error.message : String(error);
@@ -20,27 +20,7 @@ export async function handleKbSkillsList(_args) {
20
20
  // implements REQ-001
21
21
  export async function handleKbSkillsLoad(args) {
22
22
  try {
23
- assertNonEmptyString(args.id, "id");
24
- const bundle = loadBundledSkill(args.id);
25
- const resources = bundle.manifest.resources ?? [];
26
- const payload = {
27
- metadata: bundle.manifest,
28
- body: bundle.body,
29
- resources,
30
- contentHash: createHash("sha256")
31
- .update(bundle.body, "utf8")
32
- .digest("hex"),
33
- sourceType: "bundled",
34
- };
35
- return {
36
- content: [
37
- {
38
- type: "text",
39
- text: `Loaded bundled skill ${bundle.manifest.id} with ${resources.length} resources: ${formatResourceList(resources)}`,
40
- },
41
- ],
42
- structuredContent: payload,
43
- };
23
+ return await skillsLoadSpec.execute(args, runtimeContext());
44
24
  }
45
25
  catch (error) {
46
26
  const message = error instanceof Error ? error.message : String(error);
@@ -50,44 +30,24 @@ export async function handleKbSkillsLoad(args) {
50
30
  // implements REQ-001
51
31
  export async function handleKbSkillsRead(args) {
52
32
  try {
53
- assertNonEmptyString(args.id, "id");
54
- assertNonEmptyString(args.resource, "resource");
55
- const resourceContent = readBundledSkillResource(args.id, args.resource);
56
- return {
57
- content: [
58
- {
59
- type: "text",
60
- text: `Read bundled skill resource ${args.id}/${args.resource}`,
61
- },
62
- ],
63
- structuredContent: { content: resourceContent },
64
- };
33
+ return await skillsReadSpec.execute(args, runtimeContext());
65
34
  }
66
35
  catch (error) {
67
36
  const message = error instanceof Error ? error.message : String(error);
68
37
  throw new Error(`Skills read failed: ${message}${resourceListHint(args.id)}`);
69
38
  }
70
39
  }
71
- function formatResourceList(resources) {
72
- return resources.length === 0 ? "none" : resources.join(", ");
73
- }
74
40
  function resourceListHint(id) {
75
41
  if (typeof id !== "string" || id.trim() === "") {
76
42
  return "";
77
43
  }
78
44
  try {
79
45
  const bundle = loadBundledSkill(id);
80
- return `. Declared resources: ${formatResourceList(bundle.manifest.resources ?? [])}`;
81
- }
82
- catch (error) {
83
- if (error instanceof Error) {
84
- return "";
85
- }
86
- throw error;
46
+ const resources = bundle.manifest.resources ?? [];
47
+ const resourceList = resources.length === 0 ? "none" : resources.join(", ");
48
+ return `. Declared resources: ${resourceList}`;
87
49
  }
88
- }
89
- function assertNonEmptyString(value, field) {
90
- if (typeof value !== "string" || value.trim() === "") {
91
- throw new Error(`${field} must be a non-empty string`);
50
+ catch {
51
+ return "";
92
52
  }
93
53
  }
@@ -1,96 +1,15 @@
1
- import { runJsonModuleQuery, toPrologAtom } from "./core-module.js";
2
- // implements REQ-002, REQ-013
3
- export async function handleSparql(prolog, args) {
4
- validateSparqlArgs(args);
5
- try {
6
- const payload = await runJsonModuleQuery(prolog, "sparql_client.pl", `kibi_sparql_client:remote_sparql_select_json(${toPrologAtom(args.endpoint)}, ${toPrologAtom(args.query)}, ${toSparqlOptions(args)}, JsonString)`, "SPARQL remote query");
7
- const rows = payload?.rows ?? [];
8
- return {
9
- content: [
10
- {
11
- type: "text",
12
- text: `Remote SPARQL query returned ${rows.length} row${rows.length === 1 ? "" : "s"}.`,
13
- },
14
- ],
15
- ...(payload !== undefined ? { structuredContent: payload } : {}),
16
- };
17
- }
18
- catch (error) {
19
- const message = error instanceof Error ? error.message : String(error);
20
- throw new Error(`SPARQL remote query failed: ${message}`);
21
- }
22
- }
23
- function validateSparqlArgs(args) {
24
- if (!args.endpoint || args.endpoint.trim().length === 0) {
1
+ import { sparqlRemoteSpec } from "kibi-cli/operations";
2
+ // implements REQ-002, REQ-013, REQ-kibi-operation-interface-parity
3
+ export async function handleSparql(prologOrArgs, legacyArgs) {
4
+ const args = legacyArgs ?? ("endpoint" in prologOrArgs ? prologOrArgs : undefined);
5
+ if (args === undefined) {
25
6
  throw new Error("SPARQL endpoint is required");
26
7
  }
27
- if (!args.query || args.query.trim().length === 0) {
28
- throw new Error("SPARQL query is required");
29
- }
30
- if (!isRemoteHttpEndpoint(args.endpoint)) {
31
- throw new Error("SPARQL endpoint must be an http:// or https:// URL");
32
- }
33
- if (!isSelectQuery(args.query)) {
34
- throw new Error("SPARQL query must be a SELECT query");
35
- }
36
- if (!isPublicRemoteEndpoint(args.endpoint)) {
37
- throw new Error("SPARQL endpoint must target a public remote host");
38
- }
39
- if (args.timeoutMs !== undefined &&
40
- (!Number.isFinite(args.timeoutMs) || args.timeoutMs <= 0)) {
41
- throw new Error("SPARQL timeoutMs must be a positive number when provided");
42
- }
43
- }
44
- function isRemoteHttpEndpoint(endpoint) {
45
- try {
46
- const url = new URL(endpoint);
47
- return url.protocol === "http:" || url.protocol === "https:";
48
- }
49
- catch {
50
- return false;
51
- }
52
- }
53
- function isSelectQuery(query) {
54
- return /^\s*select\b/i.test(query);
55
- }
56
- function isPublicRemoteEndpoint(endpoint) {
57
- const url = new URL(endpoint);
58
- const host = normalizeHostname(url.hostname);
59
- return !isLocalOrPrivateHost(host);
60
- }
61
- function normalizeHostname(hostname) {
62
- return hostname
63
- .toLowerCase()
64
- .replace(/^\[/, "")
65
- .replace(/\]$/, "")
66
- .replace(/\.$/, "");
67
- }
68
- function isLocalOrPrivateHost(host) {
69
- if (host === "localhost" ||
70
- host.endsWith(".localhost") ||
71
- host === "0.0.0.0" ||
72
- host === "::1" ||
73
- (host.includes(":") &&
74
- (host.startsWith("fe80:") ||
75
- host.startsWith("fc") ||
76
- host.startsWith("fd")))) {
77
- return true;
78
- }
79
- const octets = host.split(".").map((part) => Number(part));
80
- if (octets.length !== 4 || octets.some((octet) => !Number.isInteger(octet))) {
81
- return false;
82
- }
83
- const [first = -1, second = -1] = octets;
84
- return (first === 10 ||
85
- first === 127 ||
86
- (first === 169 && second === 254) ||
87
- (first === 172 && second >= 16 && second <= 31) ||
88
- (first === 192 && second === 168));
89
- }
90
- function toSparqlOptions(args) {
91
- if (args.timeoutMs === undefined) {
92
- return "[]";
93
- }
94
- const timeoutSeconds = Math.max(1, Math.ceil(args.timeoutMs / 1000));
95
- return `[timeout(${timeoutSeconds})]`;
8
+ const context = {
9
+ workspaceRoot: process.cwd(),
10
+ signal: new AbortController().signal,
11
+ clock: () => new Date(),
12
+ net: { fetch: (input, init) => globalThis.fetch(input, init) },
13
+ };
14
+ return sparqlRemoteSpec.execute(args, context);
96
15
  }
@@ -1,20 +1,6 @@
1
- import { runJsonModuleQuery } from "./core-module.js";
2
- // implements REQ-002, REQ-013
3
- export async function handleKbStatus(prolog, _args) {
4
- try {
5
- const payload = await runJsonModuleQuery(prolog, "status.pl", "status:kb_status_json(JsonString)", "Status execution");
6
- return {
7
- content: [
8
- {
9
- type: "text",
10
- text: `Branch ${payload.branch} is ${payload.syncState} (snapshot ${payload.snapshotId}, dirty=${payload.dirty})`,
11
- },
12
- ],
13
- structuredContent: payload,
14
- };
15
- }
16
- catch (error) {
17
- const message = error instanceof Error ? error.message : String(error);
18
- throw new Error(`Status execution failed: ${message}`);
19
- }
1
+ import { statusSpec } from "kibi-cli/operations";
2
+ import { createDiscoveryContext } from "./discovery-adapter.js";
3
+ export async function handleKbStatus(prolog, args) {
4
+ // implements REQ-kibi-operation-interface-parity
5
+ return statusSpec.execute(args, createDiscoveryContext(prolog));
20
6
  }