karajan-code 2.5.0 → 2.6.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.
Files changed (111) hide show
  1. package/README.md +39 -4
  2. package/package.json +5 -2
  3. package/src/agents/aider-agent.js +1 -2
  4. package/src/agents/base-agent.js +63 -1
  5. package/src/agents/claude-agent.js +3 -4
  6. package/src/agents/codex-agent.js +1 -2
  7. package/src/agents/gemini-agent.js +1 -2
  8. package/src/agents/index.js +11 -2
  9. package/src/agents/opencode-agent.js +1 -2
  10. package/src/brain/decision-tracker.js +123 -0
  11. package/src/brain/decisor.js +243 -0
  12. package/src/brain/solomon-consult.js +171 -0
  13. package/src/budget/comparison.js +96 -0
  14. package/src/checks/binaries.js +123 -0
  15. package/src/checks/ci.js +105 -0
  16. package/src/checks/config-files.js +217 -0
  17. package/src/checks/dir-setup.js +63 -0
  18. package/src/checks/mcp-health.js +157 -0
  19. package/src/checks/node.js +61 -0
  20. package/src/checks/ports.js +110 -0
  21. package/src/checks/rtk.js +36 -0
  22. package/src/checks/runner.js +267 -0
  23. package/src/checks/skills.js +49 -0
  24. package/src/checks/sonar.js +67 -0
  25. package/src/checks/system.js +53 -0
  26. package/src/checks/tokens.js +96 -0
  27. package/src/checks/types.js +105 -0
  28. package/src/cli.js +29 -3
  29. package/src/commands/board.js +23 -0
  30. package/src/commands/doctor.js +130 -362
  31. package/src/commands/resume.js +1 -1
  32. package/src/commands/run.js +2 -1
  33. package/src/commands/skills.js +49 -0
  34. package/src/config/schema.js +222 -0
  35. package/src/config.js +32 -3
  36. package/src/guards/policy-resolver.js +8 -0
  37. package/src/hu/store.js +9 -0
  38. package/src/infrastructure/command-runner.js +44 -0
  39. package/src/infrastructure/environment.js +38 -0
  40. package/src/infrastructure/file-system-service.js +63 -0
  41. package/src/infrastructure/mocks.js +182 -0
  42. package/src/mcp/handlers/management-handlers.js +7 -2
  43. package/src/mcp/tools.js +10 -3
  44. package/src/orchestrator/config-init.js +16 -1
  45. package/src/orchestrator/flow-runner.js +2085 -0
  46. package/src/orchestrator/pipeline-context.js +17 -0
  47. package/src/orchestrator/preflight-checks.js +78 -4
  48. package/src/orchestrator/solomon-escalation.js +55 -0
  49. package/src/orchestrator/stages/stage-executor.js +155 -0
  50. package/src/orchestrator.js +19 -1923
  51. package/src/prompts/architect.js +2 -2
  52. package/src/prompts/coder.js +2 -2
  53. package/src/prompts/prompt-resolver.js +127 -0
  54. package/src/prompts/reviewer.js +2 -2
  55. package/src/roles/agent-role.js +9 -0
  56. package/src/roles/architect-role.js +3 -1
  57. package/src/roles/base-role.js +40 -2
  58. package/src/roles/coder-role.js +3 -1
  59. package/src/roles/security-role.js +12 -0
  60. package/src/roles/tester-role.js +11 -0
  61. package/src/session/journal/decisions-writer.js +200 -0
  62. package/src/session/journal/iteration-logger.js +194 -0
  63. package/src/session/journal/summary-writer.js +176 -0
  64. package/src/session/journal/tree-writer.js +164 -0
  65. package/src/skills/semantic-detector.js +147 -0
  66. package/src/skills/skill-detector.js +186 -8
  67. package/src/skills/skill-loader.js +131 -1
  68. package/src/skills/skills-cache.js +128 -0
  69. package/src/types/agent.js +55 -0
  70. package/src/types/config.js +114 -0
  71. package/src/types/hu.js +47 -0
  72. package/src/types/index.js +38 -0
  73. package/src/types/policy.js +43 -0
  74. package/src/types/session.js +74 -0
  75. package/src/types/solomon.js +87 -0
  76. package/src/types/stage.js +68 -0
  77. package/src/utils/display/event-handlers.js +389 -0
  78. package/src/utils/display/formatters.js +132 -0
  79. package/src/utils/display/header.js +48 -0
  80. package/src/utils/display/session-summary.js +108 -0
  81. package/src/utils/display/solomon.js +42 -0
  82. package/src/utils/port-check.js +45 -0
  83. package/src/utils/port-occupant.js +95 -0
  84. package/src/utils/provider-env.js +116 -0
  85. package/src/utils/with-timeout.js +42 -0
  86. package/templates/roles/architect/anthropic.md +65 -0
  87. package/templates/roles/architect/default.md +63 -0
  88. package/templates/roles/architect/google.md +52 -0
  89. package/templates/roles/architect/openai.md +51 -0
  90. package/templates/roles/architect/opencode.md +50 -0
  91. package/templates/roles/coder/anthropic.md +72 -0
  92. package/templates/roles/coder/default.md +69 -0
  93. package/templates/roles/coder/google.md +78 -0
  94. package/templates/roles/coder/openai.md +59 -0
  95. package/templates/roles/coder/opencode.md +49 -0
  96. package/templates/roles/planner/anthropic.md +50 -0
  97. package/templates/roles/planner/default.md +48 -0
  98. package/templates/roles/planner/google.md +66 -0
  99. package/templates/roles/planner/openai.md +46 -0
  100. package/templates/roles/planner/opencode.md +53 -0
  101. package/templates/roles/reviewer/anthropic.md +61 -0
  102. package/templates/roles/reviewer/default.md +62 -0
  103. package/templates/roles/reviewer/google.md +63 -0
  104. package/templates/roles/reviewer/openai.md +57 -0
  105. package/templates/roles/reviewer/opencode.md +42 -0
  106. package/templates/roles/solomon/anthropic.md +71 -0
  107. package/templates/roles/solomon/default.md +83 -0
  108. package/templates/roles/solomon/google.md +61 -0
  109. package/templates/roles/solomon/openai.md +53 -0
  110. package/templates/roles/solomon/opencode.md +55 -0
  111. package/src/utils/display.js +0 -669
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Shared check schema for doctor/preflight subsystem.
3
+ *
4
+ * A Check describes an environment requirement (binary present, port free,
5
+ * token configured, MCP reachable...). Each check can optionally remediate
6
+ * itself when it fails, using one of 4 strategies:
7
+ *
8
+ * - "auto" → fix without asking. Use for non-invasive, reversible changes
9
+ * (in-memory runtime overrides, starting existing services,
10
+ * creating files under ~/.karajan/, etc.)
11
+ * - "prompt" → ask user before fixing. Use for invasive changes that touch
12
+ * the user's system outside Karajan's scope (global npm install,
13
+ * writing kj.config.yml, `gh auth login`, etc.)
14
+ * - "manual" → cannot auto-fix, only report a hint (Node runtime upgrade,
15
+ * missing Docker, missing API key with no admin creds)
16
+ * - "none" → informational check, always OK (Karajan version, feature
17
+ * disabled by config)
18
+ */
19
+
20
+ /**
21
+ * @typedef {Object} CheckResult
22
+ * @property {boolean} ok - true if check passes
23
+ * @property {"fail"|"warn"|"info"} [severity] - relevant when !ok; default "fail"
24
+ * @property {string} detail - human-readable status
25
+ * @property {string} [fix] - remediation hint shown when manual or user declines
26
+ * @property {Object} [extra] - structured data consumed by remediate (e.g. occupant PID, host, roles)
27
+ */
28
+
29
+ /**
30
+ * @typedef {Object} RemediationContext
31
+ * @property {Object} config - resolved Karajan config
32
+ * @property {AbortSignal} [signal] - cancellation
33
+ * @property {Object} extra - check's CheckResult.extra
34
+ * @property {Object} logger - logger instance
35
+ */
36
+
37
+ /**
38
+ * @typedef {Object} RemediationResult
39
+ * @property {boolean} fixed - true if remediation succeeded
40
+ * @property {string} detail - what was done, human-readable
41
+ * @property {Object} [changes] - runtime config overrides to merge into the active session
42
+ */
43
+
44
+ /**
45
+ * @typedef {Object} Check
46
+ * @property {string} name - slug, unique across all checks (e.g. "node-version")
47
+ * @property {string} label - human label (e.g. "Node.js runtime")
48
+ * @property {"auto"|"prompt"|"manual"|"none"} strategy
49
+ * @property {(ctx: { config: Object }) => Promise<CheckResult>} detect
50
+ * @property {(ctx: RemediationContext) => Promise<RemediationResult>} [remediate]
51
+ * @property {string} [describe] - shown to user when strategy is "prompt"
52
+ * @property {(config: Object) => boolean} [applies] - if false, check is SKIPPED (lazy evaluation). Default: always applies.
53
+ */
54
+
55
+ /**
56
+ * @typedef {Object} CheckReport
57
+ * @property {string} name
58
+ * @property {string} label
59
+ * @property {"OK"|"FIXED"|"WARN"|"FAIL"|"SKIPPED"|"TIMEOUT"} status
60
+ * @property {"auto"|"prompt"|"manual"|"none"} strategy
61
+ * @property {string} detail - detect detail or remediate detail when FIXED
62
+ * @property {string} [fix] - remediation hint for FAIL/WARN
63
+ * @property {number} runMs - total time (detect + remediate + re-verify)
64
+ * @property {boolean} [cached] - future: served from cache
65
+ */
66
+
67
+ /**
68
+ * @typedef {Object} RunReport
69
+ * @property {CheckReport[]} checks
70
+ * @property {Object} overrides - merged runtime overrides from auto-remediations
71
+ * @property {number} totalMs
72
+ * @property {{ ok: number, fixed: number, warn: number, fail: number, skipped: number, timeout: number }} summary
73
+ */
74
+
75
+ /**
76
+ * Status constants.
77
+ */
78
+ export const STATUS = Object.freeze({
79
+ OK: "OK",
80
+ FIXED: "FIXED",
81
+ WARN: "WARN",
82
+ FAIL: "FAIL",
83
+ SKIPPED: "SKIPPED",
84
+ TIMEOUT: "TIMEOUT",
85
+ });
86
+
87
+ export const STRATEGY = Object.freeze({
88
+ AUTO: "auto",
89
+ PROMPT: "prompt",
90
+ MANUAL: "manual",
91
+ NONE: "none",
92
+ });
93
+
94
+ export const SEVERITY = Object.freeze({
95
+ FAIL: "fail",
96
+ WARN: "warn",
97
+ INFO: "info",
98
+ });
99
+
100
+ /**
101
+ * Whether the final status blocks the pipeline (for preflight).
102
+ */
103
+ export function isBlocking(status) {
104
+ return status === STATUS.FAIL || status === STATUS.TIMEOUT;
105
+ }
package/src/cli.js CHANGED
@@ -128,6 +128,10 @@ program
128
128
  .option("--no-smart-models", "Disable smart model selection")
129
129
  .option("--design", "Activate design refactoring mode (impeccable role applies design changes)")
130
130
  .option("--domain <text-or-path>", "Domain knowledge: inline text or path to .md file")
131
+ .option("--skills-mode <mode>", "Skill detection mode: auto|regex|semantic|none (default: auto)")
132
+ .option("--brain <mode>", "Brain decisor: on|off (default: on). When off, only legacy flags drive routing.")
133
+ .option("--skip-role <role...>", "Force one or more roles OFF regardless of triage (e.g. --skip-role tester security)")
134
+ .option("--force-role <role...>", "Force one or more roles ON regardless of triage")
131
135
  .option("--dry-run", "Show what would be executed without running anything")
132
136
  .option("--json", "Output JSON only (no styled display)")
133
137
  .option("-q, --quiet", "Show only stage status lines, suppress raw agent output (default)")
@@ -172,9 +176,22 @@ program
172
176
 
173
177
  program
174
178
  .command("doctor")
175
- .description("Check environment requirements")
176
- .action(async () => {
177
- await withConfig("doctor", {}, doctorCommand);
179
+ .description("Check environment requirements and auto-remediate when possible")
180
+ .option("--check-only", "Detect issues without applying fixes")
181
+ .option("-y, --yes", "Auto-confirm prompts for invasive remediations (CI mode)")
182
+ .option("--json", "Emit machine-readable JSON instead of human output")
183
+ .option("--verbose", "Include fix hints and timing for every check")
184
+ .action(async (flags) => {
185
+ const exitCode = await withConfig("doctor", {}, (ctx) =>
186
+ doctorCommand({
187
+ ...ctx,
188
+ checkOnly: !!flags.checkOnly,
189
+ yes: !!flags.yes,
190
+ json: !!flags.json,
191
+ verbose: !!flags.verbose,
192
+ })
193
+ );
194
+ if (Number.isInteger(exitCode)) process.exit(exitCode);
178
195
  });
179
196
 
180
197
  program
@@ -198,6 +215,15 @@ program
198
215
  await reportCommand(flags);
199
216
  });
200
217
 
218
+ program
219
+ .command("skills [action]")
220
+ .description("Manage the local OpenSkills cache (actions: list | clear-cache)")
221
+ .action(async (action) => {
222
+ const { skillsCommand } = await import("./commands/skills.js");
223
+ const exitCode = await skillsCommand({ action: action || "list" });
224
+ if (Number.isInteger(exitCode)) process.exit(exitCode);
225
+ });
226
+
201
227
  program
202
228
  .command("roles [subcommand] [role]")
203
229
  .description("List pipeline roles or show role template instructions")
@@ -115,6 +115,29 @@ export async function boardStatus(port = 4000) {
115
115
  };
116
116
  }
117
117
 
118
+ /**
119
+ * Render a highlighted cyan box with the HU Board URL + optional project name.
120
+ * Centralizes the banner used by both the init-time auto-start (flow-runner.js)
121
+ * and the post-planner auto-HU generation safety net so they stay in sync.
122
+ *
123
+ * @param {Object} params
124
+ * @param {string} params.url - "http://localhost:4000"
125
+ * @param {string} params.status - "started" | "already running"
126
+ * @param {string} [params.projectName] - optional project label
127
+ * @returns {string} ANSI-escaped box ready for console.log
128
+ */
129
+ export function renderBoardBanner({ url, status, projectName }) {
130
+ const title = projectName ? ` Project: \u001b[1m${projectName}\u001b[0m` : null;
131
+ const lines = [
132
+ "",
133
+ "\u001b[36m\u256d\u2500 HU Board \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256e",
134
+ `\u001b[36m\u2502\u001b[0m \u001b[1m${status}\u001b[0m \u001b[4m${url}\u001b[0m`,
135
+ ];
136
+ if (title) lines.push(`\u001b[36m\u2502\u001b[0m${title}`);
137
+ lines.push("\u001b[36m\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256f\u001b[0m", "");
138
+ return lines.join("\n");
139
+ }
140
+
118
141
  export async function boardCommand({ action = "start", port = 4000, logger }) {
119
142
  switch (action) {
120
143
  case "start": {