@serkanalgur/opencode-nexus 2.6.0 → 2.8.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 (4) hide show
  1. package/README.md +148 -40
  2. package/dist/index.js +4628 -218
  3. package/dist/tui.js +266 -52
  4. package/package.json +3 -4
package/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@serkanalgur/opencode-nexus?style=flat-square&color=6366f1)](https://www.npmjs.com/package/@serkanalgur/opencode-nexus)
6
6
  [![npm downloads](https://img.shields.io/npm/dw/@serkanalgur/opencode-nexus?style=flat-square&color=22c55e)](https://www.npmjs.com/package/@serkanalgur/opencode-nexus)
7
+ [![stars](https://img.shields.io/github/stars/serkanalgur/opencode-nexus?style=flat-square&color=f59e0b)](https://github.com/serkanalgur/opencode-nexus/stargazers)
7
8
  [![license](https://img.shields.io/npm/l/@serkanalgur/opencode-nexus?style=flat-square&color=8b5cf6)](https://github.com/serkanalgur/opencode-nexus/blob/main/LICENSE)
8
9
  [![opencode](https://img.shields.io/badge/OpenCode-V2-6366f1?style=flat-square)](https://opencode.ai)
9
10
  [![typescript](https://img.shields.io/badge/TypeScript-5.5+-3178c6?style=flat-square)](https://www.typescriptlang.org/)
@@ -30,17 +31,17 @@ OpenCode Nexus is an agent orchestration plugin for [OpenCode V2](https://openco
30
31
  | **DAG Execution** | Tasks are parallelized based on dependency graphs with priority queuing |
31
32
  | **Cost-Aware Routing** | Scores models by quality/cost/speed, selects optimal per task complexity |
32
33
  | **Self-Healing** | Retries with exponential backoff, context transfer, escalation policies |
33
- | **Web Dashboard** | Real-time monitoring via HTTP + WebSocket server on port 4747 |
34
+ | **Web Dashboard** | A live view of sessions, agents, tasks, costs and config, served over HTTP + WebSocket (default port 4747) — started on request from `/nexus-dashboard` or the agent, never automatically |
34
35
  | **TUI Dashboard** | Monitor agents, budget, and config from the terminal |
35
36
  | **Team Mode** | Lead agent orchestrates specialist agents in parallel |
36
37
  | **Todo & Goal Tracking** | Enforce task completion, persist objectives across sessions |
37
38
  | **Persistent Memory** | SQLite-backed memory store with TTL and search |
38
39
  | **Learning Module** | Pattern recognition from failures, confidence scoring |
39
40
  | **JSONC Config** | Read/write project and global config files with comments |
40
- | **LSP Integration** | Auto-enabled for TypeScript, Python, Go, and 30+ languages |
41
+ | **OpenCode LSP opt-in** | On startup, inserts `"lsp": true` into your global `opencode.jsonc` if it isn't already there. That is the whole of it — Nexus does not read LSP state, manage servers, or report anything about them |
41
42
  | **AST-Grep** | Pattern-aware code search and rewriting |
42
43
  | **Security Scanning** | Automated secrets and vulnerability detection |
43
- | **Slash Commands** | `/nexus`, `/nexus web`, `/nexus review`, and more |
44
+ | **Slash Commands** | `/nexus`, `/nexus-dashboard`, `/nexus-web`, `/nexus-overview`, `/nexus-config`, `/nexus-model`, `/nexus-status`, `/nexus-reset` |
44
45
 
45
46
  ---
46
47
 
@@ -105,11 +106,11 @@ Use nexus.goal.set with description="Build complete auth system"
105
106
  ### 3. Use Slash Commands
106
107
 
107
108
  ```
108
- /nexus # Open full configuration
109
- /nexus web # Start web dashboard (open http://localhost:4747)
110
- /nexus review # Quick code review
111
- /nexus fix # Quick fix for last error
112
- /nexus explain # Explain last change
109
+ /nexus # Open full configuration dialog
110
+ /nexus dashboard # Start the web dashboard and open it in your browser
111
+ /nexus status # Show the config summary
112
+ /nexus model coder # Pick the model for a role
113
+ /nexus reset # Reset configuration to defaults
113
114
  ```
114
115
 
115
116
  ---
@@ -146,35 +147,109 @@ Failed tasks follow a 4-step escalation chain:
146
147
 
147
148
  ### Web Dashboard
148
149
 
149
- Real-time monitoring via embedded HTTP + WebSocket server on port 4747.
150
+ A live view of the orchestrator, served by an HTTP + WebSocket server on port 4747 (`127.0.0.1`).
150
151
 
151
- **How to start:**
152
+ **Nothing is listening until you ask for it.** The server is not started at
153
+ startup, and no command starts it implicitly. The start has to happen in the
154
+ OpenCode *server* process, next to the orchestrator that feeds it, and there are
155
+ two ways to reach it:
152
156
 
153
- 1. Ask the agent to start the dashboard:
154
- ```
155
- Use nexus.dashboard.start with port=4747
156
- ```
157
+ ```
158
+ /nexus dashboard [port] [host] # from the TUI — starts it and opens it
159
+ Ask the agent: "start the nexus dashboard"
160
+ ```
161
+
162
+ The TUI command submits `/nexus dashboard [port] [host]` to that server process,
163
+ whose prompt hook routes it to the orchestrator; the agent's route calls
164
+ `nexus.dashboard.start(port=4747, host="127.0.0.1")` directly. Both end at the
165
+ same start, and both print the URL it bound. **If the start fails, nothing is
166
+ listening and no browser is opened** — the reason is reported, and no URL is
167
+ offered for a server that is not there. The ways it fails are a port already in
168
+ use (the bind is refused; pass a different `port`) and `dashboard.enabled: false`
169
+ in `nexus.jsonc`, which is refused by name.
157
170
 
158
- 2. Or use the TUI command:
159
- ```
160
- /nexus web
161
- ```
162
- This shows instructions and tries to open your browser.
171
+ Once it is serving, the same command opens it:
163
172
 
164
- 3. Open in browser: `http://localhost:4747`
173
+ ```
174
+ /nexus dashboard [port] [host] # /nexus web is an alias of this
175
+ /nexus web [port] [host]
176
+ ```
177
+
178
+ The TUI cannot start the server itself — its process has no orchestrator, no
179
+ module registry and no way to invoke a tool — but it can reach the process that
180
+ has all three, and it can ask whether anything is listening. So the command asks
181
+ `http://host:port/api/health` first, and then does one of four things:
182
+
183
+ | What it found | What it does |
184
+ |---|---|
185
+ | A nexus dashboard | Opens your browser at that URL. Nothing is started a second time |
186
+ | A different process on that port | Says so, opens nothing, suggests another port |
187
+ | Nothing there | Submits `/nexus dashboard [port] [host]` to the server, waits for the port to answer, then opens the browser |
188
+ | Still nothing after ~3s | Says the start did not confirm, opens nothing, and points at the command's own reply for the reason |
189
+
190
+ The browser opens **only** after a confirmed listen. That is the whole point of
191
+ the wait: a browser pointed at a dead address gives a connection-refused page,
192
+ which looks like the dashboard failing rather than the dashboard not running.
193
+
194
+ **How it stays current.** A WebSocket to `/ws/events` carries a throttled
195
+ `orchestrator:state` push — every state change schedules a full snapshot, at
196
+ most once a second — plus the thirteen orchestrator events as they happen. On
197
+ top of that, an **Auto-refresh** checkbox (on by default) has the page ask the
198
+ server for a fresh state every 5 seconds and poll `/api/health` and `/api/costs`,
199
+ the two things the socket does not carry. The push is what keeps the page fresh;
200
+ the interval is a belt-and-braces refresh you can switch off. The page also
201
+ shows how old the last snapshot is, and labels it stale past 15 seconds.
165
202
 
166
203
  **What it shows:**
167
- - Agent grid with role, status, model, and metrics
168
- - Cost tracker with budget gauge
169
- - DAG visualization with task dependencies
170
- - Activity log with all events
171
- - Config panel (read-only)
172
- - Auto-refresh every 5 seconds
204
+ - **Sessions** — one row per session nexus owns, is still collecting cost from,
205
+ or has abandoned, with each one's state (`running` / `idle` / `abandoned` /
206
+ `settled`), age, last read token count, and unbilled spend. Rows with **no
207
+ owning agent** are called out in a banner above the table, because a session
208
+ that is still generating after its agent was terminated keeps spending and
209
+ nothing is collecting that spend — a case that was invisible on every layer
210
+ before. The **Age** column is elapsed time, not a wall clock, and reads `—`
211
+ for those orphan rows: `spawnedAt` comes from the owning agent, so an unowned
212
+ session has no start time to show. The cell says so in its tooltip, and the
213
+ `—` is shown rather than the column dropped, so the gap is visible.
214
+ This list is nexus's own bookkeeping, not an enumeration of every open session
215
+ on the server, and the page says so on the section itself.
216
+ - **Agents** — role, status, model, session id, and metrics
217
+ - **Budget** — spend against the configured cap, with the alert threshold marked
218
+ - **Tasks and DAG** — the task list, and a graph drawn from the dependency edges
219
+ the state actually reports. Edges pointing at tasks that are not in the
220
+ snapshot, self-edges, and cycles are counted and reported in the section note
221
+ rather than silently not drawn.
222
+ - **Cost breakdown** — by agent and by model, read from `/api/costs`, which
223
+ covers the full history rather than only the live agents
224
+ - **Configuration (read-only)** — the resolved config the orchestrator reports
225
+ as in force, plus a `read-only` JSON viewer. The write path was deliberately
226
+ removed rather than left broken: it used to post a `config:update` message
227
+ that the server does not handle, so the Apply button reported success and
228
+ nothing happened. There is no auth story for writes and the socket is a
229
+ localhost server answering with `CORS: *`, so no write path was added to
230
+ replace it — edit `nexus.jsonc` instead.
231
+ - **Activity log** — every event the broadcaster forwards, each delivered once.
232
+ Two of them carry a fact the line used to leave out:
233
+ - `cost:delta` names **where the price came from** (`settledTier.pricing`) and
234
+ which token tier the amount was priced at. That is deliberately not the same
235
+ as the measured/estimated split elsewhere on the page: `settledTier.pricing`
236
+ is about the *price* — the model's published list, a fallback table because
237
+ this model is not in it, or an unknown-model fallback — while
238
+ measured/estimated is about the *token counts*, which the orchestrator reads
239
+ off a real session. A line whose `settledTier` is missing says so instead of
240
+ implying a price source.
241
+ - `config:reloaded` names the **cause** (`trigger`) alongside the load number,
242
+ the raw ISO load time, and both config files' state, so a reload that
243
+ happened for a reason you did not ask for is visible as one.
173
244
 
174
245
  **Stop the dashboard:**
175
246
  ```
176
- nexus.dashboard.stop()
247
+ /nexus dashboard stop
248
+ Ask the agent to call nexus.dashboard.stop
177
249
  ```
250
+ This stops the HTTP/WebSocket server only. The orchestrator, its agents and its
251
+ sessions keep running. Both routes say so plainly when there was nothing
252
+ running, rather than reporting a stop that did not happen.
178
253
 
179
254
  ### Team Mode
180
255
 
@@ -297,8 +372,8 @@ nexus.clarify(question="Should I use JWT or OAuth?", options="JWT, OAuth", assum
297
372
  | `nexus.preset` | Apply preset config | `{ name }` |
298
373
  | `nexus.config.save` | Save config to disk | `{ level: 'project' \| 'global' }` |
299
374
  | `nexus.config.init` | Initialize config files | `{ level }` |
300
- | `nexus.dashboard.start` | Start web dashboard | `{ port?, host? }` |
301
- | `nexus.dashboard.stop` | Stop web dashboard | `{}` |
375
+ | `nexus.dashboard.start` | Start the web dashboard server (port must be free) | `{ port?, host? }` |
376
+ | `nexus.dashboard.stop` | Stop the web dashboard server | `{}` |
302
377
  | `nexus.todo.add` | Add a todo item | `{ description, assignedTo? }` |
303
378
  | `nexus.todo.list` | List all todos | `{}` |
304
379
  | `nexus.todo.complete` | Complete a todo | `{ id }` |
@@ -327,17 +402,31 @@ nexus.clarify(question="Should I use JWT or OAuth?", options="JWT, OAuth", assum
327
402
 
328
403
  ## TUI Commands
329
404
 
405
+ The TUI plugin registers exactly these slash commands. With no argument,
406
+ `/nexus` opens the full configuration dialog; with one, it dispatches to a
407
+ subcommand (`config`/`c`, `status`/`s`, `dashboard`/`d`, `web`/`w`,
408
+ `overview`, `model`/`m`, `reset`).
409
+
330
410
  | Command | Alias | Description |
331
411
  |---------|-------|-------------|
332
- | `/nexus` | `Ctrl+N` | Open full configuration dialog |
333
- | `/nexus web` | `/nw` | Start web dashboard |
334
- | `/nexus review` | `/nr` | Quick code review |
335
- | `/nexus fix` | `/nf` | Quick fix for last error |
336
- | `/nexus explain` | `/ne` | Explain last change |
337
- | `/nexus config` | `/nc` | Configure models & budget |
338
- | `/nexus model` | `/nm` | Select model for a role |
339
- | `/nexus status` | `/ns` | Show config summary |
340
- | `/nexus reset` | — | Reset all settings to defaults |
412
+ | `/nexus` | `Ctrl+N` | Full configuration dialog, or a subcommand |
413
+ | `/nexus-dashboard` | `/nd` | Start the web dashboard and open it. If one is already serving, opens that and starts nothing — see [Web Dashboard](#web-dashboard) |
414
+ | `/nexus-web` | `/nw` | Alias of `/nexus-dashboard` |
415
+ | `/nexus-overview` | `/no` | Config, budget and dashboard-status overview. Prints text; starts nothing |
416
+ | `/nexus-config` | `/nc` | Configure models & budget |
417
+ | `/nexus-model` | `/nm` | Select a model for a role |
418
+ | `/nexus-status` | `/ns` | Show the config summary |
419
+ | `/nexus-reset` | — | Reset all settings to defaults |
420
+
421
+ A prompt beginning `/nexus …` typed into the composer is a *different* thing: it
422
+ is intercepted by a prompt hook and routed to `orchestrator.handleCommand()`,
423
+ which understands `status`, `agents`, `costs`, `pause`, `resume`, and
424
+ `dashboard [port] [host]` (which starts the server, or says why it did not),
425
+ `dashboard stop`, and `dashboard state` (the state as JSON). Anything else
426
+ answers `Unknown command`. This hook cannot cancel the prompt — the plugin API
427
+ gives it no way to — so it replaces the command text with the command's result
428
+ rather than leaving the model holding a bare `/nexus dashboard` next to an
429
+ answer it has no reason to read. The table above is the TUI palette.
341
430
 
342
431
  ---
343
432
 
@@ -356,6 +445,24 @@ Configure via `/nexus` or `Ctrl+N`:
356
445
  📝 Documenter: opencode/big-pickle
357
446
  ```
358
447
 
448
+ ### Web Dashboard
449
+
450
+ `.opencode/nexus.jsonc` (project) and `~/.config/opencode/nexus.jsonc` (global)
451
+ both accept:
452
+
453
+ ```jsonc
454
+ {
455
+ "dashboard": {
456
+ "enabled": true, // false makes every start attempt refuse, and say so
457
+ "port": 4747, // default port; startDashboard({port}) still wins
458
+ "host": "127.0.0.1"
459
+ }
460
+ }
461
+ ```
462
+
463
+ The server has no authentication, which is why `host` defaults to loopback.
464
+ Leave it there unless you have put your own authentication in front of it.
465
+
359
466
  ### Custom Roles
360
467
 
361
468
  Define your own agent roles:
@@ -395,7 +502,7 @@ nexus.template(name="documentation") — Documentation update
395
502
  │ ┌────────────────────────────────────────────────────┐ │
396
503
  │ │ SERVER PLUGIN (index.ts) │ │
397
504
  │ │ • 40+ tool registrations │ │
398
- │ │ • Auto-creates agents and enables LSP │ │
505
+ │ │ • Auto-creates agent files; opts OpenCode into LSP │ │
399
506
  │ │ • Config file loading and creation │ │
400
507
  │ └────────────────────────────────────────────────────┘ │
401
508
  │ │
@@ -422,7 +529,8 @@ nexus.template(name="documentation") — Documentation update
422
529
  │ ┌────────────────────────────────────────────────────┐ │
423
530
  │ │ WEB DASHBOARD │ │
424
531
  │ │ • Bun.serve() HTTP + WebSocket (port 4747) │ │
425
- │ │ • DAG viz, cost chart, config editor, auto-refresh │ │
532
+ │ │ • DAG viz, cost chart, read-only config, sessions │ │
533
+ │ │ • Started on request; throttled push + poll │ │
426
534
  │ └────────────────────────────────────────────────────┘ │
427
535
  │ │
428
536
  │ ┌────────────────────────────────────────────────────┐ │