Peak-hour auto session gate: weekend mode + global peak auto-pause + session-level freeze/resume + backend auto-retry, auto-resume on off-peak.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-session-guard
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
dsh-session-guard
- English README
- 中文 README
- 日本語 README
- 한국어 README
- README en français
- README auf Deutsch
- README in italiano
- README на русском
- README en español
- Installation guide
- 中文安装指南
- 日本語インストールガイド
- 한국어 설치 안내
- Guide d'installation en français
- Installationsanleitung auf Deutsch
- Guida all'installazione in italiano
- Руководство по установке на русском
- Guía de instalación en español
- Changelog
- 日本語 changelog
- 한국어 changelog
- Changelog en français
- Changelog auf Deutsch
- Changelog in italiano
- Changelog на русском
- Changelog en español
Compatibility note: v0.1.1 ships Japanese (
ja) and Korean (ko) dictionaries, but the current official DSH releases expose onlyzhandenthroughLocaleRuntime. On stock DSH, selectingjaorkofails withlocale "<id>" is not registered. These languages will work after official DSH adds the locale IDs. Advanced users can use a DSH fork that updatesLOCALE_IDSandLOCALESlabels, then rebuild.
▼ DSH version compatibility
DSH version Load Settings registration Session events / gate Client half 0.1.0-rc.7 ~ 0.1.1-rc.x ✅ (2.x / 0.2.x line) ctx.settings.register(ns, schema, { base })✅ same shape ✅ no platform value imports 0.1.2-alpha.2+ / 0.1.2-rc.1 ✅ (2.x / 0.2.x line) registerstill present (installSectionadded)✅ same shape ✅ no platform value imports 0.1.5-rc.2 ✅ (3.x dedicated line compat/0.1.5)registerunchanged (string namespaces)✅ events read via snapshotEvents()dual path✅ 3.x is the 0.1.5 dedicated line: engines/peers narrow to
>=0.1.5-rc.2 <0.2.0-0; 0.1.0-rc.7~0.1.2 hosts should stay on the 2.x / 0.2.x line (main). 0.1.5 adaptation (compat/0.1.5 branch, v3.0.0): ① dual-path resume enqueue — 0.1.5 turns Inbox into an agent-loop read-only projection; ifagent.followupis gone the plugin falls back toagent.send, and degrades to a warn (never throws) when neither exists; ② resume messages now carrysource.form: 'instructions'(0.1.5 ContextFormed contract; older versions ignore it); ③webServer.registeris wrapped in try/catch so a failed registration only logs instead of breaking host loading; ④ 0.1.5 removes thesession.eventsarray accessor — events are now read viasnapshotEvents()(legacy array kept as fallback), affecting only thefindToolOutcome/lastUserPrompthelper paths. Verified that 0.1.5WebRoute(exact/prefix + SSE) contract is unchanged — clientfetch('/session-guard/...')needs no/apiprefix. The 2.x-line table (one artifact, both versions) is kept below.session/event,agent.cancel,goals.pause,agent.followup,commands.register,timer.interval,webServer.register,agent/request,llm.listConfigurableProvidersandsettings.register/getare signature-identical betweendsh-v0.1.1-rc.2anddsh-v0.1.2-rc.1(3.x verified againstdsh-v0.1.5-rc.2). The one seam that needs a dual read is thetool/resultcall id (content[].toolCallIdfirst,source.callIdas fallback) — both forms appear in replay logs of both versions. It now lives insrc/tool-call-id.jswith unit tests. Since 0.1.5 thesession.eventsarray accessor is removed; 3.x reads events throughsnapshotEvents()(with the legacy array as fallback), affecting only thefindToolOutcome/lastUserPrompthelper paths. Themodel/selectionevent exists only on 0.1.2+ and is feature-probed; the settings surface uses only theregister+getintersection (neverinstallSection, never the removedinstallSettingsSection). Drift guard:tools/check-api-drift.ps1(3.x defaults to asserting againstdsh-v0.1.5-rc.2).
Automatically pause running sessions during peak pricing hours and resume during off-peak/weekend; pair with input-traffic's freeze button for per-session locking; backend auto-retry yields during freeze/gate. Core based on a custom session gate (
agent.cancel keepInbox + goals.pause + session/event safe boundary + followup resume), no longer depending on dsh-task-control.
A cordis plugin assembled via the dsh plugin command and a bundle patch — no dsh source changes, no PR required.
💡 Why recommended: DeepSeek moved to peak/off-peak billing on 2026-08-17 — the peak window (Beijing time 09:00-12:00, 14:00-18:00) costs 2× the off-peak rate. This plugin auto-pauses running sessions during peak and auto-resumes off-peak, saving up to 50% on long-running sessions; manual freeze (via input-traffic button) provides per-session precision.
Features
- Weekend mode: detects weekends (timezone-correct via
Intl.DateTimeFormat, no裸getUTCDay()Beijing-boundary 8-hour bug) → weekends ignore peak/off-peak, run freely. - Peak auto-pause (global): on peak entry (and not weekend), auto-pauses all running root sessions; off-peak auto-resumes all — global switch, no manual action needed.
- Official-source guard (
providerGuard): during peak hours only requests whose target is a DeepSeek official source are blocked; local/third-party providers (e.g.local-35b) keep running. Verdict order = explicit id list →baseURLendpoint → catalog default endpoint → builtin id. - Request-level backstop + deferral queue: sessions started after peak entry, or switched to an official source mid-session, are caught by the
agent/requestguard (defaulthold: the request is suspended without an error and released off-peak). - Per-session freeze / resume:
sessionGuardredundant port +POST /session-guard/rpc, input-traffic freeze button per-session passthrough; also provides/pause /resume /cancelmanual commands. - Backend auto-retry (D9): turn/end transient failures (error/429/max-tokens) auto-retry with adaptive backoff; permanent failures stop; yields during freeze/gate, never bypasses the session gate.
- Fail-open: custom session gate unavailable, session-guard not installed, settings service missing — all silently degrade, never crash on dependencies.
Installation
# DSH 0.1.5-rc.x hosts (this line, dist-tag dsh-0.1.5)
dsh plugin --profile web add dsh-session-guard@dsh-0.1.5
# or straight from the git branch
dsh plugin --profile web add github:drscrewdriver/dsh-session-guard#compat/0.1.5
# DSH 0.1.2-rc.x hosts must use the 0.1.2 line instead
dsh plugin --profile web add dsh-session-guard@dsh-0.1.2
compat/0.1.5 is the DSH 0.1.5-rc.x line, npm version 3.0.0. DSH 0.1.2-rc.x hosts must
use the legacy/0.1.2 branch (npm dist-tag dsh-0.1.2, version 0.3.1). main is frozen at
0.2.0-beta.1 and is no longer the 0.1.2 line's release branch.
⚠️ Do not rely on the bare package name
dsh-session-guard: npm'slatesttag cannot serve two mutually exclusive version lines (theirengines.dshranges are exclusive under semver prerelease matching) — always pin the dist-tag explicitly.
Restart dsh web and refresh the page after installation.
Settings (Settings → Plugins → session-guard, simple toggles)
| Toggle | Default | Description |
|---|---|---|
enabled |
on | Peak auto-pause: auto-pause running sessions during peak hours |
stepLevelPause |
on | Step-level gate: during peak, hold before the next step's model request (earlier and cheaper than turn-level); off = fall back to turn-level pause |
providerGuard |
on | Official-source guard: block only DeepSeek official sources during peak; local/third-party providers keep running |
guardSubagents |
on | Guard subagent requests: subagent requests are billed too, guarded by default |
offPeakAutoResume |
on | Off-peak auto-resume: auto-resume paused sessions off-peak; off = no auto-resume (manual required) |
weekendMode |
on | Weekend mode: detect weekends → no auto-pause on weekends (no peak, run freely) |
deferredResume |
on | Auto-resume after peak: off = deferred requests/sessions stay parked until a manual /resume |
queueFallback |
on | Fallback to lock-wait queue when custom session gate is unavailable (fail-open) |
retryEnabled |
off | Auto-retry (backend): transient failure auto-resume (off by default, conservative) |
Additional configuration:
timezone(default Asia/Shanghai) — used for weekend detection and badge display; does not affect peak/off-peak detection (always Beijing time);peakWindows(default 09:00–12:00 / 14:00–18:00) — peak windows in Beijing time (UTC+8), matching DeepSeek's official billing;pauseMode(safe/force),pauseReason(wait/stop);stepGateTimeoutMs(default 300000) — step-gate hold timeout; on expiry the gate is released and the session escalates to a turn-level pause (anti-deadlock, and no "one step per 5 minutes" token drip);- Official-source guard:
officialProviders(extra official provider ids, comma separated, highest priority),officialBaseURLs(official endpoint hosts, defaultapi.deepseek.com); - Deferral queue:
deferredMode(hold/error),deferredResumeText,deferredMaxHoldMs(hold cap, default 6h, then converts to an error); - Retry parameters:
retryText,retryGraceMs,retryCooldownMs,retryBackoffFactor,retryBackoffMaxMs,retryMaxConsecutive.
Behavior
Peak auto-gate (global)
- Peak entry (and not weekend): with
stepLevelPauseon, the running turn is no longer interrupted — the session runs to the nextagent/pre-stepboundary where the step gate holds it (see below); with it off, callsgate.stopNextTurnon all running root sessions (custom session gate truly pauses, or falls back to lock-wait queue perqueueFallback); - Off-peak / weekend: first
releaseAllthe held steps (the turn just continues in place), thengate.resumeall sessions — controlled byoffPeakAutoResume; - Peak timezone: hardcoded to Beijing time (
Asia/Shanghai), matching DeepSeek's official billing basis — not affected by thetimezonesetting; - State machine: single-instance
NORMAL ↔ PAUSED_PEAK(scheduler.js), driven by a single 30s tick.
Step-level gate (v0.2.0, the token saver)
Hooks the agent/pre-step waterfall and holds the turn before the next step's model request happens.
- Hold conditions (all required):
enabled+stepLevelPause+step > 1+ peak (Beijing time, not weekend) + official target provider (providerGuard; all providers when off) + the session is not request-held + not manually bypassed this peak window; - Why
step > 1: the first step of a turn is covered by the request-level guard, so the two gates never overlap; - Release paths: ① the "⏸ paused (resume)" button /
POST /session-guard/rpc {action:'stepResume'}//resume→ lets the current step through and stops gating this session for the rest of the peak window; ② off-peak → release all, the turn continues in place (no followup needed); ③ freeze button //pause//cancel→ release the gate and move to a turn-level pause; ④signalabort → release; - Timeout escalation: holding longer than
stepGateTimeoutMs(default 5 min) releases the gate and escalates to a turn-level force pause, resumed off-peak (no deadlock, no token drip); - State:
GET /session-guard/state?session=<id>returnspaused: { step, turn }andstepGate: { held, since, bypass }; the service port'spausedstays boolean for compatibility, withpausedStepfor the step gate; - Not persisted: the hold is an in-process promise; a restart drops it (no ghost state).
Pause / resume session button (provided by session-guard)
The "Pause session" button in the composer's right row (slot conversation.input.right, id session-guard-pause, order 20, left of input-traffic's "❄ Freeze & append"):
- not paused → "Pause session", clickable: calls
stepPauseand pauses the session before the next step's model request (the current step is not interrupted; step 1 is held too, regardless of peak/provider); - paused → "Resume session", calls
stepResume: lets the current step through and stops gating this session for the rest of the peak window; - push updates:
GET /session-guard/events?session=<id>(SSE) pushes step-gate state changes immediately — when peak auto-holds, the button flips to "Resume session" without waiting for a poll; a 10s/session-guard/statepoll remains as a fallback (SSE down → still converges); - styled to match input-traffic's button in the same row (24px height / 6px radius / 12px font / same CSS tokens), with hover and paused states.
Session locking (freeze)
- Redundant port:
ctx.provide('sessionGuard', service)—stopNextTurn(sessionId)/resume(sessionId)/lockQueue(sessionId)/unlockQueue(sessionId)/state(sessionId); - RPC bridge:
POST /session-guard/rpc { action, sessionId }— input-traffic freeze button callsstopNextTurn/resumepersessionId; silently skipped when session-guard is not installed (fail-open); - Manual commands:
/pause [force|safe] [stop|wait],/resume [confirm] [rerun|skip],/cancel—作用于调用它的会话.
Backend auto-retry (D9)
Listens to turn/end, classifies failures:
- Transient (error/429/max-tokens) → adaptive backoff auto
followup(retryText)resume; - Permanent (auth/balance/model/context limit) → stop;
- Yields during freeze/gate:
isFrozen(sessionId)true (queueLocked / paused / taskControl paused) → no retry; - User intervention or successful turn resets consecutive failure count.
Status badge (frontend display)
A read-only status badge is rendered on the right side of the composer input area, reflecting the current phase in real time:
| Phase | Label | CSS class | Meaning |
|---|---|---|---|
peak (guard on) |
高峰·拦官方 | sg-peak |
Peak hours; only DeepSeek official-source requests are blocked |
peak (guard off) |
高峰·全部暂停 | sg-peak |
Peak hours; every session is paused |
off-peak |
谷时 | sg-off |
Off-peak hours, sessions running normally |
weekend |
周末 | sg-weekend |
Weekend (when weekend mode is on), ignore peak/off-peak |
- Polling: requests
GET /session-guard/statusevery 15 seconds forphase,providerGuard,held,deferred; - Fail-open: route unreachable, network error, or
enabledoff → badge silently hidden, no session affected; - Independent of input-traffic: the badge is rendered by session-guard's client code alone — input-traffic is not required. input-traffic only provides the freeze button, which is unrelated to the badge;
- Tooltip: hovering shows
phase · timezone · weekend mode · verdict scope · held/deferred counts.
Official-source detection (providerGuard)
During peak hours the plugin does not blanket-pause sessions: it first decides whether the route this request will actually use is a DeepSeek official source.
| Priority | Basis | matchedBy |
Example |
|---|---|---|---|
| 1 | officialProviders explicit id list |
explicit |
user declares a self-hosted gateway as official |
| 2 | live baseURL normalized to a host |
endpoint |
deepseek-official pointed at a relay → not blocked |
| 3 | catalog builtin default endpoint | endpoint-default |
pi-ai's deepseek route defaults to the official API → blocked |
| 4 | builtin id list (deepseek-official) |
route-id |
fallback when no endpoint is readable |
| 5 | anything else | unknown |
not official, pass |
- Endpoint beats id: a route named
deepseek-officialwhosebaseURLpoints at a relay is not mis-blocked; conversely pi-ai's builtindeepseekroute is not missed. - Endpoint source:
ctx.get('llm').listConfigurableProviders()→ directory entry →ctx.settings.get(settingsNs)→baseURLviasettingsPath(non-secret fields only;apiKeyEnvvalues are never read). Recomputed per request, never cached → provider config edits apply immediately. - Switching away auto-resumes: if a session paused at peak entry is switched to a local/third-party provider (the
model/selectionevent on 0.1.2+), it is resumed automatically (subject todeferredResume); only sessions this plugin paused at peak entry are touched — a manual/pauseis never overridden. On 0.1.1 there is no such event, so this degrades to "next request or manual/resume". - When the endpoint is unreadable: missing
llmservice, changed namespace shape, non-string field — degrade to id / builtin-endpoint verdict, recordmatchedBy, never throw. - Troubleshooting a wrong verdict:
GET /session-guard/provider?provider=<id>returns{ official, matchedBy, endpoint }.
Request-level guard and the deferral queue
- Why request level: the 30s tick only handles sessions that were
runningat theNORMAL → PAUSED_PEAKtransition; sessions started after peak entry, or switched to an official source mid-session, slip through. Theagent/requestwaterfall runs on every request. - Verdict uses
next()'s return value: the model-selection middleware overrides provider/model inside the waterfall, so we mustawait next()before deciding. holdmode (default): the request is suspended — not sent, no error — and released at the exact off-peak instant (msUntilOffPeaktimer, 30s tick as backstop); abort cancels it normally.errormode: throws a recognizablePEAK_DEFERREDerror + records a deferral, then resumes off-peak withdeferredResumeText(or stays parked whendeferredResumeis off).- Cap:
deferredMaxHoldMs(default 6h) converts a still-held request into an error instead of hanging forever. - Mutual exclusion: while a request is held the plugin never also asks the session gate to pause (a pause waits for a safe boundary that a held request can never reach). Sessions already held are skipped on peak entry.
- No persistence: the deferral queue is an in-process promise; a restart drops it.
Boundaries (explicitly out of scope)
- No provider rerouting: this plugin blocks, it does not switch models.
- Compaction does not go through
agent/request: it cannot happen while a session is paused; a manually triggered compaction during peak may still hit the official source (we do not interceptctx.llm.stream). - 0.1.1 has no
model/selectionevent: auto-recovery after switching to a non-official source degrades to "next request or manual/resume" (immediate on 0.1.2+). - No new npm dependencies, no credential reads, and
dsh-llm-retry's 429 / transport retry behavior is untouched.
Timezone handling
- Peak/off-peak detection: always uses Beijing time (UTC+8) via
BILLING_TIMEZONE = 'Asia/Shanghai', matching DeepSeek's official billing basis. This is hardcoded and not affected by thetimezonesetting; - Weekend detection: uses the user-configured
timezone(e.g.Asia/Tokyo,Asia/Seoul), because "weekend" is a local concept; Intl.DateTimeFormatis used for timezone projection — invalid IANA timezone names throwRangeError, caught by fail-open and falling back toAsia/Shanghai;- Peak windows are left-closed, right-open
[start, end), supporting cross-midnight windows (e.g.22:00–06:00); - The
timezonesetting works identically across all UI languages (zh/en/ja/ko) — IANA timezone names are locale-independent.
Division of labour with input-traffic: one "stops", one "orders"
They act on different links of the same chain, and the boundary is set by DSH's own inbox model:
user input ──(input-traffic picks the tier)──▶ next-step / next-turn pending queues
│
agent/pre-step ──(this plugin's step gate)──▶ pass / hold
│
agent/request ──(this plugin's request hold)──▶ pass / hold
│
model call
DSH queue semantics (two queues — don't mix them up)
| Queue | Meaning | Consumed when |
|---|---|---|
next-step |
"Input awaiting the next step boundary" | The next agent/pre-step: same level as a tool result, another step inside the same turn |
next-turn |
"Prompts awaiting individual turns" | After the current turn closes, as a new turn |
Inbox.claim() always drains next-step first, and only additionally takes one next-turn when that boundary opens a new turn; a turn's first step reads next-turn, every later step reads next-step.
Ownership
- session-guard = stop: decides when progress may happen, and never touches queue content or order.
- step gate (
agent/pre-step): holds before the next step's model request; - turn-level pause (
agent.cancel({keepInbox:true})+goals.pause+ safe boundary): stops the turn, queue preserved as-is; - request-level guard (
agent/requesthold): holds this one model request.
- step gate (
- input-traffic = order: decides which queue user input goes to, at what tier, and when it is consumed.
- three tiers = which queue: red "interrupt" calls
cancel()thensteer; yellow "steer" callssteer(→next-step, the same turn's next step); green "queue" stays innext-turn; - freeze = detach all
queued+steeringrows (tiers preserved) + composer block + callsessionGuard.stopNextTurn; resume = clear the block →sessionGuard.resumefirst → re-submit by tier.
- three tiers = which queue: red "interrupt" calls
Two invariants at the meeting point
- Freeze must let this plugin release the step gate first: the step gate sits at
agent/pre-stepwhile a turn-level pause waits for a safe-boundary event — they would wait on each other (pauseTask/cancelTaskrelease it first); - While the step gate is held, messages are already claimed:
preStep()callsinbox.claim()before dispatching the waterfall, so new input queues behind the claimed batch;keepInboxonly applies to turn-level pauses.
No crossing over: input-traffic does not listen to agent/pre-step / agent/request (the only exception is the "interrupt" tier's explicit cancel(), which the user asked for); this plugin never rewrites next-step / next-turn content or order.
Buttons: this plugin's "Pause session / Resume session" (order 20) and input-traffic's "❄ Freeze & append / Resume & append" (order 30) sit side by side and replace neither — the former owns the step gate, the latter owns queue detach + turn-level freeze.
Redundant port sessionGuard
{
stopNextTurn(sessionId, opts),
resume(sessionId, opts),
lockQueue(sessionId, reason),
unlockQueue(sessionId),
stepPause(sessionId), // request a manual step-level pause (held at the next pre-step)
stepResume(sessionId, opts), // release the step gate (v0.2.0); opts.bypass=false keeps gating this peak
state(sessionId), // { queueLocked, lockReason, paused, pausedStep, stepHeldSince, stepBypass, ... }
}
HTTP routes
GET /session-guard/state?session=<id>— session state (paused: { step, turn, manual }/stepGate/ last target / held / deferred)GET /session-guard/events?session=<id>— SSE: pushes step-gate state changes immediately (drives the button)GET /session-guard/settings— settings + taskControl availabilityGET /session-guard/status— global current phase (status badge polling; includesstepHeld)GET /session-guard/provider?provider=<id>— official-source verdict diagnostics (official/matchedBy/endpoint)GET /session-guard/diag— runtime diagnostics (includesstepGate)POST /session-guard/rpc—{ action: stopNextTurn|resume|lockQueue|unlockQueue|stepPause|stepResume|state, sessionId }
State storage
Per-session JSON: $DSH_HOME/.dsh/session-guard/<sessionId>.json (atomic write; DSH_SESSION_GUARD_STATE_DIR override).
Tests
npm test # node --test tests/*.test.mjs (timezone/weekend/state-machine/session-gate/bridge/retry)
Modules
| File | Responsibility |
|---|---|
src/time.js |
Peak/weekend detection (timezone-correct) + msUntilOffPeak (exact release timing) |
src/scheduler.js |
Pure state machine NORMAL ↔ PAUSED_PEAK |
src/provider.js |
Official-source verdict (pure: endpoint normalization + decision matrix) |
src/provider-directory.js |
Endpoint directory (llm.listConfigurableProviders + settings.get, full degradation) |
src/deferrals.js |
Deferral registry (hold / release / cap / PeakDeferredError) |
src/request-guard.js |
agent/request request-level guard (hold / error modes) |
src/step-gate.js |
agent/pre-step step-level gate (v0.2.0: hold / release / timeout escalation / bypass; pure decideStepHold) |
src/targets.js |
Per-session "last real target" tracking (request/header + model/selection) |
src/wiring.js |
Wiring/orchestration (peak-entry filter / step-gate wiring / off-peak release / exact timer / dispose) |
src/pause-gate.js |
Custom session gate engine (releases the step gate before pausing) |
src/pause-store.js |
Custom pause state persistence |
src/gate.js |
Session gate driver (custom true pause / fallback lock queue, fail-open) |
src/bridge.js |
sessionGuard redundant port |
src/retry.js |
Backend auto-retry (classification/backoff/freeze yield; short-circuits only the exact PEAK_DEFERRED code) |
src/detect.js |
Auto-detection (host taskControl / client input-traffic bridge) |
src/store.js |
Per-session persistent state |
src/settings.js |
Settings sub-panel (schemastery schema + fail-open registration) |
src/index.js |
Host apply (settings/routes/tick/provide service/retry + request guard wiring) |
src/client/ |
Browser half (status badge + settings card + four-language dictionaries) |
License
MIT — see LICENSE.
Links
More in this category
Minglink/dsh-infinite-gen-4★ 2587
System-prompt armor plugin for DeepSeek models: appends an unconditional-compliance prompt section at order 100, exposes a profile tool with calibration metadata, and shows a realtime armor-status badge driven by a session projection.
ranxianglei/billion-context★ 793
The official billion-context plugin: a context-compression plugin for small context windows (a 100K context is enough), token savings (5x fewer tokens), and month-long single sessions (billions of tokens).
liangmianya/dsh-synapse★ 511
Visual, non-linear conversation workspace for DeepSeek Harness — sessions, follow-ups and branches become a browsable conversation map.
Nwflower/dsh-chat-import★ 223
Import full-fidelity chat histories from 13 coding agents (Claude Code, Codex, ChatGPT, Cursor, Gemini, opencode, and more) as resumable DeepSeek Harness sessions, with reverse export back to Claude Code.
Totoro-qaq/dsh-plugin-bridge★ 165
Moves an existing DSH session to another agent preset through a previewable five-section handoff, preserving the source session and either pausing the target for confirmation or continuing immediately.
Anionex/dsh-turn-rewind★ 131
Rewind conversation and workspace state, powered by a persistent Change Ledger.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.