karajan-code 1.27.0 → 1.27.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/package.json +1 -1
- package/src/mcp/run-kj.js +5 -2
- package/src/mcp/server-handlers.js +32 -15
- package/src/mcp/tools.js +9 -0
package/package.json
CHANGED
package/src/mcp/run-kj.js
CHANGED
|
@@ -76,11 +76,14 @@ export async function runKjCommand({ command, commandArgs = [], options = {}, en
|
|
|
76
76
|
|
|
77
77
|
const timeout = options.timeoutMs ? Number(options.timeoutMs) : undefined;
|
|
78
78
|
|
|
79
|
-
const
|
|
79
|
+
const execOpts = {
|
|
80
80
|
env: runEnv,
|
|
81
81
|
reject: false,
|
|
82
82
|
timeout
|
|
83
|
-
}
|
|
83
|
+
};
|
|
84
|
+
if (options.projectDir) execOpts.cwd = options.projectDir;
|
|
85
|
+
|
|
86
|
+
const result = await execa("node", args, execOpts);
|
|
84
87
|
|
|
85
88
|
const ok = result.exitCode === 0;
|
|
86
89
|
const payload = {
|
|
@@ -25,20 +25,37 @@ import { currentBranch } from "../utils/git.js";
|
|
|
25
25
|
import { isPreflightAcked, ackPreflight, getSessionOverrides } from "./preflight.js";
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Resolve the user's project directory
|
|
29
|
-
*
|
|
28
|
+
* Resolve the user's project directory.
|
|
29
|
+
* Priority: 1) explicit projectDir param, 2) MCP roots, 3) error with instructions.
|
|
30
30
|
*/
|
|
31
|
-
async function resolveProjectDir(server) {
|
|
31
|
+
async function resolveProjectDir(server, explicitProjectDir) {
|
|
32
|
+
// 1. Explicit projectDir from tool parameter — always wins
|
|
33
|
+
if (explicitProjectDir) return explicitProjectDir;
|
|
34
|
+
|
|
35
|
+
// 2. MCP roots (host-provided workspace directory)
|
|
32
36
|
try {
|
|
33
37
|
const { roots } = await server.listRoots();
|
|
34
38
|
if (roots?.length > 0) {
|
|
35
39
|
const uri = roots[0].uri;
|
|
36
|
-
// MCP roots use file:// URIs
|
|
37
40
|
if (uri.startsWith("file://")) return new URL(uri).pathname;
|
|
38
41
|
return uri;
|
|
39
42
|
}
|
|
40
43
|
} catch { /* client may not support roots */ }
|
|
41
|
-
|
|
44
|
+
|
|
45
|
+
// 3. Check if process.cwd() looks like a real project (has package.json or .git)
|
|
46
|
+
const cwd = process.cwd();
|
|
47
|
+
try {
|
|
48
|
+
const hasGit = await fs.access(`${cwd}/.git`).then(() => true).catch(() => false);
|
|
49
|
+
const hasPkg = await fs.access(`${cwd}/package.json`).then(() => true).catch(() => false);
|
|
50
|
+
if (hasGit || hasPkg) return cwd;
|
|
51
|
+
} catch { /* ignore */ }
|
|
52
|
+
|
|
53
|
+
// 4. No valid project directory — fail with clear instructions
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Cannot determine project directory. The MCP server is running from "${cwd}" which does not appear to be your project. ` +
|
|
56
|
+
`Fix: pass the "projectDir" parameter with the absolute path to your project (e.g., projectDir: "/home/user/my-project"), ` +
|
|
57
|
+
`or run "kj init" inside your project directory.`
|
|
58
|
+
);
|
|
42
59
|
}
|
|
43
60
|
|
|
44
61
|
export function asObject(value) {
|
|
@@ -260,7 +277,7 @@ export async function handleRunDirect(a, server, extra) {
|
|
|
260
277
|
if (config.pipeline?.security?.enabled) requiredProviders.push(resolveRole(config, "security").provider);
|
|
261
278
|
await assertAgentsAvailable(requiredProviders);
|
|
262
279
|
|
|
263
|
-
const projectDir = await resolveProjectDir(server);
|
|
280
|
+
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
264
281
|
const runLog = createRunLog(projectDir);
|
|
265
282
|
runLog.logText(`[kj_run] started — task="${a.task.slice(0, 80)}..."`);
|
|
266
283
|
|
|
@@ -293,7 +310,7 @@ export async function handleResumeDirect(a, server, extra) {
|
|
|
293
310
|
const config = await buildConfig(a);
|
|
294
311
|
const logger = createLogger(config.output.log_level, "mcp");
|
|
295
312
|
|
|
296
|
-
const projectDir = await resolveProjectDir(server);
|
|
313
|
+
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
297
314
|
const runLog = createRunLog(projectDir);
|
|
298
315
|
runLog.logText(`[kj_resume] started — session="${a.sessionId}"`);
|
|
299
316
|
|
|
@@ -349,7 +366,7 @@ export async function handlePlanDirect(a, server, extra) {
|
|
|
349
366
|
const plannerRole = resolveRole(config, "planner");
|
|
350
367
|
await assertAgentsAvailable([plannerRole.provider]);
|
|
351
368
|
|
|
352
|
-
const projectDir = await resolveProjectDir(server);
|
|
369
|
+
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
353
370
|
const runLog = createRunLog(projectDir);
|
|
354
371
|
const silenceTimeoutMs = Number(config?.session?.max_agent_silence_minutes) > 0
|
|
355
372
|
? Math.round(Number(config.session.max_agent_silence_minutes) * 60 * 1000)
|
|
@@ -416,7 +433,7 @@ export async function handleCodeDirect(a, server, extra) {
|
|
|
416
433
|
const coderRole = resolveRole(config, "coder");
|
|
417
434
|
await assertAgentsAvailable([coderRole.provider]);
|
|
418
435
|
|
|
419
|
-
const projectDir = await resolveProjectDir(server);
|
|
436
|
+
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
420
437
|
const runLog = createRunLog(projectDir);
|
|
421
438
|
runLog.logText(`[kj_code] started — provider=${coderRole.provider}`);
|
|
422
439
|
const emitter = buildDirectEmitter(server, runLog, extra);
|
|
@@ -465,7 +482,7 @@ export async function handleReviewDirect(a, server, extra) {
|
|
|
465
482
|
const reviewerRole = resolveRole(config, "reviewer");
|
|
466
483
|
await assertAgentsAvailable([reviewerRole.provider, config.reviewer_options?.fallback_reviewer]);
|
|
467
484
|
|
|
468
|
-
const projectDir = await resolveProjectDir(server);
|
|
485
|
+
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
469
486
|
const runLog = createRunLog(projectDir);
|
|
470
487
|
runLog.logText(`[kj_review] started — provider=${reviewerRole.provider}`);
|
|
471
488
|
const emitter = buildDirectEmitter(server, runLog, extra);
|
|
@@ -512,7 +529,7 @@ export async function handleDiscoverDirect(a, server, extra) {
|
|
|
512
529
|
const discoverRole = resolveRole(config, "discover");
|
|
513
530
|
await assertAgentsAvailable([discoverRole.provider]);
|
|
514
531
|
|
|
515
|
-
const projectDir = await resolveProjectDir(server);
|
|
532
|
+
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
516
533
|
const runLog = createRunLog(projectDir);
|
|
517
534
|
runLog.logText(`[kj_discover] started — mode=${a.mode || "gaps"}`);
|
|
518
535
|
const emitter = buildDirectEmitter(server, runLog, extra);
|
|
@@ -565,7 +582,7 @@ export async function handleTriageDirect(a, server, extra) {
|
|
|
565
582
|
const triageRole = resolveRole(config, "triage");
|
|
566
583
|
await assertAgentsAvailable([triageRole.provider]);
|
|
567
584
|
|
|
568
|
-
const projectDir = await resolveProjectDir(server);
|
|
585
|
+
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
569
586
|
const runLog = createRunLog(projectDir);
|
|
570
587
|
runLog.logText(`[kj_triage] started`);
|
|
571
588
|
const emitter = buildDirectEmitter(server, runLog, extra);
|
|
@@ -609,7 +626,7 @@ export async function handleResearcherDirect(a, server, extra) {
|
|
|
609
626
|
const researcherRole = resolveRole(config, "researcher");
|
|
610
627
|
await assertAgentsAvailable([researcherRole.provider]);
|
|
611
628
|
|
|
612
|
-
const projectDir = await resolveProjectDir(server);
|
|
629
|
+
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
613
630
|
const runLog = createRunLog(projectDir);
|
|
614
631
|
runLog.logText(`[kj_researcher] started`);
|
|
615
632
|
const emitter = buildDirectEmitter(server, runLog, extra);
|
|
@@ -653,7 +670,7 @@ export async function handleArchitectDirect(a, server, extra) {
|
|
|
653
670
|
const architectRole = resolveRole(config, "architect");
|
|
654
671
|
await assertAgentsAvailable([architectRole.provider]);
|
|
655
672
|
|
|
656
|
-
const projectDir = await resolveProjectDir(server);
|
|
673
|
+
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
657
674
|
const runLog = createRunLog(projectDir);
|
|
658
675
|
runLog.logText(`[kj_architect] started`);
|
|
659
676
|
const emitter = buildDirectEmitter(server, runLog, extra);
|
|
@@ -780,7 +797,7 @@ function buildReportArgs(a) {
|
|
|
780
797
|
|
|
781
798
|
async function handleStatus(a, server) {
|
|
782
799
|
const maxLines = a.lines || 50;
|
|
783
|
-
const projectDir = await resolveProjectDir(server);
|
|
800
|
+
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
784
801
|
return readRunLog(projectDir, maxLines);
|
|
785
802
|
}
|
|
786
803
|
|
package/src/mcp/tools.js
CHANGED
|
@@ -53,6 +53,7 @@ export const tools = [
|
|
|
53
53
|
required: ["task"],
|
|
54
54
|
properties: {
|
|
55
55
|
task: { type: "string", description: "Task description for the coder (can include a Planning Game card ID like KJC-TSK-0042)" },
|
|
56
|
+
projectDir: { type: "string", description: "Absolute path to the project directory. Required when KJ MCP server runs from a different directory than the target project." },
|
|
56
57
|
pgTask: { type: "string", description: "Planning Game card ID (e.g., KJC-TSK-0042). If provided, fetches full card details as task context and updates card status on completion." },
|
|
57
58
|
pgProject: { type: "string", description: "Planning Game project ID (e.g., 'Karajan Code'). Required when pgTask is used." },
|
|
58
59
|
planner: { type: "string" },
|
|
@@ -112,6 +113,7 @@ export const tools = [
|
|
|
112
113
|
properties: {
|
|
113
114
|
sessionId: { type: "string", description: "Session ID to resume" },
|
|
114
115
|
answer: { type: "string", description: "Answer to the question that caused the pause" },
|
|
116
|
+
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
115
117
|
kjHome: { type: "string" }
|
|
116
118
|
}
|
|
117
119
|
}
|
|
@@ -185,6 +187,7 @@ export const tools = [
|
|
|
185
187
|
task: { type: "string" },
|
|
186
188
|
coder: { type: "string" },
|
|
187
189
|
coderModel: { type: "string" },
|
|
190
|
+
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
188
191
|
kjHome: { type: "string" }
|
|
189
192
|
}
|
|
190
193
|
}
|
|
@@ -200,6 +203,7 @@ export const tools = [
|
|
|
200
203
|
reviewer: { type: "string" },
|
|
201
204
|
reviewerModel: { type: "string" },
|
|
202
205
|
baseRef: { type: "string" },
|
|
206
|
+
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
203
207
|
kjHome: { type: "string" }
|
|
204
208
|
}
|
|
205
209
|
}
|
|
@@ -226,6 +230,7 @@ export const tools = [
|
|
|
226
230
|
plannerModel: { type: "string" },
|
|
227
231
|
coder: { type: "string", description: "Legacy alias for planner" },
|
|
228
232
|
coderModel: { type: "string", description: "Legacy alias for plannerModel" },
|
|
233
|
+
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
229
234
|
kjHome: { type: "string" }
|
|
230
235
|
}
|
|
231
236
|
}
|
|
@@ -242,6 +247,7 @@ export const tools = [
|
|
|
242
247
|
context: { type: "string", description: "Additional context for the analysis (e.g., research output)" },
|
|
243
248
|
pgTask: { type: "string", description: "Planning Game card ID (e.g., KJC-TSK-0042). If provided, fetches full card details as additional context." },
|
|
244
249
|
pgProject: { type: "string", description: "Planning Game project ID. Required when pgTask is used." },
|
|
250
|
+
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
245
251
|
kjHome: { type: "string" }
|
|
246
252
|
}
|
|
247
253
|
}
|
|
@@ -254,6 +260,7 @@ export const tools = [
|
|
|
254
260
|
required: ["task"],
|
|
255
261
|
properties: {
|
|
256
262
|
task: { type: "string", description: "Task description to classify" },
|
|
263
|
+
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
257
264
|
kjHome: { type: "string" }
|
|
258
265
|
}
|
|
259
266
|
}
|
|
@@ -266,6 +273,7 @@ export const tools = [
|
|
|
266
273
|
required: ["task"],
|
|
267
274
|
properties: {
|
|
268
275
|
task: { type: "string", description: "Task description to research" },
|
|
276
|
+
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
269
277
|
kjHome: { type: "string" }
|
|
270
278
|
}
|
|
271
279
|
}
|
|
@@ -279,6 +287,7 @@ export const tools = [
|
|
|
279
287
|
properties: {
|
|
280
288
|
task: { type: "string", description: "Task description to architect" },
|
|
281
289
|
context: { type: "string", description: "Additional context (e.g., researcher output)" },
|
|
290
|
+
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
282
291
|
kjHome: { type: "string" }
|
|
283
292
|
}
|
|
284
293
|
}
|