lv24-opencode-consilium 0.0.0-stage → 1.4.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 (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +511 -3
  3. package/bin/cli.js +19 -0
  4. package/bin/mcp.js +24 -0
  5. package/consilium.config.example.json +84 -0
  6. package/dist/agents.d.ts +79 -0
  7. package/dist/agents.d.ts.map +1 -0
  8. package/dist/agents.js +1051 -0
  9. package/dist/agents.js.map +1 -0
  10. package/dist/artifacts.d.ts +75 -0
  11. package/dist/artifacts.d.ts.map +1 -0
  12. package/dist/artifacts.js +464 -0
  13. package/dist/artifacts.js.map +1 -0
  14. package/dist/cli.d.ts +12 -0
  15. package/dist/cli.d.ts.map +1 -0
  16. package/dist/cli.js +1392 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/compat.d.ts +160 -0
  19. package/dist/compat.d.ts.map +1 -0
  20. package/dist/compat.js +419 -0
  21. package/dist/compat.js.map +1 -0
  22. package/dist/config.d.ts +112 -0
  23. package/dist/config.d.ts.map +1 -0
  24. package/dist/config.js +728 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/consensus.d.ts +73 -0
  27. package/dist/consensus.d.ts.map +1 -0
  28. package/dist/consensus.js +273 -0
  29. package/dist/consensus.js.map +1 -0
  30. package/dist/defaults.d.ts +34 -0
  31. package/dist/defaults.d.ts.map +1 -0
  32. package/dist/defaults.js +102 -0
  33. package/dist/defaults.js.map +1 -0
  34. package/dist/doctor.d.ts +27 -0
  35. package/dist/doctor.d.ts.map +1 -0
  36. package/dist/doctor.js +798 -0
  37. package/dist/doctor.js.map +1 -0
  38. package/dist/fallback.d.ts +50 -0
  39. package/dist/fallback.d.ts.map +1 -0
  40. package/dist/fallback.js +134 -0
  41. package/dist/fallback.js.map +1 -0
  42. package/dist/git.d.ts +28 -0
  43. package/dist/git.d.ts.map +1 -0
  44. package/dist/git.js +71 -0
  45. package/dist/git.js.map +1 -0
  46. package/dist/index.d.ts +100 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +653 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/mcp.d.ts +20 -0
  51. package/dist/mcp.d.ts.map +1 -0
  52. package/dist/mcp.js +1215 -0
  53. package/dist/mcp.js.map +1 -0
  54. package/dist/models.d.ts +97 -0
  55. package/dist/models.d.ts.map +1 -0
  56. package/dist/models.js +873 -0
  57. package/dist/models.js.map +1 -0
  58. package/dist/plugin.d.ts +59 -0
  59. package/dist/plugin.d.ts.map +1 -0
  60. package/dist/plugin.js +223 -0
  61. package/dist/plugin.js.map +1 -0
  62. package/dist/presets.d.ts +27 -0
  63. package/dist/presets.d.ts.map +1 -0
  64. package/dist/presets.js +86 -0
  65. package/dist/presets.js.map +1 -0
  66. package/dist/replay.d.ts +37 -0
  67. package/dist/replay.d.ts.map +1 -0
  68. package/dist/replay.js +103 -0
  69. package/dist/replay.js.map +1 -0
  70. package/dist/report.d.ts +28 -0
  71. package/dist/report.d.ts.map +1 -0
  72. package/dist/report.js +300 -0
  73. package/dist/report.js.map +1 -0
  74. package/dist/smart-experts.d.ts +44 -0
  75. package/dist/smart-experts.d.ts.map +1 -0
  76. package/dist/smart-experts.js +242 -0
  77. package/dist/smart-experts.js.map +1 -0
  78. package/dist/stream.d.ts +50 -0
  79. package/dist/stream.d.ts.map +1 -0
  80. package/dist/stream.js +219 -0
  81. package/dist/stream.js.map +1 -0
  82. package/dist/tool-run.d.ts +49 -0
  83. package/dist/tool-run.d.ts.map +1 -0
  84. package/dist/tool-run.js +143 -0
  85. package/dist/tool-run.js.map +1 -0
  86. package/dist/types.d.ts +352 -0
  87. package/dist/types.d.ts.map +1 -0
  88. package/dist/types.js +6 -0
  89. package/dist/types.js.map +1 -0
  90. package/dist/variants.d.ts +30 -0
  91. package/dist/variants.d.ts.map +1 -0
  92. package/dist/variants.js +111 -0
  93. package/dist/variants.js.map +1 -0
  94. package/dist/verify.d.ts +33 -0
  95. package/dist/verify.d.ts.map +1 -0
  96. package/dist/verify.js +80 -0
  97. package/dist/verify.js.map +1 -0
  98. package/dist/watch.d.ts +73 -0
  99. package/dist/watch.d.ts.map +1 -0
  100. package/dist/watch.js +350 -0
  101. package/dist/watch.js.map +1 -0
  102. package/docs/README.ru.md +508 -0
  103. package/docs/README.zh.md +196 -0
  104. package/docs/session-and-plugin.md +642 -0
  105. package/package.json +88 -6
  106. package/schema/config.schema.json +100 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LevapVeeskela
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,511 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # lv24-opencode-consilium
2
+
3
+ **Languages:** English · [Русский](docs/README.ru.md) · [中文](docs/README.zh.md)
4
+
5
+ > **Кратко по-русски.** Консилиум ИИ-экспертов для OpenCode V1 и V2: роли `arch`, `ux`, `ba`, `sec` параллельно отвечают на разных моделях, а председатель синтезирует итоговый план. Бесплатные модели подбираются и проверяются автоматически (`consilium init --free`). В комплекте: CLI `consilium`, MCP-сервер, нативный плагин OpenCode V2 (`consilium.run`), артефакты запусков с replay/diff, анализ согласия, HTML/PR-отчёты, watch-режим, git-hooks и варианты моделей.
6
+ >
7
+ > Установка: `npm install -g lv24-opencode-consilium`, затем `consilium doctor` и `consilium "ваша задача"`. Полная документация — [docs/README.ru.md](docs/README.ru.md).
8
+
9
+ A council of AI experts for [OpenCode](https://opencode.ai): several agent personas answer your task **in parallel on different models**, then a chair model synthesizes a final plan. Ships with a zero-config free-model bootstrap, a CLI, a library API, and an **MCP server** that works in any harness (Claude Desktop, Codex, Cursor, VS Code, custom agents).
10
+
11
+ ```
12
+ consilium "Review the authentication design"
13
+ arch → flint-40b-free
14
+ ux → inkling-2-small-free
15
+ ba → deepseek-v4.1-flash-free
16
+ sec → iceman-free
17
+ chair → beam-free ← synthesis
18
+ ```
19
+
20
+ ## Why
21
+
22
+ - **Different models = different blind spots.** One model often misses what another catches; the chair resolves disagreements.
23
+ - **Zero cost by default.** Discovers free, tool-capable models from public catalogs, ranks them, verifies they actually work in your region, and wires them into your config.
24
+ - **Works with what you already have.** Uses the OpenCode CLI (agents, auth, providers), not a parallel provider stack.
25
+ - **Works inside any harness.** The same engine is exposed as an MCP server over stdio.
26
+
27
+ ## Features
28
+
29
+ - Parallel experts with per-expert `agent` and `model` routing, bounded concurrency.
30
+ - Chair synthesis with configurable prompt template and per-expert text limits.
31
+ - Dynamic free-model discovery: `models.dev` + OpenRouter + curated offline fallback; cached 12 h.
32
+ - Quality ranking heuristic (context, tools, structured output, reasoning, recency, family prior, shadow price of the paid sibling).
33
+ - Optional real verification: each candidate gets a tiny probe request, region-blocked/unavailable models are dropped.
34
+ - Robust runner: prompt via stdin (no shell injection, no Windows 8 KB limit), `--standalone` isolation, retries with backoff, timeouts, cancellation, usage/cost accounting.
35
+ - `doctor` preflight, presets, git-diff review mode, clean JSON output.
36
+ - MCP tools: run the council, list agents, list free models, diagnose, bootstrap free models.
37
+ - TypeScript strict, zero runtime dependencies, Node >= 18.
38
+
39
+ ## Requirements
40
+
41
+ - Node.js **>= 18**
42
+ - [OpenCode CLI](https://opencode.ai) installed and authenticated (`npm install -g opencode-ai`), **V1 or V2**
43
+ - Optional: `OPENROUTER_API_KEY` to use OpenRouter's free models
44
+
45
+ ## OpenCode V1 and V2 compatibility
46
+
47
+ The package supports both OpenCode branches and picks the right config shape itself:
48
+
49
+ | Area | OpenCode V1 | OpenCode V2 |
50
+ | --- | --- | --- |
51
+ | `opencode.json` agents | `agent` + `prompt` | `agents` + `system` |
52
+ | MCP servers | `mcp.<name>` + `enabled` | `mcp.servers.<name>` + `disabled` |
53
+ | Commands | `command` + `subtask` | `commands` + `subagent` |
54
+ | Agent model on `run --agent` | applied from config | **ignored**, `--model` required |
55
+
56
+ In practice:
57
+
58
+ - **V1 shape is the safe default.** Both versions read it, so `consilium init --free` writes it unless you ask otherwise.
59
+ - **Native V2 agents** (`agents` + `system`) are written only with `consilium init --free --native-v2` or when the file already uses V2 keys. MCP registration is separate: `consilium mcp --install`.
60
+ - **Models are always passed explicitly** via `--model`, so V2 cannot silently fall back to the root model.
61
+ - **Agents are read from both sections.** `opencode.json(c)`, `.opencode/opencode.json(c)`, and parent directories are merged in OpenCode's own order (`.opencode` wins).
62
+ - **`RATE_LIMITED`** from V2 structured errors retries short limits (up to 30 s) and fails fast with the retry delay for long ones.
63
+ - **`doctor` checks compatibility**: CLI major, config flavor, `agent`/`agents` duplicates, V2-ignored fields, flat MCP entries.
64
+
65
+ One-command MCP registration (shape follows the installed OpenCode version):
66
+
67
+ ```bash
68
+ consilium mcp --install # ./opencode.json
69
+ consilium mcp --install --global # ~/.config/opencode/opencode.json
70
+ opencode mcp list # verify
71
+ ```
72
+
73
+ ## Install
74
+
75
+ ```bash
76
+ npm install -g lv24-opencode-consilium
77
+ # or run without installing:
78
+ npx -y lv24-opencode-consilium --help
79
+ ```
80
+
81
+ ## Quick start
82
+
83
+ ```bash
84
+ # 1. Check the environment (CLI, config, agents, models)
85
+ consilium doctor
86
+
87
+ # 2. Pick the strongest working free models and write the config
88
+ consilium init --free
89
+
90
+ # 3. Run the council
91
+ consilium "Design a rate limiter for a public API"
92
+ ```
93
+
94
+ `init --free`:
95
+
96
+ 1. downloads `https://models.dev/api.json` and `https://openrouter.ai/api/v1/models`;
97
+ 2. keeps only free (`cost = 0`), active, chat models with tool calling and >= 32K context;
98
+ 3. ranks them and probes the top candidates with a tiny request (unless `--no-verify`);
99
+ 4. writes the winning models into `opencode.json` (agents `arch`, `ux`, `ba`, `sec`, `consilium`) and `consilium.config.json`;
100
+ 5. never overwrites your existing agent models unless you pass `--force`.
101
+
102
+ Preview without writes:
103
+
104
+ ```bash
105
+ consilium init --free --dry-run
106
+ ```
107
+
108
+ Write native V2 agents (`agents` + `system`):
109
+
110
+ ```bash
111
+ consilium init --free --native-v2
112
+ ```
113
+
114
+ ## Free models
115
+
116
+ ```bash
117
+ consilium models # top 20 ranked models
118
+ consilium models --available # only providers you can use
119
+ consilium models --verify # probe the shown models with a real request
120
+ consilium models --refresh # ignore the 12 h cache
121
+ consilium models --json # machine-readable
122
+ ```
123
+
124
+ Sources and fallbacks:
125
+
126
+ | Source | What it gives |
127
+ | --- | --- |
128
+ | `https://models.dev/api.json` | Full catalog, cost/limits/capabilities, canonical links to paid siblings |
129
+ | `https://openrouter.ai/api/v1/models` | `:free` variants, context, `tools` support, expiry |
130
+ | Built-in curated list | Known-good OpenCode free models if a catalog rotates them out |
131
+
132
+ Cache: `%TEMP%/lv24-opencode-consilium/models-cache.json` (or `CONSILIUM_MODELS_CACHE`), TTL 12 h.
133
+
134
+ The `opencode-go` provider is no longer excluded wholesale: its free models (`*-free`, `iceman-contributor-free`, and similar) take part in ranking. Paid models of that provider, such as `opencode-go/muse-spark-1.3-contributor`, are not selected by `--free`; set them manually in `experts[].model` or `chair.model`.
135
+
136
+ Current recommended set (catalog as of 2026-11-08):
137
+
138
+ | Role | Model | Why |
139
+ | --- | --- | --- |
140
+ | arch | `opencode/flint-40b-free` | coding agent, structured output, 262k |
141
+ | ux | `opencode/inkling-2-small-free` | 1M context, multimodal, fast |
142
+ | ba | `opencode/deepseek-v4.1-flash-free` | reasoning + agentic coding, 200k |
143
+ | sec | `opencode/iceman-free` | newest reasoning model, 262k (stealth) |
144
+ | chair | `opencode/beam-free` | top score, 1M, structured, coding/agentic |
145
+
146
+ Free models rotate: `consilium init --free` re-checks the catalog and real responses. Stealth/alpha models (`iceman`, `crouton`) can disappear — `--refresh` will pick replacements.
147
+
148
+ Ranking (0-1.2) is transparent and deterministic: context window 30%, tool calling 20%, structured output 10%, reasoning 10%, recency 10%, output limit 10%, family prior 10%, paid-sibling "shadow price" 15%; alpha/preview/stealth penalties.
149
+
150
+ ## MCP server (any harness)
151
+
152
+ Start it over stdio:
153
+
154
+ ```bash
155
+ consilium mcp
156
+ # or directly:
157
+ consilium-mcp
158
+ ```
159
+
160
+ OpenCode V1/V2 — install into config (shape detected automatically):
161
+
162
+ ```bash
163
+ consilium mcp --install # ./opencode.json → mcp.servers.consilium or mcp.consilium
164
+ consilium mcp --install --global # global OpenCode config
165
+ ```
166
+
167
+ Claude Desktop (`claude_desktop_config.json`):
168
+
169
+ ```json
170
+ {
171
+ "mcpServers": {
172
+ "consilium": {
173
+ "command": "npx",
174
+ "args": ["-y", "lv24-opencode-consilium", "mcp"]
175
+ }
176
+ }
177
+ }
178
+ ```
179
+
180
+ Codex (`~/.codex/config.toml`):
181
+
182
+ ```toml
183
+ [mcp_servers.consilium]
184
+ command = "npx"
185
+ args = ["-y", "lv24-opencode-consilium", "mcp"]
186
+ ```
187
+
188
+ Any MCP client that supports stdio JSON-RPC 2.0 works. Logs go to **stderr**; stdout carries only the protocol.
189
+
190
+ ### MCP tools
191
+
192
+ | Tool | Arguments | Result |
193
+ | --- | --- | --- |
194
+ | `consilium_run` | `task` (required), `experts`, `chair`, `timeout_ms`, `format`, `preset`, `output_file` | Chair synthesis + expert opinions + JSON metadata (time, usage, models) |
195
+ | `consilium_list_agents` | — | Configured experts, models, chair, presets, config path |
196
+ | `consilium_free_models` | `limit`, `available_only`, `refresh` | Ranked free models table |
197
+ | `consilium_doctor` | — | Environment/config diagnostics |
198
+ | `consilium_init_free` | `apply`, `force`, `verify` | Proposal (default) or writes `opencode.json` + `consilium.config.json` |
199
+
200
+ MCP `consilium_init_free` is dry-run by default; pass `"apply": true` to write files. `consilium_run` reports live progress when the client sends a `progressToken`.
201
+
202
+ `consilium_run` also accepts `consensus`, `smart_experts`, `max_cost`, `fallback_models`, `session`, and `artifacts`. Its response includes `cost` and a consensus summary in the JSON metadata plus an `**Artifacts:**` line with the saved run path.
203
+
204
+ ## CLI reference
205
+
206
+ ```
207
+ consilium [options] <task>
208
+ consilium <task> - # read the task from stdin
209
+ consilium init [--free] [--dry-run] [--force] [--no-verify] [--native-v2]
210
+ consilium models [--available] [--verify] [--limit N] [--refresh] [--json]
211
+ consilium doctor
212
+ consilium mcp [--install] [--global]
213
+ consilium watch [--debounce <ms>] [task]
214
+ consilium hooks install|uninstall
215
+ ```
216
+
217
+ Flags:
218
+
219
+ | Flag | Meaning |
220
+ | --- | --- |
221
+ | `-c, --config <file>` | Config file (otherwise auto-discovers) |
222
+ | `-e, --experts a,b` | Subset of experts |
223
+ | `--chair <agent>` | Chair agent name |
224
+ | `--preset <name>` | `fast`, `deep`, `security`, `review`, `free` |
225
+ | `--expert-timeout`, `--chair-timeout` | Timeouts in ms (per attempt) |
226
+ | `-r, --retries <n>` | Retry count (0 = single attempt) |
227
+ | `-o, --output <file>` | Save the result (text/markdown/json by `-f`) |
228
+ | `--no-save` | Never write a file |
229
+ | `-f, --format <fmt>` | `text` (stdout), `markdown`, `json` (pure JSON on stdout) |
230
+ | `--diff [--staged] [--base <ref>]` | Append the current git diff to the task |
231
+ | `--task-file <file>` | Read the task from a file (`-` = stdin) |
232
+ | `--verify` / `--no-verify` | Probe models before selecting (`models` / `init --free`) |
233
+ | `--consensus` / `--no-consensus` | Lexical expert-agreement analysis (term overlap, Jaccard); compact summary goes into the chair prompt, full report into the result |
234
+ | `--smart-experts` | Heuristically pick 2–3 relevant roles from the task/diff (dropped roles are logged) |
235
+ | `--max-cost <usd>` | Cost limit in USD; when exceeded before the chair starts, it is skipped (`COST_LIMIT`, partial result with consensus) |
236
+ | `--fallback-models a,b` | Fallback models: on `RATE_LIMITED` / `MODEL_UNAVAILABLE` / `EMPTY_RESPONSE` the same expert is retried on the next model (chain capped at 2) |
237
+ | `--session <id>` | Base OpenCode session id; each agent gets its own `ses_<base>-<agent>` (parallel agents never share a session) |
238
+ | `--artifacts` / `--no-artifacts` | Save / don't save run artifacts (off by default) |
239
+ | `--artifacts-dir <path>` | Save artifacts to a custom directory (instead of `.consilium/runs/<id>/`) |
240
+ | `--replay <id>` | Rerun a saved run (restores the chair agent/model, expert models, and the artifact's consensus/smartExperts/fallbackModels/session flags) |
241
+ | `--report <format>` | Report after the run: `html`, `pr`, `markdown` (`markdown` = PR variant) |
242
+ | `--report-file <file>` | Write the report to a file (`.html` → html, `.md` → pr; without a file prints to stdout, except with `-f json`) |
243
+ | `--variant <name>` | Model variant for all agents (`provider/model` → `provider/model#variant`); invalid variant exits 2 |
244
+ | `--debounce <ms>` | Watch-mode debounce delay (default 400) |
245
+ | `watch [--debounce <ms>] [task]` | Watch the project and rerun the council on changes (until Ctrl+C) |
246
+ | `hooks install\|uninstall` | Install/remove a git pre-commit hook (staged review before commit) |
247
+ | `--diff-runs <a> <b>` | Print a markdown comparison of two saved runs |
248
+ | `--native-v2` | Write native V2 config (`agents`/`system`) |
249
+ | `--install`, `--global` | Register the MCP server in the project or global config |
250
+ | `-s, --silent` | Only the final result |
251
+ | `-V, --verbose` | Raw progress events |
252
+ | `-v, --version`, `-h, --help` | Version / help |
253
+
254
+ Exit codes: `0` success, `1` run failed, `2` usage error.
255
+
256
+ Examples:
257
+
258
+ ```bash
259
+ consilium -e arch,sec "Threat-model the file upload endpoint"
260
+ consilium --preset deep "Design the migration plan"
261
+ git diff --staged | consilium - --diff "Review these changes"
262
+ consilium -f json "..." > council.json
263
+ consilium --smart-experts --consensus "Design the subscriptions DB schema"
264
+ consilium --artifacts --max-cost 0.5 "Design the migration plan"
265
+ consilium --replay 2026-11-08-abc123
266
+ consilium --diff-runs 2026-11-08-abc123 2026-11-08-def456
267
+ consilium --report pr --report-file review.md "Review the current changes"
268
+ consilium --variant high "Design the subscriptions DB schema"
269
+ consilium watch --debounce 500 "Review the current changes"
270
+ consilium hooks install
271
+ ```
272
+
273
+ ## Analysis, artifacts, and cost
274
+
275
+ `--consensus` computes lexical expert agreement: shared significant terms (Jaccard, RU+EN stopwords) per pair, an average score, and an `agreement` level (`high`/`medium`/`low`). This is a deterministic count over answer texts, not an LLM judgement. A compact summary is injected into the chair prompt; the full report is appended to the result and stored in `metadata.consensus` (`agreement`, `averageSimilarity`, `pairs`, `sharedTerms`, `uniqueTerms`).
276
+
277
+ `--smart-experts` picks 2–3 relevant roles with a heuristic (arch/ux/ba/sec lexicons, RU+EN) over the task and diff; dropped roles are logged to progress. The selection is stored in `metadata.smartExperts`.
278
+
279
+ `--max-cost <usd>` tracks accumulated expert+chair cost. When the limit is exceeded before the chair starts, the chair is skipped: a partial result with expert opinions and consensus is returned with `errorCode: COST_LIMIT`. The breakdown lives in `metadata.cost` (`limit`/`spent`/`exceeded`/`byAgent`); `metadata.costExceeded` is added on overrun.
280
+
281
+ `--fallback-models a,b` sets spare models: on `RATE_LIMITED`, `MODEL_UNAVAILABLE`, or `EMPTY_RESPONSE` the same expert is retried on the next model in the chain (max 2 substitutions per expert), usage is summed. The list is stored in `metadata.fallbackModels`.
282
+
283
+ Artifacts are plain files, no database. `--artifacts` saves a run to `.consilium/runs/<id>/`: `run.json` (task, expert answers, models, usage, consensus), `report.md` (readable report), and `experts/<agent>.md` (each expert's answer). `--artifacts-dir <path>` changes the directory, `--no-artifacts` disables saving. The id and directory are visible in `metadata.artifacts: { id, dir }`. `consilium --replay <id>` reruns a saved run (restores the chair agent/model, expert models, and the artifact's consensus/smartExperts/fallbackModels/session flags); `consilium --diff-runs <a> <b>` prints a markdown comparison of two runs.
284
+
285
+ `--session <id>` sets the base OpenCode session id: the chair continues it as-is, and each expert gets its own `ses_<base>-<agent>` (OpenCode requires the `ses_` prefix). Parallel agents never share one session — otherwise some prompts are lost (see `docs/session-and-plugin.md`). Unknown agents from `opencode.json` are detected and run on the default agent with a separate `ses_<base>-default-<agent>` session instead of polluting someone else's session. The flag does not hide sessions from lists: archived sessions still show up in `opencode session list`.
286
+
287
+ ## Reports, watch, and git hooks
288
+
289
+ ```bash
290
+ # HTML report to a file / PR markdown to stdout
291
+ consilium --report html --report-file report.html "Review the current changes"
292
+ consilium --report pr "Review the current changes"
293
+
294
+ # --report-file infers the format itself: .html → html, .md → pr
295
+ # Without --report-file the report goes to stdout, except with -f json (then --report-file is required)
296
+ consilium --report-file notes.md "Design the subscriptions DB schema"
297
+
298
+ # Rerun on file changes (ignores .git/node_modules/dist/.consilium/coverage/*.tmp/*.log,
299
+ # 400 ms debounce, the current git diff is appended to the task)
300
+ consilium watch "Review the current changes"
301
+ consilium watch --debounce 800
302
+
303
+ # Pre-commit hook: reviews staged changes before every git commit and blocks the commit on failure
304
+ consilium hooks install
305
+ consilium hooks uninstall # removes only the managed block, leaves the rest of the hook alone
306
+ ```
307
+
308
+ The PR report is GitHub-comment markdown with an `<!-- consilium:report -->` marker and collapsible `<details>` blocks of expert opinions; the HTML report is a self-contained file with escaped text. The hook writes only its own block (`# >>> consilium >>>` … `# <<< consilium <<<`) into the git hooks directory (`git rev-parse --git-path hooks`: `.git/hooks`, `core.hooksPath`, worktrees) and preserves the rest.
309
+
310
+ ## OpenCode V2 plugin
311
+
312
+ A native plugin that runs the council **inside the OpenCode V2 TUI** without MCP or an external CLI — via the `consilium.run` tool. It does not work in OpenCode V1 (the V1 plugin API is incompatible).
313
+
314
+ Register in `opencode.json` (V2):
315
+
316
+ ```json
317
+ {
318
+ "plugins": [{ "package": "lv24-opencode-consilium" }]
319
+ }
320
+ ```
321
+
322
+ The package publishes the server part as `./server` (`dist/plugin.js`); the plugin has no runtime dependencies (`@opencode/plugin` is needed only for types at build time). The tool accepts `task`, `experts`, `chair`, `timeout_ms`, `consensus`, `smart_experts`, `max_cost`, `fallback_models`, `session`, `artifacts`, `preset`.
323
+
324
+ When to use what:
325
+
326
+ | Way | When |
327
+ | --- | --- |
328
+ | Plugin (`consilium.run`) | Working inside the OpenCode V2 TUI, advice needed right in the conversation |
329
+ | MCP server | External harnesses (Claude Desktop, Codex, Cursor, VS Code, custom agents) |
330
+ | CLI | Terminal, scripts, CI, hooks, watch |
331
+
332
+ ## Presets
333
+
334
+ | Preset | Experts | Behaviour |
335
+ | --- | --- | --- |
336
+ | `fast` | arch, sec | 3 min expert timeout, no retries |
337
+ | `deep` | all four | doubled timeouts, retries enabled |
338
+ | `security` | sec, arch, ba | security-focused review |
339
+ | `review` | arch, sec, ux | code review |
340
+ | `free` | all four | for a free-model bootstrap |
341
+
342
+ ## Configuration
343
+
344
+ Config is discovered in this order (cwd): `consilium.config.json`, `consilium.json`, `.consiliumrc`, `.consiliumrc.json`. Use `-c` for an explicit path. JSONC comments are allowed in `opencode.json`/`opencode.jsonc`.
345
+
346
+ Minimal example:
347
+
348
+ ```json
349
+ {
350
+ "experts": [
351
+ { "name": "arch", "model": "opencode/flint-40b-free" },
352
+ { "name": "sec", "model": "opencode/iceman-free" }
353
+ ],
354
+ "chair": {
355
+ "agent": "consilium",
356
+ "model": "opencode/beam-free"
357
+ },
358
+ "retry": { "maxConcurrency": 3 }
359
+ }
360
+ ```
361
+
362
+ Key options:
363
+
364
+ | Key | Default | Notes |
365
+ | --- | --- | --- |
366
+ | `experts[].model` | — | `provider/model`; passed as `--model`, overrides the agent's model |
367
+ | `chair.model` | — | Chair model override |
368
+ | `timeouts.expert` / `.chair` | 300000 / 600000 | Per attempt, ms |
369
+ | `retry.expertRetries` / `.chairRetries` | 1 | `0` = single attempt |
370
+ | `retry.jitter` | `false` | Randomized retry delay (50–100%) so experts don't hit the limit together |
371
+ | `retry.maxConcurrency` | 3 | 1–8 parallel agents |
372
+ | `output.file` | `false` | `false` disables saving; a string enables it |
373
+ | `standalone` | `true` | `--standalone` private server; avoids port conflicts when OpenCode is already running |
374
+ | `autoApprove` | `false` | `--auto`; only enable if you trust the agents/tools |
375
+ | `autoDiscoverAgents` | `true` | Reuse agents from `opencode.json` |
376
+ | `artifacts` | `false` | `true` saves to `.consilium/runs/<id>/`; a string sets a custom directory |
377
+ | `consensus` | `false` | Lexical expert-agreement analysis |
378
+ | `smartExperts` | `false` | Heuristically pick 2–3 roles for the task |
379
+ | `maxCost` | — | Cost limit in USD (number >= 0); unset means no limit |
380
+ | `fallbackModels` | — | Array of `provider/model` strings for model-error retries |
381
+ | `session` | — | Base OpenCode session id (non-empty string) |
382
+ | `report` | — | Report format: `html`, `pr`, `markdown` |
383
+ | `reportFile` | — | Report file path (`.html`/`.md` extension picks the format) |
384
+ | `variant` | - | Model variant for models without `#variant` (explicit variants win) |
385
+ | `debounceMs` | 400 | Watch-mode delay, ms (integer >= 0) |
386
+ | `opencodePath` | `opencode` | Custom CLI path |
387
+ | `cwd` | current | Working directory for OpenCode |
388
+
389
+ Full schema: [`schema/config.schema.json`](schema/config.schema.json); example: [`consilium.config.example.json`](consilium.config.example.json).
390
+
391
+ ## Library API
392
+
393
+ ```ts
394
+ import { Consilium, runConsilium, fetchFreeModels, selectCouncilModels } from 'lv24-opencode-consilium';
395
+
396
+ const council = new Consilium();
397
+ council.onProgress(event => console.error(event.type, event.agent ?? ''));
398
+
399
+ const result = await council.run('Design a cache invalidation strategy');
400
+ console.log(result.text); // chair synthesis
401
+ console.log(result.usage?.cost); // total cost (0 for free models)
402
+
403
+ // one-shot
404
+ const oneShot = await runConsilium('...'); // returns ConsiliumResult
405
+ console.log(oneShot.text);
406
+
407
+ // discover + pick models
408
+ const { models } = await fetchFreeModels({ includeUnavailable: true });
409
+ const top = selectCouncilModels(models, 5);
410
+ ```
411
+
412
+ `Consilium` instances are reusable: `run()` can be called again after a completed, failed, or cancelled run. `cancel()` stops all child processes of the current run.
413
+
414
+ ## How it works
415
+
416
+ For every expert and the chair, Consilium spawns:
417
+
418
+ ```
419
+ opencode run --standalone --format json [--auto] [--agent=NAME] [--model=provider/model]
420
+ ```
421
+
422
+ The prompt is written to the child's **stdin** (UTF-8), so arbitrary task text is safe and never hits shell/command-line limits. NDJSON events are decoded incrementally (`text`, `step_finish` usage/cost, `error` with `type`/`status`/`retryAfterMs`). The model is always passed as `--model` so behavior is identical on V1 and V2, where `--agent` does not apply the configured agent model. Exit codes, stderr tails, and structured errors are reported with typed `errorCode`s (`RATE_LIMITED`, `MODEL_UNAVAILABLE`, `AGENT_NOT_FOUND`, ...). If an agent name is missing in your OpenCode config, the call is retried once with the same model and the default agent; the run keeps working even without persona agents.
423
+
424
+ ## Security
425
+
426
+ - Task text is never interpolated into a shell command; it is passed via stdin.
427
+ - Agent names and model IDs are validated before use.
428
+ - `--auto` (auto-approve permissions) is **off** by default.
429
+ - `--standalone` isolates the child server; no port takeover.
430
+ - API keys are never printed or written by Consilium; `doctor` only checks whether expected environment variables are present, and OpenCode handles auth.
431
+ - `doctor` warns about missing keys and risky configuration.
432
+
433
+ ## Troubleshooting
434
+
435
+ | Symptom | Fix |
436
+ | --- | --- |
437
+ | `OpenCode CLI не найден` | `npm install -g opencode-ai` or set `opencodePath` |
438
+ | `Model unavailable` | Model rotated out/region-blocked; run `consilium models --verify --refresh` |
439
+ | `Agent not found` | Persona agent missing; Consilium falls back to the default agent + your model. Add agents via `consilium init --free` |
440
+ | Timeouts | Free models can be slow; raise `--expert-timeout` or use `--preset fast` |
441
+ | `RATE_LIMITED` / 429 | Free-model quota exhausted; the error shows the retry delay. Switch the model/provider |
442
+ | Agent model ignored on V2 | Consilium already passes `--model`; run `consilium doctor` (the `opencode-v2-compat` check) |
443
+ | `COST_LIMIT` (`--max-cost` exceeded) | Chair skipped by design; expert opinions and consensus are in the partial result, spend in `metadata.cost.byAgent`. Raise the limit or drop the flag |
444
+ | Fallbacks still hit 429 | Spare models often share the same free quotas; switch providers or wait for the retry delay in the error |
445
+ | Sessions pile up in `session list` | By design: each agent owns a session and `--session` does not hide them (`--archived` doesn't either). Clean up with `opencode session delete <id>` |
446
+ | `replay` can't find the id | Ids resolve under `.consilium/runs/`; check the directory or pass that run's `--artifacts-dir` |
447
+ | MCP server missing on V2 | Flat `mcp.<name>` is ignored; run `consilium mcp --install --force` |
448
+ | `Managed service port ... in use` | Keep `standalone: true` (default) |
449
+ | Empty result | `consilium doctor`, then rerun with `-V` |
450
+
451
+ ## What's next (feature ideas)
452
+
453
+ Remaining ideas (1.3.0 shipped artifacts, consensus, smart-experts, model fallback, `--max-cost`, `--session`; 1.4.0 shipped reports, model variants, `watch`, git hooks, and the native V2 plugin):
454
+
455
+ | Idea | Value | Size |
456
+ | --- | --- | --- |
457
+ | `consilium` slash command for the TUI | Invoke the council with one command inside OpenCode | S |
458
+ | Report export to ticket systems | Ready-made artifact for Jira/Linear | S |
459
+
460
+ ## 1.4.1 changes
461
+
462
+ - npm package renamed to **`lv24-opencode-consilium`** (npm cannot rename in place; the old `opencode-consilium@1.0.2` stays in the registry and is deprecated).
463
+ - The npm page now shows this `README.md`; Russian and Chinese translations moved to `docs/README.ru.md` and `docs/README.zh.md` so they no longer compete for npm's single readme slot.
464
+ - No functional changes since 1.4.0.
465
+
466
+ ## 1.4.0 changes
467
+
468
+ - Reports: `--report html|pr|markdown`, `--report-file <path>` (`.html` → html, `.md` → pr; without a file prints to stdout, except with `-f json`); `renderHtmlReport` (self-contained escaped HTML), `renderPrMarkdown` (GitHub comment with an `<!-- consilium:report -->` marker and `<details>` blocks), `renderReport`.
469
+ - `--variant high`: appends `#high` to expert and chair models; an invalid variant exits 2. Config key `variant`.
470
+ - `consilium watch [--debounce <ms>] [task]`: watches the project (ignores `.git`/`node_modules`/`dist`/`.consilium`/`coverage`/`*.tmp`/`*.log`), debounces 400 ms, appends `git diff`, reruns until Ctrl+C.
471
+ - `consilium hooks install`: writes a managed pre-commit block (`# >>> consilium >>>` … `# <<< consilium <<<`) that runs `npx -y lv24-opencode-consilium --staged -s "Ревью staged-изменений" || exit 1` on every `git commit`; preserves existing hook content; `uninstall` removes only its block.
472
+ - Native OpenCode V2 plugin: server part `./server` → `dist/plugin.js`, registration `{"plugins": [{"package": "lv24-opencode-consilium"}]}`, a `consilium.run` tool (task, experts, chair, timeout_ms, consensus, smart_experts, max_cost, fallback_models, session, artifacts, preset). No runtime dependencies; `@opencode/plugin` is only needed for types. V2 only, does not work in V1.
473
+ - `--replay <id>` now restores the chair agent/model, expert models, and the artifact's consensus/smartExperts/fallbackModels/session flags (previously models only).
474
+ - New config keys: `report`, `reportFile`, `variant`, `debounceMs` (schema updated).
475
+ - 224 tests; OpenCode V1/V2 compatibility unchanged.
476
+
477
+ ## 1.3.0 changes
478
+
479
+ - Run artifacts: `--artifacts` / `--artifacts-dir <path>` / `--no-artifacts` save runs to `.consilium/runs/<id>/` (`run.json`, `report.md`, `experts/<agent>.md`); `consilium --replay <id>` reruns a saved run, `consilium --diff-runs <a> <b>` prints a markdown comparison.
480
+ - `--consensus` / `--no-consensus`: lexical agreement analysis (Jaccard, RU+EN stopwords); summary into the chair prompt, full report into the result and `metadata.consensus`.
481
+ - `--smart-experts`: heuristic role selection for the task/diff (2 by default, max 3, dropped roles logged); stored in `metadata.smartExperts`.
482
+ - `--max-cost <usd>`: cost tracker; when exceeded before the chair, the chair is skipped (`errorCode: COST_LIMIT`, partial result with consensus); details in `metadata.cost`.
483
+ - `--fallback-models a,b`: retry the same expert on a fallback model on `RATE_LIMITED` / `MODEL_UNAVAILABLE` / `EMPTY_RESPONSE` (chain capped at 2, usage summed).
484
+ - `--session <id>`: the chair continues the base session, each expert gets its own `ses_<base>-<agent>`; unknown agents run on the default agent with `ses_<base>-default-<agent>`.
485
+ - MCP `consilium_run`: new `consensus`, `smart_experts`, `max_cost`, `fallback_models`, `session`, `artifacts` args; response includes `cost`, a consensus summary, and an `**Artifacts:**` line.
486
+ - New config keys: `artifacts`, `consensus`, `smartExperts`, `maxCost`, `fallbackModels`, `session` (schema updated).
487
+ - 149 tests; OpenCode V1/V2 compatibility unchanged.
488
+
489
+ ## 1.2.0 changes
490
+
491
+ - OpenCode V2 compatibility while keeping V1 support: reads `agent` and `agents`, `.opencode/opencode.json(c)`, parent directories, and merges config layers in OpenCode's order.
492
+ - The agent model is passed via `--model`, so V2 no longer loses it with `--agent`.
493
+ - `consilium mcp --install [--global]` writes `mcp.servers` for V2 and `mcp.<name>` for V1, preserving an existing entry's `environment`/`cwd`/`timeout`.
494
+ - `init --free --native-v2` writes native V2 agents; duplicate `agent`/`agents` entries are updated together. Agents with V1-only restrictions (`tools`, `permission`, `temperature`) are not migrated automatically, to avoid losing them.
495
+ - `opencodeConfigPath` is no longer set by default: discovery works out of the box, and a missing configured path warns and falls back.
496
+ - `RATE_LIMITED` + `retryAfterMs` from V2 events: short limits are retried, long ones fail fast with the retry time.
497
+ - Retry jitter (`retry.jitter`), resilient decoder (`properties`, delta text), `opencode-v2-compat` doctor check.
498
+ - 81 test, including the new `test/compat.test.mjs` (149 as of 1.3.0).
499
+
500
+ ## Development
501
+
502
+ ```bash
503
+ npm install
504
+ npm run build # tsc
505
+ npm test # build + node:test (224 tests)
506
+ npm run typecheck # tsc --noEmit
507
+ ```
508
+
509
+ ## License
510
+
511
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @file Точка входа CLI для consilium
5
+ */
6
+
7
+ import('../dist/cli.js')
8
+ .then(async (module) => {
9
+ const code = await module.main(process.argv.slice(2));
10
+ process.exitCode = code;
11
+ })
12
+ .catch((error) => {
13
+ const message = error instanceof Error ? error.message : String(error);
14
+ console.error('❌ Ошибка запуска CLI:', message);
15
+ if (message.includes('Cannot find module')) {
16
+ console.error(' Похоже, проект не собран. Выполните: npm run build');
17
+ }
18
+ process.exit(1);
19
+ });
package/bin/mcp.js ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from 'node:fs';
4
+
5
+ function readVersion() {
6
+ try {
7
+ const content = readFileSync(new URL('../package.json', import.meta.url), 'utf-8');
8
+ const parsed = JSON.parse(content);
9
+ return typeof parsed.version === 'string' ? parsed.version : '0.0.0';
10
+ } catch {
11
+ return '0.0.0';
12
+ }
13
+ }
14
+
15
+ import('../dist/mcp.js')
16
+ .then(({ startMcpServer }) => {
17
+ const running = startMcpServer({ version: readVersion() });
18
+ console.error('lv24-opencode-consilium MCP server running on stdio');
19
+ return running;
20
+ })
21
+ .catch((error) => {
22
+ console.error('MCP server failed:', error);
23
+ process.exit(1);
24
+ });
@@ -0,0 +1,84 @@
1
+ {
2
+ "$schema": "./schema/config.schema.json",
3
+ "version": "1.4.1",
4
+
5
+ "experts": [
6
+ {
7
+ "name": "arch",
8
+ "model": "opencode/flint-40b-free",
9
+ "enabled": true,
10
+ "priority": 1,
11
+ "timeout": 300000,
12
+ "retries": 1,
13
+ "prompt": "Как архитектор, проанализируй задачу кратко (3-5 предложений): ${task}\nНе вызывай инструменты — ответь только текстом."
14
+ },
15
+ {
16
+ "name": "ux",
17
+ "model": "opencode/inkling-2-small-free",
18
+ "enabled": true,
19
+ "priority": 2,
20
+ "prompt": "Как UX-специалист, оцени задачу с точки зрения пользователя (3-5 предложений): ${task}\nНе вызывай инструменты — ответь только текстом."
21
+ },
22
+ {
23
+ "name": "ba",
24
+ "model": "opencode/deepseek-v4.1-flash-free",
25
+ "enabled": true,
26
+ "priority": 3,
27
+ "prompt": "Как бизнес-аналитик, оцени ценность и риски (3-5 предложений): ${task}\nНе вызывай инструменты — ответь только текстом."
28
+ },
29
+ {
30
+ "name": "sec",
31
+ "model": "opencode/iceman-free",
32
+ "enabled": true,
33
+ "priority": 4,
34
+ "prompt": "Как эксперт по безопасности, проанализируй риски (3-5 предложений): ${task}\nНе вызывай инструменты — ответь только текстом."
35
+ }
36
+ ],
37
+
38
+ "chair": {
39
+ "agent": "consilium",
40
+ "model": "opencode/beam-free",
41
+ "timeout": 600000,
42
+ "maxExpertTextLength": 3000
43
+ },
44
+
45
+ "excludedAgents": [
46
+ "build",
47
+ "plan",
48
+ "compaction",
49
+ "summary",
50
+ "title",
51
+ "explore",
52
+ "general",
53
+ "consilium"
54
+ ],
55
+
56
+ "timeouts": {
57
+ "expert": 300000,
58
+ "chair": 600000,
59
+ "shutdown": 5000
60
+ },
61
+
62
+ "retry": {
63
+ "expertRetries": 1,
64
+ "chairRetries": 1,
65
+ "delay": 1000,
66
+ "exponentialBackoff": true,
67
+ "maxConcurrency": 3
68
+ },
69
+
70
+ "output": {
71
+ "file": false,
72
+ "format": "markdown",
73
+ "progress": true,
74
+ "logLevel": "info"
75
+ },
76
+
77
+ "standalone": true,
78
+ "autoApprove": false,
79
+ "autoDiscoverAgents": true,
80
+
81
+ "artifacts": false,
82
+ "consensus": false,
83
+ "smartExperts": false
84
+ }