dsh-wsl-tool 1.10.0 → 1.10.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 CHANGED
@@ -67,6 +67,22 @@ both that the entry stays relative and that it resolves.
67
67
  once at load. A patch change (the tool row, or the sidebar terminal override)
68
68
  is read at composition time, so it needs that restart too.
69
69
 
70
+ **Then prove the schema really builds from the installed copy**, because this
71
+ is the one failure the tools survive:
72
+
73
+ ```sh
74
+ cd ~/.dsh/profiles/desktop/node_modules/dsh-wsl
75
+ node -e "import('./index.js').then(m => console.log(typeof m.Config, JSON.stringify(m.Config({}))))"
76
+ ```
77
+
78
+ It must print `function` and the resolved defaults. If it prints `undefined`,
79
+ the plugin declares no `Config`, the platform has no schema to project, the
80
+ entry's config status stays `absent` and the sidebar panel renders without a
81
+ single switch while all three tools keep working. The fragile step is the
82
+ interop hop: `@deepseek-ai/schemastery` exports its builder as the **default**
83
+ export, so `const { Schema } = await import(...)` silently yields `undefined`
84
+ (see `lib/schema.js`, and the regression test that pins the picking).
85
+
70
86
  3. The tag runs the pipeline. The order is deliberate — the release asset goes
71
87
  **first** because it is the market's critical path, then npm, so a failing npm
72
88
  publish fails the run loudly without withholding the release.
package/index.js CHANGED
@@ -22,6 +22,7 @@
22
22
  // every switch below is consulted once, in `apply`.
23
23
 
24
24
  import { resolveConfig } from './lib/config.js'
25
+ import { pickSchemaBuilder } from './lib/schema.js'
25
26
  import { createRunner } from './lib/runner.js'
26
27
  import { createWslTool } from './lib/tools/wsl.js'
27
28
  import { createWslPathTool } from './lib/tools/wsl-path.js'
@@ -31,18 +32,29 @@ export const name = 'tool-wsl'
31
32
  export const inject = ['tools', 'subprocess']
32
33
 
33
34
  // The schema is what gives this plugin a settings surface at all: the platform
34
- // derives the namespace the sidebar panel writes to from the entry's id plus this
35
- // schema. It needs `@deepseek-ai/schemastery`, which a real DSH profile supplies
36
- // (the plugin declares it as an optional peer dependency) but which is absent when
37
- // this module is imported standalone, as `test/smoke.mjs` does. A soft import
38
- // keeps the tools runnable there: without a schema every switch keeps its default
39
- // and only the panel is missing.
35
+ // projects the config of every entry that declares one (`ctx.settings.describe()`
36
+ // is keyed by entry id), and the sidebar panel reads and writes that projection.
37
+ // It needs `@deepseek-ai/schemastery`, which a real DSH profile supplies (the
38
+ // plugin declares it as an optional peer dependency) but which is absent when this
39
+ // module is imported standalone, as `test/smoke.mjs` does. A soft import keeps the
40
+ // tools runnable there: without a schema every switch keeps its default and only
41
+ // the panel is missing — and `lib/schema.js` explains why the PICKING, not just
42
+ // the import, is the fragile part.
40
43
  let Schema = null
41
44
  try {
42
- ({ Schema } = await import('@deepseek-ai/schemastery'))
45
+ Schema = pickSchemaBuilder(await import('@deepseek-ai/schemastery'))
43
46
  } catch {
44
47
  Schema = null
45
48
  }
49
+ if (Schema === null) {
50
+ // Not fatal — the tools run on their defaults — but it is exactly the difference
51
+ // between a panel with switches and one without, so say so instead of failing
52
+ // quietly.
53
+ console.warn(
54
+ 'dsh-wsl-tool: no schema builder (@deepseek-ai/schemastery) — the tools run on ' +
55
+ 'their defaults and the sidebar panel will not offer the switches',
56
+ )
57
+ }
46
58
 
47
59
  /**
48
60
  * The plugin's own configuration.
package/lib/schema.js ADDED
@@ -0,0 +1,35 @@
1
+ // The schema builder behind `Config`, resolved through one interop hop.
2
+ //
3
+ // `@deepseek-ai/schemastery` exports the builder as its DEFAULT export: the module
4
+ // namespace of `import('@deepseek-ai/schemastery')` is `{ default: Schema }`, with
5
+ // no named `Schema`. Code that destructures `{ Schema }` from it gets `undefined`
6
+ // without any error, and `Schema?.object({...})` then yields `undefined` — so the
7
+ // plugin declares no `Config`, the platform has no schema to project, its settings
8
+ // namespace never appears, and the sidebar panel renders without switches. That is
9
+ // a quiet failure two layers away from its cause (measured: the Loader entry's
10
+ // config status stayed `absent` while the tools themselves worked), so the shape is
11
+ // pinned here, in one place, with a unit test.
12
+ //
13
+ // A named `Schema` export and a `Schema` property on the default are accepted too:
14
+ // other DSH packages re-export the builder in those shapes, and the check below is
15
+ // about what can actually build a schema, not about this one package.
16
+
17
+ /**
18
+ * Pick the schema builder out of a module namespace.
19
+ *
20
+ * @param namespace - a module namespace (`await import(...)`), or anything else.
21
+ * @returns the builder, or null when the namespace carries none.
22
+ */
23
+ export function pickSchemaBuilder(namespace) {
24
+ if (namespace === null || typeof namespace !== 'object') return null
25
+ const candidates = [namespace.Schema, namespace.default?.Schema, namespace.default]
26
+ for (const candidate of candidates) {
27
+ // `object` is the entry point every Config needs; requiring it here is what
28
+ // makes a wrong export shape look like a missing builder instead of a schema
29
+ // that throws later, while the composition is already being built.
30
+ if (candidate !== null && candidate !== undefined && typeof candidate.object === 'function') {
31
+ return candidate
32
+ }
33
+ }
34
+ return null
35
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-wsl-tool",
3
- "version": "1.10.0",
3
+ "version": "1.10.1",
4
4
  "description": "Run Linux commands from Windows through WSL, essentially matching a native Linux DSH for command execution: background jobs, stdin, path translation, a destructive-command guard and a WSL capability report. A left-sidebar panel switches each capability on or off, each with a one-line explanation, and an opt-in patch gives the desktop app's sidebar terminal a WSL shell. WSL calls run below the DSH sandbox, and a project on a Windows drive keeps Windows filesystem semantics.",
5
5
  "type": "module",
6
6
  "main": "index.js",