karajan-code 1.16.0 → 1.17.0
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/activity-log.js +13 -13
- package/src/agents/availability.js +2 -3
- package/src/agents/claude-agent.js +42 -21
- package/src/agents/model-registry.js +1 -1
- package/src/becaria/dispatch.js +1 -1
- package/src/becaria/repo.js +3 -3
- package/src/cli.js +5 -2
- package/src/commands/doctor.js +154 -108
- package/src/commands/init.js +101 -90
- package/src/commands/plan.js +1 -1
- package/src/commands/report.js +77 -71
- package/src/commands/roles.js +0 -1
- package/src/commands/run.js +2 -3
- package/src/config.js +155 -93
- package/src/git/automation.js +3 -4
- package/src/guards/policy-resolver.js +3 -3
- package/src/mcp/orphan-guard.js +1 -2
- package/src/mcp/progress.js +4 -3
- package/src/mcp/run-kj.js +1 -0
- package/src/mcp/server-handlers.js +242 -253
- package/src/mcp/server.js +4 -3
- package/src/mcp/tools.js +2 -0
- package/src/orchestrator/agent-fallback.js +1 -3
- package/src/orchestrator/iteration-stages.js +206 -170
- package/src/orchestrator/pre-loop-stages.js +200 -34
- package/src/orchestrator/solomon-rules.js +2 -2
- package/src/orchestrator.js +820 -748
- package/src/planning-game/adapter.js +23 -20
- package/src/planning-game/architect-adrs.js +45 -0
- package/src/planning-game/client.js +15 -1
- package/src/planning-game/decomposition.js +7 -5
- package/src/prompts/architect.js +88 -0
- package/src/prompts/discover.js +54 -53
- package/src/prompts/planner.js +53 -33
- package/src/prompts/triage.js +8 -16
- package/src/review/parser.js +18 -19
- package/src/review/profiles.js +2 -2
- package/src/review/schema.js +3 -3
- package/src/review/scope-filter.js +3 -4
- package/src/roles/architect-role.js +122 -0
- package/src/roles/commiter-role.js +2 -2
- package/src/roles/discover-role.js +59 -67
- package/src/roles/index.js +1 -0
- package/src/roles/planner-role.js +54 -38
- package/src/roles/refactorer-role.js +8 -7
- package/src/roles/researcher-role.js +6 -7
- package/src/roles/reviewer-role.js +4 -5
- package/src/roles/security-role.js +3 -4
- package/src/roles/solomon-role.js +6 -18
- package/src/roles/sonar-role.js +5 -1
- package/src/roles/tester-role.js +8 -5
- package/src/roles/triage-role.js +2 -2
- package/src/session-cleanup.js +29 -24
- package/src/session-store.js +1 -1
- package/src/sonar/api.js +1 -1
- package/src/sonar/manager.js +1 -1
- package/src/sonar/project-key.js +5 -5
- package/src/sonar/scanner.js +34 -65
- package/src/utils/display.js +312 -272
- package/src/utils/git.js +3 -3
- package/src/utils/logger.js +6 -1
- package/src/utils/model-selector.js +5 -5
- package/src/utils/process.js +80 -102
- package/src/utils/rate-limit-detector.js +13 -13
- package/src/utils/run-log.js +55 -52
- package/templates/roles/architect.md +62 -0
- package/templates/roles/planner.md +1 -0
package/src/config.js
CHANGED
|
@@ -17,7 +17,8 @@ const DEFAULTS = {
|
|
|
17
17
|
tester: { provider: null, model: null },
|
|
18
18
|
security: { provider: null, model: null },
|
|
19
19
|
triage: { provider: null, model: null },
|
|
20
|
-
discover: { provider: null, model: null }
|
|
20
|
+
discover: { provider: null, model: null },
|
|
21
|
+
architect: { provider: null, model: null }
|
|
21
22
|
},
|
|
22
23
|
pipeline: {
|
|
23
24
|
planner: { enabled: false },
|
|
@@ -27,7 +28,8 @@ const DEFAULTS = {
|
|
|
27
28
|
tester: { enabled: true },
|
|
28
29
|
security: { enabled: true },
|
|
29
30
|
triage: { enabled: true },
|
|
30
|
-
discover: { enabled: false }
|
|
31
|
+
discover: { enabled: false },
|
|
32
|
+
architect: { enabled: false }
|
|
31
33
|
},
|
|
32
34
|
review_mode: "standard",
|
|
33
35
|
max_iterations: 5,
|
|
@@ -221,96 +223,144 @@ export async function writeConfig(configPath, config) {
|
|
|
221
223
|
await fs.writeFile(configPath, yaml.dump(config, { lineWidth: 120 }), "utf8");
|
|
222
224
|
}
|
|
223
225
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
226
|
+
// Declarative mappings for applyRunOverrides to reduce cognitive complexity.
|
|
227
|
+
|
|
228
|
+
// Role provider flags: [flagName, roleName] — truthy check
|
|
229
|
+
const ROLE_PROVIDER_FLAGS = [
|
|
230
|
+
["planner", "planner"], ["coder", "coder"], ["reviewer", "reviewer"],
|
|
231
|
+
["refactorer", "refactorer"], ["solomon", "solomon"], ["researcher", "researcher"],
|
|
232
|
+
["tester", "tester"], ["security", "security"], ["triage", "triage"],
|
|
233
|
+
["discover", "discover"], ["architect", "architect"]
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
// Role model flags: [flagName, roleName] — truthy check, String coercion
|
|
237
|
+
const ROLE_MODEL_FLAGS = [
|
|
238
|
+
["plannerModel", "planner"], ["coderModel", "coder"], ["reviewerModel", "reviewer"],
|
|
239
|
+
["refactorerModel", "refactorer"], ["solomonModel", "solomon"], ["discoverModel", "discover"],
|
|
240
|
+
["architectModel", "architect"]
|
|
241
|
+
];
|
|
238
242
|
|
|
239
|
-
|
|
243
|
+
// Pipeline enable flags: [flagName, pipelineKey] — !== undefined check, Boolean coercion
|
|
244
|
+
const PIPELINE_ENABLE_FLAGS = [
|
|
245
|
+
["enablePlanner", "planner"], ["enableRefactorer", "refactorer"],
|
|
246
|
+
["enableSolomon", "solomon"], ["enableResearcher", "researcher"],
|
|
247
|
+
["enableTester", "tester"], ["enableSecurity", "security"],
|
|
248
|
+
["enableTriage", "triage"], ["enableDiscover", "discover"],
|
|
249
|
+
["enableArchitect", "architect"]
|
|
250
|
+
];
|
|
251
|
+
|
|
252
|
+
// Scalar flags: [flagName, setter] — truthy check
|
|
253
|
+
const SCALAR_FLAGS = [
|
|
254
|
+
["mode", (out, v) => { out.review_mode = v; }],
|
|
255
|
+
["maxIterations", (out, v) => { out.max_iterations = Number(v); }],
|
|
256
|
+
["maxIterationMinutes", (out, v) => { out.session.max_iteration_minutes = Number(v); }],
|
|
257
|
+
["maxTotalMinutes", (out, v) => { out.session.max_total_minutes = Number(v); }],
|
|
258
|
+
["checkpointInterval", (out, v) => { out.session.checkpoint_interval_minutes = Number(v); }],
|
|
259
|
+
["baseBranch", (out, v) => { out.base_branch = v; }],
|
|
260
|
+
["coderFallback", (out, v) => { out.coder_options.fallback_coder = v; }],
|
|
261
|
+
["reviewerFallback", (out, v) => { out.reviewer_options.fallback_reviewer = v; }],
|
|
262
|
+
["taskType", (out, v) => { out.taskType = String(v); }],
|
|
263
|
+
["branchPrefix", (out, v) => { out.git.branch_prefix = String(v); }]
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
// Boolean/undefined-check flags: [flagName, setter] — !== undefined check
|
|
267
|
+
const UNDEF_CHECK_FLAGS = [
|
|
268
|
+
["reviewerRetries", (out, v) => { out.reviewer_options.retries = Number(v); }],
|
|
269
|
+
["autoCommit", (out, v) => { out.git.auto_commit = Boolean(v); }],
|
|
270
|
+
["autoPush", (out, v) => { out.git.auto_push = Boolean(v); }],
|
|
271
|
+
["autoPr", (out, v) => { out.git.auto_pr = Boolean(v); }],
|
|
272
|
+
["autoRebase", (out, v) => { out.git.auto_rebase = Boolean(v); }],
|
|
273
|
+
["enableSerena", (out, v) => { out.serena.enabled = Boolean(v); }]
|
|
274
|
+
];
|
|
275
|
+
|
|
276
|
+
function applyRoleOverrides(out, flags) {
|
|
277
|
+
for (const [flag, role] of ROLE_PROVIDER_FLAGS) {
|
|
278
|
+
if (flags[flag]) out.roles[role].provider = flags[flag];
|
|
279
|
+
}
|
|
280
|
+
// coder/reviewer also update top-level aliases
|
|
240
281
|
if (flags.coder) out.coder = flags.coder;
|
|
241
|
-
if (flags.coder) out.roles.coder.provider = flags.coder;
|
|
242
282
|
if (flags.reviewer) out.reviewer = flags.reviewer;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (flags.researcher) out.roles.researcher.provider = flags.researcher;
|
|
247
|
-
if (flags.tester) out.roles.tester.provider = flags.tester;
|
|
248
|
-
if (flags.security) out.roles.security.provider = flags.security;
|
|
249
|
-
if (flags.triage) out.roles.triage.provider = flags.triage;
|
|
250
|
-
if (flags.discover) out.roles.discover.provider = flags.discover;
|
|
251
|
-
if (flags.discoverModel) out.roles.discover.model = String(flags.discoverModel);
|
|
252
|
-
if (flags.enableDiscover !== undefined) out.pipeline.discover.enabled = Boolean(flags.enableDiscover);
|
|
253
|
-
if (flags.plannerModel) out.roles.planner.model = String(flags.plannerModel);
|
|
254
|
-
if (flags.coderModel) {
|
|
255
|
-
out.roles.coder.model = String(flags.coderModel);
|
|
283
|
+
|
|
284
|
+
for (const [flag, role] of ROLE_MODEL_FLAGS) {
|
|
285
|
+
if (flags[flag]) out.roles[role].model = String(flags[flag]);
|
|
256
286
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
287
|
+
// reviewerModel also updates reviewer_options
|
|
288
|
+
if (flags.reviewerModel) out.reviewer_options.model = String(flags.reviewerModel);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function applyPipelineOverrides(out, flags) {
|
|
292
|
+
for (const [flag, key] of PIPELINE_ENABLE_FLAGS) {
|
|
293
|
+
if (flags[flag] !== undefined) out.pipeline[key].enabled = Boolean(flags[flag]);
|
|
260
294
|
}
|
|
261
|
-
if (flags.refactorerModel) out.roles.refactorer.model = String(flags.refactorerModel);
|
|
262
|
-
if (flags.solomonModel) out.roles.solomon.model = String(flags.solomonModel);
|
|
263
|
-
if (flags.enablePlanner !== undefined) out.pipeline.planner.enabled = Boolean(flags.enablePlanner);
|
|
264
|
-
if (flags.enableRefactorer !== undefined) out.pipeline.refactorer.enabled = Boolean(flags.enableRefactorer);
|
|
265
|
-
if (flags.enableSolomon !== undefined) out.pipeline.solomon.enabled = Boolean(flags.enableSolomon);
|
|
266
|
-
if (flags.enableResearcher !== undefined) out.pipeline.researcher.enabled = Boolean(flags.enableResearcher);
|
|
267
|
-
if (flags.enableTester !== undefined) out.pipeline.tester.enabled = Boolean(flags.enableTester);
|
|
268
|
-
if (flags.enableSecurity !== undefined) out.pipeline.security.enabled = Boolean(flags.enableSecurity);
|
|
269
295
|
if (flags.enableReviewer !== undefined) {
|
|
270
296
|
out.pipeline.reviewer = out.pipeline.reviewer || {};
|
|
271
297
|
out.pipeline.reviewer.enabled = Boolean(flags.enableReviewer);
|
|
272
298
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (flags.checkpointInterval) out.session.checkpoint_interval_minutes = Number(flags.checkpointInterval);
|
|
279
|
-
if (flags.baseBranch) out.base_branch = flags.baseBranch;
|
|
280
|
-
if (flags.coderFallback) out.coder_options.fallback_coder = flags.coderFallback;
|
|
281
|
-
if (flags.reviewerFallback) out.reviewer_options.fallback_reviewer = flags.reviewerFallback;
|
|
282
|
-
if (flags.reviewerRetries !== undefined) out.reviewer_options.retries = Number(flags.reviewerRetries);
|
|
283
|
-
if (flags.autoCommit !== undefined) out.git.auto_commit = Boolean(flags.autoCommit);
|
|
284
|
-
if (flags.autoPush !== undefined) out.git.auto_push = Boolean(flags.autoPush);
|
|
285
|
-
if (flags.autoPr !== undefined) out.git.auto_pr = Boolean(flags.autoPr);
|
|
286
|
-
if (flags.autoRebase !== undefined) out.git.auto_rebase = Boolean(flags.autoRebase);
|
|
287
|
-
if (flags.branchPrefix) out.git.branch_prefix = String(flags.branchPrefix);
|
|
288
|
-
if (flags.methodology) {
|
|
289
|
-
const methodology = String(flags.methodology).toLowerCase();
|
|
290
|
-
out.development = out.development || {};
|
|
291
|
-
out.development.methodology = methodology;
|
|
292
|
-
out.development.require_test_changes = methodology === "tdd";
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function applyScalarAndBooleanOverrides(out, flags) {
|
|
302
|
+
for (const [flag, setter] of SCALAR_FLAGS) {
|
|
303
|
+
if (flags[flag]) setter(out, flags[flag]);
|
|
293
304
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
305
|
+
for (const [flag, setter] of UNDEF_CHECK_FLAGS) {
|
|
306
|
+
if (flags[flag] !== undefined) setter(out, flags[flag]);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function applyMethodologyOverride(out, flags) {
|
|
311
|
+
if (!flags.methodology) return;
|
|
312
|
+
const methodology = String(flags.methodology).toLowerCase();
|
|
313
|
+
out.development.methodology = methodology;
|
|
314
|
+
out.development.require_test_changes = methodology === "tdd";
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function applyBecariaOverride(out, flags) {
|
|
298
318
|
out.becaria = out.becaria || { enabled: false };
|
|
299
|
-
if (flags.enableBecaria
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
}
|
|
319
|
+
if (flags.enableBecaria === undefined) return;
|
|
320
|
+
out.becaria.enabled = Boolean(flags.enableBecaria);
|
|
321
|
+
// BecarIA requires git automation (commit + push + PR)
|
|
322
|
+
if (out.becaria.enabled) {
|
|
323
|
+
out.git.auto_commit = true;
|
|
324
|
+
out.git.auto_push = true;
|
|
325
|
+
out.git.auto_pr = true;
|
|
307
326
|
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function applyMiscOverrides(out, flags) {
|
|
330
|
+
if (flags.noSonar || flags.sonar === false) out.sonarqube.enabled = false;
|
|
331
|
+
|
|
308
332
|
out.planning_game = out.planning_game || {};
|
|
309
333
|
if (flags.pgTask) out.planning_game.enabled = true;
|
|
310
334
|
if (flags.pgProject) out.planning_game.project_id = flags.pgProject;
|
|
335
|
+
|
|
311
336
|
out.model_selection = out.model_selection || { enabled: true, tiers: {}, role_overrides: {} };
|
|
312
337
|
if (flags.smartModels === true) out.model_selection.enabled = true;
|
|
313
338
|
if (flags.smartModels === false || flags.noSmartModels === true) out.model_selection.enabled = false;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export function applyRunOverrides(config, flags) {
|
|
342
|
+
const out = mergeDeep(config, {});
|
|
343
|
+
out.coder_options = out.coder_options || {};
|
|
344
|
+
out.reviewer_options = out.reviewer_options || {};
|
|
345
|
+
out.session = out.session || {};
|
|
346
|
+
out.git = out.git || {};
|
|
347
|
+
out.development = out.development || {};
|
|
348
|
+
out.sonarqube = out.sonarqube || {};
|
|
349
|
+
if (out.max_budget_usd === undefined || out.max_budget_usd === null) {
|
|
350
|
+
out.max_budget_usd = out.session.max_budget_usd ?? null;
|
|
351
|
+
}
|
|
352
|
+
out.budget = mergeDeep(DEFAULTS.budget, out.budget || {});
|
|
353
|
+
out.roles = mergeDeep(DEFAULTS.roles, out.roles || {});
|
|
354
|
+
out.pipeline = mergeDeep(DEFAULTS.pipeline, out.pipeline || {});
|
|
355
|
+
out.serena = out.serena || { enabled: false };
|
|
356
|
+
|
|
357
|
+
applyRoleOverrides(out, flags);
|
|
358
|
+
applyPipelineOverrides(out, flags);
|
|
359
|
+
applyScalarAndBooleanOverrides(out, flags);
|
|
360
|
+
applyMethodologyOverride(out, flags);
|
|
361
|
+
applyBecariaOverride(out, flags);
|
|
362
|
+
applyMiscOverrides(out, flags);
|
|
363
|
+
|
|
314
364
|
return out;
|
|
315
365
|
}
|
|
316
366
|
|
|
@@ -323,45 +373,57 @@ export function resolveRole(config, role) {
|
|
|
323
373
|
let provider = roleConfig.provider ?? null;
|
|
324
374
|
if (!provider && role === "coder") provider = legacyCoder;
|
|
325
375
|
if (!provider && role === "reviewer") provider = legacyReviewer;
|
|
326
|
-
if (!provider && (role === "planner" || role === "refactorer" || role === "solomon" || role === "researcher" || role === "tester" || role === "security" || role === "triage" || role === "discover")) {
|
|
376
|
+
if (!provider && (role === "planner" || role === "refactorer" || role === "solomon" || role === "researcher" || role === "tester" || role === "security" || role === "triage" || role === "discover" || role === "architect")) {
|
|
327
377
|
provider = roles.coder?.provider || legacyCoder;
|
|
328
378
|
}
|
|
329
379
|
|
|
330
380
|
let model = roleConfig.model ?? null;
|
|
331
381
|
if (!model && role === "coder") model = config?.coder_options?.model ?? null;
|
|
332
382
|
if (!model && role === "reviewer") model = config?.reviewer_options?.model ?? null;
|
|
333
|
-
if (!model && (role === "planner" || role === "refactorer" || role === "solomon" || role === "researcher" || role === "tester" || role === "security" || role === "triage" || role === "discover")) {
|
|
383
|
+
if (!model && (role === "planner" || role === "refactorer" || role === "solomon" || role === "researcher" || role === "tester" || role === "security" || role === "triage" || role === "discover" || role === "architect")) {
|
|
334
384
|
model = config?.coder_options?.model ?? null;
|
|
335
385
|
}
|
|
336
386
|
|
|
337
387
|
return { provider, model };
|
|
338
388
|
}
|
|
339
389
|
|
|
390
|
+
// Pipeline roles checked when commandName is "run": [pipelineKey, roleName]
|
|
391
|
+
const RUN_PIPELINE_ROLES = [
|
|
392
|
+
["reviewer", "reviewer"], ["triage", "triage"], ["planner", "planner"],
|
|
393
|
+
["refactorer", "refactorer"], ["researcher", "researcher"],
|
|
394
|
+
["tester", "tester"], ["security", "security"]
|
|
395
|
+
];
|
|
396
|
+
|
|
397
|
+
// Direct command-to-role mapping for non-"run" commands
|
|
398
|
+
const COMMAND_ROLE_MAP = {
|
|
399
|
+
discover: ["discover"],
|
|
400
|
+
plan: ["planner"],
|
|
401
|
+
code: ["coder"],
|
|
402
|
+
review: ["reviewer"]
|
|
403
|
+
};
|
|
404
|
+
|
|
340
405
|
function requiredRolesFor(commandName, config) {
|
|
341
|
-
if (commandName
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
406
|
+
if (commandName !== "run") {
|
|
407
|
+
return COMMAND_ROLE_MAP[commandName] || [];
|
|
408
|
+
}
|
|
409
|
+
const required = ["coder"];
|
|
410
|
+
for (const [pipelineKey, roleName] of RUN_PIPELINE_ROLES) {
|
|
411
|
+
const pipelineEntry = config?.pipeline?.[pipelineKey];
|
|
412
|
+
// reviewer defaults to enabled (only excluded if explicitly false)
|
|
413
|
+
const isEnabled = pipelineKey === "reviewer"
|
|
414
|
+
? pipelineEntry?.enabled !== false
|
|
415
|
+
: Boolean(pipelineEntry?.enabled);
|
|
416
|
+
if (isEnabled) required.push(roleName);
|
|
351
417
|
}
|
|
352
|
-
|
|
353
|
-
if (commandName === "plan") return ["planner"];
|
|
354
|
-
if (commandName === "code") return ["coder"];
|
|
355
|
-
if (commandName === "review") return ["reviewer"];
|
|
356
|
-
return [];
|
|
418
|
+
return required;
|
|
357
419
|
}
|
|
358
420
|
|
|
359
421
|
export function validateConfig(config, commandName = "run") {
|
|
360
422
|
const errors = [];
|
|
361
|
-
if (!["paranoid", "strict", "standard", "relaxed", "custom"].
|
|
423
|
+
if (!new Set(["paranoid", "strict", "standard", "relaxed", "custom"]).has(config.review_mode)) {
|
|
362
424
|
errors.push(`Invalid review_mode: ${config.review_mode}`);
|
|
363
425
|
}
|
|
364
|
-
if (!["tdd", "standard"].
|
|
426
|
+
if (!new Set(["tdd", "standard"]).has(config.development?.methodology)) {
|
|
365
427
|
errors.push(`Invalid development.methodology: ${config.development?.methodology}`);
|
|
366
428
|
}
|
|
367
429
|
|
package/src/git/automation.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
|
|
20
20
|
export function commitMessageFromTask(task) {
|
|
21
21
|
const clean = String(task || "")
|
|
22
|
-
.
|
|
22
|
+
.replaceAll(/\s+/g, " ")
|
|
23
23
|
.trim();
|
|
24
24
|
return `feat: ${clean.slice(0, 72) || "karajan update"}`;
|
|
25
25
|
}
|
|
@@ -72,8 +72,7 @@ export function buildPrBody({ task, stageResults }) {
|
|
|
72
72
|
const shouldDecompose = stageResults?.triage?.shouldDecompose;
|
|
73
73
|
const pendingSubtasks = shouldDecompose && triageSubtasks?.length > 1 ? triageSubtasks.slice(1) : [];
|
|
74
74
|
if (pendingSubtasks.length > 0) {
|
|
75
|
-
sections.push("", "## Pending subtasks");
|
|
76
|
-
sections.push("This PR addresses part of a larger task. The following subtasks were identified but not included:");
|
|
75
|
+
sections.push("", "## Pending subtasks", "This PR addresses part of a larger task. The following subtasks were identified but not included:");
|
|
77
76
|
for (const subtask of pendingSubtasks) {
|
|
78
77
|
sections.push(`- [ ] ${subtask}`);
|
|
79
78
|
}
|
|
@@ -115,7 +114,7 @@ export async function earlyPrCreation({ gitCtx, task, logger, session, stageResu
|
|
|
115
114
|
logger.info(`Early PR created: ${prUrl}`);
|
|
116
115
|
|
|
117
116
|
// Extract PR number from URL (e.g. https://github.com/owner/repo/pull/42)
|
|
118
|
-
const prNumber = parseInt(prUrl.split("/").pop(), 10) || null;
|
|
117
|
+
const prNumber = Number.parseInt(prUrl.split("/").pop(), 10) || null;
|
|
119
118
|
return { prNumber, prUrl, commits };
|
|
120
119
|
}
|
|
121
120
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const VALID_TASK_TYPES = ["sw", "infra", "doc", "add-tests", "refactor"];
|
|
1
|
+
export const VALID_TASK_TYPES = new Set(["sw", "infra", "doc", "add-tests", "refactor"]);
|
|
2
2
|
|
|
3
3
|
export const DEFAULT_POLICIES = {
|
|
4
4
|
sw: { tdd: true, sonar: true, reviewer: true, testsRequired: true },
|
|
@@ -16,7 +16,7 @@ const FALLBACK_TYPE = "sw";
|
|
|
16
16
|
* configOverrides optionally merges over defaults per taskType.
|
|
17
17
|
*/
|
|
18
18
|
export function resolvePolicies(taskType, configOverrides) {
|
|
19
|
-
const resolvedType = VALID_TASK_TYPES.
|
|
19
|
+
const resolvedType = VALID_TASK_TYPES.has(taskType) ? taskType : FALLBACK_TYPE;
|
|
20
20
|
const base = { ...DEFAULT_POLICIES[resolvedType] };
|
|
21
21
|
const overrides = configOverrides?.[resolvedType];
|
|
22
22
|
if (overrides && typeof overrides === "object") {
|
|
@@ -31,7 +31,7 @@ export function resolvePolicies(taskType, configOverrides) {
|
|
|
31
31
|
* orchestrator to determine which pipeline stages to enable/disable.
|
|
32
32
|
*/
|
|
33
33
|
export function applyPolicies({ taskType, policies } = {}) {
|
|
34
|
-
const resolvedType = VALID_TASK_TYPES.
|
|
34
|
+
const resolvedType = VALID_TASK_TYPES.has(taskType) ? taskType : FALLBACK_TYPE;
|
|
35
35
|
const resolved = resolvePolicies(taskType, policies);
|
|
36
36
|
return { taskType: resolvedType, ...resolved };
|
|
37
37
|
}
|
package/src/mcp/orphan-guard.js
CHANGED
package/src/mcp/progress.js
CHANGED
|
@@ -57,7 +57,7 @@ export function buildPipelineTracker(config, emitter) {
|
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
emitter.on("progress", (event) => {
|
|
60
|
-
const match =
|
|
60
|
+
const match = /^(\w+):(start|end)$/.exec(event.type ?? "");
|
|
61
61
|
if (!match) return;
|
|
62
62
|
|
|
63
63
|
const [, name, phase] = match;
|
|
@@ -127,9 +127,10 @@ export function buildProgressNotifier(extra) {
|
|
|
127
127
|
if (idx < 0) return;
|
|
128
128
|
|
|
129
129
|
const iteration = event.iteration || event.detail?.iteration;
|
|
130
|
+
const baseMessage = event.message || event.type;
|
|
130
131
|
const message = iteration
|
|
131
|
-
? `[${event.iteration}] ${
|
|
132
|
-
:
|
|
132
|
+
? `[${event.iteration}] ${baseMessage}`
|
|
133
|
+
: baseMessage;
|
|
133
134
|
|
|
134
135
|
try {
|
|
135
136
|
extra.sendNotification({
|
package/src/mcp/run-kj.js
CHANGED
|
@@ -44,6 +44,7 @@ export async function runKjCommand({ command, commandArgs = [], options = {}, en
|
|
|
44
44
|
normalizeBoolFlag(options.enableSecurity, "--enable-security", args);
|
|
45
45
|
normalizeBoolFlag(options.enableTriage, "--enable-triage", args);
|
|
46
46
|
normalizeBoolFlag(options.enableDiscover, "--enable-discover", args);
|
|
47
|
+
normalizeBoolFlag(options.enableArchitect, "--enable-architect", args);
|
|
47
48
|
normalizeBoolFlag(options.enableSerena, "--enable-serena", args);
|
|
48
49
|
normalizeBoolFlag(options.autoCommit, "--auto-commit", args);
|
|
49
50
|
normalizeBoolFlag(options.autoPush, "--auto-push", args);
|