dsh-plugin-toolkit 0.8.3 → 0.8.5
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/CHANGELOG.md +18 -0
- package/README.md +42 -2
- package/lib/cli.mjs +3 -0
- package/lib/release.mjs +19 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## 0.8.5
|
|
2
|
+
|
|
3
|
+
- `release --market <dir>`: write the index entry into a checkout of the
|
|
4
|
+
repository that owns the index, and open the pull request there. Before this,
|
|
5
|
+
`release` only touched a `market/index.json` inside the plugin's own repo, so
|
|
6
|
+
anyone listed in a central market had to patch the entry by hand — which is
|
|
7
|
+
where the timestamp goes wrong.
|
|
8
|
+
- `--index` still names the file inside that repository.
|
|
9
|
+
|
|
10
|
+
## 0.8.4
|
|
11
|
+
|
|
12
|
+
- README: `## When the panel does not appear` — the five checks that explain a
|
|
13
|
+
successful install with nothing on screen (restart, root export, tarball,
|
|
14
|
+
patch row, a bundle that throws). Each one is a failure this tool has already
|
|
15
|
+
hit. A test keeps the section from losing a step.
|
|
16
|
+
- `doctor` table lists the new `root export` check; the verify example no longer
|
|
17
|
+
pins an old version in its own docs.
|
|
18
|
+
|
|
1
19
|
## 0.8.3
|
|
2
20
|
|
|
3
21
|
`verify` now imports the host half it just installed.
|
package/README.md
CHANGED
|
@@ -247,6 +247,7 @@ latest release.
|
|
|
247
247
|
| `patch file` | The path declared above must be a real file |
|
|
248
248
|
| `client entry` | If `dsh.client` is declared, the bundle has to be there |
|
|
249
249
|
| `files list` | Every path `package.json` points at (`exports`, patch, client) must be covered by `files` |
|
|
250
|
+
| `root export` | The loader imports the bare package name; if that module is the CLI (or exports no `apply`), the row mounts nothing while the install reports success |
|
|
250
251
|
|
|
251
252
|
Exit code is `0` when the plugin can be installed and `1` when it cannot, so it drops into CI unchanged.
|
|
252
253
|
|
|
@@ -255,7 +256,7 @@ Exit code is `0` when the plugin can be installed and `1` when it cannot, so it
|
|
|
255
256
|
`doctor` reads your working copy. Users install the tarball, and a `files` list can ship everything except the panel — `doctor` will not notice.
|
|
256
257
|
|
|
257
258
|
```sh
|
|
258
|
-
$ npx dsh-plugin-toolkit
|
|
259
|
+
$ npx dsh-plugin-toolkit verify .
|
|
259
260
|
ok packed 5 file(s), installed the tarball, mounted the panel
|
|
260
261
|
My panel This panel came from dsh-plugin init. Clicks: 0
|
|
261
262
|
```
|
|
@@ -263,11 +264,37 @@ ok packed 5 file(s), installed the tarball, mounted the panel
|
|
|
263
264
|
It packs, installs that tarball into a throwaway directory, then mounts the bundle **from the installed copy**. When the `files` list drops the panel:
|
|
264
265
|
|
|
265
266
|
```sh
|
|
266
|
-
$ npx dsh-plugin-toolkit
|
|
267
|
+
$ npx dsh-plugin-toolkit verify .
|
|
267
268
|
dsh-plugin verify: stopped at pack
|
|
268
269
|
✗ pack: the tarball does not contain client.js, so the installed plugin has no panel
|
|
269
270
|
```
|
|
270
271
|
|
|
272
|
+
## When the panel does not appear
|
|
273
|
+
|
|
274
|
+
The install reports success and nothing shows up. In this order:
|
|
275
|
+
|
|
276
|
+
1. **Did the host restart?** Client bundles are read at startup. `dsh plugin add`
|
|
277
|
+
writes the profile; the running window still has the old bundle.
|
|
278
|
+
2. **Is the root export the plugin?**
|
|
279
|
+
```sh
|
|
280
|
+
node -e "import('my-plugin').then((m) => console.log(typeof m.apply))"
|
|
281
|
+
```
|
|
282
|
+
`function` is what the loader needs. `undefined` means `exports["."]` points
|
|
283
|
+
at the CLI — `0.8.0` of this tool shipped exactly that.
|
|
284
|
+
3. **Does the tarball ship the panel?** `dsh-plugin verify .` installs what users
|
|
285
|
+
get and mounts it. `doctor` cannot see this.
|
|
286
|
+
4. **Is the patch row shaped right?** `cordis.patch.yml` needs one `- insert:`
|
|
287
|
+
entry with `id` and `name`:
|
|
288
|
+
```yaml
|
|
289
|
+
- insert:
|
|
290
|
+
- id: my-plugin
|
|
291
|
+
name: my-plugin
|
|
292
|
+
config: {}
|
|
293
|
+
```
|
|
294
|
+
5. **Did the client bundle throw?** The host logs the loader error with the
|
|
295
|
+
plugin id; a bundle that throws at factory time looks identical to one that
|
|
296
|
+
never loaded.
|
|
297
|
+
|
|
271
298
|
## What `release` does
|
|
272
299
|
|
|
273
300
|
`release` runs the sequence in the order that fails cheapest first:
|
|
@@ -293,6 +320,19 @@ merged
|
|
|
293
320
|
|
|
294
321
|
Without `--pr` it prints the `git add` / `gh pr create` commands instead of running them; `--dry-run` prints the whole sequence before anything happens. A re-run after a failure is safe: the same version with the same publish time is a no-op.
|
|
295
322
|
|
|
323
|
+
### When the index lives in someone else's repository
|
|
324
|
+
|
|
325
|
+
Most plugins are listed in a central market repository, not their own. Point
|
|
326
|
+
`--market` at a checkout of that repository and the entry — and the pull
|
|
327
|
+
request — land there:
|
|
328
|
+
|
|
329
|
+
```sh
|
|
330
|
+
$ dsh-plugin release . --market ../market-repo --pr --merge
|
|
331
|
+
tagged plugin-v0.4.0, npm served my-plugin@0.4.0 after 92s
|
|
332
|
+
updated /Users/me/market-repo/market/index.json on market/0.4.0
|
|
333
|
+
merged
|
|
334
|
+
```
|
|
335
|
+
|
|
296
336
|
## Exit codes
|
|
297
337
|
|
|
298
338
|
| Code | Meaning |
|
package/lib/cli.mjs
CHANGED
|
@@ -37,6 +37,7 @@ export const HELP = `dsh-plugin — preflight and release DeepSeek Harness plugi
|
|
|
37
37
|
Flags
|
|
38
38
|
--dry-run show the steps without touching anything
|
|
39
39
|
--index <path> index file, default market/index.json
|
|
40
|
+
--market <dir> with release: a checkout of the repository that holds the index
|
|
40
41
|
--tag-prefix <prefix> default plugin-v
|
|
41
42
|
--budget <seconds> how long to wait for npm, default 480
|
|
42
43
|
--pr commit the index on a branch, push it, open the pull request
|
|
@@ -72,6 +73,7 @@ function flags(argv) {
|
|
|
72
73
|
else if (token === '--pr') parsed.pr = true;
|
|
73
74
|
else if (token === '--merge') parsed.merge = true;
|
|
74
75
|
else if (token === '--base') parsed.base = argv[++index];
|
|
76
|
+
else if (token === '--market') parsed.market = argv[++index];
|
|
75
77
|
else if (token.startsWith('--') === true) throw new Error(`unknown flag ${token}`);
|
|
76
78
|
else parsed.positional.push(token);
|
|
77
79
|
}
|
|
@@ -210,6 +212,7 @@ export async function run(argv, io = console) {
|
|
|
210
212
|
const result = await release({
|
|
211
213
|
dir,
|
|
212
214
|
indexFile: options.index,
|
|
215
|
+
marketDir: options.market,
|
|
213
216
|
tagPrefix: options.tagPrefix,
|
|
214
217
|
budgetMs: options.budget === undefined ? undefined : options.budget * 1000,
|
|
215
218
|
pr: options.pr === true,
|
package/lib/release.mjs
CHANGED
|
@@ -51,7 +51,7 @@ export function dirtyPaths(dir, limit = 3, run) {
|
|
|
51
51
|
* anything runs is what makes `--dry-run` useful: it shows the whole sequence
|
|
52
52
|
* and the exact commands.
|
|
53
53
|
*/
|
|
54
|
-
export function plan({ dir = process.cwd(), version, name, tagPrefix = 'plugin-v', indexFile = 'market/index.json' }) {
|
|
54
|
+
export function plan({ dir = process.cwd(), version, name, tagPrefix = 'plugin-v', indexFile = 'market/index.json', marketDir }) {
|
|
55
55
|
const report = doctor(dir);
|
|
56
56
|
const resolvedName = name ?? report.manifest.name ?? 'this-plugin';
|
|
57
57
|
const resolvedVersion = version ?? report.manifest.version ?? '0.0.0';
|
|
@@ -61,7 +61,13 @@ export function plan({ dir = process.cwd(), version, name, tagPrefix = 'plugin-v
|
|
|
61
61
|
{ title: `Create the tag ${tag}`, command: `git tag ${tag}`, runs: true },
|
|
62
62
|
{ title: 'Push the tag, which starts the release workflow', command: `git push origin ${tag}`, runs: true },
|
|
63
63
|
{ title: `Wait until the registry serves ${resolvedName}@${resolvedVersion}`, command: `GET /${resolvedName}`, runs: true },
|
|
64
|
-
{
|
|
64
|
+
{
|
|
65
|
+
title: marketDir === undefined
|
|
66
|
+
? 'Write the version into the market index, with the publish time the registry reported'
|
|
67
|
+
: `Write the version into the market index at ${marketDir}`,
|
|
68
|
+
command: `patch ${path.join(marketDir ?? '', indexFile)}`,
|
|
69
|
+
runs: true,
|
|
70
|
+
},
|
|
65
71
|
{ title: 'Open the index pull request', command: 'gh pr create', runs: false },
|
|
66
72
|
{ title: 'Re-read the live index and confirm the version is listed', command: 'GET market/index.json', runs: false },
|
|
67
73
|
];
|
|
@@ -74,6 +80,7 @@ export async function release(options) {
|
|
|
74
80
|
registry,
|
|
75
81
|
tagPrefix = 'plugin-v',
|
|
76
82
|
indexFile = 'market/index.json',
|
|
83
|
+
marketDir,
|
|
77
84
|
budgetMs,
|
|
78
85
|
intervalMs,
|
|
79
86
|
sleep,
|
|
@@ -155,7 +162,10 @@ export async function release(options) {
|
|
|
155
162
|
|
|
156
163
|
const timestamp = publishedAt(waited.document, version);
|
|
157
164
|
const entry = buildEntry({ version, publishTimestamp: timestamp, hostRange: report.notes.hostRange });
|
|
158
|
-
|
|
165
|
+
// Most plugins are listed in someone else's index: `--market` points at a
|
|
166
|
+
// checkout of that repository, and the entry plus the pull request land there.
|
|
167
|
+
const indexRoot = typeof marketDir === 'string' && marketDir.length > 0 ? path.resolve(marketDir) : dir;
|
|
168
|
+
const indexPath = path.join(indexRoot, indexFile);
|
|
159
169
|
let indexUpdate = null;
|
|
160
170
|
if (fs.existsSync(indexPath) === true) {
|
|
161
171
|
try {
|
|
@@ -163,10 +173,10 @@ export async function release(options) {
|
|
|
163
173
|
const after = addVersion(before, name, entry);
|
|
164
174
|
if (after !== before) {
|
|
165
175
|
writeIndex(indexPath, after);
|
|
166
|
-
indexUpdate = { file:
|
|
176
|
+
indexUpdate = { file: indexPath, version, entry };
|
|
167
177
|
if (typeof onChange === 'function') onChange(indexUpdate);
|
|
168
178
|
} else {
|
|
169
|
-
indexUpdate = { file:
|
|
179
|
+
indexUpdate = { file: indexPath, version, entry, unchanged: true };
|
|
170
180
|
}
|
|
171
181
|
} catch (error) {
|
|
172
182
|
return { ok: false, stage: 'index', failures: [{ check: 'index', message: error.message }] };
|
|
@@ -188,16 +198,17 @@ export async function release(options) {
|
|
|
188
198
|
// The index change is one line, but it still needs a branch, a pull request,
|
|
189
199
|
// a green CI and a merge; doing that by hand is where "forgot to open the PR"
|
|
190
200
|
// happens.
|
|
191
|
-
const ghRunner = options.gh ?? defaultGh(
|
|
201
|
+
const ghRunner = options.gh ?? defaultGh(indexRoot);
|
|
202
|
+
const marketGit = options.marketGit ?? (indexRoot === dir ? options.git : ((args) => git(indexRoot, args)));
|
|
192
203
|
const pull = await openIndexPr({
|
|
193
|
-
dir,
|
|
204
|
+
dir: indexRoot,
|
|
205
|
+
git: marketGit,
|
|
194
206
|
indexFile,
|
|
195
207
|
version,
|
|
196
208
|
base: options.base ?? 'main',
|
|
197
209
|
branch: options.branch,
|
|
198
210
|
title: options.prTitle,
|
|
199
211
|
body: options.prBody,
|
|
200
|
-
git: options.git,
|
|
201
212
|
gh: ghRunner,
|
|
202
213
|
onStep: options.onStep,
|
|
203
214
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-toolkit",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "Preflight, release and test DeepSeek Harness plugins: checks what the host needs, waits for npm to actually serve the version, and keeps the market index honest.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|