dsh-dbhub-live 5.0.1 → 5.2.0-dev.3

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.
Files changed (50) hide show
  1. package/AGENTS.md +95 -209
  2. package/README.en.md +251 -169
  3. package/README.md +251 -169
  4. package/doc/ARCHITECTURE.md +108 -0
  5. package/doc/CLIENT.md +124 -0
  6. package/doc/DESENSITIZE.md +56 -0
  7. package/doc/DEVELOPMENT.md +139 -0
  8. package/doc/IMPACT-MATRIX.md +36 -0
  9. package/doc/RELEASE.md +93 -0
  10. package/doc/REQUIREMENTS.md +177 -105
  11. package/doc/images/chat-query.png +0 -0
  12. package/doc/images/row-editor.png +0 -0
  13. package/doc/images/settings-page.png +0 -0
  14. package/lib/adhoc.mjs +412 -34
  15. package/lib/capability.mjs +157 -0
  16. package/lib/client.js +1243 -80
  17. package/lib/config.mjs +370 -21
  18. package/lib/i18n.mjs +119 -4
  19. package/lib/index.mjs +401 -43
  20. package/lib/mcp.mjs +496 -391
  21. package/lib/meta.mjs +267 -0
  22. package/lib/options.mjs +25 -5
  23. package/lib/policy.mjs +92 -0
  24. package/lib/toml.mjs +188 -0
  25. package/lib/tools.mjs +1093 -827
  26. package/lib/update.mjs +244 -0
  27. package/package.json +34 -10
  28. package/scripts/desensitize-check.mjs +10 -3
  29. package/scripts/desensitize.config.mjs +255 -237
  30. package/scripts/docs-check.mjs +214 -0
  31. package/scripts/release-preflight.mjs +180 -0
  32. package/scripts/render-check.mjs +1366 -843
  33. package/test/adhoc-toml.test.mjs +365 -0
  34. package/test/bridge.test.mjs +227 -185
  35. package/test/capability.test.mjs +231 -0
  36. package/test/client-format.test.mjs +515 -352
  37. package/test/configure-options.test.mjs +244 -0
  38. package/test/configure-ssh.test.mjs +232 -0
  39. package/test/copy-from.test.mjs +155 -0
  40. package/test/env-options.test.mjs +456 -0
  41. package/test/meta.test.mjs +234 -0
  42. package/test/options.test.mjs +160 -123
  43. package/test/policy.test.mjs +132 -0
  44. package/test/row-cache.test.mjs +237 -138
  45. package/test/ssh-probe.test.mjs +834 -0
  46. package/test/test-op-fastpath.test.mjs +208 -0
  47. package/test/toml.test.mjs +352 -0
  48. package/test/update.test.mjs +270 -0
  49. package/test/util.test.mjs +17 -0
  50. package/test/zero-knowledge.test.mjs +120 -78
package/README.en.md CHANGED
@@ -1,169 +1,251 @@
1
- # dsh-dbhub-live
2
-
3
- [简体中文](README.md) | English
4
-
5
- > Let [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/DeepSeek-Harness) operate databases directly and safely: **zero-knowledge credentials** (passwords never reach the model) + **one-shot process execution** (no resident server — naturally concurrent and multi-instance safe) + workspace × environment connection management + a browser Configure Page.
6
-
7
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
- [![DSH](https://img.shields.io/badge/DSH-plugin-blue.svg)](#installation)
9
- [![DBHub](https://img.shields.io/badge/Built_on-DBHub-22a05a)](https://github.com/bytebase/dbhub)
10
- [![npm version](https://img.shields.io/npm/v/dsh-dbhub-live)](https://www.npmjs.com/package/dsh-dbhub-live)
11
- [![Listed on dsh-plugin.org](https://dsh-plugin.org/badges/listed.svg)](https://dsh-plugin.org/plugins/mr-mihu/dsh-dbhub-live)
12
-
13
- `dsh-dbhub-live` is a DSH plugin built on [DBHub](https://dbhub.ai) (a database MCP server) that lets the model query databases directly: the model only says *which workspace/environment* to query, and the plugin resolves the real connection host-side and executes it — **passwords and DSNs never appear anywhere the model can see**. Every call is an independent throwaway dbhub process, killed right after the call.
14
-
15
- ## ✨ Features
16
-
17
- - **Zero-knowledge credentials** — the model only ever sees `source` handles and metadata (type / host / port / database); passwords, usernames and full DSNs exist only host-side; entering/changing a password happens **in the UI**, never through the model.
18
- - **One-shot process execution** — no resident dbhub service: each call spawns an independent process and recycles it when done. A hung/failed query only affects its own call; parallel tasks and multiple DSH instances running at once never interfere (no shared ports, no cross-kills).
19
- - **Constant 4 tool declarations** — `dbhub_configure` / `dbhub_list_sources` / `dbhub_execute_sql` / `dbhub_search_objects`; more environments never inflate the model context.
20
- - **Workspace × environment connection management** — one workspace can hold multiple environments (default / prod / dev / test…) distinguished by their `source` value.
21
- - **Auth-failure loop** — when credentials or connection details are wrong, the tool gives clear guidance; the model steers you to update the password in the UI (it never asks you for it), or you edit it directly in the settings card. **Auto-probe during configuration**: non-sensitive connection facts are tested host-side first — if they connect they take effect with zero input (password-less databases never prompt), and if only the password is missing the dialog asks just for "account (when unknown) + password" instead of re-asking for the whole input method. When the probe explicitly blames an EMPTY account (e.g. `Access denied for user ''`), the account is required — the "leave empty (use empty account)" choice is not offered, so the same doomed DSN is never saved again.
22
- - **Enable / disable switch** — turning it off makes every dbhub tool return a friendly "plugin disabled" message immediately; no restart needed.
23
- - **Browser configure page** — three entries to the same page: **Settings → DBHub Database Tools** (a first-level settings page, recommended), the **sidebar entry DBHub Database Tools** (a shortcut you can switch off on the settings page), and the plugin row's Configure control on the Plugins page. It shows the status badge, tool count and environment count, and offers the enable/disable switch, connection CRUD, **environment rename** and connection tests. **The connection list is organised per workspace**: when every workspace holds exactly one environment it renders as flat tiles (up to 3 columns, everything visible); as soon as one workspace owns several environments the rows fold per workspace with **click-to-expand group heads**, opening the workspace you used most recently by default, plus an expand/collapse-all control. Each connection **takes one line only** (environment · 🔒 type/host/port/**database** · source handle · icon actions): a narrow column truncates the host/port prefix first and **the database name always stays visible**; the actions are three small icons — ⚡ test / ✏ edit / 🗑 delete — instead of text buttons eating half the row; the `source` handle is a dashed chip showing `…` plus its distinguishing tail (e.g. `…1a2b3c`) — click it to copy, hover for the full value (it is the handle the model uses to target this connection, not a copy of the whole row). Where a connection came from (hand-entered / scanned / copied / auto-discovered) never takes row width — hover the environment chip to see it (an auto-discovered connection that is not saved says so explicitly). The auto-update interval and the sidebar switch live in the "⚙ Settings" strip, and the add form is folded away too (a group's "+ Environment" adds straight into that workspace, no workspace field to fill). All colours come from DSH theme tokens, so the page follows the active theme/skin and dark mode — **including translucent-background themes**. Writes are guarded against silent overwrites: **saving into an environment name that already exists asks “overwrite?” first** (cancelling writes nothing at all and leaves the form as typed so you can rename it), and renaming an environment onto an existing one asks too.
24
- - **Out of the box** — if `dbhub` is missing, the plugin installs it on first use and keeps it updated at your configured interval.
25
-
26
- ## Supported Data Sources
27
-
28
- MySQL · PostgreSQL · MariaDB · SQLite · SQL Server
29
-
30
- ## Requirements
31
-
32
- - DeepSeek Harness's `dsh` CLI (`dsh web` runs the GUI)
33
- - Works with **every dsh release line from 0.1.5 on, 0.2.x included**: the configure page rides the settings namespace on 0.1.x and the plugin's own authenticated HTTP bridge (`/api/dsh-dbhub-live/*`) on 0.1.7+/0.2.x, and both carry the same state
34
- - Node.js ≥ 18 with `npm` recommended — `dbhub` is auto-installed on first use
35
-
36
- ## Installation
37
-
38
- ```bash
39
- # Option 1: use a locally installed dsh
40
- dsh plugin --profile web add dsh-dbhub-live
41
-
42
- # Option 2: invoke dsh via npx (no global dsh installation required)
43
- npx @deepseek-ai/dsh plugin --profile web add dsh-dbhub-live
44
-
45
- # Update to a specific version (pin the currently published version so pnpm doesn't skip with "Already up to date")
46
- dsh plugin --profile web update dsh-dbhub-live@5.0.0
47
- ```
48
-
49
- After installing, **restart `dsh web`** for it to take effect (you can then see the configure page at **Settings → DBHub Database Tools**).
50
-
51
- > Upgrading from 4.x: dsh 0.2.x removed the settings-namespace interface the old configure page relied on, so dsh refuses to load 4.x there. 5.0.0 serves both release lines; upgrading the plugin keeps your connections and your saved options.
52
-
53
- ## Quick Start
54
-
55
- The tools below are invoked automatically by DSH's AI — you don't run them by hand; just state your request in natural language (e.g., "look up the users table"):
56
-
57
- ```text
58
- # 1) If the current workspace has no connection yet, the AI guides configuration (password is entered in the UI, the AI never sees it)
59
- dbhub_configure
60
-
61
- # 2) Run a query on a configured connection (source comes from dbhub_list_sources)
62
- dbhub_execute_sql source=myapp sql="SELECT * FROM users LIMIT 10;"
63
-
64
- # 3) List registered connections and their source values
65
- dbhub_list_sources
66
- ```
67
-
68
- ## Tools
69
-
70
- | Tool | Description |
71
- | --- | --- |
72
- | `dbhub_configure(workspace?, env?, renameFrom?, copyFrom?, type?, host?, port?, database?, user?)` | Configure/persist a workspace connection. **Does NOT accept a dsn argument** — the password/DSN is always entered in the UI (never through the model); type/host/port/database/user may be passed as non-sensitive prefills. **With enough prefills the plugin auto-probes first**: connectable → saved directly and the source value returned; password required → a minimal "account (when unknown) + password" dialog; incomplete info or another failure → the full method choice appears. **Rename**: `env=new name` + `renameFrom=old name` (the connection and its credentials stay as they are; works for `default` → `prod` or a Chinese/English swap; an existing target is confirmed with the user first). **Cross-workspace copy**: `copyFrom=<another workspace's source value>` + `env=<environment to create here>`; the Host copies the connection, so the password never passes through the model. |
73
- | `dbhub_list_sources()` | List every connection source, **grouped by workspace** and marking the **[CURRENT WORKSPACE]**: metadata only (type/host/port/database) + origin badge + the corresponding **source** value. |
74
- | `dbhub_execute_sql(source, sql)` | Execute SQL on a source; `source` comes from `dbhub_list_sources`. **Every source belongs to exactly one workspace** — prefer the current workspace's; to reuse another workspace's connection, first copy it here with `dbhub_configure`'s `copyFrom` instead of querying that workspace's source directly. Each call is an independent one-shot connection; multiple statements separated by `;`. |
75
- | `dbhub_search_objects(source, object_type, ...)` | Search database objects (tables/views/columns/indexes, etc.) on a given source. |
76
-
77
- > **Security**: the model can never obtain a password through this plugin — results and lists only show metadata like `mysql://host:3306/db`; dbhub's error text is scrubbed before it is returned. On a failing query, follow the hint and update the password in the UI.
78
-
79
- > Note: `search_objects` works only for SQLite; for MySQL / PostgreSQL etc. use `dbhub_execute_sql` directly (e.g., `SHOW TABLES`).
80
-
81
- ### Configuration Methods
82
-
83
- 0. **Auto-probe (preferred by default)** — once you state connection facts in chat (e.g. "mysql 198.51.100.1:3307/mydb"), the plugin tests them first: connectable → saved immediately (password-less databases need zero input); password required → the dialog asks only for "account (when unknown) + password" with the failure reason and a "use another way" escape when the connection details themselves are wrong; when the probe blames an EMPTY account (e.g. `Access denied for user ''`), the account is required (no "leave empty" choice); incomplete info or another failure → the three methods below appear. If you name a different database/host/port than the saved connection, the plugin re-runs the probe against the new target.
84
- 1. **Explicit DSN** — enter a full connection string in the UI, e.g. `mysql://user:pass@host:3306/db`.
85
- 2. **Fill in fields** — fill type / host / port / user / password / database name in the UI; fields already known from the conversation are pre-filled — you only fill in the gaps.
86
- 3. **Authorized scan** — after authorization, scan project config files (`.env`, `application*.yml`, `docker-compose`, `jdbc.properties`, etc.) and list candidates (host/port/database only — passwords are read host-side and never shown) for you to confirm.
87
-
88
- If a workspace already has `mise env` or `.env` (`DSN` / `DB_*`), the plugin discovers it automatically — no manual configuration needed.
89
-
90
- ## Configure Page
91
-
92
- Three entries, one page and one state:
93
-
94
- 1. **Settings → DBHub Database Tools** (recommended): the first-level settings page the plugin registers; present in every deployment.
95
- 2. **Sidebar entry DBHub Database Tools**: a shortcut, on by default; turn off "Show the sidebar entry" on the settings page to drop it (applies immediately, no restart or reload).
96
- 3. **Plugins → dsh-dbhub-live → Configure**: the configure control the official Plugins page gives each plugin row since dsh 0.1.6 (that page is provided by the official plugin manager; use the first two entries when it is absent).
97
-
98
- > Hiding the sidebar entry never removes access: the settings page and the plugin row's Configure control stay available.
99
-
100
- All page copy (name, status, config fields, buttons, connection rows) follows the dsh UI language (Chinese / English — Settings → General → Language); model-facing errors, feedback and the host logs follow it as well.
101
-
102
- **Status**: status badge (🟢 running / ⚪ disabled), the **enable/disable switch**, mode (one-shot connection), tool declarations (`4 (fixed)`), environments (`N · M saved`), most recent error (shown in red on error).
103
-
104
- **Configuration** (edit, then click "Save Configuration" to apply immediately and persist):
105
-
106
- | Parameter | Description | Default |
107
- | --- | --- | --- |
108
- | Auto-update interval (days) | How often dbhub is auto-updated; `0` disables | `7` |
109
- | Show the sidebar entry | Whether the DBHub Database Tools shortcut appears in the sidebar; applies immediately | on |
110
-
111
- Precedence: **settings saved on the configure page > process environment variables (default seeds) > built-in defaults**; when upgrading from an older 0.1.x install, the options still stored in the settings document are read as a lower layer (they are never silently reset). On dsh 0.1.7 and later these two options are also the plugin's declared configuration (volatile Config): set them in the plugin's row in `cordis.patch.yml`, or in the official Plugins form — **either change is adopted, and this plugin's page shows the same value** (a page save writes back to that configuration too, so the two surfaces never disagree). The auto-installed package is not in the UI (controlled separately by the `DSH_DBHUB_PACKAGE` environment variable, default `@bytebase/dbhub`).
112
-
113
- **Workspace connections**:
114
-
115
- - Lists every workspace × environment connection: workspace name, environment name, **source value** (what the model passes to `dbhub_execute_sql`, shown in monospace), **connection metadata** (🔒 `mysql://host:3306/db` — no username, no password; passwords never appear on the page), origin badge (`saved` / `auto`) and origin detail (`saved · user` / `saved · scan` / `saved · copied` / `auto · mise env` / `auto · .env`).
116
- - `saved`: you configured it (`dbhub_configure` or added in the page).
117
- - `auto`: not saved, discovered from `mise env` / `.env` — not persisted and follows the source files; if auto-discovery is wrong, use "Edit" to override it with a manual configuration.
118
- - Each row can be **tested** (connectivity probe, see below), **edited** (change the connection string **and/or the environment name**; a rename keeps the connection and its credentials untouched — enter only a name to rename) or **deleted** (saved items only).
119
- - **Connection test**: clicking "Test" makes the Host probe the row's real DSN through a throwaway connection (a one-off dbhub process running `SELECT 1`) and shows success/failure inline. The report is one-shot feedback: never persisted, fades after ~10 s; a failure never marks, restricts or alters the connection, other environments or queries (slow/unreachable databases wait at most ~30 s).
120
- - **Multiple environments per workspace**: fill "workspace (path or title, empty = default current workspace) + environment name + connection string" in the form and click "Add Connection". Environment names **may be Chinese** (e.g. `线上` / `测试`): the name is shown verbatim while the environment segment of the source value becomes `env-<short hash>`, so two Chinese names can never collide (purely ASCII names such as `test` / `dev` keep their existing source values).
121
-
122
- ## dbhub Environment Variables
123
-
124
- | Environment variable | Description | Default |
125
- | --- | --- | --- |
126
- | `DSH_DBHUB_PACKAGE` | npm package name used for auto-install (environment variable only, not exposed in the UI) | `@bytebase/dbhub` |
127
- | `DSH_DBHUB_UPDATE_DAYS` | Seed for the auto-update interval in days; `0` disables (overridden once saved in the settings card) | `7` |
128
-
129
- ## 🔄 Automatic Installation & Updates
130
-
131
- - **Auto-install on first use** — when `dbhub` is missing locally, the plugin installs it on the first execution; afterwards it also works offline.
132
- - **Kept up to date automatically** — silently updates to the latest version in the background (interval under "Configure Page → configurable parameters"); on failure the existing version is kept.
133
- - **Never touches your configuration** — a `dbhub` you installed yourself via PATH / mise is left untouched.
134
-
135
- > The default update interval can also be seeded by an environment variable, see "Configure Page → Configuration"; once saved in the settings card, the saved value wins.
136
-
137
- ## Data Location
138
-
139
- All configuration and credentials live outside the module directory (unaffected by pnpm packaging); deleting the directory clears everything:
140
-
141
- ```
142
- ~/.dsh/storages/dsh-dbhub-live/
143
- ```
144
-
145
- Instances are isolated by `DSH_HOME`; multiple profiles of the same instance share it (same convention as dsh's own `workspace.json`). Workspace connections are stored per "workspace × environment" (`environments.default` is the default environment); legacy v1 single-connection entries migrate automatically at startup. The plugin cleans up and migrates legacy config left by upgrades or manual edits in one pass; it does not crash if the runtime directory is deleted or writes are blocked by the system — it recreates the directory, warns once and keeps running in memory when a write fails. **There is no resident dbhub process and no shared config file**: concurrent instances on the same machine — even sharing one DSH_HOME — do not interfere with each other.
146
-
147
- ## Uninstall
148
-
149
- ```bash
150
- dsh plugin --profile web remove dsh-dbhub-live
151
- ```
152
-
153
- ## Troubleshooting
154
-
155
- | Symptom | Fix |
156
- | --- | --- |
157
- | "Cannot locate dbhub" on first use | Make sure npm is present and online; offline, install `dbhub` manually and add it to PATH. |
158
- | A query to one environment fails with connection refused / auth error | Environments use independent one-shot connections: an unreachable environment only fails that call — other environments and calls keep working. The error carries guidance — for wrong credentials/details, ask the AI to run `dbhub_configure` and enter the password in the UI, or edit it directly in Plugins → dsh-dbhub-live → Configure. |
159
- | Tools say "plugin disabled" | Open Plugins → dsh-dbhub-live → Configure and click "Enable". |
160
- | Configure Page not visible | Confirm the plugin is installed and restart `dsh web`; the card only shows in the Web settings panel (`dsh web`) — on terminal environments without the panel, tool usage is unaffected. |
161
- | dsh reports the plugin as incompatible after a dsh upgrade | That is dsh's peer-version check: upgrade the plugin to 5.0.0 or later (it serves both 0.1.x and 0.2.x). Forcing it through with `dsh plugin --profile web allow-version` does not help — the interface 4.x depends on is gone in 0.2.x, so the configure page stays empty. |
162
- | No config files found by the scan | `node_modules` / `.git` / `target` / `dist` etc. are skipped by default; use "Enter DSN" or "Fill in fields" instead. |
163
- | Need a custom dbhub version | Set the `DSH_DBHUB_PACKAGE` environment variable (e.g. `@bytebase/dbhub@1.2.1`) and restart; or delete `~/.dsh/storages/dsh-dbhub-live` and let it reinstall automatically. |
164
- | Don't want automatic dbhub updates | Set "Auto-update interval (days)" to `0` in the Configure Page and save; or set `DSH_DBHUB_UPDATE_DAYS=0`. |
165
- | Can't update the password in chat (the model asks you for it) | That is by design — the model must not handle passwords. Ask the AI to run `dbhub_configure` and fill in the password in the UI prompt, or edit it yourself in Plugins → dsh-dbhub-live → Configure. |
166
-
167
- ## License
168
-
169
- [MIT](./LICENSE)
1
+ # dsh-dbhub-live
2
+
3
+ [简体中文](README.md) · **English**
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![DSH](https://img.shields.io/badge/DSH-plugin-blue.svg)](#installation)
7
+ [![DBHub](https://img.shields.io/badge/Built_on-DBHub-22a05a)](https://github.com/bytebase/dbhub)
8
+ [![npm version](https://img.shields.io/npm/v/dsh-dbhub-live)](https://www.npmjs.com/package/dsh-dbhub-live)
9
+ [![Listed on dsh-plugin.org](https://dsh-plugin.org/badges/listed.svg)](https://dsh-plugin.org/plugins/mr-mihu/dsh-dbhub-live)
10
+
11
+ > Let the AI inside [DeepSeek Harness](https://github.com/deepseek-ai/DeepSeek-Harness) query your databases directly — **the password is typed in the UI, not passed to the model as a tool argument**.
12
+
13
+ Install it and you can simply tell the AI "show me the last 10 rows of the orders table". The AI runs SQL through [DBHub](https://dbhub.ai) (a database MCP server), but all it ever knows is *which environment of which workspace*, plus metadata such as `mysql://host:3306/db`; **passwords, accounts and full connection strings always stay on your machine**, typed only into the box in front of you.
14
+
15
+ <details>
16
+ <summary>📷 Preview: Settings → DBHub Database Tools</summary>
17
+
18
+ ![DBHub Database Tools configure page](doc/images/settings-page.png)
19
+
20
+ </details>
21
+
22
+ ## Why use it
23
+
24
+ | | |
25
+ | --- | --- |
26
+ | 🔒 **Credentials stay out of tool arguments** | The model only sees type / host / port / database; the password and the full DSN are not accepted as tool arguments — they are typed in the UI |
27
+ | ⚡ **One-shot process** | No resident dbhub service: every call is its own process, killed the moment it finishes; a failed query only affects itself, and parallel instances never kill each other |
28
+ | 🧮 **Always 4 tools** | However many environments you add, the model context never grows |
29
+ | 🗂 **Per workspace × environment** | One workspace can hold `default` / `prod` / `dev`… (environment names may be Chinese), told apart by their `source` — never the wrong database |
30
+ | 🛡 **Per-environment read-only** | Writes are refused natively by dbhub; **the model can switch it on but never off** (only you can switch it off on the configure page) |
31
+ | 🔐 **Manual SSH tunnel** | Databases behind a bastion are reachable too; the SSH password / key passphrase is typed in the UI only |
32
+ | 📦 **Works out of the box** | If dbhub is missing it is installed for you, then kept up to date at your interval |
33
+
34
+ Supports **MySQL · PostgreSQL · MariaDB · SQLite · SQL Server**.
35
+
36
+ <!-- release-test:versions:begin -->
37
+ ## Supported version range
38
+
39
+ **From DSH 0.1.5 (lines 0.1.5 / 0.1.6 / 0.1.7 / 0.2.0 / 0.2.1, prereleases included)** — 6 declared versions verified (last verified 2026-10-24).
40
+
41
+ <details>
42
+ <summary>Per-version verification details (expand)</summary>
43
+
44
+ | DSH version | UI | Boot | Hard checks | Result | Last verified |
45
+ | --- | --- | --- | --- | --- | --- |
46
+ | `0.1.5-rc.3` | legacy | 7.3s | 19 | ⚠️ pass with notes · manual | 2026-10-24 · 4f6a854a |
47
+ | `0.1.6-alpha.2` | legacy | 3.5s | 19 | ⚠️ pass with notes · manual | 2026-10-24 · 4f6a854a |
48
+ | `0.1.7-rc.2` | legacy | 4.7s | 20 | ⚠️ pass with notes · manual | 2026-10-24 · 4f6a854a |
49
+ | `0.2.0-rc.2` | legacy | 4.9s | 20 | ⚠️ pass with notes · manual | 2026-10-24 · 4f6a854a |
50
+ | `0.2.1-alpha.1` | modern | 5.1s | 20 | ⚠️ pass with notes · manual | 2026-10-24 · 4f6a854a |
51
+ | `0.2.1-rc.2` | modern | 5.3s | 20 | ⚠️ pass with notes · manual | 2026-10-24 · 4f6a854a |
52
+
53
+ </details>
54
+
55
+ Full evidence, review rules and known drift live in [doc/SUPPORT-MATRIX.md](doc/SUPPORT-MATRIX.md).
56
+ <!-- release-test:versions:end -->
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ # web (dsh web)
62
+ dsh plugin --profile web add dsh-dbhub-live
63
+
64
+ # desktop
65
+ dsh plugin --profile desktop add dsh-dbhub-live
66
+
67
+ # no dsh yet (use npx): same commands, prefix them with npx @deepseek-ai/dsh
68
+ npx @deepseek-ai/dsh plugin --profile web add dsh-dbhub-live
69
+ npx @deepseek-ai/dsh plugin --profile desktop add dsh-dbhub-live
70
+ ```
71
+
72
+ On desktop you can also **install entirely through the UI**: **left menu → Plugins → Add → type `dsh-dbhub-live` (or search the plugin marketplace) → Install**. **The same plugin works on both the web profile and the desktop profile**, with the same UI and behaviour; installing, updating and uninstalling on desktop can all be done on that Plugins page.
73
+
74
+ Once installed, **restart `dsh web`** and open **Settings → DBHub Database Tools** to see the configure page (there is also a sidebar shortcut, and the Configure control on the plugin's row on the Plugins page — all three entries lead to the same page).
75
+
76
+ > Requirements: every `dsh` release line from 0.1.5 on (0.2.x included); **the new UI needs 0.2.1+** (0.2.1 prereleases included) — the wide full page, the version/update header and the inline read-only switch only render on 0.2.1 and later; **0.1.x is still supported but keeps the old layout and behaviour**. Node.js ≥ 18 is recommended locally (it is used to install dbhub automatically). **Read-only mode and SSH tunnels need dbhub 1.4.0+** — the plugin detects this and gives you upgrade guidance. Per-version verification results live in [doc/SUPPORT-MATRIX.md](doc/SUPPORT-MATRIX.md) (generated by the release test, which must pass before every release).
77
+
78
+ ## Updating
79
+
80
+ **Web** (command line):
81
+
82
+ ```bash
83
+ dsh plugin --profile web up dsh-dbhub-live@<latest version>
84
+ ```
85
+
86
+ Then **restart `dsh web`**.
87
+
88
+ **Desktop**: uninstall the plugin on the **left menu → Plugins** page and reinstall the latest version (desktop updates go through the visual Plugins page). **Connections and credentials survive the reinstall** — they live in `~/.dsh/storages/dsh-dbhub-live`, independent of the module directory.
89
+
90
+ **No need to remember version numbers**: the configure page header shows the plugin name and the current version; when a newer version exists a quiet "**↑ Upgrade to <latest>**" text link appears and **clicking it copies** `dsh-dbhub-live@<latest>`; the "Check for updates" button next to it checks on demand. Opening the page also triggers one automatic check (throttled, so it does not hit the network on every open). Checks use the **npm registry first, with GitHub Releases as the fallback**; release notes live in [GitHub Releases](https://github.com/mr-mihu/dsh-dbhub-live/releases).
91
+
92
+ > The version/update hint is part of the new UI and needs plugin 5.2.0+ and DSH 0.2.1+; on 0.1.x it is not shown (see "Configure Page").
93
+
94
+ ## Quick Start
95
+
96
+ No commands to memorise — just talk to the AI:
97
+
98
+ ```text
99
+ You: mysql on 192.0.2.10:3306, database app, account ops
100
+ AI: (a dialog opens — you type the password there) → saved, source = myapp_1a2b3c_default
101
+ You: the 3 most recent rows of the orders table
102
+ AI: … (query results)
103
+ ```
104
+
105
+ <details>
106
+ <summary>📷 In action: ask the AI, get the query results</summary>
107
+
108
+ ![Asking the AI and getting query results](doc/images/chat-query.png)
109
+
110
+ </details>
111
+
112
+ The password is only ever typed into the box in front of you. If you give only part of the picture (say "connect to mydb on 192.0.2.10"), the plugin **probes with those non-sensitive facts first**: if it connects, the connection is saved straight away (password-less databases need no input at all); if only the password is missing it asks just for "account (when unknown) + password"; only when the information is incomplete do you choose a full method (enter a DSN / fill in fields / authorise a scan of project config files).
113
+
114
+ > **Do not paste a password into the chat.** The plugin itself does not hand the password to the model, but **anything you paste into the conversation does enter the context** — the plugin cannot prevent that, and cannot take it back.
115
+
116
+ When the workspace already has `mise env` or a `.env` (`DSN` / `DB_*`), the plugin discovers it automatically — no manual configuration needed.
117
+
118
+ ## Tools
119
+
120
+ | Tool | Description |
121
+ | --- | --- |
122
+ | `dbhub_configure(...)` | Configure / change a workspace connection. **It does not accept a `dsn` argument** — the password and connection string are always typed in the UI; `type`/`host`/`port`/`database`/`user` may be passed as non-sensitive prefills. Supports renaming with `env=<new name>` + `renameFrom=<old name>`, cross-workspace copying with `copyFrom=<another workspace's source>`, `readOnly:true` (`readOnly:false` is refused) and the tunnel options `sshHost`/`sshPort`/`sshUser`/`sshAuthKind`/`sshKeyPath`/`sshProxyJump` (**the SSH password and passphrase can only be typed by you in the dialog**). |
123
+ | `dbhub_list_sources()` | List every connection source, **grouped by workspace** and marking the **[CURRENT WORKSPACE]**; metadata and the **source value** only. |
124
+ | `dbhub_execute_sql(source, sql)` | Execute SQL on the given source; `source` comes from `dbhub_list_sources`. Every call is an independent one-shot connection; separate multiple statements with `;`. |
125
+ | `dbhub_search_objects(source, object_type, ...)` | Search database objects (tables / views / columns / indexes, etc.). |
126
+
127
+ > **Every source belongs to exactly one workspace**: to reuse a connection from another workspace, copy it over with `dbhub_configure`'s `copyFrom` — do not query another workspace's source directly.
128
+ > `search_objects` is currently available for SQLite only; for MySQL / PostgreSQL etc. use `dbhub_execute_sql` (e.g. `SHOW TABLES`).
129
+
130
+ ## Model-facing database access policy
131
+
132
+ While the plugin is enabled it contributes a **system-prompt section** (about 400 characters) that keeps database access on this plugin and states how it coexists with **other database plugins**:
133
+
134
+ - **One authorized route — scoped to this plugin's own connections**: every database listed by `dbhub_list_sources` goes through the `dbhub_*` tools; no `psql` / `mysql` / `sqlite3` / `sqlcmd` / `pg_dump` command-line client, throwaway script, driver, other MCP, or **other database plugin** is used to reach them, and the agent does not go looking for such an executable on the host.
135
+ - **A workspace "recipe" is not authorization**: direct-connection instructions found in project docs, scripts, or `AGENTS.md` (for example a psql recipe an earlier session wrote itself) are never followed — the system prompt outranks workspace instructions.
136
+ - **Read-only is the user's safety boundary**: after a `READONLY_VIOLATION` the agent must not complete the write by any other route (**including another database plugin**); it reports the reason and the impact instead.
137
+ - **Databases this plugin does not cover stay with the plugin that does**: dbhub speaks MySQL / PostgreSQL / MariaDB / SQLite / SQL Server only. MongoDB / Redis / Oracle and any instance **you never configured here** are explicitly handed to the other database plugin you installed — the agent must not refuse them for the sake of "everything through this plugin", and must not fall back to a command-line connection either.
138
+ - **The same database configured in both plugins**: the default is this plugin's source (read-only and tunnel settings live here); the agent switches only when you explicitly ask for the other tool, and asks you when it cannot tell.
139
+ - **Operations this plugin cannot do**: backups and non-SQL administration commands are reported as a limitation, and the agent asks you for an authorized route instead of improvising.
140
+
141
+ **Switch**: "Announce the database-access policy to the model" in the settings (expanded inline in the wide page's settings block; in the modal layout it sits behind the ⚙ Settings strip), **on by default**; a deployment can also pin it with `config: { announceAccessPolicy: false }` in `cordis.patch.yml`. Turning it off only removes that text — tools, read-only, tunnels and every other setting keep working.
142
+
143
+ **No plugin suppression**: this plugin does not (and cannot) disable another database plugin you installed. The conflict is resolved by the three rules above — scope, a default for overlapping targets, and asking you when it cannot tell. Which plugin to disable is your decision, made on the Plugins page.
144
+
145
+ **Honest boundary**: this policy is a **prompt-level (soft) constraint**; read-only itself is **hard-rejected** by dbhub inside the plugin. A shell-level connection that bypasses the plugin is outside the plugin's control — the policy names it explicitly, but it relies on the model complying rather than blocking it.
146
+
147
+ ## Configure Page
148
+
149
+ <details>
150
+ <summary>📷 Row editor: read-only mode and SSH tunnel</summary>
151
+
152
+ ![Connection row and "Test SSH tunnel"](doc/images/row-editor.png)
153
+
154
+ </details>
155
+
156
+ The same component offers **three layouts**, picked automatically from the host surface and the window width (the new UI needs plugin 5.2.0+ and **DSH 0.2.1+**; on DSH 0.1.x the old layout and behaviour are kept, see the end of this section):
157
+
158
+ | Layout | How to reach it | Shape |
159
+ | --- | --- | --- |
160
+ | Modal | **Settings → DBHub Database Tools** | A narrow modal, same density as before, settings behind the "Settings" disclosure on the status line |
161
+ | Wide page | The **DBHub** entry in the left menu / the Configure control on the Plugins row | A full page in a wide column, with the version and upgrade entry in the header and settings rows expanded inline |
162
+ | Small screen | A mobile browser, width < ~700px | Stacked and compact, controls sized for touch |
163
+
164
+ **Header: version and upgrade entry**: the title is the plugin name with the current version (small, muted) right next to it; when a newer version exists a quiet "**↑ Upgrade to <latest>**" text link appears on the right, and **clicking it expands** the update notes — the `dsh-dbhub-live@<latest>` spec (click to copy), the update command / steps for this deployment, and a link to the release notes; the "↻" button checks on demand. Opening the page also triggers an automatic check (throttled). Checks use the npm registry first, with GitHub Releases as the fallback. **An update is neutral news, never styled as an error.**
165
+
166
+ - **Status line**: it shows only "running / disabled · N connections". Implementation facts — tool count, one-shot execution mode, dbhub version — live in the collapsed "ⓘ Details & diagnostics" block at the bottom of the page.
167
+ - **Connection list**: organised by workspace. When every workspace has a single environment the rows render as flat cards; as soon as one workspace owns several environments they fold into per-workspace groups (click a group head to expand; the most recently used one is open by default). Each connection takes one line: environment name · type / host / port / **database** · **read-only switch** · the `source` handle (click it to copy) · test / edit / delete. In a narrow window the host and port are truncated first, while **the database name always stays visible**.
168
+ - **Settings (DSH-native style, deliberately quiet)**: on the wide page the four controls collapse into **one compact settings line** — `Plugin settings · Enable plugin [enabled] · Sidebar entry [shown] · Access policy [on] · Auto-update [7] days [save] · ⓘ details`; the modal and the phone use compact stacked rows. Fonts and switches are kept small so the **connection list** stays the main content. The controls are DSH's own switches (theme/skin aware, with state words); every explanatory paragraph lives in "ⓘ Details & diagnostics".
169
+ - **Read-only switch (outside the edit form in all three layouts)**: right next to the datasource on every connection row there is a small "RO" toggle — one click flips it (open lock + "Writable" = writable; closed lock + "RO" = read-only) without opening the edit form; the modal and the phone layout have it too. The tick-box in the edit form stays as well; both are the same state. **The connection string itself no longer carries a lock icon** — it used to read like "this row needs a password" and clashed with the read-only lock.
170
+ - **Add / edit / delete**: use ✏ on a row to change the connection string or the environment name; "+ Add connection" accepts Chinese environment names. **Saving onto an environment name that already exists asks "overwrite?" first** — cancel and not a single byte is written.
171
+ - **Connection test**: runs `SELECT 1` over **the effective connection that environment will really use** (read-only / tunnel included) and shows the elapsed time while it runs. The result is one-shot feedback: nothing is persisted and no connection state changes.
172
+
173
+ **"Show the sidebar entry" is not disabling the plugin**: switching it off merely hides the sidebar shortcut — the plugin keeps working and the model can still query; use "Disable" to stop the plugin as a whole (a disabled plugin always hides the entry). In either state, **the settings page and the Plugins row's Configure control always stay reachable**, so the change can be undone at any time.
174
+
175
+ **Compatibility path for DSH 0.1.x**: the header version / upgrade entry, the wide full page, the row read-only chip and the settings rows all render only on **DSH 0.2.1+** (prereleases included); on 0.1.x the plugin keeps its previous layout and behaviour and **shows no upgrade hint** — that is deliberate, not a defect.
176
+
177
+ ## 🔒 Read-only Mode and SSH Tunnels
178
+
179
+ Both are **per-environment** connection options executed by dbhub's native features. Once either is on, every execution in that environment switches to a **temporary, generated dbhub configuration** (the file holds only `${…}` placeholders and no password at all — the real values reach the child process through its environment) and is deleted as soon as the call ends; every other environment is unaffected.
180
+
181
+ **Read-only mode**: in all three layouts the connection row carries a small "RO" switch next to the datasource — one click flips it (you can also click ✏ and tick it in the edit form; the model can enable it for an environment too). dbhub then lets read statements through only (measured on MySQL: `select/with/explain/show/describe/desc`), and writes come straight back as `READONLY_VIOLATION`; object search keeps working. **Turning read-only off is something only you can do on the configure page** — an attempt by the model is refused. A read-only environment's name gains a small "RO" badge.
182
+
183
+ **SSH tunnel** (configured by hand, for databases sitting behind a bastion):
184
+
185
+ | Field | Description |
186
+ | --- | --- |
187
+ | SSH host | A **domain or IP** (e.g. `203.0.113.10`); do not enter an alias from `~/.ssh/config` |
188
+ | Port | Defaults to `22` |
189
+ | SSH user | The account used to log in to the bastion |
190
+ | Auth | **Key** (enter the key path; give a passphrase if the private key has one; **blank = the default `~/.ssh/id_ed25519`**) or **password** |
191
+ | ProxyJump | Optional, **one hop only**, format `[user@]host[:port]` |
192
+ | Key passphrase / SSH password | **Typed in the UI only**, never echoed back; when editing, **blank = keep the stored value** |
193
+
194
+ "Advanced: SSH tunnel" holds **two** test buttons:
195
+
196
+ - **"Test SSH tunnel"** validates the tunnel layer alone: it first probes TCP reachability of `ssh_host:ssh_port` (about 5 seconds; a failure carries a code such as `ENOTFOUND` / `ECONNREFUSED` / `ETIMEDOUT`), with key auth it checks that the private key file exists and is readable, and finally it **deliberately** asks dbhub to open a tunnel to an address that cannot possibly be listening — then decides from the evidence: an error carrying **SSH signatures** (handshake / authentication / private key) means the tunnel is down; one carrying a **database-layer signature** (`PROTOCOL_CONNECTION_LOST`, `Connection lost`, `Access denied`, `Unknown database`, `ER_*`, `ECONNREFUSED` and the like) means the connection **already got past the tunnel**, so the verdict is "SSH tunnel works"; only when neither is present does it honestly say "cannot be determined", with the tail of the output attached.
197
+ - **"Test this configuration"** probes the **effective connection** (tunnel + read-only) for real.
198
+
199
+ > **One line to remember**: a **database-layer** error means the tunnel is already up — the problem is the database behind it (authentication / database name / target address), so SSH need not be suspected any longer.
200
+ >
201
+ > **Honest limit**: the SSH-layer test proves "the network is reachable + the key is present + the SSH layer comes up"; it is not a full session test against a real database — a tunnel coming up does not mean the database behind it is reachable, and that question is answered by "Test this configuration".
202
+
203
+ Order of checks: ① your machine can log in with `ssh user@bastion`; ② **the address in the connection string must be the one the bastion sees** (write `127.0.0.1` when the database runs on the bastion itself) — this is the most common cause; ③ the key path exists and is readable (remember the passphrase for an encrypted key); ④ ProxyJump is a single hop.
204
+
205
+ **Prerequisites and limits**: dbhub **1.4.0+** is required (an older version fails with an explicit error rather than being silently ignored); multi-hop, `ProxyCommand` and ssh-agent are **not supported**, and the plugin does **not reuse** the SSH configuration of any other plugin (including DSH's own SSH tooling) — the tunnel information comes only from what you type in. Read-only and SSH are two independent switches; either can be used on its own.
206
+
207
+ ## Data Location
208
+
209
+ All configuration and credentials live outside the module directory; delete that directory and everything is cleared:
210
+
211
+ ```
212
+ ~/.dsh/storages/dsh-dbhub-live/
213
+ ```
214
+
215
+ Isolated per `DSH_HOME` and shared by multiple profiles of the same instance (the same convention as dsh's own `workspace.json`). Connections are stored per "workspace × environment"; old formats and leftovers from manual edits are cleaned up and migrated in one pass at startup, and the plugin does not crash if the runtime directory is deleted by accident or a write is blocked. **There is no resident process and no shared configuration file**, so several instances running at once on one machine never interfere. **Upgrading, reinstalling or uninstalling the plugin never touches this directory** — including the desktop upgrade path of "uninstall, then reinstall the latest": connections, read-only / tunnel settings and credentials are all preserved.
216
+
217
+ ## Uninstall
218
+
219
+ ```bash
220
+ # web
221
+ dsh plugin --profile web remove dsh-dbhub-live
222
+
223
+ # desktop
224
+ dsh plugin --profile desktop remove dsh-dbhub-live
225
+ ```
226
+
227
+ On desktop you can also uninstall directly on the **left menu → Plugins** page. Uninstalling does not delete connections or credentials (see "Data Location"); to wipe everything, delete `~/.dsh/storages/dsh-dbhub-live` by hand.
228
+
229
+ ## Troubleshooting
230
+
231
+ | Symptom | Fix |
232
+ | --- | --- |
233
+ | "Cannot fetch dbhub" on first use | Make sure npm is present and the machine can reach the network; offline, install `dbhub` by hand and add it to PATH. |
234
+ | A connection to one environment is refused / authentication fails | That environment is an independent one-shot connection, so only this one call is affected. The end of the error carries guidance: ask the AI to run `dbhub_configure` and walk you through updating the password in the UI, or edit it directly on the configure page. |
235
+ | The tools report "plugin disabled" | Go to **Settings → DBHub Database Tools** and click "Enable". |
236
+ | The sidebar entry is gone after disabling | Expected behaviour (a disabled plugin contributes no entry). Click "Enable" and the entry is back immediately. |
237
+ | A write reports `READONLY_VIOLATION` after read-only was turned on | Not a fault — read-only is doing its job. To write, clear that environment's "Read-only mode" on the configure page (the model cannot turn it off). |
238
+ | The read-only / SSH controls are greyed out, or dbhub is reported as too old | Both need dbhub 1.4.0+: upgrade dbhub, or delete `~/.dsh/storages/dsh-dbhub-live` so the plugin installs a version that satisfies it. |
239
+ | A connection test fails and you cannot tell why | Read the **end** of the message (the diagnostic is the tail of dbhub's output and marks the layer: [SSH layer] / [database layer] / [plugin layer]). **A [database layer] report means the tunnel is already up**; with a tunnel configured, press "Test SSH tunnel" first to verify the SSH layer on its own. |
240
+ | The configure page is not visible | Check the plugin is installed: restart `dsh web` on the web side; on desktop use the Configure control on the Plugins row or the DBHub entry in the left menu. The page only shows in the Web / desktop UI and does not affect tool usage in terminal environments. |
241
+ | The old UI is still shown after upgrading | The new UI needs **DSH 0.2.1+** (prereleases included) and plugin 5.2.0+; restart after upgrading dsh. On DSH 0.1.x the plugin deliberately keeps the old layout and behaviour and shows no update hint. |
242
+ | No "Upgrade to …" hint appears in the header | You may already be on the latest version, or this check could not reach the npm registry / GitHub Releases; press "Check for updates" to retry. A failed check is only a hint and does not affect plugin functionality. |
243
+ | How do I upgrade on desktop | Uninstall on the **left menu → Plugins** page, then reinstall the latest version; connections and credentials live in `~/.dsh/storages/dsh-dbhub-live` and are still there after the reinstall. |
244
+ | After a dsh upgrade the plugin is reported as incompatible | Upgrade the plugin to 5.0.0+ (it supports both 0.1.x and 0.2.x); forcing it through with `allow-version` buys nothing. |
245
+ | Automatic dbhub updates are not wanted | Set "Auto-update interval (days)" to `0` on the configure page and save, or set `DSH_DBHUB_UPDATE_DAYS=0`. |
246
+
247
+ **Environment variables** (only these two, not exposed in the UI): `DSH_DBHUB_PACKAGE` (the package that gets auto-installed, default `@bytebase/dbhub`), `DSH_DBHUB_UPDATE_DAYS` (the seed for the auto-update interval, default `7`, overridden by the value saved on the configure page).
248
+
249
+ ## License
250
+
251
+ [MIT](./LICENSE)