@dsdenes/devboard 0.1.563 → 0.1.564
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -11
- package/package.json +1 -1
- package/templates/host-AGENTS.md +2 -1
package/README.md
CHANGED
|
@@ -159,9 +159,11 @@ issue through `/api/feedback` at once, then replaces itself with the issue URL.
|
|
|
159
159
|
never replace mode content or steal focus, and several arrivals are all retained. Flow blockers
|
|
160
160
|
and verification results also remain in their mode context.
|
|
161
161
|
|
|
162
|
-
The 26px status bar is two groups. The left group states the WebSocket connection
|
|
162
|
+
The 26px status bar is two groups. The left group states the WebSocket connection, the
|
|
163
163
|
project's own name (the last path segment, with a folder mark and the full path in its tooltip),
|
|
164
|
-
|
|
164
|
+
and the Providers control: the selected provider with the lowest remaining percentage, or
|
|
165
|
+
`No provider`, which opens the Providers dialog. The right group states the running lane count,
|
|
166
|
+
the issues worker
|
|
165
167
|
state with a state dot, the watchdog's last action and age, and the running and installed
|
|
166
168
|
versions; each metric carries a 10px uppercase label so its meaning never rests on color. When
|
|
167
169
|
`versionState.stale` is true it shows the existing reload control (`reload-devboard`), whose
|
|
@@ -220,6 +222,9 @@ npx @dsdenes/devboard update # install the newest npm version; do not restar
|
|
|
220
222
|
npx @dsdenes/devboard doctor # one PASS or FAIL line per check
|
|
221
223
|
```
|
|
222
224
|
|
|
225
|
+
The launcher never discovers, reads, copies, or waits on another local Devboard installation or
|
|
226
|
+
source checkout; it resolves the npm version and artifact for the target host alone.
|
|
227
|
+
|
|
223
228
|
`install` writes a real npm prefix at `<host>/.devboard`, replacing `.devboard`,
|
|
224
229
|
`.omp/commands`, and `.omp/extensions` symlinks with real directories that hold the installed
|
|
225
230
|
package's files. It keeps `.devboard/.tmp`, copies `templates/host-AGENTS.md` to
|
|
@@ -254,18 +259,63 @@ The global `/setup-devboard` command runs the launcher against the invoking sess
|
|
|
254
259
|
directory. It lives here as `omp/commands/setup-devboard.md` and is linked into the user-level
|
|
255
260
|
command directory (`$HOME/.omp/agent/commands/setup-devboard.md`) so every session sees it.
|
|
256
261
|
|
|
257
|
-
###
|
|
262
|
+
### Providers and model selection
|
|
258
263
|
|
|
259
|
-
|
|
260
|
-
Every harness peer starts its ACP process with `<REPO_DIR>` as the working directory, so each
|
|
261
|
-
one, and the interactive agent started in that repository, uses the same policy:
|
|
264
|
+
Provider authentication is a harness capability, not host settings. Exactly two providers exist:
|
|
262
265
|
|
|
263
|
-
|
|
|
266
|
+
|Provider|Environment variable|Model|
|
|
264
267
|
|---|---|---|
|
|
265
|
-
|`
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
268
|
+
|OpenCode Go|`OPENCODE_API_KEY`|`opencode-go/deepseek-v4.1-flash`|
|
|
269
|
+
|OpenRouter|`OPENROUTER_API_KEY`|`openrouter/deepseek/deepseek-v4.1-flash-1017`|
|
|
270
|
+
|
|
271
|
+
The operator registers keys in the **Providers** dialog, reachable from the status-bar control
|
|
272
|
+
(`data-testid="providers-indicator"`) and the `settings.providers` palette command. The dialog
|
|
273
|
+
supports add, edit, enable/disable, delete with confirmation, refresh, and save. It shows each
|
|
274
|
+
key's masked value, status (`ok`, `near limit`, `exhausted`, `invalid`, `unknown`), every quota
|
|
275
|
+
window's remaining fraction, and the last check time.
|
|
276
|
+
|
|
277
|
+
Credentials live in `<stateDir>/providers/credentials.json` (directory `0700`, file `0600`,
|
|
278
|
+
atomic replacement). The file survives a dashboard restart and is never removed by
|
|
279
|
+
`bun run cleanup` or the watchdog sweep, however old it is. Generated per-peer agent directories
|
|
280
|
+
live beside it under `<stateDir>/providers/agents/<selection-id>/`. No key is ever returned by a
|
|
281
|
+
command or event, written to the journal or activity log, or placed in a process's argv; the
|
|
282
|
+
only value the interface receives is a mask ending in at most the last four characters. The
|
|
283
|
+
durable state file under `<stateDir>/state/` carries no key material.
|
|
284
|
+
|
|
285
|
+
Usage is read from `https://opencode.ai/zen/go/v1/usage` (`rolling`, `weekly`, and `monthly`
|
|
286
|
+
percent used) and `https://openrouter.ai/api/v1/key` (`limit_remaining` and `limit`).
|
|
287
|
+
`DEVBOARD_OPENCODE_GO_USAGE_BASE_URL` and `DEVBOARD_OPENROUTER_USAGE_BASE_URL` override the base
|
|
288
|
+
URLs for tests and offline verification. A key's usage is fetched at most once per 60 seconds
|
|
289
|
+
unless the operator forces a refresh.
|
|
290
|
+
|
|
291
|
+
Remaining is `1 - percent/100` for each Go window and `limit_remaining / limit` for OpenRouter,
|
|
292
|
+
or unlimited when the account has no limit. A subscription is eligible only when every gating
|
|
293
|
+
window is strictly above **1% remaining**; that is the rule the dialog states. Eligible
|
|
294
|
+
OpenCode Go subscriptions rank by their lowest remaining window, and ties keep the operator's
|
|
295
|
+
list order. A key whose usage check failed or timed out stays eligible with unknown headroom and
|
|
296
|
+
ranks below every key with known headroom. When no Go subscription is eligible, the peer starts
|
|
297
|
+
on the OpenRouter fallback model; when neither provider has an eligible subscription, no process
|
|
298
|
+
starts and the UI and event stream report the reason. With no subscription configured at all,
|
|
299
|
+
every peer start is refused with an error pointing at the Providers dialog, so a peer never
|
|
300
|
+
silently inherits the operator's OMP login.
|
|
301
|
+
|
|
302
|
+
Every agent process — goal work, lifecycle lanes, Flow, issues, Auto Scout, Ask, Discover, goal
|
|
303
|
+
drafts, and skills preparation — starts with `PI_CODING_AGENT_DIR` pointing at a generated
|
|
304
|
+
directory under `<stateDir>/providers/agents/`. Its `config.yml` pins `default`, `plan`, `smol`,
|
|
305
|
+
`slow`, and `task` to the selected model. A Go selection also sets `retry.modelFallback: true`,
|
|
306
|
+
`retry.fallbackOn: any`, and a chain from `opencode-go/*` to the OpenRouter fallback; an
|
|
307
|
+
OpenRouter selection sets no chain. The peer environment removes the operator's inherited
|
|
308
|
+
`OPENCODE_API_KEY` and `OPENROUTER_API_KEY` first, then adds only the selected keys (a Go peer
|
|
309
|
+
also receives an OpenRouter key when one exists, for its fallback chain).
|
|
310
|
+
|
|
311
|
+
`omp/config.yml` is still installed as `<host>/.omp/config.yml`, but it no longer pins
|
|
312
|
+
`modelRoles`: a project-level pin would override the per-peer selection. The interactive agent
|
|
313
|
+
started in the repository keeps OMP's configured default. Editing `omp/config.yml` here and
|
|
314
|
+
rerunning `install.sh` changes the installed copy.
|
|
315
|
+
|
|
316
|
+
`bun run verify:providers` proves the selection matrix, the 1% boundary, unknown-usage ranking,
|
|
317
|
+
OpenRouter fallback, refusal, masking, environment and argv hygiene, generated roles,
|
|
318
|
+
persistence, and cleanup protection against a local provider stub and a deterministic ACP peer.
|
|
269
319
|
|
|
270
320
|
## Build and run
|
|
271
321
|
|
|
@@ -1097,6 +1147,8 @@ and is retried the same way.
|
|
|
1097
1147
|
|`STATIC_DIR`|`dist`|Built client directory.|
|
|
1098
1148
|
|`AGENT_COMMAND`|`omp acp`|ACP peer command, split on whitespace. `server/fixtures/stub-agent.ts` is a deterministic substitute for tests and local verification.|
|
|
1099
1149
|
|`STATE_DIR`|`<harness>/.tmp`|State and journal directory; an installed dashboard passes `<host>/.devboard/.tmp`.|
|
|
1150
|
+
|`DEVBOARD_OPENCODE_GO_USAGE_BASE_URL`|`https://opencode.ai/zen/go`|OpenCode Go usage base; overridden by tests and offline verification.|
|
|
1151
|
+
|`DEVBOARD_OPENROUTER_USAGE_BASE_URL`|`https://openrouter.ai/api`|OpenRouter usage base; overridden by tests and offline verification.|
|
|
1100
1152
|
|`DEVBOARD_UPDATE_INTERVAL_MS`|`60000`|Automatic update check interval.|
|
|
1101
1153
|
|`DEVBOARD_UPDATE_BACKOFF_MAX_MS`|`3600000`|Ceiling for the exponential retry delay after a failed check or install.|
|
|
1102
1154
|
|`DEVBOARD_RELEASE_DIR`|unset|Local release directory for offline verification; unset reads the newest Gitea release over the public HTTP API.|
|
|
@@ -1224,6 +1276,8 @@ stale files are therefore removed after a week. These entries are never deleted
|
|
|
1224
1276
|
|
|
1225
1277
|
- `.tmp/state/` and everything below it.
|
|
1226
1278
|
- `.tmp/journal/`, which the journal rule above governs.
|
|
1279
|
+
- `.tmp/providers/` in full: the operator's credential store and every generated per-peer agent
|
|
1280
|
+
directory. A credential is operator input, not scratch, and nothing recreates it.
|
|
1227
1281
|
- `.tmp/watchdog/state.json`, `.tmp/watchdog/latest.json`, and `.tmp/watchdog/lock`.
|
|
1228
1282
|
- `.tmp/orchestrator/state.json`, `.tmp/orchestrator/ledger.json`, and `.tmp/orchestrator/lock`,
|
|
1229
1283
|
which the first Issues Start still reads to migrate handled issue numbers.
|
|
@@ -1995,6 +2049,11 @@ The client sends:
|
|
|
1995
2049
|
{ "type": "answer", "id": 1, "value": "Gamma" }
|
|
1996
2050
|
{ "type": "ask", "conversationId": "…", "question": "What does this label mean?", "context": { … } }
|
|
1997
2051
|
{ "type": "closeAsk", "conversationId": "…" }
|
|
2052
|
+
{ "type": "getProviders" }
|
|
2053
|
+
{ "type": "saveProvider", "id": "…", "provider": "opencode-go", "label": "Work", "key": "…" }
|
|
2054
|
+
{ "type": "deleteProvider", "id": "…" }
|
|
2055
|
+
{ "type": "setProviderEnabled", "id": "…", "enabled": false }
|
|
2056
|
+
{ "type": "refreshProviders" }
|
|
1998
2057
|
```
|
|
1999
2058
|
|
|
2000
2059
|
- `getGoal` reads the goal document from disk and answers with its complete contents; an
|
|
@@ -2010,6 +2069,14 @@ The client sends:
|
|
|
2010
2069
|
version a release packs, so an unpacked checkout never claims `0.1.0`. A client that connects,
|
|
2011
2070
|
and the page every few seconds, asks for it; a stale answer makes the reload control appear
|
|
2012
2071
|
with both versions in its title.
|
|
2072
|
+
- `getProviders` answers with `providersState`: every subscription with its masked key, status,
|
|
2073
|
+
quota windows, remaining fraction, last check time, and error; the current `selection` (or
|
|
2074
|
+
`null`), the refusal reason, and the fixed rule `rotates at 1% remaining`. `saveProvider`
|
|
2075
|
+
validates a new or changed key first: HTTP 401/403 answers `providerError` and changes nothing,
|
|
2076
|
+
while an unreachable endpoint or 5xx saves the subscription with status `unknown`. Editing a
|
|
2077
|
+
label without a key never revalidates. `deleteProvider` and `setProviderEnabled` persist the
|
|
2078
|
+
store without touching a running peer. `refreshProviders` bypasses the 60-second usage cache.
|
|
2079
|
+
Every mutation broadcasts a fresh `providersState`; failures answer `providerError`.
|
|
2013
2080
|
- `getIssues` answers with `issuesState`, the worker snapshot plus `present` and `attached`:
|
|
2014
2081
|
lifecycle, enabled, paused, repository, poll times, queue entries with `labels`, `handled`,
|
|
2015
2082
|
`runId`, and `agentRunId`, run summaries, the running `agents` (run id, issue number, startedAt,
|
|
@@ -2352,6 +2419,7 @@ The server answers with events:
|
|
|
2352
2419
|
cd .devboard
|
|
2353
2420
|
bun test
|
|
2354
2421
|
bun run verify:interface
|
|
2422
|
+
bun run verify:providers
|
|
2355
2423
|
bun run verify:install
|
|
2356
2424
|
bun run verify:update
|
|
2357
2425
|
bun run verify:ui
|
package/package.json
CHANGED
package/templates/host-AGENTS.md
CHANGED
|
@@ -84,7 +84,8 @@ no local checkout, running dashboard, or required release tarball is involved. G
|
|
|
84
84
|
push mirror of this repository; it carries no release the dashboard reads.
|
|
85
85
|
|
|
86
86
|
A host installs a real npm prefix at `<host>/.devboard` with
|
|
87
|
-
`npx @dsdenes/devboard install`.
|
|
87
|
+
`npx @dsdenes/devboard install`. The launcher never discovers, reads, copies, or waits on another
|
|
88
|
+
local Devboard installation or source checkout. `<host>/.omp/commands`, `<host>/.omp/extensions`, and
|
|
88
89
|
`<host>/AGENTS.md` are real copies from the installed package; no harness path is a symlink.
|
|
89
90
|
The canonical `.devboard/` in this checkout is the source tree and is never an npm install.
|
|
90
91
|
|