kibi-cursor 0.6.0 → 1.0.1
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/.cursor-plugin/plugin.json +1 -1
- package/CHANGELOG.md +181 -0
- package/README.md +28 -10
- package/agent-plugin/plugin.json +1 -1
- package/agent-plugin/skills/kibi-bootstrap/SKILL.md +58 -0
- package/agent-plugin/skills/kibi-bootstrap/resources/bootstrap.md +11 -0
- package/agent-plugin/skills/kibi-bootstrap/resources/branch-lifecycle.md +7 -0
- package/agent-plugin/skills/kibi-bootstrap/resources/operation-access.md +5 -0
- package/agent-plugin/skills/kibi-bootstrap/resources/source-authoring.md +8 -0
- package/agent-plugin/skills/kibi-freshness/SKILL.md +40 -10
- package/agent-plugin/skills/kibi-freshness/resources/branch-lifecycle.md +7 -0
- package/agent-plugin/skills/kibi-freshness/resources/operation-access.md +6 -0
- package/agent-plugin/skills/kibi-freshness/resources/source-authoring.md +7 -0
- package/agent-plugin/skills/kibi-traceability/SKILL.md +47 -47
- package/agent-plugin/skills/kibi-traceability/resources/branch-lifecycle.md +7 -0
- package/agent-plugin/skills/kibi-traceability/resources/operation-access.md +5 -0
- package/agent-plugin/skills/kibi-traceability/resources/source-authoring.md +6 -0
- package/agent-plugin/skills/kibi-traceability/resources/traceability.md +8 -0
- package/agent-plugin/skills/kibi-usage/SKILL.md +138 -237
- package/agent-plugin/skills/kibi-usage/resources/branch-lifecycle.md +31 -0
- package/agent-plugin/skills/kibi-usage/resources/kb-improvement.md +38 -0
- package/agent-plugin/skills/kibi-usage/resources/operation-access.md +36 -38
- package/agent-plugin/skills/kibi-usage/resources/proof.md +105 -0
- package/agent-plugin/skills/kibi-usage/resources/relationship-directions.md +3 -3
- package/agent-plugin/skills/kibi-usage/resources/source-authoring.md +31 -0
- package/agent-plugin/skills/kibi-usage/resources/workflows.md +57 -4
- package/bin/launch-kibi-mcp.d.mts +18 -0
- package/bin/launch-kibi-mcp.mjs +378 -0
- package/commands/kibi-bootstrap.md +19 -0
- package/dist/.cursor-plugin/plugin.json +1 -1
- package/dist/bin/launch-kibi-mcp.d.mts +18 -0
- package/dist/bin/launch-kibi-mcp.mjs +378 -0
- package/dist/commands/kibi-bootstrap.md +19 -0
- package/dist/hook-input.d.ts +2 -0
- package/dist/hook-input.js +10 -0
- package/dist/hook-runner.js +34 -12
- package/dist/hook-state-storage.js +3 -0
- package/dist/hook-state.d.ts +2 -0
- package/dist/hook-state.js +3 -0
- package/dist/mcp.json +2 -2
- package/dist/messages.js +6 -1
- package/dist/path-policy.js +43 -1
- package/dist/rules/kibi-workflow.mdc +16 -1
- package/dist/skills/.canon-hash.json +22 -7
- package/dist/skills/kibi-bootstrap/SKILL.md +58 -0
- package/dist/skills/kibi-bootstrap/resources/bootstrap.md +11 -0
- package/dist/skills/kibi-bootstrap/resources/branch-lifecycle.md +7 -0
- package/dist/skills/kibi-bootstrap/resources/operation-access.md +5 -0
- package/dist/skills/kibi-bootstrap/resources/source-authoring.md +8 -0
- package/dist/skills/kibi-freshness/SKILL.md +40 -10
- package/dist/skills/kibi-freshness/resources/branch-lifecycle.md +7 -0
- package/dist/skills/kibi-freshness/resources/operation-access.md +6 -0
- package/dist/skills/kibi-freshness/resources/source-authoring.md +7 -0
- package/dist/skills/kibi-traceability/SKILL.md +47 -47
- package/dist/skills/kibi-traceability/resources/branch-lifecycle.md +7 -0
- package/dist/skills/kibi-traceability/resources/operation-access.md +5 -0
- package/dist/skills/kibi-traceability/resources/source-authoring.md +6 -0
- package/dist/skills/kibi-traceability/resources/traceability.md +8 -0
- package/dist/skills/kibi-usage/SKILL.md +138 -237
- package/dist/skills/kibi-usage/resources/branch-lifecycle.md +31 -0
- package/dist/skills/kibi-usage/resources/kb-improvement.md +38 -0
- package/dist/skills/kibi-usage/resources/operation-access.md +36 -38
- package/dist/skills/kibi-usage/resources/proof.md +105 -0
- package/dist/skills/kibi-usage/resources/relationship-directions.md +3 -3
- package/dist/skills/kibi-usage/resources/source-authoring.md +31 -0
- package/dist/skills/kibi-usage/resources/workflows.md +57 -4
- package/mcp.json +2 -2
- package/package.json +4 -3
- package/rules/kibi-workflow.mdc +16 -1
- package/skills/.canon-hash.json +22 -7
- package/skills/kibi-bootstrap/SKILL.md +58 -0
- package/skills/kibi-bootstrap/resources/bootstrap.md +11 -0
- package/skills/kibi-bootstrap/resources/branch-lifecycle.md +7 -0
- package/skills/kibi-bootstrap/resources/operation-access.md +5 -0
- package/skills/kibi-bootstrap/resources/source-authoring.md +8 -0
- package/skills/kibi-freshness/SKILL.md +40 -10
- package/skills/kibi-freshness/resources/branch-lifecycle.md +7 -0
- package/skills/kibi-freshness/resources/operation-access.md +6 -0
- package/skills/kibi-freshness/resources/source-authoring.md +7 -0
- package/skills/kibi-traceability/SKILL.md +47 -47
- package/skills/kibi-traceability/resources/branch-lifecycle.md +7 -0
- package/skills/kibi-traceability/resources/operation-access.md +5 -0
- package/skills/kibi-traceability/resources/source-authoring.md +6 -0
- package/skills/kibi-traceability/resources/traceability.md +8 -0
- package/skills/kibi-usage/SKILL.md +138 -237
- package/skills/kibi-usage/resources/branch-lifecycle.md +31 -0
- package/skills/kibi-usage/resources/kb-improvement.md +38 -0
- package/skills/kibi-usage/resources/operation-access.md +36 -38
- package/skills/kibi-usage/resources/proof.md +105 -0
- package/skills/kibi-usage/resources/relationship-directions.md +3 -3
- package/skills/kibi-usage/resources/source-authoring.md +31 -0
- package/skills/kibi-usage/resources/workflows.md +57 -4
- package/agent-plugin/skills/init-kibi/SKILL.md +0 -62
- package/commands/init-kibi.md +0 -21
- package/dist/commands/init-kibi.md +0 -21
- package/dist/skills/init-kibi/SKILL.md +0 -62
- package/skills/init-kibi/SKILL.md +0 -62
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Consumer-side entrypoint for Cursor's MCP process launcher.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Launch the kibi-mcp package installed by the consumer project.
|
|
9
|
+
*
|
|
10
|
+
* Cursor starts plugin MCP commands with the plugin directory as their cwd.
|
|
11
|
+
* This adapter deliberately knows nothing about the Kibi source tree: it only
|
|
12
|
+
* resolves a consumer workspace, finds that workspace's kibi-mcp package, and
|
|
13
|
+
* runs its declared bin with the consumer as both cwd and KIBI_WORKSPACE.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { spawn } from "node:child_process";
|
|
17
|
+
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
18
|
+
import { createRequire } from "node:module";
|
|
19
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
|
|
22
|
+
const PACKAGE_NAME = "kibi-mcp";
|
|
23
|
+
const PLACEHOLDER_PATTERN = /\$\{[^}]+\}/;
|
|
24
|
+
const SIGNAL_EXIT_CODES = {
|
|
25
|
+
SIGHUP: 129,
|
|
26
|
+
SIGINT: 130,
|
|
27
|
+
SIGTERM: 143,
|
|
28
|
+
SIGBREAK: 148,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function readJson(path) {
|
|
32
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isDirectory(path) {
|
|
36
|
+
try {
|
|
37
|
+
return statSync(path).isDirectory();
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isPlaceholder(value) {
|
|
44
|
+
return PLACEHOLDER_PATTERN.test(value.trim());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function normalizeWorkspacePath(value, baseDirectory) {
|
|
48
|
+
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
49
|
+
if (!trimmed || isPlaceholder(trimmed)) return null;
|
|
50
|
+
const candidate = isAbsolute(trimmed)
|
|
51
|
+
? trimmed
|
|
52
|
+
: resolve(baseDirectory, trimmed);
|
|
53
|
+
return isDirectory(candidate) ? resolve(candidate) : null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Cursor has used both a platform-delimited string and a JSON-like list for
|
|
58
|
+
* workspace-folder environment values. Accept both without treating a
|
|
59
|
+
* literal unresolved placeholder as a path relative to the plugin directory.
|
|
60
|
+
*/
|
|
61
|
+
export function parseWorkspaceFolderPaths(value) {
|
|
62
|
+
if (typeof value !== "string" || !value.trim()) return [];
|
|
63
|
+
const trimmed = value.trim();
|
|
64
|
+
if (trimmed.startsWith("[")) {
|
|
65
|
+
try {
|
|
66
|
+
const parsed = JSON.parse(trimmed);
|
|
67
|
+
if (Array.isArray(parsed)) {
|
|
68
|
+
return parsed.filter((item) => typeof item === "string");
|
|
69
|
+
}
|
|
70
|
+
} catch {
|
|
71
|
+
// Fall through to the platform-delimited form.
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const separator = process.platform === "win32" ? ";" : ":";
|
|
76
|
+
const separated = trimmed.split(separator);
|
|
77
|
+
const values =
|
|
78
|
+
separated.length === 1 && trimmed.includes(",")
|
|
79
|
+
? trimmed.split(",")
|
|
80
|
+
: separated;
|
|
81
|
+
return values
|
|
82
|
+
.flatMap((item) =>
|
|
83
|
+
process.platform === "win32" ? item.split(",") : [item],
|
|
84
|
+
)
|
|
85
|
+
.map((item) => item.trim())
|
|
86
|
+
.filter(Boolean);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function packageJsonForResolvedFile(startPath) {
|
|
90
|
+
let current = resolve(startPath);
|
|
91
|
+
try {
|
|
92
|
+
if (!statSync(current).isDirectory()) current = dirname(current);
|
|
93
|
+
} catch {
|
|
94
|
+
current = dirname(current);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
while (true) {
|
|
98
|
+
const packageJsonPath = join(current, "package.json");
|
|
99
|
+
if (existsSync(packageJsonPath)) {
|
|
100
|
+
try {
|
|
101
|
+
const packageJson = readJson(packageJsonPath);
|
|
102
|
+
if (packageJson.name === PACKAGE_NAME) {
|
|
103
|
+
return { packageJsonPath, packageRoot: current, packageJson };
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
// Keep walking if a parent package manifest is malformed.
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const parent = dirname(current);
|
|
110
|
+
if (parent === current) return null;
|
|
111
|
+
current = parent;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isWithinRoot(rootPath, candidatePath) {
|
|
116
|
+
const relativePath = relative(resolve(rootPath), resolve(candidatePath));
|
|
117
|
+
return (
|
|
118
|
+
relativePath === "" ||
|
|
119
|
+
(!relativePath.startsWith("..") && !isAbsolute(relativePath))
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function hasConsumerNodeModulesLink(workspaceRoot, packageRoot) {
|
|
124
|
+
try {
|
|
125
|
+
const linkPath = join(workspaceRoot, "node_modules", PACKAGE_NAME);
|
|
126
|
+
const linkedRoot = realpathSync(linkPath);
|
|
127
|
+
return (
|
|
128
|
+
isWithinRoot(linkedRoot, packageRoot) ||
|
|
129
|
+
isWithinRoot(packageRoot, linkedRoot)
|
|
130
|
+
);
|
|
131
|
+
} catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function isProjectScopedPackage(workspaceRoot, packageRoot) {
|
|
137
|
+
if (isWithinRoot(workspaceRoot, packageRoot)) return true;
|
|
138
|
+
|
|
139
|
+
// pnpm can expose a package through a symlink whose realpath is outside the
|
|
140
|
+
// workspace. Require that the consumer's node_modules entry points to it;
|
|
141
|
+
// this rejects arbitrary NODE_PATH/global packages while retaining that
|
|
142
|
+
// package-manager layout. Yarn PnP has no node_modules entry, so only its
|
|
143
|
+
// active resolver hook may authorize an out-of-tree package.
|
|
144
|
+
return (
|
|
145
|
+
hasConsumerNodeModulesLink(workspaceRoot, packageRoot) ||
|
|
146
|
+
Boolean(process.versions.pnp)
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Resolve the consumer's package through Node's project-scoped resolver. This
|
|
152
|
+
* works with npm, pnpm, Yarn, and Bun layouts, unlike a hard-coded .bin path.
|
|
153
|
+
*/
|
|
154
|
+
export function resolveProjectLocalMcp(workspaceRoot) {
|
|
155
|
+
const root = resolve(workspaceRoot);
|
|
156
|
+
const consumerRequire = createRequire(join(root, "package.json"));
|
|
157
|
+
let packageInfo;
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
packageInfo = packageJsonForResolvedFile(
|
|
161
|
+
consumerRequire.resolve(`${PACKAGE_NAME}/package.json`),
|
|
162
|
+
);
|
|
163
|
+
} catch {
|
|
164
|
+
try {
|
|
165
|
+
packageInfo = packageJsonForResolvedFile(
|
|
166
|
+
consumerRequire.resolve(PACKAGE_NAME),
|
|
167
|
+
);
|
|
168
|
+
} catch {
|
|
169
|
+
packageInfo = null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!packageInfo) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`[KIBI-CURSOR] No project-local ${PACKAGE_NAME} package was found for ${root}. ` +
|
|
176
|
+
`Install it in that workspace (for example: npm install --save-dev ${PACKAGE_NAME}) and reload Cursor.`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (!isProjectScopedPackage(root, packageInfo.packageRoot)) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`[KIBI-CURSOR] Resolved ${PACKAGE_NAME} outside the consumer workspace: ${packageInfo.packageRoot}. Install it in ${root}; global, plugin-local, and ambient NODE_PATH packages are not supported.`,
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const declaredBin = packageInfo.packageJson.bin;
|
|
187
|
+
const binEntry =
|
|
188
|
+
typeof declaredBin === "string"
|
|
189
|
+
? declaredBin
|
|
190
|
+
: declaredBin && typeof declaredBin === "object"
|
|
191
|
+
? declaredBin[PACKAGE_NAME]
|
|
192
|
+
: undefined;
|
|
193
|
+
if (typeof binEntry !== "string" || !binEntry) {
|
|
194
|
+
throw new Error(
|
|
195
|
+
`[KIBI-CURSOR] Project-local ${PACKAGE_NAME} does not declare a ${PACKAGE_NAME} executable.`,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const binPath = resolve(packageInfo.packageRoot, binEntry);
|
|
200
|
+
if (!existsSync(binPath)) {
|
|
201
|
+
throw new Error(
|
|
202
|
+
`[KIBI-CURSOR] Project-local ${PACKAGE_NAME} declares a missing executable: ${binPath}. Reinstall the workspace dependency and reload Cursor.`,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
packageRoot: packageInfo.packageRoot,
|
|
208
|
+
packageJsonPath: packageInfo.packageJsonPath,
|
|
209
|
+
packageJson: packageInfo.packageJson,
|
|
210
|
+
binPath,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function hasDeclaredProjectDependency(workspaceRoot) {
|
|
215
|
+
const packageJsonPath = join(workspaceRoot, "package.json");
|
|
216
|
+
if (!existsSync(packageJsonPath)) return false;
|
|
217
|
+
try {
|
|
218
|
+
const packageJson = readJson(packageJsonPath);
|
|
219
|
+
return [
|
|
220
|
+
packageJson.dependencies,
|
|
221
|
+
packageJson.devDependencies,
|
|
222
|
+
packageJson.optionalDependencies,
|
|
223
|
+
packageJson.peerDependencies,
|
|
224
|
+
].some((dependencies) =>
|
|
225
|
+
Boolean(
|
|
226
|
+
dependencies &&
|
|
227
|
+
typeof dependencies === "object" &&
|
|
228
|
+
dependencies[PACKAGE_NAME],
|
|
229
|
+
),
|
|
230
|
+
);
|
|
231
|
+
} catch {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function isDemonstrablyProjectWorkspace(workspaceRoot) {
|
|
237
|
+
return (
|
|
238
|
+
existsSync(join(workspaceRoot, ".git")) ||
|
|
239
|
+
existsSync(join(workspaceRoot, ".kb")) ||
|
|
240
|
+
hasDeclaredProjectDependency(workspaceRoot)
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function usableWorkspaceCandidates(values, baseDirectory) {
|
|
245
|
+
return values
|
|
246
|
+
.map((value) => normalizeWorkspacePath(value, baseDirectory))
|
|
247
|
+
.filter((value, index, all) => value && all.indexOf(value) === index)
|
|
248
|
+
.filter((value) => {
|
|
249
|
+
try {
|
|
250
|
+
resolveProjectLocalMcp(value);
|
|
251
|
+
return true;
|
|
252
|
+
} catch {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function chooseSingleWorkspace(candidates, source) {
|
|
259
|
+
if (candidates.length > 1) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
`[KIBI-CURSOR] ${source} names multiple workspaces with project-local ${PACKAGE_NAME}: ${candidates.join(", ")}. Open a single-root workspace or set KIBI_WORKSPACE to one root.`,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
return candidates[0];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Resolve the consumer workspace without ever defaulting to the plugin root. */
|
|
268
|
+
export function resolveWorkspaceRoot(explicitWorkspace, options = {}) {
|
|
269
|
+
const cwd = resolve(options.cwd ?? process.cwd());
|
|
270
|
+
const env = options.env ?? process.env;
|
|
271
|
+
|
|
272
|
+
if (typeof explicitWorkspace === "string" && explicitWorkspace.trim()) {
|
|
273
|
+
const explicit = normalizeWorkspacePath(explicitWorkspace, cwd);
|
|
274
|
+
// Cursor can leave ${workspaceFolder} unresolved. It is invalid, so allow
|
|
275
|
+
// the environment fallbacks below rather than resolving it under cwd.
|
|
276
|
+
if (explicit) return explicit;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const folderCandidates = chooseSingleWorkspace(
|
|
280
|
+
usableWorkspaceCandidates(
|
|
281
|
+
parseWorkspaceFolderPaths(env.WORKSPACE_FOLDER_PATHS),
|
|
282
|
+
cwd,
|
|
283
|
+
),
|
|
284
|
+
"WORKSPACE_FOLDER_PATHS",
|
|
285
|
+
);
|
|
286
|
+
if (folderCandidates) return folderCandidates;
|
|
287
|
+
|
|
288
|
+
for (const name of ["KIBI_WORKSPACE", "CURSOR_WORKSPACE"]) {
|
|
289
|
+
const candidate = chooseSingleWorkspace(
|
|
290
|
+
usableWorkspaceCandidates([env[name]], cwd),
|
|
291
|
+
name,
|
|
292
|
+
);
|
|
293
|
+
if (candidate) return candidate;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// A plugin installation is commonly the current cwd. Only use it when
|
|
297
|
+
// project markers make it demonstrably a consumer project and its local
|
|
298
|
+
// package can be resolved; never use an ambient/plugin-local package merely
|
|
299
|
+
// because it happens to be on disk.
|
|
300
|
+
if (isDemonstrablyProjectWorkspace(cwd)) {
|
|
301
|
+
try {
|
|
302
|
+
resolveProjectLocalMcp(cwd);
|
|
303
|
+
return cwd;
|
|
304
|
+
} catch {
|
|
305
|
+
// Continue to the actionable error below.
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
throw new Error(
|
|
310
|
+
`[KIBI-CURSOR] Unable to determine a consumer workspace. Cursor must provide \${workspaceFolder}, WORKSPACE_FOLDER_PATHS, KIBI_WORKSPACE, or CURSOR_WORKSPACE; the selected workspace must contain project-local ${PACKAGE_NAME}.`,
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function signalExitCode(signal) {
|
|
315
|
+
return SIGNAL_EXIT_CODES[signal] ?? 1;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** Spawn the project-local MCP server and mirror its transport and exit state. */
|
|
319
|
+
export function launchKibiMcp(argv = process.argv.slice(2), env = process.env) {
|
|
320
|
+
const [explicitWorkspace, ...childArgs] = argv;
|
|
321
|
+
let workspaceRoot;
|
|
322
|
+
let projectLocal;
|
|
323
|
+
try {
|
|
324
|
+
workspaceRoot = resolveWorkspaceRoot(explicitWorkspace, {
|
|
325
|
+
cwd: process.cwd(),
|
|
326
|
+
env,
|
|
327
|
+
});
|
|
328
|
+
projectLocal = resolveProjectLocalMcp(workspaceRoot);
|
|
329
|
+
} catch (error) {
|
|
330
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
331
|
+
process.stderr.write(`${message}\n`);
|
|
332
|
+
return Promise.resolve(1);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const child = spawn(process.execPath, [projectLocal.binPath, ...childArgs], {
|
|
336
|
+
cwd: workspaceRoot,
|
|
337
|
+
env: { ...env, KIBI_WORKSPACE: workspaceRoot },
|
|
338
|
+
stdio: ["inherit", "inherit", "inherit"],
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
return new Promise((resolveExit) => {
|
|
342
|
+
let finished = false;
|
|
343
|
+
const signalHandlers = new Map();
|
|
344
|
+
const finish = (exitCode) => {
|
|
345
|
+
if (finished) return;
|
|
346
|
+
finished = true;
|
|
347
|
+
for (const [signal, handler] of signalHandlers) {
|
|
348
|
+
process.removeListener(signal, handler);
|
|
349
|
+
}
|
|
350
|
+
resolveExit(exitCode);
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
for (const signal of ["SIGHUP", "SIGINT", "SIGTERM", "SIGBREAK"]) {
|
|
354
|
+
if (process.platform === "win32" && signal !== "SIGBREAK") continue;
|
|
355
|
+
const handler = () => {
|
|
356
|
+
if (!child.killed) child.kill(signal);
|
|
357
|
+
};
|
|
358
|
+
signalHandlers.set(signal, handler);
|
|
359
|
+
process.once(signal, handler);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
child.once("error", (error) => {
|
|
363
|
+
process.stderr.write(
|
|
364
|
+
`[KIBI-CURSOR] Failed to start project-local ${PACKAGE_NAME}: ${error.message}\n`,
|
|
365
|
+
);
|
|
366
|
+
finish(1);
|
|
367
|
+
});
|
|
368
|
+
child.once("close", (code, signal) => {
|
|
369
|
+
finish(signal ? signalExitCode(signal) : (code ?? 1));
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const entrypoint = process.argv[1] ? resolve(process.argv[1]) : undefined;
|
|
375
|
+
if (entrypoint === resolve(fileURLToPath(import.meta.url))) {
|
|
376
|
+
const exitCode = await launchKibiMcp(process.argv.slice(2));
|
|
377
|
+
process.exitCode = exitCode;
|
|
378
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kibi-bootstrap
|
|
3
|
+
description: Bootstrap Kibi knowledge for an existing repository
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Kibi bootstrap
|
|
7
|
+
|
|
8
|
+
Route an explicit bootstrap request to the canonical `kibi-bootstrap` skill.
|
|
9
|
+
|
|
10
|
+
## Route
|
|
11
|
+
|
|
12
|
+
Inspect `kb_status.bootstrap` and follow its typed `nextAction`. If Kibi
|
|
13
|
+
infrastructure is missing, run `kibi init` first. Then use the canonical
|
|
14
|
+
planner and pass its unchanged returned `structuredContent.plan` to
|
|
15
|
+
`kb_apply_plan` only after explicit approval.
|
|
16
|
+
|
|
17
|
+
Questions come only from a `needs_context` planner result. Inspect typed apply
|
|
18
|
+
`nextActions`, finish with `kb_check` and `kb_status`, and never read or edit
|
|
19
|
+
`.kb` directly.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-cursor",
|
|
3
3
|
"displayName": "Kibi",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"description": "Optional Cursor adapter for Kibi. Requires SWI-Prolog 9+ and project-local kibi-cli, kibi-mcp, and kibi-core before the bundled MCP server can start.",
|
|
6
6
|
"license": "AGPL-3.0-or-later",
|
|
7
7
|
"author": {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function parseWorkspaceFolderPaths(value: unknown): string[];
|
|
2
|
+
|
|
3
|
+
export function resolveProjectLocalMcp(workspaceRoot: string): {
|
|
4
|
+
packageRoot: string;
|
|
5
|
+
packageJsonPath: string;
|
|
6
|
+
packageJson: Record<string, unknown>;
|
|
7
|
+
binPath: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function resolveWorkspaceRoot(
|
|
11
|
+
explicitWorkspace?: string,
|
|
12
|
+
options?: { cwd?: string; env?: NodeJS.ProcessEnv },
|
|
13
|
+
): string;
|
|
14
|
+
|
|
15
|
+
export function launchKibiMcp(
|
|
16
|
+
argv?: string[],
|
|
17
|
+
env?: NodeJS.ProcessEnv,
|
|
18
|
+
): Promise<number>;
|