feat(dashboard): interactive control panel — drive QodeX from the browser#51
Merged
Conversation
…wser
Turns the read-only dashboard into a CONTROL surface, on a foundation that grows to "every
capability controllable" — each control is one entry in an action registry.
- src/cli/dashboard-control.ts: the action registry + dispatch. config.set goes through a
strict WHITELIST of (path, type) knobs (caching, efficient mode, memory mode, sub-agents,
learning/episodic/lessons) so the panel can NEVER write an arbitrary config key; plus
memory.forget, schedule.setEnabled/remove, offload.apply. Pure validators (validateConfigSet,
setDeep/getDeep) are unit-tested; only the appliers touch disk/the store.
- src/cli/dashboard-server.ts: a local control server — binds 127.0.0.1 ONLY, every request
needs a random per-launch token (?k= / x-qodex-token) or it 401s (CSRF-ish guard, since this
mutates config + memory). handleRequest is factored out and unit-tested; live smoke-tested
(401 without token, state with token, clean close).
- dashboard.ts: buildDashboardHtml(d, {token}) renders live toggles/selects + schedule
enable/remove buttons + a toast and the action JS when tokened; read-only otherwise (so the
old static render + `--static` still work). gatherDashboardData now includes control state +
schedules. runDashboard starts the server + opens the tokened URL; writeStaticDashboard keeps
the snapshot path. `qodex dashboard` runs the live server (Ctrl-C to stop); `--static` for the file.
+19 tests (whitelist/coercion, setDeep/getDeep, dispatch unknown+reject, route auth/routing,
live vs read-only render). Full suite 1366 green; tsc clean.
QodeXcli
added a commit
that referenced
this pull request
Jun 30, 2026
…idates (#52) More of "every capability controllable", each one more action + widget on the registry/server foundation from #51. - model.set — switch defaults.model from a dropdown of every model the configured providers expose (+ the current default). - memory.add — a "Remember a fact" input in the memory panel (writes via the store + mirror). - skill.promote / skill.reject — the quarantine of captured skill candidates is now listed with confidence, and promoted (re-checks the human-protection guard) or rejected inline. - gatherDashboardData surfaces `models` + `candidates`; new widgets render live (and degrade to read-only state without a token). All four validate input before touching disk/the store; unknown/empty params are rejected. +5 tests (live render wires the new actions + lists candidates; dispatch rejects empty input). Full suite 1367 green; tsc clean. Co-authored-by: Louise Lau <QodeXcli@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The goal: every capability controllable from the dashboard. This lays the foundation and ships the first batch — the read-only dashboard becomes a live control panel, and each new control is just one entry in an action registry.
What
dashboard-control.ts— action registry + dispatch.config.setgoes through a strict whitelist of(path, type)knobs (prompt caching, efficient mode, memory mode, sub-agents, learning / episodic / failure-lessons) — the panel can never write an arbitrary config key. Plusmemory.forget,schedule.setEnabled/remove,offload.apply. Pure validators (validateConfigSet,setDeep/getDeep) are unit-tested; only the appliers touch disk/the store.dashboard-server.ts— a local control server. Binds 127.0.0.1 only; every request needs a random per-launch token (?k=/x-qodex-token) or it 401s — a CSRF-ish guard, since this mutates config + memory.handleRequestis factored out for unit tests; live smoke-tested (401 without token, state with token, HTML served, clean close).buildDashboardHtml(d, {token})renders live toggles/selects + schedule enable/remove buttons + a toast and the action JS when tokened; read-only otherwise (the old static render and--staticstill work).runDashboardstarts the server and opens the tokened URL;qodex dashboardkeeps it alive (Ctrl-C),--staticwrites the snapshot.Security
Local-only bind + per-launch token; whitelisted config writes; unknown actions rejected. The mutating API is never reachable without the token printed to your terminal.
Tests
+19 (whitelist + coercion,
setDeep/getDeep, dispatch unknown+reject, route auth/routing, live-vs-read-only render). Full suite 1366 green,tscclean.Next
The registry makes "all capabilities" incremental: provider add/remove, skill curate/promote, bot start/stop,
/projectworklog, model switch — each is one more action + widget.