dsh-better-workspace 0.18.0 → 0.19.0

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/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-better-workspace",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "main": "./src/index.js",
5
5
  "description": "侧边栏工作区树:按官方磁盘目录嵌套(官方 workspace-tree 语义),可选按名称中的 / 分组(默认关闭,设置里开启);添加工作区由官方目录流承载。Workspace tree for the DSH sidebar workspace list, nested by official disk folders with optional \"/\"-name grouping.",
6
6
  "engines": {
package/icon.svg ADDED
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" fill="none">
2
+ <path d="M4 10.5A2.5 2.5 0 0 1 6.5 8h6l2.4 2.8H29.5A2.5 2.5 0 0 1 32 13.3V26a2.5 2.5 0 0 1-2.5 2.5h-23A2.5 2.5 0 0 1 4 26V10.5z" stroke="#4493f8" stroke-width="1.7" stroke-linejoin="round"/>
3
+ <path d="M11 17.5h9M11 21.5h14" stroke="#4493f8" stroke-width="1.5" stroke-linecap="round"/>
4
+ <circle cx="24.5" cy="17.5" r="1.3" fill="#f0883e"/>
5
+ </svg>
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Better Workspace",
4
+ "description": "Upgrades the sidebar workspace list into a two-layer hierarchy tree (disk nesting by the official owningParentFolder semantics, optional name-slash grouping), explicit empty folders, appearance customization with live preview, and the official add-workspace flow for every backend."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "更好的工作区",
4
+ "description": "把侧边栏工作区列表升级为两层层级树(磁盘层按官方 owningParentFolder 语义嵌套,名称层按标题里的 / 可选分组),支持显式空分组、带实时预览的外观自定义,添加工作区全程走官方目录流。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-better-workspace",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "侧边栏工作区树:按官方磁盘目录嵌套(官方 workspace-tree 语义),可选按名称中的 / 分组(默认关闭,设置里开启);添加工作区走官方目录流。Workspace tree for the DSH sidebar: disk-path nesting (official workspace-tree semantics), with optional \"/\"-name grouping (off by default); add-workspace rides the official directory flow.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -13,7 +13,8 @@
13
13
  "main": "src/index.js",
14
14
  "exports": {
15
15
  ".": "./src/index.js",
16
- "./client": "./src/client.js"
16
+ "./client": "./src/client.js",
17
+ "./locale/*.json": "./locale/*.json"
17
18
  },
18
19
  "engines": {
19
20
  "node": ">=18",
@@ -41,7 +42,9 @@
41
42
  "dsh.plugin.json",
42
43
  "README.md",
43
44
  "README_EN.md",
44
- "LICENSE"
45
+ "LICENSE",
46
+ "locale",
47
+ "icon.svg"
45
48
  ],
46
49
  "scripts": {
47
50
  "test": "node --test tests/smoke.mjs",
@@ -64,5 +67,9 @@
64
67
  "homepage": "https://github.com/KannaKuron/dsh-better-workspace",
65
68
  "bugs": {
66
69
  "url": "https://github.com/KannaKuron/dsh-better-workspace/issues"
70
+ },
71
+ "icon": "./icon.svg",
72
+ "devDependencies": {
73
+ "@deepseek-ai/schemastery": "^3.18.1"
67
74
  }
68
75
  }
package/src/client.js CHANGED
@@ -3683,6 +3683,10 @@ window.__ModuleLoader__.load({
3683
3683
  // simply never mirror and never sync, which is exactly the pre-0.9.5
3684
3684
  // browser-local behavior.
3685
3685
  let prefsScopeRef = null
3686
+ // 'settingsScope' (dsh <= 0.1.6, the shared ~/.dsh/settings.yaml home —
3687
+ // the only world where CROSS-DEVICE sync makes sense) or 'configForms'
3688
+ // (dsh >= 0.1.7, per-profile patch persistence). null = browser-local.
3689
+ let prefsScopeVia = null
3686
3690
  const HOST_SNAP_UNAVAILABLE = { status: 'unavailable', value: undefined }
3687
3691
  const hostPrefsOf = (snap) => (snap && snap.status === 'ready' && snap.value && typeof snap.value === 'object'
3688
3692
  ? snap.value
@@ -4864,19 +4868,24 @@ window.__ModuleLoader__.load({
4864
4868
  E(BTN, { variant: 'outline', onClick: () => setAppearance(DEFAULT_APPEARANCE) }, t('settings.appearance.reset')),
4865
4869
  ),
4866
4870
  ),
4867
- E('div', { className: 'bw-setting-label', style: { marginTop: 16 } }, t('sync.title')),
4868
- E('div', { className: 'bw-hint' }, t('sync.desc')),
4869
- E('div', { className: 'bw-sync-modes' },
4870
- modeButton('overwrite', t('sync.mode.overwrite')),
4871
- modeButton('merge', t('sync.mode.merge')),
4872
- ),
4873
- E('div', { className: 'bw-sync-actions' },
4874
- syncActionButton(t(IS_DESKTOP_SURFACE ? 'sync.pull.web' : 'sync.pull.desktop'), onPull, true, !scopeLive || snap.status === 'loading'),
4875
- syncActionButton(t('sync.push'), onPush, false, !scopeLive),
4876
- ),
4877
- syncMsg !== null ? E('div', { className: 'bw-hint' }, syncMsg)
4878
- : (scopeLive ? null : E('div', { className: 'bw-hint' }, t('sync.off'))),
4879
- scopeLive && snap.status === 'loading' ? E('div', { className: 'bw-hint' }, t('sync.loading')) : null,
4871
+ // Manual cross-device sync exists only where a SHARED host home does
4872
+ // (dsh <= 0.1.6 settings.yaml; both surfaces read one file). On
4873
+ // dsh >= 0.1.7 settings persist per profile, so the section hides.
4874
+ prefsScopeVia === 'settingsScope' ? E(React.Fragment, null,
4875
+ E('div', { className: 'bw-setting-label', style: { marginTop: 16 } }, t('sync.title')),
4876
+ E('div', { className: 'bw-hint' }, t('sync.desc')),
4877
+ E('div', { className: 'bw-sync-modes' },
4878
+ modeButton('overwrite', t('sync.mode.overwrite')),
4879
+ modeButton('merge', t('sync.mode.merge')),
4880
+ ),
4881
+ E('div', { className: 'bw-sync-actions' },
4882
+ syncActionButton(t(IS_DESKTOP_SURFACE ? 'sync.pull.web' : 'sync.pull.desktop'), onPull, true, !scopeLive || snap.status === 'loading'),
4883
+ syncActionButton(t('sync.push'), onPush, false, !scopeLive),
4884
+ ),
4885
+ syncMsg !== null ? E('div', { className: 'bw-hint' }, syncMsg)
4886
+ : (scopeLive ? null : E('div', { className: 'bw-hint' }, t('sync.off'))),
4887
+ scopeLive && snap.status === 'loading' ? E('div', { className: 'bw-hint' }, t('sync.loading')) : null,
4888
+ ) : null,
4880
4889
  )
4881
4890
  }
4882
4891
 
@@ -6788,14 +6797,38 @@ window.__ModuleLoader__.load({
6788
6797
  // block). Binding is best-effort: a missing/failed bind leaves the
6789
6798
  // plugin fully browser-local — the pre-0.9.5 behavior.
6790
6799
  prefsScopeRef = null
6800
+ prefsScopeVia = null
6791
6801
  try {
6792
6802
  if (ctx.settingsScope && typeof ctx.settingsScope.bind === 'function') {
6793
6803
  prefsScopeRef = ctx.settingsScope.bind({ namespace: 'better-workspace' })
6804
+ prefsScopeVia = 'settingsScope'
6794
6805
  }
6795
6806
  } catch (error) {
6796
6807
  console.warn('[dsh-better-workspace] settings scope bind failed; sync stays local', error)
6797
6808
  prefsScopeRef = null
6798
6809
  }
6810
+ // dsh >= 0.1.7: the settings service is gone; one ConfigForm per live
6811
+ // profile entry replaces it (same getSnapshot/set/subscribe contract).
6812
+ // Values then persist in THIS profile's patch — there is no shared home
6813
+ // any more, so the manual cross-device sync section stays hidden.
6814
+ try {
6815
+ if (ctx.inject) {
6816
+ ctx.inject(['configForms'], (fctx) => {
6817
+ try {
6818
+ if (prefsScopeVia === 'settingsScope') return
6819
+ const forms = fctx && fctx.configForms
6820
+ if (forms && typeof forms.get === 'function') {
6821
+ prefsScopeRef = forms.get('better-workspace')
6822
+ prefsScopeVia = 'configForms'
6823
+ }
6824
+ } catch (error) {
6825
+ console.warn('[dsh-better-workspace] configForms acquisition failed', error)
6826
+ }
6827
+ })
6828
+ }
6829
+ } catch (error) {
6830
+ console.warn('[dsh-better-workspace] configForms wiring failed', error)
6831
+ }
6799
6832
 
6800
6833
  // Settings → Plugins card only (the tab dispatches the intersection of
6801
6834
  // served namespaces — registered host-side — and settings.plugin.item
@@ -6849,7 +6882,7 @@ window.__ModuleLoader__.load({
6849
6882
 
6850
6883
  return {
6851
6884
  name: 'dsh-better-workspace',
6852
- inject: ['slots', 'sessions', 'workspaces', 'locale', 'uiWorkspace', 'settingsScope'],
6885
+ inject: ['slots', 'sessions', 'workspaces', 'locale', 'uiWorkspace'],
6853
6886
  apply,
6854
6887
  }
6855
6888
  },
package/src/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import Schema from '@deepseek-ai/schemastery'
1
2
  /**
2
3
  * dsh-better-workspace — host half (plain JavaScript, no build step).
3
4
  *
@@ -10,6 +11,36 @@
10
11
  */
11
12
  export const name = 'dsh-better-workspace'
12
13
 
14
+ /**
15
+ * dsh >= 0.1.7 marks a Config field live-editable without remount; a
16
+ * 0.1.6-era schemastery predates the method and the guard keeps this module
17
+ * loadable there (values then behave as ordinary config, read through the
18
+ * registered settings namespace instead).
19
+ */
20
+ function live(schema) {
21
+ return typeof schema.volatile === 'function' ? schema.volatile() : schema
22
+ }
23
+
24
+ /**
25
+ * Row Config = the settings surface on dsh >= 0.1.7 (values persist under the
26
+ * row id 'better-workspace' — the same string as the old settings namespace,
27
+ * so the one-shot legacy settings.yaml import maps old user values onto the
28
+ * new home). Inert metadata on older hosts. NOTE: settings are per-profile
29
+ * on the new host; the client hides the manual cross-device sync section
30
+ * accordingly (the shared settings.yaml home no longer exists).
31
+ */
32
+ export const Config = Schema.object({
33
+ compactChains: live(Schema.boolean().default(true)),
34
+ statusPulse: live(Schema.boolean().default(true)),
35
+ styling: live(Schema.dict(Schema.any()).default({})),
36
+ appearance: live(Schema.dict(Schema.any()).default({})),
37
+ })
38
+
39
+ /** Read one Config value across eras: Volatile ref (>= 0.1.7) or plain value. */
40
+ export function valueOf(value) {
41
+ return value && typeof value.get === 'function' ? value.get() : value
42
+ }
43
+
13
44
  export function apply(ctx) {
14
45
  const log = ctx && ctx.logger && typeof ctx.logger.info === 'function'
15
46
  ? (msg) => ctx.logger.info(msg)
@@ -24,7 +55,18 @@ export function apply(ctx) {
24
55
  // The dsh-settings and zod modules resolve only through the dsh Loader; the
25
56
  // smoke test imports this file in plain Node with a logger-only ctx and
26
57
  // never reaches this path.
27
- ctx.inject(['settings'], (sctx) => {
58
+ // OLD-era namespace registration (dsh <= 0.1.6): the row Config above IS
59
+ // the surface on dsh >= 0.1.7 — register() no longer exists there and this
60
+ // block is skipped entirely.
61
+ const legacySettings = (() => {
62
+ try {
63
+ const settings = ctx.get('settings')
64
+ return !!(settings && typeof settings.register === 'function')
65
+ } catch {
66
+ return false
67
+ }
68
+ })()
69
+ if (legacySettings) ctx.inject(['settings'], (sctx) => {
28
70
  log('[dsh-better-workspace] settings inject fired')
29
71
  // The settings service calls the schema AS A FUNCTION to resolve a value
30
72
  // (schema(mergeLayers(...))) — that is @deepseek-ai/schemastery's contract: