@exagone313/dsh-podman 0.2.0-rc.3 → 0.2.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 (191) hide show
  1. package/README.md +14 -2
  2. package/README.zh.md +14 -2
  3. package/cordis.patch.yml +58 -0
  4. package/dist/approval-reasons.d.ts +3 -4
  5. package/dist/approval-reasons.js +40 -49
  6. package/dist/approval-reasons.test.js +43 -15
  7. package/dist/approval.js +27 -10
  8. package/dist/approval.test.js +165 -34
  9. package/dist/card-route.d.ts +3 -2
  10. package/dist/card-route.js +154 -42
  11. package/dist/card-route.test.js +85 -43
  12. package/dist/card-test-support.js +39 -66
  13. package/dist/client/ContainerCard.d.ts +1 -1
  14. package/dist/client/ContainerCard.js +92 -50
  15. package/dist/client/card-protocol.d.ts +6 -3
  16. package/dist/client/container-card-caches.js +11 -6
  17. package/dist/client/container-card-controller.d.ts +16 -18
  18. package/dist/client/container-card-controller.js +92 -40
  19. package/dist/client/container-card-create-modal.d.ts +2 -2
  20. package/dist/client/container-card-create-modal.js +13 -5
  21. package/dist/client/container-card-default-env.d.ts +10 -0
  22. package/dist/client/container-card-default-env.js +69 -0
  23. package/dist/client/container-card-directory.d.ts +2 -2
  24. package/dist/client/container-card-directory.js +12 -4
  25. package/dist/client/container-card-editors.d.ts +3 -3
  26. package/dist/client/container-card-editors.js +104 -32
  27. package/dist/client/container-card-images.d.ts +4 -4
  28. package/dist/client/container-card-images.js +19 -6
  29. package/dist/client/container-card-paths.d.ts +3 -3
  30. package/dist/client/container-card-paths.js +18 -11
  31. package/dist/client/container-card-row.d.ts +10 -6
  32. package/dist/client/container-card-row.js +82 -13
  33. package/dist/client/container-card-secrets.d.ts +3 -3
  34. package/dist/client/container-card-secrets.js +8 -6
  35. package/dist/client/container-card-shared.d.ts +4 -17
  36. package/dist/client/container-card-shared.js +9 -25
  37. package/dist/client/container-card-styles.d.ts +2 -8
  38. package/dist/client/container-card-styles.js +14 -52
  39. package/dist/client/container-card-volumes.d.ts +2 -2
  40. package/dist/client/container-card-volumes.js +9 -5
  41. package/dist/client/container-card-workspace.d.ts +8 -6
  42. package/dist/client/container-card-workspace.js +9 -3
  43. package/dist/client/directory-picker.js +2 -1
  44. package/dist/client/index.js +13141 -2036
  45. package/dist/client/locales.d.ts +6 -1
  46. package/dist/client/locales.js +106 -38
  47. package/dist/client/podman-terminal-guide.d.ts +11 -0
  48. package/dist/client/podman-terminal-guide.js +208 -0
  49. package/dist/client/podman-terminal-title.d.ts +7 -0
  50. package/dist/client/podman-terminal-title.js +30 -0
  51. package/dist/client/podman-terminal.d.ts +26 -0
  52. package/dist/client/podman-terminal.js +412 -0
  53. package/dist/client/read-only-approval.d.ts +2 -2
  54. package/dist/client/read-only-approval.js +13 -3
  55. package/dist/client/slot-contract.d.ts +0 -11
  56. package/dist/client/terminal-preference.d.ts +26 -0
  57. package/dist/client/terminal-preference.js +67 -0
  58. package/dist/client/terminal-protocol.d.ts +85 -0
  59. package/dist/client/terminal-protocol.js +14 -0
  60. package/dist/client/terminal-tab.d.ts +60 -0
  61. package/dist/client/terminal-tab.js +35 -0
  62. package/dist/client/terminal-targets.d.ts +33 -0
  63. package/dist/client/terminal-targets.js +65 -0
  64. package/dist/client/terminal-titles.d.ts +23 -0
  65. package/dist/client/terminal-titles.js +52 -0
  66. package/dist/client/terminal-transport.d.ts +63 -0
  67. package/dist/client/terminal-transport.js +207 -0
  68. package/dist/client/tool-views.js +215 -49
  69. package/dist/container-env.d.ts +11 -0
  70. package/dist/container-env.js +96 -0
  71. package/dist/container-env.test.d.ts +1 -0
  72. package/dist/container-env.test.js +93 -0
  73. package/dist/containers.test.js +196 -18
  74. package/dist/daemons.test.js +18 -4
  75. package/dist/dsh-version.d.ts +1 -0
  76. package/dist/dsh-version.js +46 -0
  77. package/dist/env-rows.d.ts +14 -0
  78. package/dist/env-rows.js +52 -0
  79. package/dist/env-rows.test.d.ts +1 -0
  80. package/dist/env-rows.test.js +43 -0
  81. package/dist/fs-provider.d.ts +1 -0
  82. package/dist/fs-provider.js +26 -12
  83. package/dist/fs-provider.test.js +51 -10
  84. package/dist/generated/version.d.ts +2 -2
  85. package/dist/generated/version.js +2 -2
  86. package/dist/grpc/proto/dshctl/v1/control.proto +11 -1
  87. package/dist/grpc/proto/dshguest/v1/guest.proto +5 -0
  88. package/dist/grpc/runtime-client.d.ts +3 -1
  89. package/dist/grpc/runtime-client.js +90 -17
  90. package/dist/guest-rpc.d.ts +15 -19
  91. package/dist/guest-rpc.js +289 -70
  92. package/dist/guest-rpc.test.d.ts +1 -0
  93. package/dist/guest-rpc.test.js +241 -0
  94. package/dist/guest-terminal.d.ts +30 -0
  95. package/dist/guest-terminal.js +196 -0
  96. package/dist/images.test.js +10 -3
  97. package/dist/index.d.ts +11 -16
  98. package/dist/index.js +42 -36
  99. package/dist/locales.test.d.ts +1 -0
  100. package/dist/locales.test.js +34 -0
  101. package/dist/misc.test.js +38 -10
  102. package/dist/mount-enums.js +2 -1
  103. package/dist/mount-input.d.ts +2 -0
  104. package/dist/mount-input.js +38 -22
  105. package/dist/mounts.test.js +81 -11
  106. package/dist/naming.test.d.ts +1 -0
  107. package/dist/naming.test.js +28 -0
  108. package/dist/output-reader.js +36 -4
  109. package/dist/package-deps.test.d.ts +1 -0
  110. package/dist/package-deps.test.js +49 -0
  111. package/dist/paths.test.js +4 -2
  112. package/dist/plugin-meta.test.d.ts +1 -0
  113. package/dist/plugin-meta.test.js +29 -0
  114. package/dist/project-path.js +33 -7
  115. package/dist/project-path.test.js +14 -0
  116. package/dist/prompts.d.ts +0 -4
  117. package/dist/prompts.js +15 -84
  118. package/dist/read-only-shell.js +3 -1
  119. package/dist/read-only-shell.test.js +80 -25
  120. package/dist/runtime-client.test.d.ts +1 -0
  121. package/dist/runtime-client.test.js +53 -0
  122. package/dist/secrets.test.js +21 -6
  123. package/dist/settings-commands.test.js +61 -14
  124. package/dist/settings-create.test.js +32 -10
  125. package/dist/settings-default-env.test.d.ts +1 -0
  126. package/dist/settings-default-env.test.js +175 -0
  127. package/dist/settings-mounts.test.js +46 -7
  128. package/dist/settings-schema.d.ts +6 -11
  129. package/dist/settings-schema.js +4 -8
  130. package/dist/settings-schema.test.d.ts +1 -0
  131. package/dist/settings-schema.test.js +35 -0
  132. package/dist/settings-workspaces.test.js +38 -63
  133. package/dist/spill-store.d.ts +1 -0
  134. package/dist/spill-store.js +17 -4
  135. package/dist/spill-store.test.js +31 -8
  136. package/dist/subprocess.d.ts +4 -0
  137. package/dist/subprocess.js +148 -162
  138. package/dist/subprocess.test.js +118 -8
  139. package/dist/terminal-preference.test.d.ts +1 -0
  140. package/dist/terminal-preference.test.js +62 -0
  141. package/dist/terminal-route.d.ts +10 -0
  142. package/dist/terminal-route.js +270 -0
  143. package/dist/terminal-route.test.d.ts +1 -0
  144. package/dist/terminal-route.test.js +265 -0
  145. package/dist/terminal-sessions.d.ts +69 -0
  146. package/dist/terminal-sessions.js +252 -0
  147. package/dist/terminal-shells.d.ts +22 -0
  148. package/dist/terminal-shells.js +99 -0
  149. package/dist/terminal-tab.test.d.ts +1 -0
  150. package/dist/terminal-tab.test.js +58 -0
  151. package/dist/terminal-targets.test.d.ts +1 -0
  152. package/dist/terminal-targets.test.js +43 -0
  153. package/dist/terminal-titles.test.d.ts +1 -0
  154. package/dist/terminal-titles.test.js +36 -0
  155. package/dist/test-support.d.ts +35 -5
  156. package/dist/test-support.js +91 -29
  157. package/dist/tool-defs.js +19 -4
  158. package/dist/tool-handlers.js +80 -28
  159. package/dist/tool-params.js +19 -5
  160. package/dist/version-compat.d.ts +4 -0
  161. package/dist/version-compat.js +29 -0
  162. package/dist/version-compat.test.d.ts +1 -0
  163. package/dist/version-compat.test.js +27 -0
  164. package/dist/volumes.test.js +1 -1
  165. package/dist/workspace-binding.d.ts +19 -10
  166. package/dist/workspace-binding.js +252 -78
  167. package/dist/workspace-binding.test.js +202 -27
  168. package/docs/architecture.md +71 -20
  169. package/docs/architecture.zh.md +62 -12
  170. package/docs/configuration.md +61 -20
  171. package/docs/configuration.zh.md +53 -19
  172. package/docs/development-prompt.md +72 -0
  173. package/docs/development-prompt.zh.md +69 -0
  174. package/docs/development.md +184 -29
  175. package/docs/development.zh.md +165 -26
  176. package/docs/install-dsh-and-dsh-podman.md +24 -21
  177. package/docs/install-dsh-and-dsh-podman.zh.md +20 -21
  178. package/docs/uninstall.md +83 -0
  179. package/docs/uninstall.zh.md +79 -0
  180. package/docs/update.md +120 -0
  181. package/docs/update.zh.md +114 -0
  182. package/docs/usage.md +108 -61
  183. package/docs/usage.zh.md +76 -38
  184. package/locale/en.json +6 -0
  185. package/locale/zh.json +6 -0
  186. package/package.json +58 -25
  187. package/quadlet/dsh-podman-orchestrator.container +46 -0
  188. package/quadlet/dsh.container +35 -0
  189. package/LICENSE.pkg +0 -17103
  190. package/dist/preferences.d.ts +0 -6
  191. package/dist/preferences.js +0 -27
package/docs/usage.md CHANGED
@@ -6,7 +6,7 @@ SPDX-License-Identifier: MIT
6
6
 
7
7
  # Usage
8
8
 
9
- This page documents the model-facing tools, the settings card, and the image
9
+ This page documents the model-facing tools, the Podman page, and the image
10
10
  model. See [Architecture](architecture.md) for how the pieces fit together.
11
11
 
12
12
  ## Model context
@@ -19,7 +19,10 @@ the assembled system prompt; the model is never told a misleading path.
19
19
  dsh-podman also adds its own prompt section clarifying that the built-in shell
20
20
  and filesystem tools (`bash`, `read`, `write`, `edit`, `glob`, `grep`) run
21
21
  inside the workspace's default container rather than on the host, and how they
22
- relate to the `container_*` tools.
22
+ relate to the `container_*` tools. The same section steers the model toward
23
+ building a custom image with `image_build` (then `container_start` or
24
+ `container_recreate`) for software installs, and toward named volumes rather
25
+ than `tmpfs` for data that must survive a container recreate.
23
26
 
24
27
  ## Image model
25
28
 
@@ -35,8 +38,8 @@ dsh-podman organizes the images its containers run into three tiers:
35
38
  manager. By default they are **built locally** from the primitive (installing
36
39
  the default packages); when `DSH_PODMAN_BASE_IMAGE_PREFIX` points at a
37
40
  registry (anything not starting with `localhost/`), they are **pulled**
38
- instead. Base images are listed in the settings UI even when not yet
39
- built/pulled, are rebuilt or pulled from the card, and their short names are
41
+ instead. Base images are listed on the Podman page even when not yet
42
+ built/pulled, are rebuilt or pulled from there, and their short names are
40
43
  reserved — they cannot be built over, rebuilt, or removed as custom images.
41
44
  - **Custom images** are user-built images created from a **parent** — a base
42
45
  image or another custom image — inheriting its package manager and adding
@@ -75,7 +78,8 @@ policy):
75
78
  `read`, `glob`, and `grep` always run.
76
79
  - **Workspace Write** — the `✱` tools ask through DSH's approval service (the
77
80
  call shows the standard approval prompt and is denied when no approval channel
78
- is available); `container_start` asks only when `mounts` is passed.
81
+ is available); `container_start` asks only when `mounts` is passed or
82
+ `secretEnv` attaches secrets.
79
83
  - **Full access** — tools run without approval prompts.
80
84
 
81
85
  The harness's `sandbox_permissions` argument (a one-shot sandbox widening, e.g.
@@ -86,11 +90,12 @@ The prompt's reason is a full sentence naming the action and the objects it
86
90
  touches, quoting every identifier — for example
87
91
  `Add mount to container "web": volume "data" (read-only)`. It covers the
88
92
  container image, each mount's kind and destination, the environment variable
89
- keys, and the resolved file path. It follows the UI language: the browser client
90
- records the active locale in the plugin settings, with the durable locale
91
- preference as the fallback (English when neither is set). A policy denial — a
92
- read-only sandbox, or a destination on a project mount — is reported in the same
93
- language. The settings-card actions are direct control calls and are not gated.
93
+ keys, the secret env var names, and the resolved file path. It follows the UI
94
+ language: the browser client records the active locale in the plugin's
95
+ `uiLocale` preference, which the Host persists in the plugin config (English
96
+ when unset). A policy denial — a read-only sandbox, or a destination on a
97
+ project mount — is reported in the same language. The Podman page's actions are
98
+ direct control calls and are not gated.
94
99
 
95
100
  `container_start`, `container_recreate`, and `container_bash` accept an `env`
96
101
  map applied to the container (or the bash process); `container_exec` and
@@ -105,6 +110,14 @@ Environment variables are not treated as secrets, so the approval reason and
105
110
  reserved and rejected, since the orchestrator uses that namespace for
106
111
  guest-agent wiring.
107
112
 
113
+ New containers are also seeded with the plugin's **default environment** (the
114
+ `containerEnv` setting), so a git identity can be configured once instead of per
115
+ project — see [Default environment](configuration.md#default-environment). The
116
+ Podman page's **Git identity** popup fills the four
117
+ `GIT_AUTHOR_*`/`GIT_COMMITTER_*` variables from one name and one email, and
118
+ **Apply default environment variables** adds them to the running containers that
119
+ lack them.
120
+
108
121
  `container_bash` and `container_exec` run with the same command-visible
109
122
  environment as the built-in `bash`: the harness's managed `DSH_*` facts
110
123
  (`DSH_HOME`, `DSH_SHELL`, `DSH_SESSION_ID`, `DSH_WEB_URL`) and its
@@ -114,14 +127,14 @@ managed `DSH_*` fact.
114
127
 
115
128
  ### Images
116
129
 
117
- | Tool | Params | Description |
118
- | --------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
119
- | `image_build` ✱ | `imageId`, `parent`, `packages` | Build a new custom image from a base or custom parent and package list |
120
- | `image_get` | `imageId` | Details for one image |
121
- | `image_list` | — | List the built workspace images, base images first |
122
- | `image_rebuild_all` ✱ | — | Ensure every base, then rebuild every custom image in dependency order, skipping any image whose rebuild fails and its dependents |
123
- | `image_rebuild` ✱ | `imageId` | Rebuild an existing custom image in place |
124
- | `image_remove` ✱ | `imageId` | Remove a built image; refused while a workspace or container still references it |
130
+ | Tool | Params | Description |
131
+ | --------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
132
+ | `image_build` ✱ | `imageId`, `parent`, `packages` | Build a new custom image from a base or custom parent and package list |
133
+ | `image_get` | `imageId` | Details for one image |
134
+ | `image_list` | — | List the built workspace images, base images first |
135
+ | `image_rebuild_all` ✱ | — | Ensure every base, then rebuild every custom image in dependency order, skipping any image whose rebuild fails and its dependents; a base it cannot ensure is reported in `skipped` by short name |
136
+ | `image_rebuild` ✱ | `imageId` | Rebuild an existing custom image in place |
137
+ | `image_remove` ✱ | `imageId` | Remove a built image; refused while a workspace or container still references it |
125
138
 
126
139
  ### Containers
127
140
 
@@ -136,7 +149,7 @@ managed `DSH_*` fact.
136
149
  | `container_read` | `container`, `file_path`, optional `offset`, `limit` | Read a file |
137
150
  | `container_recreate` ✱ | `container`, optional `image`, `mounts`, `env`, `secretEnv`, `paths` | Recreate a container, keeping its current image when `image` is omitted, optionally with new project mounts, environment, or PATH additions |
138
151
  | `container_remove` ✱ | `container` | Remove a container (stops its daemons gracefully first) |
139
- | `container_start` ✱ | `container`, optional `image`, `mounts`, `env`, `secretEnv`, `paths` | Start a container (default image when `image` is omitted); approval required only when `mounts` is passed |
152
+ | `container_start` ✱ | `container`, optional `image`, `mounts`, `env`, `secretEnv`, `paths` | Start a container (default image when `image` is omitted); approval required only when `mounts` or `secretEnv` is passed |
140
153
  | `container_write` | `container`, `file_path`, `content` | Write a file |
141
154
 
142
155
  The `container_bash`, `container_exec`, `container_read`, `container_write`,
@@ -205,14 +218,13 @@ Project mounts do not take a `destination`: a project directory is always
205
218
  mounted at its mirrored path under the projects root. `destination` applies only
206
219
  to `tmpfs`, `volume` and `secret` mounts.
207
220
 
208
- In the settings card, the project path field of the add-mount and
209
- create-container dialogs has a **Browse…** button. It opens a directory picker
210
- that reads the projects root through dsh's own host-side directory listing — the
211
- same service behind dsh's workspace directory selection — not through the
212
- orchestrator or a container. Its layout follows dsh's own directory browser: two
213
- columns, chevron breadcrumbs, folder icons, and a hidden-entry toggle. The
214
- dialog is confined to the projects root, and the path it produces is stored
215
- relative to that root.
221
+ On the Podman page, the project path field of the add-mount and create-container
222
+ dialogs has a **Browse…** button. It opens a directory picker that reads the
223
+ projects root through dsh's own host-side directory listing — the same service
224
+ behind dsh's workspace directory selection — not through the orchestrator or a
225
+ container. Its layout follows dsh's own directory browser: two columns, chevron
226
+ breadcrumbs, folder icons, and a hidden-entry toggle. The dialog is confined to
227
+ the projects root, and the path it produces is stored relative to that root.
216
228
 
217
229
  Removing a mount names it by `kind` plus that mount's own handle: `project` for
218
230
  a project mount, `volume` for a named volume, `secret` for a secret, and
@@ -283,7 +295,7 @@ read tool. A secret can be attached to a container either as a **mount**
283
295
  (`container_mount_add kind="secret"` + `secret` + `destination`, read-only, at
284
296
  an absolute path never under the projects root) or as an **environment
285
297
  variable** (`container_secret_add`; the env var name must not start with
286
- `DSH_PODMAN`). The settings card can **overwrite** a secret with user-typed
298
+ `DSH_PODMAN`). The Podman page can **overwrite** a secret with user-typed
287
299
  content (write-only) but never reads it.
288
300
 
289
301
  A secret mounted at a path is created as a root-owned **file** (not a directory)
@@ -323,34 +335,34 @@ started with.
323
335
 
324
336
  ## Container management UI
325
337
 
326
- The plugin ships a browser half that registers a card in the dsh **Settings →
327
- Plugins** page. The card lists the orchestrator-created guest containers and the
328
- built images. A workspace with no container gets a **Create container** button
329
- that opens a configuration modal — image, environment, mounts (project, tmpfs,
330
- volume, and secret), PATH additions, and secret environment variables — and
331
- workspaces that already have containers offer an **Add container** button for
332
- additional, named containers through the same modal, which is titled after the
333
- button that opened it. In that modal each mount's mode is a dropdown
334
- (read-only/read-write), so the workspace project mount can be created read-only
335
- in one step; tmpfs and secret mounts are fixed (read-write and read-only
336
- respectively) and show a disabled dropdown. Container rows show their
337
- environment and secret-environment variables and their mounts, let you edit
338
- environment variables and add/remove mounts (each removal is confirmed), and
339
- attach/detach named secrets to a container's environment variables; each row
340
- also offers **Remove**, **Recreate** (same image), and **Recreate with image**.
341
- Every workspace row also offers **Remove pod**, which removes the workspace's
342
- pod, all of its containers, and the orchestrator's record for it (volumes,
343
- secrets, and project data are kept); removing a workspace's last container
344
- removes its pod as well, so an empty pod is never left behind. The card re-reads
345
- the live state whenever the Plugins page is opened, and its header has a
346
- **Reload this view** button. The images section can rebuild a single image or
347
- **rebuild all** in dependency order; **Build image** opens a popup with an
348
- image-id/base-image form and a chip input for the package list (type a name and
349
- press space/comma, or paste a list, to add removable chips). Volumes and secrets
350
- are listed as individual expandable rows, each with its own actions, and
351
- **Create volume** / **Create secret** open popup forms (the secret form takes an
352
- optional length; a secret's value can be overwritten, never read). Card actions
353
- are direct control calls and are not approval-gated.
338
+ The plugin ships a browser half that registers its card on the **dsh-podman**
339
+ page (sidebar **Plugins** panel → **Installed**). The page lists the
340
+ orchestrator-created guest containers and the built images. A workspace with no
341
+ container gets a **Create container** button that opens a configuration modal —
342
+ image, environment, mounts (project, tmpfs, volume, and secret), PATH additions,
343
+ and secret environment variables — and workspaces that already have containers
344
+ offer an **Add container** button for additional, named containers through the
345
+ same modal, which is titled after the button that opened it. In that modal each
346
+ mount's mode is a dropdown (read-only/read-write), so the workspace project
347
+ mount can be created read-only in one step; tmpfs and secret mounts are fixed
348
+ (read-write and read-only respectively) and show a disabled dropdown. Container
349
+ rows show their environment and secret-environment variables and their mounts,
350
+ let you edit environment variables and add/remove mounts (each removal is
351
+ confirmed), and attach/detach named secrets to a container's environment
352
+ variables; each row also offers **Remove**, **Recreate** (same image), and
353
+ **Recreate with image**. Every workspace row also offers **Remove pod**, which
354
+ removes the workspace's pod, all of its containers, and the orchestrator's
355
+ record for it (volumes, secrets, and project data are kept); removing a
356
+ workspace's last container removes its pod as well, so an empty pod is never
357
+ left behind. The page re-reads the live state whenever the Plugins panel opens
358
+ it, and its footer has a **Reload this view** button. The images section can
359
+ rebuild a single image or **rebuild all** in dependency order; **Build image**
360
+ opens a popup with an image-id/base-image form and a chip input for the package
361
+ list (type a name and press space/comma, or paste a list, to add removable
362
+ chips). Volumes and secrets are listed as individual expandable rows, each with
363
+ its own actions, and **Create volume** / **Create secret** open popup forms (the
364
+ secret form takes an optional length; a secret's value can be overwritten, never
365
+ read). Card actions are direct control calls and are not approval-gated.
354
366
 
355
367
  A **Package caches** section reports the size of every configured build cache
356
368
  (`DSH_PODMAN_HOST_PACMAN_CACHE`, `DSH_PODMAN_HOST_APT_CACHE`,
@@ -360,13 +372,47 @@ versions** removes every cached package file except the newest of each package
360
372
  safe — a cached package is only ever re-downloaded — and neither runs while an
361
373
  image build is in progress.
362
374
 
375
+ ## Podman terminal
376
+
377
+ The plugin owns a **Podman terminal** right-Sidebar tab, separate from dsh's own
378
+ Terminal tab. Open it from the right Sidebar's new-tab guide — the card is **New
379
+ terminal** — or press
380
+ **Ctrl+`**; the tab is named after the shell it runs
381
+ (`bash`,`sh`, …). The built-in Terminal UI is disabled by the plugin's bundle
382
+ patch, which frees that shortcut (if it is enabled again, the plugin falls back
383
+ to **Ctrl+Shift+`**);
384
+ the agent's `terminal` tool is unaffected. It always runs in the session's own
385
+ workspace — each workspace has its own side panes and terminals — so the start
386
+ form only asks for a container and then a shell, and a shell can run in the
387
+ default container or in a named one. If the session's directory names no known
388
+ workspace the form reports that instead of guessing; the harness's own Terminal
389
+ always uses that workspace's default container. The container and shell you last
390
+ started are remembered in the browser's local storage and preselected while they
391
+ are still available — a container that disappeared falls back to the default,
392
+ and a shell the image no longer ships falls back to the first one the container
393
+ offers.
394
+
395
+ The shell list is discovered **inside the chosen container**: candidate names
396
+ are looked up on that container's PATH (`command -v`) and merged with
397
+ `/etc/shells` and `$SHELL`, so a shell installed through a PATH addition or a
398
+ mounted volume appears while one the image lacks does not. The list is ordered
399
+ most capable first (`zsh`, `bash`, `fish`, … down to `dash`, `ash`, `sh`), so
400
+ the picker preselects the best shell the container has. The selected shell is
401
+ verified again before it starts.
402
+
403
+ Terminals are retained on the host: switching tabs, closing the Sidebar or
404
+ reloading the page keeps the shell and its scrollback, and reattaching replays
405
+ the screen. Closing the tab leaves the shell retained for a while (until the
406
+ host reaps it); **Reconnect** starts a fresh shell in the current selection.
407
+ Closing or recreating a container drops its terminals, so reconnect afterwards.
408
+
363
409
  ## Podman operator mode
364
410
 
365
411
  The plugin ships an **agent preset** named _Podman operator mode_ (id
366
- `podman-ops`). On every load it (re)writes the preset into the harness's
367
- user-presets root (`~/.dsh/.agent-presets/podman-ops/`), overwriting any local
368
- copy so the shipped content stays authoritative. It appears in the session's
369
- agent-preset picker next to the shipped presets.
412
+ `podman-ops`). The plugin's bundle patch declares it as a
413
+ `@deepseek-ai/dsh-agent-preset` row, so the harness's preset registry serves it
414
+ directly. It appears in the session's agent-preset picker next to the shipped
415
+ presets.
370
416
 
371
417
  The preset composes a Podman-focused persona with the built-in task tools
372
418
  (`ask_user_question`, `todo_write`) and `web_search` (web fetch disabled). It
@@ -377,7 +423,8 @@ are global and all remain available, split as:
377
423
  - **Direct:** `image_list`, `image_get`, `container_list`, `container_read`,
378
424
  `container_glob`, `container_grep`, `container_mount_list`, `volume_list`,
379
425
  `secret_list`, `secret_create`, `daemon_list`, `daemon_logs`, `daemon_stop`,
380
- `daemon_restart`, `container_start` (asks only when `mounts` is passed).
426
+ `daemon_restart`, `container_start` (asks only when `mounts` or `secretEnv` is
427
+ passed).
381
428
  - **Approval-gated** (the usual `✱` tools): `image_build`, `image_rebuild`,
382
429
  `image_rebuild_all`, `image_remove`, `container_recreate`, `container_remove`,
383
430
  `container_mount_add`, `container_mount_remove`, `container_mount_update`,
package/docs/usage.zh.md CHANGED
@@ -6,7 +6,8 @@ SPDX-License-Identifier: MIT
6
6
 
7
7
  # 使用
8
8
 
9
- 本页面记录了面向模型的工具、设置卡片以及镜像模型。参见[架构](architecture.zh.md)了解各部分如何组合在一起。
9
+ 本页面记录了面向模型的工具、Podman
10
+ 页面以及镜像模型。参见[架构](architecture.zh.md)了解各部分如何组合在一起。
10
11
 
11
12
  ## 模型上下文
12
13
 
@@ -16,7 +17,9 @@ Harness 会添加一个提示词区段,指明其自身的磁盘检出目录,
16
17
 
17
18
  dsh-podman 还会添加自己的提示词区段,说明内置的 shell
18
19
  与文件系统工具(`bash`、`read`、`write`、`edit`、`glob`、`grep`)在工作区的默认容器内运行,而非宿主机,并说明它们与
19
- `container_*` 工具的关系。
20
+ `container_*` 工具的关系。同一区段还会引导模型:安装软件时用 `image_build`
21
+ 构建自定义镜像(再用 `container_start` 或 `container_recreate`
22
+ 启动),需要跨容器重建保留的数据应使用命名卷而非 `tmpfs`。
20
23
 
21
24
  ## 镜像模型
22
25
 
@@ -31,7 +34,8 @@ dsh-podman 将容器运行的镜像组织为三个层级:
31
34
  拥有的默认软件包列表及其软件包管理器定义。默认情况下它们从原始镜像**本地构建**(安装默认软件包);当
32
35
  `DSH_PODMAN_BASE_IMAGE_PREFIX` 指向某个镜像仓库(任何不以 `localhost/`
33
36
  开头的名称)时,它们改为被**拉取**。即使尚未构建/拉取,基础镜像也会列在设置 UI
34
- 中,可从卡片重建或拉取,并且它们的短名称是保留的——它们不能被覆盖构建、重建或作为自定义镜像移除。
37
+ 中,可从 Podman
38
+ 页面重建或拉取,并且它们的短名称是保留的——它们不能被覆盖构建、重建或作为自定义镜像移除。
35
39
  - **自定义镜像**是从**父镜像**——基础镜像或另一个自定义镜像——创建的用户构建镜像,继承其软件包管理器并在此基础上添加额外软件包。它们通过短名称引用(例如
36
40
  `valkey`)。
37
41
 
@@ -60,14 +64,17 @@ dsh-podman 将容器运行的镜像组织为三个层级:
60
64
  和 `grep` 始终可运行。
61
65
  - **Workspace Write** — 带 `✱` 的工具通过 DSH
62
66
  的审批服务询问(调用会显示标准审批提示,当没有可用的审批通道时被拒绝);`container_start`
63
- 仅在传入 `mounts` 时询问。
67
+ 仅在传入 `mounts` 或 `secretEnv` 时询问。
64
68
  - **Full access** — 工具运行时不显示审批提示。
65
69
 
66
70
  harness 的 `sandbox_permissions` 参数(例如 `bash`
67
71
  上的一次性沙箱放宽)会被接受但在此处没有效果:沙箱在容器内被绕过,因此插件会直接授予该升权而不询问。
68
72
 
69
73
  审批提示的原因是一句话,说明操作及其涉及的对象,并对每个标识符加引号——例如
70
- `Add mount to container "web": volume "data" (read-only)`。它涵盖容器镜像、每个挂载的类型与目标路径、环境变量的键,以及解析后的文件路径。它会跟随界面语言:浏览器客户端将当前语言记录到插件设置中,并以持久化的语言偏好作为回退(两者都未设置时为英文)。策略拒绝——只读沙箱,或项目挂载上指定了目标路径——也会使用相同的语言。设置卡片操作是直接的控制调用,不进行门控。
74
+ `Add mount to container "web": volume "data" (read-only)`。它涵盖容器镜像、每个挂载的类型与目标路径、环境变量的键、机密环境变量名,以及解析后的文件路径。它会跟随界面语言:浏览器客户端将当前语言记录到插件的
75
+ `uiLocale`
76
+ 偏好中,并由主机持久化到插件配置(未设置时为英文)。策略拒绝——只读沙箱,或项目挂载上指定了目标路径——也会使用相同的语言。Podman
77
+ 页面操作是直接的控制调用,不进行门控。
71
78
 
72
79
  `container_start`、`container_recreate` 和 `container_bash` 接受应用于容器(或
73
80
  bash 进程)的 `env` 映射;`container_exec` 和 `daemon_start` 已经接受 `env`,而
@@ -79,6 +86,12 @@ bash 进程)的 `env` 映射;`container_exec` 和 `daemon_start` 已经接
79
86
  `container_list` 显示变量的**键**。以 `DSH_PODMAN`
80
87
  开头的键被保留并被拒绝,因为编排器将该命名空间用于 guest-agent 接线。
81
88
 
89
+ 新容器还会注入插件的**默认环境变量**(`containerEnv` 设置),因此 Git
90
+ 身份只需配置一次,而不必按项目重复设置——见[默认环境变量](configuration.zh.md#默认环境变量)。Podman
91
+ 页面中的 **Git 身份**弹窗用一份姓名与邮箱填入四个
92
+ `GIT_AUTHOR_*`/`GIT_COMMITTER_*`
93
+ 变量,**应用默认环境变量**会把它们补给尚未具备的现有运行中容器。
94
+
82
95
  `container_bash` 和 `container_exec` 使用与内置 `bash`
83
96
  相同的命令可见环境运行:harness 托管的 `DSH_*`
84
97
  事实(`DSH_HOME`、`DSH_SHELL`、`DSH_SESSION_ID`、`DSH_WEB_URL`)及其非交互式终端覆盖项(`NO_COLOR`、`TERM=dumb`、`PAGER=cat`、`GIT_PAGER=cat`)。调用方的
@@ -86,30 +99,30 @@ bash 进程)的 `env` 映射;`container_exec` 和 `daemon_start` 已经接
86
99
 
87
100
  ### 镜像
88
101
 
89
- | 工具 | 参数 | 描述 |
90
- | --------------------- | ------------------------------- | ------------------------------------------------------------------------------------ |
91
- | `image_build` ✱ | `imageId`, `parent`, `packages` | 从基础或自定义父镜像及软件包列表构建新的自定义镜像 |
92
- | `image_get` | `imageId` | 单个镜像的详细信息 |
93
- | `image_list` | — | 列出已构建的工作区镜像,基础镜像在前 |
94
- | `image_rebuild_all` ✱ | — | 确保每个基础镜像,然后按依赖顺序重建每个自定义镜像,跳过重建失败的任何镜像及其依赖项 |
95
- | `image_rebuild` ✱ | `imageId` | 原地重建现有的自定义镜像 |
96
- | `image_remove` ✱ | `imageId` | 移除已构建的镜像;当工作区或容器仍引用它时拒绝 |
102
+ | 工具 | 参数 | 描述 |
103
+ | --------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
104
+ | `image_build` ✱ | `imageId`, `parent`, `packages` | 从基础或自定义父镜像及软件包列表构建新的自定义镜像 |
105
+ | `image_get` | `imageId` | 单个镜像的详细信息 |
106
+ | `image_list` | — | 列出已构建的工作区镜像,基础镜像在前 |
107
+ | `image_rebuild_all` ✱ | — | 确保每个基础镜像,然后按依赖顺序重建每个自定义镜像,跳过重建失败的任何镜像及其依赖项;无法确保的基础镜像以短名称出现在 `skipped` 中 |
108
+ | `image_rebuild` ✱ | `imageId` | 原地重建现有的自定义镜像 |
109
+ | `image_remove` ✱ | `imageId` | 移除已构建的镜像;当工作区或容器仍引用它时拒绝 |
97
110
 
98
111
  ### 容器
99
112
 
100
- | 工具 | 参数 | 描述 |
101
- | ---------------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
102
- | `container_bash` | `container`, `command`, `description`, optional `workdir`, `timeoutMs`, `env`, `uid`, `gid`, `groups` | 运行 shell 命令 |
103
- | `container_edit` | `container`, `file_path`, `old_string`, `new_string`, optional `replace_all` | 编辑文件 |
104
- | `container_exec` | `container`, `argv`, `description`, optional `workdir`, `timeoutMs`, `env`, `uid`, `gid`, `groups` | 运行程序 |
105
- | `container_glob` | `container`, `pattern`, optional `path` | 列出匹配模式的文件 |
106
- | `container_grep` | `container`, `pattern`, optional `path`, `include` | 按正则表达式搜索文件 |
107
- | `container_list` | — | 列出当前工作区的容器 |
108
- | `container_read` | `container`, `file_path`, optional `offset`, `limit` | 读取文件 |
109
- | `container_recreate` ✱ | `container`, optional `image`, `mounts`, `env`, `secretEnv`, `paths` | 重建容器,省略 `image` 时保留其当前镜像,可选地使用新的项目挂载、环境或 PATH 附加项 |
110
- | `container_remove` ✱ | `container` | 移除容器(先优雅地停止其守护进程) |
111
- | `container_start` ✱ | `container`, optional `image`, `mounts`, `env`, `secretEnv`, `paths` | 启动容器(省略 `image` 时使用默认镜像);仅在传入 `mounts` 时需要审批 |
112
- | `container_write` | `container`, `file_path`, `content` | 写入文件 |
113
+ | 工具 | 参数 | 描述 |
114
+ | ---------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
115
+ | `container_bash` | `container`, `command`, `description`, optional `workdir`, `timeoutMs`, `env`, `uid`, `gid`, `groups` | 运行 shell 命令 |
116
+ | `container_edit` | `container`, `file_path`, `old_string`, `new_string`, optional `replace_all` | 编辑文件 |
117
+ | `container_exec` | `container`, `argv`, `description`, optional `workdir`, `timeoutMs`, `env`, `uid`, `gid`, `groups` | 运行程序 |
118
+ | `container_glob` | `container`, `pattern`, optional `path` | 列出匹配模式的文件 |
119
+ | `container_grep` | `container`, `pattern`, optional `path`, `include` | 按正则表达式搜索文件 |
120
+ | `container_list` | — | 列出当前工作区的容器 |
121
+ | `container_read` | `container`, `file_path`, optional `offset`, `limit` | 读取文件 |
122
+ | `container_recreate` ✱ | `container`, optional `image`, `mounts`, `env`, `secretEnv`, `paths` | 重建容器,省略 `image` 时保留其当前镜像,可选地使用新的项目挂载、环境或 PATH 附加项 |
123
+ | `container_remove` ✱ | `container` | 移除容器(先优雅地停止其守护进程) |
124
+ | `container_start` ✱ | `container`, optional `image`, `mounts`, `env`, `secretEnv`, `paths` | 启动容器(省略 `image` 时使用默认镜像);仅在传入 `mounts` 或 `secretEnv` 时需要审批 |
125
+ | `container_write` | `container`, `file_path`, `content` | 写入文件 |
113
126
 
114
127
  `container_bash`、`container_exec`、`container_read`、`container_write`、
115
128
  `container_edit`、`container_glob` 和 `container_grep` 的参数与 harness 内置的
@@ -166,7 +179,7 @@ UI 行(图标、标题、摘要和结果正文),因此它们会像内置
166
179
  根目录下与之对应的路径上。`destination` 仅适用于 `tmpfs`、`volume` 和 `secret`
167
180
  挂载。
168
181
 
169
- 在设置卡片中,添加挂载与创建容器对话框的项目路径字段带有 **浏览…**
182
+ 在 Podman 页面中,添加挂载与创建容器对话框的项目路径字段带有 **浏览…**
170
183
  按钮。它会打开一个目录选择器,通过 dsh 自身的主机侧目录列表(也就是 dsh
171
184
  工作区目录选择所用的同一服务)读取 projects
172
185
  根目录,而不经过编排器或容器。其布局与 dsh
@@ -231,8 +244,8 @@ UI 使用短名称。`secret_create` 的值由服务端用 `crypto/rand`
231
244
  生成,且**永不暴露**——没有读取工具。机密可以附加到容器上,既可以作为**挂载**(`container_mount_add kind="secret"` +
232
245
  `secret` + `destination`,只读,位于绝不位于 projects
233
246
  根目录之下的绝对路径),也可以作为**环境变量**(`container_secret_add`;环境变量名不得以
234
- `DSH_PODMAN`
235
- 开头)。设置卡片可以用用户输入的内容**覆盖**机密(只写),但绝不读取它。
247
+ `DSH_PODMAN` 开头)。Podman
248
+ 页面可以用用户输入的内容**覆盖**机密(只写),但绝不读取它。
236
249
 
237
250
  挂载到某个路径的机密以 root 所有的**文件**(而非目录)形式创建,权限为除 root
238
251
  外一律拒绝,因此只有容器的默认(root)用户可以读取它;以其他 `uid`
@@ -267,8 +280,8 @@ UI 使用短名称。`secret_create` 的值由服务端用 `crypto/rand`
267
280
 
268
281
  ## 容器管理 UI
269
282
 
270
- 插件附带一个浏览器端,在 dsh **Settings → Plugins**
271
- 页面注册一个卡片。该卡片列出编排器创建的 guest
283
+ 插件附带一个浏览器端,把卡片注册到 **dsh-podman** 页面(侧边栏 **插件** 面板 →
284
+ **已安装**)。该页面列出编排器创建的 guest
272
285
  容器和已构建的镜像。没有容器的工作区会得到一个 **Create container**
273
286
  按钮,打开一个配置模态框——镜像、环境、挂载(project、tmpfs、volume 和
274
287
  secret)、PATH 附加项以及机密环境变量——而已有容器的工作区通过同一个模态框提供
@@ -279,23 +292,48 @@ read-only),显示为不可编辑的下拉框。容器行显示其环境和
279
292
  **Remove**、**Recreate**(相同镜像)和 **Recreate with
280
293
  image**。每个工作区行还提供 **移除 Pod**,它会移除该工作区的
281
294
  Pod、其所有容器以及编排器对应的记录(卷、机密和项目数据会保留);移除工作区的最后一个容器也会一并移除其
282
- Pod,因此不会留下空的 Pod。每次打开 Plugins
283
- 页面时卡片都会重新读取实时状态,其头部还有一个 **Reload this view**
295
+ Pod,因此不会留下空的 Pod。每次通过 **插件**
296
+ 面板打开该页面时都会重新读取实时状态,其底部还有一个 **Reload this view**
284
297
  按钮。镜像部分可以重建单个镜像或按依赖顺序**重建全部**;**Build image**
285
298
  打开一个弹窗,包含 image-id/base-image 表单和用于软件包列表的 chip
286
299
  输入框(输入名称并按空格/逗号,或粘贴列表,以添加可移除的
287
300
  chips)。卷和机密以独立的可展开行列出,每行都有自己的操作,**Create volume** /
288
301
  **Create secret**
289
- 打开弹窗表单(机密表单接受可选的长度;机密的值可以被覆盖,但绝不读取)。卡片操作是直接的控制调用,不受审批门控。
302
+ 打开弹窗表单(机密表单接受可选的长度;机密的值可以被覆盖,但绝不读取)。Podman
303
+ 页面操作是直接的控制调用,不受审批门控。
290
304
 
291
305
  **软件包缓存**区段会报告每个已配置构建缓存(`DSH_PODMAN_HOST_PACMAN_CACHE`、`DSH_PODMAN_HOST_APT_CACHE`、`DSH_PODMAN_HOST_APK_CACHE`)的大小,并提供两个清理操作:**保留最新版本**会移除每个软件包除最新版本之外的所有缓存文件(连同其签名),**全部移除**会清空缓存。两者都是安全的——缓存的软件包只会被重新下载——且都不会在镜像构建进行时运行。
292
306
 
307
+ ## Podman 终端
308
+
309
+ 插件自带一个右侧边栏的 **Podman 终端**标签页,与 dsh
310
+ 自带的终端标签页相互独立。可从右侧边栏的“新建标签页”指南中打开(卡片名为**新建终端**),或按
311
+ **Ctrl+`**;标签页以所运行的 shell 命名(`bash`、`sh`等)。插件的 bundle patch 会禁用 dsh 自带的终端界面,从而让出该快捷键(若重新启用,插件会回退到 **Ctrl+Shift+`**);agent
312
+ 的 `terminal`
313
+ 工具不受影响。它始终在会话所在的工作区中运行——每个工作区都有自己的侧边栏和终端——因此启动表单只需选择容器和
314
+ shell,既可在默认容器中运行,也可在命名容器中运行;若会话目录不属于任何已知工作区,表单会直接提示而不是猜测。harness
315
+ 自带的终端始终使用该工作区的默认容器。上次启动所使用的容器与 shell
316
+ 会记录在浏览器的本地存储中,只要仍然可用就会预先选中——容器已不存在时回退到默认容器,镜像不再提供该
317
+ shell 时回退到容器提供的第一个 shell。
318
+
319
+ shell 列表在**所选容器内部**探测:按候选名称在该容器的 PATH
320
+ 中查找(`command -v`),并与 `/etc/shells` 和 `$SHELL` 合并,因此通过 PATH
321
+ 追加项或挂载卷安装的 shell
322
+ 会出现,而镜像中不存在的则不会。列表按能力从强到弱排列(`zsh`、`bash`、`fish`……直到
323
+ `dash`、`ash`、`sh`),因此选择器会预选容器中最好的
324
+ shell。启动前还会再次校验所选 shell。
325
+
326
+ 终端由主机保留:切换标签页、关闭侧边栏或刷新页面都不会丢失 shell
327
+ 及其回滚缓冲,重新接入时会回放屏幕内容。关闭标签页后 shell
328
+ 仍会保留一段时间(直到主机回收);**重新连接**会在当前选择中启动一个新的
329
+ shell。关闭或重建容器会丢弃其终端,之后请重新连接。
330
+
293
331
  ## Podman 操作员模式
294
332
 
295
333
  插件附带一个名为 _Podman operator mode_(id `podman-ops`)的 **agent
296
- 预设**。每次加载时,它都会将预设(重新)写入 harness
297
- 的用户预设根目录(`~/.dsh/.agent-presets/podman-ops/`),覆盖任何本地副本,使发布的内容保持权威。它出现在会话的
298
- agent 预设选择器中,紧挨着内置预设。
334
+ 预设**。插件的 bundle patch 会把它声明为一行
335
+ `@deepseek-ai/dsh-agent-preset`,因此 harness
336
+ 的预设注册表会直接提供它。它出现在会话的 agent 预设选择器中,紧挨着内置预设。
299
337
 
300
338
  该预设将聚焦 Podman 的人格与内置任务工具(`ask_user_question`、`todo_write`)和
301
339
  `web_search`(web fetch 已禁用)组合在一起。它不挂载主机 shell、主机文件系统或
@@ -304,7 +342,7 @@ mode、jobs)。插件自身的工具是全局的,全部保持可用,分为
304
342
 
305
343
  - **直接:**
306
344
  `image_list`、`image_get`、`container_list`、`container_read`、`container_glob`、`container_grep`、`container_mount_list`、`volume_list`、`secret_list`、`secret_create`、`daemon_list`、`daemon_logs`、`daemon_stop`、`daemon_restart`、`container_start`(仅在传入
307
- `mounts` 时询问)。
345
+ `mounts` 或 `secretEnv` 时询问)。
308
346
  - **需审批**(通常的 `✱`
309
347
  工具):`image_build`、`image_rebuild`、`image_rebuild_all`、`image_remove`、`container_recreate`、`container_remove`、`container_mount_add`、`container_mount_remove`、`container_mount_update`、`container_path_set`、`container_path_add`、`container_path_remove`、`volume_remove`、`secret_remove`、`container_secret_add`、`container_secret_remove`。
310
348
  - **仅在此预设中需审批:**
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "dsh-podman",
4
+ "description": "Podman-backed execution for DeepSeek Harness (dsh)."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "dsh-podman",
4
+ "description": "为 DeepSeek Harness(dsh)提供基于 Podman 的容器执行环境。"
5
+ }
6
+ }