Adapted to HEAD's unified editor+explorer tab: the reveal gesture now
opens the editor home tab (the files window) instead of the deleted
explorer type. PR's revealInExplorer implementation, produced-files
engine-data selector, and tests are retained verbatim.
New global Side card setting `agentOpenTools` (default off, 常规 group):
when enabled, one `sidebar_open` tool is injected into the model so it can
actively open a local file, a local folder (tree rooted there), or an
HTTP(S) page in the calling session's sidebar.
- host: AgentOpenRegistry + registerOpenTool (src/agent-opens.ts); the tool
classifies http(s) URLs / stat-driven file/folder paths, refuses other
schemes, resolves relative paths against the session cwd, and reports
target-tab-disabled instead of silently no-oping. Gated like
agentTerminalTools (register/drain on settings watch).
- delivery: /sidebar/ws/agent-opens push (consume-on-send queue, replay on
attach); the tool result reports `delivered` so queued opens for
non-active sessions are honest.
- client: Sidebar subscribes and routes pushes to editor (file), folder
window (meta.dir, tree rooted at the folder — EditorHost), or browser
(URL) tabs; settings row in 常规 + 20 locale dictionaries.
- tests: agent-opens registry/tool spec, smoke gating + WS route list,
prefs/plugin-shape defaults, editor-host folder window, side-card rows.
- docs: design doc, AGENTS.md key lists + reference, README feature bullets.
Under the DSH 0.1.1-rc.x web shell, the Cordis plugin loader registers
the provided betterSidebar impl on a neighboring fiber that is not on
the rendering fiber parent chain, so every direct ctx.betterSidebar
read inside the plugin own tree throws
cannot get property "betterSidebar" without inject
and the panel dies inside RenderBoundary on page load (observed with
0.14.0 and 0.15.2 on npm-installed dsh 0.1.1-rc.2). This is the same
failure class #135 fixed for the dsh-web-mobile path; declaring
betterSidebar in the plugin own inject would deadlock the fiber (it
waits for the service before running apply, but the service is only
provided inside apply).
ctx.get() resolves through the root reflect store and is unaffected by
the fiber chain, so all 26 internal reads switch to it. External
consumers keep using ctx.betterSidebar after injecting it, unchanged.
Test mocks gain a matching get() shim.
#1 GitView: hide/disable 'open in editor' for external linked worktrees
(path outside session workspace is rejected by the fence); add
isWithinWorkspace client helper for the gate.
#2 DiffTab: untracked diff read resolves against diff.repoRoot (child-repo
paths are repo-root-relative, not cwd-relative); fs.read route threads
selectedRepoOf into resolveGitPath so the host resolves the right base.
#3 GitView: chooseRepo handler mirrors chooseWorktree — clears status/
history/log and bumps generation before async refresh, preventing stale
rows from acting on the newly selected repository.
#4 git.ts: repoRoots/repoRoot compare roots via pathIdentity() (platform-
aware) instead of raw includes(), fixing win32 forward/backslash
mismatch that silently fell back to roots[0].
#5 markdown-images: mask fenced code blocks and inline code spans before
rewriting; only rewrite reference definitions whose label is actually
referenced by image syntax (not plain links). +3 tests.
#6 package.json: downgrade unrun ^0.3.1 → ^0.2.39 (0.3.x requires Node
^22.13, incompatible with declared engines >=20).
#7 market-manifest.spec: shell:true on win32 so execFileSync resolves the
pnpm .cmd shim.
#8 smoke.spec: build html-route URL via encodeHtmlUrl() (production
encoder) so the Windows drive separator is correct.
#9 index.ts git.worktrees route: thread selectedRepoOf so a workspace
container's selected child repo's linked worktrees appear.
PR #285 added the zh/en 'worktree' key but the 19 third-language dicts
(de/fr/pt/ko/ar/hi/id/tr/vi/th/ru/it/nl/sv/pl/zhHK/zhTW/zhMO) were missing
it — only ja was patched in the prior commit. The dicts are typed
Record<keyof typeof zh, string> via an unchecked 'as' cast, so tsc did
not catch the gap.
This commit:
- adds the worktree translation to all 19 dicts
- strengthens tests/locales.spec.ts to assert key-set equality for EVERY
shipped dictionary (not just zh/en/ja), preventing future regressions
* feat(editor): file tree 'open with' submenu (external editors, pin, SSH-remote, custom editors)
The file tree right-click menu gains an 'Open with >' submenu with the
resource manager (reveal in file manager), VS Code, Cursor and Zed, plus
user-defined custom editors (name + URL template + VSCode-family flag).
Each submenu row carries a pushpin that promotes the target to a direct
top-level menu item.
A configurable SSH host (settings: Files card gear) switches VSCode-family
openers to <scheme>://vscode-remote/ssh-remote+<host>/<path> and hides
host-local targets (file manager / Zed / non-VSCode custom editors).
External opens run through the new fenced /sidebar/api/open.external route
which spawns the platform opener with an argv array (no shell); the client
never navigates raw scheme URLs itself. The settings seam's render panel now
appends after the declarative rows instead of replacing them.
* feat(editor): polish open-with menu UI — brand icons, pushpin, chevron, row alignment
- Submenu rows: the custom label is now a block-level flex row filling the
primitives itemLabel, so the pushpin docks at the row's far right (matching
the trailing check of every other menu); menu row icons normalized to 16px
(DSH native menus use 16, ours were 14).
- The submenu parent row gains a right-aligned chevron (the primitives Menu
renders no arrow for submenu parents).
- Icons via react-icons: codicons VscPin/VscPinned pushpins (replacing the
hand-drawn pin), VscFile/VscFolder/VscFolderOpened tree glyphs (replacing
the </> file mark), VscLinkExternal for the open-with parent and the
browser tab's open-external button (globally), SiCursor/SiZedindustries
brand silhouettes; the VS Code mark is inlined from simple-icons@11.0.0
(CC0) as IconVscode16 since later simple-icons releases dropped it. All
monochrome currentColor to follow the active skin.
- tsdown: pin react-icons si/vsc to their ESM entries via resolve.alias —
the package's exports map lists require before import, so the shared
conditionNames picked the unshakeable CJS entry and bloated the core
bundle by ~6.4 MB; tree-shaken it now adds only ~12 KB.