Commit Graph
116 Commits
Author SHA1 Message Date
Bill d3529bb9dc chore(release): v1.0.24
CI / typecheck + test + build (windows) (push) Waiting to run
v1.0.24
2026-10-09 15:51:12 +08:00
Bill 12ee779040 test(renderer): 新增 cwd/链接/broadcast 纯函数表驱动测试
CI / typecheck + test + build (windows) (push) Canceled after 0s
渲染层纯逻辑此前零测试覆盖。三个新测试直接 import .ts 源文件(Node
22.18+ 原生类型剥离,不经 esbuild bundle):
- terminal-cwd(69 断言):cdArgument 全部 shell 变体与 conemuCwd 载荷
- terminal-links(92 断言):findUrls 真实合同——尾随标点剥离、重叠
  收敛、裸 host 补 scheme、36 条不变式
- broadcast-store(39 断言):broadcastFanOut 扇出与 pruneOnTargetLoss
  (经 unregisterSession 间接覆盖)
2026-10-09 11:31:26 +08:00
Bill 64982993f3 build(scripts): 发布护栏 fail-closed 与 flag 语义;文档对齐
- release.cjs:assertNoDowngrade 的通道探测原先对网络错误/5xx/解析失败
  一律放行(fail-open),旧分支发旧版本号撞上探测失败会覆盖 latest.yml
  并让 pruneChannel 删掉线上更新版本的 exe。现仅通道真空(404)放行,
  其余抛错中止发布;prune 前的探测保持 best-effort
- 新增 --skip-gitea-release(只跳 Gitea release、通道照常上传);
  --skip-gitea 保持原行为但打印醒目警告;usage 补全 flag 语义
- 文档对齐:STATE.md(v1.0.23、19→22 离线测试、清除 MSI 描述、bundle
  清单补全)、ROADMAP 补 M12/M13、ci.yml 与 AGENTS.md 测试计数、
  AGENTS.md 补录本轮关键不变式(legacy 模板门控、SESSION_STATE/
  pendingOpens、zmodem 背压钩子、主机密钥 TTL);.gitignore 清重复与
  死条目
2026-10-09 11:31:25 +08:00
Bill 6a218ec6c0 fix(renderer): 界面与设置页一轮修补
- FilePanel 上传进度监听器组件卸载时清理(原先只在终态/reject 时 off)
- MonitorPanel:首采即失败时显示中断错误条,不再被 meta 门挡成永远
  '采集中'
- HighlightImportExport:blob 下载延迟 revokeObjectURL(原先同步回收
  会中止下载);FileReader 补 onerror
- HighlightTab 新建规则改 getState() 读法防 stale(对齐 replaceRule)
- ConnectionSidebar/CommandsPanel 三处删除/清空 handler 补 try/catch
  与 message.error(原先失败静默)
- highlightIO 导入信封补 version 校验、kind 缺失不再放行
- i18n:补 settings.highlight.builtin.percent 四语言键(原先唯一缺失
  的内置规则,非中文界面显示中文 note)
2026-10-09 11:31:10 +08:00
Bill 172cce1962 fix(stores): 配置文件形状不符先备份再回退;日志尾部同步落盘
- commands/connections/settings 三个 store 原先只对 JSON.parse 抛错做
  .bak 备份,合法 JSON 但形状不符(如 [1,2,3])会静默回退空/默认,下次
  写盘把命令库/书签凭据/自定义主题整体销毁。现统一为形状不符也先备份
  (与 knownHosts 的 fail-closed 策略对齐),三个 store 测试补对应用例
- sanitizeRules 回退分支返回预设副本而非模块级共享数组引用,并在回退时
  记录 warning(原先连警告都没有)
- 会话日志尾部:logStop 触发的最后一轮 flush 改同步落盘(在途异步写未
  落地时由 drain 循环做保序的最终同步轮),before-quit 不再丢日志尾巴
2026-10-09 11:31:06 +08:00
Bill e23010f950 fix(zmodem): 接收路径写背压;sftp 删除容忍 ENOENT;sysinfo 停止关流
- zmodem 接收:fs WriteStream 缓冲无上限,慢盘 + 快对端可把内存涨到接近
  文件大小。write() 返回 false 时暂停喂入 sentry 的 ssh 流、drain 恢复;
  touchActivity 只在写入被接受或 drain 恢复时计数,stall 看门狗不再把
  '堆在缓冲里'当进展;finalize/detach 解除悬挂暂停
- sftp 删除路径 ENOENT 一律视为已删成功(文件已被他人删除/重复删除/
  传输重跑后目标已消失),不再汇成假 delete failed;真错误仍报错
  (tests/sftp-timeout.mjs 新增 5 断言含防过度吞错用例)
- sysinfo:exec 回调里 state.stopped 分支先 close 到手的 stream
2026-10-09 11:30:51 +08:00
Bill 81ac112dac fix(main): PTY_EXIT 补偿查询、SSH 飞行连接登记与双窗口守卫
- 新增 SESSION_STATE 查询通道(契约先行):PTY_EXIT 只广播一次不重放,
  绑定晚于退出的窗格订阅后补查一次退出状态,快速退出的 shell 不再留下
  永远空白、无死亡遮罩的窗格(退出码登记表上限 512 条 FIFO)
- openSession 在 connectSsh 返回前登记 pendingOpens(owner + onClient
  最早引用),killPtysByOwner/killAllPtys 可中止飞行中的握手,renderer
  崩溃后不再留下无主孤儿 SSH 会话
- whenReady 的 createWindow 加已有窗口守卫,堵住与 second-instance
  showOrCreate 的双窗口竞态
- killAllPtys 补 replayBuffers.clear(),与 killSession 拆卸清单对齐
- promptUser 注释 30s 改为实际 120s;pty.ts 顺带注入 zmodem 背压钩子
  (见下一提交)
2026-10-09 11:30:51 +08:00
Bill 0289dcbd1d fix(workspace): 旧版布局模板不再误杀 SSH 会话
legacy(M6.1 前单 dockview)模板只喂 terminal dockview,成功路径却无条件
rebind 两个 dockview 并 kill 全部 previousSessions,SSH 活面板被降级为本地
终端、会话被静默销毁。成功路径改为按 sshTouched 门控 rebind、按 live 集合
过滤收尾 kill(与错误路径同一语义)。

另:handleApplyTemplate 加在途守卫(并发应用会互杀对方刚恢复的会话);
主机密钥队列加 120s TTL 清扫(主进程超时后不再广播,陈旧弹窗会永远占住
只渲染队头的队列),respondHostKey 移出 setState updater。
2026-10-09 11:30:34 +08:00
Bill 06cfc61392 chore: 对齐 package-lock 根版本号到 1.0.23
CI / typecheck + test + build (windows) (push) Canceled after 0s
2026-10-09 08:47:07 +08:00
Bill e9e0f7592f website: v1.0.23 — SFTP 列表改造、字体缩放与空白处右键菜单
Deploy website to GitHub Pages / deploy (push) Waiting to run
CI / typecheck + test + build (windows) (push) Canceled after 0s
2026-10-09 08:38:32 +08:00
Bill 3ab4b50afb chore(release): v1.0.23
CI / typecheck + test + build (windows) (push) Canceled after 0s
v1.0.23
2026-10-09 08:35:12 +08:00
Bill 6e7c9d5376 feat(sftp): 文件面板列头/排序、字体缩放与空白处右键菜单
- 列表头改为 sticky 并支持点击排序(名称/大小/修改时间/权限/用户/组,目录恒在前)
- 时间显示改为 YYYY/M/D HH:MM,大小显示改为 30.7 KB 风格
- 新增字体缩放 0.8–1.8(A-/A+ 与 Ctrl+滚轮),行高字号联动并记忆到 localStorage
- 行高/字号统一由 FilePanel.tsx 计算,经 CSS 变量下发,sftp.css 只消费变量
- 主进程新增 readdirDetailed + parseLongnameOwner,从 OpenSSH longname 解析真实的用户/组
- 列表空白处右键弹出菜单(行内右键仍走原菜单,两者不叠加)
- 修复:antd 把 ant-dropdown-trigger 克隆到行元素上,旧规则以更高特异性顶掉了 .sftp-row 的 display:grid,导致列此前并未按网格对齐
- 4 语言词典补充列名与缩放键
2026-10-09 08:33:06 +08:00
Bill 5602949a4f website: dark-first redesign + SFTP 面板截图
CI / typecheck + test + build (windows) (push) Canceled after 0s
Deploy website to GitHub Pages / deploy (push) Canceled after 0s
- 全站深色(#0b0e12 + 终端绿),右上角可切浅色;两套主题共用 CSS 令牌
- 自托管字体:Space Grotesk(展示)+ JetBrains Mono(等宽),不再依赖系统栈
- 「核心能力」改为横向滚动卡片轨道(箭头翻页 / 拖拽 / 键盘方向键)
- 新增 SFTP 文件面板截图(含空白处右键菜单),IP 已打码
- 补 og:image / theme-color / skip-link / 焦点环 / 导航当前位置高亮
2026-10-09 00:46:35 +08:00
Bill 9e5e959f80 docs(readme): add screenshots & advantages section; fix stale facts (11 themes, 19 tests, MSI dropped)
CI / typecheck + test + build (windows) (push) Canceled after 0s
2026-10-08 14:19:22 +08:00
Bill 309de439e8 website: v1.0.22 — drop MSI, refresh screenshots (agents/themes/lock)
CI / typecheck + test + build (windows) (push) Canceled after 0s
Deploy website to GitHub Pages / deploy (push) Canceled after 0s
- download: NSIS exe only, v1.0.22 links, update-source order GitHub-first
- features: 22 highlight rules, 11 builtin themes, bg dim layer
- new rows: AI Agent workspace, lock screen & security
- changelog: 1.0.22 / 1.0.21 / 1.0.20
2026-10-08 14:10:15 +08:00
Bill a381d7be03 docs: warn about auto-created wrong-target tags in release flow
CI / typecheck + test + build (windows) (push) Canceled after 0s
2026-10-08 13:31:54 +08:00
Bill 14f5963706 build: drop MSI installer, NSIS exe only
CI / typecheck + test + build (windows) (push) Canceled after 0s
electron-updater never supported MSI auto-updates; the exe is the only
installer from v1.0.22 on. release.cjs no longer expects/uploads the msi.
2026-10-08 13:25:01 +08:00
Bill 40336d014d release: v1.0.22
CI / typecheck + test + build (windows) (push) Canceled after 0s
fix(ime): actually ship @xterm/xterm 6.1.0-beta.304 (v1.0.21 built from stale
node_modules with 6.0.0); add predist dependency-consistency gate
(scripts/verify-deps.cjs) and rename-retry shim for the AV scan EPERM race
v1.0.22
2026-10-08 13:09:13 +08:00
Bill ac43844f8a release: v1.0.21
CI / typecheck + test + build (windows) (push) Canceled after 0s
v1.0.21
2026-10-08 00:17:05 +08:00
Bill 2653ab1820 feat(i18n): tab auto titles follow the UI language
Titles are stored display text (layout templates, session snapshot,
broadcast registry), so a pane used to keep the wording of the language it
was opened in, and nextTerminalTitle could not even parse the number back
out of another language's pattern (numbering restarted, duplicates).

New pure module src/shared/terminalTitle.ts: resolution tries all four
languages' patterns, rendering uses the active one; i18n gains tFor(lang)
for off-language rendering. Workspace retitles auto-numbered local tabs in
place on language switch, snapshot restore and template apply; SSH panels
(user-typed connection names) are never touched. dockview's title-change
event propagates the new title to the broadcast registry and the snapshot
save with no extra wiring.

New test terminal-title.mjs (16 writer/reader language pairs, non-auto
title boundaries, gap filling); offline suite grows 17 -> 18.
2026-10-08 00:11:20 +08:00
Bill 9a46555fc1 docs: close out M11 in ROADMAP; AGENTS.md gains performance/security boundary notes
Test count 12 -> 17, dependency placement rule (main-only packages in
dependencies), and the new invariants: field-level subscriptions,
sftp row-height sync, localPathGrants admission, keyPath validation,
shared reservedAccelerator table, sftp per-op timeouts, explicit
webPreferences. Panel-title i18n fix deferred (5 consumers + persisted
data compat).
2026-10-07 23:12:33 +08:00
Bill eea40d87a6 build(deps): move renderer-only deps to devDependencies, shrink asar 98MB -> 8.1MB
Renderer code is fully bundled by Vite into out/renderer; externalizeDepsPlugin
only applies to main/preload, so renderer packages in 'dependencies' were
shipped twice. Moved to devDependencies: @xterm/*, antd, dockview-react,
react, react-dom, zustand. Kept in dependencies (imported by src/main):
@lydell/node-pty, ssh2, zmodem.js, font-list, electron-updater. undici is
now explicit (release.cjs/download-stats.cjs require it). Also dropped the
dead @xterm/addon-serialize (zero imports anywhere).

Verified: npm test 17/17 green, dist:dir builds, asar node_modules contains
only main-process deps, asarUnpack natives intact, win-unpacked smoke
(window, theme, pty spawn) passes.
2026-10-07 23:08:43 +08:00
Bill a0be827650 test(main): cover updater fallback, ipc sender guard, log sanitizer, sftp timeouts
- updater-fallback.mjs (82 assertions): GitHub probe fallback to Gitea,
  timeout budgets, in-flight check never stuck in 'checking'; updater.ts
  gains a setUpdateTimeouts test seam, electron-updater aliased to a stub
- ipc-guard.mjs (43): trusted-frame guard exercised through real
  registerIpc handlers with forged senderFrames; electron-stub now records
  registrations via globalThis so bundle and test share one instance
- log-sanitizer.mjs (71): CSI/OSC/charset state machine, alt-screen fold,
  byte-split fuzz equal to whole-chunk output; fixes a wrong comment
- sftp-timeout.mjs (39): per-op timeouts (metadata 30s, transfer chunk 60s,
  open 10s) evict half-dead channels with one retry, slow-but-progressing
  transfers untouched, late rejections never unhandled
- reservedAccelerators.ts: single pure isReservedAccelerator shared by the
  settings recorder and applyGlobalShortcut (the two tables had drifted —
  main now also refuses Ctrl+=/-/0/PgUp/PgDn legacy values); 56 assertions
- ssh-loopback.mjs loads the real ssh.ts via a bundle (50 assertions):
  TOFU pinning, fail-closed stores, auth gate, connect budget

Offline suite grows 13 -> 17. Renderer test framework evaluated: not
introducing vitest/jsdom; pure logic keeps being extracted and tested
through the existing bundle harness.
2026-10-07 22:57:16 +08:00
Bill 5ff311ea0f docs+chore: refresh README/STATE, cache electron in CI, lock chord by keycode, misc P3
- README: add lock-screen section, refresh test list (13 offline tests),
  updater fallback order, data locations, architecture tree
- STATE.md: v1.0.20, current release.cjs flow (no --skip-github), M11-M13
- ci.yml: actions/cache for the ~100MB Electron binary keyed on lockfile
- .gitignore: ignore .env.* but keep committed templates
- scripts/archive-releases.cjs moved in from tmp-test; KEEP_TAG is now a
  required CLI arg (a hardcoded default is how the wrong version gets wiped)
- lockShortcuts: isPanicLockChord matches input.code ('KeyL') so Dvorak and
  non-Latin layouts trigger Ctrl+L lock correctly
- settings: drop the dead single-option update-channel Select from About tab
- Workspace/App: memo(IconRail/LayoutFlyout), useMemo layoutMenu keyed on
  language, useCallback onOpenSettings; drop unused IconRail onSplit prop
2026-10-07 22:06:58 +08:00
Bill d22923aedd security(main): dialog-grant admission for local paths, explicit webPreferences
New localPathGrants.ts: an in-memory registry of paths the user picked in a
native dialog. Every check resolves realpath + stat at grant and use time;
Windows case folding; missing files, directories-as-files, devices and
symlinked parents can never pass. SFTP upload/download and zmodem send/
receive now refuse renderer-supplied local paths that were never granted,
returning the resolved path so callers never re-traverse a symlink. keyPath
is validated as a regular file <= 1MB before reading (a device node would
have blocked the UI thread forever). Tests inject a stub policy via
setLocalPathPolicy; production always defaults to the real registry.

Also: webPreferences now explicitly pins contextIsolation/nodeIntegration/
webSecurity instead of relying on defaults.

New offline test tests/local-path-grants.mjs (37 assertions incl. symlink
escape); offline suite grows to 13. i18n: 6 main.sftp/main.key error keys
in 4 languages.
2026-10-07 22:06:45 +08:00
Bill 9c75cdc7d4 perf(renderer): field-level settings subscriptions, file list virtualization, per-panel error boundary
- TerminalView: replace whole-settings subscription with five useShallow
  field groups; theme writes no longer refit every pane, and unrelated
  settings writes no longer touch xterm options at all. useResolvedTheme
  is now a shallow subscription + memoized lookup. TerminalHandle was dead
  (no caller ever passed a ref) — dropped forwardRef/useImperativeHandle
- FilePanel: fixed-row-height (24px) windowing above 200 entries, no new
  dependency (antd 6 ships @rc-component/virtual-list only transitively);
  per-row Dropdown kept. NOTE: .sftp-row is now box-sizing:border-box
  height:24px, keep in sync with ROW_HEIGHT in FilePanel.tsx
- PanelErrorBoundary wraps each dockview panel so a pane crash no longer
  unmounts the whole workspace (i18n: workspace.error.panelTitle/panelRetry)
- SshBottomPanel: memo(FilePanel) — sessionId is the only prop and constant
- TransferPanel: ref-held Map + version counter replaces per-event Map
  copies; memo rows skip unchanged entries
- MonitorPanel: ResizeObserver/canvas setup runs once, data updates only
  redraw
2026-10-07 22:06:31 +08:00
Bill 6c04f0e8c1 feat(theme): add background image dim scrim slider
New terminal.backgroundImageDim setting (0-90%, default 0 = off). A black
scrim layer sits between the background image and the xterm screen, so
bright wallpapers stay readable at any opacity: unlike the opacity slider
(which blends the image toward the dark dock base), the scrim darkens the
image while preserving its saturation, and the raised minimumContrastRatio
(4.5) keeps lifted text legible on top.

- settings: backgroundImageDim with deepMerge type-fallback sanitize
- TerminalView: render .term-bg-dim only when image set and dim > 0
- ThemeSettingsTab: slider follows the existing draft + onChangeComplete
  pattern (no settings writes while dragging)
- i18n: settings.theme.backgroundImageDim(+Desc) in zh-CN/zh-TW/en/ja
- AGENTS.md: document the third image-mode invariant
2026-10-07 21:24:27 +08:00
Bill e16c860c7a fix(theme): dim background image toward dark and lift text contrast in image mode
On light themes the pane base is near-white (--chrome-bg), so lowering the
background image opacity washed the wallpaper out to white instead of
darkening it, and the theme's dark foreground text became unreadable.

- terminal.css: in has-bg-image mode the dock gets a fixed dark base
  (#0d1117), so the opacity slider always dims toward dark regardless of
  theme
- TerminalView: raise xterm minimumContrastRatio from 1 to 4.5 (WCAG AA,
  same as VS Code's terminal default) while an image is set; xterm treats
  the transparent background as black luminance, so dark foreground colors
  are lifted to stay readable over the wallpaper. Also fix the option name
  (minContrastRatio is silently ignored; the real key is
  minimumContrastRatio)
- i18n: update backgroundImageDesc in zh-CN/zh-TW/en/ja
- AGENTS.md: document the two image-mode invariants
2026-10-07 21:02:14 +08:00
Bill f5acf26d1f docs: record this round's fixes in AGENTS.md; add download-stats script; plan M11 in ROADMAP 2026-10-07 20:44:46 +08:00
Bill 36627ee4b7 i18n: add keys for zmodem/startup/updater/sftp/template messages 2026-10-07 20:44:45 +08:00
Bill b7938de464 fix(ui): theme-derived sftp/monitor surfaces, transfer cancel button, dialog cleanup; drop dead autoWrap; gentler bg-image default 2026-10-07 20:44:31 +08:00
Bill fb65981bff fix(workspace): restore layout snapshot on failed template apply; inert late-mounted portals while locked 2026-10-07 20:44:30 +08:00
Bill ee667cdc2b fix(main): harden startup chain, updater/sftp timeouts, host-key guard, shell env scrub 2026-10-07 20:44:28 +08:00
Bill 7aca8c5cb0 fix(release): refuse channel downgrades; verify assets by sha512; harden .env parsing 2026-10-07 20:44:12 +08:00
Bill 46b76ebca7 fix(zmodem): finalize on sink errors, throttle progress, emit terminal events on detach 2026-10-07 20:44:11 +08:00
Bill 655c660607 fix(store): back up unparseable connections/commands files before rebuild 2026-10-07 20:44:10 +08:00
Bill 7438d84d89 Merge branch 'Dev_202609'
CI / typecheck + test + build (windows) (push) Canceled after 0s
2026-10-04 01:19:58 +08:00
954801926@qq.com d1376b7d1d chore: release v1.0.20
CI / typecheck + test + build (windows) (push) Canceled after 0s
v1.0.20
2026-10-01 21:56:24 +08:00
954801926@qq.com d04452cd7f fix(ime): pin @xterm/xterm 6.1.0-beta.304 for IME caret follow; sync lockfile root version in predist
CI / typecheck + test + build (windows) (push) Canceled after 0s
2026-10-01 21:28:07 +08:00
Bill 86f51df2e6 fix(lock): harden lock screen input paths
CI / typecheck + test + build (windows) (push) Canceled after 0s
- remove the application menu while locked (lockMenu.ts): Alt reveals the
  default menu and its mouse-clickable Reload/DevTools/Zoom items bypass
  before-input-event entirely; menu is rebuilt from the default template on
  unlock, startup-restored locks covered from initLockController
- extract the keyboard classification into pure lockShortcuts.ts
  (isLockBlockedShortcut/isPanicLockChord) with a table-driven test
  (lock-shortcuts.mjs, 29 cases) — the v1.0.17 lockout escaped CI because
  this decision lived inline in createWindow()
- reserve Ctrl+L in the global show/hide shortcut recorder: a global
  registration intercepts the chord at OS level and silently disables the
  panic lock
- skip auto-repeat keydowns in the panic-lock branch (held Ctrl+L on an
  unconfigured app re-read lock.json + settings.json per repeat)
- LockScreen: re-sync the cooldown clock on visibilitychange/focus/pageshow
  so a suspended renderer timer cannot leave the password input disabled
  past the real deadline
2026-09-30 00:38:57 +08:00
Bill f026400676 fix(release): GitHub publish survives partial runs and flaky proxies
CI / typecheck + test + build (windows) (push) Canceled after 0s
Skip assets a previous partial run already uploaded (the POST 422s on
duplicates, so a retry could never get past them), and retry transient
network errors on large proxied uploads.
2026-09-28 13:58:51 +08:00
Bill dd08f8054a chore: release v1.0.19
CI / typecheck + test + build (windows) (push) Canceled after 0s
v1.0.19
2026-09-28 13:39:27 +08:00
Bill dba2b14c33 feat(updater): GitHub-first update checks with 20s connectivity probe
checkWithFallback now probes api.github.com through a dedicated system-proxy
session with a 20s AbortSignal timeout before choosing the feed: reachable ->
GitHub releases (with Gitea as the error fallback), unreachable/timeout ->
straight to the domestic Gitea channel (forced direct), so proxy-less users
never hang on a dead proxy. Feed is decided before touching the updater, so
there is never a raced concurrent checkForUpdates. Docs updated: AGENTS.md
update-mechanism section and the release flow (GitHub assets ship per version
again, release.cjs runs with no skip flags).
2026-09-28 13:39:26 +08:00
Bill 680254cad6 fix(release): drop stray TS annotation in .cjs GitHub path
The hardening-round edit left `(): Promise<Response> =>` in a plain .cjs
file; every run since that commit died at parse time before reaching any flag
handling.
2026-09-28 13:39:25 +08:00
Bill b7c7c5cd76 fix(highlight): settings UI fixes from review — grouped view, import guard, basic flag
CI / typecheck + test + build (windows) (push) Canceled after 0s
- grouped view actually clusters: drop the priority column's defaultSortOrder
  that made antd re-sort the dataSource and undo the category clustering
- replace import is Popconfirm-guarded and the import mode resets to append
  each time the dialog opens (it stayed on the destructive choice)
- rule editor exposes the basic flag (basic-mode membership) with a switch;
  clearing it on edit now actually removes the flag
- rule/profile writes read the store at call time instead of the render-scoped
  array, so two writes in one React batch no longer drop the first
- profile editor lists the rules a non-empty profile leaves out (uses the
  previously dead excludedByProfile helper)
- bands editor keeps rows sorted by min; band preview keys by index (duplicate
  min no longer collides); clear-background also closes the bg picker
- TerminalView pushes compiled rules into the HighlightStream from an effect
  instead of during render
2026-09-28 13:06:40 +08:00
Bill 462da60977 perf(highlight): precompute SGR at compile, sorted span claiming, stream ESC-free fast path
- compileRules precomputes the full SGR open sequence per rule and per band;
  wrap() is now pure concatenation, bandOpen() a table lookup (output bytes
  unchanged, bg keeps its unvalidated white-fallback)
- claim() replaces the linear overlaps() scan: claimed spans stay sorted by
  start, O(1) append on the common left-to-right sweep plus one binary search
  otherwise (match-dense 200KB payload: -19% one-shot, -56% streamed)
- HighlightStream: bufferHasEsc flag skips the O(buffer) escape rescans when
  neither the held text nor the chunk contains ESC, fixing quadratic rescan on
  escape-free floods (plain 200KB streamed: -54%)
- applyHighlights tracks the consumed match budget incrementally instead of
  two budgets.reduce() passes per text token
- ESCAPE_RE now covers DCS/APC/PM/SOS (BEL or ST terminated) and single-char
  Fe escapes (DECSC/DECRC/NEL/RI/RIS, orphan ST); isIncompleteEscape holds cut
  tails of the new families; split-smoke exercises every cut point through them
2026-09-28 13:06:29 +08:00
Bill 4e5377f49c fix: hardening round from code review (4 P1 + 15 P2)
CI / typecheck + test + build (windows) (push) Canceled after 0s
P1:
- settingsStore: back up an unparseable settings.json to .bak before
  falling back to defaults, so the next mutation can no longer silently
  wipe custom themes/highlight rules
- ptyDispatcher: fan out per-session data/exit handlers (Set instead of
  a single slot) so SSH split panes stop stealing each other's stream
- FilePanel: monotonic refresh token keeps stale listings from painting
  over a newer navigation; upload finish no longer yanks the panel back
- settings.css: active settings-tab label derives from --chrome-fg so it
  stays visible on the shipped light themes

P2 (main/renderer):
- paste guard: a paste ending in a newline always confirms
- Workspace: closing an SSH pane no longer seeds the local cwd with a
  remote path
- tray: skip close-dialog continuation on a destroyed window
- commands: close zombie 'in-progress' session logs at hydrate
- zmodem: clear the stale offer timer before arming a new one
- connectionsStore: coerce/validate renderer input before persisting
- sftp: OperationError marker class keeps translated errors out of the
  transport-retry classifier
- CommandsPanel: surface save failures inside the dialog
- ConnectionSidebar: drop a tautological tooltip condition

P2 (i18n/tooling/tests):
- localize the 16 ANSI color labels and the highlight sample text
  (21 new keys across zh-CN/zh-TW/en/ja)
- sync-changelog: keep ### subheadings, normalize CRLF notes
- release.cjs: GitHub release reuse-by-tag (idempotent re-runs); fail
  loudly on a failed Gitea asset listing
- commands-store test: absent historyEnabled now truly tests absence
2026-09-27 22:25:03 +08:00
Bill 33efbe921e chore: release v1.0.18
CI / typecheck + test + build (windows) (push) Canceled after 0s
v1.0.18
2026-09-24 22:53:29 +08:00
Bill 83dc3f15cc fix(lock): lock screen swallowed every keystroke; add Ctrl+L to lock
The renderer-side guard added in v1.0.17 called preventDefault on every
keydown while locked. A keydown's default action IS inserting the
character into the focused field, so the lock screen's password box
received nothing and a locked app could never be unlocked. Menu
accelerators are already stopped in main (before-input-event); the
renderer guard now just skips its own logic.

Also: Ctrl+L locks the screen from anywhere in the app, terminals
included. The chord is only taken when a lock actually engages, so an
unconfigured app keeps Ctrl+L for the shell's clear-screen.
2026-09-24 22:53:27 +08:00
Bill 244199c512 chore: release v1.0.17
CI / typecheck + test + build (windows) (push) Canceled after 0s
v1.0.17
2026-09-24 22:16:49 +08:00