dsh-plugin-toolkit 0.7.0 → 0.7.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ ## 0.7.2
2
+
3
+ `verify` runs from npx's cache, so it has to find jsdom and React where the
4
+ plugin is, not where the tool is.
5
+
6
+ - `testkit` resolves `jsdom`, `react` and `react-dom` from the plugin folder
7
+ first, then the working directory, then the tool's own dependencies.
8
+ - `verify` passes the plugin folder through, so
9
+ `uses: WJDdidi-1/dsh-plugin-toolkit@v1` works in a workflow that ran `npm ci`
10
+ in the plugin: before this, the action failed with
11
+ `testkit needs a DOM: npm install --save-dev jsdom react react-dom` even
12
+ though the plugin declared them.
13
+
14
+ ## 0.7.1
15
+
16
+ The action now checks the tarball, which is the only thing a user installs.
17
+
18
+ - `uses: WJDdidi-1/dsh-plugin-toolkit@v1` defaults to `command: verify` instead
19
+ of `doctor`. `doctor` reads the working copy, so a `files` list that omits
20
+ `client.js` passes it and the plugin installs without a panel.
21
+ - The action fetches the published package with `npx` rather than shipping
22
+ `node_modules` in the repository — `verify` mounts the panel, which needs
23
+ jsdom and React, and those belong to the caller's dev dependencies.
24
+ - New `version` input (default `latest`) so a workflow can pin the tool.
25
+ - `test/action.test.mjs` guards the three things that break silently: the
26
+ default command, the commands it offers existing in the CLI, and the README
27
+ showing the action the way a consumer writes it.
28
+
1
29
  # Changelog
2
30
 
3
31
  ## 0.7.0
package/README.md CHANGED
@@ -215,9 +215,17 @@ The same checks run as a GitHub Action, so a tag cannot go out on a plugin that
215
215
  - uses: WJDdidi-1/dsh-plugin-toolkit@v1
216
216
  with:
217
217
  dir: plugin # the folder holding the plugin's package.json
218
+ command: verify # pack it, install the tarball, mount the panel
218
219
  ```
219
220
 
220
- `command: index` audits `market/index.json` instead, and fails on any version that cannot state a host range.
221
+ `verify` is the default because it is the only check that reads what a user
222
+ actually installs: `doctor` reads the working copy, so a `files` list that
223
+ forgets `client.js` passes it and fails only after `npm i`.
224
+
225
+ `command: doctor` stops at the manifest checks (fast, no install), and
226
+ `command: index` audits `market/index.json` instead, failing on any version that
227
+ cannot state a host range. Pin `version:` if you would rather not track the
228
+ latest release.
221
229
 
222
230
  ## What `doctor` checks
223
231
 
@@ -6,15 +6,34 @@
6
6
  * jsdom plus the real React gives us the same arrangement in Node, which is what
7
7
  * makes panel behaviour assertable in CI instead of by hand.
8
8
  */
9
- let JSDOM;
10
- let VirtualConsole;
11
- try {
12
- ({ JSDOM, VirtualConsole } = await import('jsdom'));
13
- } catch {
14
- throw new Error('testkit needs a DOM: npm install --save-dev jsdom react react-dom');
9
+ import { createRequire } from 'node:module';
10
+ import path from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
12
+
13
+ /**
14
+ * Resolve a dependency the way the *plugin under test* would.
15
+ *
16
+ * `npx dsh-plugin-toolkit verify` installs the tool in npx's own cache, so a
17
+ * bare `import('jsdom')` looks there and not in the project that declared it.
18
+ * The plugin folder is the authority on what is installed.
19
+ */
20
+ export function requireFrom(name, resolveFrom) {
21
+ const anchors = [resolveFrom, process.cwd(), path.dirname(fileURLToPath(import.meta.url))]
22
+ .filter((anchor) => typeof anchor === 'string' && anchor !== '');
23
+ for (const anchor of anchors) {
24
+ try {
25
+ return createRequire(path.join(anchor, 'noop.js'))(name);
26
+ } catch {
27
+ // Try the next place a dependency could legitimately live.
28
+ }
29
+ }
30
+ throw new Error(
31
+ `testkit needs ${name} where the plugin is installed: cd ${anchors[0]} && npm install --save-dev jsdom react react-dom`,
32
+ );
15
33
  }
16
34
 
17
- export function createDom({ html = '<!doctype html><html><body><div id="root"></div></body></html>' } = {}) {
35
+ export function createDom({ html = '<!doctype html><html><body><div id="root"></div></body></html>', resolveFrom } = {}) {
36
+ const { JSDOM, VirtualConsole } = requireFrom('jsdom', resolveFrom);
18
37
  // jsdom's CSS parser predates nesting and `:has()`, so it complains about
19
38
  // stylesheets it cannot parse. That is a jsdom limit, not a panel bug.
20
39
  const virtualConsole = new VirtualConsole();
@@ -4,7 +4,7 @@
4
4
  * The helpers are deliberately blunt — click, type, press — because that is the
5
5
  * vocabulary a bug report uses. Anything cleverer hides which selector was hit.
6
6
  */
7
- import { createDom, installGlobals } from './env.mjs';
7
+ import { createDom, installGlobals, requireFrom } from './env.mjs';
8
8
  import { createHost } from './host.mjs';
9
9
  import { loadBundle } from './load.mjs';
10
10
  import { compare, write } from './snapshot.mjs';
@@ -37,24 +37,29 @@ export async function mountClient(options) {
37
37
  container = 'root',
38
38
  } = options;
39
39
 
40
- const { dom, window, document } = createDom();
40
+ // React is resolved from the plugin's folder too: when the tool runs from
41
+ // npx's cache, its own dependencies are not the ones the panel was written
42
+ // against.
43
+ const resolveFrom = options.resolveFrom ?? process.cwd();
44
+ const need = (name) => requireFrom(name, resolveFrom);
45
+
46
+ const { dom, window, document } = createDom({ resolveFrom });
41
47
  const restoreGlobals = installGlobals(window, document);
42
48
 
43
- const need = async (name) => {
49
+ const React = need('react');
50
+ const reactDom = need('react-dom/client');
51
+ const jsxRuntime = need('react/jsx-runtime');
52
+ const jsxDevRuntime = (() => {
44
53
  try {
45
- return await import(name);
54
+ return need('react/jsx-dev-runtime');
46
55
  } catch {
47
- throw new Error(`testkit needs ${name}: npm install --save-dev jsdom react react-dom`);
56
+ return jsxRuntime;
48
57
  }
49
- };
50
- const React = await need('react');
51
- const reactDom = await need('react-dom/client');
52
- const jsxRuntime = await need('react/jsx-runtime');
53
- const jsxDevRuntime = await import('react/jsx-dev-runtime').catch(() => jsxRuntime);
58
+ })();
54
59
 
55
60
  const modules = {
56
61
  react: React.default ?? React,
57
- 'react-dom': await import('react-dom'),
62
+ 'react-dom': need('react-dom'),
58
63
  'react-dom/client': reactDom.default ?? reactDom,
59
64
  'react/jsx-runtime': jsxRuntime,
60
65
  'react/jsx-dev-runtime': jsxDevRuntime,
package/lib/verify.mjs CHANGED
@@ -121,7 +121,9 @@ export async function verify({ dir, mount = true }) {
121
121
  }
122
122
  try {
123
123
  const { mountClient } = await import('./testkit/index.mjs');
124
- const panel = await mountClient({ file: entryFile });
124
+ // Resolve jsdom/React from the plugin's own folder: `verify` may be
125
+ // running out of npx's cache, whose dependencies are not the panel's.
126
+ const panel = await mountClient({ file: entryFile, resolveFrom: dir });
125
127
  const text = panel.text();
126
128
  await panel.unmount();
127
129
  return { ok: true, stage: 'mount', failures: [], files: packed.files, size: packed.size, installed, text };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-toolkit",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
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": {