@exagone313/dsh-podman 0.2.0-rc.2

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 (165) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +41 -0
  3. package/README.zh.md +41 -0
  4. package/cordis.patch.yml +17 -0
  5. package/dist/approval-reasons.d.ts +129 -0
  6. package/dist/approval-reasons.js +253 -0
  7. package/dist/approval-reasons.test.d.ts +1 -0
  8. package/dist/approval-reasons.test.js +115 -0
  9. package/dist/approval.d.ts +29 -0
  10. package/dist/approval.js +412 -0
  11. package/dist/approval.test.d.ts +1 -0
  12. package/dist/approval.test.js +462 -0
  13. package/dist/card-route.d.ts +15 -0
  14. package/dist/card-route.js +478 -0
  15. package/dist/card-route.test.d.ts +1 -0
  16. package/dist/card-route.test.js +181 -0
  17. package/dist/card-test-support.d.ts +15 -0
  18. package/dist/card-test-support.js +160 -0
  19. package/dist/client/ContainerCard.d.ts +6 -0
  20. package/dist/client/ContainerCard.js +79 -0
  21. package/dist/client/card-client.d.ts +6 -0
  22. package/dist/client/card-client.js +47 -0
  23. package/dist/client/card-protocol.d.ts +101 -0
  24. package/dist/client/card-protocol.js +10 -0
  25. package/dist/client/container-card-caches.d.ts +10 -0
  26. package/dist/client/container-card-caches.js +31 -0
  27. package/dist/client/container-card-controller.d.ts +107 -0
  28. package/dist/client/container-card-controller.js +207 -0
  29. package/dist/client/container-card-create-modal.d.ts +24 -0
  30. package/dist/client/container-card-create-modal.js +109 -0
  31. package/dist/client/container-card-directory-styles.d.ts +5 -0
  32. package/dist/client/container-card-directory-styles.js +246 -0
  33. package/dist/client/container-card-directory.d.ts +12 -0
  34. package/dist/client/container-card-directory.js +144 -0
  35. package/dist/client/container-card-editors.d.ts +30 -0
  36. package/dist/client/container-card-editors.js +116 -0
  37. package/dist/client/container-card-images.d.ts +37 -0
  38. package/dist/client/container-card-images.js +35 -0
  39. package/dist/client/container-card-paths.d.ts +20 -0
  40. package/dist/client/container-card-paths.js +88 -0
  41. package/dist/client/container-card-row.d.ts +30 -0
  42. package/dist/client/container-card-row.js +54 -0
  43. package/dist/client/container-card-secrets.d.ts +21 -0
  44. package/dist/client/container-card-secrets.js +71 -0
  45. package/dist/client/container-card-shared.d.ts +55 -0
  46. package/dist/client/container-card-shared.js +152 -0
  47. package/dist/client/container-card-styles.d.ts +21 -0
  48. package/dist/client/container-card-styles.js +143 -0
  49. package/dist/client/container-card-volumes.d.ts +12 -0
  50. package/dist/client/container-card-volumes.js +37 -0
  51. package/dist/client/container-card-workspace.d.ts +31 -0
  52. package/dist/client/container-card-workspace.js +24 -0
  53. package/dist/client/directory-picker.d.ts +12 -0
  54. package/dist/client/directory-picker.js +30 -0
  55. package/dist/client/index.d.ts +5 -0
  56. package/dist/client/index.js +4419 -0
  57. package/dist/client/locales.d.ts +9 -0
  58. package/dist/client/locales.js +370 -0
  59. package/dist/client/read-only-approval.d.ts +8 -0
  60. package/dist/client/read-only-approval.js +63 -0
  61. package/dist/client/slot-contract.d.ts +12 -0
  62. package/dist/client/slot-contract.js +4 -0
  63. package/dist/client/terminal-styles.d.ts +5 -0
  64. package/dist/client/terminal-styles.js +31 -0
  65. package/dist/client/tool-views.d.ts +8 -0
  66. package/dist/client/tool-views.js +241 -0
  67. package/dist/containers.test.d.ts +1 -0
  68. package/dist/containers.test.js +443 -0
  69. package/dist/daemons.test.d.ts +1 -0
  70. package/dist/daemons.test.js +153 -0
  71. package/dist/fs-provider.d.ts +23 -0
  72. package/dist/fs-provider.js +184 -0
  73. package/dist/fs-provider.test.d.ts +1 -0
  74. package/dist/fs-provider.test.js +260 -0
  75. package/dist/generated/version.d.ts +2 -0
  76. package/dist/generated/version.js +6 -0
  77. package/dist/grpc/proto/dshctl/v1/control.proto +133 -0
  78. package/dist/grpc/proto/dshguest/v1/guest.proto +79 -0
  79. package/dist/grpc/runtime-client.d.ts +5 -0
  80. package/dist/grpc/runtime-client.js +43 -0
  81. package/dist/guest-rpc.d.ts +62 -0
  82. package/dist/guest-rpc.js +391 -0
  83. package/dist/images.test.d.ts +1 -0
  84. package/dist/images.test.js +79 -0
  85. package/dist/index.d.ts +22 -0
  86. package/dist/index.js +140 -0
  87. package/dist/misc.test.d.ts +1 -0
  88. package/dist/misc.test.js +141 -0
  89. package/dist/mount-enums.d.ts +22 -0
  90. package/dist/mount-enums.js +81 -0
  91. package/dist/mount-input.d.ts +14 -0
  92. package/dist/mount-input.js +64 -0
  93. package/dist/mounts.test.d.ts +1 -0
  94. package/dist/mounts.test.js +408 -0
  95. package/dist/output-reader.d.ts +34 -0
  96. package/dist/output-reader.js +87 -0
  97. package/dist/paths.test.d.ts +1 -0
  98. package/dist/paths.test.js +74 -0
  99. package/dist/preferences.d.ts +6 -0
  100. package/dist/preferences.js +27 -0
  101. package/dist/project-path.d.ts +6 -0
  102. package/dist/project-path.js +73 -0
  103. package/dist/project-path.test.d.ts +1 -0
  104. package/dist/project-path.test.js +52 -0
  105. package/dist/prompts.d.ts +13 -0
  106. package/dist/prompts.js +149 -0
  107. package/dist/public.d.ts +4 -0
  108. package/dist/public.js +63 -0
  109. package/dist/read-only-shell.d.ts +14 -0
  110. package/dist/read-only-shell.js +150 -0
  111. package/dist/read-only-shell.test.d.ts +1 -0
  112. package/dist/read-only-shell.test.js +127 -0
  113. package/dist/secrets.test.d.ts +1 -0
  114. package/dist/secrets.test.js +181 -0
  115. package/dist/settings-commands.test.d.ts +1 -0
  116. package/dist/settings-commands.test.js +549 -0
  117. package/dist/settings-create.test.d.ts +1 -0
  118. package/dist/settings-create.test.js +394 -0
  119. package/dist/settings-mounts.test.d.ts +1 -0
  120. package/dist/settings-mounts.test.js +467 -0
  121. package/dist/settings-paths.test.d.ts +1 -0
  122. package/dist/settings-paths.test.js +65 -0
  123. package/dist/settings-schema.d.ts +14 -0
  124. package/dist/settings-schema.js +14 -0
  125. package/dist/settings-workspaces.test.d.ts +1 -0
  126. package/dist/settings-workspaces.test.js +265 -0
  127. package/dist/spill-store.d.ts +17 -0
  128. package/dist/spill-store.js +54 -0
  129. package/dist/spill-store.test.d.ts +1 -0
  130. package/dist/spill-store.test.js +59 -0
  131. package/dist/subprocess.d.ts +9 -0
  132. package/dist/subprocess.js +369 -0
  133. package/dist/subprocess.test.d.ts +1 -0
  134. package/dist/subprocess.test.js +234 -0
  135. package/dist/test-support.d.ts +328 -0
  136. package/dist/test-support.js +437 -0
  137. package/dist/tool-defs.d.ts +26 -0
  138. package/dist/tool-defs.js +188 -0
  139. package/dist/tool-handlers.d.ts +2 -0
  140. package/dist/tool-handlers.js +546 -0
  141. package/dist/tool-params.d.ts +803 -0
  142. package/dist/tool-params.js +494 -0
  143. package/dist/tool-schemas.d.ts +2 -0
  144. package/dist/tool-schemas.js +5 -0
  145. package/dist/tool-views.d.ts +2 -0
  146. package/dist/tool-views.js +56 -0
  147. package/dist/views.test.d.ts +1 -0
  148. package/dist/views.test.js +23 -0
  149. package/dist/volumes.test.d.ts +1 -0
  150. package/dist/volumes.test.js +40 -0
  151. package/dist/workspace-binding.d.ts +40 -0
  152. package/dist/workspace-binding.js +275 -0
  153. package/dist/workspace-binding.test.d.ts +1 -0
  154. package/dist/workspace-binding.test.js +337 -0
  155. package/docs/architecture.md +173 -0
  156. package/docs/architecture.zh.md +129 -0
  157. package/docs/configuration.md +160 -0
  158. package/docs/configuration.zh.md +147 -0
  159. package/docs/development.md +142 -0
  160. package/docs/development.zh.md +135 -0
  161. package/docs/install-dsh-and-dsh-podman.md +165 -0
  162. package/docs/install-dsh-and-dsh-podman.zh.md +145 -0
  163. package/docs/usage.md +393 -0
  164. package/docs/usage.zh.md +315 -0
  165. package/package.json +119 -0
@@ -0,0 +1,142 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Elouan Martinet <exa@elou.world>
3
+
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+ # Development
8
+
9
+ This page is for **contributors** building the plugin from this repository.
10
+
11
+ ## Repository layout
12
+
13
+ - `src/` — the Cordis plugin (host half + browser client).
14
+ - `cmd/dsh-podman-orchestrator/` and `cmd/dsh-podman-guest-agent/` — the two Go
15
+ binaries.
16
+ - `internal/` — Go implementation of the orchestrator, guest agent, and protobuf
17
+ bindings.
18
+ - `proto/` — the gRPC definitions.
19
+ - `.github/workflows/` — CI and release automation.
20
+
21
+ ## Building
22
+
23
+ Prerequisites: Go 1.27, Node ≥ 22, pnpm 12, and (for the browser half) the
24
+ `@deepseek-ai/dsh-client-*` packages published on npm.
25
+
26
+ ```sh
27
+ pnpm install
28
+ pnpm run build # tsc host + tsc client -> dist/, copies proto/ -> dist/grpc/proto/
29
+ ```
30
+
31
+ The Go build tags skip the btrfs and devicemapper storage drivers, which need
32
+ host C headers; `make` applies the same tags automatically.
33
+
34
+ The `Makefile` wraps the common workflows:
35
+
36
+ ```sh
37
+ make build-go # build both Go binaries into bin/<os>-<arch>/
38
+ make build # build-go + pnpm-build
39
+ make vet # go vet with the build tags
40
+ make test-go # go test with the build tags
41
+ make test # test-go + pnpm test (JS tests, which run against dist/)
42
+ make download-licenses # generate LICENSE.pkg from the project and third-party Go licenses
43
+ make image # build the orchestrator and guest-agent container images
44
+ ```
45
+
46
+ `make image` depends on `LICENSE.pkg`: the `download-licenses` target runs the
47
+ Go collector in `scripts/download-licenses`, which shells out to
48
+ `go-licenses save` and gathers the project's MIT license plus every third-party
49
+ Go license and Apache `NOTICE` into `LICENSE.pkg`. That file is gitignored
50
+ (never committed) and is baked into the orchestrator and guest-agent images at
51
+ `/usr/share/licenses/dsh-podman/LICENSE`; because workspace containers mount the
52
+ guest-agent image, it also rides along into every workspace container.
53
+
54
+ `pnpm test` runs `node --test dist/*.test.js`, so it requires `pnpm build` to
55
+ have run first (the `test` target handles this).
56
+
57
+ ## Protobuf
58
+
59
+ The `.proto` sources live in `proto/`; the generated Go bindings in
60
+ `internal/genproto/` are committed. After changing a `.proto`, regenerate them
61
+ with Buf (`buf generate`), which must be installed separately (it has no `make`
62
+ target) — pin it with `go install github.com/bufbuild/buf/cmd/buf@v1.73.0`.
63
+ Commit the `.proto` change together with the regenerated Go bindings.
64
+
65
+ The JS side loads the raw `.proto` files at runtime via `@grpc/proto-loader`
66
+ (copied to `dist/grpc/proto/` at build time); no TypeScript bindings are
67
+ generated. Optionally validate the schema with `buf lint` and `buf breaking`.
68
+
69
+ ## Install development builds
70
+
71
+ ### Build
72
+
73
+ ```bash
74
+ make # builds plugin and go binaries
75
+ make image # build images
76
+ ```
77
+
78
+ ### Recreate containers
79
+
80
+ ```bash
81
+ systemctl --user restart dsh dsh-podman-orchestrator
82
+ ```
83
+
84
+ ### Update plugin
85
+
86
+ ```bash
87
+ npm pack
88
+ v="$(jq -r .version package.json)"
89
+ podman cp ./exagone313-dsh-podman-"${v}".tgz dsh:/tmp/
90
+ podman exec -it dsh dsh plugin --profile web remove @exagone313/dsh-podman # necessary, to force reinstall if the same version
91
+ podman exec -it dsh dsh plugin --profile web add /tmp/exagone313-dsh-podman-"${v}".tgz --allow-build=protobufjs
92
+ systemctl --user restart dsh
93
+ ```
94
+
95
+ ## Continuous integration
96
+
97
+ CI (`.github/workflows/ci.yml`) runs on every branch push and pull request:
98
+
99
+ - **actions-lint** — zizmor scans the workflows for insecure practices.
100
+ - **go** — build, vet, tests, and govulncheck (Go vulnerabilities). Unfixed
101
+ findings don't fail the job; fixable ones do.
102
+ - **js** — install, typecheck, build, tests, and `pnpm audit`.
103
+ - **images** — builds the orchestrator and guest-agent images (runs only after
104
+ the test jobs pass).
105
+ - **trivy** — filesystem vulnerability scan (unfixed ignored) and container
106
+ misconfiguration scan (DS-0002 excluded via `.trivyignore.yaml`).
107
+
108
+ All third-party actions are pinned to full commit SHAs and checked by zizmor.
109
+
110
+ ## Releasing
111
+
112
+ Releases are triggered by pushing a **bare semver tag** (`x.y.z`, no `v`;
113
+ pre-releases like `1.0.0-rc.1` also work). The release workflow
114
+ (`.github/workflows/release.yml`):
115
+
116
+ 1. Runs the tests, then builds both binaries for `linux/amd64` and
117
+ `linux/arm64`.
118
+ 2. Pushes the **orchestrator** and **guest-agent** images to GHCR
119
+ (`ghcr.io/exagone313/dsh-podman/{orchestrator,guest-agent}`), tagged with the
120
+ version plus `latest` for stable releases (pre-releases never get `latest`).
121
+ 3. Publishes the plugin to **npm** (`@exagone313/dsh-podman`) with provenance;
122
+ pre-releases are published under the `next` dist-tag.
123
+ 4. Creates a **GitHub release** with auto-generated notes and attaches the
124
+ binaries and the npm tarball.
125
+
126
+ The tag must match `package.json`'s version — the workflow fails otherwise — so
127
+ bump both with the version script:
128
+
129
+ ```sh
130
+ pnpm bump-version 0.1.1 # add --dry-run to validate only
131
+ git push origin master 0.1.1
132
+ ```
133
+
134
+ `scripts/bump-version.mjs` checks that the version is a semver release or
135
+ pre-release that increases the current one, writes it to `package.json`, commits
136
+ `chore: bump version to X`, and creates the tag; it pushes nothing, and it
137
+ requires the `master` branch with a clean working tree. The tag is also what the
138
+ built plugin and binaries report, since `scripts/generate-version.mjs` derives
139
+ the embedded version from `git describe --tags`. Pre-releases (`1.0.0-rc.1`) are
140
+ bumped the same way.
141
+
142
+ The `NPM_TOKEN` secret must be configured on the repository for the npm step.
@@ -0,0 +1,135 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Elouan Martinet <exa@elou.world>
3
+
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+ # 开发
8
+
9
+ 本页面向从本仓库构建插件的**贡献者**。
10
+
11
+ ## 仓库结构
12
+
13
+ - `src/` — Cordis 插件(宿主端 + 浏览器客户端)。
14
+ - `cmd/dsh-podman-orchestrator/` 和 `cmd/dsh-podman-guest-agent/` — 两个 Go
15
+ 二进制文件。
16
+ - `internal/` — orchestrator、guest agent 和 protobuf 绑定的 Go 实现。
17
+ - `proto/` — gRPC 定义。
18
+ - `.github/workflows/` — CI 和发布自动化。
19
+
20
+ ## 构建
21
+
22
+ 前置要求:Go 1.27、Node ≥ 22、pnpm 12,以及(浏览器端所需的)发布在 npm 上的
23
+ `@deepseek-ai/dsh-client-*` 包。
24
+
25
+ ```sh
26
+ pnpm install
27
+ pnpm run build # tsc host + tsc client -> dist/, copies proto/ -> dist/grpc/proto/
28
+ ```
29
+
30
+ Go 构建标签会跳过 btrfs 和 devicemapper 存储驱动,它们需要宿主机的 C
31
+ 头文件;`make` 会自动应用相同的标签。
32
+
33
+ `Makefile` 封装了常见的工作流:
34
+
35
+ ```sh
36
+ make build-go # build both Go binaries into bin/<os>-<arch>/
37
+ make build # build-go + pnpm-build
38
+ make vet # go vet with the build tags
39
+ make test-go # go test with the build tags
40
+ make test # test-go + pnpm test (JS tests, which run against dist/)
41
+ make download-licenses # generate LICENSE.pkg from the project and third-party Go licenses
42
+ make image # build the orchestrator and guest-agent container images
43
+ ```
44
+
45
+ `make image` 依赖 `LICENSE.pkg`:`download-licenses` 目标会运行
46
+ `scripts/download-licenses` 中的 Go 收集器,它调用 `go-licenses save` 并将项目的
47
+ MIT 许可证以及所有第三方 Go 许可证和 Apache `NOTICE` 汇总到 `LICENSE.pkg`
48
+ 中。该文件被 gitignore (从不提交),并被烘焙进 orchestrator 和 guest-agent
49
+ 镜像,位于 `/usr/share/licenses/dsh-podman/LICENSE`;由于工作区容器会挂载
50
+ guest-agent 镜像,因此它也会随之进入每个工作区容器。
51
+
52
+ `pnpm test` 运行 `node --test dist/*.test.js`,因此它要求先运行 `pnpm build`
53
+ (`test` 目标会处理这一点)。
54
+
55
+ ## Protobuf
56
+
57
+ `.proto` 源文件位于 `proto/`;生成的 Go 绑定位于
58
+ `internal/genproto/`,会被提交。修改 `.proto` 后,需要使用单独安装的
59
+ Buf(`buf generate`)重新生成(没有对应的 `make` 目标)——请用
60
+ `go install github.com/bufbuild/buf/cmd/buf@v1.73.0` 固定版本。请将 `.proto`
61
+ 改动与重新生成的 Go 绑定一起提交。
62
+
63
+ JS 端在运行时通过 `@grpc/proto-loader` 加载原始 `.proto` 文件(构建时复制到
64
+ `dist/grpc/proto/`);不生成 TypeScript 绑定。也可以使用 `buf lint` 和
65
+ `buf breaking` 校验 schema。
66
+
67
+ ## 安装开发构建
68
+
69
+ ### 构建
70
+
71
+ ```bash
72
+ make # builds plugin and go binaries
73
+ make image # build images
74
+ ```
75
+
76
+ ### 重建容器
77
+
78
+ ```bash
79
+ systemctl --user restart dsh dsh-podman-orchestrator
80
+ ```
81
+
82
+ ### 更新插件
83
+
84
+ ```bash
85
+ npm pack
86
+ v="$(jq -r .version package.json)"
87
+ podman cp ./exagone313-dsh-podman-"${v}".tgz dsh:/tmp/
88
+ podman exec -it dsh dsh plugin --profile web remove @exagone313/dsh-podman # necessary, to force reinstall if the same version
89
+ podman exec -it dsh dsh plugin --profile web add /tmp/exagone313-dsh-podman-"${v}".tgz --allow-build=protobufjs
90
+ systemctl --user restart dsh
91
+ ```
92
+
93
+ ## 持续集成
94
+
95
+ CI(`.github/workflows/ci.yml`)在每次分支推送和拉取请求时运行:
96
+
97
+ - **actions-lint** — zizmor 扫描工作流是否存在不安全实践。
98
+ - **go** — 构建、vet、测试和 govulncheck(Go 漏洞)。未修复的
99
+ 发现不会导致任务失败;可修复的会导致失败。
100
+ - **js** — 安装、类型检查、构建、测试和 `pnpm audit`。
101
+ - **images** — 构建 orchestrator 和 guest-agent 镜像(仅在测试任务通过后运行)。
102
+ - **trivy** — 文件系统漏洞扫描(未修复的被忽略)和容器 错误配置扫描(DS-0002
103
+ 通过 `.trivyignore.yaml` 排除)。
104
+
105
+ 所有第三方 actions 都锁定到完整的提交 SHA,并由 zizmor 检查。
106
+
107
+ ## 发布
108
+
109
+ 发布由推送**纯 Semver 标签**(`x.y.z`,不带 `v`; 像 `1.0.0-rc.1`
110
+ 这样的预发布同样有效)触发。发布工作流 (`.github/workflows/release.yml`):
111
+
112
+ 1. 运行测试,然后为 `linux/amd64` 和 `linux/arm64` 构建两个二进制文件。
113
+ 2. 将 **orchestrator** 和 **guest-agent** 镜像推送到 GHCR
114
+ (`ghcr.io/exagone313/dsh-podman/{orchestrator,guest-agent}`),并打上
115
+ 版本号以及稳定版的 `latest` 标签(预发布永远不会获得 `latest`)。
116
+ 3. 将插件发布到 **npm**(`@exagone313/dsh-podman`),附带来源证明; 预发布在
117
+ `next` dist-tag 下发布。
118
+ 4. 创建带有自动生成说明的 **GitHub release**,并附上 二进制文件和 npm tarball。
119
+
120
+ 标签必须与 `package.json`
121
+ 中的版本一致——否则工作流会失败——因此请用版本脚本同时更新两者:
122
+
123
+ ```sh
124
+ pnpm bump-version 0.1.1 # 加上 --dry-run 则仅校验
125
+ git push origin master 0.1.1
126
+ ```
127
+
128
+ `scripts/bump-version.mjs` 会检查版本是否为递增的 Semver
129
+ 正式版或预发布版,将其写入 `package.json`,提交
130
+ `chore: bump version to X`,并创建标签;它不会推送,且要求处于 `master`
131
+ 分支且工作区干净。标签同时也是构建出的插件与二进制文件所报告的版本,因为
132
+ `scripts/generate-version.mjs` 从 `git describe --tags`
133
+ 推导嵌入的版本。预发布版(`1.0.0-rc.1`)也用同样的方式递增。
134
+
135
+ npm 步骤要求仓库配置 `NPM_TOKEN` 密钥。
@@ -0,0 +1,165 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Elouan Martinet <exa@elou.world>
3
+
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+ # Install DeepSeek Harness & dsh-podman with rootless Podman
8
+
9
+ ## Goals
10
+
11
+ The goal of this guide is to install:
12
+
13
+ - [DeepSeek Harness](https://deepseek.com/harness), referred to later as _dsh_
14
+ - the dsh-podman plugin in dsh, which replaces host filesystem and shell access
15
+ - the dsh-podman orchestrator, a separate Podman container that integrates with
16
+ Podman
17
+
18
+ Having the dsh plugin and the orchestrator running as separate containers is an
19
+ important part of the security design of dsh-podman: dsh itself doesn't have
20
+ direct access to Podman, only the orchestrator does, with limitations. dsh
21
+ shouldn't be able to escalate privileges using this path, as the capabilities
22
+ provided to dsh are constrained:
23
+
24
+ - the names of pods, containers, volumes and secrets are prefixed with
25
+ `dsh-podman-`
26
+ - mounted paths are limited to bind-mounted project directories and managed
27
+ volumes
28
+ - containers are dealt with separately for each dsh workspace.
29
+
30
+ Nevertheless, it is recommended to run dsh as a dedicated user instead of your
31
+ main user.
32
+
33
+ Note that, for now, network access is not constrained, but support for this
34
+ could be added in the future.
35
+
36
+ ## Terminology
37
+
38
+ - **dsh**: DeepSeek Harness, a plugin-oriented AI agent harness developed by
39
+ DeepSeek
40
+ - **dsh-podman**: this project
41
+ - **dsh-podman plugin**: the plugin installed in dsh, which provides tools to
42
+ agents and a UI for manual settings, and connects to the orchestrator;
43
+ referred to later as _plugin_
44
+ - **dsh-podman orchestrator**: the daemon that receives connections from the
45
+ dsh-podman plugin, has access to the Podman socket and manages containers and
46
+ other resources; it runs in a container; referred to later as _orchestrator_
47
+ - **Podman socket**: while the Podman client can be used without a daemon, it is
48
+ still possible to enable management through a socket, which is required by the
49
+ orchestrator to work as if it were running on the host system
50
+ - **guest container**: a container created by the dsh-podman orchestrator, in
51
+ relation to a dsh workspace
52
+ - **dsh workspace**: in dsh, a project uses the name _workspace_, with its own
53
+ dedicated directory
54
+
55
+ ## Requirements
56
+
57
+ - A user to run dsh as (not root)
58
+ - A Linux distribution powered by systemd
59
+ - Podman 5 or later; Podman 6 is recommended
60
+ - A systemd session as your dsh user (**`sudo -iu` will not work**):
61
+ - by using machinectl (recommended; on some distributions, this command is
62
+ part of the `systemd-container` package; it needs to be run as root or as
63
+ part of the _wheel_ group):
64
+ ```bash
65
+ machinectl shell --uid=your-username
66
+ ```
67
+ - by connecting via SSH
68
+ - by connecting on a tty
69
+
70
+ ## Recommendations
71
+
72
+ - If you want to start dsh at boot,
73
+ [enable _user lingering_ for your user](https://www.freedesktop.org/software/systemd/man/loginctl.html#enable-linger%20USER%E2%80%A6)
74
+ as root:
75
+ ```bash
76
+ loginctl enable-linger your-username
77
+ ```
78
+ - Ensure that Podman is working correctly as your dsh user (⚠️ the first command
79
+ may stop existing containers!):
80
+ ```bash
81
+ podman system migrate
82
+ podman run --rm quay.io/podman/hello
83
+ podman rmi quay.io/podman/hello
84
+ ```
85
+
86
+ ## Preparation
87
+
88
+ - You need to choose a project directory. This directory will be mounted
89
+ read-only in dsh (necessary for the integrated project manager) and read-write
90
+ in guest containers. In this guide we will use `${HOME}/project`
91
+ (`%h/project`) but you are free to choose another path, as long as your user
92
+ has read-write access to it.
93
+ - Create a project inside the chosen directory. This will be useful to create a
94
+ workspace in dsh to validate the setup.
95
+
96
+ ## Installation
97
+
98
+ ### dsh setup
99
+
100
+ This installation uses
101
+ [Podman Quadlet](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html),
102
+ which adds Podman integration into systemd.
103
+
104
+ 1. Create the Quadlet directory for your user:
105
+ ```bash
106
+ mkdir -p ~/.config/containers/systemd
107
+ ```
108
+ 2. Copy the files [dsh.container](../quadlet/dsh.container) and
109
+ [dsh-podman-orchestrator.container](../quadlet/dsh-podman-orchestrator.container)
110
+ to `~/.config/containers/systemd/`.
111
+ - Adapt the files to your desired project directory if you wish to change it.
112
+ 3. Reload systemd session configuration:
113
+ ```bash
114
+ systemctl --user daemon-reload
115
+ ```
116
+ 4. Check if there are errors in the configuration:
117
+ ```bash
118
+ journalctl --user -e
119
+ ```
120
+ 5. Start dsh and dsh-podman-orchestrator:
121
+ ```bash
122
+ systemctl --user start dsh dsh-podman-orchestrator
123
+ ```
124
+ 6. Check if there are startup errors from either container:
125
+ ```bash
126
+ journalctl --user -eu dsh
127
+ ```
128
+ ```bash
129
+ journalctl --user -eu dsh-podman-orchestrator
130
+ ```
131
+ 7. View the dsh container logs:
132
+ ```bash
133
+ podman logs dsh
134
+ ```
135
+ 8. Visit the given URL in the form `http://127.0.0.1:3080/?token=xxx` to access
136
+ dsh.
137
+ 9. Once your web browser has saved this token, you'll be able to access dsh with
138
+ the URL [http://127.0.0.1:3080/](http://127.0.0.1:3080/).
139
+
140
+ ### dsh-podman plugin installation
141
+
142
+ 1. Run this command to install the dsh-podman plugin:
143
+ ```bash
144
+ podman exec dsh dsh plugin --profile web add @exagone313/dsh-podman --allow-build=protobufjs
145
+ ```
146
+ 2. Restart dsh to complete the installation:
147
+ ```bash
148
+ systemctl --user restart dsh
149
+ ```
150
+
151
+ ## Verification
152
+
153
+ - Open **Settings → Plugins → dsh-podman**: the card should list the base images
154
+ and, for a workspace, offer to create its default container.
155
+ - In a dsh session, run a shell command. It should execute inside a Podman
156
+ container for the current workspace (the plugin auto-creates the workspace's
157
+ default container on first use).
158
+
159
+ ## Enable daily auto-updates (optional)
160
+
161
+ This requires enabling lingering for your user.
162
+
163
+ ```bash
164
+ systemctl --user enable --now podman-auto-update.timer
165
+ ```
@@ -0,0 +1,145 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Elouan Martinet <exa@elou.world>
3
+
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+ # 使用 rootless Podman 安装 DeepSeek Harness 与 dsh-podman
8
+
9
+ ## 目标
10
+
11
+ 本指南的目标是安装:
12
+
13
+ - [DeepSeek Harness](https://deepseek.com/harness),下文简称 _dsh_
14
+ - dsh 中的 dsh-podman 插件,它取代了宿主的文件系统和 shell 访问
15
+ - dsh-podman 编排器,一个与 Podman 集成的独立 Podman 容器
16
+
17
+ 将 dsh 插件和编排器作为独立的容器运行,是 dsh-podman 安全设计的重要一环: dsh
18
+ 本身不能直接访问 Podman,只有编排器可以,并且受到限制。dsh
19
+ 不应能通过这条路径提权,因为提供给 dsh 的权限能力是受限的:
20
+
21
+ - pod、容器、卷和 secret 的名称都以 `dsh-podman-` 为前缀
22
+ - 挂载路径仅限于绑定挂载的项目目录和受管理的卷
23
+ - 每个 dsh 工作区分别管理各自的容器。
24
+
25
+ 尽管如此,仍建议使用专用用户运行 dsh,而不是你的主用户。
26
+
27
+ 请注意,目前网络访问不受限制,但未来可能会添加对此的支持。
28
+
29
+ ## 术语
30
+
31
+ - **dsh**:DeepSeek Harness,由 DeepSeek 开发的面向插件的 AI agent harness
32
+ - **dsh-podman**:本项目
33
+ - **dsh-podman 插件**:安装在 dsh 中的插件,它为 agent 提供工具、提供手动设置
34
+ UI,并连接编排器;下文简称 _plugin_
35
+ - **dsh-podman 编排器**:接收来自 dsh-podman 插件连接的守护进程,可访问 Podman
36
+ 套接字并管理容器和其他资源;它在容器中运行;下文简称 _orchestrator_
37
+ - **Podman 套接字**:虽然 Podman
38
+ 客户端可以在没有守护进程的情况下使用,但仍然可以通过套接字启用管理,这是编排器以仿佛在主机系统上运行的方式工作所必需的
39
+ - **guest 容器**:由 dsh-podman 编排器创建的容器,与 dsh 工作区相关联
40
+ - **dsh 工作区**:在 dsh 中,项目使用 _workspace_ 这一名称,并有自己的专用目录
41
+
42
+ ## 要求
43
+
44
+ - 一个用于运行 dsh 的用户(不能是 root)
45
+ - 基于 systemd 的 Linux 发行版
46
+ - Podman 5 或更高版本;推荐使用 Podman 6
47
+ - 以你的 dsh 用户身份存在的 systemd 会话(**`sudo -iu` 无法工作**):
48
+ - 通过 machinectl(推荐;在某些发行版上,此命令属于 `systemd-container`
49
+ 包;需要以 root 身份或作为 _wheel_ 组的成员运行):
50
+ ```bash
51
+ machinectl shell --uid=your-username
52
+ ```
53
+ - 通过 SSH 连接
54
+ - 通过 tty 连接
55
+
56
+ ## 建议
57
+
58
+ - 如果你想在开机时启动 dsh,请以 root 身份
59
+ [为你的用户启用 _user lingering_(常驻)](https://www.freedesktop.org/software/systemd/man/loginctl.html#enable-linger%20USER%E2%80%A6):
60
+ ```bash
61
+ loginctl enable-linger your-username
62
+ ```
63
+ - 确保 Podman 在你的 dsh 用户下能正常工作(⚠️ 第一条命令可能会停止现有容器!):
64
+ ```bash
65
+ podman system migrate
66
+ podman run --rm quay.io/podman/hello
67
+ podman rmi quay.io/podman/hello
68
+ ```
69
+
70
+ ## 准备工作
71
+
72
+ - 你需要选择一个项目目录。该目录在 dsh
73
+ 中以只读方式挂载(对于内置的项目管理器是必需的),在 guest
74
+ 容器中以读写方式挂载。在本指南中,我们将使用
75
+ `${HOME}/project`(`%h/project`),但你可以自由选择其他路径,只要你的用户对该路径具有读写访问权限即可。
76
+ - 在所选目录中创建一个项目。这将有助于在 dsh 中创建工作区以验证安装是否成功。
77
+
78
+ ## 安装
79
+
80
+ ### dsh 配置
81
+
82
+ 本次安装使用
83
+ [Podman Quadlet](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html),
84
+ 它为 systemd 增加了 Podman 集成。
85
+
86
+ 1. 为你的用户创建 Quadlet 目录:
87
+ ```bash
88
+ mkdir -p ~/.config/containers/systemd
89
+ ```
90
+ 2. 将文件 [dsh.container](../quadlet/dsh.container) 和
91
+ [dsh-podman-orchestrator.container](../quadlet/dsh-podman-orchestrator.container)
92
+ 复制到 `~/.config/containers/systemd/`。
93
+ - 如果你希望更改项目目录,可相应调整这些文件。
94
+ 3. 重新加载 systemd 会话配置:
95
+ ```bash
96
+ systemctl --user daemon-reload
97
+ ```
98
+ 4. 检查配置中是否有错误:
99
+ ```bash
100
+ journalctl --user -e
101
+ ```
102
+ 5. 启动 dsh 和 dsh-podman-orchestrator:
103
+ ```bash
104
+ systemctl --user start dsh dsh-podman-orchestrator
105
+ ```
106
+ 6. 检查任一容器是否有启动错误:
107
+ ```bash
108
+ journalctl --user -eu dsh
109
+ ```
110
+ ```bash
111
+ journalctl --user -eu dsh-podman-orchestrator
112
+ ```
113
+ 7. 查看 dsh 容器日志:
114
+ ```bash
115
+ podman logs dsh
116
+ ```
117
+ 8. 访问形如 `http://127.0.0.1:3080/?token=xxx` 的给定 URL 以使用 dsh。
118
+ 9. 浏览器保存该令牌后,即可通过 [http://127.0.0.1:3080/](http://127.0.0.1:3080/)
119
+ 访问 dsh。
120
+
121
+ ### dsh-podman 插件安装
122
+
123
+ 1. 运行以下命令安装 dsh-podman 插件:
124
+ ```bash
125
+ podman exec dsh dsh plugin --profile web add @exagone313/dsh-podman --allow-build=protobufjs
126
+ ```
127
+ 2. 重启 dsh 以完成安装:
128
+ ```bash
129
+ systemctl --user restart dsh
130
+ ```
131
+
132
+ ## 验证
133
+
134
+ - 打开 **Settings → Plugins →
135
+ dsh-podman**:卡片应列出基础镜像,并针对工作区提供创建其默认容器的选项。
136
+ - 在 dsh 会话中运行一条 shell 命令。它应在当前工作区的 Podman
137
+ 容器内执行(插件会在首次使用时自动创建工作区的默认容器)。
138
+
139
+ ## 启用每日自动更新(可选)
140
+
141
+ 这需要为你的用户启用 lingering。
142
+
143
+ ```bash
144
+ systemctl --user enable --now podman-auto-update.timer
145
+ ```