Issue #611 asked for file-type icons like the official explorer's, and #429
built a colored theme for them. DSH 0.1.5-rc.2 makes most of that work
unnecessary: `@deepseek-ai/dsh-client-ui-primitives` now exports
`FileTypeIcon` / `CodeFileIcon` with the host's own 48-type full-color code
artwork plus category-colored sheet glyphs (and its classifier behind them).
So the plugin renders the host's icons instead of shipping a color table, and
color becomes the only behaviour rather than an opt-in theme.
File icons (src/client/file-icons.tsx)
- `builtinFileIcon(path, size)` → `<FileTypeIcon path size />`; folders use the
host's folder category. The plugin's own per-extension VSCodicon map is gone.
- The public `registerFileIcon` API from #531 is unchanged and still outranks
the built-ins, so an external plugin can take over any row. One semantic
consequence, now documented and tested: because the host classifier covers
every path, a registered catch-all (`exts: []`) claims rows it used to lose
to the built-in map. An unregistered catch-all (the old icon theme's shape)
is unaffected.
- Nothing is lazy any more: the artwork lives in a platform module the client
already holds, so `lib/client-file-icons.js` and its 563-entry dataset (255
kB) are deleted outright — the core bundle grew by 10 kB (0.85 → 0.86 MB).
- `src/client/file-icon-theme.ts`, the `fileIconTheme` pref (prefs-shared /
config / client prefs), the settings-page select row and the six
`settingsFileIconTheme*` keys in all 20 dictionaries are removed with it.
Tab glyphs (src/client/builtins/tab-icons.tsx)
- Every built-in tab type now declares a colored glyph: files (the host's
folder artwork), changes/diff (commit), tasks (checklist), side chat
(discussion), terminal (shell), browser (globe).
- The color comes from a `--dsw-alias-*` token through a wrapper class, never
from a literal — the skin contract (§12) holds and `tests/theme.spec.ts`
enforces both halves (no literals in the module, every color declaration in
the stylesheet resolves to a token).
Native right Sidebar chips (src/client/native/tab-adapter.tsx)
- The host's tab definition has no icon field, but the
`sidebar.right.pane.tab.title` slot IS the chip's content, so the plugin
draws the glyph itself: an editor tab with a path shows that file's icon,
every other tab shows its descriptor's icon — the same `descriptor.icon` the
workbench strip and the guide capsules already render, so the three cannot
drift. The glyph is `aria-hidden`, which keeps the chip's accessible name
exactly the title the mount lane matches on.
Gates: typecheck / lint / check:consumer-types green; pnpm test 127 files /
1342 passed / 9 skipped (3 new chip cases, 1 rewritten built-in case).
First ci-windows run exposed four platform assumptions in the fixtures:
- smoke: the scratch repo inherited the runner's system-wide
core.autocrlf=true (Git for Windows default), so every index restore
smudged LF to CRLF and broke the byte-exact assertions — pin
core.autocrlf=false in the fixture (eol policy is not what these
destructive-op tests are about).
- git / git-worktree: Windows TEMP is the 8.3 short form
(C:\Users\RUNNER~1\...) while git reports long paths, and
realpathSync does not expand 8.3 aliases — switch the canonicalizer
to realpathSync.native (libuv resolves via GetFinalPathNameByHandle,
which does); same trick as the existing macOS /var workaround.
- bundle-route: the ETag memo revalidates on stat (mtime+size) and
Windows updates file timestamps lazily, so the equal-size rewrite
still looked unchanged — change the length too.
- market-manifest: GNU tar (Git Bash) reads the drive-letter colon of
absolute Windows paths as a remote-host spec — run it from the pack
dir with the bare tarball name instead.
The core client bundle statically imported every third-language
dictionary (ja/de/fr/…/zh-HK/MO/TW, ~640KB of source — roughly half
the bundle's weight) for a code path most sessions never enter: the
sidebar's own t() only consults zh/en plus the better-locale override
store, and the dicts' ONLY consumer is that store's register() call.
They now ride the existing lazy-chunk machinery as lib/client-locale.js
(fetched from /sidebar/bundle only when better-locale is actually
installed; a generation counter keeps the async registration moot when
the integration effect re-runs or disposes mid-flight). Until the chunk
lands, t() keeps the zh/en chain; the store's own revision bump on
register re-renders the chrome once the dicts arrive.
Core client.js: 1.46MB → 822KB (-44%). The chunk-boundary key-set
check moves to the existing runtime test (every shipped dict stays
key-set-equal to zh).