@martijn-on-fhir/docker-desktop-mx 1.23.0

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 (124) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +231 -0
  3. package/bin/docker-desktop-mx.js +38 -0
  4. package/build/icons/icon-1024.png +0 -0
  5. package/build/icons/icon-128.png +0 -0
  6. package/build/icons/icon-16.png +0 -0
  7. package/build/icons/icon-256.png +0 -0
  8. package/build/icons/icon-32.png +0 -0
  9. package/build/icons/icon-48.png +0 -0
  10. package/build/icons/icon-512.png +0 -0
  11. package/build/icons/icon-64.png +0 -0
  12. package/build/icons/icon.ico +0 -0
  13. package/build/icons/icon.iconset/icon_128x128.png +0 -0
  14. package/build/icons/icon.iconset/icon_128x128@2x.png +0 -0
  15. package/build/icons/icon.iconset/icon_16x16.png +0 -0
  16. package/build/icons/icon.iconset/icon_16x16@2x.png +0 -0
  17. package/build/icons/icon.iconset/icon_256x256.png +0 -0
  18. package/build/icons/icon.iconset/icon_256x256@2x.png +0 -0
  19. package/build/icons/icon.iconset/icon_32x32.png +0 -0
  20. package/build/icons/icon.iconset/icon_32x32@2x.png +0 -0
  21. package/build/icons/icon.iconset/icon_512x512.png +0 -0
  22. package/build/icons/icon.iconset/icon_512x512@2x.png +0 -0
  23. package/build/icons/icon.png +0 -0
  24. package/dist/docker-desktop-mx/browser/chunk-DIDSONYO.js +39 -0
  25. package/dist/docker-desktop-mx/browser/chunk-LIK3FY4I.js +1 -0
  26. package/dist/docker-desktop-mx/browser/favicon.ico +0 -0
  27. package/dist/docker-desktop-mx/browser/index.html +14 -0
  28. package/dist/docker-desktop-mx/browser/main-Q4Z5LDLK.js +2 -0
  29. package/dist/docker-desktop-mx/browser/styles-5EFPCUJK.css +1 -0
  30. package/dist-electron/api.js +10 -0
  31. package/dist-electron/api.js.map +1 -0
  32. package/dist-electron/assistant-key.js +70 -0
  33. package/dist-electron/assistant-key.js.map +1 -0
  34. package/dist-electron/assistant-models.js +19 -0
  35. package/dist-electron/assistant-models.js.map +1 -0
  36. package/dist-electron/assistant-tools.js +335 -0
  37. package/dist-electron/assistant-tools.js.map +1 -0
  38. package/dist-electron/assistant.js +302 -0
  39. package/dist-electron/assistant.js.map +1 -0
  40. package/dist-electron/channels.js +96 -0
  41. package/dist-electron/channels.js.map +1 -0
  42. package/dist-electron/compose.js +230 -0
  43. package/dist-electron/compose.js.map +1 -0
  44. package/dist-electron/containers.js +139 -0
  45. package/dist-electron/containers.js.map +1 -0
  46. package/dist-electron/context-menu.js +56 -0
  47. package/dist-electron/context-menu.js.map +1 -0
  48. package/dist-electron/contexts.js +346 -0
  49. package/dist-electron/contexts.js.map +1 -0
  50. package/dist-electron/crash.js +129 -0
  51. package/dist-electron/crash.js.map +1 -0
  52. package/dist-electron/diagnosis.js +338 -0
  53. package/dist-electron/diagnosis.js.map +1 -0
  54. package/dist-electron/docker-client.js +284 -0
  55. package/dist-electron/docker-client.js.map +1 -0
  56. package/dist-electron/engine.js +115 -0
  57. package/dist-electron/engine.js.map +1 -0
  58. package/dist-electron/events.js +132 -0
  59. package/dist-electron/events.js.map +1 -0
  60. package/dist-electron/exec.js +138 -0
  61. package/dist-electron/exec.js.map +1 -0
  62. package/dist-electron/files.js +362 -0
  63. package/dist-electron/files.js.map +1 -0
  64. package/dist-electron/host-overview.js +50 -0
  65. package/dist-electron/host-overview.js.map +1 -0
  66. package/dist-electron/host-shell.js +193 -0
  67. package/dist-electron/host-shell.js.map +1 -0
  68. package/dist-electron/i18n.js +58 -0
  69. package/dist-electron/i18n.js.map +1 -0
  70. package/dist-electron/images.js +141 -0
  71. package/dist-electron/images.js.map +1 -0
  72. package/dist-electron/ipc.js +658 -0
  73. package/dist-electron/ipc.js.map +1 -0
  74. package/dist-electron/links.js +46 -0
  75. package/dist-electron/links.js.map +1 -0
  76. package/dist-electron/logs.js +153 -0
  77. package/dist-electron/logs.js.map +1 -0
  78. package/dist-electron/main.js +456 -0
  79. package/dist-electron/main.js.map +1 -0
  80. package/dist-electron/merged-logs.js +127 -0
  81. package/dist-electron/merged-logs.js.map +1 -0
  82. package/dist-electron/navigation.js +37 -0
  83. package/dist-electron/navigation.js.map +1 -0
  84. package/dist-electron/ndjson.js +30 -0
  85. package/dist-electron/ndjson.js.map +1 -0
  86. package/dist-electron/networks.js +284 -0
  87. package/dist-electron/networks.js.map +1 -0
  88. package/dist-electron/preload.js +223 -0
  89. package/dist-electron/preload.js.map +1 -0
  90. package/dist-electron/pull.js +220 -0
  91. package/dist-electron/pull.js.map +1 -0
  92. package/dist-electron/redact.js +129 -0
  93. package/dist-electron/redact.js.map +1 -0
  94. package/dist-electron/registry-auth.js +150 -0
  95. package/dist-electron/registry-auth.js.map +1 -0
  96. package/dist-electron/renew.js +162 -0
  97. package/dist-electron/renew.js.map +1 -0
  98. package/dist-electron/run.js +148 -0
  99. package/dist-electron/run.js.map +1 -0
  100. package/dist-electron/self-update.js +163 -0
  101. package/dist-electron/self-update.js.map +1 -0
  102. package/dist-electron/servers.js +108 -0
  103. package/dist-electron/servers.js.map +1 -0
  104. package/dist-electron/settings.js +90 -0
  105. package/dist-electron/settings.js.map +1 -0
  106. package/dist-electron/ssh.js +574 -0
  107. package/dist-electron/ssh.js.map +1 -0
  108. package/dist-electron/stats.js +209 -0
  109. package/dist-electron/stats.js.map +1 -0
  110. package/dist-electron/streams.js +63 -0
  111. package/dist-electron/streams.js.map +1 -0
  112. package/dist-electron/system.js +123 -0
  113. package/dist-electron/system.js.map +1 -0
  114. package/dist-electron/terminal-transcript.js +55 -0
  115. package/dist-electron/terminal-transcript.js.map +1 -0
  116. package/dist-electron/updates.js +136 -0
  117. package/dist-electron/updates.js.map +1 -0
  118. package/dist-electron/volume-backup.js +203 -0
  119. package/dist-electron/volume-backup.js.map +1 -0
  120. package/dist-electron/volumes.js +253 -0
  121. package/dist-electron/volumes.js.map +1 -0
  122. package/dist-electron/wsl.js +136 -0
  123. package/dist-electron/wsl.js.map +1 -0
  124. package/package.json +123 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Martijn Schimmel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,231 @@
1
+ # Docker Desktop MX
2
+
3
+ A desktop client for a Docker daemon: the everyday work of Docker Desktop (containers,
4
+ images, volumes, networks, compose and logs) without Docker Desktop itself. It was made for
5
+ Docker running in WSL on Windows, but it talks to any daemon you can reach.
6
+
7
+ The app does **not** manage the engine. The daemon already runs somewhere (a WSL distro, a
8
+ Linux host, Colima, Docker Desktop); Docker Desktop MX is only the client.
9
+
10
+ ![The containers page, grouped by compose project, with live CPU and memory per container](docs/application.png)
11
+
12
+ ## Features
13
+
14
+ - **Dashboard**: engine status, CPU/memory/network charts, disk usage, and a prune dialog.
15
+ - **Containers**: grouped by compose project; start, stop, restart, pause and remove, also in
16
+ bulk. The detail page has live logs, inspect, stats, a terminal, a file browser (download
17
+ and upload by drag and drop) and a one-click diagnosis you can paste into an issue.
18
+ - **Images**: pull with per-layer progress, run a container from an image, check the registry
19
+ for newer versions, and recreate compose containers after an update.
20
+ - **Volumes and networks**: list, remove and prune; back up a volume to a `.tar` and restore it.
21
+ - **Compose**: projects as a group, with `up` and `down`.
22
+ - **Logs**: the logs of all running containers merged in one view, with a level filter.
23
+ - **Terminal**: a root shell on the Docker host itself, next to the per-container shells.
24
+ - **Claude** (optional): with your own Claude API key, a Claude tab on every container and on
25
+ the host terminal that reads logs and inspect data and suggests fixes or commands.
26
+ - **Docker contexts**: switch between them from the status bar.
27
+ - **Command palette**: `Ctrl+K` (`Cmd+K` on macOS) jumps to any page, container, image, volume
28
+ or network.
29
+ - **Background**: the app keeps running in the system tray and sends a notification when a
30
+ container crashes or becomes unhealthy. It can start at login.
31
+ - **Updates**: the Windows installer version updates itself.
32
+ - **Languages and themes**: English (the default) and Dutch, chosen under Settings.
33
+ Technical terms stay in English. Light and dark theme, toggled in the header.
34
+
35
+ ## Requirements
36
+
37
+ - **A running Docker daemon.** The app finds it the same way the `docker` CLI does:
38
+ `DOCKER_HOST` first, then the current docker context, then the platform default
39
+ (`npipe:////./pipe/docker_engine` on Windows, `/var/run/docker.sock` elsewhere).
40
+ - **The `docker` CLI with the compose plugin**, only for compose `up` and `down`. Everything
41
+ else goes through the Engine API directly.
42
+ - **A Claude API key**, only for the Claude tab.
43
+
44
+ ### Docker in WSL, without Docker Desktop
45
+
46
+ With Docker Engine installed inside a WSL distro, make the daemon listen on localhost as well
47
+ as on its socket. In the distro, edit `/etc/docker/daemon.json`:
48
+
49
+ ```json
50
+ { "hosts": ["unix:///var/run/docker.sock", "tcp://127.0.0.1:2375"] }
51
+ ```
52
+
53
+ On systemd distros, also remove the `-H fd://` flag from the service, because it conflicts
54
+ with `hosts`. Then restart Docker. On Windows, point a context at it:
55
+
56
+ ```bash
57
+ docker context create wsl --docker host=tcp://localhost:2375
58
+ docker context use wsl
59
+ ```
60
+
61
+ Port 2375 has no authentication, so bind it to `127.0.0.1` only, as above. If the distro is not
62
+ running, the app says so and offers to start it.
63
+
64
+ ### A Docker host over SSH
65
+
66
+ A context with an `ssh://` endpoint works too, like it does for the `docker` CLI. Add one under
67
+ **Settings → Servers** (which also tests the connection and can trust a new host key after you
68
+ compare its fingerprint), or with the CLI:
69
+
70
+ ```bash
71
+ docker context create server --docker host=ssh://user@192.168.1.16
72
+ ```
73
+
74
+ The app logs in and runs `docker system dial-stdio` on the server, so nothing has to listen on
75
+ TCP there. What it needs:
76
+
77
+ - **The server in `~/.ssh/known_hosts`.** The app never accepts an unknown host key by itself:
78
+ trust it under Settings → Servers after comparing the fingerprint, or connect once with
79
+ `ssh user@host`. A changed host key is refused; that one you check with `ssh-keygen -R`.
80
+ - **A key without a passphrase prompt**: the ssh agent (`SSH_AUTH_SOCK`, or the OpenSSH agent
81
+ service on Windows), or `~/.ssh/id_ed25519`, `id_ecdsa` or `id_rsa` without a passphrase.
82
+ `~/.ssh/config` is not read, so put the user name in the address.
83
+ - **The `docker` CLI on the server**, and the user in its `docker` group.
84
+
85
+ ## Installing
86
+
87
+ - **Windows installer**: download `Docker-Desktop-MX-Setup.exe` from the latest
88
+ [release on Codeberg](https://codeberg.org/MartijnSchimmel/docker-desktop-mx/releases). It is
89
+ not code-signed, so SmartScreen asks for confirmation the first time.
90
+ - **npm**: `npx @martijn-on-fhir/docker-desktop-mx`, or `npm install -g @martijn-on-fhir/docker-desktop-mx`
91
+ and then `docker-desktop-mx`. The first start downloads Electron (about 100 MB). Starting at
92
+ login and self-updating only work with the installer.
93
+ - **From source**: see [Development](#development).
94
+
95
+ ## Using Claude
96
+
97
+ Open **Settings → Claude** and paste an API key from the
98
+ [Claude Console](https://console.anthropic.com/). The key is stored encrypted on this computer
99
+ and is readable only by your user account. Each question costs a little API usage, billed to
100
+ your own account.
101
+
102
+ The same screen picks the model: Opus 5 (the default) reasons best about a stubborn problem,
103
+ Sonnet 5 and Haiku 4.5 answer faster and cost less.
104
+
105
+ Claude can only read: container logs, events, stats, inspect data, compose projects and, on
106
+ the host terminal, what the terminal shows. Secrets such as passwords and tokens are masked
107
+ before anything is sent. Claude never acts on its own. It can propose an action, such as a
108
+ restart, which runs only when you click it. It can also propose a command, which goes into
109
+ the terminal prompt; you decide whether to press Enter.
110
+
111
+ ## Development
112
+
113
+ Built with **Angular 22** (standalone, zoneless, signals) in the renderer, **Electron 44** as
114
+ the shell, and **dockerode** in the main process. Needs Node 20 or later and a running daemon.
115
+
116
+ ```bash
117
+ npm install
118
+ npm start
119
+ ```
120
+
121
+ The original design notes are in [`docs/plan.md`](docs/plan.md), and how releases work is in
122
+ [`RELEASING.md`](RELEASING.md). Both are in Dutch.
123
+
124
+ ### Scripts
125
+
126
+ | Command | What it does |
127
+ | -------------------------- | ------------------------------------------------------------ |
128
+ | `npm start` | builds the app and starts it, the way the installer does |
129
+ | `npm run dev` | the same, with `ng serve` behind it so the renderer reloads |
130
+ | `npm run build` | production build of the renderer |
131
+ | `npm run electron:compile` | compiles `electron/` and bundles the preload |
132
+ | `npm run electron:build` | both builds, ready to run with `electron .` |
133
+ | `npm run electron:package` | builds everything and makes an installer with electron-builder |
134
+ | `npm run lint` | ESLint over TypeScript, the configs and the Angular templates |
135
+ | `npm run lint:fix` | the same, with autofix |
136
+ | `npm test` | renderer unit tests (Vitest + jsdom) |
137
+ | `npm run test:electron` | main process unit tests (Vitest, node) |
138
+ | `npm run smoke` | starts the built app and checks the whole chain end to end |
139
+ | `npm run release` | semantic-release; runs in CI, not by hand |
140
+
141
+ The app only runs inside Electron. In a plain browser `window.electron` does not exist and the
142
+ shell fails straight away, which is why there is no script that serves only the renderer.
143
+
144
+ ### Layout
145
+
146
+ ```
147
+ electron/ main process (TypeScript, compiled to CommonJS)
148
+ api.ts the contract between main/preload and the renderer
149
+ channels.ts IPC channel names, without imports
150
+ ipc.ts the only place where channels are attached to ipcMain
151
+ preload.ts contextBridge, the renderer's only window into main
152
+ main.ts window, tray, notifications and app lifecycle
153
+ docker-client.ts daemon connection and readable errors
154
+ i18n.ts language of the texts main produces
155
+ *.ts one file per feature (containers, images, logs, exec, compose, ...)
156
+ *.spec.ts unit tests, kept out of dist-electron
157
+
158
+ src/
159
+ styles.css Tailwind 4 and the theme tokens
160
+ app/core/ stores and services without UI of their own
161
+ app/shell/ header, sidebar, status bar, table, dialogs, toasts, command palette
162
+ app/pages/ one folder per route
163
+ app/i18n/ the dictionaries: en/ is the source, nl/ follows the same shape
164
+ testing/ the fake window.electron for renderer tests
165
+
166
+ scripts/smoke.js starts the built app against a real daemon
167
+ .forgejo/workflows/ CI on every branch, release on main
168
+ eslint-rules/ two custom formatting rules
169
+ ```
170
+
171
+ ### Adding a feature that needs main
172
+
173
+ Type it in `electron/api.ts`, attach the channel in `electron/ipc.ts` (validate the input with
174
+ zod there), and add the wrapper in `electron/preload.ts`. Angular picks up the type through
175
+ `src/electron.d.ts` (`window.electron`).
176
+
177
+ ### Translations
178
+
179
+ Every visible text in the renderer comes from `src/app/i18n/`. Add a key to the English file in
180
+ `en/`, and the compiler requires the same key in `nl/`. A text that includes a number or a name
181
+ is a function, so each language can handle plurals its own way. Texts made in the main process
182
+ use `t({ en: '…', nl: '…' })` from `electron/i18n.ts`. The tests run in Dutch
183
+ (`src/testing/setup.ts`, `electron/test-setup.ts`). Each area also has tests that switch to
184
+ English.
185
+
186
+ ### Theme
187
+
188
+ The tokens in `src/styles.css` are a `--color-ink-*` ramp, where a lower number means more
189
+ contrast with the page, plus `accent`, `ok`, `warn`, `danger` and `panel`.
190
+ `:root[data-theme='dark']` overrides the same names, so every Tailwind utility follows the
191
+ theme without template changes. `src/main.ts` sets the theme before Angular starts, which
192
+ avoids a light flash with a dark theme.
193
+
194
+ Filters on the list pages and the log view toggles are remembered (`app/core/preferences.ts`).
195
+ Search fields deliberately are not: a search term still active after a restart looks as if
196
+ half your containers have gone.
197
+
198
+ ### Code style
199
+
200
+ The lint config enforces the house style:
201
+ - lines up to 200 characters, and always braces;
202
+ - blank lines around control statements, and one after the `{` of a function declaration;
203
+ - parameters on one line as long as it fits within 150 characters.
204
+
205
+ Two custom rules for this live in `eslint-rules/`. There is deliberately **no Prettier**,
206
+ because it conflicts with these rules. `angular-eslint` also lints the `.html` templates.
207
+
208
+ Commits follow **conventional commits**, which commitlint checks through
209
+ `.husky/commit-msg`. The messages decide the version number: every push to `main` releases
210
+ automatically.
211
+
212
+ ### Security
213
+
214
+ The window runs with `contextIsolation: true`, `nodeIntegration: false` and `sandbox: true`.
215
+ The renderer has no Node access and no socket. Everything goes through `contextBridge` in
216
+ `electron/preload.ts`, which never passes `ipcRenderer` itself along. Otherwise the renderer
217
+ could call any channel instead of only the actions we meant to expose.
218
+
219
+ `src/index.html` sets a Content-Security-Policy that allows only the app's own scripts. Two
220
+ consequences that fail silently if you forget them:
221
+
222
+ - **The preload must be one self-contained file.** A sandboxed preload cannot load local
223
+ modules, so `electron:compile` bundles it with esbuild.
224
+ - **`inlineCritical` is off** in the production build. It adds an inline `onload` handler to
225
+ the stylesheet, which the CSP blocks, and then part of the CSS is never applied.
226
+
227
+ `npm run smoke` guards both.
228
+
229
+ ## License
230
+
231
+ MIT, see [`LICENSE`](LICENSE).
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * Start de app vanuit npm: `npx @martijn-on-fhir/docker-desktop-mx`.
4
+ *
5
+ * Het pakket bevat de gebouwde app, geen Electron zelf; dat komt als peer-dependency mee met de
6
+ * installatie. `require('electron')` geeft in Node het pad naar het programma, en dat starten we
7
+ * met de map van dit pakket als app.
8
+ *
9
+ * `--from-npm` vertelt main dat dit geen ontwikkelversie is, ook al is de app niet verpakt:
10
+ * zonder die vlag noemt hij zich "(dev)" en gebruikt hij een eigen gebruikersmap.
11
+ */
12
+ const { spawn } = require('node:child_process');
13
+ const path = require('node:path');
14
+
15
+ let electron;
16
+
17
+ try {
18
+ electron = require('electron');
19
+ } catch {
20
+ // Engels: de taalinstelling van de app is hier nog niet te lezen, en Engels is de standaard.
21
+ console.error('Electron is missing. Reinstall the package, or add electron: npm install electron');
22
+ process.exit(1);
23
+ }
24
+
25
+ const child = spawn(electron, [path.join(__dirname, '..'), '--from-npm', ...process.argv.slice(2)], { stdio: 'inherit' });
26
+
27
+ child.on('exit', (code, signal) => {
28
+ if (signal !== null) {
29
+ process.kill(process.pid, signal);
30
+ } else {
31
+ process.exit(code ?? 0);
32
+ }
33
+ });
34
+
35
+ // Ctrl+C in de terminal hoort ook de app te sluiten, niet alleen dit script.
36
+ for (const signal of ['SIGINT', 'SIGTERM']) {
37
+ process.on(signal, () => child.kill(signal));
38
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file