From a0d0e4cb012c28adcc121a00374ae966aa60249e Mon Sep 17 00:00:00 2001 From: lencx Date: Wed, 22 Jul 2026 22:53:32 +0800 Subject: [PATCH] fix(docs): use portable README links --- README.md | 28 ++++++++++++++-------------- README.zh-CN.md | 28 ++++++++++++++-------------- packages/node/test/skill.test.js | 24 ++++++++++++++++++++---- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index e1044e0..990fd88 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ English | 简体中文

-Buy Me A Coffee +Buy Me A Coffee Opsail is a modular native toolkit that gives software agents small, composable, and reliable capabilities through one command-line entry point. Its Rust crates keep acquisition, browser control, content extraction, and application-specific refits behind explicit boundaries, while the Node.js package makes the same native runtime easy to embed. @@ -33,13 +33,13 @@ opsail read https://example.com/article opsail read https://example.com/app --launch ``` -See [`opsail-read`](crates/opsail-read/README.md) for acquisition, extraction, result contracts, and Rust APIs. See [`opsail-chrome`](crates/opsail-chrome/README.md) for Chrome discovery, owned launch, borrowed CDP, navigation, and rendered DOM capture. +See [`opsail-read`](https://github.com/lencx/opsail/blob/main/crates/opsail-read/README.md) for acquisition, extraction, result contracts, and Rust APIs. See [`opsail-chrome`](https://github.com/lencx/opsail/blob/main/crates/opsail-chrome/README.md) for Chrome discovery, owned launch, borrowed CDP, navigation, and rendered DOM capture. ### Refit Codex `opsail refit codex` provides a reversible, target-validated Codex adapter. Its first feature adds localized remaining-usage information to the Codex sidebar using the renderer's existing local bridge, without model calls or changes to the application bundle. -![refit-codex](assets/refit-codex.png) +![refit-codex](https://raw.githubusercontent.com/lencx/opsail/main/assets/refit-codex.png) The refit target is implemented for the signed macOS application and the current-user Microsoft Store application on Windows; Linux is not supported. Windows release targets are x64 and ARM64; no 32-bit x86/ia32 artifact is provided. Opsail resolves the exact package family and AUMID, derives the application executable from the installed signed manifest (currently `app\ChatGPT.exe`), and protects its Local AppData state with an explicit current-user-and-SYSTEM DACL. Native CI and npm packaging targets are configured for both Windows architectures. A Windows 11 ARM64 canary against the installed Store application validates package activation, listener ownership, renderer discovery, bridge injection, persistence, and cleanup; a real installed-application x64 canary remains pending, while hosted CI covers the no-installed-package path. @@ -51,17 +51,17 @@ Persistent mode starts a validated background manager and returns after its heal Interactive waits show their current validated lifecycle stage on `stderr`, while the final machine-readable JSON remains isolated on `stdout`. -See [`opsail-refit-codex`](crates/opsail-refit-codex/README.md) for supported targets, attach and launch modes, lifecycle semantics, renderer updates, localization, security checks, and library APIs. +See [`opsail-refit-codex`](https://github.com/lencx/opsail/blob/main/crates/opsail-refit-codex/README.md) for supported targets, attach and launch modes, lifecycle semantics, renderer updates, localization, security checks, and library APIs. ## Packages | Package | Responsibility | Documentation | | --- | --- | --- | | [`opsail`](https://crates.io/crates/opsail) | Native CLI and unified command entry point | Run `opsail --help` | -| [`opsail-read`](https://crates.io/crates/opsail-read) | Content acquisition, extraction, sanitization, and result contracts | [README](crates/opsail-read/README.md) | -| [`opsail-chrome`](https://crates.io/crates/opsail-chrome) | Cross-platform Chrome lifecycle, CDP transport, and rendered capture | [README](crates/opsail-chrome/README.md) | -| [`opsail-refit-codex`](https://crates.io/crates/opsail-refit-codex) | Validated Codex refit lifecycle, usage semantics, localization, and UI payload | [README](crates/opsail-refit-codex/README.md) | -| [`opsail`](https://www.npmjs.com/package/opsail) for Node.js | ESM API and native binary distribution | [README](packages/node/README.md) | +| [`opsail-read`](https://crates.io/crates/opsail-read) | Content acquisition, extraction, sanitization, and result contracts | [README](https://github.com/lencx/opsail/blob/main/crates/opsail-read/README.md) | +| [`opsail-chrome`](https://crates.io/crates/opsail-chrome) | Cross-platform Chrome lifecycle, CDP transport, and rendered capture | [README](https://github.com/lencx/opsail/blob/main/crates/opsail-chrome/README.md) | +| [`opsail-refit-codex`](https://crates.io/crates/opsail-refit-codex) | Validated Codex refit lifecycle, usage semantics, localization, and UI payload | [README](https://github.com/lencx/opsail/blob/main/crates/opsail-refit-codex/README.md) | +| [`opsail`](https://www.npmjs.com/package/opsail) for Node.js | ESM API and native binary distribution | [README](https://github.com/lencx/opsail/blob/main/packages/node/README.md) | ## Install @@ -77,15 +77,15 @@ Install the Node.js API and CLI from npm: npm install opsail ``` -Prebuilt native binaries are available from [GitHub Releases](https://github.com/lencx/opsail/releases/latest). Agent hosts can use the reviewed [`bootstrap-opsail` Skill](skills/bootstrap-opsail/SKILL.md) to reconcile the CLI and runtime Skill with explicit approval. +Prebuilt native binaries are available from [GitHub Releases](https://github.com/lencx/opsail/releases/latest). Agent hosts can use the reviewed [`bootstrap-opsail` Skill](https://github.com/lencx/opsail/blob/main/skills/bootstrap-opsail/SKILL.md) to reconcile the CLI and runtime Skill with explicit approval. ## Project documentation -- [Content extraction and result model](crates/opsail-read/README.md) -- [Chrome and CDP integration](crates/opsail-chrome/README.md) -- [Codex sidebar refit](crates/opsail-refit-codex/README.md) -- [Node.js API and packaging](packages/node/README.md) -- [Development and contribution guide](CONTRIBUTING.md) +- [Content extraction and result model](https://github.com/lencx/opsail/blob/main/crates/opsail-read/README.md) +- [Chrome and CDP integration](https://github.com/lencx/opsail/blob/main/crates/opsail-chrome/README.md) +- [Codex sidebar refit](https://github.com/lencx/opsail/blob/main/crates/opsail-refit-codex/README.md) +- [Node.js API and packaging](https://github.com/lencx/opsail/blob/main/packages/node/README.md) +- [Development and contribution guide](https://github.com/lencx/opsail/blob/main/CONTRIBUTING.md) ## License diff --git a/README.zh-CN.md b/README.zh-CN.md index c502cc2..eaaf914 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -10,7 +10,7 @@ English | 简体中文

-Buy Me A Coffee +Buy Me A Coffee Opsail 是一个模块化原生工具集,通过统一的命令行入口,为软件 Agent 提供小而可组合、行为可靠的能力。它使用职责清晰的 Rust crate 隔离内容获取、浏览器控制、正文提取和应用适配,并通过 Node.js 包方便地嵌入同一套原生运行时。 @@ -33,13 +33,13 @@ opsail read https://example.com/article opsail read https://example.com/app --launch ``` -内容获取、正文提取、结果契约和 Rust API 请参阅 [`opsail-read`](crates/opsail-read/README.md);Chrome 发现、自有启动、借用 CDP、页面导航和渲染 DOM 捕获请参阅 [`opsail-chrome`](crates/opsail-chrome/README.md)。 +内容获取、正文提取、结果契约和 Rust API 请参阅 [`opsail-read`](https://github.com/lencx/opsail/blob/main/crates/opsail-read/README.md);Chrome 发现、自有启动、借用 CDP、页面导航和渲染 DOM 捕获请参阅 [`opsail-chrome`](https://github.com/lencx/opsail/blob/main/crates/opsail-chrome/README.md)。 ### Codex Refit `opsail refit codex` 提供可逆且经过目标校验的 Codex 适配器。它的首个功能通过 renderer 已有的本地 bridge,在 Codex 左侧栏显示本地化的剩余额度信息,不调用模型,也不修改应用包。 -![refit-codex](assets/refit-codex.png) +![refit-codex](https://raw.githubusercontent.com/lencx/opsail/main/assets/refit-codex.png) Refit 目标已实现对签名 macOS 应用和 Windows 当前用户 Microsoft Store 应用的支持;Linux 不支持。Windows 发布目标为 x64 和 ARM64,不提供 32 位 x86/ia32 产物。Windows 实现使用精确的包家族名和 AUMID 定位应用,从已安装的签名 manifest 中解析可执行文件(当前为 `app\ChatGPT.exe`),并使用仅授权当前用户和 SYSTEM 的显式 DACL 保护 Local AppData 状态。Windows x64 和 ARM64 都已配置原生 CI 与 npm 打包目标;已在 Windows 11 ARM64 的 Store 应用上完成包激活、端口归属、renderer 发现、bridge 注入、持久模式与清理的端到端验证,真实 x64 Store 应用 canary 仍待完成,托管 CI 覆盖未安装目标包的路径。 @@ -51,17 +51,17 @@ opsail refit codex enable usage --launch 交互式等待会在 `stderr` 中显示当前经过校验的生命周期阶段,最终供程序读取的 JSON 仍只写入 `stdout`。 -支持目标、附加与启动模式、生命周期语义、renderer 更新、多语言、安全校验和库 API 请参阅 [`opsail-refit-codex`](crates/opsail-refit-codex/README.md)。 +支持目标、附加与启动模式、生命周期语义、renderer 更新、多语言、安全校验和库 API 请参阅 [`opsail-refit-codex`](https://github.com/lencx/opsail/blob/main/crates/opsail-refit-codex/README.md)。 ## 包结构 | 包 | 职责 | 文档 | | --- | --- | --- | | [`opsail`](https://crates.io/crates/opsail) | 原生 CLI 与统一命令入口 | 运行 `opsail --help` | -| [`opsail-read`](https://crates.io/crates/opsail-read) | 内容获取、正文提取、清理和结果契约 | [README](crates/opsail-read/README.md) | -| [`opsail-chrome`](https://crates.io/crates/opsail-chrome) | 跨平台 Chrome 生命周期、CDP 传输和渲染捕获 | [README](crates/opsail-chrome/README.md) | -| [`opsail-refit-codex`](https://crates.io/crates/opsail-refit-codex) | Codex 适配生命周期、额度语义、多语言和 UI payload | [README](crates/opsail-refit-codex/README.md) | -| Node.js [`opsail`](https://www.npmjs.com/package/opsail) | ESM API 与原生二进制分发 | [README](packages/node/README.md) | +| [`opsail-read`](https://crates.io/crates/opsail-read) | 内容获取、正文提取、清理和结果契约 | [README](https://github.com/lencx/opsail/blob/main/crates/opsail-read/README.md) | +| [`opsail-chrome`](https://crates.io/crates/opsail-chrome) | 跨平台 Chrome 生命周期、CDP 传输和渲染捕获 | [README](https://github.com/lencx/opsail/blob/main/crates/opsail-chrome/README.md) | +| [`opsail-refit-codex`](https://crates.io/crates/opsail-refit-codex) | Codex 适配生命周期、额度语义、多语言和 UI payload | [README](https://github.com/lencx/opsail/blob/main/crates/opsail-refit-codex/README.md) | +| Node.js [`opsail`](https://www.npmjs.com/package/opsail) | ESM API 与原生二进制分发 | [README](https://github.com/lencx/opsail/blob/main/packages/node/README.md) | ## 安装 @@ -77,15 +77,15 @@ cargo install opsail npm install opsail ``` -预编译原生二进制可从 [GitHub Releases](https://github.com/lencx/opsail/releases/latest) 下载。Agent 宿主可以在明确授权后,使用经过审阅的 [`bootstrap-opsail` Skill](skills/bootstrap-opsail/SKILL.md) 同步 CLI 和运行时 Skill。 +预编译原生二进制可从 [GitHub Releases](https://github.com/lencx/opsail/releases/latest) 下载。Agent 宿主可以在明确授权后,使用经过审阅的 [`bootstrap-opsail` Skill](https://github.com/lencx/opsail/blob/main/skills/bootstrap-opsail/SKILL.md) 同步 CLI 和运行时 Skill。 ## 项目文档 -- [内容提取与结果模型](crates/opsail-read/README.md) -- [Chrome 与 CDP 集成](crates/opsail-chrome/README.md) -- [Codex 左侧栏 Refit](crates/opsail-refit-codex/README.md) -- [Node.js API 与打包](packages/node/README.md) -- [开发与贡献指南](CONTRIBUTING.md) +- [内容提取与结果模型](https://github.com/lencx/opsail/blob/main/crates/opsail-read/README.md) +- [Chrome 与 CDP 集成](https://github.com/lencx/opsail/blob/main/crates/opsail-chrome/README.md) +- [Codex 左侧栏 Refit](https://github.com/lencx/opsail/blob/main/crates/opsail-refit-codex/README.md) +- [Node.js API 与打包](https://github.com/lencx/opsail/blob/main/packages/node/README.md) +- [开发与贡献指南](https://github.com/lencx/opsail/blob/main/CONTRIBUTING.md) ## 许可证 diff --git a/packages/node/test/skill.test.js b/packages/node/test/skill.test.js index e3e774b..58daca6 100644 --- a/packages/node/test/skill.test.js +++ b/packages/node/test/skill.test.js @@ -20,6 +20,7 @@ const opsailSkillPath = path.join( "SKILL.md", ); const readmePath = path.join(repositoryRoot, "README.md"); +const readmeZhPath = path.join(repositoryRoot, "README.zh-CN.md"); const releaseWorkflowPath = path.join( repositoryRoot, ".github", @@ -120,16 +121,31 @@ test("bootstrap is independently versioned and runtime matches the public packag }); test("root README stays concise and release workflow keeps one installer source", async () => { - const [readme, releaseWorkflow] = await Promise.all([ + const [readme, readmeZh, releaseWorkflow] = await Promise.all([ readFile(readmePath, "utf8"), + readFile(readmeZhPath, "utf8"), readFile(releaseWorkflowPath, "utf8"), ]); assert.match(readme, /## Core characteristics/); - assert.match(readme, /See \[`opsail-read`\]\(crates\/opsail-read\/README\.md\)/); - assert.match(readme, /See \[`opsail-refit-codex`\]\(crates\/opsail-refit-codex\/README\.md\)/); + assert.match( + readme, + /See \[`opsail-read`\]\(https:\/\/github\.com\/lencx\/opsail\/blob\/main\/crates\/opsail-read\/README\.md\)/, + ); + assert.match( + readme, + /See \[`opsail-refit-codex`\]\(https:\/\/github\.com\/lencx\/opsail\/blob\/main\/crates\/opsail-refit-codex\/README\.md\)/, + ); assert.match(readme, /\[GitHub Releases\]\(https:\/\/github\.com\/lencx\/opsail\/releases\/latest\)/); - assert.match(readme, /\[`bootstrap-opsail` Skill\]\(skills\/bootstrap-opsail\/SKILL\.md\)/); + assert.match( + readme, + /\[`bootstrap-opsail` Skill\]\(https:\/\/github\.com\/lencx\/opsail\/blob\/main\/skills\/bootstrap-opsail\/SKILL\.md\)/, + ); + for (const source of [readme, readmeZh]) { + assert.doesNotMatch(source, /!?\[[^\]]*\]\((?!https:\/\/|#)[^)]+\)/); + assert.doesNotMatch(source, /(?:href|src)="(?!https:\/\/|#)[^"]+"/); + assert.doesNotMatch(source, /^\s*\[[^\]]+\]:\s*(?!https:\/\/|#)\S+/m); + } assert.ok(readme.split("\n").length <= 100); assert.doesNotMatch( readme,