dsh-wsl-tool 1.8.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/PUBLISHING.md ADDED
@@ -0,0 +1,161 @@
1
+ # Publishing
2
+
3
+ Maintainer notes for releasing this plugin. Four channels carry the same commit
4
+ and they are not interchangeable.
5
+
6
+ | Channel | What it is | What ships it |
7
+ |---|---|---|
8
+ | GitHub Release asset | what the plugin market installs from | `.github/workflows/release.yml`, on a `v*` tag |
9
+ | npm | the package `dsh-wsl-tool` | the same workflow, as its last step |
10
+ | Catalog entry | the listing line and the install command the market shows | a PR to `awesome-dsh-plugin/awesome-dsh-plugin` |
11
+ | Your working profile | the copy DSH actually loads | `npm run sync`, then a DSH restart |
12
+
13
+ ## The name split is deliberate
14
+
15
+ The npm package is **`dsh-wsl-tool`**, not `dsh-wsl`. The registry answers
16
+
17
+ ```
18
+ 403 Forbidden - PUT https://registry.npmjs.org/dsh-wsl -
19
+ Package name too similar to existing package is-wsl
20
+ ```
21
+
22
+ for the repository name. A name policy is not a permission problem: no token, no
23
+ 2FA bypass, and no scope changes it, and the name stays unclaimable. The
24
+ repository, the plugin (`tool-wsl`), and the market listing keep the `dsh-wsl`
25
+ name.
26
+
27
+ Nothing else depends on that name, because `cordis.patch.yml` names its entry by
28
+ **relative path**:
29
+
30
+ ```yaml
31
+ - insert:
32
+ - id: tool-wsl
33
+ name: './index.js'
34
+ ```
35
+
36
+ DSH anchors a relative `name:` beside the patch file that declared it
37
+ (`anchorInsertedPluginNames` in `@deepseek-ai/dsh-app-boot`), so this row loads
38
+ this bundle's own `index.js` whatever the install folder is called —
39
+ `node_modules/dsh-wsl-tool` from npm, `node_modules/dsh-wsl` in a local `file:`
40
+ profile. A bare package name would resolve in only one of those layouts, and
41
+ would silently couple this file to the registry name. `test/smoke.mjs` asserts
42
+ both that the entry stays relative and that it resolves.
43
+
44
+ ## Release checklist
45
+
46
+ 1. Green locally:
47
+
48
+ ```sh
49
+ npm test # shim backend, real WSL
50
+ DSH_SUBPROCESS_LOCAL=/path/to/dsh/node_modules npm run test:real
51
+ ```
52
+
53
+ 2. Bump, sync, commit, tag, push:
54
+
55
+ ```sh
56
+ npm version <x.y.z> --no-git-tag-version
57
+ npm run sync # into the profile copy DSH loads
58
+ git add -A && git commit -m "..."
59
+ git tag -a v<x.y.z> -m "..."
60
+ git push origin main && git push origin v<x.y.z>
61
+ ```
62
+
63
+ `npm run sync` defaults to
64
+ `%USERPROFILE%/.dsh/profiles/web/node_modules/dsh-wsl` — the folder the
65
+ profile's dependency key created, which need not match the npm name. Pass a
66
+ path to target another profile. Restart DSH afterwards: the plugin is imported
67
+ once at load.
68
+
69
+ 3. The tag runs the pipeline. The order is deliberate — the release asset goes
70
+ **first** because it is the market's critical path, then npm, so a failing npm
71
+ publish fails the run loudly without withholding the release.
72
+
73
+ The build step asks `npm pack --silent` for the tarball name (it follows
74
+ `package.json`, so it is `dsh-wsl-tool-<version>.tgz`) and copies it to
75
+ `dsh-wsl.tgz`, which is the fixed name the catalog's URL points at. Never
76
+ rename that copy: the market install breaks the moment the asset is not called
77
+ `dsh-wsl.tgz`, and `--latest` is what keeps `releases/latest` resolving to it.
78
+
79
+ 4. Verify each channel.
80
+
81
+ **CI** — a check annotation is readable anonymously, unlike the job log:
82
+
83
+ ```sh
84
+ curl -s "https://api.github.com/repos/XINY11451/dsh-wsl/actions/runs?per_page=5"
85
+ curl -s "https://api.github.com/repos/XINY11451/dsh-wsl/check-runs/<id>/annotations"
86
+ ```
87
+
88
+ A successful publish leaves `published <version> to npm`; a failure leaves
89
+ `npm publish failed: <the npm error lines>`, which is why the workflow turns
90
+ npm's stderr into `::error::` instead of only printing it.
91
+
92
+ **npm**:
93
+
94
+ ```sh
95
+ curl -s https://registry.npmjs.org/dsh-wsl-tool # dist-tags.latest
96
+ npm view dsh-wsl-tool version --registry https://registry.npmjs.org
97
+ ```
98
+
99
+ Fetching `dist.tarball` and unpacking it is the honest check — it proves the
100
+ artifact, not just the metadata. Scripted requests to `npmjs.com`'s HTML hit a
101
+ Cloudflare challenge; the registry API is the source of truth.
102
+
103
+ **Market asset** (this is what users install, and it is independent of npm):
104
+
105
+ ```sh
106
+ curl -sL -o /tmp/a.tgz https://github.com/XINY11451/dsh-wsl/releases/latest/download/dsh-wsl.tgz
107
+ tar -xzOf /tmp/a.tgz package/package.json | grep '"version"'
108
+ ```
109
+
110
+ **Catalog**: the catalog's generated data is at
111
+ <https://awesome-dsh-plugin.com/plugins.json> — look up `dsh-wsl` and read
112
+ `npm`, `version`, `downloads`, `install`, `tarball`.
113
+
114
+ ## The catalog entry
115
+
116
+ The listing lives at `data/plugins/XINY11451__dsh-wsl.yml` in
117
+ `awesome-dsh-plugin/awesome-dsh-plugin`, one file per plugin. Only
118
+ `description.en` is required; `description.zh` is optional. Edit it through a
119
+ one-file PR (the web UI's pencil button forks and proposes the change).
120
+
121
+ Two of its keys are hand-written and must stay:
122
+
123
+ - `tarball:` — the fixed release URL above. It is what the market's `install`
124
+ command points at today.
125
+ - `url` / `name` / `category` — `category: wsl`.
126
+
127
+ Everything else about the entry is **generated** and must never be written by
128
+ hand: `npm`, `version`, `downloads`, `screenshots`, and `install`. In particular
129
+ `scripts/probe-npm.mjs` reads `package.json`'s `name` from the repository's
130
+ `HEAD`, then accepts the package only when the registry document's
131
+ `versions[latest].repository.url` contains `<owner>/<repo>`
132
+ (case-insensitively — that check is what stops name squatting). So keep
133
+ `repository` in `package.json` accurate, or the catalog stops discovering the npm
134
+ package. "Not published" verdicts are re-probed daily, so a freshly published
135
+ version can take a day to appear; when it does, `install` switches from the
136
+ tarball URL to `dsh plugin --profile web add dsh-wsl-tool`.
137
+
138
+ ## Things that bite
139
+
140
+ - **A tag event runs the workflow from the tag's commit.** To change the
141
+ pipeline you must commit *and cut a new tag*; re-running an old run reuses the
142
+ workflow it was created with, and moving a tag is not a fix.
143
+ - **Job logs need authentication; annotations do not.** There is no `gh` and no
144
+ `GITHUB_TOKEN` on the maintainer machine, so anything that must be diagnosable
145
+ without a credential belongs in an annotation.
146
+ - **An interactive `npm publish` asks for a one-time password** and cannot be
147
+ driven from an unattended run. CI authenticates with a granular token that may
148
+ bypass 2FA, stored as the `NPM_TOKEN` secret; with the secret absent the step
149
+ skips with a notice instead of failing. Now that the package exists, OIDC
150
+ trusted publishing is the better replacement.
151
+ - **`publishConfig.registry` in `package.json` wins** over a developer's
152
+ `~/.npmrc` mirror, so a mirror configured for reads cannot intercept a publish.
153
+ - **The profile's dependency key is not the package name** (`dsh-wsl` versus
154
+ `dsh-wsl-tool`). Do not "fix" that by hand: the profile is managed by pnpm, and
155
+ its `pnpm-lock.yaml`, `node_modules/.modules.yaml`, and
156
+ `node_modules/.package-map.json` all record the key. The relative patch entry
157
+ means the difference costs nothing.
158
+ - **Short unscoped names ending in `-wsl` are a minefield.** `dsh-wsl` collides
159
+ with `is-wsl`; longer suffixed names such as `dsh-wsl-workspace` are published
160
+ by other authors and pass. Prefer npm's suggestion (a scope) or a clearly
161
+ suffixed name, and check the registry before tagging.
package/README.md CHANGED
@@ -96,18 +96,33 @@ specifier you install under.
96
96
  or `dsh plugin add --profile <profile> file:<path-to-this-repo>` from a
97
97
  checkout (which names the dependency after this package).
98
98
 
99
- 2. Add a `tool-wsl` row to an agent preset's `agent.cordis.yml`:
99
+ 2. Nothing else. The package's `cordis.patch.yml` inserts the `tool-wsl` row
100
+ itself when the bundle is loaded, process-wide, so the three tools are
101
+ available to every agent preset without further wiring.
100
102
 
101
- ```yaml
102
- - id: tool-wsl
103
- name: 'dsh-wsl-tool'
104
- ```
105
-
106
- `name` is the installed package name — use your own dependency key if you
107
- installed under a different one.
103
+ Do **not** also list `tool-wsl` in a preset: DSH registers tools by name, and
104
+ the second registration fails with
105
+ `tool "wsl" is already registered in this scope`. One row, from the bundle.
108
106
 
109
107
  3. Restart DSH.
110
108
 
109
+ ## Compatibility
110
+
111
+ Verified against DSH **0.1.7-rc.2** (and 0.1.5-rc.2 before it): the tool schemas
112
+ pass DSH's own `assertSupportedJsonSchema`, the subprocess seam is exercised
113
+ against the real provider rather than a shim, and the background-job path is
114
+ checked against the real job registry, including the session-id ownership fence
115
+ that 0.1.7 tightened. `test/real-seam.mjs` is that check and it re-verifies a host
116
+ in about a minute, so point it at any DSH installation after an upgrade:
117
+
118
+ ```sh
119
+ DSH_SUBPROCESS_LOCAL=/path/to/dsh/node_modules npm run test:real
120
+ ```
121
+
122
+ A background job is owned by the calling session (`owner: exec.agent.id`), which
123
+ is what lets the model read it back with `job_output`/`job_kill` and what keeps
124
+ other sessions out; an execution with no agent starts the job unowned.
125
+
111
126
  ## `wsl` parameters
112
127
 
113
128
  | Param | Required | Type | Notes |
@@ -312,6 +327,9 @@ the folder name itself never matters.
312
327
 
313
328
  then restart DSH — the plugin is imported once at load.
314
329
 
330
+ Releasing — the tag-triggered workflow, the npm name, and the catalog entry — is
331
+ documented in [`PUBLISHING.md`](PUBLISHING.md).
332
+
315
333
  ## Listing
316
334
 
317
335
  The repository carries the `dsh-plugin` topic and is listed under the `wsl`
package/README.zh-CN.md CHANGED
@@ -86,17 +86,29 @@ launcher: WSL 版本: 2.6.3.0 · 内核版本: 6.6.87.2-1 · WSLg 版本: 1.0.71
86
86
  `dsh plugin add --profile <profile> file:<path-to-this-repo>` 从本地检出安装
87
87
  (依赖名会取本包自身的名字)。
88
88
 
89
- 2. 在某个 agent preset 的 `agent.cordis.yml` 中加入 `tool-wsl` 行:
89
+ 2. 不必再做别的。本包的 `cordis.patch.yml` 会在组合包加载时**自己插入** `tool-wsl` 行
90
+ (进程级),因此三个工具对所有 agent preset 都可用,无需额外接线。
90
91
 
91
- ```yaml
92
- - id: tool-wsl
93
- name: 'dsh-wsl-tool'
94
- ```
95
-
96
- `name` 即安装后的包名;若你用了别的依赖名,就填那个名字。
92
+ **不要**再在 preset 里列一遍 `tool-wsl`:DSH 按名字注册工具,第二次注册会直接失败
93
+ —— `tool "wsl" is already registered in this scope`。这一行只由组合包提供。
97
94
 
98
95
  3. 重启 DSH。
99
96
 
97
+ ## 兼容性
98
+
99
+ 已在 DSH **0.1.7-rc.2** 上验证(此前为 0.1.5-rc.2):工具 schema 通过 DSH 自己的
100
+ `assertSupportedJsonSchema`;subprocess 接缝是跑在**真实 provider** 上而非替身;后台任务
101
+ 路径跑在**真实 job 注册表**上,包含 0.1.7 收紧的「会话 id 属主围栏」。这套检查就是
102
+ `test/real-seam.mjs`,约一分钟即可重验一个新宿主——升级后把它指向新的 DSH 安装即可:
103
+
104
+ ```sh
105
+ DSH_SUBPROCESS_LOCAL=/path/to/dsh/node_modules npm run test:real
106
+ ```
107
+
108
+ 后台任务由**调用方会话**持有(`owner: exec.agent.id`),这既是模型能用
109
+ `job_output`/`job_kill` 读回它的依据,也是其他会话读不到它的围栏;exec 里没有 agent 时
110
+ 任务则是无主的。
111
+
100
112
  ## `wsl` 参数
101
113
 
102
114
  | 参数 | 必填 | 类型 | 说明 |
@@ -299,6 +311,8 @@ npm run sync -- /path/to/profiles/<profile>/node_modules/<你的依赖名>
299
311
 
300
312
  然后重启 DSH——插件在加载时只导入一次。
301
313
 
314
+ 发版流程(tag 触发的流水线、npm 包名与目录条目)见 [`PUBLISHING.md`](PUBLISHING.md)。
315
+
302
316
  ## 收录
303
317
 
304
318
  本仓库带有 `dsh-plugin` topic,并已提交至 awesome-dsh-plugin 社区列表的 `wsl` 分类。
package/lib/tools/wsl.js CHANGED
@@ -71,7 +71,15 @@ export function createWslTool({ ctx, config, runner }) {
71
71
  kind: 'wsl',
72
72
  label: jobLabel(command),
73
73
  outputLimitBytes: config.maxOutputBytes,
74
- ...(exec?.agent === undefined ? {} : { owner: exec.agent }),
74
+ // `owner` is the owner's SESSION ID, not the Agent handle: the registry
75
+ // resolves it through the live-agent registry (`agents.get(sessionId)`)
76
+ // and fails with `session "…" has no live agent` for anything else. It
77
+ // is also the fence key — the model's `job_output`/`job_kill` reach this
78
+ // job by passing the same session id as their caller. Bound to
79
+ // `exec.agent.id` exactly as `dsh-tool-bash` and `dsh-tool-pwsh` do.
80
+ // An execution with no agent starts an unowned job, which is open to any
81
+ // caller but never listed for a session.
82
+ ...(exec?.agent === undefined ? {} : { owner: exec.agent.id }),
75
83
  // The spawn happens INSIDE run(): the contract says a throw leaves
76
84
  // nothing registered, so spawning first and registering second could
77
85
  // leak a process if registration failed.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-wsl-tool",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "description": "Model-facing WSL tools for DeepSeek Harness: run Linux commands from Windows with background jobs, stdin, path translation, destructive-command guard and WSL capability diagnostics.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -29,6 +29,7 @@
29
29
  "cordis.patch.yml",
30
30
  "README.md",
31
31
  "README.zh-CN.md",
32
+ "PUBLISHING.md",
32
33
  "screenshots.json",
33
34
  "assets",
34
35
  "LICENSE"