Compare commits

...
4 Commits
Author SHA1 Message Date
Bill 309de439e8 website: v1.0.22 — drop MSI, refresh screenshots (agents/themes/lock)
Deploy website to GitHub Pages / deploy (push) Waiting to run
CI / typecheck + test + build (windows) (push) Waiting to run
- 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) Waiting to run
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
2026-10-08 13:09:13 +08:00
19 changed files with 215 additions and 68 deletions

No files matched your search

+7 -4
View File
@@ -10,9 +10,12 @@ Electron + electron-vite + React 终端工具(本地终端 / SSH / SFTP)。
- 测试:`npm test`(**npm 生命周期先自动跑 `pretest` 做类型检查**,再 `node tests/build-bundles.cjs` 重建 esbuild bundle,然后依次跑可离线运行的 18 个测试:ssh-loopback、commands-store、connections-store、settings-store、local-path-grants、lock-store、lock-controller、lock-shortcuts、hl-split-smoke、hl-rules、reserved-accelerators、ipc-guard、updater-fallback、log-sanitizer、sftp-timeout、terminal-title、zmodem-e2e、ssh-session-e2e、sysinfo-e2e;真实服务器测试需 JD_* 凭据,不在此列)
- 依赖分类规则:**只有 `src/main/`/`src/preload/` 实际 import 的包才能进 `dependencies`**(node-pty/ssh2/zmodem.js/font-list/electron-updater);纯渲染层依赖一律 devDependencies(Vite 全量打包进 out/renderer,`externalizeDepsPlugin` 不作用渲染层)——这条让 asar 从 98MB 瘦到 8.1MB,加新依赖时别放错边
- 下载量统计:`node scripts/download-stats.cjs`(Gitea + GitHub release 资产的 download_count 汇总;GitHub 优先直连、失败自动回退 `HTTPS_PROXY`/本地 7897;更新通道无计数接口不计入)
- 打包:`npm run dist`(**生命周期先自动跑 `predist` → `npm test`,即类型检查 + 18 个离线测试全部通过后才 build/package**,typecheck 全程只跑一次;predist 末尾的 `npm install --package-lock-only` 会把 `package-lock.json` 根版本号对齐 `package.json`,**发布提交必须带上 package-lock.json**),产物在 `release/`(msi + exe + latest.yml + blockmap)
- 打包:`npm run dist`(**生命周期先自动跑 `predist` → `npm test`,即类型检查 + 18 个离线测试全部通过后才 build/package**,typecheck 全程只跑一次;predist 末尾的 `npm install --package-lock-only` 会把 `package-lock.json` 根版本号对齐 `package.json`,**发布提交必须带上 package-lock.json**),产物在 `release/`(exe + latest.yml + blockmap)
- GitHub Actions:`.github/workflows/ci.yml` 在 windows-latest + Node 22 上跑 `npm ci` / `npm test`(含 pretest typecheck)/ `npm run build`,只做验证,不打包安装器、不发布
- 国内网络需镜像:`ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ ELECTRON_BUILDER_BINARIES_MIRROR=https://npmmirror.com/mirrors/electron-builder-binaries/ npm run dist`
- 依赖一致性闸门:`predist` 开头跑 `node scripts/verify-deps.cjs`(逐条比对 `node_modules` 与 `package-lock.json` 的版本,跨平台 optional 依赖缺失跳过;不一致就 exit 1)——`npm install --package-lock-only` **只重算 lockfile、不碰 node_modules**(本版 npm 还会把 `node_modules/.package-lock.json` 一并重写成理想树,制造「已经装好了」的假象),所以**改动依赖版本后必须真实 `npm install` 或 `npm ci` 再构建**,别指望 lockfile 对齐就等于树里换了包;v1.0.21 的中文输入法回归正是这个坑(`@xterm/xterm` 锁 6.1.0-beta.304,树里还是 6.0.0,打进去的是旧代码)
- **换机/重装环境后第一次打包前必须先跑 `npm ci`**(verify-deps 会兜底拦截,但别浪费一次构建);在任何机器上都先 `node scripts/verify-deps.cjs` 确认再 `npm run dist`
- electron-builder `rename win-unpacked.tmp` 撞 EPERM = 安全软件实时扫描新解压文件短暂持锁(实测约 4s,进程退出后数秒即可手动重命名)。应对:`NODE_OPTIONS="--require $(pwd -W)/scripts/rename-retry-shim.cjs" npm run dist`(注入重试垫片,stderr 会打印每次重试);根治是把仓库目录加进安全软件信任区
## 仓库与远程
@@ -31,20 +34,20 @@ Electron + electron-vite + React 终端工具(本地终端 / SSH / SFTP)。
2. `node scripts/sync-changelog.cjs` 把发布说明并入 `CHANGELOG*.md` —— **必须在 `npm run dist` 之前**:更新日志以 `?raw` 打进安装包(「关于」页离线读),`release.cjs` 也校验 `CHANGELOG.md` 已含该版本号
3. `npm run dist` 构建
4. `node scripts/release.cjs <版本号>`,例如 `node scripts/release.cjs 1.0.14`(**不带 skip 参数**,Gitea 与 GitHub 一起发)
- Gitea:release(msi + exe 资产)→ Gitea 更新通道(`api/packages/admin/generic/openterminal-update/stable`:exe.blockmap → exe → release-notes.md → **latest.yml 最后**)
- Gitea:release(exe 资产)→ Gitea 更新通道(`api/packages/admin/generic/openterminal-update/stable`:exe.blockmap → exe → release-notes.md → **latest.yml 最后**)
- GitHub:release 资产再次随版本同步发布(exe + exe.blockmap + latest.yml),electron-updater 标准 GitHub provider 直接吃 release 资产
- 通道不再先删旧版:新版本文件全部传完、latest.yml 生效后才清掉上一版 exe/blockmap,中途失败不会把通道打空;同一版本可重复运行(release 复用、已传资产跳过)
- 上传前先比通道版本:`assertNoDowngrade()` 读通道 latest.yml,若线上版本**高于**待发布版本就直接拒绝——三条本地护栏只比本地产物,旧分支发旧版本号会一路通过,覆盖 latest.yml 之后 `pruneChannel` 会把线上新版本的 exe/blockmap 删掉
- 只补通道:`node scripts/release.cjs <版本号> --channel-only`(不建 release、不发 GitHub)
- 国内通道全程直连,**不需要设代理**;GitHub 请求走 `HTTPS_PROXY=http://127.0.0.1:7897`(脚本只把它用于 GitHub 请求)
5. 验证更新通道:`curl https://git.codingplan.site/api/packages/admin/generic/openterminal-update/stable/latest.yml` 应返回新版本号
6. `git tag v<版本号>` 并推送两个远程(代码/tag 与 release 资产的镜像保持同步)
6. `git tag v<版本号>` 并推送两个远程(代码/tag 与 release 资产的镜像保持同步)。注意顺序坑:release.cjs 创建 release 时若远端尚无该 tag,Gitea/GitHub 会在**默认分支 HEAD** 自动建一个指向错误 commit 的 tag,第 6 步推送会被拒——要么先建 tag 推上去再跑 release.cjs,要么事后 `git push -f <远端> v<版本号>` 强制修正到 release commit(v1.0.22 即踩过)
## 更新机制
- 检查更新:**GitHub 优先**(走系统代理;前置 20 秒连通性探测 `probeGithub`——探测失败/超时直接兜底 Gitea,不给 electron-updater 挂起的机会),失败回退国内 Gitea 通用包通道(强制直连,不走系统代理)。 electron-updater 用独立 session(partition `electron-updater`),代理模式在 `useFeed` 里按源切换
- 更新日志:Gitea 仓库是私有的(匿名 API 404),改为从更新通道的 `release-notes.md` 读取(直连 session `openterminal-update-direct`),再回退 Gitea/GitHub releases API
- electron-updater 不支持 MSI 自动更新,自动更新只走 NSIS exe
- 自动更新只走 NSIS exe;自 v1.0.22 起不再构建 MSI 安装包(electron-updater 本就不支持 MSI 自动更新)
- 每次 checkForUpdates 都被 **30s 整体超时**包住(`withTimeout`):electron-updater 自带的 60s 只是 socket 空闲超时,慢滴流响应能一直占住它。超时按普通失败走 GitHub→Gitea 回退,但**被放弃的检查取消不掉**,而 electron-updater 对并发检查去重(返回同一个 in-flight promise),所以兜底那次共用被放弃的 promise——它同样被超时兜住,最终落到错误态,不会永远停在「检查中」
- 更新日志 / releases API 的 fetch 都带 `AbortSignal.timeout(15s)`(`directFetch` 与 `fetchChangelog` 里的 `net.fetch`):卡住的通道必须让位给下一个来源,不能把「关于」页吊住
+11
View File
@@ -1,5 +1,16 @@
# OpenTerminal Changelog
## v1.0.22 - 2026-10-08
### IME
- **Fixed: Chinese IME candidate window not following the caret** (regression in v1.0.21): the v1.0.21 build environment had a terminal component dependency that did not match the locked version, so the installer shipped an older build without the upstream IME fix; this release restores the terminal component version used by v1.0.20, and the candidate window follows the caret again.
### Installer
- The MSI installer is discontinued (electron-updater never supported MSI auto-updates); the NSIS exe is now the only installer format.
### Internal
- The packaging pipeline now verifies dependency consistency before building: installed dependencies are compared against the lockfile and the build aborts on any mismatch, preventing this class of issue from recurring.
## v1.0.21 - 2026-10-07
### Background image experience
+11
View File
@@ -1,5 +1,16 @@
# OpenTerminal 更新履歴
## v1.0.22 - 2026-10-08
### IME
- **中国語 IME の候補ウィンドウがキャレットに追従しない問題を修正**(v1.0.21 でのリグレッション):v1.0.21 のビルド環境では端末コンポーネントの依存がロックされたバージョンと一致しておらず、インストーラーには上流の IME 修正を含まない古いビルドが同梱されていました。本バージョンでは v1.0.20 と同じ端末コンポーネントに戻し、候補ウィンドウが再びキャレットに追従します。
### インストーラー
- MSI インストーラーの提供を終了しました(electron-updater は MSI の自動更新に非対応のため)。今後は NSIS exe インストーラーに統一されます。
### 内部
- パッケージング前に依存関係の整合性チェックを追加:インストール済み依存とロックファイルを照合し、不一致があればビルドを中止します。同種の問題の再発を防ぎます。
## v1.0.21 - 2026-10-07
### 背景画像の体験
+11
View File
@@ -1,5 +1,16 @@
# OpenTerminal 更新日志
## v1.0.22 - 2026-10-08
### 输入法
- **修复中文输入法候选窗不跟随光标**(v1.0.21 回归):v1.0.21 的构建环境中终端组件依赖未按锁定版本安装,安装包实际打进的是不含上游输入法修复的旧版本;本版本恢复 v1.0.20 所用的终端组件版本,候选窗重新紧贴光标。
### 安装包
- 不再提供 MSI 安装包(electron-updater 本就不支持 MSI 自动更新),统一使用 NSIS exe 安装包。
### 内部
- 打包流程新增依赖一致性校验:构建前自动比对实际安装的依赖与锁定清单,不一致即中止,防止同类问题再次发生。
## v1.0.21 - 2026-10-07
### 背景图体验
+11
View File
@@ -1,5 +1,16 @@
# OpenTerminal 更新日誌
## v1.0.22 - 2026-10-08
### 輸入法
- **修復中文輸入法候選視窗不跟隨游標**(v1.0.21 回歸):v1.0.21 的建置環境中終端機元件相依未按鎖定版本安裝,安裝包實際打包的是不含上游輸入法修復的舊版本;本版本恢復 v1.0.20 所用的終端機元件版本,候選視窗重新緊貼游標。
### 安裝包
- 不再提供 MSI 安裝包(electron-updater 本就不支援 MSI 自動更新),統一使用 NSIS exe 安裝包。
### 內部
- 打包流程新增相依一致性校驗:建置前自動比對實際安裝的相依與鎖定清單,不一致即中止,防止同類問題再次發生。
## v1.0.21 - 2026-10-07
### 背景圖體驗
+2 -13
View File
@@ -16,23 +16,12 @@ asarUnpack:
# @lydell/node-pty ships prebuilt binaries; do not trigger a rebuild.
npmRebuild: false
# Electron-updater only supports NSIS auto-updates (MSI has no update channel).
# The NSIS .exe + latest.yml get uploaded together; MSI is manual/enterprise only.
# NSIS exe is the only installer: electron-updater only supports NSIS
# auto-updates, so the MSI (no update channel) was dropped in v1.0.22.
win:
target:
- target: msi
- target: nsis
msi:
oneClick: false
# Fixed upgrade code keeps the upgrade chain consistent across releases.
upgradeCode: "{5ab9f79e-e4eb-4052-9df6-3af3a301ab0a}"
artifactName: ${productName}-${version}-setup.${ext}
# Shortcuts need an <Icon>; build/icon.png (auto-converted to .ico) provides it.
# Without an icon the WiX shortcut Icon reference fails to link (LGHT0094).
createDesktopShortcut: true
createStartMenuShortcut: true
nsis:
oneClick: false
allowToChangeInstallationDirectory: true
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "open-terminal",
"version": "1.0.21",
"version": "1.0.22",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "open-terminal",
"version": "1.0.21",
"version": "1.0.22",
"license": "MIT",
"dependencies": {
"@lydell/node-pty": "^1.2.0-beta.15",
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "open-terminal",
"productName": "OpenTerminal",
"version": "1.0.21",
"version": "1.0.22",
"description": "Open-source terminal with SSH, split panes, themes and fonts",
"main": "out/main/index.js",
"author": "CodingPlan.Site",
@@ -14,8 +14,8 @@
"typecheck": "tsc --noEmit -p tsconfig.node.json && tsc --noEmit -p tsconfig.web.json",
"pretest": "npm run typecheck",
"test": "node tests/build-bundles.cjs && node tests/ssh-loopback.mjs && node tests/commands-store.mjs && node tests/connections-store.mjs && node tests/settings-store.mjs && node tests/local-path-grants.mjs && node tests/lock-store.mjs && node tests/lock-controller.mjs && node tests/lock-shortcuts.mjs && node tests/reserved-accelerators.mjs && node tests/.terminal-title.cjs && node tests/ipc-guard.mjs && node tests/updater-fallback.mjs && node tests/log-sanitizer.mjs && node tests/sftp-timeout.mjs && node tests/.hl-split-smoke.cjs && node tests/.hl-rules.cjs && node tests/zmodem-e2e.mjs && node tests/ssh-session-e2e.mjs && node tests/sysinfo-e2e.mjs",
"predist": "npm test && npm install --package-lock-only",
"dist": "electron-vite build && electron-builder --win msi nsis",
"predist": "node scripts/verify-deps.cjs && npm test && npm install --package-lock-only",
"dist": "electron-vite build && electron-builder --win nsis",
"dist:dir": "electron-vite build && electron-builder --win --dir"
},
"dependencies": {
+5 -7
View File
@@ -42,14 +42,12 @@ const env = Object.fromEntries(
)
const notes = fs.readFileSync(path.join(ROOT, 'RELEASE_NOTES.md'), 'utf8')
const R = path.join(ROOT, 'release')
const msi = path.join(R, `OpenTerminal-${V}-setup.msi`)
const exe = path.join(R, `OpenTerminal-${V}-setup.exe`)
const files = [msi, exe]
// --channel-only republishes the update channel, which carries the NSIS exe and
// its blockmap (electron-updater cannot consume an MSI) — the msi is a release
// asset only, so demanding it here would block the repair path this mode exists
// for. The channel's own file list is validated in giteaChannel().
for (const f of CHANNEL_ONLY ? [exe] : files) {
const files = [exe]
// Only the NSIS exe is built (the MSI was dropped in v1.0.22 — electron-updater
// never supported it). The channel's own file list is validated in
// giteaChannel().
for (const f of files) {
if (!fs.existsSync(f)) { console.error('missing build artifact:', f); process.exit(1) }
}
// Guard rails: the artifacts must belong to the version being published —
+30
View File
@@ -0,0 +1,30 @@
// 构建垫片:Windows 上安全软件实时扫描新解压的文件时会短暂持有目录句柄(实测 ~4s),
// electron-builder 解包后立即 rename 会撞 EPERM。对 fs.promises 的 rename/rm/unlink/copyFile
// 加 EPERM/EBUSY/ENOTEMPTY 重试(30 次 × 1s),stderr 会打印每次重试。
// 用法(命中 EPERM 时):NODE_OPTIONS="--require $(pwd -W)/scripts/rename-retry-shim.cjs" npm run dist
const fs = require('node:fs');
const RETRY_CODES = new Set(['EPERM', 'EBUSY', 'ENOTEMPTY']);
const MAX_TRIES = 30;
const DELAY_MS = 1000;
function wrap(name) {
const orig = fs.promises[name];
if (typeof orig !== 'function') return;
fs.promises[name] = async function (...args) {
for (let i = 0; ; i++) {
try {
return await orig.apply(fs.promises, args);
} catch (err) {
if (!RETRY_CODES.has(err && err.code) || i >= MAX_TRIES - 1) throw err;
process.stderr.write(`[rename-retry-shim] ${name} ${args[0]} -> ${err.code}, retry ${i + 1}/${MAX_TRIES}\n`);
await new Promise(r => setTimeout(r, DELAY_MS));
}
}
};
}
wrap('rename');
wrap('rm');
wrap('unlink');
wrap('copyFile');
+59
View File
@@ -0,0 +1,59 @@
/* Dependency consistency gate: node_modules must match package-lock.json.
Usage: node scripts/verify-deps.cjs (runs first in `predist`)
Why it exists: v1.0.21 shipped an input-method fix that never reached the
build. @xterm/xterm had been pinned to 6.1.0-beta.304 in package.json, but
node_modules still held 6.0.0 from an older install — `npm install
--package-lock-only` (the last step of predist) rewrites only the lockfile,
so the lockfile agreed with package.json while the tree on disk stayed
stale, and the bundler took the stale tree. An install that never happened
is invisible to every other check, so it gets its own gate here.
Scope: version equality only, for every entry the lockfile lists under
node_modules. The root entry ("") is deliberately excluded — bumping
package.json makes the lockfile root version lag by design until the
`npm install --package-lock-only` at the end of predist rewrites it. */
const fs = require('node:fs')
const path = require('node:path')
const ROOT = path.join(__dirname, '..')
const lock = JSON.parse(fs.readFileSync(path.join(ROOT, 'package-lock.json'), 'utf8'))
const packages = lock.packages ?? {}
const mismatched = []
let checked = 0
// Optional entries are the cross-platform variants (darwin/linux/arm64 …) that
// npm records in the lockfile but never installs on this machine. Their absence
// is expected, not drift.
let skippedOptional = 0
for (const [key, entry] of Object.entries(packages)) {
if (key === '' || !key.startsWith('node_modules/')) continue
// The key is the path under node_modules, so it also resolves nested
// ("node_modules/a/node_modules/b") and scoped ("node_modules/@scope/pkg")
// entries without any name reconstruction.
let installed
try {
installed = JSON.parse(fs.readFileSync(path.join(ROOT, key, 'package.json'), 'utf8')).version
} catch {
installed = undefined
}
if (installed === undefined) {
if (entry.optional) skippedOptional++
else mismatched.push([key, entry.version, 'MISSING'])
continue
}
checked++
if (installed !== entry.version) mismatched.push([key, entry.version, installed])
}
if (mismatched.length) {
console.error('node_modules does not match package-lock.json:')
for (const [name, expected, actual] of mismatched) {
console.error(` ${name}: lockfile expects ${expected}, installed ${actual}`)
}
console.error('\nnode_modules 与 package-lock.json 不一致,请运行 npm ci 重装依赖')
process.exit(1)
}
console.log(`dependencies ok: ${checked} packages verified, ${skippedOptional} optional entries skipped`)
+6 -5
View File
@@ -15,19 +15,20 @@ website/
├── .nojekyll # 让 GitHub Pages 原样托管(跳过 Jekyll 处理)
└── assets/
├── style.css # 全部样式(企业风浅色主题,单一强调色)
├── shot-terminal.png # 主界面截图(四路分屏)
├── shot-themes.png # 主题设置页截图
├── shot-terminal.jpg # 主界面截图(三路分屏并行 AI 编程 Agent,含背景图个性化)
├── shot-agents.png # 多路 AI Agent 分屏截图(无背景图版)
├── shot-themes.jpg # 主题设置页截图(背景图/不透明度/压暗层)
├── shot-lock.png # 锁屏界面截图
└── icon.png # 应用图标(来自仓库 build/icon.png)
```
## 发新版本时需要更新的地方
`index.html` 中搜索 `1.0.15`,共 3 处下载链接(hero 主按钮、下载表格 exe、msi)。
下载链接使用 GitHub Releases 原生地址:
`index.html` 中搜索当前版本号,共 2 处下载链接(hero 主按钮、下载表格 exe)。
自 v1.0.22 起不再提供 MSI,只有 NSIS exe 一条直链:
```
https://github.com/billowliu2/OpenTerminal/releases/download/v<版本>/OpenTerminal-<版本>-setup.exe
https://github.com/billowliu2/OpenTerminal/releases/download/v<版本>/OpenTerminal-<版本>-setup.msi
```
注意:发布新版本时需同时把安装包资产上传到 GitHub release
Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

+57 -34
View File
@@ -37,22 +37,22 @@
内置 SFTP 文件管理与广播输入。安装即用,支持自动更新。
</p>
<div class="hero-actions">
<a class="btn btn-primary" id="dl-exe" href="https://github.com/billowliu2/OpenTerminal/releases/download/v1.0.15/OpenTerminal-1.0.15-setup.exe">
<a class="btn btn-primary" id="dl-exe" href="https://github.com/billowliu2/OpenTerminal/releases/download/v1.0.22/OpenTerminal-1.0.22-setup.exe">
下载 Windows 安装包
</a>
<a class="btn btn-ghost" href="https://github.com/billowliu2/OpenTerminal" target="_blank" rel="noopener">
查看源码
</a>
</div>
<p class="hero-note">当前版本 v1.0.15 · 提供 exe 与 msi 安装包。</p>
<p class="hero-note">当前版本 v1.0.22 · NSIS exe 安装包,支持应用内自动更新。</p>
</div>
<figure class="hero-shot">
<img src="assets/shot-terminal.png" alt="OpenTerminal 主界面:四个分屏终端会话" width="1282" height="801" />
<figcaption>四路分屏会话,每路独立连接本地或远程主机</figcaption>
<img src="assets/shot-terminal.jpg" alt="OpenTerminal 主界面:三路分屏并行运行 Kimi Code、Claude Code 与 Codex" width="1739" height="870" />
<figcaption>三路分屏并行运行 AI 编程 Agent,背景图与压暗层可自定义</figcaption>
</figure>
</div>
<div class="container spec-strip">
<span>当前版本 <strong class="mono">1.0.15</strong></span>
<span>当前版本 <strong class="mono">1.0.22</strong></span>
<span>Windows 10 / 11 · x64</span>
<span>MIT 开源协议</span>
<span>exe 支持应用内自动更新</span>
@@ -71,7 +71,7 @@
<li>node-pty 本地会话,自动探测 PowerShell / zsh / bash</li>
<li>xterm.js WebGL 渲染,声明 256 色与真彩能力,异常时自动降级</li>
<li>内嵌搜索(Ctrl+F)、命令历史、粘贴风险确认</li>
<li>关键词高亮:内置 11 条规则(错误状态、路径、IP、URL 等),支持自定义正则</li>
<li>关键词高亮:22 条内置规则(错误状态、路径、IP、URL 等),支持自定义正则与三档强度</li>
<li>字体、字重、字距、行高、光标样式实时生效</li>
</ul>
</div>
@@ -89,19 +89,49 @@
<div class="feature-row media-row">
<figure class="feature-shot">
<img src="assets/shot-themes.png" alt="OpenTerminal 主题设置:主题画廊与背景图片配置" width="1282" height="801" />
<img src="assets/shot-agents.png" alt="OpenTerminal 多路分屏运行 Kimi Code、Claude Code、Codex 等 AI 编程 Agent" width="1296" height="870" />
</figure>
<div class="feature-copy">
<h3>AI Agent 工作台</h3>
<ul>
<li>多路分屏并行运行 Kimi Code、Claude Code、Codex 等 AI 编程工具</li>
<li>为高频刷新的 TUI 界面优化:终端尺寸去抖同步,避免反复重绘</li>
<li>中文输入法候选窗紧贴光标,TUI 内输入中文不再漂移</li>
<li>关键词高亮自动标出错误、警告、HTTP 状态码与百分比</li>
</ul>
</div>
</div>
<div class="feature-row media-row">
<figure class="feature-shot">
<img src="assets/shot-themes.jpg" alt="OpenTerminal 主题设置:背景图片、不透明度、压暗层与主题画廊" width="1739" height="870" />
</figure>
<div class="feature-copy">
<h3>定制与效率</h3>
<ul>
<li>主题编辑器:22 个颜色位逐项调整,实时预览;支持自定义背景图片与不透明度</li>
<li>内置 13 套主题,跟随系统明暗自动切换</li>
<li>主题编辑器:22 个颜色位逐项调整,实时预览;支持自定义背景图片、不透明度与压暗层</li>
<li>内置 11 套主题,跟随系统明暗自动切换</li>
<li>命令库:保存常用命令片段,跨会话发送到指定终端</li>
<li>启动恢复上次会话布局;界面缩放 50% 至 150%</li>
<li>四语言界面:简体中文、繁体中文、English、日本語</li>
</ul>
</div>
</div>
<div class="feature-row media-row">
<figure class="feature-shot">
<img src="assets/shot-lock.png" alt="OpenTerminal 锁屏界面:不透明遮罩与密码解锁" width="1739" height="870" />
</figure>
<div class="feature-copy">
<h3>锁屏与安全</h3>
<ul>
<li>Ctrl+L 一键锁屏,支持闲置自动锁定与启动即锁</li>
<li>锁定期间禁用应用菜单、页面刷新与开发者工具快捷键</li>
<li>密码经 scrypt 加盐哈希存储,不落盘明文;输错触发递增冷却</li>
<li>锁屏只是遮罩:背后的终端会话与文件传输保持运行不中断</li>
</ul>
</div>
</div>
</div>
</section>
@@ -110,7 +140,7 @@
<h2>下载</h2>
<p class="section-sub">
从 GitHub Releases 下载;全部历史版本在同一页面。
<!-- 发新版本时更新下方两条直链与 hero 的 id=dl-exe 链接 -->
<!-- 发新版本时更新下方 exe 直链与 hero 的 id=dl-exe 链接 -->
</p>
<table class="dl-table">
<thead>
@@ -118,19 +148,11 @@
</thead>
<tbody>
<tr>
<td class="mono">OpenTerminal-1.0.15-setup.exe</td>
<td>常规安装,支持应用内自动更新(推荐)</td>
<td class="mono">122 MB</td>
<td class="mono">OpenTerminal-1.0.22-setup.exe</td>
<td>NSIS 安装包,支持应用内自动更新(推荐)</td>
<td class="mono">109 MB</td>
<td>
<a href="https://github.com/billowliu2/OpenTerminal/releases/download/v1.0.15/OpenTerminal-1.0.15-setup.exe">下载</a>
</td>
</tr>
<tr>
<td class="mono">OpenTerminal-1.0.15-setup.msi</td>
<td>企业批量部署(MSI 无自动更新,需手动升级)</td>
<td class="mono">135 MB</td>
<td>
<a href="https://github.com/billowliu2/OpenTerminal/releases/download/v1.0.15/OpenTerminal-1.0.15-setup.msi">下载</a>
<a href="https://github.com/billowliu2/OpenTerminal/releases/download/v1.0.22/OpenTerminal-1.0.22-setup.exe">下载</a>
</td>
</tr>
<tr>
@@ -147,8 +169,9 @@
<div class="update-note">
<h3>自动更新说明</h3>
<p>
应用内检查更新优先访问 git.codingplan.site 更新通道,失败时回退 GitHub Releases。
应用内检查更新优先访问 GitHub Releases(跟随系统代理),失败时自动回退国内 git.codingplan.site 更新通道(直连)。
更新包经 SHA-512 校验后安装。更新说明文字从发布通道的 release-notes.md 读取,与每次发布同步更新。
自 v1.0.22 起不再提供 MSI 安装包,统一使用 NSIS exe。
</p>
</div>
</div>
@@ -159,26 +182,26 @@
<h2>近期更新</h2>
<div class="changelog-list">
<article>
<h3><span class="mono">1.0.15</span> 2026-09-20</h3>
<h3><span class="mono">1.0.22</span> 2026-10-08</h3>
<ul>
<li>新增自定义终端背景图片与图片不透明度设置</li>
<li>主题编辑器重名提醒与颜色值校验</li>
<li>设置导航选中项文字对比度修复</li>
<li>修复中文输入法候选窗不跟随光标(v1.0.21 回归)</li>
<li>不再提供 MSI 安装包,统一使用 NSIS exe</li>
<li>打包流程新增依赖一致性校验,防止旧依赖混入安装包</li>
</ul>
</article>
<article>
<h3><span class="mono">1.0.14</span> 2026-09-20</h3>
<h3><span class="mono">1.0.21</span> 2026-10-07</h3>
<ul>
<li>修复大文件(约 250KB 以上)上传损坏与 SFTP 句柄泄漏</li>
<li>SSH 中文乱码、命令历史错乱等终端修复</li>
<li>权限编辑、连接错误提示等 20 余项修复</li>
<li>背景图体验:任意主题下调透明度均为压暗、文字自动提亮到 WCAG AA、新增背景压暗滑杆</li>
<li>性能:设置热更不再触发全窗格重排,SFTP 大目录虚拟滚动,面板独立错误边界</li>
<li>安装包精简约 90MB;SFTP/ZMODEM 本地路径准入与多处安全加固</li>
</ul>
</article>
<article>
<h3><span class="mono">1.0.13</span> 2026-09-20</h3>
<h3><span class="mono">1.0.20</span> 2026-10-01</h3>
<ul>
<li>命令片段库与广播输入改进</li>
<li>监控面板历史曲线实时重绘</li>
<li>修复中文输入法候选窗不跟随光标</li>
<li>锁屏加固:锁定期间移除应用菜单,Ctrl+L 按键判定重构并补测试</li>
</ul>
</article>
</div>