@aryacode/dsh-aryacode-polish 0.6.0 → 0.6.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,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.2] - 2026-10-28
4
+
5
+ ### Fixed
6
+
7
+ - **The "+" menu and the GitHub dialog are opaque again in the desktop app.**
8
+ Both are portaled to `document.body`, which puts them outside the themed tree,
9
+ and they painted themselves with the harness menu fill `--dsw-specific-menu`
10
+ (`#f8f9fa94`, 58% alpha) relying on `backdrop-filter` to make that read solid.
11
+ The AryaCode desktop build does not composite that blur, so the page showed
12
+ through the panel. Every portaled surface now lays that fill over an opaque
13
+ `Canvas` base and keeps the blur only where the platform honours it.
14
+
15
+ ## [0.6.1] - 2026-10-28
16
+
17
+ ### Fixed
18
+
19
+ - **"On this PC" opens the real Windows folder dialog in the desktop app again.**
20
+ The desktop preload exposes the OS chooser as `__DSH_DIRECTORY_PICKER__.pick()`
21
+ — the same bridge the shipped native picker uses — and the flow now calls it
22
+ directly, so picking a folder behaves exactly like the picker it stands in for.
23
+ The in-app folder list is now only the browser fallback, where no such bridge
24
+ exists and the composed picker's `pick` would wait on a dialog that cannot open.
25
+
3
26
  ## [0.6.0] - 2026-10-28
4
27
 
5
28
  ### Changed
package/client/face.js CHANGED
@@ -252,6 +252,24 @@ const PILL_STYLE = {
252
252
  /** The label half of the pill, cut with an ellipsis rather than wrapped. */
253
253
  const PILL_LABEL_STYLE = { minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }
254
254
 
255
+ /**
256
+ * The menu skin of the harness, made opaque on purpose.
257
+ *
258
+ * `--dsw-specific-menu` is a translucent fill (`#f8f9fa94`) that only reads as a
259
+ * solid surface because the harness pairs it with `backdrop-filter`. A plugin
260
+ * face has to portal its panels to `document.body`, and in the AryaCode desktop
261
+ * build that blur does not composite: the panel then showed the page behind it
262
+ * through a 58% fill. So the token stays as a tint over an opaque backdrop
263
+ * colour, and the blur is kept only where the platform actually honours it.
264
+ */
265
+ const PANEL_SURFACE = {
266
+ backgroundColor: 'Canvas',
267
+ backgroundImage:
268
+ 'linear-gradient(var(--dsw-specific-menu, rgba(248, 249, 250, 0.94)), var(--dsw-specific-menu, rgba(248, 249, 250, 0.94)))',
269
+ backdropFilter: 'var(--dsw-menu-backdrop-filter, none)',
270
+ border: '0.5px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12))',
271
+ }
272
+
255
273
  /** The dialog surface, copied from the harness `stat-dialog.module.css` skin. */
256
274
  const PANEL_STYLE = {
257
275
  position: 'fixed',
@@ -261,10 +279,8 @@ const PANEL_STYLE = {
261
279
  minWidth: 'min(300px, calc(100vw - 24px))',
262
280
  maxWidth: 'min(440px, calc(100vw - 24px))',
263
281
  padding: '16px',
264
- border: 0,
265
282
  borderRadius: 'var(--dsw-radius-lg, 12px)',
266
- background: 'var(--dsw-specific-menu, Canvas)',
267
- backdropFilter: 'var(--dsw-menu-backdrop-filter, none)',
283
+ ...PANEL_SURFACE,
268
284
  boxShadow: 'var(--dsw-elevation-prominent, 0 10px 30px rgba(0, 0, 0, 0.18))',
269
285
  fontSize: '12px',
270
286
  lineHeight: '18px',
@@ -1064,16 +1080,33 @@ function WorkspaceSourceFlow(props) {
1064
1080
  }
1065
1081
 
1066
1082
  /**
1067
- * Start the folder browser at the machine's roots.
1083
+ * Hand folder choice to the Host.
1068
1084
  *
1069
- * This deliberately does not call the Host's directory picker: a composed
1070
- * picker serves either `browse` or `native`, never both, and the browser build
1071
- * composes the one whose chooser cannot open there — a `pick` call would wait
1072
- * for a dialog that never appears. Our own listing behaves the same in the app
1073
- * and in the browser, and hands the chosen path back through `onPicked`.
1085
+ * In the desktop app the preload exposes the real OS chooser as
1086
+ * `__DSH_DIRECTORY_PICKER__.pick()` — the same bridge the shipped native
1087
+ * picker uses — so the flow opens the Windows folder dialog and behaves like
1088
+ * the stock picker it stands in for. In a browser there is no such bridge, and
1089
+ * the composed picker's `pick` waits on a dialog that cannot open, so the flow
1090
+ * lists folders itself instead of hanging.
1074
1091
  */
1075
1092
  const chooseOnPc = () => {
1076
1093
  if (busy) return
1094
+ const bridge = typeof globalThis === 'undefined' ? undefined : globalThis.__DSH_DIRECTORY_PICKER__
1095
+ if (bridge !== undefined && typeof bridge.pick === 'function') {
1096
+ setBusy(true)
1097
+ setError('')
1098
+ Promise.resolve()
1099
+ .then(() => bridge.pick())
1100
+ .then(path => {
1101
+ if (typeof path === 'string' && path !== '') {
1102
+ land(path)
1103
+ return
1104
+ }
1105
+ setBusy(false)
1106
+ })
1107
+ .catch(reason => fail(messageOf(reason)))
1108
+ return
1109
+ }
1077
1110
  setBusy(true)
1078
1111
  setError('')
1079
1112
  Promise.resolve()
@@ -1189,7 +1222,7 @@ function WorkspaceSourceFlow(props) {
1189
1222
  padding: '6px',
1190
1223
  overflowY: 'auto',
1191
1224
  borderRadius: 'var(--dsw-radius-lg, 12px)',
1192
- background: 'var(--dsw-specific-menu, Canvas)',
1225
+ ...PANEL_SURFACE,
1193
1226
  boxShadow: 'var(--dsw-elevation-prominent, 0 8px 24px rgba(0,0,0,0.18))',
1194
1227
  fontSize: '12px',
1195
1228
  lineHeight: '18px',
@@ -38,7 +38,11 @@ The "+" menu's **Add workspace…** entry only appears when something occupies
38
38
  takes it stands in for the folder picker. This bundle takes it and offers the
39
39
  two sources the owner asked for:
40
40
 
41
- - **On this PC** — a folder browser driven by this bundle's own route
41
+ - **On this PC** — the OS folder dialog. The desktop preload exposes it as
42
+ `window.__DSH_DIRECTORY_PICKER__.pick()`, the same bridge the shipped native
43
+ picker uses, so the flow calls it directly and behaves exactly like the picker
44
+ it stands in for. Where that bridge is absent (the web build) the flow falls
45
+ back to a folder browser driven by this bundle's own route
42
46
  (`api/polish.folders`, actions `roots` and `ls`): roots, a `..` row for going
43
47
  back, directories only, hidden and system entries filtered out, and **Use this
44
48
  folder** hands the current path to the flow's `onPicked`.
@@ -46,15 +50,14 @@ two sources the owner asked for:
46
50
  flow, so a finished clone hands its path back through the flow's `onPicked`,
47
51
  and the Shell creates the workspace exactly as it does for a picked folder.
48
52
 
49
- ### Why the browser does not borrow the Host's chooser
53
+ ### Why the fallback exists at all
50
54
 
51
55
  A composed directory picker serves exactly one capability: `browse` answers
52
56
  `list` and `createDirectory`, `native` answers `pick`. The web profile composes
53
57
  the picker whose chooser cannot open there, so `directoryPicker.pick()` waits on
54
- a dialog that never appears — the first build of this flow did exactly that and
55
- the row spun forever. Owning the listing keeps one behaviour in the app and in
56
- the browser, needs no capability guess, and does not break when a profile mounts
57
- a different picker.
58
+ a dialog that never appears — an earlier build of this flow did exactly that and
59
+ the row spun forever. The preload bridge is the reliable door in the app; the
60
+ listing is what a browser gets instead of a spinner.
58
61
 
59
62
  The tray of the foot keeps the sign-in state (`GitHub · <login>`, or
60
63
  `GitHub · signed out`) next to the balance, so the account is visible without
package/lib/client.js CHANGED
@@ -41,7 +41,7 @@ window.__ModuleLoader__.load({
41
41
  ]
42
42
  const ROW_ID = "polish"
43
43
  const ROW_KEY = "@aryacode/dsh-aryacode-polish" + '#' + ROW_ID
44
- const CLIENT_VERSION = "0.6.0"
44
+ const CLIENT_VERSION = "0.6.2"
45
45
 
46
46
  /**
47
47
  * The two pure decisions behind the balance line: which wallet to show, and how
@@ -419,6 +419,24 @@ window.__ModuleLoader__.load({
419
419
  /** The label half of the pill, cut with an ellipsis rather than wrapped. */
420
420
  const PILL_LABEL_STYLE = { minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }
421
421
 
422
+ /**
423
+ * The menu skin of the harness, made opaque on purpose.
424
+ *
425
+ * `--dsw-specific-menu` is a translucent fill (`#f8f9fa94`) that only reads as a
426
+ * solid surface because the harness pairs it with `backdrop-filter`. A plugin
427
+ * face has to portal its panels to `document.body`, and in the AryaCode desktop
428
+ * build that blur does not composite: the panel then showed the page behind it
429
+ * through a 58% fill. So the token stays as a tint over an opaque backdrop
430
+ * colour, and the blur is kept only where the platform actually honours it.
431
+ */
432
+ const PANEL_SURFACE = {
433
+ backgroundColor: 'Canvas',
434
+ backgroundImage:
435
+ 'linear-gradient(var(--dsw-specific-menu, rgba(248, 249, 250, 0.94)), var(--dsw-specific-menu, rgba(248, 249, 250, 0.94)))',
436
+ backdropFilter: 'var(--dsw-menu-backdrop-filter, none)',
437
+ border: '0.5px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12))',
438
+ }
439
+
422
440
  /** The dialog surface, copied from the harness `stat-dialog.module.css` skin. */
423
441
  const PANEL_STYLE = {
424
442
  position: 'fixed',
@@ -428,10 +446,8 @@ window.__ModuleLoader__.load({
428
446
  minWidth: 'min(300px, calc(100vw - 24px))',
429
447
  maxWidth: 'min(440px, calc(100vw - 24px))',
430
448
  padding: '16px',
431
- border: 0,
432
449
  borderRadius: 'var(--dsw-radius-lg, 12px)',
433
- background: 'var(--dsw-specific-menu, Canvas)',
434
- backdropFilter: 'var(--dsw-menu-backdrop-filter, none)',
450
+ ...PANEL_SURFACE,
435
451
  boxShadow: 'var(--dsw-elevation-prominent, 0 10px 30px rgba(0, 0, 0, 0.18))',
436
452
  fontSize: '12px',
437
453
  lineHeight: '18px',
@@ -1231,16 +1247,33 @@ window.__ModuleLoader__.load({
1231
1247
  }
1232
1248
 
1233
1249
  /**
1234
- * Start the folder browser at the machine's roots.
1250
+ * Hand folder choice to the Host.
1235
1251
  *
1236
- * This deliberately does not call the Host's directory picker: a composed
1237
- * picker serves either `browse` or `native`, never both, and the browser build
1238
- * composes the one whose chooser cannot open there — a `pick` call would wait
1239
- * for a dialog that never appears. Our own listing behaves the same in the app
1240
- * and in the browser, and hands the chosen path back through `onPicked`.
1252
+ * In the desktop app the preload exposes the real OS chooser as
1253
+ * `__DSH_DIRECTORY_PICKER__.pick()` — the same bridge the shipped native
1254
+ * picker uses — so the flow opens the Windows folder dialog and behaves like
1255
+ * the stock picker it stands in for. In a browser there is no such bridge, and
1256
+ * the composed picker's `pick` waits on a dialog that cannot open, so the flow
1257
+ * lists folders itself instead of hanging.
1241
1258
  */
1242
1259
  const chooseOnPc = () => {
1243
1260
  if (busy) return
1261
+ const bridge = typeof globalThis === 'undefined' ? undefined : globalThis.__DSH_DIRECTORY_PICKER__
1262
+ if (bridge !== undefined && typeof bridge.pick === 'function') {
1263
+ setBusy(true)
1264
+ setError('')
1265
+ Promise.resolve()
1266
+ .then(() => bridge.pick())
1267
+ .then(path => {
1268
+ if (typeof path === 'string' && path !== '') {
1269
+ land(path)
1270
+ return
1271
+ }
1272
+ setBusy(false)
1273
+ })
1274
+ .catch(reason => fail(messageOf(reason)))
1275
+ return
1276
+ }
1244
1277
  setBusy(true)
1245
1278
  setError('')
1246
1279
  Promise.resolve()
@@ -1356,7 +1389,7 @@ window.__ModuleLoader__.load({
1356
1389
  padding: '6px',
1357
1390
  overflowY: 'auto',
1358
1391
  borderRadius: 'var(--dsw-radius-lg, 12px)',
1359
- background: 'var(--dsw-specific-menu, Canvas)',
1392
+ ...PANEL_SURFACE,
1360
1393
  boxShadow: 'var(--dsw-elevation-prominent, 0 8px 24px rgba(0,0,0,0.18))',
1361
1394
  fontSize: '12px',
1362
1395
  lineHeight: '18px',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aryacode/dsh-aryacode-polish",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "AryaCode Polish: one install for the small things that make AryaCode feel finished. One Plugins row, one switch per quality-of-life feature.",
5
5
  "keywords": [
6
6
  "dsh",