@muzi3/dsh-plugin-next-step-waiting
v0.1.4
Published
DSH plugin: wait_for_condition tool — pause and wait for an external action to complete, or ask the user whether to continue. Pluggable detectors (shell command polling / sub-agent judgement) with round-based human check-ins.
Maintainers
Readme
@muzi3/dsh-plugin-next-step-waiting
A DSH plugin exposing one tool:
wait_for_condition — pause and wait for an external action to finish (a login,
manual configuration, a deploy, CI, someone operating a phone), or just ask the user
whether to continue.
Ported from the pi extension @muzi3/next-step-waiting.
Install
dsh plugin --profile <name> add @muzi3/dsh-plugin-next-step-waitingThen add one row to that profile's patch layer
(~/.dsh/profiles/<name>/cordis.patch.yml):
- insert:
- id: next-step-waiting
name: '@muzi3/dsh-plugin-next-step-waiting'
inject: []Restart the profile. The row mounts by package name, so it carries no machine-specific path and can be committed to a dotfiles repo as-is.
Behaviour
One call = detector polling plus round-based check-ins:
- The detector polls at
intervalMs; a success ends the call immediately (detected). - With a detector, the wait is cut into rounds (default 5 minutes). When a
round ends without success, the tool asks once — through DSH's own question
seam — whether to keep waiting:
- keep waiting opens another round, until the detector succeeds;
- stop returns
declinedimmediately, so the agent continues on current facts.
- With no detector → pure confirmation: one question, answered by
continue(orcancelledif dismissed).
Waiting therefore stays observable and interruptible even when the external action takes hours — and never becomes an unattended long sleep.
Parameters
| Parameter | Required | Description |
|-----------|----------|-------------|
| instruction | yes | What the user is expected to do or wait for; shown verbatim in the question |
| check | no | Local shell command polled for completion, exit 0 = done. Default interval 5s |
| checkPrompt | no | Handed to a subagent when no single command can decide. Default interval 60s |
| intervalMs | no | Polling interval; floor 500ms |
| timeoutMs | no | Length of one round, default 300000. Not a global deadline |
check wins over checkPrompt when both are given.
Returned status
| status | meaning |
|--------|---------|
| detected | The detector confirmed the external action finished |
| continue | Pure-confirmation mode: the user chose to continue |
| declined | The user stopped waiting — or no answerer could extend the wait; the external condition is unconfirmed |
| cancelled | The question was dismissed, the call was aborted, or no answerer could put the question at all |
A surface with no answerer — the headless profile mounts none — can never be read
as an answer. continue requires a real confirmation, so pure confirmation there
returns cancelled; a detector round that cannot be extended returns declined.
The message always says which case it was.
Result text always carries detector diagnostics (mode, interval, checks run, last output), which is how the caller tells "the condition is not met yet" apart from "the check command itself is wrong".
Why not a TUI overlay
The pi version paints a non-capturing TUI overlay and listens for Enter/Esc globally. In DSH the agent loop runs on the host, so a tool cannot reach a front end's UI — the web UI renders in a browser, the TUI is a separate front end. So:
- Visibility and interruption go through
ctx.userQuestions, the same seam behindask_user_question. Both front ends render it already, and no extra UI component is needed; - Cancellation rides the tool call's own
exec.signal, so aborting the turn returnscancelledimmediately.
This also means the plugin does not require ask_user_question to be registered
by any particular preset — it only needs the four host services it injects.
Development
npm install
npm testtest/wait-for-condition.test.js drives the plugin's own apply() over stub
shell / subagents / userQuestions services. The stub is the point: the
wait/ask loop is unreachable without a live human answerer, so those branches can
only be exercised by faking the services.
Not covered by these tests: whether a composition loads the plugin, and how a
real front end renders the question. Use dsh --profile <name> --dump-config
plus a real session for the first, and a real session for the second.
Requirements
@deepseek-ai/dsh-tools is a peer dependency, satisfied by the running dsh
installation. It is declared optional: the package is only meaningful inside a
DSH host that already provides that registry.
