Skip to content

Dashboard: intercept built-in slash commands instead of passing them to the LLM - #425

Merged
m-aebrer merged 5 commits into
aebrer:masterfrom
Hrovatin:feature/issue-400-dashboard-builtin-commands
Aug 4, 2026
Merged

Dashboard: intercept built-in slash commands instead of passing them to the LLM#425
m-aebrer merged 5 commits into
aebrer:masterfrom
Hrovatin:feature/issue-400-dashboard-builtin-commands

Conversation

@Hrovatin

Copy link
Copy Markdown
Contributor

Closes #400

Makes the dashboard intercept built-in slash commands (like /fork) instead of leaking them to the LLM, via a general mechanism: built-in commands flow through get_commands (new source: "builtin") so the dashboard automatically knows every built-in — including future ones — and intercepts them on submit. Known commands route to existing dashboard affordances (fork modal, model picker, compact/rename modals, settings/fleet screens, export, copy); the rest degrade gracefully to a friendly hint. No LLM leak for any built-in.

Implementation plan posted as a comment below.

@Hrovatin

Copy link
Copy Markdown
Contributor Author

Implementation Plan — Dashboard built-in slash command interception

Problem

Typing a built-in command such as /fork in the dashboard composer sends it to the LLM as plain text. The LLM produces a fake acknowledgment and nothing happens.

Root cause (three gaps found during exploration):

  1. Built-ins are exposed nowhere the dashboard can see. get_commands (RPC + extension SDK) only returns extension | prompt | skill sources. RpcSlashCommand.source has no "builtin" variant. docs/rpc.md explicitly documents that built-ins are excluded. So the dashboard has no data describing built-ins — it can neither show them in autocomplete nor know which /tokens to intercept.
  2. No shared execution contract for built-ins. BUILTIN_SLASH_COMMANDS (packages/coding-agent/src/core/slash-commands.ts) is metadata only (name + description). Actual behavior is an ad-hoc if (text === "/x") chain in interactive-mode.ts (lines ~2373–2487), each handler mixing TUI rendering with AgentSession calls. There is no registry coupling a name to an action or to a UI-vs-headless classification.
  3. The composer forwards everything to the LLM. send()api.prompt() → RPC promptsession.prompt(), which only special-cases extension/skill/template commands. Built-in text passes straight through.

Design — a general pipe + graceful degradation

The maintainer's bar (issue discussion): worth doing only if all commands — including new ones — are handled automatically, low-effort; not one-by-one.

The automatic guarantee is delivered by a pipe:

BUILTIN_SLASH_COMMANDS (enriched registry)
        -> get_commands returns them with source:"builtin"
        -> dashboard generically intercepts ANY known built-in on submit
        -> never sent to the LLM (true for future commands too)

On top of that pipe, a name -> dashboard-affordance map routes the built-ins that already have dashboard UI to that UI, and everything else (terminal-only or not-yet-wired) shows a friendly inline hint. A brand-new built-in added later is automatically intercepted (no LLM leak) and shows the hint until/unless someone opts it into the map — so nothing is ever broken by default.

Layering: the core registry stays UI-agnostic (a coarse, presentation-neutral availability classification only). The dashboard client owns the name->modal/screen mapping. No dashboard concepts leak into coding-agent core.

Deliverables

A. Core registry + parser (packages/coding-agent/src/core/slash-commands.ts)

  • Extend BuiltinSlashCommand with a UI-agnostic availability: "universal" | "terminal-only" (universal = action is meaningful outside a terminal: fork, compact, new, resume, model, name, export, import, settings, tree, session, scoped-models, dream, reload, copy, login, logout; terminal-only = hotkeys, buddy, quit).
  • Add a tested helper parseBuiltinSlashCommand(text): { command; args } | undefined matching the TUI's === "/x" || startsWith("/x ") semantics — the single source of truth for "is this a built-in".
  • Note: debug and arminsayshi remain intentionally unregistered (hidden dev/easter-egg); documented as such.

B. RPC exposure (rpc-types.ts, rpc-mode.ts, agent-session.ts)

  • Add "builtin" to the slash-command source union (RpcSlashCommand and the shared SlashCommandSource); carry availability. Built-ins have no file origin — sourceInfo becomes optional or a synthetic { kind: "builtin" } (resolve during implementation).
  • Unify the two duplicate getCommands producers (rpc-mode.ts get_commands and agent-session.ts _bindExtensionCore) into one shared collector that appends registry built-ins. RPC includes them; keep the extension-SDK surface consistent (see open question 2).
  • Update docs/rpc.md: get_commands now includes built-ins; correct the "built-ins are excluded" note.

C. Dashboard protocol + server (shared/protocol.ts, server/server.ts)

  • CommandDto.source gains "builtin"; add optional availability.
  • Ensure the /api/runtimes/:key/commands mapping forwards the new fields.

D. Dashboard client — the fix (client/screens/session.tsx, new client/builtin-commands.ts)

  • In the submit path, before api.prompt(): if the leading /token matches a built-in from commands() (source "builtin"), call dispatchBuiltinCommand(name, args) and return — never call api.prompt(). This is the general interception (auto-covers future built-ins).
  • dispatchBuiltinCommand (its own module for unit-testing) maps built-ins to existing affordances:
    • fork -> fork modal - model -> model selector - compact -> compact modal (args as instructions) - name -> rename (prefill/execute) - settings -> navigate settings - resume -> navigate fleet - new -> new-session flow - export -> HTML export download - session -> stats/context modal - copy -> copy last agent message (client clipboard)
    • terminal-only (hotkeys, buddy, quit) and not-yet-wired (tree, scoped-models, import, dream, reload, login, logout) -> friendly inline notice
    • default (unknown/new built-in) -> "/ isn't available in the dashboard yet — use the terminal UI."
  • Add an actionNotice (info) signal to surface hints near the composer.
  • Autocomplete popover: built-ins now arrive via commands(); render a builtin source badge and mark terminal-only ones. Selecting one then Enter routes through the same interception.

E. (Optional / stretch) server-side defense-in-depth — intercept an exact built-in in the RPC prompt handler (not in core session.prompt()) so no RPC client (dashboard, Telegram) can leak a built-in to the LLM. Flagged optional to limit scope and avoid surprising other clients; see open question 4.

Acceptance criteria

  • Typing /fork in the dashboard composer does not call api.prompt / reach the LLM, and opens the fork modal.
  • Every registered built-in typed in the composer is intercepted (never sent to the LLM); mapped ones trigger their affordance, the rest show a user-friendly hint.
  • A hypothetical new entry in BUILTIN_SLASH_COMMANDS is automatically surfaced by get_commands, shown in dashboard autocomplete, and intercepted on submit with no code change in the dashboard.
  • Normal (non-slash / unknown-slash) text still reaches the LLM unchanged.
  • get_commands returns built-ins with source:"builtin"; docs/rpc.md updated to match.
  • npm run build, npm test, and npx biome check all pass.

Testing approach (mandatory)

coding-agent

  • New test/slash-commands.test.ts: parseBuiltinSlashCommand exact + prefix + args + non-builtin + whitespace; every registry entry has a valid availability.
  • Extend RPC tests: get_commands includes built-ins with source:"builtin" + availability, excludes hidden dev commands; shared collector behavior.

dashboard

  • New test/client/session-composer.test.tsx (or extend test/client/screens.test.tsx): /fork submit does not call a mocked api.prompt and opens the fork modal; a terminal-only/unmapped built-in shows the notice and does not call api.prompt; normal text still calls api.prompt.
  • Unit-test dispatchBuiltinCommand's routing table directly (mapped -> handler, unknown -> notice).
  • Extend test/server.test.ts: /commands maps built-in source/availability into CommandDto.

Files to create / modify

Create: packages/dashboard/src/client/builtin-commands.ts; packages/coding-agent/test/slash-commands.test.ts; packages/dashboard/test/client/session-composer.test.tsx

Modify: slash-commands.ts; rpc-types.ts; rpc-mode.ts; agent-session.ts; docs/rpc.md; dashboard shared/protocol.ts, server/server.ts, client/screens/session.tsx, client/api.ts (only if a new endpoint is needed — mostly reuse); docs: docs/dashboard.md, root README.md, packages/coding-agent/README.md (where dashboard command behavior is described).

Risks & open questions

  1. sourceInfo for built-ins — currently required on RpcSlashCommand/SlashCommandInfo; built-ins have no file. Make optional or synthesize { kind: "builtin" }.
  2. Extension SDK surface — should dreb.getCommands() also include built-ins, or only the RPC/dashboard path? Recommend consistent inclusion; flagging because it widens the extension-facing source union.
  3. Commands with args (/model x, /compact <instr>, /name <n>) — prefill the modal vs. execute directly. Proposed: execute directly when trivially resolvable (name/compact), else open the modal prefilled.
  4. Server-side defense-in-depth (deliverable E) — include it (also fixes the latent Telegram gap) or keep the fix dashboard-only? Tradeoff: broader safety vs. scope + other-client behavior.
  5. /new, /resume, /quit semantics in a persistent dashboard/resume->fleet, /new->new-session flow, /quit->hint (not process exit). Confirm desired UX.

Notes on branch setup

Branch feature/issue-400-dashboard-builtin-commands was created off master (ff51a98), isolated in a git worktree, and pushed to the Hrovatin fork (matching this repo's fork-based contributor workflow); this PR targets aebrer/dreb:master.


Plan created by mach6

@m-aebrer

m-aebrer commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Plan Assessment

Summary

The diagnosis is correct: dashboard submission currently sends built-in slash text directly through api.prompt(), while get_commands exposes only extension, prompt-template, and skill commands. A registry-to-RPC-to-dashboard discovery pipe plus generic interception is the right broad direction.

The posted plan should not be implemented as written yet. It has a sound core idea, but several unresolved contract and failure-mode problems prevent its stated “never reaches the LLM” guarantee and expand the work beyond wiring existing dashboard affordances.

Current state confirmed

  • BUILTIN_SLASH_COMMANDS contains 20 metadata-only entries; TUI execution remains an ad-hoc branch chain in interactive-mode.ts.
  • RPC get_commands and extension dreb.getCommands() are separate producers. They look similar, but differ intentionally: RPC uses filtered skills while the extension API uses all loaded skills.
  • dreb.getCommands() is documented as commands “available for invocation via prompt”; every returned entry has required file-oriented sourceInfo. Built-ins do not satisfy either contract.
  • Dashboard commands are fetched asynchronously after mount. send() does not wait for that fetch and currently calls api.prompt() unconditionally.
  • /fork, model selection, compact, rename, export, and context/stats have existing dashboard UI. /copy has no existing clipboard action, /new has no equivalent action in the session screen, and /resume navigation is not the TUI's session-switch operation.
  • The command popover displays only eight sorted matches. Adding 20 built-ins will make the initial / menu mostly built-ins and can hide current skill/template suggestions.

Required plan revisions

  1. Keep the extension SDK contract separate. Do not add built-ins to dreb.getCommands() and do not unify the two collectors merely because their code is similar. Doing so would expose non-invokable commands through an API explicitly documented as prompt-invokable, widen a public source union, weaken or fake sourceInfo, and erase the filtered/unfiltered-skill distinction. Limit source: "builtin" to the RPC/dashboard discovery contract, and document that these entries require client-side handling. Prefer a discriminated RPC type over making sourceInfo optional for every command.

  2. Make the no-leak defense fail closed. Interception based only on commands() has a startup race: a user can submit /fork before get_commands resolves, and a failed fetch leaves the same leak permanently. Therefore the proposed RPC prompt guard cannot be optional if the acceptance criterion says “never sent to the LLM.” The dashboard should dispatch discovered built-ins, while the RPC prompt boundary rejects any recognized built-in that reaches it. That rejection should be explicit, not silently converted to ordinary prompt text. Add coverage for direct RPC submission, submission before command loading completes, and command-load failure.

  3. Resolve the parser contradiction. The proposed helper is called a single source of truth, but the plan does not wire the TUI dispatch chain to it, and the dashboard is described as parsing independently from fetched DTOs. Also, current TUI behavior is not uniformly exact || prefix-with-space: /export and /import currently use broader startsWith checks. Define one deliberate token-boundary rule for interception (including unsupported arguments), list its callers, and test /fork, /fork arg, /forklift, whitespace, and unknown slash text. If the TUI will not use the helper, it is not a single source of truth and should not be added as such.

  4. Narrow mapped actions to genuine equivalents. Generic interception plus a clear “not available in the dashboard” notice satisfies automatic coverage for every present and future registry entry. It does not require implementing new /copy or /new UX in this change. Before implementation, explicitly settle behavior for /model <arg>, /compact <instructions>, /name <name>, /export <path>, /session, /new, and /resume; the current plan leaves these open while simultaneously listing them as deliverables. In particular, dashboard runtime creation/navigation is not automatically equivalent to TUI new/resume semantics.

  5. Reconsider availability. The proposed universal | terminal-only field does not describe actual dashboard support: several commands classified as universal are still routed to the unavailable notice. It also makes every future registry addition choose dashboard-oriented metadata despite the claim of automatic low-maintenance handling. Unless a concrete non-dashboard consumer and behavior require it, the generic builtin source plus dashboard dispatch/default notice is sufficient.

  6. Specify collision and autocomplete behavior. Existing TUI autocomplete gives built-ins precedence over colliding extension names; RPC currently does not deduplicate. The plan must define behavior when a built-in and extension/template share a name, ensure the built-in cannot leak, avoid duplicate menu rows, and decide how built-ins are ranked so adding them does not bury current skill/template suggestions.

  7. Cover composer edge cases. Built-in interception must define what happens when files/images are attached, while streaming/compacting, and when a mapped action fails. Attachments must not be silently discarded. The composer should clear only after a command is accepted or intentionally replaced by a notice, while unknown slash text must continue to reach api.prompt() unchanged.

Scope and risk

As written, this is a medium-to-large cross-package API/UI change spanning public SDK types, RPC, core registry semantics, dashboard protocol/server/client, several command-specific behaviors, tests, and documentation. That is materially broader than the filed dashboard defect and no longer resembles a low-complexity good-first change. Keeping the SDK untouched, making the RPC guard mandatory, and limiting command-specific mappings to proven dashboard equivalents would make the work focused and reviewable while preserving the automatic future-command safety goal.

Recommended acceptance criteria adjustment

  • Every registry entry is exposed to the dashboard as source: "builtin" without changing dreb.getCommands().
  • Every recognized built-in is intercepted in the dashboard; mapped commands use an existing equivalent action and all others show an explicit notice.
  • The RPC prompt boundary rejects recognized built-ins as defense in depth, including during dashboard command-loading races or failures.
  • Built-in/extension name collisions have deterministic precedence and one autocomplete entry.
  • Unknown slash text remains prompt text; command-like prefixes such as /forklift are not misclassified.
  • Attachments are preserved or explicitly rejected with a visible message.

The branch has also been updated from current origin/master; GitHub added merge commit 6390debe.


Automated assessment by mach6

@m-aebrer

m-aebrer commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Resolved Plan Decisions

The plan-vetting discussion resolved the earlier blockers as follows.

Command discovery and matching

  • Add built-ins to RPC get_commands; leave extension dreb.getCommands() unchanged.
  • This remains a dashboard feature for handling user-entered slash commands. Do not add a separate prompt/model invocation mechanism or broaden the extension SDK.
  • Match on the first slash token: /fork and /fork anything identify the fork built-in, while /forklift does not.
  • Pass remaining text to the dashboard handler. A handler that does not accept arguments shows a visible usage notice rather than treating the text as a normal prompt.

Dashboard validity is opt-out

All registered built-ins are dashboard-valid by default. Valid means the command is shown in dashboard autocomplete and intercepted by the dashboard. A valid command without a completed dashboard action uses the generic “not implemented in the dashboard yet” notice; present and future commands therefore remain automatically discoverable and intercepted.

Only these commands are explicitly invalid in the dashboard:

  • copy
  • hotkeys
  • buddy

Use one simple opt-out field such as dashboard: false; do not add an availability taxonomy. Invalid commands should not be offered as dashboard actions, but typed occurrences must still be recognized and answered with clear guidance rather than submitted as ordinary prompt text.

Actions included in this change

Implement dashboard behavior for:

  • settings
  • model
  • export
  • import
  • name
  • session
  • fork
  • tree
  • new
  • compact
  • dream
  • resume
  • reload
  • quit

dream is a valid dashboard command and should preserve its current forms:

  • /dream — run consolidation
  • /dream backup — show the archive path
  • /dream backup <path> — set the archive path

Valid commands tracked for later UI work

These remain valid and visible now, using the not-yet-implemented notice until their dashboard actions land. OAuth login/logout will receive a separate tracking issue.

Autocomplete

  • Deduplicate collisions by command name, with the built-in taking precedence.
  • For a bare /, keep existing extension/prompt/skill suggestions ahead of built-ins so the new entries do not bury current workflows.
  • Once a query is typed, rank by relevance so a query such as /f surfaces /fork.

This decision record supersedes the narrower action map and the universal | terminal-only classification in the posted implementation plan.


Plan decisions recorded by mach6

@m-aebrer

m-aebrer commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

OAuth login/logout dashboard implementation is now tracked at #429. Until that issue lands, /login and /logout remain valid, discoverable dashboard commands using the agreed not-yet-implemented notice.

@m-aebrer

m-aebrer commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Progress Update

Implemented the built-in slash-command pipeline across core RPC and the dashboard:

  • RPC get_commands now exposes registered built-ins with source: "builtin" and dashboard opt-out metadata while leaving the extension SDK contract unchanged.
  • Built-ins take deterministic precedence over name collisions. RPC prompt, steer, and follow_up reject recognized built-ins before model invocation, including dashboard discovery races or failures.
  • The dashboard generically intercepts current and future built-ins, keeps existing resource suggestions ahead for a bare slash, and routes the agreed dashboard actions: settings/model, export/import, name/session stats, fork/tree, new/compact/dream, resume/reload, and quit.
  • Dashboard-invalid commands provide terminal-only guidance; valid but unfinished commands provide an explicit not-yet-implemented notice. Attachments and composer text are preserved when a built-in cannot run.
  • Added RPC methods/routes and dashboard modals for JSONL import, tree navigation, same-runtime new/resume, dream, and reload.
  • Added parser, RPC guard/discovery, server mapping/action, dispatcher/ranking, composer race/failure, attachment-preservation, and mapped-action coverage. Updated root, RPC, extension, dashboard, and package documentation.
  • Stabilized the Groq Qwen compatibility regression test against upstream model-catalog removal discovered during verification.

Verification completed successfully in the commit hook: 5,439 passed, 0 failed, 711 skipped. npm run build, npx biome check ., git diff --check, and workspace-link verification also pass.

Commit: 87007ab


Progress tracked by mach6

@m-aebrer
m-aebrer marked this pull request as ready for review August 4, 2026 18:34
@m-aebrer

m-aebrer commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Code Review

Critical

None.

Important

  1. Dashboard-invalid built-ins are not covered end to endpackages/dashboard/test/client/builtin-commands.test.ts, packages/dashboard/test/client/screens.test.tsx, and packages/dashboard/test/server.test.ts cover only copy or a valid fork DTO. The approved opt-out set is copy, hotkeys, and buddy, and manual QA specifically observed hotkeys and buddy appearing. Parameterize coverage across all three, including RPC/server metadata propagation, autocomplete exclusion, typed interception, no api.prompt, and terminal-only guidance. Confidence: 99.

  2. Most mapped built-in actions lack composer-routing coveragepackages/dashboard/src/client/screens/session.tsx adds handlers for settings, model, export, import, name, session, fork, tree, new, compact, dream, resume, reload, and quit, but only /fork is exercised through the real composer path. Add focused or table-driven integration tests proving each command selects the intended action, preserves argument semantics, rejects unsupported arguments visibly, and never calls api.prompt. Confidence: 98.

  3. RPC fail-closed dispatch is tested only for promptpackages/coding-agent/test/rpc-dashboard-commands.test.ts does not exercise the guards added to steer and follow_up. Add dispatcher tests proving built-ins are rejected before session.steer/session.followUp, plus an unknown/prefix command such as /forklift that remains ordinary model input. Confidence: 98.

Suggestions

  1. The pending command-discovery race is not directly testedpackages/dashboard/test/client/screens.test.tsx covers a rejected discovery request, not a still-pending one. Use a deferred api.commands() promise, submit /fork before it resolves, verify the RPC rejection is visible and composer state is preserved, then resolve discovery and verify the dashboard action works. Severity: medium. Confidence: 96.

  2. Unknown and built-in-prefix slash text lacks composer integration coverage — parser unit tests cover /forklift and unknown commands, but the composer path does not prove they reach api.prompt() unchanged. Add integration assertions for both. Severity: medium. Confidence: 93.

  3. Cancelled import, resume, and tree navigation return silently — in packages/dashboard/src/client/screens/session.tsx, these flows use if (result.cancelled) return, leaving the modal open without feedback when a cancellable session-switch hook declines the operation. Show an explicit modal error or action notice, consistent with the new-session flow. Severity: low. Confidence: 85.

  4. Autocomplete filtering has a redundant condition — in packages/dashboard/src/client/builtin-commands.ts, name.startsWith(query) || name.includes(query) can be name.includes(query) because prefix ranking is handled separately in the comparator. Severity: low. Confidence: 95.

  5. Deduplication fetches a map value only to test existence — in packages/dashboard/src/client/builtin-commands.ts, replace const existing = byName.get(...) plus !existing with byName.has(...) for clearer intent. Severity: low. Confidence: 92.

Strengths

  • Current source correctly marks copy, hotkeys, and buddy with dashboard: false, forwards that field through RPC/server, excludes them from autocomplete, and still intercepts typed occurrences with terminal-only guidance. The reported manual-QA behavior was not reproducible from the reviewed source at head.
  • The two-layer interception is fail closed: dashboard dispatch handles discovered commands, while RPC rejects recognized built-ins across prompt, steer, and follow_up.
  • Built-in collision precedence, future-command discovery, attachment preservation, and the extension SDK boundary are handled cleanly.
  • The new RPC discriminated types and extracted dashboard command helpers are well structured and testable.

Agents run: code-reviewer, error-auditor, test-reviewer, completeness-checker, simplifier


Reviewed by mach6

@m-aebrer

m-aebrer commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Review Assessment

Review: #425 (comment)

Classifications

Finding Classification Reasoning
1. Dashboard-invalid built-ins lack end-to-end coverage genuine Factual: Source marks copy, hotkeys, and buddy with dashboard: false, but RPC/server/composer tests exercise only copy or valid fork; no end-to-end assertion covers hotkeys or buddy. Scope: The approved decisions explicitly name all three opt-outs, and manual QA implicates the two untested members, so all three must be verified before merge.
2. Most mapped actions lack composer-routing coverage genuine Factual: session.tsx defines all 14 approved handlers, but the real composer test submits only /fork; endpoint tests do not prove composer parsing, arguments, action selection, or no api.prompt(). Scope: These actions are explicitly included and are newly added testable behavior, so representative/table-driven composer coverage must ship.
3. RPC fail-closed dispatch is tested only for prompt genuine Factual: The guard precedes session.steer() and session.followUp(), but dispatcher coverage exercises only prompt. Scope: The no-leak contract covers all three model-bound ingress paths, including streaming dashboard submissions, so direct tests are required.
4. Pending command-discovery race is not directly tested genuine Factual: Existing coverage waits for command discovery to reject before submission; it does not submit while discovery remains pending. Scope: Startup races were explicitly identified as a required fail-closed case, including visible rejection and preserved composer state.
5. Unknown and prefix slash text lacks composer integration coverage genuine Factual: Helper tests cover /forklift and unknown commands, while composer coverage only proves a known resource command reaches api.prompt(). Scope: Approved acceptance behavior requires unknown slash text and built-in-like prefixes to reach the model unchanged.
6. Cancelled import, resume, and tree navigation return silently deferred Factual: These flows return on result.cancelled with their modal left open and no new feedback. Scope: This is a valid UX improvement, but cancellation feedback was not required to deliver slash interception safely.
7. Redundant autocomplete filter condition nitpick Factual: `startsWith(query)
8. Map lookup used only as an existence check nitpick Factual: get() plus a truthiness check behaves like has() for stored CommandDto values. Scope: Clarity only; collision behavior is unchanged.

Manual-QA Reconciliation

At clean head 87007ab, current source marks copy, hotkeys, and buddy as dashboard: false, transports that value through RPC/server, and filters those entries from autocomplete. Typed occurrences intentionally remain recognized and show terminal-only guidance. If the report refers to autocomplete, it conflicts with clean-head source behavior and may indicate a stale served bundle/runtime or deployment mismatch. The missing end-to-end coverage means the report must still be reproduced from a clean build rather than dismissed.

Action Plan

  1. Parameterize end-to-end coverage for copy, hotkeys, and buddy, then rebuild from clean head and repeat the reported manual QA.
  2. Add table-driven composer-routing tests for every approved mapped action, including argument semantics and assertions that api.prompt() is never invoked.
  3. Extend real RPC dispatcher coverage across prompt, steer, and follow_up, with unknown and built-in-prefix controls.
  4. Test composer submission while command discovery remains pending, including visible RPC rejection, preserved composer state, and successful handling after discovery resolves.
  5. Add composer integration tests proving unknown slash text and prefixes such as /forklift reach api.prompt() unchanged.

Assessment by mach6

@m-aebrer

m-aebrer commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Progress Update

Addressed genuine review findings 1–5 with expanded regression coverage:

  • Covered copy, hotkeys, and buddy end to end across RPC metadata, server transport, autocomplete exclusion, typed interception, and terminal-only guidance.
  • Exercised every approved mapped dashboard action through the real composer, including optional arguments, rejected arguments, and all /dream forms.
  • Verified fail-closed built-in rejection across RPC prompt, steer, and follow_up, with unknown-command and built-in-prefix controls.
  • Added the pending command-discovery race: RPC rejection preserves the composer, then dashboard dispatch succeeds after discovery resolves.
  • Proved unknown slash text and /forklift reach api.prompt() unchanged through the composer.

Current production source already implements the reported /hotkeys and /buddy filtering correctly, so this batch adds the missing proof rather than changing working behavior.

Verification passed: full build, full test suite, Biome, diff checks, and workspace-link verification. The commit hook reported 5,479 passed, 0 failed, and 711 skipped.

Commit: 142bf0a


Progress tracked by mach6

@m-aebrer
m-aebrer merged commit dc76566 into aebrer:master Aug 4, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard: /fork command passed to LLM instead of intercepted

2 participants