dsh-wsl-tool 1.10.1 → 1.10.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.
Files changed (2) hide show
  1. package/lib/client.js +67 -7
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -163,6 +163,25 @@ window.__ModuleLoader__.load({
163
163
  revision: undefined,
164
164
  }
165
165
 
166
+ /**
167
+ * No scope yet — the Host has not listed this namespace, or its `describe()`
168
+ * round trip is still in flight.
169
+ *
170
+ * This is deliberately NOT the unavailable snapshot: a panel that reads "this
171
+ * DSH does not provide the plugin's settings scope" while it is merely still
172
+ * waiting sends whoever is debugging it after the wrong thing (measured: it
173
+ * said exactly that for a namespace the Host was already serving, because the
174
+ * form had been taken before the round trip settled).
175
+ */
176
+ const PENDING_SNAPSHOT = {
177
+ status: 'loading',
178
+ value: undefined,
179
+ base: undefined,
180
+ user: undefined,
181
+ writable: false,
182
+ revision: undefined,
183
+ }
184
+
166
185
  // ---------------------------------------------------------------- helpers
167
186
 
168
187
  /** Read one path out of a possibly absent object, never throwing. */
@@ -218,7 +237,7 @@ window.__ModuleLoader__.load({
218
237
 
219
238
  const read = () => {
220
239
  if (scope === undefined || scope === null || typeof scope.getSnapshot !== 'function') {
221
- return UNAVAILABLE_SNAPSHOT
240
+ return PENDING_SNAPSHOT
222
241
  }
223
242
  try {
224
243
  const snapshot = scope.getSnapshot()
@@ -231,8 +250,15 @@ window.__ModuleLoader__.load({
231
250
 
232
251
  return {
233
252
  /** Whether the `configForms` service was there at all. A service this DSH
234
- * does not ship reads differently from a row it does not serve. */
253
+ * does not ship reads differently from a row it does not serve — and both
254
+ * read differently from a namespace that simply has not been listed yet. */
235
255
  hasService: () => served,
256
+ /** Record that the service exists, before any scope is available. Without
257
+ * this, a namespace that has not been served yet reads as "this DSH has no
258
+ * configuration forms", which is a different (and wrong) diagnosis. */
259
+ noteService: () => {
260
+ served = true
261
+ },
236
262
  /** Bind the scope once the service appears. */
237
263
  attach: (next) => {
238
264
  if (next === undefined || next === null) return
@@ -542,7 +568,8 @@ window.__ModuleLoader__.load({
542
568
  ),
543
569
  )
544
570
  } else if (snapshot.status === 'loading') {
545
- children.push(React.createElement('p', { key: 'note-loading', style: NOTE_STYLE }, '正在读取配置…'))
571
+ children.push(React.createElement('p', { key: 'note-loading', style: NOTE_STYLE },
572
+ '正在等待 Host 提供该插件的配置作用域(' + CONFIG_ROW_ID + ')…'))
546
573
  } else if (snapshot.status !== 'ready') {
547
574
  children.push(
548
575
  React.createElement('p', { key: 'note-unavailable', style: NOTE_STYLE }, '此 DSH 未提供该插件的配置作用域'),
@@ -632,18 +659,51 @@ window.__ModuleLoader__.load({
632
659
  try {
633
660
  if (typeof ctx.inject === 'function') {
634
661
  ctx.inject(['configForms'], (inner) => {
635
- let scope
662
+ const configForms = inner.configForms
663
+ if (configForms === undefined || configForms === null) return
664
+ // The service is here; whether it lists our namespace is a separate
665
+ // question that `whileServed` answers below.
666
+ model.noteService()
667
+ /**
668
+ * Take the form once the Host actually lists the namespace.
669
+ *
670
+ * A form fetched before the `describe()` round trip settles is born
671
+ * with its persistence already fixed to "not host" and never upgrades
672
+ * — it stays `unavailable` forever. That is exactly how this panel
673
+ * lost every switch while the tools kept working, so the namespace is
674
+ * awaited through the platform's own gate instead of being requested
675
+ * eagerly. The shipped settings pages use this same call.
676
+ */
677
+ const attachWhenServed = () => {
678
+ if (typeof configForms.whileServed !== 'function') {
679
+ // Older host face: no gate to wait on, so take whatever it gives
680
+ // and let the model report `unavailable` honestly.
681
+ attach(configForms.get(CONFIG_ROW_ID))
682
+ return () => model.detach()
683
+ }
684
+ return configForms.whileServed([CONFIG_ROW_ID], () => {
685
+ attach(configForms.get(CONFIG_ROW_ID))
686
+ return () => model.detach()
687
+ })
688
+ }
689
+ const attach = (scope) => {
690
+ try {
691
+ model.attach(scope)
692
+ } catch (error) {
693
+ console.error('dsh-wsl-tool: reading the "' + CONFIG_ROW_ID + '" configuration scope failed', error)
694
+ }
695
+ }
696
+ let stop
636
697
  try {
637
- scope = inner.configForms.get(CONFIG_ROW_ID)
698
+ stop = attachWhenServed()
638
699
  } catch (error) {
639
700
  console.error('dsh-wsl-tool: this DSH serves no "' + CONFIG_ROW_ID + '" configuration row', error)
640
701
  return
641
702
  }
642
- model.attach(scope)
643
703
  // The subscription lives exactly as long as this fiber: `effect` runs
644
704
  // the returned disposer on unload or recomposition.
645
705
  if (typeof inner.effect === 'function') {
646
- inner.effect(() => () => model.detach(), 'dsh-wsl-tool: configuration scope')
706
+ inner.effect(() => stop, 'dsh-wsl-tool: configuration scope')
647
707
  }
648
708
  })
649
709
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-wsl-tool",
3
- "version": "1.10.1",
3
+ "version": "1.10.2",
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",