WaitBuddy
An Agent long-task monitor for the DSH session view, with lightweight games
Monitoring first · read-only · one-way Agent → game signals
中文 · Changelog · Acceptance Runbook · GitHub
Current version 0.4.1: M1 status board + M2 games + M3 core one-way signals. Tested on DSH
0.2.1-rc.5.
Table of Contents
- What is this
- Features
- Quick start
- Usage
- Configuration
- Architecture
- Compatibility and known deviations
- Development
- Project layout
- Documentation
- Roadmap
- Security and privacy
- Contributing
- License
What is this
WaitBuddy is a session-view plugin for DSH Desktop. It adds a WaitBuddy tab next to Chat / Trajectory in the current session and lets you:
- see what the Agent is doing: status, completed steps, latest commands/tool calls;
- get a visible secondary reminder for pending approvals and task failures;
- play Snake or Gomoku while waiting for a long task;
- in M3, let Agent events one-way drive the game: pause on approval, +5 per step, +50 on success.
It never controls the Agent, never intercepts the native approval dialog, and never writes to the session log.
Features
Monitoring
- Session view: registered on
conversation.view, next to Chat / Trajectory. - Honest status: loading / ready / degraded / stale; a missing projection is never shown as “idle”.
- Real step count: “N steps completed”; no total steps, no fake percentage.
- Activity feed: only
tool/callcommand/tool entries (max 3); no raw model reasoning (D27). - Dedicated alert rail: approval/failure alerts live outside the scrolling content and stay visible.
Games
- Snake: Canvas, no external assets, keyboard arrows; direction queue, pause/reset, speed presets.
- Gomoku: 15×15, human black vs heuristic AI; difficulty presets; redraws on resize.
- Both games keep their own state; switching view/session pauses but does not reset.
One-way signals (M3)
- Approval appears → the game pauses automatically with “Waiting for approval”.
- Approval is resolved → no auto-resume; the overlay shows “Handled — press Space or click Resume”.
- step +5, success +50, failed/abort only show a notice; the current round is not reset.
- Signals are published as
agent:*; the game only consumes them. The monitor layer defines no rewards.
Quick start
Requirements
- DSH Desktop
0.2.1-rc.5(the only tested version) - Node.js 22+ and pnpm for local development
Install
In DSH: sidebar → Plugins → Add plugin, then use one of:
| Method | Value | Notes |
|---|---|---|
| Git (recommended, includes 0.4.1) | github:CelineHuangdz/dsh-wait-buddy |
Follows the latest commit |
| Local directory | /abs/path/to/dsh-wait-buddy |
For development; run pnpm install first |
| Tarball | absolute path to dist/dsh-wait-buddy-0.4.1.tgz |
Create with npm pack --pack-destination dist |
| npm | dsh-wait-buddy |
The npm version may lag behind this repository |
After installing, enable the plugin and refresh the page, then select WaitBuddy in the session view tabs.
For a local directory, run
pnpm installfirst (the Host half useszodfor projection schema validation).
Usage
- Open a session and switch to WaitBuddy.
- Send a task: status, steps and activity update from
turn/start/step/end/tool/call. - Click Start game to play Snake; arrow keys require focus inside the view (click the board once).
- When approval appears, the game pauses; handle it in the native approval panel, then resume manually.
- On success, +50 points; switching views does not replay the toast.
Arrow keys only act inside the view and never steal composer keys. Touch/pointer-only devices cannot control direction (D7, approved deviation).
Configuration
| Item | Storage | Values |
|---|---|---|
| Snake speed | localStorage → dsh-wait-buddy.settings.v1 |
Slow / Normal / Fast |
| Gomoku difficulty | Same | Easy / Medium / Hard |
- Settings are local only; no upload, no cross-device sync.
- Best score and the current round are in memory only (M4 candidate).
- No environment variables or remote configuration.
Architecture
Host (index.js)
session log ── pure fold ──> waitbuddy projection (stateVersion 4)
│
Client (client.js) ▼
projection + sessionStatus ──> composeMonitor ──> TrackState ──> WaitBuddyView
│
└── diffMonitorSignals ──> agent:* SignalHub
│
▼
gameStore (snake)
- Host: registers the
waitbuddysession projection; pure fold, read-only, never writes logs. - Client:
conversation.viewentry; merges the durable projection with process-localrunning/pendingInteraction. - M3 signal layer:
task_start/step_advance/approval_enter/approval_leave/task_finish. - Game layer: consumes signals only; no direct monitor reads, no reverse-control API.
Compatibility and known deviations
| Capability | Status |
|---|---|
| M1 status board | ✅ |
| M2 Snake / Gomoku | ✅ |
| M3 signals / approval pause / +5/+50 | ✅ core; real approval pause + manual resume verified |
| D7 soft buttons | Approved deviation: keyboard arrows only |
| D16/D17 Gomoku/settings | Approved deviation: M4 scope shipped early |
| D28 question / plan-review | Deferred; next iteration |
| D22 unknown terminal | aborted + reason text; no new enum |
- Verified on DSH
0.2.1-rc.5; other versions are not promised. - 320px is covered by visual regression; run a real double-instance smoke before release.
- Real DSH Canvas drawing and the native approval chain are outside automated coverage (see the Runbook).
Development
pnpm install
npx playwright install chromium # required for visual tests the first time
npm test # 59 unit/component cases
npm run test:visual # 4 headless layout scenarios (with host tabs / Todo dock / composer)
npm run test:all # both
- CI:
.github/workflows/ci.ymlrunsnpm test+npm run test:visualon push/PR. - Tests:
test/*.test.js; visual script:tools/visual-layout.mjs. - Visual tests render the real view with React server rendering and inspect spacing, horizontal overflow, alert position and pause copy in Chromium.
Change process
- Update docs first: UI/copy → docs/ui-spec.md; boundaries/trade-offs → docs/decisions.md.
- Then change code so implementation matches docs.
- The M0 baseline is frozen; semantic changes must be recorded in decisions.
Project layout
index.js Host half: waitbuddy session projection (pure fold, read-only)
client.js Client half: conversation.view + monitor + UI + games + M3 signal consumer
cordis.patch.yml Bundler entry: id = wait-buddy
locale/*.json Plugin manager title/description
icon.svg Plugin icon
docs/ Baseline, UI spec, decisions, reviews, acceptance, release docs
test/ node:test unit/component tests
test-support/ Test loader (VM + minimal browser stubs)
tools/ Headless visual layout checks
CHANGELOG.md Release notes
Documentation
| Document | Content |
|---|---|
| M0 baseline | Frozen product baseline |
| M0 compliance | Implementation vs baseline, deviations |
| M1 acceptance | M1 acceptance record |
| M3 implementation | Signals, pause, rewards |
| UI spec | Layout, copy, interaction spec |
| Decisions | ADR-lite, D1–D28 |
| Acceptance Runbook | Manual checks and pass criteria |
| Reviews | 2026-11-05 review archive |
| Iteration plan | Backlog and iteration plan |
| Release Runbook | Packaging, npm, Git distribution |
| CHANGELOG | Version history |
Roadmap
- 0.4.x: fix real-device regressions; add DSH end-to-end coverage (approval, two instances, Canvas).
- Next iteration: evaluate D28 question/plan-review; M4 candidates (more games, score persistence, wait stats/export).
- Never: in-game approval, auto-approval, or any reverse control over the Agent.
Security and privacy
- The plugin runs inside the DSH process with the current user's permissions; there is no sandbox.
- Read-only session events; no session-log writes; no network requests; no telemetry.
- Settings are stored only in local
localStorage. - The activity feed may show tool/command arguments (paths, queries); raw model reasoning was removed by D27.
- The plugin never registers, replaces, or intercepts the native approval panel.
Contributing
- Open an issue/discussion first; for UI/behavior changes, update docs first.
- Run
npm run test:allbefore submitting a PR. - Do not add reverse control, composer replacement, or fake progress (see decisions.md).
No comments yet. Be the first to write one.