Commit Graph
9 Commits
Author SHA1 Message Date
Menghuan1918 5912274e41 feat: yield the terminal and browser to DSH 0.1.6's own sidebar types
DSH 0.1.6-alpha.2 ships a right-Sidebar terminal and a right-Sidebar browser
of its own. Both were things this plugin had built from scratch, so keeping
them meant two implementations of one surface plus a plugin that shadows a
host type the product is actively developing.

Terminal: the plugin's whole PTY stack goes — the UI-tab manager, the
agent-owned registry, the lazy node-pty loader, the eight model-facing
terminal_* tools, the xterm view and its font/link/scrollback helpers, and
the cross-session 'pinned terminal' rail that existed only to keep a terminal
alive across a session switch. The host's terminal kind becomes the only
provider, which also retires the node-pty dependency, its pnpm allowBuilds
entry, and the installer's -Repair mode (issue #140's whole class of
'node-pty failed to load' support).

Model-facing capability note: the plugin used to inject terminal_* tools
(off by default). Those are the model's only cross-call persistent terminal,
and DSH's own equivalent (@deepseek-ai/dsh-tool-terminal) is not mounted by
any shipped bundle, so removing them leaves the model with the one-shot
bash/pwsh tools only. That is the accepted cost of not maintaining a second
PTY surface; the README documents how to enable the upstream toolset.

Browser: the plugin's browser tab type is dropped, so the host's own browser
kind owns embedded pages. The DOM-level link takeover STAYS (it is the only
thing that can route an https link to the system browser by protocol, which
the host does not do) but now delegates to the host's browser tab via
ctx.sidebarRight.openTab('browser', …) with a window.open fallback, and the
two settings that only ever configured the plugin's own iframe (sandbox
escape hatch, loopback allowlist) go with it — along with the host-side
browser.probe route they fed.

Cards: the empty-pane welcome cards adopt the host's guide-capsule recipe
(0.5px l4 hairline, 24px radius, layer-1 fill, 56px floor, 14px/20px padding)
so the plugin's 'pick what opens here' surface reads as the same design as
DSH's own. A theme.spec guard pins the geometry and the token-only paint —
including that the upstream-only --dsw-alias-bg-l1/-l2 spellings (defined
nowhere, so their declarations are silently dropped upstream) never appear
here.

Also drops the dead state the removed features left behind (SidebarTab.pin,
nextTerminal, agentWaits, bottomOpenedOnce, the agent-tab helpers, the
pinned-tab memo key), re-points every test fixture that used them at
surviving equivalents, and prunes the specs of the deleted features.
2026-09-21 20:35:11 +08:00
Menghuan1918 7f2674ab70 docs+test: 对齐等待 banner 的注释/设计口径并钉住 skip-wait 的 404 契约
v0.19.0 发版前 review 发现两处「文档与实现互相矛盾」(均不改运行时行为):

- use-host-feeds.ts 的 effect 注释仍写「terminal tab 类型禁用时 pushes are
  ignored」,而 mirrorAgentWaits 恰恰改成了不忽略(只跳过 tab 增删 reconcile)。
  注释改为如实描述;
- 设计文档 §1 写「轮询每圈优先检查 skipped」,实现是 aborted → exited →
  skipped。维持实现现状(pty 已死是客观事实,两种顺序下用户可见结果——banner
  消失 / skipWait 归零 / 等待结束——完全相同,只有 kind 文案不同),设计原文
  同步为「退出优先」,并在实施偏差记录写清未采纳「用户意图优先」的理由与日后
  改动点;
- src/index.ts 的 agent-pty.skip-wait 注释把「无活动等待 → 0」泛化成了
  「幂等」,收窄为「无活动等待返回 {skipped:0};未知 uuid 走 expect → 404,
  客户端 .catch 容忍并等下一次推送收敛」。

另把 skipWait 未知 uuid 的既有断言从「只校验 /not found/ 文案」升级为
「SidebarError + status 404 + code not-found」——HTTP 层 writeError 直接把
status 映射成响应码,此前这条契约没有测试守护(把 404 改成 410 时新断言即
失败,已验证)。

验证:pnpm test 126 files / 1312 passed / 0 failed,tsc --noEmit 与 eslint
均 exit 0;改动面仅 5 个文件,src/client/service.ts、builtins/ 与
external-plugin-guide.md 继续零改动。
2026-09-10 22:26:02 +08:00
HuanLinOTO 22a0452a59 Merge origin/main into feat/wait-banner: resolve use-host-feeds import overlap
Conflict: src/client/sidebar/use-host-feeds.ts
- ours: import { mirrorAgentWaits, ... } from '../state.ts'
- theirs: same line + new import { isNarrowWidth } from '../breakpoints.ts'
Resolution keeps both imports; the two sides' semantic changes are in
disjoint regions (ours: tab-disabled wait mirroring; theirs:
activateTasksPage native-landing) and both survive intact.
2026-09-10 22:04:13 +08:00
HuanLinOTO 70a150794b fix: address Copilot review round 3 (code-point truncation, a11y live status, disabled-tab wait mirroring, test unmount, concurrent-wait test) 2026-09-10 21:28:22 +08:00
HuanLinOTO ccb89fd91b Merge origin/main into feat/wait-banner: resolve floats retirement + openTabInBottomPane 2026-09-10 18:21:09 +08:00
Menghuan1918 6c1efc1b00 fix(shell): land auto-activation in DSH's native right Sidebar
The two auto-open switches (a new subagent, a new background job) and the
topology jump-back opened the Tasks page with `target: 'bottom'` — the
plugin's own bottom workbench, i.e. the bottom bar. The right column IS DSH's
native Sidebar since v0.19.0 and every other open in this plugin already lands
there, so `service.ts`'s native branch was bypassed and the switches did NOT
do what their copy promises (README feature table + `settingsSubagentDesc` /
`settingsJobsDesc` in all 20 dictionaries: "wide viewports also expand the
sidebar, while narrow full-screen drawers are not forced open").

- use-host-feeds: one `activateTasksPage(ctx, sessionId, { background })`
  carries all three triggers and opens the Tasks page at the default (native)
  landing, so the host expands the column in the same step.
- Narrow viewports keep that promise: below 768px the host draws the column
  FULLSCREEN (`autoFullscreen = viewportWidth < 768`, `position: fixed;
  inset: 0`) and expands it on every open with no way to suppress it, so a
  BACKGROUND activation parks the tab — reads `ctx.sidebarRight.isExpanded()`
  first and puts the column back to collapsed in the same React batch (only
  for the mounted session, which is what that face acts on, and only when the
  user had it collapsed). The explicit jump-back is a user gesture and always
  takes the host's expansion.
- The bottom workbench keeps its own flows on `target: 'bottom'` (its `+`
  menu, the first-expansion auto-terminal); `OpenTabSeed.target` is unchanged.
- tests/sidebar-auto-activation.spec.tsx: asserts the native surface receives
  `openTab { kind: 'subagent', revealIfOpened: true }`, that the workbench
  stays closed and gains no tab, the park counts per width, the resize-before
  -fire read, and the jump-back's no-park. All 10 cases fail against the
  unfixed module.

Root cause: 223b254 (retire the plugin's own right panel, v0.19.0-alpha.0)
rewrote these three landings from the plugin's right pane to the bottom one.
2026-09-10 17:13:21 +08:00
Menghuan1918 223b2545d9 refactor(shell): retire the plugin's own right panel and free windows
DSH 0.1.5 owns the right column (its native Sidebar hosts every tab type
this plugin registers), so the plugin's own right panel, its width drag /
new-session seed prefs, and the free-window feature are gone. The bottom
workbench is the only plugin-owned surface left, and its expand/collapse
control is registered into DSH's session-header utilities list slot (the
header's corner seat belongs to the native sidebar's own control).

- state: one `bottomSplits` tree; `makeDefaultState()` takes no arguments;
  `toggleBottomPanel` / `openTabInBottomPane` are the only landing
  reducers; `setBottomHeight` and `sanitizeState` share the
  `CONVERSATION_MIN` cap (a persisted tall height no longer snaps on the
  first drag).
- service: every landing in the workbench (creation or focus) expands it;
  `SIDEBAR_FEATURES` drops `'floatWindows'`; the open/close/activate tab
  pools cover the single tree.
- shell: `Sidebar.tsx` renders only the bottom workbench; the toggle lives
  in `sidebar/bottom-toggle.tsx`; layout-push pushes height only (no width,
  no `--dsh-sidebar-width`).
- prefs: `openByDefault` / `defaultWidthPercent` / `changesDiffFloat`
  removed from the schema, defaults, client parser, settings page, and all
  20 dictionaries; the retired keys in stored documents are ignored.
- tests: free-window specs deleted, panel/float assertions dropped,
  remaining suites adapted (124 files / 1287 tests); the mount lane asserts
  the header toggle and sweeps the native sidebar's guide page.
- docs: README / README_EN / guide §0,§11 / AGENTS test map.
2026-09-09 15:18:06 +08:00
HuanLinOTO 1fa777293f feat(sidebar): 镜像 agent 终端等待状态到 agentWaits(瞬态) 2026-09-09 13:29:27 +08:00
Menghuan1918 d5b1201ad8 refactor(client): 抽取宿主推送与自动激活触发器到 sidebar/use-host-feeds.ts
Sidebar.tsx 拆分第三块:agent-terminals / agent-opens 两条 WS 推送
(含重连退避与失败上限)、子代理自动激活(去抖重估)、后台任务自动
激活、拓扑跳回(subagentJumpRef)连同 FAILURE_LIMIT /
AUTO_OPEN_DEBOUNCE_MS 常量原样迁出,注释逐字保留。Sidebar 侧仅
消费返回的 subagentJumpRef(renderTab 的 onSubagentJump 装填)。

行为不变:五个 effect 的依赖数组与闭包值逐字相同,hook 每 render
无条件调用,effect 挂载顺序保持(feeds → center → float →
bottomAuto → drag)。
2026-09-03 21:05:41 +08:00