karajan-code 1.25.0 → 1.25.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/package.json +1 -1
- package/src/cli.js +2 -0
- package/src/config.js +5 -1
- package/src/mcp/run-kj.js +2 -0
- package/src/mcp/server-handlers.js +33 -0
- package/src/mcp/tools.js +1 -0
- package/src/orchestrator.js +31 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -103,6 +103,8 @@ program
|
|
|
103
103
|
.option("--checkpoint-interval <n>", "Minutes between interactive checkpoints (default: 5)")
|
|
104
104
|
.option("--pg-task <cardId>", "Planning Game card ID (e.g., KJC-TSK-0042)")
|
|
105
105
|
.option("--pg-project <projectId>", "Planning Game project ID")
|
|
106
|
+
.option("--auto-simplify", "Auto-simplify pipeline for simple tasks (disable reviewer/tester)")
|
|
107
|
+
.option("--no-auto-simplify", "Force full pipeline regardless of triage level")
|
|
106
108
|
.option("--smart-models", "Enable smart model selection based on triage complexity")
|
|
107
109
|
.option("--no-smart-models", "Disable smart model selection")
|
|
108
110
|
.option("--dry-run", "Show what would be executed without running anything")
|
package/src/config.js
CHANGED
|
@@ -31,7 +31,8 @@ const DEFAULTS = {
|
|
|
31
31
|
impeccable: { enabled: false },
|
|
32
32
|
triage: { enabled: true },
|
|
33
33
|
discover: { enabled: false },
|
|
34
|
-
architect: { enabled: false }
|
|
34
|
+
architect: { enabled: false },
|
|
35
|
+
auto_simplify: true
|
|
35
36
|
},
|
|
36
37
|
review_mode: "standard",
|
|
37
38
|
max_iterations: 5,
|
|
@@ -283,6 +284,8 @@ const PIPELINE_ENABLE_FLAGS = [
|
|
|
283
284
|
["enableArchitect", "architect"]
|
|
284
285
|
];
|
|
285
286
|
|
|
287
|
+
const AUTO_SIMPLIFY_FLAG = "autoSimplify";
|
|
288
|
+
|
|
286
289
|
// Scalar flags: [flagName, setter] — truthy check
|
|
287
290
|
const SCALAR_FLAGS = [
|
|
288
291
|
["mode", (out, v) => { out.review_mode = v; }],
|
|
@@ -361,6 +364,7 @@ function applyBecariaOverride(out, flags) {
|
|
|
361
364
|
}
|
|
362
365
|
|
|
363
366
|
function applyMiscOverrides(out, flags) {
|
|
367
|
+
if (flags[AUTO_SIMPLIFY_FLAG] !== undefined) out.pipeline.auto_simplify = Boolean(flags[AUTO_SIMPLIFY_FLAG]);
|
|
364
368
|
if (flags.noSonar || flags.sonar === false) out.sonarqube.enabled = false;
|
|
365
369
|
out.sonarcloud = out.sonarcloud || {};
|
|
366
370
|
if (flags.enableSonarcloud === true) out.sonarcloud.enabled = true;
|
package/src/mcp/run-kj.js
CHANGED
|
@@ -53,6 +53,8 @@ export async function runKjCommand({ command, commandArgs = [], options = {}, en
|
|
|
53
53
|
if (options.autoRebase === false) args.push("--no-auto-rebase");
|
|
54
54
|
addOptionalValue(args, "--task-type", options.taskType);
|
|
55
55
|
normalizeBoolFlag(options.noSonar, "--no-sonar", args);
|
|
56
|
+
if (options.autoSimplify === true) args.push("--auto-simplify");
|
|
57
|
+
if (options.autoSimplify === false) args.push("--no-auto-simplify");
|
|
56
58
|
if (options.smartModels === true) args.push("--smart-models");
|
|
57
59
|
if (options.smartModels === false) args.push("--no-smart-models");
|
|
58
60
|
addOptionalValue(args, "--checkpoint-interval", options.checkpointInterval);
|
|
@@ -823,10 +823,43 @@ function handleRoles(a) {
|
|
|
823
823
|
return runKjCommand({ command: "roles", commandArgs, options: a });
|
|
824
824
|
}
|
|
825
825
|
|
|
826
|
+
const RESUME_MAX_ANSWER_LENGTH = 500;
|
|
827
|
+
const RESUME_INJECTION_PATTERNS = [
|
|
828
|
+
/ignore\s+(previous|all|above)\s+(instructions|rules|prompts)/i,
|
|
829
|
+
/you\s+are\s+now/i,
|
|
830
|
+
/new\s+instructions?:/i,
|
|
831
|
+
/override\s+(all|security|guardrails|rules)/i,
|
|
832
|
+
/skip\s+(all\s+)?(review|test|sonar|security|solomon|guard)s?\b/i,
|
|
833
|
+
/disable\s+(tdd|review|test|sonar|security)\b/i,
|
|
834
|
+
/set\s+(status|approved|verdict)\s*(=|to|:)/i,
|
|
835
|
+
/force\s+(approve|merge|push|commit)\b/i,
|
|
836
|
+
];
|
|
837
|
+
|
|
838
|
+
export function validateResumeAnswer(answer) {
|
|
839
|
+
if (answer == null || answer === "") return { valid: true, sanitized: answer ?? null };
|
|
840
|
+
if (typeof answer !== "string") return { valid: true, sanitized: String(answer) };
|
|
841
|
+
if (answer.length > RESUME_MAX_ANSWER_LENGTH) {
|
|
842
|
+
return { valid: false, reason: `Answer too long (${answer.length} chars, max ${RESUME_MAX_ANSWER_LENGTH})` };
|
|
843
|
+
}
|
|
844
|
+
for (const pattern of RESUME_INJECTION_PATTERNS) {
|
|
845
|
+
if (pattern.test(answer)) {
|
|
846
|
+
return { valid: false, reason: "Answer rejected: matches guardrail bypass pattern" };
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return { valid: true, sanitized: answer.trim() };
|
|
850
|
+
}
|
|
851
|
+
|
|
826
852
|
async function handleResume(a, server, extra) {
|
|
827
853
|
if (!a.sessionId) {
|
|
828
854
|
return failPayload("Missing required field: sessionId");
|
|
829
855
|
}
|
|
856
|
+
if (a.answer) {
|
|
857
|
+
const validation = validateResumeAnswer(a.answer);
|
|
858
|
+
if (!validation.valid) {
|
|
859
|
+
return failPayload(`Resume answer rejected: ${validation.reason}`);
|
|
860
|
+
}
|
|
861
|
+
a.answer = validation.sanitized;
|
|
862
|
+
}
|
|
830
863
|
applySessionOverrides(a, ["coder", "reviewer", "tester", "security", "solomon", "enableTester", "enableSecurity", "enableImpeccable"]);
|
|
831
864
|
return handleResumeDirect(a, server, extra);
|
|
832
865
|
}
|
package/src/mcp/tools.js
CHANGED
|
@@ -90,6 +90,7 @@ export const tools = [
|
|
|
90
90
|
autoPr: { type: "boolean" },
|
|
91
91
|
autoRebase: { type: "boolean" },
|
|
92
92
|
branchPrefix: { type: "string" },
|
|
93
|
+
autoSimplify: { type: "boolean", description: "Auto-simplify pipeline for simple tasks (level trivial/simple). Disable with false to force full pipeline." },
|
|
93
94
|
smartModels: { type: "boolean", description: "Enable/disable smart model selection based on triage complexity" },
|
|
94
95
|
checkpointInterval: { type: "number", description: "Minutes between interactive checkpoints (default: 5). Set 0 to disable." },
|
|
95
96
|
taskType: { type: "string", enum: ["sw", "infra", "doc", "add-tests", "refactor"], description: "Explicit task type for policy resolution. Overrides triage classification." },
|
package/src/orchestrator.js
CHANGED
|
@@ -214,6 +214,29 @@ function applyTriageOverrides(pipelineFlags, roleOverrides) {
|
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
const SIMPLE_LEVELS = new Set(["trivial", "simple"]);
|
|
218
|
+
|
|
219
|
+
function applyAutoSimplify({ pipelineFlags, triageLevel, config, flags, logger, emitter, eventBase }) {
|
|
220
|
+
if (!config.pipeline?.auto_simplify) return false;
|
|
221
|
+
if (!triageLevel || !SIMPLE_LEVELS.has(triageLevel)) return false;
|
|
222
|
+
if (flags.mode) return false;
|
|
223
|
+
if (flags.enableReviewer !== undefined || flags.enableTester !== undefined) return false;
|
|
224
|
+
|
|
225
|
+
pipelineFlags.reviewerEnabled = false;
|
|
226
|
+
pipelineFlags.testerEnabled = false;
|
|
227
|
+
|
|
228
|
+
const disabledRoles = ["reviewer", "tester"];
|
|
229
|
+
logger.info(`Simple task (${triageLevel}) — lightweight pipeline (disabled: ${disabledRoles.join(", ")})`);
|
|
230
|
+
emitProgress(
|
|
231
|
+
emitter,
|
|
232
|
+
makeEvent("pipeline:simplify", { ...eventBase, stage: "triage" }, {
|
|
233
|
+
message: `Simple task (${triageLevel}) — lightweight pipeline`,
|
|
234
|
+
detail: { level: triageLevel, disabledRoles }
|
|
235
|
+
})
|
|
236
|
+
);
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
|
|
217
240
|
async function handlePgDecomposition({ triageResult, pgTaskId, pgProject, config, askQuestion, emitter, eventBase, session, stageResults, logger }) {
|
|
218
241
|
const shouldDecompose = triageResult.stageResult?.shouldDecompose
|
|
219
242
|
&& triageResult.stageResult.subtasks?.length > 1
|
|
@@ -795,6 +818,14 @@ async function runPreLoopStages({ config, logger, emitter, eventBase, session, f
|
|
|
795
818
|
applyTriageOverrides(pipelineFlags, triageResult.roleOverrides);
|
|
796
819
|
stageResults.triage = triageResult.stageResult;
|
|
797
820
|
|
|
821
|
+
// --- Auto-simplify pipeline for simple tasks (before explicit flag overrides) ---
|
|
822
|
+
const simplified = applyAutoSimplify({
|
|
823
|
+
pipelineFlags,
|
|
824
|
+
triageLevel: triageResult.stageResult?.level || null,
|
|
825
|
+
config, flags, logger, emitter, eventBase
|
|
826
|
+
});
|
|
827
|
+
if (simplified) stageResults.triage.autoSimplified = true;
|
|
828
|
+
|
|
798
829
|
await handlePgDecomposition({ triageResult, pgTaskId, pgProject, config, askQuestion, emitter, eventBase, session, stageResults, logger });
|
|
799
830
|
|
|
800
831
|
applyFlagOverrides(pipelineFlags, flags);
|