Repository navigation
Releases
Releases · dsh-labs/kivotos
v0.6.1
Highlights
- The Restart dsh dialog lines up. Its own stylesheet was only ever rendered by the restarting overlay and the back-online notice, so the dialog's empty-state line, its task list and its buttons row fell back to no padding: the line started at the dialog's edge while the title and description were indented. The dialog now renders that stylesheet itself and every line — title, description, empty state, running tasks, buttons — sits in the dialog's body and foot on one 24 px grid.
- The dialog fits a phone. Its width is bounded by the viewport, its height by the dynamic viewport with the safe-area insets respected, the title wraps instead of clipping, the buttons share one row (each at least 44 px tall) and the close control keeps a 44 px target. The desktop app's dialog and the phone layout use the same component, so both get it.
Fixes
- Restart dialog: empty-state text and buttons were flush with the dialog's left edge and had no gap to the body (0.6.0).
- Restart dialog: content could exceed a phone's viewport height with the buttons row unreachable; it now stays inside it.
Compatibility
- DeepSeek Harness
>=0.2.1-rc.5 <0.3.0-0. Presentation only: no endpoint, protocol, config or relay change. Colours come from the user's dsh theme and are untouched.
中文
- 「重启 dsh」对话框对齐了。该对话框自身从不渲染重启样式表(只有「正在重启」遮罩和「已恢复在线」提示会渲染),所以空状态行、任务列表和按钮行都没有内边距:文字顶在对话框左边缘,而标题和说明是缩进的。现在对话框自己渲染样式表,标题、说明、空状态、运行中的任务和按钮全部落在对话框 body / foot 的同一套 24 px 网格上。
- 对话框适配手机:宽度受视口限制,高度受动态视口限制并避开安全区,标题换行而不被裁切,按钮同处一行且高度不小于 44 px,关闭按钮保持 44 px 触达面积。桌面应用与手机布局用同一组件,两边同时生效。
What's Changed
Full Changelog: v0.6.0...v0.6.1
v0.6.0
Highlights
- Approve or deny from the notification, when — and only when — the notification maps to an exact tool call. The phone shows 允许本次 / 拒绝 on an approval notification whose request carries the tool call it decides; a question, an approval without a call, or one another answerer already took stays a reminder and is answered in the session's own page.
- The answer travels through the same admission as everything else:
POST /kivotos/approve {token, decision}behind the listener's or the relay session's fence, and the token names exactly one held ask, so a stale notification only gets404. The Host's own page keeps working: its answerers run first, and only an ask they leftunavailableis held for the phone (for up to 10 minutes, cancelled at once if the turn withdraws it).
Fixes
- None.
Compatibility
- DeepSeek Harness
>=0.2.1-rc.5 <0.3.0-0. Notification buttons need Kivotos 0.6.0 on both the phone and the machine; an older Host sends no approval action and the notification stays a reminder. The relay and its protocol are unchanged.
中文
- 通知栏可直接「允许本次 / 拒绝」——仅当这条通知精确对应某一次工具调用时。审批请求带上了它所决定的工具调用,才会出现两个按钮;提问、没有工具调用的审批、以及已被页面上答过的请求,仍然只是提醒,需要进会话页面处理。
- 回答走与其他请求相同的准入路径:
POST /kivotos/approve {token, decision}位于监听器或 relay 会话的准入检查之后,token 只对应一个待决请求,过期通知只会得到404。页面本身的审批不受影响:页面内的回答者先运行,只有它们都答不了(unavailable)时才交给手机,最多保留 10 分钟;对应回合撤回时立即取消。
What's Changed
Full Changelog: v0.5.0...v0.6.0
v0.5.0
Highlights
- The session stream now compresses.
/api/remote.mux— the WebSocket that carries events, session history and RPC — runspermessage-deflateend to end when dsh and the browser both support it (dsh 0.2.2-rc.1 does; Kivotos forwards the handshake and frames unchanged), and Kivotos compresses the hop to the browser itself when the Host is an older dsh that has no compression. The mux is uncompressed today on such a Host: one 600 KB history snapshot plus a few hundred streaming deltas cost 876–878 KB. Measured on a rate-limited link with a 600 KB history snapshot and 300 streaming deltas: 876 KB → 258 KB at 60 ms/10 Mbps (first byte 1.02 s → 0.37 s) and 878 KB → 259 KB at 300 ms/1 Mbps (6.87 s → 0.65 s). Real history frames are mostly repetitive JSON, so they compress better still. - Nothing is compressed twice: a Host that negotiates the extension keeps the end-to-end path. Messages under 1 KB and context takeover are left out, so a small RPC round trip is unchanged and no stream has to be buffered.
Fixes
- None.
Compatibility
- DeepSeek Harness
>=0.2.1-rc.5 <0.3.0-0. The relay, its protocol and the Android app are unchanged; the plaintext boundary is the same as before (loopback, WireGuard or the relay's inner TLS). - New config
muxCompression("auto", the default, or"off").offsends no offer and strips one, leaving both hops plain.
中文
- 会话流现在会压缩。
/api/remote.mux(承载事件、会话历史和 RPC 的 WebSocket)在 dsh 与浏览器都支持时端到端启用permessage-deflate(dsh 0.2.2-rc.1 支持;Kivotos 原样转发握手与帧),对没有压缩能力的旧版 dsh,则由 Kivotos 自己压缩到浏览器这一段。在限速链路下实测(600 KB 历史快照 + 300 条流式增量):60 ms/10 Mbps 下 876 KB → 258 KB(首字节 1.02 s → 0.37 s);300 ms/1 Mbps 下 878 KB → 259 KB(6.87 s → 0.65 s)。真实历史帧是高度重复的 JSON,压缩率还会更高。 - 不会重复压缩:Host 自己协商成功时保持端到端直通。小于 1 KB 的消息、以及上下文接管都不启用,小 RPC 往返不变,也不需要缓冲整条流。
What's Changed
Full Changelog: v0.4.1...v0.5.0
v0.4.1
Highlights
- Relay failures no longer kill dsh. A relay peer that disappears, stalls past the ping timeout, or answers a WebSocket after the member gave up used to surface as an uncaught
errorevent and exit the whole dsh process — one dropped link and a remote user's dsh was gone. Each failure now closes only that relay session, the link reconnects with backoff, and the reason is recorded in the log and the link's status.
Fixes
- Relay streams carry a guard that handles an unobserved
error(between two reads, an idle pooled HTTP socket, a WebSocket the relay answers after its caller gave up), on the stream itself and on the TLS sockets a secured session returns;relayAgentreports a refused connection through its callback instead of a rejection. - The control connection's silence deadline is configurable:
relaySilenceSeconds(30..600, default 70 — the protocol's own 20 s ping with three misses). Raise it on a link whose queue (bufferbloat, a saturated uplink) can run longer than that. - Regression tests (
test/relay-crash.test.ts) run each failure mode in a child process and fail if the process exits.
Compatibility
- DeepSeek Harness
>=0.2.1-rc.5 <0.3.0-0, unchanged. The relay protocol and the Android app are unchanged; no relay image rebuild is needed.
中文
- relay 断链不再拖垮 dsh。对端异常断开、卡过 ping 超时、或 relay 在成员放弃之后才接下 WebSocket,原来会变成未捕获的
error事件让整个 dsh 进程退出——断一条链路,远控用户就失联了。现在每次失败只关闭那一个 relay 会话,链路按退避重连,原因写进日志和链路状态。 - relay 流现在自带保护:两次读之间、HTTP 连接池里闲置的、以及成员已放弃后才建立的 WebSocket,它们的
error由流自己处理;relayAgent用回调返回失败,不再产生未处理的 rejection。 - 控制连接的静默超时可配置:
relaySilenceSeconds(30..600,默认 70,即协议 20 秒 ping 的三次未应答)。链路排队时间(bufferbloat、上行拥塞)更长时可以调大。 - 回归测试(
test/relay-crash.test.ts)把每种失败放进独立子进程运行,进程退出即测试失败。
What's Changed
Full Changelog: v0.4.0...v0.4.1
v0.4.0
Highlights
- Safe restart: restart dsh from Machines → Restart dsh… (computer and phone) or
/kivotos restart [now|idle|status|cancel], even when you are only connected remotely. A detached helper outlives dsh, asks it to quit cleanly, starts it again, and checks that Kivotos answers again, retrying the launch up to three times; the page shows a "restarting" cover, reconnects by itself, and then shows "back online" with the dsh version and the plugins that changed. Log:$DSH_HOME/kivotos/restart/restart.log. - The dialog lists the running sessions and jobs and offers Restart when idle (waits until nothing runs, cancellable) or Restart now.
Breaking changes
- None.
Fixes
- None.
Compatibility
- DeepSeek Harness
>=0.2.1-rc.5 <0.3.0-0. Restart is supported for the macOS desktop app (relaunched through LaunchServices) and fordsh webstarted from a terminal (same command line again); it is refused, with the reason, on Windows, under systemd, and for a desktop app started with extra arguments. - When the desktop app would ask for quit confirmation (running tasks or armed reminders), nobody can answer it remotely: Kivotos waits 15 s and then force-quits the window process. The Host still shuts down cleanly and finishes its session logs. The log and the state file record that this happened.
中文
- 安全重启:可在「机器 → 重启 dsh…」(电脑和手机)或
/kivotos restart [now|idle|status|cancel]重启 dsh,仅远程连接时也可用。独立的辅助进程比 dsh 活得久:让 dsh 正常退出、再启动、确认 Kivotos 重新可用,启动失败最多重试三次;页面显示「正在重启」,自动重连,恢复后提示 dsh 版本和有变化的插件。日志:$DSH_HOME/kivotos/restart/restart.log。 - 对话框列出运行中的会话和任务,可选「空闲时重启」(等待全部结束,可取消)或「立即重启」。
- 支持 macOS 桌面端(通过 LaunchServices 重新打开)和终端启动的
dsh web;Windows、systemd 下及带额外参数启动的桌面端会拒绝并说明原因。桌面端需要退出确认时(有运行中的任务或已设定的提醒),远程无法点击,Kivotos 等待 15 秒后强制结束窗口进程,Host 仍会正常关闭并写完会话日志。
What's Changed
Full Changelog: v0.3.1...v0.4.0
v0.3.1
Highlights
- Support DeepSeek Harness 0.2.2-rc.1, the release the desktop app ships now. The index rewrites, the page probes, the desktop boot guard and every adapter marker were re-verified against it, and the pinned index fixture is re-captured from it. 0.2.1-rc.5 keeps working.
Breaking changes
- None.
Fixes
- Session titles in the phone's notifications and the switcher's attention badges are read from dsh's
sessionTitleservice instead ofsessionProjections.stateOf(session, "title"), which dsh 0.2.2 deprecates and logs a warning for on first use. - The plugin manifest now declares
engines.dsh(>=0.2.1-rc.5 <0.3.0-0), so dsh's plugin manager checks the supported range itself instead of loading Kivotos into a release it was never verified on.
Compatibility
- DeepSeek Harness
>=0.2.1-rc.5 <0.3.0-0(verified on 0.2.1-rc.5 and 0.2.2-rc.1). The Android app and the relay are unchanged; an existing 0.3.0 app and relay keep working with this plugin.
中文
- 支持 DeepSeek Harness 0.2.2-rc.1(桌面端当前随附的版本):index 改写、页面探测、桌面启动保护和所有适配器标记都已在新版本上重新验证,固定 index 夹具改为从 0.2.2-rc.1 采集;0.2.1-rc.5 仍可用。
- 会话标题改从 dsh 的
sessionTitle服务读取,不再用 0.2.2 已弃用、首次调用会打警告的sessionProjections.stateOf(session, "title")。 - 插件清单声明
engines.dsh(>=0.2.1-rc.5 <0.3.0-0),由 dsh 插件管理器自行检查支持范围。
What's Changed
- Support DeepSeek Harness 0.2.1-rc.5 (re-pin the adapter, fixture and docs) by @Rinai-R in #52
- fix: support DeepSeek Harness 0.2.2-rc.1 and release 0.3.1 by @Rinai-R in #53
Full Changelog: v0.3.0...v0.3.1
v0.3.0
- How a machine is reached is now a priority with a fallback instead of an exclusive link: Tailscale first (the default, the relay when it fails) or the relay first (the tailnet listener when it fails). The computer's Remote access dropdown and the phone's long-press sheet offer exactly these two, a machine with one link shows no choice, and a saved
autofrom an older version reads as the default (Tailscale first).POST /kivotos/modetakes only the two values;autois refused now. - The Android app's doors dial the machine's preferred link first and fall back to the other, so a relay-first machine reaches a computer whose relay is down over Tailscale and a Tailscale-first one still falls back to the relay; the notification stream follows the same choice.
- On a phone, Enter in the composer writes a line break instead of sending: dsh sends on a plain Enter and writes the line break for Shift+Enter, and a phone's keyboard has no Shift; the send button still sends.
- On a phone, the welcome page no longer leaves a large blank at the top with the hero pushed down the screen: dsh centers that hero and a phone's tall screen turned the centering into blank space; a conversation with messages keeps dsh's layout.
- In the Kivotos app the page no longer adds the system's safe-area insets on top of the app's own padding: a WebView that reports them (a phone with a display cutout) left a blank strip above the header, which an emulator without a cutout never showed.
- A file dropped or picked on another machine's page in the desktop window now uploads to that machine: the desktop preload exposes this computer's file paths to the page as well, and dsh wrote them into the draft as references the other machine could not resolve. A dropped directory and files pasted from the clipboard keep dsh's behaviour.
- Opening another machine from a machine's page in the phone app now goes through that machine when it is the faster way there: if the phone's own route to the target is not a direct Tailscale one (no row for it, its probe found no route, or only the relay reaches it) and the page's computer lists it with a route, the app opens it as that computer's mount (
/kivotos/peer/<id>/), reusing the page's door and cache instead of dialling the target over the relay itself. A direct Tailscale route is still used directly, as the fastest way. The pages loaded ahead follow the same choice, so the warmed page is the one the switch shows.
中文
- 每台机器的连接方式不再固定走某一条链路,而是两个优先级、失败自动回落:优先 Tailscale(默认,不通时改走中继)或优先中继(不通时改走 Tailscale)。电脑的「远程连接」下拉框和手机的长按面板都只有这两项;只有一条链路的机器不显示选择;旧版本保存的
auto读入后等于默认值(优先 Tailscale)。POST /kivotos/mode只接受这两个值,auto会被拒绝。 - 安卓 App 的门先走机器首选的链路,失败再走另一条:优先中继的机器在中继不通时改走 Tailscale,优先 Tailscale 的机器仍会回落到中继;通知流也跟随同一选择。
- 手机输入框里的回车现在是换行,不再把消息发出去:dsh 对纯回车是发送、对 Shift+回车才是换行,而手机键盘没有 Shift;发送仍然用发送按钮。
- 手机上的欢迎页不再在顶部留出一大片空白:dsh 会把欢迎页的标题和输入框垂直居中,手机屏幕更高,空白就被放大了;现在欢迎页靠上,有消息的会话维持 dsh 原样。
- 在 Kivotos App 里,页面不再在 App 自己留出的安全区之上再叠一层系统安全区:会报告安全区的 WebView(有刘海/挖孔的真机)原来会在顶部多留一条空白,而没有 cutout 的模拟器复现不出来。
- 在桌面窗口里打开另一台机器的页面时,拖入或选择文件现在会真正上传到那台机器:桌面端 preload 会把本机文件路径也暴露给该页面,dsh 原来只把路径写成引用,对端解析不到。拖入文件夹、从剪贴板粘贴文件维持 dsh 原有行为。
- 手机 App 里从一台机器的页面打开另一台机器时,如果手机自己过去更慢(没有它的机器行、探测没有路由,或只有中继可达),而当前页面的电脑列出它有路由,App 现在会经这台电脑打开它(
/kivotos/peer/<id>/),复用该页面的门和缓存,而不是让手机自己走中继。有 Tailscale 直达时仍然直连(最快)。预加载也按同样的选择,预热的就是切换时会显示的页面。
What's Changed
- Fix the phone's Enter, the welcome page and peer-page file uploads by @Rinai-R in #46
- Open a peer through the page's machine when the phone only reaches it over the relay by @Rinai-R in #48
- Feat: connection modes become two priorities with fallback by @Rinai-R in #50
- Release 0.3.0 by @Rinai-R in #51
Full Changelog: v0.2.2...v0.3.0
v0.2.2
- The machine switcher no longer shows attention marks for the machine currently on screen, this computer or a peer page: dsh shows that machine's own approvals and turns itself. Other machines keep their marks; no stuck dot on the machine in front.
中文
- 机器切换器不再显示当前前台机器的 attention 标记,无论是本机还是 peer 页面:那台机器自己的审批和任务由 dsh 界面显示。其他机器仍然保留标记;前台机器不会再出现清不掉的红/黄/绿点。
What's Changed
Full Changelog: v0.2.1...v0.2.2
v0.2.1
- A finished turn on this computer no longer leaves a machine-switcher dot that never clears: the current machine marks only the Session on screen as seen, so switching to the Session that finished clears its dot, while a turn that finishes in another Session still shows one.
中文
- 本机完成的任务不再留下一个永远清不掉的机器切换器圆点:只有当前显示的 Session 会被标记为已读,切到完成的那条会话后圆点消失;在别的会话里完成的任务仍然会显示圆点。
What's Changed
Full Changelog: v0.2.0...v0.2.1
v0.2.0
- The machine switcher no longer lists this computer twice when an old relay identity of it (same name and OS, an earlier node id) is no longer reported: that entry is dropped instead of being kept as an offline machine.
- This computer's own approvals, questions and finished turns now appear on its row in the machine switcher (and the trigger), like another machine's, including a turn that finished in a Session that is not on screen.
- Switching Sessions on a phone no longer opens the software keyboard: dsh focuses the composer by itself after a Session switch, and the page now blurs that focus unless the last press was inside the composer. A tap on the composer still types as before.
中文
- 机器切换器不再把同一台电脑显示两次:当它旧的 relay 身份(同名同 OS、旧的 node id)不再被上报时,这条记录会直接丢掉,而不是保留成离线机器。
- 本机自己的审批、提问和已完成的任务现在也会出现在机器切换器里本机那一行(以及触发器上),和其他机器一样;不在当前会话里完成的任务也会显示。
- 手机上切换会话不再弹出输入法:dsh 在切换会话后会自己 focus 输入框,现在除非最后一次按下发生在输入框内,页面会立即 blur;主动点输入框仍然正常输入。
What's Changed
- Fix duplicate self machine and show its own attention by @Rinai-R in #42
- Keep the phone keyboard closed when dsh focuses the composer by @Rinai-R in #43
Full Changelog: v0.1.9...v0.2.0