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.
Files changed (68) hide show
  1. package/package.json +1 -1
  2. package/src/activity-log.js +13 -13
  3. package/src/agents/availability.js +2 -3
  4. package/src/agents/claude-agent.js +42 -21
  5. package/src/agents/model-registry.js +1 -1
  6. package/src/becaria/dispatch.js +1 -1
  7. package/src/becaria/repo.js +3 -3
  8. package/src/cli.js +5 -2
  9. package/src/commands/doctor.js +154 -108
  10. package/src/commands/init.js +101 -90
  11. package/src/commands/plan.js +1 -1
  12. package/src/commands/report.js +77 -71
  13. package/src/commands/roles.js +0 -1
  14. package/src/commands/run.js +2 -3
  15. package/src/config.js +155 -93
  16. package/src/git/automation.js +3 -4
  17. package/src/guards/policy-resolver.js +3 -3
  18. package/src/mcp/orphan-guard.js +1 -2
  19. package/src/mcp/progress.js +4 -3
  20. package/src/mcp/run-kj.js +1 -0
  21. package/src/mcp/server-handlers.js +242 -253
  22. package/src/mcp/server.js +4 -3
  23. package/src/mcp/tools.js +2 -0
  24. package/src/orchestrator/agent-fallback.js +1 -3
  25. package/src/orchestrator/iteration-stages.js +206 -170
  26. package/src/orchestrator/pre-loop-stages.js +200 -34
  27. package/src/orchestrator/solomon-rules.js +2 -2
  28. package/src/orchestrator.js +820 -748
  29. package/src/planning-game/adapter.js +23 -20
  30. package/src/planning-game/architect-adrs.js +45 -0
  31. package/src/planning-game/client.js +15 -1
  32. package/src/planning-game/decomposition.js +7 -5
  33. package/src/prompts/architect.js +88 -0
  34. package/src/prompts/discover.js +54 -53
  35. package/src/prompts/planner.js +53 -33
  36. package/src/prompts/triage.js +8 -16
  37. package/src/review/parser.js +18 -19
  38. package/src/review/profiles.js +2 -2
  39. package/src/review/schema.js +3 -3
  40. package/src/review/scope-filter.js +3 -4
  41. package/src/roles/architect-role.js +122 -0
  42. package/src/roles/commiter-role.js +2 -2
  43. package/src/roles/discover-role.js +59 -67
  44. package/src/roles/index.js +1 -0
  45. package/src/roles/planner-role.js +54 -38
  46. package/src/roles/refactorer-role.js +8 -7
  47. package/src/roles/researcher-role.js +6 -7
  48. package/src/roles/reviewer-role.js +4 -5
  49. package/src/roles/security-role.js +3 -4
  50. package/src/roles/solomon-role.js +6 -18
  51. package/src/roles/sonar-role.js +5 -1
  52. package/src/roles/tester-role.js +8 -5
  53. package/src/roles/triage-role.js +2 -2
  54. package/src/session-cleanup.js +29 -24
  55. package/src/session-store.js +1 -1
  56. package/src/sonar/api.js +1 -1
  57. package/src/sonar/manager.js +1 -1
  58. package/src/sonar/project-key.js +5 -5
  59. package/src/sonar/scanner.js +34 -65
  60. package/src/utils/display.js +312 -272
  61. package/src/utils/git.js +3 -3
  62. package/src/utils/logger.js +6 -1
  63. package/src/utils/model-selector.js +5 -5
  64. package/src/utils/process.js +80 -102
  65. package/src/utils/rate-limit-detector.js +13 -13
  66. package/src/utils/run-log.js +55 -52
  67. package/templates/roles/architect.md +62 -0
  68. 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
- export function applyRunOverrides(config, flags) {
225
- const out = mergeDeep(config, {});
226
- out.coder_options = out.coder_options || {};
227
- out.reviewer_options = out.reviewer_options || {};
228
- out.session = out.session || {};
229
- out.git = out.git || {};
230
- out.development = out.development || {};
231
- out.sonarqube = out.sonarqube || {};
232
- if (out.max_budget_usd === undefined || out.max_budget_usd === null) {
233
- out.max_budget_usd = out.session.max_budget_usd ?? null;
234
- }
235
- out.budget = mergeDeep(DEFAULTS.budget, out.budget || {});
236
- out.roles = mergeDeep(DEFAULTS.roles, out.roles || {});
237
- out.pipeline = mergeDeep(DEFAULTS.pipeline, out.pipeline || {});
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
- if (flags.planner) out.roles.planner.provider = flags.planner;
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
- if (flags.reviewer) out.roles.reviewer.provider = flags.reviewer;
244
- if (flags.refactorer) out.roles.refactorer.provider = flags.refactorer;
245
- if (flags.solomon) out.roles.solomon.provider = flags.solomon;
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
- if (flags.reviewerModel) {
258
- out.roles.reviewer.model = String(flags.reviewerModel);
259
- out.reviewer_options.model = String(flags.reviewerModel);
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
- if (flags.enableTriage !== undefined) out.pipeline.triage.enabled = Boolean(flags.enableTriage);
274
- if (flags.mode) out.review_mode = flags.mode;
275
- if (flags.maxIterations) out.max_iterations = Number(flags.maxIterations);
276
- if (flags.maxIterationMinutes) out.session.max_iteration_minutes = Number(flags.maxIterationMinutes);
277
- if (flags.maxTotalMinutes) out.session.max_total_minutes = Number(flags.maxTotalMinutes);
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
- if (flags.taskType) out.taskType = String(flags.taskType);
295
- if (flags.noSonar || flags.sonar === false) out.sonarqube.enabled = false;
296
- out.serena = out.serena || { enabled: false };
297
- if (flags.enableSerena !== undefined) out.serena.enabled = Boolean(flags.enableSerena);
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 !== undefined) {
300
- out.becaria.enabled = Boolean(flags.enableBecaria);
301
- // BecarIA requires git automation (commit + push + PR)
302
- if (out.becaria.enabled) {
303
- out.git.auto_commit = true;
304
- out.git.auto_push = true;
305
- out.git.auto_pr = true;
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 === "run") {
342
- const required = ["coder"];
343
- if (config?.pipeline?.reviewer?.enabled !== false) required.push("reviewer");
344
- if (config?.pipeline?.triage?.enabled) required.push("triage");
345
- if (config?.pipeline?.planner?.enabled) required.push("planner");
346
- if (config?.pipeline?.refactorer?.enabled) required.push("refactorer");
347
- if (config?.pipeline?.researcher?.enabled) required.push("researcher");
348
- if (config?.pipeline?.tester?.enabled) required.push("tester");
349
- if (config?.pipeline?.security?.enabled) required.push("security");
350
- return required;
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
- if (commandName === "discover") return ["discover"];
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"].includes(config.review_mode)) {
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"].includes(config.development?.methodology)) {
426
+ if (!new Set(["tdd", "standard"]).has(config.development?.methodology)) {
365
427
  errors.push(`Invalid development.methodology: ${config.development?.methodology}`);
366
428
  }
367
429
 
@@ -19,7 +19,7 @@ import {
19
19
 
20
20
  export function commitMessageFromTask(task) {
21
21
  const clean = String(task || "")
22
- .replace(/\s+/g, " ")
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.includes(taskType) ? taskType : FALLBACK_TYPE;
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.includes(taskType) ? taskType : FALLBACK_TYPE;
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
  }
@@ -1,5 +1,4 @@
1
- import { readFileSync } from "node:fs";
2
- import { watch } from "node:fs";
1
+ import { readFileSync, watch } from "node:fs";
3
2
 
4
3
  const DEFAULT_INTERVAL_MS = 5000;
5
4
 
@@ -57,7 +57,7 @@ export function buildPipelineTracker(config, emitter) {
57
57
  };
58
58
 
59
59
  emitter.on("progress", (event) => {
60
- const match = event.type?.match(/^(\w+):(start|end)$/);
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}] ${event.message || event.type}`
132
- : event.message || event.type;
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);