bd11bad65c49abace57028d6f91648552b0ed435
14
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bd11bad65c |
feat: adapt to DSH 0.1.7-rc.1
Move the support line from 0.1.7-alpha.1 to 0.1.7-rc.1 (peer floor `^0.1.7-rc.1`). 0.21.0-alpha.1 never reached npm, and once the code-card labels below are fixed the same build crashes on alpha.1 (its DiffBlock still reads the `labels.files` upstream deleted), so declaring only the host we verify against is the honest floor — and from rc.1 on the host enforces peers at boot anyway: a row whose `@deepseek-ai/dsh-*` peers do not satisfy the runtime is silently disabled. Dependencies: 28 devDependency pins and 14 peers move to 0.1.7-rc.1. rc.1 also raised the vendored runtime (cordis 4.0.4, schemastery 3.18.4, cordis-plugin-group 1.0.4, cordis-plugin-include 1.0.9) and publishes DSH cross-references as exact versions, so bumping schemastery/cordis alone left four unmet transitive peers — the three vendor packages are hoisted into devDependencies, which is what makes `pnpm peers check` clean again. One compile break: rc.1 added `CodeToolbarLabels` (codeLabel / wrapLabel / unwrapLabel, all required), made DiffBlockLabels / ReadBlockLabels extend it and deleted `DiffBlockLabels.files`. Fixing SideChatView then leaving markdown on the legacy banner would render two different code-card styles inside one side-chat view, so the plugin adopts the card everywhere: `markdownTextProps()` now passes `labels.code.toolbarLabels` with the host's own wording (codeBlock.title|wrap|unwrap, added to all 20 dictionaries; `sideChatBlockFiles` retires with the deleted footer). Adopting the card surfaced a silent regression the suite caught: the new toolbar shows `codeLabel` for languages the highlighter does not know, and mermaid has no shiki grammar, so the info string no longer reaches the DOM and the banner-text probe in mermaid.tsx matched nothing — mermaid fences stopped being swapped for diagrams. Detection now matches the FENCE BODY from the source that produced the render. `tests/market-manifest.spec.ts` pins every DSH peer as a floating caret range: an exact pin (the devDependency style) or a comparator without a prerelease would fail rc.1's preflight and silently stop the plugin from loading, and `pnpm peers check` cannot see that — it validates the resolved dev tree, not the range shape the host reads. |
||
|
|
6586e3e2d3 |
feat: adapt to DSH 0.1.7-alpha.1 and yield the read-only previews
DSH 0.1.7-alpha.1 is 1299 commits past 0.1.6-alpha.2 and rewrites four
contracts this plugin was built on. The peer floor moves to
^0.1.7-alpha.1 (semver's prerelease rule means ^0.1.6-alpha.2 can never
match a 0.1.7 prerelease); 0.1.6-alpha.2 and earlier stay on v0.19.1.
Released as 0.21.0-alpha.1 (dist-tag alpha).
Hard breaks:
- dsh-settings was rewritten: register(ns, schema) is gone, a form is
addressed by the plugin row's Loader entry id and read from the
module's exported Config. The preferences are merged into Config and
marked volatile — which requires DSH's own schemastery, because only
that build wraps a volatile field in the cosmokit reference the
loader's volatile commit walks. With the public package a settings
write reports success and revision 1 while the effective value never
changes.
- ui-primitives renamed its whole icon family (IconXxx14/16 ->
IconXxxRegular/Medium): 26 imported symbols, 17 files. The failing
mode is render-time, not load-time. Five call sites that relied on the
old 14px default now pass size={14} explicitly.
- Session format v4 rejects source.kind === 'plugin'; the side-chat
boundary injection now writes plugin:dsh-better-sidebar, the same kind
DSH's own v3->v4 migration produces, so historical threads survive.
Tool results moved to role 'tool' with top-level content/isError; all
four parsers accept both shapes.
- The client session snapshot dropped subagentsByParent/jobsBySession
and the on-demand subagent-catalog observation API. The Tasks page
reads projectionsBySession and a new jobs.list route.
Yields and convergence:
- The read-only previews go to DSH's documentpreview (Office->PDF, a
spreadsheet worker, zoom, per-directory refresh); editor.canOpen
refuses those 26 extensions. Markdown, HTML (with its sandbox
switches) and the editable code buffer stay.
- The host browser kind is desktop-profile-only now, so the web e2e
lanes expect no browser entry and assert its absence.
- Link takeover claims only urlTarget links and passes the rest to the
host, fixing a regression from the 0.1.6 round: the fallback pointed
at a 'browser' type the plugin no longer registers, so http links in
its own markdown did nothing.
Also fixed, found along the way:
- The file tree refreshes live (new directory watch over the plugin's
own socket), since the plugin owns the `files` kind.
- ctx.sessions.list has no `current` field at either tag; the three
readers were dead. They now use ctx.sidebarRight.mounted.
- package.json.files was missing lib/client-locale.js.
- Two genuinely dead call sites: sessions.openSubagent/open/
refreshSubagents do not exist on the current baseline, so the
topology click, the jump-back and the retry were all no-ops.
- The test harness window shim lacked addEventListener, which the 0.1.7
primitives call at module-evaluation time; and the e2e token exchange
needs Playwright's request stack, not Node's fetch.
|
||
|
|
d60899841d |
chore(baseline): target DSH 0.1.6-alpha.2 and drop 0.1.5-rc support
The peer floor had to move: semver's prerelease rule needs a comparator on the same [major,minor,patch] tuple, so `^0.1.5-rc.1` can never match any 0.1.6 prerelease. The floor becomes `^0.1.6-alpha.2` (which does admit 0.1.6 alpha/rc prereleases and excludes 0.1.5), and `engines.dsh` follows. This is a deliberate support-line break, matching how v0.19.0 dropped 0.1.2: 0.1.5-rc hosts stay on 0.19.1. Three upstream changes actually reach this plugin and are adapted here: - `IconSendOutline16` no longer exists in ui-primitives (only `IconSendOutline14`). - `TerminalBlockLabels` gained a required `noExitCode` pill text. - `ConnectionIndicator` dropped `reconnectLabel`: the outage label is now the one static label that already names the retry action, so the label copy moves there, matching the host's own '连接异常,点击立即重连'. ui-primitives still declares no `dependencies` while its bundle bare-imports more than it used to: `diff` and `simple-icons` were previously satisfied only transitively and had to be hoisted into devDependencies, exactly like the anser/shiki/katex group before them. `@deepseek-ai/dsh-code-runtime` is gone upstream (the package no longer exists) and leaves the dev tree. The e2e fallback npx spec is pinned rather than version-less: an unpinned `npx @deepseek-ai/dsh` resolves npm's `latest`, which is still the 0.1.5 line this plugin no longer supports. |
||
|
|
ba0114749f |
feat(dsh): adapt to DSH 0.1.5-alpha.1
Move the plugin onto the DSH 0.1.5-alpha.1 baseline (peer floor ^0.1.5-alpha.1, CI pinned to the alpha dist-tag) and fix the two host contract changes that alpha line introduced. Baseline: - all @deepseek-ai/dsh-* peer/dev deps -> 0.1.5-alpha.1; optional peer @deepseek-ai/dsh-client-ui-sidebar-right (declared, unused until the native-surface phase); devDep @deepseek-ai/dsh-agent-loop (inbox fold) - dsh.plugin.json engines >=0.1.5-alpha.1; version 0.19.0-alpha.0; SIDEBAR_SERVICE_VERSION follows Live assistant stream (assistant/chunk is gone): - 0.1.5 publishes in-flight model deltas as process-local agent/assistant-stream frames instead of durable assistant/chunk events and embeds the settled stream in assistant/message / assistant/attempt. src/assistant-live.ts folds the frames into a bounded per-session buffer; sidechat.events serves the current attempt as `live` rows (replaced every poll, never a delta) and the transcript renders them; the inherited in-progress snapshot reads message content / attempt stream / live frames. Cold session reads (persistence.inspect is gone): - 0.1.5 reads a stored session through an explicit read handle (open(id,'read') -> handle.read() -> close()). src/session-store.ts owns that protocol; every cold read (sidechat transcript, cold-resume preset, session.cwd, changes replay) goes through it. Dead code and docs: - drop the remote.session.openWorkspacePath interception: 0.1.5's chat opens files through ctx.sidebarRight.openResource instead, so the wrapper had no caller and would hijack the host's "open in app" gesture; the interceptOpenPath pref, its settings row and its locale keys go with it - AGENTS.md §3 + external-plugin-guide.md describe the new baseline - vitest setup bridges Node's localStorage accessor to jsdom's store (the pre-existing 26 failures on Node >= 22) - desktop-layout e2e seeds through host RPC and types into the Lexical composer (0.1.5 replaced the textarea) instead of driving the directory picker Verified: pnpm typecheck / lint / build / test (124 files, 1327 tests) / check:consumer-types, plus pnpm test:mount against a real @deepseek-ai/dsh@0.1.5-alpha.1 host (18/18). |
||
|
|
1ec1565b13 |
refactor(client): 四处轮询站点迁移到 use-polling,语义逐一保持
- SubagentView useSubagentLive:self-scheduling(上一请求 settle 后才排 下一次,不重叠)+ 每代 AbortSignal + signal.aborted 拦迟到写入,行为 与原 disposed 标志等价(teardown 同步置 disposed 并 abort)。 - SideChatView:立即拉取 effect 与 2s 定时拆分——输入变化(含 running 翻转)仍先拉一次转录,运行中间隔 tick 拉转录+徽章;fetchThread 自带 的逐次 abort 与卸载 abort 原样保留。 - GitLens:可见时 2s 固定静默 tick,无初始突发(mount/scope 变更的完整 刷新在别处);refresh 身份变化照旧重启间隔相位。 - ChangesTab:输入变化即拉一次(含隐藏态翻转),可见时 2.5s 固定间隔; pull 内部 pollGen 代际守卫不动。 守护 spec 全绿:subagent-live-polling + subagent-jobs-view 13/13、 sidechat-view + sidechat-transcript 29/29、git-view-worktree + changes-tab + changes-ops 13/13;断言零改动。 |
||
|
|
5a1e75e46b |
fix(lint): 清零存量 lint 告警并接入 CI / Makefile 门禁
存量清理(首跑 141 errors / 21 warnings → 0 / 0): - 删除孤儿 disable:SideChatView / Sidebar / selection-popup 三处 exhaustive-deps 豁免与 chunk-artifact 的 no-new-func 豁免(多行理由注释把 disable-next-line 顶离了实报行;selection-popup 改为提取 popupOpen 标志真修复) - 死代码:未用导入(Sidebar×7、TextEditor、SideCardSection、config、fs-operations 及 6 个 spec)、sidechat-core 死累加器 total、chunk-loader.spec 死助手 registry、sidechat-seed-validation 死助手 toolResultMessage - 真实小修:agent-opens 三处 throw 补 cause;lazy-chunk any → ComponentType<P>(P extends object);service.ts claimed 初值改定值赋值;chunk-loader task / spec 内 etag / pendingLoad / snapshot 改 const;terminal-links 去掉字符类内多余转义;SubagentView catalogs 空兜底 useMemo 稳定标识;editor-host.spec 组件提出大写 FakeViewer(rules-of-hooks);pty-helpers.spec 内联 require 提升为静态导入;panel-host-css 注释里的零宽空格改为可见写法 - 依赖数组豁免(均带理由):granular scope 字段(EditorHost / PdfView / ChangesTab / GitLens×2)、job.status 粒度(SubagentView×2)、清理期读 ref、mount-only 注册等;ctx(挂载期恒定)直接入 deps(Sidebar×3)、TextEditor previewScroll 补 scope(幂等) - 刻意控制字符正则(conversation-draft / markdown-images)与宿主槽位 any 签名(context-types)以带理由豁免保留 接入: - Makefile:lint 目标(typecheck 旁),check 聚合补 lint 保持「对齐 CI」语义 - ci.yml ci / ci-windows 两 job 与 release.yml 在 Typecheck 后加 Lint 步骤(release 注释同步顺序) |
||
|
|
b7af498427 |
perf: stabilize renders (transcript row reuse, tree Sets, shared + options, batched drags)
SideChat transcript: every 2s poll rebuilt ALL row objects, so every row (markdown parse + DOMPurify included) re-rendered even when the log had not changed. transcriptRows now takes the previous poll's rows and re-adopts the position-aligned rows whose content is identical (reuseRows) — only the changed tail rebuilds. The view feeds the memoized array back through a ref; unit tests pin the identity contract (unchanged rows keep object identity, changed rows and everything past the change rebuild, tool-result landings never re-adopt). FileTree: expanded/revealed membership was an includes() scan per rendered row (O(rows × expanded) per render on deep trees); one Set per render keeps it O(1) per row. Shell: buildNewTabOptions was inlined in the two Workbench JSX sites — two fresh arrays per render (drag state, resizes) re-rendered every LeafView's + affordance. One shared memo now. DiffPane resize / TerminalView ResizeObserver: pointer and resize streams fired a setState / glyph-measuring fit() per event; both ride per-frame batching now (frame-batcher in the core, a local rAF gate in the lazy terminal chunk). SessionLens sizes each row's content with a Blob (a UTF-8 encode of the whole edit) — that moved from per-row-per-render into one memoized pass per changed fold. |
||
|
|
a48459c5de |
feat(sidechat): tool-kind leading icons on tool rows
The main conversation's tool row head is a 16px leading slot with the tool-kind glyph at 14 (GenericToolCard's variant table), swapped for an error StateDot on failed rows. Mirror it: bash/pwsh -> IconApiOutline14, read/web_fetch -> IconBrowseOutline16, edit/write -> IconEditOutline16, grep/glob/web_search -> IconSearchOutline16, anything else -> IconSparkle16, all from the ui-primitives module seed; CollapsibleRow gains the matching icon slot. Thinking/injection rows keep their bare chrome (the host's equivalents are a different row family). |
||
|
|
561ad66071 |
feat(sidechat): main-conversation Blocks, turn usage tail, reconnect banner
Rendering-layer upgrade for the Side Chat transcript (data already rides the raw events; the mapping just stopped discarding it): - Tool rows with a derivable structure now render the host's ui-primitives atoms instead of a generic double <pre>: bash calls map onto TerminalBlock (command from call args, output + exit pill recovered from the result's trailing exit marker), edit/write map onto DiffBlock (call-time literal replacement, refined by the result meta's contextual hunks), read maps onto ReadBlock (line-window meta, same semantic narrowing the host applies). Every narrowing declines to the generic row on malformed input. - turn/end now emits a turnSummary row: token usage aggregated from assistant/message.usage (output summed across steps, input from the last request) plus the envelope-time wall duration, printed with the main conversation's formatTokens/formatDurationMs cadence. - The client entry injects 'connection' (DSH 0.1.2-alpha.2+) and the thread view shows the host's ConnectionIndicator while the Remote transport is down; the reconnect control calls reconnect() and a disconnected -> connected transition pulls the transcript immediately instead of waiting for the next poll tick. 19 new locale keys propagated across zh/en and all 19 third-language dictionaries; unit coverage in sidechat-transcript.spec and a new sidechat-view render spec (jsdom). Real-host mount smoke: 14/14. |
||
|
|
28447ca2e8 |
fix(sidechat): read the transcript through the plugin's own events route
DSH 0.1.2-alpha.1 removed the client `ctx.connection.api` face (Remote gateway migration), so every Side Chat transcript poll (`sessions.history`) threw TypeError into the view's catch and was swallowed — the tab rendered an empty transcript forever, silently (no console error, so the mount lane never caught it). The successor APIs are not a drop-in either: session/follow|page reject plain session addresses for origin:'subagent' logs (agent-busy fence) and paging cannot read past the current cursor. Move the transcript to the plugin's own wire — one transport for every DSH generation: - new `sidechat.events` route: live threads read the in-memory `agent.session.events`; cold threads read `sessionPersistence.inspect` (both seams exist since 0.1.0-rc.8; alpha.1's inspect returns the expanded logical log, never the packed chunk-row encoding). The inherited seed is cut host-side (`threadOwnLogEvents`), polls ride an `afterSeq` delta, and the response is tail-capped at 8000 events (the old client walk ceiling). - SideChatView.fetchThread is single-path; collectOwnEvents (the client walk) is gone, and so are the ctx.connection mirror and inject entry (no consumer left). - transcriptRows keeps re-cutting at session/end-seed as defense in depth. Verification: - unit: sidechat.events route (seed cut, afterSeq delta + never resurrecting the seed, cap, cold/live sources, 404/503/bad-request), full suite 1104 passed; typecheck and build (purity gate) green. - mount e2e vs a real dsh-v0.1.2-alpha.1 source build: 14/14, including the Side Chat tab sweep polling sidechat.events (performance resource assertion) and live + post-dispose (persisted) route reads. - mount e2e vs PATH dsh 0.1.0-rc.8: 14/14 (no regression). |
||
|
|
6cfe7a736f |
feat: adapt to DSH 0.1.2-alpha.1 (Remote gateway + token auth + MarkdownText labels)
Dual-version compatibility: the plugin now works identically on
0.1.0-rc.8 ~ 0.1.1-rc.2 and 0.1.2-alpha.1 (the latter verified against a
source build of the dsh-v0.1.2-alpha.1 tag: mount smoke 14/14 + aggregate
double-mount; 0.1.1-rc.2 re-verified 14/14).
- MarkdownText: alpha.1 renamed the flat optional `codeLabels` prop to a
required nested `labels: { code: {copyLabel, copiedLabel}, footnotes }`;
the old prop alone crashes fence rendering with "reading 'code'". All
four render sites (mermaid / MarkdownHtml / TextEditor / SideChatView)
now go through src/client/markdown-labels.tsx (dual-shape object passed
under both prop names).
- e2e mount lanes speak both host dialects (tests/e2e/host-protocol.ts +
host.ts, unit-locked by tests/e2e-host-protocol.spec.ts):
- one-time-token browser auth: the launch URL grep extends past the
`/?token=` query (truncating at `/` loses the token), goto navigates
the token URL (browser cookie exchange), and stamped navigations
pre-seed the context cookie via addCookies — the exchange 303 drops
sibling query params;
- Remote gateway: dot endpoints first, slash endpoints on 404 fallback,
with args keyed by the controller parameter name (workspace/create ->
{request}, session/list -> {_request}; verified on a live host).
- package.json: drop the @deepseek-ai/dsh-client-runtime peer (package
removed upstream in alpha.1; zero references in the source — the chunk
externals entry stays and is resolution-tolerant).
- scripts/e2e-mount.sh: fix a latent set -u crash in the npx fallback
branch ($DSH_CMD followed by a full-width comma parsed as part of the
variable name).
- CI pin stays at @deepseek-ai/dsh@0.1.1-rc.2 until alpha.1 publishes to
npm (comment updated); README/AGENTS document the new contracts.
- Version lockstep bumped to 0.17.1.
|
||
|
|
197b10a3fe |
fix(sidebar): read betterSidebar via ctx.get() in all internal consumers
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. |
||
|
|
b7aab48deb |
feat(sidechat): Codex 风格转录重构 — 首问显示 / 注入拆分 / 折叠行 / 弹窗去抖 (#314)
* fix(sidechat): split context injection from the first user message The first composer message rode the same user/message event as the side boundary prompt (+ parked snapshot), and the transcript dropped that whole row by its boundary prefix — swallowing the user's first question. Deliver first contact as TWO messages: the boundary+snapshot rides agent.inject (queued next-step context, claimed first at the opening step, no wake) stamped with source kind 'plugin', and the question is the follow-up that wakes the driver. The log records injection and question as separate events; the transcript maps injections (plugin-sourced, or the legacy boundary-prefix blob of pre-split threads) onto a collapsible injection row and renders genuine user messages — the first one included — as user rows. boundaryDelivered still recognizes the injection by its unchanged boundary-prefix opening. * feat(sidechat): codex-style collapsible rows and creating shimmer Tool calls, thinking and context injections now share one quiet single-line chrome (chevron + label + a one-line argument summary) that expands into an indented body on a hairline thread — no cards or fills. Streaming labels and the creating hero shimmer (shimmer = generating); failed tools go danger; reduced-motion stills every loop. * fix(sidebar): debounce subagent auto-open past the title frame The host delivers a new child's origin and title in separate frames, so a Side Chat thread's first visible frame lacks its 'Side: ' label and tripped the 0→N auto-open — every thread creation popped the task page. The trigger now rearms for 500ms and re-evaluates the original baseline against the live snapshot, by which time the title filter recognizes the thread. Genuine subagents still auto-open, half a second later. * fix(sidechat): render legacy threads' first message as its own bubble Threads created before the host split still log the boundary (+snapshot) and the question as ONE 'user' message; the transcript mapped that row wholly onto the injection row, so the user's first question only appeared inside the expansion. The boundary prompt is a known constant, so the legacy row now splits THERE: the injection row keeps the prompt, the remainder renders as the user's real message (a pre-split snapshot, when present, rides along — the common case is a pure question). Row React keys become kind:seq so the split's two rows never collide. |
||
|
|
7f4f84c4cf |
feat(sidechat): 侧边对话——每对话一 Tab(Codex 对齐)+ 完整上下文继承 + 保存为新会话 (#286)
三轮实测驱动迭代:种子信封透传(surfaceOp 校验)、每线程一 Tab 交互重做完、四连修(fork 丢 this / 自绘 history+save 图标 / collectOwnEvents 大页回源修重开丢工具行 / descriptor 入种子修目录 corrupt 行 + 前缀过滤保拓扑零噪音)。739 单测 + 挂载冒烟 12/12 全绿。 |