@toddzheng024/dscode-desktop 0.7.39 → 0.7.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/docs/CHANGELOG.md +33 -5
- package/docs/account-login.md +3 -1
- package/docs/acp.md +17 -3
- package/docs/browser-use.md +1 -1
- package/docs/custom-providers.md +3 -1
- package/docs/distribution.md +61 -33
- package/docs/email.md +4 -4
- package/docs/hub-distribution.md +3 -1
- package/docs/opencode-go.md +4 -2
- package/docs/releases/0.7.40.md +13 -0
- package/docs/releases/0.7.41.md +25 -0
- package/docs/session-metrics.md +9 -0
- package/docs/tui-commands.md +10 -7
- package/package.json +1 -1
- package/plugins/acp/index.mjs +3 -1
- package/plugins/acp/models.mjs +47 -0
- package/plugins/custom/config.mjs +1 -1
- package/plugins/custom/index.mjs +1 -1
- package/plugins/desktop/client.mjs +2 -2
- package/plugins/dscode/index.mjs +5 -1
- package/plugins/email/inbox.mjs +1 -1
- package/plugins/i18n/messages.d.mts +2 -0
- package/plugins/i18n/messages.mjs +16 -12
- package/plugins/providers/openrouter-account.mjs +4 -5
- package/plugins/session-metrics/balance.mjs +45 -28
- package/plugins/session-metrics/desktop-client.mjs +2 -2
- package/plugins/session-metrics/desktop-host.mjs +3 -2
- package/plugins/session-metrics/index.mjs +17 -4
- package/plugins/session-metrics/view.mjs +3 -3
- package/plugins/status/index.mjs +127 -0
- package/plugins/status/selection.mjs +6 -0
- package/plugins/triggers/scheduler-service.mjs +1 -1
- package/plugins/triggers/scheduler.mjs +2 -1
- package/plugins/tui-tools/hook-sources.mjs +2 -1
- package/plugins/tui-tools/index.mjs +2 -0
- package/plugins/tui-tools/update.mjs +6 -4
- package/plugins/tui-tools/workspace-discovery.mjs +17 -3
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
DSCODE adds a coding preset, browser workflows, cross-session collaboration,
|
|
4
4
|
memory and task management to the official DeepSeek Harness Desktop application.
|
|
5
5
|
|
|
6
|
-
**Version:** 0.7.
|
|
6
|
+
**Version:** 0.7.41 · **Harness runtime:** 0.2.0-rc.2
|
|
7
7
|
|
|
8
8
|
Preview release candidate; publication is a separate step.
|
|
9
9
|
|
|
@@ -48,7 +48,7 @@ public release; a candidate build alone does not publish a package.
|
|
|
48
48
|
## Install a published version
|
|
49
49
|
|
|
50
50
|
After this version is available on npm, enter
|
|
51
|
-
`@toddzheng024/dscode-desktop@0.7.
|
|
51
|
+
`@toddzheng024/dscode-desktop@0.7.41` in **Plugins → Add plugin**,
|
|
52
52
|
review the installation, install, then choose **Enable now**. Using the exact
|
|
53
53
|
version keeps the installation tied to these instructions and compatibility
|
|
54
54
|
requirements. The `preview` tag tracks the current Desktop preview release.
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
For the self-contained terminal, `DSCODE_HOME` defaults to `~/.local/share/dscode-state`. Legacy installations retain their previous paths; see [migration](distribution.md#migration-from-older-dscode-installations).
|
|
4
|
+
|
|
5
|
+
All notable changes to DSCODE, newest first. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions identify the complete application release.
|
|
4
6
|
|
|
5
7
|
Per-release notes live in [`docs/releases/`](releases/); the entries below summarise them.
|
|
6
8
|
|
|
7
9
|
<!-- Add upcoming changes under Unreleased. -->
|
|
8
10
|
|
|
11
|
+
## [Unreleased]
|
|
12
|
+
|
|
13
|
+
## [0.7.41] - 2026-10-12
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Ship one self-contained terminal package per Mac architecture with private Node 24.21.0, pinned Harness, compiled TUI and native dependencies. Install and first launch no longer use npm or Hub.
|
|
18
|
+
- Keep terminal data outside the application, isolate existing DSH configuration and terminal preferences, and preserve explicit migration paths for older installations.
|
|
19
|
+
- Replace the complete application only after digest, version, platform and module checks; restore the old program on failed replacement and never move user data. Generate a Homebrew formula for the same archives; external tap publication remains separate.
|
|
20
|
+
|
|
21
|
+
## [0.7.40] - 2026-10-12
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- `/status` in the TUI and ACP reports the selected provider, model, currency and a fresh balance without model inference. DeepSeek and OpenRouter report explicit unavailable, unsupported, timeout and failure states; account funds and key spending limits remain distinct.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Invalidate cached footer and Desktop balances when credentials change or are removed, and reject obsolete query completions. Resolve the credential service at refresh time, including when it becomes available after plugin startup. Native credential updates clear old readings immediately; cached amounts retain their currency and distinguish account balances from fallback key spending limits. Malformed amounts remain unknown instead of becoming zero. `/status` continues to query fresh data independently.
|
|
30
|
+
- Send a labeled ACP failure notice before the failed prompt response, with bounded error data and retry guidance. Preserve cancellation and normal completion semantics. Include recognized network error codes and elapsed time in DeepSeek transport summaries without copying raw error causes.
|
|
31
|
+
- Guide model output to use correct Markdown delimiters for code containing backticks and literal backslashes, and concise labels for long file links. This guidance does not rewrite generated code or guarantee that every model response is valid Markdown.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Filter ACP model choices to providers with configured credentials or account login and saved custom services with no authentication. Retain the current model when credentials are missing, preserve exact routing and the TUI catalog, and check the Harness 0.2 DeepSeek account and API-key routes separately. This checks local configuration, not endpoint reachability, key validity or per-model access; reconnect after credential changes to refresh the picker.
|
|
36
|
+
|
|
9
37
|
## [0.7.39] - 2026-10-10
|
|
10
38
|
|
|
11
39
|
### Fixed
|
|
@@ -397,7 +425,7 @@ The 0.7.37 candidate was cancelled before publication after its Node 22.19.0 cov
|
|
|
397
425
|
### Fixed
|
|
398
426
|
|
|
399
427
|
- Code review asks for thinking off instead of the lightest reasoning level. A DeepSeek reviewer spent its whole 90-second deadline reasoning at `low` (24k-56k reasoning tokens per call) and never wrote a verdict, so reviews of a real diff came back incomplete; with thinking off the reviewer so the deadline is spent on the report instead of tokens that never reach it; a model without an `off` level keeps its own default. `DSCODE_REVIEW_EFFORT` still overrides the level.
|
|
400
|
-
- DSCODE's credentials provider mounts again in a source checkout. A patch can only override a row's config keys and is skipped when its `name` differs from the row it targets, so the overlay that pointed the upstream `credentials` row at DSCODE's provider had mounted nothing outside the npm bundle (which rewrites that name at build time). The upstream row is disabled and DSCODE's provider inserted in its place: the shared
|
|
428
|
+
- DSCODE's credentials provider mounts again in a source checkout. A patch can only override a row's config keys and is skipped when its `name` differs from the row it targets, so the overlay that pointed the upstream `credentials` row at DSCODE's provider had mounted nothing outside the npm bundle (which rewrites that name at build time). The upstream row is disabled and DSCODE's provider inserted in its place: the shared `$DSCODE_HOME/credentials.yaml` store, the read-only Grok CLI login and the per-provider credential facts now agree on both surfaces, and a key saved before this change still resolves through the profile store.
|
|
401
429
|
- The composer no longer rides up on a static flush. Ink clears its repaint ledger every time `<Static>` history is written, so the rows a shrinking frame freed are now kept reserved across that clear (ink.js reports how many rows the static write consumed). The only-ever-pushed-down guarantee covered frames between flushes before this.
|
|
402
430
|
- A running shell command keeps its own output window: every sanitized chunk feeds a per-command buffer, the tool reads that buffer instead of re-reading the shared scrollback on every poll, and a poll without new output no longer replaces the accumulated text with the current viewport. A chatty neighbour on the same terminal — a background job, a release publisher, another session — can no longer make the shell report a dropped beginning for output that was never the command.
|
|
403
431
|
|
|
@@ -477,7 +505,7 @@ The 0.7.37 candidate was cancelled before publication after its Node 22.19.0 cov
|
|
|
477
505
|
|
|
478
506
|
- `/model` searches as you type, with no `/` first, and ranks with BM25 on every keystroke: the model name counts most, then the model id, then the provider. The word being typed matches as a prefix (`kim` finds Kimi, `glm5` finds GLM 5.x); rows matching every word come first, and rows matching some words show only when none matches them all. A changed search focuses no row: Enter or an arrow focuses the first match, and Enter on a focused row selects it. Esc clears the search, then closes; Tab still opens providers and retry moves to Ctrl+R, since letters now always search.
|
|
479
507
|
- Pressing Enter on `/provider`, `/login` or `/openrouter` in the slash-command menu opens its picker straight away, instead of leaving the command in the input for another Enter or a typed argument.
|
|
480
|
-
- `/openrouter` shows the OpenRouter account: the balance, this key's limit and its spend today, this week and this month, and, with a management key, every API key's usage and the last 30 days of spend by model and the providers that served it (`r` refreshes, `m` sets the management key). After the OpenRouter API key is saved in `/provider openrouter` or `/login openrouter`, DSCODE offers an optional management key; it is checked against OpenRouter (an inference key is refused account activity), stored beside the other keys in
|
|
508
|
+
- `/openrouter` shows the OpenRouter account: the balance, this key's limit and its spend today, this week and this month, and, with a management key, every API key's usage and the last 30 days of spend by model and the providers that served it (`r` refreshes, `m` sets the management key). After the OpenRouter API key is saved in `/provider openrouter` or `/login openrouter`, DSCODE offers an optional management key; it is checked against OpenRouter (an inference key is refused account activity), stored beside the other keys in `$DSCODE_HOME/credentials.yaml` (or taken from `OPENROUTER_MANAGEMENT_KEY`), and only read from.
|
|
481
509
|
- A running compaction, automatic or `/compact`, replaces the activity line with a small Tetris bot clearing rows and the message "Compacting context, please wait" (translated with `/language`), plus its elapsed time. A short terminal shows one board row.
|
|
482
510
|
- Picking a model in `/model` (or through `/provider`) whose route would compact the current context asks first: it shows the context size, the new model's threshold and window, and whether the next request overflows. `y` switches, `n`/Esc goes back.
|
|
483
511
|
|
|
@@ -533,7 +561,7 @@ The 0.7.37 candidate was cancelled before publication after its Node 22.19.0 cov
|
|
|
533
561
|
|
|
534
562
|
### Changed
|
|
535
563
|
|
|
536
|
-
- `/login [deepseek|openrouter]` stores either key; without an argument it targets the current provider. `OPENROUTER_API_KEY` joins `DEEPSEEK_API_KEY` in the shared
|
|
564
|
+
- `/login [deepseek|openrouter]` stores either key; without an argument it targets the current provider. `OPENROUTER_API_KEY` joins `DEEPSEEK_API_KEY` in the shared `$DSCODE_HOME/credentials.yaml`, with the same environment precedence. An argument that is not a provider name is refused without being echoed.
|
|
537
565
|
- The footer follows the active provider: its balance is that provider's (OpenRouter: credits minus usage from `/api/v1/credits`), OpenRouter calls are estimated from the pinned pi-ai catalog's list prices (ledger `priceVersion` `openrouter-pi-ai-0.85.1`), and the 🔥/❄️ peak marker shows only for DeepSeek. `/status` names the wire effort Ultra sends on each route, and a missing-credential error now points at `/login`.
|
|
538
566
|
|
|
539
567
|
- `dscode exec` ships in the npm launcher. It runs the installed profile's exec runner with the same options, stdin prompt and exit codes as the source checkout; the argument parser and overlay moved to `plugins/exec/cli.mjs` so both entry points share them.
|
|
@@ -589,7 +617,7 @@ Interface languages, copyable text, a verbose view, accurate TPS figures, and st
|
|
|
589
617
|
|
|
590
618
|
### Added
|
|
591
619
|
|
|
592
|
-
- `/language` switches the interface between English, Simplified Chinese, Traditional Chinese, Japanese, Korean and Spanish. The choice is stored in
|
|
620
|
+
- `/language` switches the interface between English, Simplified Chinese, Traditional Chinese, Japanese, Korean and Spanish. The choice is stored in `$DSCODE_HOME/tui/language.json`, with `DSCODE_LANGUAGE` as a temporary override. The activity line, agents line, welcome box labels, footer telemetry labels, input placeholders, hints and the doctor report are all translated.
|
|
593
621
|
- `/verbose` (Ctrl/Alt+R) shows each step's `· Thinking:`, `· Tool Call:` and `Output:` in a dim style, with up to 8 lines of thinking and a pointer to Ctrl+O for the full history. The toggle is persisted.
|
|
594
622
|
- npm publish tokens can be kept in the macOS keychain via `pbpaste | npm run publish:token store`.
|
|
595
623
|
|
package/docs/account-login.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# DeepSeek account login
|
|
2
2
|
|
|
3
|
+
For the self-contained terminal, `DSCODE_HOME` defaults to `~/.local/share/dscode-state`. Legacy installations retain their previous paths; see [migration](distribution.md#migration-from-older-dscode-installations).
|
|
4
|
+
|
|
3
5
|
DSCODE can authenticate the DeepSeek route with a **DeepSeek account** instead of an API key. The sign-in happens in your system browser; the grant is stored on this machine and the model route picks it up automatically.
|
|
4
6
|
|
|
5
7
|
`/account` is the whole surface:
|
|
@@ -41,4 +43,4 @@ Set `DSCODE_ACCOUNT_LOGIN=0` to remove the listener entirely. `/account login` t
|
|
|
41
43
|
|
|
42
44
|
## Where the credential lives
|
|
43
45
|
|
|
44
|
-
In the same local credential store as your API keys (
|
|
46
|
+
In the same local credential store as your API keys (`$DSCODE_HOME/credentials.yaml`, `0600`), under the account provider's own record. It never reaches the model: account state is a client-safe projection with no token in it, tool results and session logs never carry it, and the command's output is redacted like every other DSCODE command result.
|
package/docs/acp.md
CHANGED
|
@@ -12,20 +12,34 @@ To select an initial model explicitly, use:
|
|
|
12
12
|
dscode acp --model custom-your-provider-id/your-model-id
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Without `--model`, the bridge uses DSCODE's saved default provider and model. Set up credentials and custom services in the normal TUI first with `/login` or `/provider custom`. The stable custom provider ID is recorded in
|
|
15
|
+
Without `--model`, the bridge uses DSCODE's saved default provider and model. Set up credentials and custom services in the normal TUI first with `/login` or `/provider custom`. The stable custom provider ID is recorded in `$DSCODE_HOME/providers.yaml`; it is not the service's display name. API keys stay in the existing credential store. Clients supporting ACP configuration options can select an advertised model and reasoning effort after creating a session.
|
|
16
|
+
|
|
17
|
+
The ACP model picker lists models from providers with configured credentials or account login, plus saved custom services using no authentication. Credential checks follow each provider's configured reference, including environment variables and saved keys. DeepSeek Account and DeepSeek API-key routes are checked separately. Providers with no recognized configuration metadata are omitted.
|
|
18
|
+
|
|
19
|
+
The current model remains listed even when its credentials are missing, so an explicit selection or resumed session is never silently switched to another model. This exception retains only the current model, not that provider's entire catalog. Configured credentials do not prove that a key is valid, credits remain, the endpoint is reachable, or every advertised model is permitted; filtering makes no inference requests. After changing credentials, reconnect the ACP client to refresh its picker. Saved custom service changes also refresh options in connected sessions.
|
|
20
|
+
|
|
21
|
+
## Current credential balance
|
|
22
|
+
|
|
23
|
+
Send `/status` as a standalone text message. The command is advertised to clients and returns the selected provider, model, balance information and query time without a model turn. It also works after switching models or resuming a session. Attachments and ordinary text mentioning `/status` remain normal model input. Arguments are rejected with usage guidance.
|
|
24
|
+
|
|
25
|
+
DeepSeek API keys show the official account balance and currency; DeepSeek account login shows recharge and bonus wallets separately. OpenRouter shows account credits and the current key's remaining spending limit separately, plus the effective budget when provided. A key without a spending cap does **not** mean unlimited account funds. If OpenRouter denies account-credit access but permits key inspection, the key information remains available. Only the active inference credential is used, never a separate management key.
|
|
26
|
+
|
|
27
|
+
Each invocation makes a fresh query using the selected route's configured credential reference. Keys and raw provider errors are not printed. Missing credentials, failed queries and timeouts are reported explicitly; they are not shown as zero. The lookup waits at most eight seconds and supports cancellation. Other providers, including custom API endpoints and subscription routes, currently report that balance lookup is unsupported. An overridden DeepSeek/OpenRouter endpoint is not queried through the official billing API. The result is sent to the client without adding a model-history turn; replay of that display depends on the client.
|
|
16
28
|
|
|
17
29
|
For a source checkout, the equivalent executable is `node` with arguments `["/absolute/path/to/dscode/bin/dscode.mjs", "acp"]`. Source and npm installations use their existing, separate state directories. `--patch FILE` adds a trusted composition overlay and can be repeated. `dscode acp --help` prints usage without starting the runtime or installing a profile.
|
|
18
30
|
|
|
19
31
|
## Behavior and limits
|
|
20
32
|
|
|
33
|
+
- A failed model turn sends a clearly labeled `DSCODE — Request failed` text update before returning JSON-RPC error `-32603`. Error data includes the session ID, a bounded failure code and explanation, and HTTP status when available. The update is a transport diagnostic, not a model-generated answer or a successful completion. Clients that persist text updates can retain it in their history. User cancellation keeps the native `cancelled` result and does not emit a failure notice.
|
|
34
|
+
- DeepSeek transport failures retain recognized low-level network error codes and request elapsed time in their summary. Raw error chains, credentials and response bodies are not added to ACP failure output. A repeated duration alone does not identify the network cause. This is bounded diagnostic feedback, not a complete network trace.
|
|
21
35
|
- New and resumed ACP agents mount the `dscode` preset, including its tools and provider adapters. The bridge reuses DSH's native ACP implementation rather than translating terminal output.
|
|
22
36
|
- ACP sessions use the `ask` permission preset. Tool requests requiring approval are sent to the ACP client; the client can allow once, reject, or cancel. Normal sandbox rules still apply. The terminal's automatic model review is not the approval decision maker for these sessions.
|
|
23
37
|
- Standard session creation, prompts, cancellation, model configuration, listing, resume, close and MCP attachment are inherited from the pinned DSH bridge. Resume reconnects a session without replaying its transcript.
|
|
24
|
-
- The inherited bridge identifies itself as `deepseek-harness-acp`. It does not advertise `session/load`, modes,
|
|
38
|
+
- The inherited bridge identifies itself as `deepseek-harness-acp`. It advertises `/status`; other terminal slash commands are not exposed. It does not advertise `session/load`, modes, terminal delegation, client filesystem operations or interactive question forms. Clients requiring those features need additional integration; a successful protocol handshake does not establish full editor compatibility.
|
|
25
39
|
- Title generation, session-card generation and memory generation are disabled in this transport. Configured providers, tools and other integrations remain available; ACP is not an offline mode.
|
|
26
40
|
- Stdout is reserved for protocol frames. First-install progress and launcher diagnostics go to stderr. Trusted custom patches must also respect this rule.
|
|
27
41
|
- Closing stdin shuts down the runtime. SIGTERM is forwarded by the launcher. Sessions persist in the same installation's state directory, and a running ACP process holds the normal installation lock against upgrades.
|
|
28
42
|
|
|
29
43
|
## Verification
|
|
30
44
|
|
|
31
|
-
`node scripts/verify-acp.mjs` exercises the source CLI with a fixture model and custom API, without paid model requests. Unit tests cover argument validation, preset composition, source and npm launcher routing, cleanup and signal forwarding. Client-specific UI behavior must be verified in the intended editor.
|
|
45
|
+
`node scripts/verify-acp.mjs` exercises the source CLI with a fixture model and custom API, without paid model requests. It checks configured model filtering on creation, selection and resume, rejects unadvertised model selections, and verifies current-model retention after a custom service starts requiring credentials. It also checks that a failure after a tool call sends exactly one diagnostic before the structured prompt error, and that cancellation does not emit a failure notice. Unit tests also cover credential references, account and login records, lookup failures, argument validation, preset composition, source and npm launcher routing, cleanup and signal forwarding. Client-specific UI behavior must be verified in the intended editor.
|
package/docs/browser-use.md
CHANGED
|
@@ -421,7 +421,7 @@ npm run eval:browser -- --model deepseek-flash
|
|
|
421
421
|
```
|
|
422
422
|
|
|
423
423
|
To evaluate a saved custom service, use its `custom-…` ID from
|
|
424
|
-
|
|
424
|
+
`$DSCODE_HOME/providers.yaml` and an explicitly configured model:
|
|
425
425
|
|
|
426
426
|
```bash
|
|
427
427
|
npm run eval:browser -- --provider custom-YOUR-ID --model your-model-id
|
package/docs/custom-providers.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Custom model providers
|
|
2
2
|
|
|
3
|
+
For the self-contained terminal, `DSCODE_HOME` defaults to `~/.local/share/dscode-state`. Legacy installations retain their previous paths; see [migration](distribution.md#migration-from-older-dscode-installations).
|
|
4
|
+
|
|
3
5
|
Use `/provider custom`, or choose **Custom** in `/provider`, to connect a self-hosted or private model API. DSCODE runs its tools in the current workspace; pointing inference at another computer does not move shell commands or file edits to that computer.
|
|
4
6
|
|
|
5
7
|
Saved services appear by name in `/provider`. Choose a service and press Enter to switch to its current or first configured model; `/model` then selects among that service's models. **Custom · add / edit model services** opens configuration instead of switching. A service without a model context window opens its editor so the missing setting can be completed.
|
|
@@ -64,7 +66,7 @@ Automatic review follows its configured model route. When that route is Custom,
|
|
|
64
66
|
|
|
65
67
|
## Persistence
|
|
66
68
|
|
|
67
|
-
Service and model configuration lives in
|
|
69
|
+
The self-contained terminal uses `~/.local/share/dscode-state` as its default `DSCODE_HOME`; legacy and Desktop installations retain `~/.dscode/providers.yaml`. Service and model configuration lives in `$DSCODE_HOME/providers.yaml`; terminal keys use the existing owner-only `$DSCODE_HOME/credentials.yaml` store. In Desktop 0.7.35 and later, existing native credentials take precedence and new keys are saved to the native Harness store (`~/.dsh/.credentials.yaml` by default). Old DSCODE keys remain a fallback; explicit removal clears both copies to avoid reactivating a legacy key. Provider records contain no key values. Each service receives a stable `custom-…` ID and a derived `DSCODE_CUSTOM_CUSTOM_…_API_KEY` credential reference. An environment variable with that exact reference takes precedence over the saved key, following the existing credential-store rules.
|
|
68
70
|
|
|
69
71
|
Configuration is shared across projects and installed versions, written atomically, and reloaded by other running Hosts. Stale editors cannot overwrite newer configuration. Renaming a service preserves its ID, so persisted sessions continue to resolve it. Removing a provider removes its route and writable stored credential; it does not reroute existing sessions or delete their history. An environment-supplied key remains in the environment. If it masks a stored key, clear the environment override before removing the provider to remove that stored key too.
|
|
70
72
|
|
package/docs/distribution.md
CHANGED
|
@@ -1,58 +1,86 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Self-contained package distribution
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The terminal is distributed as one complete application archive per platform. Download `dscode-<version>-darwin-arm64-standalone.tar.gz` for Apple Silicon or `dscode-<version>-darwin-x64-standalone.tar.gz` for Intel. Each archive contains its own Node 24.21.0, pinned Harness, compiled TUI, plugins and native modules. No system Node, npm, pnpm or DSH is needed, and first launch does not download runtime dependencies.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
macOS 14+ is supported. Git is used for repository and patch operations. Google Chrome and macOS Accessibility/Screen Recording permission are needed only for the features that use them. Models, external MCP servers and project tools retain their own configuration and requirements.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Download and run
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
|
|
10
|
+
mkdir dscode-app
|
|
11
|
+
tar -xzf dscode-0.7.41-darwin-arm64-standalone.tar.gz -C dscode-app
|
|
12
|
+
./dscode-app/dscode
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
Keep the extracted directory together. `dscode` is the executable entry; its private runtime and libraries are siblings inside that directory. You can move the complete directory while no session is running. User data does not move with it.
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|---|---|---|
|
|
17
|
-
| `dscode-<version>-darwin-arm64.tar.gz`, `dscode-<version>-darwin-x64.tar.gz` | Prebuilt package: the source tree + the locked `node_modules` installed for that platform + a `.dscode-prebuilt` marker (about 70 MB) | Node, Git; **no npm and no npm registry access** |
|
|
18
|
-
| `dscode-<version>.tar.gz` | Source package: launcher, preset, dependency manifest and the complete lockfile, without node_modules (about 1 MB) | Node, npm, Git; downloads the locked dependencies from npm at install time |
|
|
17
|
+
The optional installer downloads and verifies the same package:
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
```sh
|
|
20
|
+
curl -fsSL https://raw.githubusercontent.com/qiz029/dscode/main/install.sh | sh
|
|
21
|
+
# Pin an exact release:
|
|
22
|
+
curl -fsSL https://raw.githubusercontent.com/qiz029/dscode/main/install.sh | sh -s -- 0.7.41
|
|
23
|
+
# Or install an already unpacked package, without a download:
|
|
24
|
+
sh dscode-app/install.sh
|
|
25
|
+
```
|
|
21
26
|
|
|
22
|
-
|
|
27
|
+
The installer uses standard macOS shell tools, not Node. It verifies the published SHA-256 sidecar before extraction, checks the package with its private runtime, then installs it at `~/.local/share/dscode-app` and links `~/.local/bin/dscode`. Put that bin directory on PATH. Absolute `DSCODE_INSTALL_DIR` and `DSCODE_BIN_DIR` override those locations. An existing foreign command is never overwritten. Re-running the installer for a managed package delegates to its updater. Releases without a self-contained package or checksum are refused; there is no source/npm fallback.
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
## Existing DSH installations
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
DSCODE only installs a `dscode` command. It never creates or replaces global `dsh`, `node`, `npm` or `pnpm` commands. Runtime startup uses absolute package paths. The private Node directory is on PATH only inside DSCODE's process tree, so bundled helpers use the same runtime.
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
curl -fsSL https://raw.githubusercontent.com/qiz029/dscode/main/install.sh | sh -s -- 0.7.8
|
|
32
|
-
```
|
|
33
|
+
Inherited `DSH_*` variables, `NODE_OPTIONS` and `NODE_PATH` are removed before the application starts. DSCODE supplies its own `DSH_HOME` and `DSH_AGENTS_HOME`. Provider keys, proxies, custom CA certificates and the user's remaining tool PATH are preserved. Project-local instructions, hooks and skills remain supported; the standalone application excludes the global `~/.dsh/skills` ancestor root.
|
|
34
|
+
|
|
35
|
+
Sessions, native credentials, provider configuration, caches, user skills and local overrides live at `~/.local/share/dscode-state`, overridable with an absolute `DSCODE_HOME`. This directory must be outside the application and `~/.dsh`, including symlink aliases. Terminal preferences and input history use `tui/` under that directory. Shared DSCODE provider credentials use `credentials.yaml`; Harness-native credentials use `.credentials.yaml`. Custom services use `providers.yaml`; the mailbox uses `email/` unless `DSCODE_EMAIL_DIR` is explicitly set. Local overrides use `.env` and `config/hooks.local.json`, `config/mcp.local.yml` and `config/harness.local.yml` there.
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
The application does not import `~/.dsh` configuration, Hub tokens or the old `~/.dscode/credentials.yaml` automatically. Run `dscode --installation` to inspect the actual program, runtime and data locations. This isolation applies to the terminal package; the separate Desktop plugin deliberately runs inside its owning Desktop application.
|
|
38
|
+
|
|
39
|
+
## Upgrade and rollback
|
|
35
40
|
|
|
36
41
|
```sh
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
sh dscode-install/install.sh
|
|
40
|
-
cd /path/to/project
|
|
41
|
-
dscode
|
|
42
|
+
dscode update # newest published self-contained release
|
|
43
|
+
dscode update 0.7.41 # an exact release, including an explicit rollback
|
|
42
44
|
```
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
Exit running DSCODE sessions and schedulers first. Startup and update share kernel admission locks; each running child retains protection even if its launcher is killed. Both the program location and the selected data directory are protected. Concurrent ordinary sessions from the same package remain supported. A different package must wait until those sessions exit before taking over the same data directory. The stable `dscode-app` profile preserves native model/settings edits in `cordis.patch.yml` across upgrades and package relocation. Generated application defaults live in a separate private base bundle under the data directory.
|
|
47
|
+
|
|
48
|
+
The updater downloads a matching platform archive from GitHub, requires its published SHA-256 digest, checks its version/platform and bundled modules, and only then swaps the complete program directory. A failed check leaves the old program in place; a failed swap or relocated check restores it. Successful updates retain a sibling `dscode-app.backup-<version>-<timestamp>` directory. State never enters the staged package and is not moved or rolled back. The directory swap has a brief rename interval; a new launch in that interval may need to be retried. This is not a filesystem transaction across power failure.
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
A default update never downgrades an application newer than the published release. An explicit version may downgrade only to another self-contained package; older source/prebuilt releases are refused. `/update` schedules this same updater after the TUI exits. Its version check uses GitHub, not npm.
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
## Migration from older DSCODE installations
|
|
49
53
|
|
|
50
|
-
|
|
54
|
+
Old installations remain usable. New archives have a `-standalone` suffix so an old updater refuses them instead of applying the wrong installation or state-migration procedure. Check `type -a dscode` and `dscode --version` before changing your command link; npm, Homebrew and source links may coexist. Install the new package in a separate program directory and remove or rename an old command link only after identifying its owner.
|
|
51
55
|
|
|
52
|
-
|
|
56
|
+
Migration is explicit, with all old sessions and schedulers stopped and a backup made first:
|
|
57
|
+
|
|
58
|
+
- An existing npm/Hub data directory can be selected with `DSCODE_HOME="$HOME/.local/share/dscode-hub"`. The standalone application creates its own stable `dscode-app` profile there and does not reuse the Hub-managed dependency graph. Transfer only the desired user overrides from the old profile into `profiles/dscode-app/cordis.patch.yml`; do not copy node_modules, generated plugin insertions or absolute paths to the old installation. Do not run legacy and standalone applications against the same data concurrently.
|
|
59
|
+
- For a tar/source installation, copy the old `.runtime` contents to a separate data directory, and copy only the desired `.env` and local `config/` overrides into it. Select that directory with `DSCODE_HOME`. To retain native model/settings edits, transfer only user overrides from the old `profiles/tui/cordis.patch.yml` into `profiles/dscode-app/cordis.patch.yml`; exclude generated plugin insertions and paths to the old installation. Keep the original until sessions have been checked. Do not point the new application at the old program directory.
|
|
60
|
+
- To retain shared provider logins, explicitly copy `~/.dscode/credentials.yaml` to `credentials.yaml` in the selected data directory if no destination credential file exists, preserving owner-only permissions. Native `.credentials.yaml` already lives in the old runtime data. Re-login instead if combining stores would be ambiguous.
|
|
61
|
+
- Custom service definitions in `~/.dscode/providers.yaml` and mail in `~/.dscode/email/` can be copied explicitly to `providers.yaml` and `email/` in the data directory. Keep the matching provider keys when migrating custom services.
|
|
62
|
+
- Old terminal UI preferences in `~/.dsh/dsh-code` can be copied explicitly to the new data directory's `tui/`; no other global DSH files need to be copied.
|
|
63
|
+
|
|
64
|
+
Automatic credential merging and conversion of future incompatible session schemas are not provided. Review a resumed session before discarding old data.
|
|
65
|
+
|
|
66
|
+
## Homebrew
|
|
67
|
+
|
|
68
|
+
The release build generates `artifacts/dscode.rb` from the exact two application archives and their checksums. The new formula installs the complete package into `libexec`, links only `dscode`, and has no Node/npm dependency. Its marker makes `dscode update` direct users to `brew upgrade dscode`; Homebrew replaces the whole package, never a separate Hub profile.
|
|
69
|
+
|
|
70
|
+
The maintained tap must adopt this generated formula and switch its updater from npm versions to GitHub release formulas. The repository build does not silently publish changes to the external `qiz029/homebrew-tap` repository. Until that migration is published, use the direct archive or installer; the existing tap may still install the legacy launcher.
|
|
71
|
+
|
|
72
|
+
## Build and release
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
npm run dist # both platform archives plus SHA-256 sidecars
|
|
76
|
+
node scripts/homebrew-formula.mjs # the matching formula
|
|
77
|
+
node scripts/verify-standalone.mjs # qualify this machine's architecture
|
|
78
|
+
make release # full local terminal candidate gate
|
|
79
|
+
make publish # attach terminal assets to GitHub
|
|
80
|
+
```
|
|
53
81
|
|
|
54
|
-
|
|
82
|
+
`DSCODE_PREBUILT_ARCHS=arm64` or `x64` selects one build for development. An empty selection is an error. Builds install the repository lockfile in a fresh staging directory, compile the TUI and apply runtime patches there, then add the official Node archive verified against checked-in SHA-256 hashes. They never copy a developer's node_modules, credentials or runtime state. Both runtime archives include Node's license.
|
|
55
83
|
|
|
56
|
-
|
|
84
|
+
Release CI validates the ARM64 archive and downloads that exact candidate for a separate Intel qualification. Verification covers an unusable foreign Node/npm/DSH on PATH, foreign DSH variables, an untouched global DSH home, native module imports and a real PTY, cold profile composition, local Host diagnostics and local installation. Native macOS permission UI and real model inference remain separate acceptance checks.
|
|
57
85
|
|
|
58
|
-
The
|
|
86
|
+
The default terminal release has no npm or Hub publication dependency. Desktop continues through its own package and verification path. Historical npm/Hub tooling remains documented in [Legacy Hub distribution](hub-distribution.md); it is not used to install or update the self-contained terminal.
|
package/docs/email.md
CHANGED
|
@@ -13,7 +13,7 @@ On narrow terminals, Tab switches between list and preview.
|
|
|
13
13
|
stays on the same message when newer messages arrive.
|
|
14
14
|
|
|
15
15
|
The inbox belongs to the local user and is shared across sessions. Its default
|
|
16
|
-
directory is `~/.dscode/email`; `DSCODE_EMAIL_DIR` overrides it. New directories
|
|
16
|
+
directory is `$DSCODE_HOME/email` for the self-contained terminal (`DSCODE_HOME` defaults to `~/.local/share/dscode-state`). Legacy and Desktop installations retain `~/.dscode/email`; `DSCODE_EMAIL_DIR` overrides it. New directories
|
|
17
17
|
use mode 0700 and messages use 0600. Message content enters session history only
|
|
18
18
|
when selected with Enter. Existing composer drafts and attachments are preserved.
|
|
19
19
|
|
|
@@ -218,7 +218,7 @@ by source content. UIDVALIDITY changes trigger recovery using the original
|
|
|
218
218
|
connection timestamp (at IMAP's second precision) and content identity, instead
|
|
219
219
|
of trusting old UIDs or importing the whole historical inbox.
|
|
220
220
|
|
|
221
|
-
All sessions share
|
|
221
|
+
All sessions share `$DSCODE_HOME/email/imap/connection.json` (or
|
|
222
222
|
`$DSCODE_EMAIL_DIR/imap/connection.json`). It contains the credentials and cursor,
|
|
223
223
|
is written atomically with mode 0600 inside a new 0700 directory, and is guarded
|
|
224
224
|
by a kernel lock. A running TUI polls every 30 seconds even with `/email` closed;
|
|
@@ -284,7 +284,7 @@ and [filter](https://developers.google.com/workspace/gmail/api/reference/rest/v1
|
|
|
284
284
|
permission documentation. Login uses [desktop loopback OAuth with PKCE and state validation](https://developers.google.com/identity/protocols/oauth2/native-app).
|
|
285
285
|
|
|
286
286
|
The client JSON, tokens and sync state are stored privately under
|
|
287
|
-
|
|
287
|
+
`$DSCODE_HOME/email/gmail/` (or `$DSCODE_EMAIL_DIR/gmail/`). Files are atomic 0600
|
|
288
288
|
writes inside a new 0700 directory. `DSCODE_GMAIL_CLIENT_FILE` optionally points
|
|
289
289
|
at an existing client JSON instead of importing it. Keep that file available
|
|
290
290
|
for token refresh. Only one account is supported; reconnecting another account
|
|
@@ -327,7 +327,7 @@ sender supports Gmail app-password connections, not custom IMAP hosts or the
|
|
|
327
327
|
optional OAuth connector. Attachments, CC/BCC and automatic replies are not part
|
|
328
328
|
of this tool.
|
|
329
329
|
|
|
330
|
-
Receipts are shared across sessions under
|
|
330
|
+
Receipts are shared across sessions under `$DSCODE_HOME/email/outbox` (or
|
|
331
331
|
`DSCODE_EMAIL_DIR/outbox`), with private file permissions. `accepted` means the
|
|
332
332
|
SMTP server accepted the mail; it does not prove delivery or that someone read
|
|
333
333
|
it. `uncertain` means the send may have succeeded despite an interrupted
|
package/docs/hub-distribution.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
# npm
|
|
1
|
+
# Legacy npm and Hub distribution
|
|
2
|
+
|
|
3
|
+
The default terminal distribution from 0.7.41 is the [self-contained application package](distribution.md). This guide describes retained legacy npm/Hub tooling and the separate Desktop plugin. The legacy release order below does not apply to the new terminal package. Do not use it as the default installation or release checklist.
|
|
2
4
|
|
|
3
5
|
## Packages and responsibilities
|
|
4
6
|
|
package/docs/opencode-go.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# OpenCode Go
|
|
2
2
|
|
|
3
|
+
For the self-contained terminal, `DSCODE_HOME` defaults to `~/.local/share/dscode-state`. Legacy installations retain their previous paths; see [migration](distribution.md#migration-from-older-dscode-installations).
|
|
4
|
+
|
|
3
5
|
DSCODE can run a session on an [OpenCode Go](https://opencode.ai/docs/go/) subscription: $10 a month for open coding models. You sign in with your OpenCode account; there is no API key to paste. The route is `opencode-go`, next to DeepSeek, OpenRouter and Grok.
|
|
4
6
|
|
|
5
7
|
## Setting it up
|
|
@@ -10,7 +12,7 @@ DSCODE can run a session on an [OpenCode Go](https://opencode.ai/docs/go/) subsc
|
|
|
10
12
|
|
|
11
13
|
`/provider opencode-go` (or `/provider opencode`) before signing in, and `/login opencode-go`, point you to `/opencode login` instead of asking for a key.
|
|
12
14
|
|
|
13
|
-
**Upgrading from 0.7.31**, which used a console API key: that key is no longer read. Run `/opencode login` once. The stored `OPENCODE_API_KEY` stays in
|
|
15
|
+
**Upgrading from 0.7.31**, which used a console API key: that key is no longer read. Run `/opencode login` once. The stored `OPENCODE_API_KEY` stays in `$DSCODE_HOME/credentials.yaml` unused until you remove it.
|
|
14
16
|
|
|
15
17
|
## The account login
|
|
16
18
|
|
|
@@ -21,7 +23,7 @@ DSCODE can run a session on an [OpenCode Go](https://opencode.ai/docs/go/) subsc
|
|
|
21
23
|
/opencode logout remove the login from this machine
|
|
22
24
|
```
|
|
23
25
|
|
|
24
|
-
- DSCODE keeps its own login, stored as `OPENCODE_OAUTH` in
|
|
26
|
+
- DSCODE keeps its own login, stored as `OPENCODE_OAUTH` in `$DSCODE_HOME/credentials.yaml`. It is separate from any `opencode auth login` on the same machine, and signing in or out of one does not affect the other.
|
|
25
27
|
- The login picks the first organisation (by name) with a Go subscription. Requests go to the inference endpoint the OpenCode console names for that organisation. The public `zen/go/v1` endpoint accepts only console API keys, not the login.
|
|
26
28
|
- The access token lasts 30 days and renews itself before it expires. Each renewal replaces the refresh token, and the new one is written back at once. Several DSCODE sessions share the login: when one has renewed first, the others pick up its token instead of failing.
|
|
27
29
|
- If the login is revoked or cannot be renewed, requests fail with a message asking for `/opencode login` again.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# DSCODE 0.7.40
|
|
2
|
+
|
|
3
|
+
Credential-scoped balance snapshots, fresh status queries and clearer ACP failures.
|
|
4
|
+
|
|
5
|
+
- **Cached balance identity:** footer and Desktop balances clear immediately when credentials change or are removed. Late responses from an obsolete request cannot restore the old reading, including during credential resolution or response-body parsing. Refreshes resolve the native credential service when it becomes available after plugin startup. Transient failures retain a previous reading only for the same credential and source; authentication refusal clears it. Billing fixtures cover these transitions without real credentials or paid inference.
|
|
6
|
+
- **Currency and source:** cached amounts retain the reported currency and identify account funds versus a fallback key spending limit. CNY is displayed as CNY, malformed amounts remain unknown, and a valid zero remains zero. The public numeric balance API remains compatible; Desktop adds currency and source metadata. This does not change provider billing or currency conversion.
|
|
7
|
+
- **Fresh `/status`:** the TUI and ACP expose the selected provider and model plus a fresh DeepSeek or OpenRouter balance query, independently of the footer cache. Account funds and key limits remain distinct, credentials are not printed, and unsupported providers, unavailable data, timeouts and request failures have explicit states. The command does not send a model request or change the selected model.
|
|
8
|
+
- **ACP model choices and failures:** the picker lists providers with configured credentials or account login, plus saved custom services that require no authentication, while retaining the current model. Reconnect after credential changes to refresh the picker; local configuration does not prove endpoint reachability or model access. Failed prompts send a labeled notice before the failed response, with bounded transport details and retry guidance. Cancellation and successful completion keep their existing semantics.
|
|
9
|
+
- **Markdown guidance:** model instructions explain delimiters for code containing backticks and literal backslashes, and concise labels for long file links. They do not rewrite generated code or guarantee valid Markdown in every response.
|
|
10
|
+
|
|
11
|
+
Update the launcher with `npm install -g @toddzheng024/dscode@latest`, then run `dscode update` for an existing Hub profile. For official Harness Desktop 0.2.0-rc.2 on macOS Apple Silicon, install `@toddzheng024/dscode-desktop@0.7.40`, enable it, then fully quit and reopen Desktop.
|
|
12
|
+
|
|
13
|
+
Verification of the code passed `npm run check`: lint, both TypeScript gates, 1,129 unit/component tests, native integration, package checks and 63 offline evaluations, with 80.55% first-party `.mjs` coverage. PR CI passed on Node 22 and Node 24, plus Linux e2e. An independent Harness 0.2.0-rc.2 native Host passed packed Desktop usage checks across generation, resume and unload, including temporary native credential updates, removal, obsolete responses, currency metadata and key-limit fallback. Billing and model responses in these probes are synthetic. Public release installation is checked after publication and recorded in issue #16. Real billing, paid model inference, signed Desktop GUI interaction and real mail delivery have no automated case in this change.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# DSCODE 0.7.41
|
|
2
|
+
|
|
3
|
+
DSCODE's terminal now ships as one self-contained application package per Mac architecture, with a private runtime and separate user data.
|
|
4
|
+
|
|
5
|
+
## Self-contained installation
|
|
6
|
+
|
|
7
|
+
Each archive includes pinned Node 24.21.0, Harness, the compiled TUI, plugins and native modules. The installer and first launch no longer need Node, npm, pnpm, a Hub profile or runtime downloads. Runtime patches are applied while building a clean staging tree. External project tools, Chrome and model credentials remain user-configured.
|
|
8
|
+
|
|
9
|
+
## Coexistence with existing DSH
|
|
10
|
+
|
|
11
|
+
DSCODE supplies its own Harness home and private runtime, discards inherited DSH runtime configuration and Node injection options, and installs only the `dscode` command. Sessions, credentials, configuration and terminal UI preferences live outside the package. Generated defaults form a separate base bundle so startup preserves native user overrides across upgrades and relocation. Existing DSH configuration and old DSCODE credentials are not imported automatically; the distribution guide documents explicit migration.
|
|
12
|
+
|
|
13
|
+
## Whole-package upgrades
|
|
14
|
+
|
|
15
|
+
The updater checks the release digest, platform, version and bundled modules before replacing the application. Failed checks preserve the old version and failed swaps restore it. User data is never moved into the update staging tree. Kernel locks protect running sessions; successful updates keep the previous package. The default update does not downgrade and there is no npm fallback. Power-failure transactional recovery is not promised.
|
|
16
|
+
|
|
17
|
+
The build also generates a Homebrew formula consuming the same archives. Adoption by the external tap is a separate publication step; the current tap must not be assumed migrated. Desktop remains a separate extension distribution.
|
|
18
|
+
|
|
19
|
+
## Verification
|
|
20
|
+
|
|
21
|
+
The repository gate passed 1,147 unit/component cases with 80.00% measured first-party `.mjs` coverage. The normal-exit lease regression passed with the existing launcher lifecycle cases. The final provider, email and standalone data-isolation suite passed all 94 cases, and all 28 terminal rendering/panel cases passed. New cases cover environment and path isolation, installer checksum rejection, foreign-command protection, and successful/failed whole-package replacement without moving user data. Archive qualification uses an isolated home and deliberately unusable foreign Node/npm/DSH commands; digest-bound receipts record private native imports, PTY, cold composition, local Host diagnostics, shell installation and settings preservation. Intel rehearsal on Apple Silicon uses Rosetta; release CI also requires a separate Intel runner. See the [verification record](https://github.com/qiz029/dscode/blob/main/docs/verification.md).
|
|
22
|
+
|
|
23
|
+
Lint, both TypeScript configurations, native integration, package checks and 63 offline evaluations passed. After unifying the TUI startup lookup and `/update` routing with the package updater, lint, both TypeScript checks, documentation checks and 21 update/standalone regressions passed. The deferred updater has process tests; the TUI keyboard dispatch has no dedicated end-to-end interactive case.
|
|
24
|
+
|
|
25
|
+
Live provider inference, macOS permission dialogs, public release installation and external Homebrew tap publication are not automated acceptance claims. No power-loss recovery case is provided.
|
package/docs/session-metrics.md
CHANGED
|
@@ -12,6 +12,15 @@ work. Cost outside recorded turn windows is shown separately. Known cached
|
|
|
12
12
|
provider balance or subscription figures are included; opening or refreshing the
|
|
13
13
|
panel does not request new account data or start a model turn.
|
|
14
14
|
|
|
15
|
+
Cached balances retain the provider's currency and identify account funds or a
|
|
16
|
+
fallback key spending limit. USD values use `$`; other reported currencies carry
|
|
17
|
+
their currency code. The terminal marks a fallback limit with `key` (localized),
|
|
18
|
+
and Desktop labels it **Cached key spending limit**. The five-minute balance
|
|
19
|
+
cache is invalidated on native credential updates; removing a credential clears
|
|
20
|
+
its reading, and obsolete queries cannot restore it. Transient lookup failures
|
|
21
|
+
may retain the last reading only for the same credential and balance source.
|
|
22
|
+
Missing or malformed data stays unknown. `/status` makes a separate fresh query.
|
|
23
|
+
|
|
15
24
|
The panel refreshes once per second while visible and clears its state when
|
|
16
25
|
hidden or switched to another session. Refresh failures clear the old figures
|
|
17
26
|
and display an error. Standard sessions and closed sessions have no DSCODE usage
|
package/docs/tui-commands.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# dscode TUI commands
|
|
2
2
|
|
|
3
|
+
For the self-contained terminal, `DSCODE_HOME` defaults to `~/.local/share/dscode-state`. Legacy installations retain their previous paths; see [migration](distribution.md#migration-from-older-dscode-installations).
|
|
4
|
+
|
|
3
5
|
Restart `dscode` to load these commands. Most commands run locally; `/doctor` makes one bounded call to the selected model for analysis. At startup the TUI reads the npm registry once, within eight seconds, and shows a notice when a newer release exists; set `DSCODE_UPDATE_CHECK=off` to skip that check.
|
|
4
6
|
|
|
5
7
|
If a provider rejects a request for content filtering, the turn stops with a `CONTENT_POLICY` or `CONTENT_FILTER` error and keeps the provider's explanation. Review the request and relevant context before sending a follow-up in the same session. The default retry policy does not repeat these rejected requests, and changing an API key does not resolve a content-filter rejection. DSCODE cannot identify the triggering passage unless the provider supplies it.
|
|
@@ -10,11 +12,12 @@ If a provider rejects a request for content filtering, the turn stops with a `CO
|
|
|
10
12
|
| `/status` | Session ID, workspace, model route, permission mode, recorded token totals/context pressure, tool/plugin counts. Unknown usage stays unknown. `/review-usage` reports the independent reviewer separately. |
|
|
11
13
|
| `/provider [deepseek\|openrouter\|grok\|opencode-go\|custom]` | For self-hosted or private APIs, `/provider custom` opens [Custom model providers](custom-providers.md). Saved custom services also appear by name in the picker: Enter switches to their current or first configured model. The Custom entry adds or edits services. Switch the session between DeepSeek's official API, OpenRouter, Grok and OpenCode Go. Without an argument, open a picker (↑↓ choose, Enter switch, Esc close) that shows each provider's key status. OpenRouter is DSCODE's own adapter over OpenRouter's live model listing (cached for a day in `$DSH_HOME/openrouter-models.json`, settings in the `llm-openrouter` section; `/model` offers DSCODE's curated list from that listing rather than all of it); a switch asks for the key when none is stored, then moves to the counterpart of the current model and keeps the effort when the target offers it. When the new model would compact the current context, the switch asks first. Ultra works on both routes: on OpenRouter it sends `xhigh` plus the collaboration policy, and `low` is sent as `high`, which is how DeepSeek itself answers low. The footer shows the active provider's remaining balance (for OpenRouter, the account's remaining credits, or the key's own remaining limit when OpenRouter refuses the key those) and records the cost OpenRouter reports for each call (estimated from list prices only when it reports none); the 🔥/❄️ peak marker appears only for DeepSeek, because OpenRouter bills no peak window. OpenCode Go serves its chat-completions models to an OpenCode account login, never a key: before `/opencode login` the switch names that command instead of asking for a key, and the footer shows the subscription's usage instead of a cost; see [OpenCode Go](opencode-go.md). Stop a running turn first. |
|
|
12
14
|
| `/model` | Picker for the session's current provider only, listed alphabetically by the displayed model name (digits compare naturally, so GLM 5.2 precedes GLM 5.3). Typing searches as you type (BM25 over model name, id and provider; the word being typed matches prefixes) and narrows the list without re-ranking it; Enter focuses the first match, a second Enter selects it, Esc clears the search then closes, Tab opens the provider picker. |
|
|
13
|
-
| `/opencode [login\|cancel\|logout]` | Sign in to OpenCode Go with an OpenCode account, the route's only credential. `login` shows a code, opens the console in the browser and waits in the background for up to ten minutes; the consent page names the OpenCode CLI, whose login client DSCODE uses. Without an argument it shows who is signed in or how the last attempt ended. The login is stored in
|
|
14
|
-
| `/openrouter` | OpenRouter account panel: the account balance, this key's limit and its spend today, this week and this month; with a management key, also every API key's usage and the last 30 days of spend by model and serving provider. `r` refreshes, `m` sets the management key (checked against OpenRouter, stored in
|
|
15
|
+
| `/opencode [login\|cancel\|logout]` | Sign in to OpenCode Go with an OpenCode account, the route's only credential. `login` shows a code, opens the console in the browser and waits in the background for up to ten minutes; the consent page names the OpenCode CLI, whose login client DSCODE uses. Without an argument it shows who is signed in or how the last attempt ended. The login is stored in `$DSCODE_HOME/credentials.yaml` and renews itself. See [OpenCode Go](opencode-go.md). |
|
|
16
|
+
| `/openrouter` | OpenRouter account panel: the account balance, this key's limit and its spend today, this week and this month; with a management key, also every API key's usage and the last 30 days of spend by model and serving provider. `r` refreshes, `m` sets the management key (checked against OpenRouter, stored in `$DSCODE_HOME/credentials.yaml`, read-only use; `OPENROUTER_MANAGEMENT_KEY` also works). Saving the OpenRouter API key through `/provider openrouter` or `/login openrouter` offers the management key as an optional step. |
|
|
17
|
+
| `/status` | Query the current session's provider, model and credential balance without a model turn. Supports DeepSeek API/account login and OpenRouter; account funds and key limits are labeled separately. Uses the active credential, refreshes on every call, and reports unsupported endpoints, missing credentials and query failures explicitly. Also available in [ACP](acp.md#current-credential-balance), which documents the lookup limits. |
|
|
15
18
|
| `/review` | Independent review of the current changes. `DSCODE_REVIEW_MODEL=provider/model` pins the reviewer to its own model and `DSCODE_REVIEW_EFFORT=<level>` sets its reasoning level, so a small session model cannot cap the review; the budget leaves room for reasoning plus the report. |
|
|
16
|
-
| `/update [exact-version]` | Upgrade DSCODE after this session exits: the TUI starts a detached helper that waits for the session to end and then runs the same `dscode update` entry (
|
|
17
|
-
| `/login [deepseek\|openrouter]` | Paste an API key into the private input; it is saved to
|
|
19
|
+
| `/update [exact-version]` | Upgrade DSCODE after this session exits: the TUI starts a detached helper that waits for the session to end and then runs the same `dscode update` entry (whole-package replacement for the self-contained terminal; legacy installs keep their own updater). Progress and the outcome are written to `$DSH_HOME/update.log` and `$DSH_HOME/update-result.json`. |
|
|
20
|
+
| `/login [deepseek\|openrouter]` | Paste an API key into the private input; it is saved to `$DSCODE_HOME/credentials.yaml` (`0600`, shared across projects and installed versions). Without an argument it targets the current provider. `DEEPSEEK_API_KEY` or `OPENROUTER_API_KEY` in the environment takes precedence and makes that key read-only here. |
|
|
18
21
|
| `/memories [status\|on\|off\|global-on\|global-off\|run\|note <text>\|clear]` | Global cross-session memory controls and background model usage. [Behavior and configuration](memory.md). |
|
|
19
22
|
| `/session` | Current session ID, local socket, and external send/read/watch commands. [Multi-source sessions](session-bridge.md). |
|
|
20
23
|
| `/mailbox [cancel MESSAGE_ID]` | Read messages and deferred notes, or cancel a request/message. [Session communication](session-communication.md). |
|
|
@@ -34,9 +37,9 @@ If a provider rejects a request for content filtering, the turn stops with a `CO
|
|
|
34
37
|
| `/review [--staged\|--base REF\|--commit REF] [--path RELATIVE_PATH]` | Independently review the selected Git diff in a read-only, tool-free model request. Default includes tracked and untracked uncommitted changes, and when there are none it reviews the commits made since the latest user task started (read from the HEAD reflog), so work that was committed or merged is still reviewed; `--commit` reviews a merge commit against its first parent; empty scopes do not call the model. Narrow large or unrelated diffs with `--path`. |
|
|
35
38
|
| `/delegate <task>` | Hand the task to the main agent as coordinator: it records the parts on a delegate board, launches them as child agents with `worktree: true` in the background while child slots are free (five below Ultra, twenty at Ultra), answers the questions they send to `/`, verifies each finished worktree, and once every task is done merges the accepted ones into the main workspace with `git apply --3way`, leaving them staged and uncommitted. Refused unless the session starts at a clean Git repository root, and inside a child agent. See [Ultra](dscode-ultra.md#delegate-mode). |
|
|
36
39
|
| `/delegate-dashboard` | Popup kanban of the current session's delegate board with four columns — pending, running, verifying, complete — and the child slots in use. A task is running while its child works or waits on an answer from the main agent (marked `?`), and verifying once the child has settled and the main agent has not yet recorded the result. Columns are divided by vertical rules and every task is its own bordered card with its id, child name and title; `▲` marks high priority and `▼` low. Pending cards run in launch order, ready ones first; a blocked task has a grey card with a hollow `◌` and names what it waits on (`after t1,t2`). Waiting cards lead their column. On a short terminal each card folds to one line so more of them fit, and a narrow terminal stacks the columns. It refreshes every second; Esc or q closes it. |
|
|
37
|
-
| `/verbose` | Toggle verbose chat: thinking and tool calls appear dimmed as `· Thinking: …`, `· Tool Call: name args` and ` Output: …` (thinking capped at eight lines), with a blank line between blocks. The setting is saved per machine in
|
|
38
|
-
| `/mouse` | Toggle mouse capture. On (default) makes the wheel scroll the chat one row per notch, merging the notches that arrive in the same frame; off hands the mouse back to the terminal for drag-select and copy, leaving PageUp/PageDown to scroll the chat. While capture is on, hold Shift (Option in iTerm2, Fn in Terminal.app) to select text. The choice is saved per machine in
|
|
39
|
-
| `/language [code]` | Without an argument, open a picker (↑↓ choose, enter apply, esc close) for the interface language for DSCODE's own labels, notices, the status-line telemetry labels and the composer placeholder: `en` (default), `zh-CN`, `zh-TW`, `ja`, `ko`, `es`. Names and common aliases work too (`简体中文`, `jp`). The choice is saved per machine in
|
|
40
|
+
| `/verbose` | Toggle verbose chat: thinking and tool calls appear dimmed as `· Thinking: …`, `· Tool Call: name args` and ` Output: …` (thinking capped at eight lines), with a blank line between blocks. The setting is saved per machine in `$DSCODE_HOME/tui/verbose.json`. Ctrl/Alt+R toggles the same setting; Ctrl+O still opens the full history inspector. |
|
|
41
|
+
| `/mouse` | Toggle mouse capture. On (default) makes the wheel scroll the chat one row per notch, merging the notches that arrive in the same frame; off hands the mouse back to the terminal for drag-select and copy, leaving PageUp/PageDown to scroll the chat. While capture is on, hold Shift (Option in iTerm2, Fn in Terminal.app) to select text. The choice is saved per machine in `$DSCODE_HOME/tui/mouse.json`. |
|
|
42
|
+
| `/language [code]` | Without an argument, open a picker (↑↓ choose, enter apply, esc close) for the interface language for DSCODE's own labels, notices, the status-line telemetry labels and the composer placeholder: `en` (default), `zh-CN`, `zh-TW`, `ja`, `ko`, `es`. Names and common aliases work too (`简体中文`, `jp`). The choice is saved per machine in `$DSCODE_HOME/tui/language.json`; `DSCODE_LANGUAGE` overrides it for one process. |
|
|
40
43
|
| `/clear` | Start a fresh session and clear the screen after successful activation; the previous session remains available through `/resume`. Stop a running turn first. |
|
|
41
44
|
| Ctrl+L | Clear the screen only, keeping the conversation context. |
|
|
42
45
|
| Ctrl+C | While an agent runs, cancel it immediately; a second press exits the TUI without waiting for the busy display to settle. With an idle draft, the first press clears it and the second exits. |
|
package/package.json
CHANGED
package/plugins/acp/index.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { apply as applyAcp } from '@deepseek-ai/dsh-acp';
|
|
2
2
|
import z from '@deepseek-ai/schemastery';
|
|
3
|
+
import { configuredModels } from './models.mjs';
|
|
4
|
+
import { acpStatus } from '../status/index.mjs';
|
|
3
5
|
|
|
4
6
|
export const name = 'dscode-acp';
|
|
5
7
|
export const inject = ['acpAppStartup', 'agents', 'agentPresets', 'agentDefaultModel', 'permissionPresets', 'llm', 'sessionPersistence', 'sessions', 'dscodeCustom'];
|
|
@@ -34,7 +36,7 @@ export function startAcp(ctx, config = {}, bridge = applyAcp) {
|
|
|
34
36
|
const selection = config.model
|
|
35
37
|
? { provider: config.model.slice(0, config.model.indexOf('/')), model: config.model.slice(config.model.indexOf('/') + 1) }
|
|
36
38
|
: ctx.agentDefaultModel.currentSelection();
|
|
37
|
-
const scoped = ctx.extend({ agents: presetAgents(ctx) });
|
|
39
|
+
const scoped = ctx.extend({ agents: presetAgents(ctx), llm: configuredModels(ctx), dscodeAcpStatus: (selection, prompt, signal) => acpStatus(ctx, selection, prompt, signal) });
|
|
38
40
|
bridge(scoped, { provider: selection.provider, model: selection.model });
|
|
39
41
|
}
|
|
40
42
|
|