Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
37484b9
feat(release): split public and ChatGPT developer manifest builds
CoderLambert Oct 21, 2026
653e1dd
feat(release): split public and ChatGPT developer manifest builds
CoderLambert Oct 21, 2026
16505a7
feat(release): split public and ChatGPT developer manifest builds
CoderLambert Oct 21, 2026
a9d2672
feat(release): split public and ChatGPT developer manifest builds
CoderLambert Oct 21, 2026
3f9fced
feat(release): guard ChatGPT in public and build an explicit develope…
CoderLambert Oct 21, 2026
7675b91
feat(release): guard ChatGPT in public and build an explicit develope…
CoderLambert Oct 21, 2026
0bfc7a2
feat(release): guard ChatGPT in public and build an explicit develope…
CoderLambert Oct 21, 2026
2a9060b
feat(release): guard ChatGPT in public and build an explicit develope…
CoderLambert Oct 21, 2026
ad50e3c
feat(ui): show GitHub developer-build notice in public settings
CoderLambert Oct 21, 2026
e08e405
feat(ui): show GitHub developer-build notice in public settings
CoderLambert Oct 21, 2026
02067dc
feat(ui): show GitHub developer-build notice in public settings
CoderLambert Oct 21, 2026
2f1a03a
test(release): assert public ChatGPT isolation and developer build su…
CoderLambert Oct 21, 2026
8688434
test(release): assert public ChatGPT isolation and developer build su…
CoderLambert Oct 21, 2026
be44a28
test(ui): distinguish public notice and developer native-host flow
CoderLambert Oct 21, 2026
954ed04
test(ui): distinguish public notice and developer native-host flow
CoderLambert Oct 21, 2026
14b7cc2
docs(release): self-built ChatGPT developer edition and host setup
CoderLambert Oct 21, 2026
cb5ca57
ci(release): generate audited ChatGPT developer ZIP on PR or request
CoderLambert Oct 21, 2026
3af23e2
fix(release): detect developer edition after test-only native permiss…
CoderLambert Oct 21, 2026
5f375df
test(release): developer marker survives approved E2E permission proj…
CoderLambert Oct 21, 2026
4bf728a
Merge remote-tracking branch 'origin/main' into integration/latest-ma…
Oct 27, 2026
e9f3b84
chore(build): integrate removal of legacy size budget
Oct 27, 2026
e2b8e62
feat(translation): add semantic and format source contract
CoderLambert Oct 18, 2026
4e85c81
test(translation): cover semantic source identity and protection
CoderLambert Oct 18, 2026
b7e781b
build: prepare integrated 0.8.48 public and developer editions
Oct 27, 2026
c8b5b59
fix: resolve integrated build typing and legacy content upgrade failures
Oct 27, 2026
15c1498
docs: archive 0.8.48 integration acceptance
Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions .github/workflows/chatgpt-dev-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: chatgpt-dev-build

on:
workflow_dispatch:

permissions:
contents: read

jobs:
developer-artifact:
runs-on: ubuntu-latest
timeout-minutes: 35
env:
TF_TEST_WORKERS: "1"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "24.21.0"
- run: npm ci --no-audit --no-fund
- name: Focused release and provider checks
run: node --test tests/wxt-assets.test.mjs tests/chatgpt-plan-provider.test.mjs
- name: Public production package
run: npm run build:extension:release
- name: Audited ChatGPT developer package
run: npm run build:extension:dev
- name: Verify both Manifest editions
run: |
node --input-type=module <<'NODE'
import { readFileSync } from 'node:fs';
import assert from 'node:assert/strict';
const pub = JSON.parse(readFileSync('dist/extension/manifest.json', 'utf8'));
const dev = JSON.parse(readFileSync('dist/extension-dev/manifest.json', 'utf8'));
assert.equal(pub.version_name, undefined);
assert.equal(dev.version_name, `${dev.version}-dev`);
assert.deepEqual(dev.host_permissions, pub.host_permissions);
assert.deepEqual(dev.permissions, pub.permissions);
assert.deepEqual(dev.optional_permissions, pub.optional_permissions);
NODE
- name: Prepare Chromium
run: npx playwright install --with-deps chromium
- name: Public ChatGPT UI regression
env:
TF_E2E_ARTIFACT: dist/extension
TF_I18N_ARTIFACT: dist/extension
run: npm run test:e2e -- e2e/chatgpt-plan-nativehost.spec.mjs
- name: Developer ChatGPT UI regression
env:
TF_E2E_ARTIFACT: dist/extension-dev
TF_I18N_ARTIFACT: dist/extension-dev
run: npm run test:e2e -- e2e/chatgpt-plan-nativehost.spec.mjs
- name: Pack verified unpacked developer edition
run: |
mkdir -p artifacts
(cd dist/extension-dev && zip -qr ../../artifacts/translateflow-extension-dev.zip .)
unzip -p artifacts/translateflow-extension-dev.zip manifest.json | node -e '
let s=""; process.stdin.on("data",c=>s+=c).on("end",()=>{
const m=JSON.parse(s);
if (m.version_name !== m.version+"-dev") process.exit(1);
});'
(cd artifacts && sha256sum translateflow-extension-dev.zip > SHA256SUMS)
git rev-parse HEAD > artifacts/SOURCE_COMMIT.txt
- name: Upload developer extension and checksums
uses: actions/upload-artifact@v4
with:
name: translateflow-chatgpt-developer-${{ github.run_id }}
path: artifacts/
if-no-files-found: error
retention-days: 30
- name: Upload focused E2E evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: chatgpt-dev-e2e-${{ github.run_id }}
path: test-results/
if-no-files-found: ignore
retention-days: 7
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# TranslateFlow v0.8.47
# TranslateFlow v0.8.48

轻量、缓存优先的 Chrome Manifest V3 双语网页翻译扩展。单词查词与句段/全文分别保存一种翻译方式:单词可选免费在线、词典、Chrome 本地或 AI;短语、句子、段落和全文可选 AI、Chrome 本地或免费在线。未命中、未就绪或失败时保留所选方式,用户可在划选面板临时切换。字幕保持独立路径。直接支持 OpenAI、Anthropic、Gemini 与主流 OpenAI-compatible API,并按有效配置与原文指纹缓存结果。

Expand Down
62 changes: 62 additions & 0 deletions docs/CHATGPT_DEVELOPMENT_BUILD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# TranslateFlow ChatGPT 订阅实验开发版

> 开发者预览;**不是** Chrome Web Store 发行版。此功能需要使用自己的本机 Native Host、符合条件的 ChatGPT 账号及官方授权。实验实现或模拟测试通过不代表已获得公共应用接入许可、真实套餐权限或商店审核通过。

## 公开版与开发版

- **公开版(默认)**:保留普通网页、划词、字幕、本地词典、API Key/自托管模型翻译;在设置 → Provider 只显示 ChatGPT 订阅开发者预览提示及本页链接。隐藏登录、模型和 Host 命令。保存过的订阅配置不会被删除,但公开版拒绝订阅推理。
- **开发版(单独构建)**:扩展 Manifest 额外带 `version_name: "<version>-dev"`,解锁现有 ChatGPT 订阅设置和 Native Messaging 连接。Chrome 应使用“加载已解压的扩展程序”安装,不属于 Chrome 商店自动更新渠道。
- 两个版本使用同一份 Provider/缓存/页面代码,不创建第二套翻译引擎;默认 `npm run build:extension` 和 `npm run build:extension:release` 始终生成公开版。

## 获取开发版 ZIP(GitHub Actions)

在项目 [GitHub Actions — ChatGPT developer extension](https://github.com/CoderLambert/translateflow-plugin/actions/workflows/chatgpt-dev-build.yml) 页面,打开一次成功的运行并下载 `translateflow-chatgpt-developer-<run-id>` Artifact(通常需登录 GitHub)。压缩包中含独立的 `translateflow-extension-dev.zip`、`SHA256SUMS` 和 `SOURCE_COMMIT.txt`。

如果暂无成功运行,维护者可从默认分支手动运行该 workflow;也可以按下方从源码构建。不要下载来源不明的“已配置好 ChatGPT 账号”的扩展包。

解压 `translateflow-extension-dev.zip` 到一个空目录,确认目录根部有 `manifest.json`,并确认其中 `version_name` 以 `-dev` 结尾。在 Chrome 打开 `chrome://extensions`、启用开发者模式,点击“加载已解压的扩展程序”选择此目录。复制页面显示的 **32 位扩展 ID**。本地安装路径变化或重新安装可能产生不同 ID,Host 必须使用这次实际显示的 ID。

## 自行从源码构建

环境:Node.js 24.21.x、npm 11.19.x;从可信 Git 提交获取源码:

```bash
git clone https://github.com/CoderLambert/translateflow-plugin.git
cd translateflow-plugin
npm ci
npm run build:extension:dev
```

输出在 `dist/extension-dev/`,将该目录加载为 unpacked 扩展。默认公开构建仍在 `dist/extension/`,互不覆盖。需要自己压缩时,应从 `dist/extension-dev` 目录内部创建 ZIP,使 `manifest.json` 位于归档根部。

## Native Host 本机配置(需要 Go 1.26+)

Native Host **不随扩展 ZIP 自动安装**,账号令牌不进入扩展 ZIP。当前尚无面向公众的已签名稳定 Host 可下载,开发者需自行从可信源码构建并进行当前用户级安装。

在**同一个仓库 checkout** 里,在扩展安装后将 `<扩展ID>` 换成 `chrome://extensions` 当前显示的 ID:

```bash
TF_CHROME_EXTENSION_ID=<扩展ID> TF_NATIVE_HOST_VERSION=0.8.48 npm run build:native-host:candidate
```

`TF_NATIVE_HOST_VERSION` 必须与当前候选扩展版本相符;更新版本后请按实际 `manifest.json` 更新它。构建产物位于 `.output/native-host-candidate/`,生成 `release-candidate.json`、`SHA256SUMS` 和适用于 Linux/Windows x64 的候选二进制。候选标记为 `publishable:false`、`NOT_SIGNED`,**不得当作已签名公共安装包分发或绕过系统的未知发布者警告**。

Linux(Google Chrome)自建示例:

```bash
./.output/native-host-candidate/translateflow-host-0.8.48-linux-amd64 install --extension-id <扩展ID> --browser chrome
```

如果使用 Chromium 而不是 Chrome,将最后一个参数改为 `--browser chromium`。Windows 在 PowerShell 中构建候选后,使用相应 `windows-amd64.exe install --extension-id <扩展ID>` 安装。具体平台、安装注册位置和安全边界见 [Native Host 安装文档](../native-host/INSTALLATION.md)。

Linux 图形会话还必须提供已解锁的 Secret Service;Windows 使用 DPAPI。插件不会替用户安装或解锁密钥环。Native Host 的卸载不会自动清除账号凭据,退出账号请先使用插件的“退出登录”操作。

## 使用与安全边界

1. 在开发版设置 → Provider → ChatGPT 订阅,明确点击启用 `nativeMessaging` 权限。
2. 检测 Host 后,点击“连接 ChatGPT 账号”,在官方授权页确认 `chatgpt.tokens.use.direct` 等实际授权范围。
3. 授权完成后从账号返回的列表选择模型、保存设置,再用非隐私测试句验证翻译。测试前不要输入账号密钥、网页私人内容或未脱敏日志。
4. 服务可能因账号资格、套餐额度、地区、模型或 OpenAI 接入审批限制而拒绝请求;**不通过私人网页登录态、Cookie、非官方接口绕过限制**。
5. OAuth 真实授权、套餐用量、系统安全存储与 Windows/Linux 安装均须由开发者在自己的环境中明确执行;自动化测试使用模拟输入,不触发真实账号操作。

Chrome Web Store 发行版不承诺此功能可用。开发者版独立试验不影响普通 API Key、Chrome 本地翻译、词典和字幕功能。
2 changes: 2 additions & 0 deletions docs/WXT_COMPAT_V1.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ npm run test:wxt:smoke

WXT compiles Background, Content, Popup, Options and the learning center from their existing owners. Only mapped MAIN/Worker relative-import closures and locales remain raw assets. `src/shared/runtime-assets.js` owns the stable runtime paths. The package audit rejects undeclared public assets and preserves source confinement, exact Worker/MAIN bytes, manifest permissions and compiled React boundaries. Source locks, corpora, compilers, docs and tests stay outside the package.

Package size, platform code size and runtime/UI closure sizes are reported as measurements. Builds have no package-size threshold or advisory budget; the former #245 platform-code budget and its overage warnings are retired. Historical budget figures below remain evidence of the original migration.

The default empty dictionary library is normal. Users explicitly download or import dictionaries; production never probes missing bundled resources. Smoke and browser tests start from actual audited production bytes and explicitly prepare synthetic user dictionaries in isolated storage for tests requiring hits. They do not add runtime dictionary assets to the extension copy.

Content remains an ISOLATED classic/IIFE registry compiled to `content-scripts/content.js/.css`; MAIN and Workers retain their existing contexts. Permissions, OPFS schemas and user settings are unaffected by dictionary content removal.
Expand Down
7 changes: 7 additions & 0 deletions docs/tasks/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,13 @@
"branch": "feat/free-online-mt-20261016",
"candidateHead": "0d245001483b7b653452e0c0889f713c310be7fe"
},
{
"task": "latest-main-build",
"status": "ready_to_sync",
"dependencies": [],
"branch": "integration/latest-main-local-build",
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2"
},
{
"task": "offline-dictionary",
"status": "working",
Expand Down
186 changes: 186 additions & 0 deletions docs/tasks/latest-main-build/acceptance.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
{
"schema": 1,
"task": "latest-main-build",
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"tree": "dbe6f1a773751cf0b9ed51a61ee8c028aec32a34",
"inputTree": "b78459d34329a551ffa7ae83c1225c8de80683fa64d75edcef2f61313ac24eef",
"frozenAt": "2026-10-27T15:55:50.762Z",
"environment": {
"node": "v24.21.0",
"npm": "11.19.0",
"browser": "153.0.8010.12"
},
"checks": [
{
"command": [
"npm",
"run",
"check"
],
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"result": "PASS",
"exitCode": 0,
"signal": null,
"durationMs": 16179.662654,
"startedAt": "2026-10-27T15:55:50.908Z",
"log": "docs/task-execution/local/latest-main-build/273ee5f3-a744-40d3-b68f-474350411c69.log",
"logSha256": "4f6357b014a55284d3d44370d94b89ae0c96fb1b2c955fd8dcd8590f0b0d2139"
},
{
"command": [
"npm",
"test"
],
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"result": "PASS",
"exitCode": 0,
"signal": null,
"durationMs": 48626.876569,
"startedAt": "2026-10-27T15:56:07.243Z",
"log": "docs/task-execution/local/latest-main-build/cc277a88-7287-4701-bf99-c6a4b7dc3cc2.log",
"logSha256": "e341519d9b2ab8f6661c5986aa59ddb7d2c9eab48c8a486fc8a02aee98881eb3"
},
{
"command": [
"npm",
"run",
"typecheck"
],
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"result": "PASS",
"exitCode": 0,
"signal": null,
"durationMs": 5005.334612,
"startedAt": "2026-10-27T15:56:56.025Z",
"log": "docs/task-execution/local/latest-main-build/555af830-6825-41b3-ae5e-4834c9f943f0.log",
"logSha256": "723d94fda5dea4eb02261a721afd95ff1d33d5f53a6da4626f70f8fda0b582c8"
},
{
"command": [
"npm",
"run",
"test:unit"
],
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"result": "PASS",
"exitCode": 0,
"signal": null,
"durationMs": 4493.682776,
"startedAt": "2026-10-27T15:57:01.180Z",
"log": "docs/task-execution/local/latest-main-build/8dba4de5-53d5-4331-8ae7-09359ef2ad45.log",
"logSha256": "8515d27f3fc8cd1e65e0a3eb26b9ca8741a781eb7a6fde946ad7cc9aefa39a56"
},
{
"command": [
"npm",
"run",
"build:extension"
],
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"result": "PASS",
"exitCode": 0,
"signal": null,
"durationMs": 2520.789114,
"startedAt": "2026-10-27T15:57:05.824Z",
"log": "docs/task-execution/local/latest-main-build/2ae4e67e-bb21-41a4-934a-15c872d4c584.log",
"logSha256": "f1184c25958f820adc299a8317d46d58a4ae87766d963dd5a2bd4e8fb37fdaf4"
},
{
"command": [
"npm",
"run",
"build:extension:dev"
],
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"result": "PASS",
"exitCode": 0,
"signal": null,
"durationMs": 2536.123104,
"startedAt": "2026-10-27T15:57:08.496Z",
"log": "docs/task-execution/local/latest-main-build/20faaac7-41ed-449e-89ef-422905493530.log",
"logSha256": "bd0e32ea4455d22b462e23365489ccea24be8bde34f817f73116380607761037"
},
{
"command": [
"env",
"TF_E2E_ARTIFACT=dist/extension",
"TF_I18N_ARTIFACT=dist/extension",
"npm",
"run",
"test:e2e",
"--",
"e2e/chatgpt-plan-nativehost.spec.mjs",
"e2e/provider-connections.spec.mjs"
],
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"result": "PASS",
"exitCode": 0,
"signal": null,
"durationMs": 10472.777184,
"startedAt": "2026-10-27T15:57:11.184Z",
"log": "docs/task-execution/local/latest-main-build/4eeaaccc-2e3f-4716-8869-0bc809c7ce8d.log",
"logSha256": "bc0601b4ef192c55f4bceec40aac67796e2aea82e0b845df5e3ae08efb5593ac"
},
{
"command": [
"env",
"TF_E2E_ARTIFACT=dist/extension-dev",
"TF_I18N_ARTIFACT=dist/extension-dev",
"npm",
"run",
"test:e2e",
"--",
"e2e/chatgpt-plan-nativehost.spec.mjs"
],
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"result": "PASS",
"exitCode": 0,
"signal": null,
"durationMs": 4032.287493,
"startedAt": "2026-10-27T15:57:21.814Z",
"log": "docs/task-execution/local/latest-main-build/a0d67615-354c-4af2-8883-f5b512aa5f58.log",
"logSha256": "f62c972645ab2012d328124c881068c4bdb193c709354974ceca42e829b8fad5"
},
{
"command": [
"npm",
"run",
"build:extension:wxt"
],
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"result": "PASS",
"exitCode": 0,
"signal": null,
"durationMs": 2646.252689,
"startedAt": "2026-10-27T15:57:26.010Z",
"log": "docs/task-execution/local/latest-main-build/533a5756-f22e-4848-8233-6076ecb92544.log",
"logSha256": "8a6c79830c349098d90d229fd3ce4aa93a5d6db0c42da0dbeba548238962a240"
},
{
"command": [
"env",
"TF_SMOKE_ARTIFACT=dist/extension",
"npm",
"run",
"test:wxt:smoke"
],
"candidateHead": "c8b5b59b91cfaa51f2ab261df7670f3fa8d5f1c2",
"result": "PASS",
"exitCode": 0,
"signal": null,
"durationMs": 1215.034773,
"startedAt": "2026-10-27T15:57:28.810Z",
"log": "docs/task-execution/local/latest-main-build/6e18423f-4e4c-4435-9328-7bb8bd7c2f21.log",
"logSha256": "02f6e9c96cbafeee592bcf4e4d693cbf22b966d03c4a43e7d10e44141cde4607"
}
],
"artifact": {
"path": "dist/extension",
"treeSha256": "32a9a5cb8a6065bb46dfb65f37cb57359598ee5a55638d2f6cf0f8b638172a8b"
},
"limitations": ["Full validate stages were executed as separately recorded commands, not a single npm run validate invocation.", "Public and developer E2E each skip only the case for the other edition; all applicable cases passed.", "Real account OAuth, paid Provider, user browser installation identity, full E2E and Chrome Web Store delivery were not tested.", "Initial candidate b7e781b9 failures remain in ignored local first-acceptance.json and logs; final candidate resolves all recorded failures."],
"developerArtifact": {
"path": "dist/extension-dev",
"treeSha256": "ebca883fdb8071abbfd074b18a274b2d0d34080c64e4fb313799366af6b9052c"
}
}
Loading