kibi-mcp 3.16.0 → 3.16.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.
- package/bin/kibi-mcp +11 -0
- package/dist/diagnostics-helpers.js +8 -5
- package/dist/tools/symbols.js +10 -10
- package/dist/workspace-path.js +69 -0
- package/package.json +4 -4
package/bin/kibi-mcp
CHANGED
|
@@ -16,6 +16,17 @@
|
|
|
16
16
|
You should have received a copy of the GNU Affero General Public License
|
|
17
17
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
18
|
*/
|
|
19
|
+
// Kibi needs Node.js 22+ (package "engines"), but npm only warns on a
|
|
20
|
+
// mismatch. Fail before loading anything, with the Node that was found.
|
|
21
|
+
const nodeMajor = Number(process.versions.node.split(".")[0]);
|
|
22
|
+
if (!globalThis.Bun && nodeMajor < 22) {
|
|
23
|
+
process.stderr.write(
|
|
24
|
+
`kibi-mcp requires Node.js 22 or later, but was started with Node.js ${process.versions.node} (${process.execPath}). ` +
|
|
25
|
+
"Put Node.js 22+ first on PATH, including for the host that launches it, and retry.\n",
|
|
26
|
+
);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
19
30
|
const args = globalThis.Bun?.argv?.slice(2) ?? process.argv.slice(2);
|
|
20
31
|
|
|
21
32
|
async function importStartupResolution() {
|
|
@@ -132,11 +132,14 @@ export function buildDiagnosticToolCall(input) {
|
|
|
132
132
|
business_args: payload.businessArgs,
|
|
133
133
|
raw_args_redacted: redactDiagnosticArgs(input.args),
|
|
134
134
|
retry_key: deriveDiagnosticRetryKey(input.tool, input.args),
|
|
135
|
-
hint
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
// A successful call has no error to explain, so it carries no hint.
|
|
136
|
+
hint: input.error
|
|
137
|
+
? deriveDiagnosticHints({
|
|
138
|
+
tool: input.tool,
|
|
139
|
+
error: input.error,
|
|
140
|
+
businessArgs: payload.businessArgs,
|
|
141
|
+
})
|
|
142
|
+
: "",
|
|
140
143
|
diagnostic_error: diagnosticError,
|
|
141
144
|
diagnostic_telemetry: input.telemetry ?? payload.telemetry,
|
|
142
145
|
};
|
package/dist/tools/symbols.js
CHANGED
|
@@ -20,6 +20,7 @@ import { access, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
|
20
20
|
import path from "node:path";
|
|
21
21
|
import { dump as dumpYAML, load as parseYAML } from "js-yaml";
|
|
22
22
|
import { enrichSymbolCoordinates, withSymbolCompilerLock, } from "kibi-runtime";
|
|
23
|
+
import { resolveWorkspaceSourceAbsolute } from "../workspace-path.js";
|
|
23
24
|
import { resolveWorkspaceRoot } from "../workspace.js";
|
|
24
25
|
const SYMBOL_COORDINATES_FORMAT_VERSION = 2;
|
|
25
26
|
const SYMBOL_COORDINATES_COMMENT_BLOCK = `# symbol-coordinates.yaml
|
|
@@ -214,10 +215,8 @@ function hasGeneratedCoordinates(entry) {
|
|
|
214
215
|
async function isEligible(sourceFile, workspaceRoot) {
|
|
215
216
|
if (!sourceFile)
|
|
216
217
|
return false;
|
|
217
|
-
const absolute =
|
|
218
|
-
|
|
219
|
-
: path.resolve(workspaceRoot, sourceFile);
|
|
220
|
-
if (!(await fileExists(absolute)))
|
|
218
|
+
const absolute = resolveWorkspaceSourceAbsolute(workspaceRoot, sourceFile);
|
|
219
|
+
if (absolute === null || !(await fileExists(absolute)))
|
|
221
220
|
return false;
|
|
222
221
|
return SOURCE_EXTENSIONS.has(path.extname(absolute).toLowerCase());
|
|
223
222
|
}
|
|
@@ -253,9 +252,10 @@ async function fillMissingCoordinates(before, after, workspaceRoot) {
|
|
|
253
252
|
if (!sourceFile) {
|
|
254
253
|
return after;
|
|
255
254
|
}
|
|
256
|
-
const absolutePath =
|
|
257
|
-
|
|
258
|
-
|
|
255
|
+
const absolutePath = resolveWorkspaceSourceAbsolute(workspaceRoot, sourceFile);
|
|
256
|
+
if (absolutePath === null) {
|
|
257
|
+
return after;
|
|
258
|
+
}
|
|
259
259
|
try {
|
|
260
260
|
const content = await readFile(absolutePath, "utf8");
|
|
261
261
|
const lines = content.split(/\r?\n/);
|
|
@@ -357,9 +357,9 @@ function coordinateSourceHash(sourceText) {
|
|
|
357
357
|
return createHash("sha256").update(sourceText).digest("hex");
|
|
358
358
|
}
|
|
359
359
|
async function readSourceText(sourceFile, workspaceRoot) {
|
|
360
|
-
const absolutePath =
|
|
361
|
-
|
|
362
|
-
|
|
360
|
+
const absolutePath = resolveWorkspaceSourceAbsolute(workspaceRoot, sourceFile);
|
|
361
|
+
if (absolutePath === null)
|
|
362
|
+
return null;
|
|
363
363
|
try {
|
|
364
364
|
return await readFile(absolutePath, "utf8");
|
|
365
365
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import { realpathSync } from "node:fs";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
/**
|
|
21
|
+
* Canonical repository-relative form of a recorded path. Returns null when the
|
|
22
|
+
* candidate escapes `workspaceRoot` (absolute foreign path, `..` segment).
|
|
23
|
+
* Kept in lockstep with packages/cli/src/utils/repo-relative-path.ts.
|
|
24
|
+
*/
|
|
25
|
+
export function normalizeRepoRelativePath(workspaceRoot, candidate) {
|
|
26
|
+
if (candidate.trim() === "")
|
|
27
|
+
return null;
|
|
28
|
+
let slashed = candidate.replaceAll("\\", "/");
|
|
29
|
+
const foreignAbsolute = /^[A-Za-z]:\//.test(slashed) || slashed.startsWith("//");
|
|
30
|
+
if (slashed.startsWith("/") || foreignAbsolute) {
|
|
31
|
+
if (foreignAbsolute && path.sep === "/")
|
|
32
|
+
return null;
|
|
33
|
+
const root = path.resolve(workspaceRoot);
|
|
34
|
+
const relative = path.relative(root, path.resolve(candidate));
|
|
35
|
+
if (relative === "" || path.isAbsolute(relative))
|
|
36
|
+
return null;
|
|
37
|
+
slashed = relative.replaceAll("\\", "/");
|
|
38
|
+
}
|
|
39
|
+
const normalized = path.posix.normalize(slashed).replace(/\/+$/, "");
|
|
40
|
+
if (normalized === "" ||
|
|
41
|
+
normalized === "." ||
|
|
42
|
+
normalized === ".." ||
|
|
43
|
+
normalized.startsWith("../")) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return normalized;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve a recorded source path to an absolute path confined under
|
|
50
|
+
* `workspaceRoot`. Returns null for escapes; callers must not read on null.
|
|
51
|
+
*/
|
|
52
|
+
// implements REQ-symbol-sourcefile-workspace-confinement
|
|
53
|
+
export function resolveWorkspaceSourceAbsolute(workspaceRoot, sourceFile) {
|
|
54
|
+
const relative = normalizeRepoRelativePath(workspaceRoot, sourceFile);
|
|
55
|
+
if (relative === null)
|
|
56
|
+
return null;
|
|
57
|
+
const absolute = path.resolve(workspaceRoot, relative);
|
|
58
|
+
try {
|
|
59
|
+
const realRoot = realpathSync.native(path.resolve(workspaceRoot));
|
|
60
|
+
const realFile = realpathSync.native(absolute);
|
|
61
|
+
const confined = path.relative(realRoot, realFile);
|
|
62
|
+
if (confined.startsWith("..") || path.isAbsolute(confined))
|
|
63
|
+
return null;
|
|
64
|
+
return realFile;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return absolute;
|
|
68
|
+
}
|
|
69
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-mcp",
|
|
3
|
-
"version": "3.16.
|
|
3
|
+
"version": "3.16.2",
|
|
4
4
|
"mcpName": "io.github.Looted/kibi-mcp",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
"fast-glob": "^3.2.12",
|
|
11
11
|
"gray-matter": "^4.0.3",
|
|
12
12
|
"js-yaml": "^4.1.0",
|
|
13
|
-
"kibi-runtime": "^2.18.
|
|
14
|
-
"kibi-core": "^0.22.
|
|
15
|
-
"zod": "^4.
|
|
13
|
+
"kibi-runtime": "^2.18.2",
|
|
14
|
+
"kibi-core": "^0.22.4",
|
|
15
|
+
"zod": "^4.6.7"
|
|
16
16
|
},
|
|
17
17
|
"type": "module",
|
|
18
18
|
"description": "Model Context Protocol server for Kibi knowledge base",
|