Previously /cancel was intercepted inside the 'unknown' branch, and the
comparison used the command WITHOUT the leading slash while parseCommand
returns it WITH one ('/cancel') — the check never matched, so /cancel
always fell through to the unknown-command reply, even with a pending
ask/approval.
Now a first-class command (menu included): closes the TG-side
answer/approval channel when one is pending, otherwise reports that
nothing is awaiting a reply.
Delivery & visibility:
- per-chunk retry with capped backoff on rich/HTML sends; rich failure now
falls back to HTML instead of dropping the reply
- typing heartbeat: refresh sendChatAction every 4s for the whole turn
(a single action expires in ~5s, long turns looked dead)
- turn/end error / abort / crash-recovery notices reach Telegram
(API failures were previously invisible)
- tool/call progress summaries, tool/result failure notices, todo progress
- thinking indicator (one notice per reasoning phase, status only)
- notices prefixed '> ' render as Telegram blockquotes; plain-text fallback
- non-text messages get a hint instead of being silently dropped
- busy feedback: a followup queued mid-turn gets an explicit ack
TG-side answering (dual-path race; UI path untouched, first answer wins):
- ask_user_question questions render with letter options on TG; reply A /
[A] / A,B (multi) / free text / '1: A' per-line for multi-question
- approval requests (approval/request waterfall) answerable from TG:
[A] allow once / [B] reject; /cancel closes only the TG side
Commands: /stop (cancel current turn), /mission (todo snapshot + busy state),
/new (create a session in the current workspace and attach)
Persistence: chat→session bindings stored at $DSH_HOME/
telegram-channel-bindings.json (override: DSH_TELEGRAM_BINDINGS_FILE) and
restored on start — hot reloads and restarts no longer drop attachments.
Host seams without public surface yet are reached with documented structural
casts (userQuestions provider wrap, approval/request waterfall).
Tests: 41/41 pass. Two pre-existing environment failures in bridge.test.ts
(/last history mirror, assistant mirror) now pass: the former was fixed by
the rich→HTML fallback, the latter needed an event-loop flush after the
(void) listener call since resilient delivery lengthens the chain.
After attaching a session, show a button and /last command that load the latest human/assistant turn via session.history so phone users can continue with context.
Co-authored-by: Cursor <cursoragent@cursor.com>
Cordis throws on ctx.apiProxy without inject; use ctx.get and declare apiProxy inject so catalog and model APIs work under dsh web.
Co-authored-by: Cursor <cursoragent@cursor.com>
Align Telegram session list with Web via apiProxy (exclude archived), resume cold sessions on bind, and allow model selection from the phone.
Co-authored-by: Cursor <cursoragent@cursor.com>
Attach via /sessions picker instead of creating parallel agents; mirror the same session trajectory to phone and Web (Codex-style remote).
Co-authored-by: Cursor <cursoragent@cursor.com>