dsh-plugin-toolkit 0.8.7 → 0.8.8

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,9 @@
1
+ ## 0.8.8
2
+
3
+ - `dev` reads the plugin graph the app sends first, so a plugin the app never
4
+ loaded is reported as that ("restart the app once after installing it") instead
5
+ of as a timeout. Found by running `dev` against a real app, not a fake stream.
6
+
1
7
  ## 0.8.7
2
8
 
3
9
  - `panel.aria(selector)` and `panel.expectAria(selector, expected)`: assert what a
package/README.md CHANGED
@@ -217,6 +217,12 @@ watching /work/plugin
217
217
 
218
218
  That last line is the whole point: the revision came back from the app's own event stream, so "it reloaded" is a fact, not a hope.
219
219
 
220
+ A plugin the running app never loaded cannot be reloaded, and the app says so by leaving it out of the graph it sends first. `dev` reads that graph, so a freshly installed plugin gets the sentence that fixes it instead of a timeout:
221
+
222
+ ```
223
+ copied, but not confirmed: the running app has not loaded demo-panel, so it will not report a reload; restart the app once after installing it
224
+ ```
225
+
220
226
  | Flag | Meaning |
221
227
  |---|---|
222
228
  | `--dest <dir>` | write into this installed copy instead of searching `~/.dsh/profiles/*/node_modules/<name>` |
package/lib/dev.mjs CHANGED
@@ -61,6 +61,15 @@ export function build({ command, cwd, io = console }) {
61
61
  export async function verifyReload({ host, id, timeoutMs = 6000, fetchImpl = fetch, action }) {
62
62
  const controller = new AbortController();
63
63
  const timer = setTimeout(() => controller.abort(), timeoutMs);
64
+ // The app sends its plugin graph first. If this plugin is not in it, no amount
65
+ // of waiting will produce a rebuilt frame: it was installed after the app
66
+ // started, and one restart is the fix.
67
+ let loaded = null;
68
+ // Two ways to give up — the stream ended, or it timed out — and both mean the
69
+ // same thing when the app never had this plugin in its graph.
70
+ const miss = (fallback) => (loaded !== null && loaded.has(id) === false
71
+ ? `the running app has not loaded ${id}, so it will not report a reload; restart the app once after installing it`
72
+ : fallback);
64
73
  const url = `${String(host).replace(/\/+$/, '')}/plugins/events`;
65
74
  try {
66
75
  const response = await fetchImpl(url, { headers: { accept: 'text/event-stream' }, signal: controller.signal });
@@ -90,14 +99,19 @@ export async function verifyReload({ host, id, timeoutMs = 6000, fetchImpl = fet
90
99
  } catch {
91
100
  continue;
92
101
  }
102
+ if (payload.type === 'graph') {
103
+ const entries = payload.graph?.entries;
104
+ if (Array.isArray(entries) === true) loaded = new Set(entries.map((entry) => entry.id));
105
+ continue;
106
+ }
93
107
  if (payload.type !== 'rebuilt') continue;
94
108
  if (JSON.stringify(payload).includes(id) === false) continue;
95
109
  return { ok: true, rev: payload.rev ?? null, frame: payload };
96
110
  }
97
111
  }
98
- return { ok: false, reason: 'the stream ended before a rebuilt frame arrived' };
112
+ return { ok: false, reason: miss('the stream ended before a rebuilt frame arrived') };
99
113
  } catch (error) {
100
- if (error.name === 'AbortError') return { ok: false, reason: `no rebuilt frame for ${id} within ${timeoutMs}ms` };
114
+ if (error.name === 'AbortError') return { ok: false, reason: miss(`no rebuilt frame for ${id} within ${timeoutMs}ms`) };
101
115
  return { ok: false, reason: error.message };
102
116
  } finally {
103
117
  clearTimeout(timer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-toolkit",
3
- "version": "0.8.7",
3
+ "version": "0.8.8",
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": {