fix: enforce centralized version inputs

This commit is contained in:
Kayshen-X 2026-07-15 21:10:09 +08:00
parent e28506d0af
commit f82f4e4ea3
20 changed files with 345 additions and 54 deletions

View file

@ -5,6 +5,7 @@ on:
paths:
- "Cargo.toml"
- "Cargo.lock"
- "README*.md"
- "crates/**/Cargo.toml"
- "crates/**/*.rs"
- "crates/op-cli/assets/skill-bundle.json"
@ -27,6 +28,7 @@ on:
- "scripts/install-op.sh"
- "tools/check-version-sync.sh"
- "tools/check-version-sync.test.sh"
- "tools/check-version-sync-policy.test-cases.sh"
- "tools/bundle-macos.sh"
- ".githooks/pre-commit"
- ".github/workflows/rust-release.yml"
@ -35,6 +37,7 @@ on:
paths:
- "Cargo.toml"
- "Cargo.lock"
- "README*.md"
- "crates/**/Cargo.toml"
- "crates/**/*.rs"
- "crates/op-cli/assets/skill-bundle.json"
@ -57,6 +60,7 @@ on:
- "scripts/install-op.sh"
- "tools/check-version-sync.sh"
- "tools/check-version-sync.test.sh"
- "tools/check-version-sync-policy.test-cases.sh"
- "tools/bundle-macos.sh"
- ".githooks/pre-commit"
- ".github/workflows/rust-release.yml"

View file

@ -123,14 +123,15 @@ Getaggte Rust-Releases veröffentlichen ein einzelnes Web-Host-Image. Die frühe
| Image | Enthält |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust-Web-Host, wasm bundle und CanvasKit-Assets |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust-Web-Host, wasm bundle und CanvasKit-Assets |
Die Web-UI zeigt nur integrierte Agent-Profile; Claude/Codex/OpenCode/Copilot/Gemini-CLI-Tools sind nicht in Docker-Images enthalten.
**Ausführen:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
Öffnen Sie dann `http://localhost:3100/`.
@ -308,7 +309,7 @@ OpenPencil wurde von Grund auf in **Rust** neu geschrieben ([#129](https://githu
- **Native Barrierefreiheit** — AccessKit auf macOS, Windows und Linux sowie ein DOM-Spiegel im Web, anstatt sich auf den a11y-Baum eines Browsers zu stützen.
- **Ein typgeprüfter Workspace** — der MCP-Host, CLI, AI-Anbieter, Codegenerierung, Figma-Import und Git-Integration leben alle in einem einzigen Rust-Workspace, mit `cargo-deny`-Supply-Chain-Kontrolle in der CI.
> **Status:** der TypeScript-Editor wurde mit `v0.7.5` eingestellt und existiert nur noch in der Git-Historie; dieses Repository ist der Rust-Workspace. Das `v0.8.1`-Rust-Release befindet sich in aktiver Entwicklung (siehe Roadmap unten).
> **Status:** der TypeScript-Editor wurde mit `v0.7.5` eingestellt und existiert nur noch in der Git-Historie; dieses Repository ist der Rust-Workspace. Das Rust-Produkt wird aktiv weiterentwickelt (siehe Roadmap unten).
## Projektstruktur

View file

@ -123,14 +123,15 @@ Las releases Rust etiquetadas publican una única imagen de web host. Las imáge
| Imagen | Incluye |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle y recursos de CanvasKit |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle y recursos de CanvasKit |
La UI web expone solo perfiles de agente integrados; las herramientas Claude/Codex/OpenCode/Copilot/Gemini CLI no se incluyen en las imágenes Docker.
**Ejecutar:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
Luego abre `http://localhost:3100/`.
@ -308,7 +309,7 @@ OpenPencil fue reescrito desde cero en **Rust** ([#129](https://github.com/ZSeve
- **Accesibilidad nativa** — AccessKit en macOS, Windows y Linux, más un espejo DOM en web, en lugar de depender del árbol de accesibilidad del navegador.
- **Un workspace con tipado estricto** — el host MCP, CLI, proveedores de AI, generación de código, importación de Figma y la integración con Git conviven en un único workspace Rust, con `cargo-deny` vigilando la cadena de suministro en CI.
> **Estado:** el editor TypeScript se retiró en `v0.7.5` y solo vive en el historial de git; este repositorio es el workspace Rust. La versión `v0.8.1` de Rust está en desarrollo activo (consulta la Hoja de Ruta más abajo).
> **Estado:** el editor TypeScript se retiró en `v0.7.5` y solo vive en el historial de git; este repositorio es el workspace Rust. El producto en Rust está en desarrollo activo (consulta la Hoja de Ruta más abajo).
## Estructura del Proyecto

View file

@ -123,14 +123,15 @@ Les releases Rust taguées publient une seule image web host. Les anciennes imag
| Image | Contenu |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle et ressources CanvasKit |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle et ressources CanvasKit |
L'interface web expose uniquement les profils d'agents intégrés ; les outils Claude/Codex/OpenCode/Copilot/Gemini CLI ne sont pas inclus dans les images Docker.
**Exécuter :**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
Ouvrez ensuite `http://localhost:3100/`.
@ -308,7 +309,7 @@ OpenPencil a été réécrit intégralement en **Rust** ([#129](https://github.c
- **Accessibilité native** — AccessKit sur macOS, Windows et Linux, plus un miroir DOM sur le web, plutôt que de s'appuyer sur l'arbre a11y d'un navigateur.
- **Un workspace avec vérification de types** — l'hôte MCP, le CLI, les fournisseurs AI, la génération de code, l'import Figma et l'intégration Git résident tous dans un seul workspace Rust, avec filtrage de la chaîne d'approvisionnement par `cargo-deny` en CI.
> **Statut :** l'éditeur TypeScript a été retiré en `v0.7.5` et ne subsiste que dans l'historique Git ; ce dépôt est le workspace Rust. La version Rust `v0.8.1` est en développement actif (voir la Feuille de route ci-dessous).
> **Statut :** l'éditeur TypeScript a été retiré en `v0.7.5` et ne subsiste que dans l'historique Git ; ce dépôt est le workspace Rust. Le produit Rust est en développement actif (voir la Feuille de route ci-dessous).
## Structure du projet

View file

@ -123,14 +123,15 @@ cargo run -p op-host-desktop
| इमेज | शामिल |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle और CanvasKit assets |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle और CanvasKit assets |
Web UI केवल built-in agent profiles दिखाता है; Claude/Codex/OpenCode/Copilot/Gemini CLI tools Docker images में शामिल नहीं हैं।
**चलाएँ:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
फिर `http://localhost:3100/` खोलें।
@ -308,7 +309,7 @@ OpenPencil को पूरी तरह **Rust** में नए सिरे
- **नेटिव एक्सेसिबिलिटी** — macOS, Windows और Linux पर AccessKit, साथ ही वेब पर DOM मिरर — ब्राउज़र के a11y ट्री पर निर्भर रहने के बजाय।
- **एक टाइप-चेक्ड वर्कस्पेस** — MCP होस्ट, CLI, AI प्रदाता, कोड जनरेशन, Figma इम्पोर्ट और Git इंटीग्रेशन सभी एक ही Rust वर्कस्पेस में रहते हैं, CI में `cargo-deny` सप्लाई-चेन गेटिंग के साथ।
> **स्थिति:** TypeScript एडिटर को `v0.7.5` पर रिटायर कर दिया गया था और अब यह केवल git इतिहास में मौजूद है; यह रिपॉज़िटरी अब Rust वर्कस्पेस है। `v0.8.1` Rust रिलीज़ सक्रिय विकास में है (नीचे रोडमैप देखें)।
> **स्थिति:** TypeScript एडिटर को `v0.7.5` पर रिटायर कर दिया गया था और अब यह केवल git इतिहास में मौजूद है; यह रिपॉज़िटरी अब Rust वर्कस्पेस है। Rust प्रोडक्ट सक्रिय विकास में है (नीचे रोडमैप देखें)।
## प्रोजेक्ट संरचना

View file

@ -123,14 +123,15 @@ Rilis Rust bertag menerbitkan satu image web host. Image TypeScript lama yang me
| Image | Termasuk |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle, dan aset CanvasKit |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle, dan aset CanvasKit |
Web UI hanya menampilkan built-in agent profiles; alat Claude/Codex/OpenCode/Copilot/Gemini CLI tidak dibundel ke dalam image Docker.
**Jalankan:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
Lalu buka `http://localhost:3100/`.
@ -308,7 +309,7 @@ OpenPencil telah ditulis ulang dari awal dalam **Rust** ([#129](https://github.c
- **Aksesibilitas native** — AccessKit di macOS, Windows, dan Linux, ditambah mirror DOM di web, alih-alih mengandalkan pohon a11y browser.
- **Satu workspace bertipe** — host MCP, CLI, penyedia AI, pembuatan kode, impor Figma, dan integrasi Git semuanya berada dalam satu workspace Rust, dengan penjagaan rantai pasokan `cargo-deny` di CI.
> **Status:** editor TypeScript dipensiunkan pada `v0.7.5` dan kini hanya ada dalam riwayat git; repositori ini adalah workspace Rust. Rilis Rust `v0.8.1` sedang dalam pengembangan aktif (lihat Peta Jalan di bawah).
> **Status:** editor TypeScript dipensiunkan pada `v0.7.5` dan kini hanya ada dalam riwayat git; repositori ini adalah workspace Rust. Produk Rust sedang dalam pengembangan aktif (lihat Peta Jalan di bawah).
## Struktur Proyek

View file

@ -123,14 +123,15 @@ cargo run -p op-host-desktop
| イメージ | 含まれるもの |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host、wasm bundle、CanvasKit assets |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host、wasm bundle、CanvasKit assets |
Web UI は built-in agent profiles のみを公開します。Claude/Codex/OpenCode/Copilot/Gemini CLI ツールは Docker イメージに同梱されません。
**実行:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
その後 `http://localhost:3100/` を開いてください。
@ -308,7 +309,7 @@ OpenPencil は **Rust** で一から書き直されました ([#129](https://git
- **ネイティブアクセシビリティ** — macOS・Windows・Linux では AccessKit を使用し、Web ではブラウザの a11y ツリーに依存する代わりに DOM ミラーを提供。
- **型チェック済みの単一ワークスペース** — MCP ホスト、CLI、AI プロバイダー、コード生成、Figma インポート、Git 統合がすべて単一の Rust ワークスペースに収まり、CI では `cargo-deny` によるサプライチェーンのゲーティングを実施。
> **ステータス:** TypeScript エディターは `v0.7.5` で廃止され、現在は Git 履歴にのみ残っています。このリポジトリは Rust ワークスペースです。`v0.8.1` の Rust リリースは現在活発に開発中です(下記のロードマップを参照)。
> **ステータス:** TypeScript エディターは `v0.7.5` で廃止され、現在は Git 履歴にのみ残っています。このリポジトリは Rust ワークスペースです。Rust 製品は現在活発に開発中です(下記のロードマップを参照)。
## プロジェクト構成

View file

@ -123,14 +123,15 @@ cargo run -p op-host-desktop
| 이미지 | 포함 내용 |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle, CanvasKit assets |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle, CanvasKit assets |
웹 UI는 내장 agent profiles만 노출합니다. Claude/Codex/OpenCode/Copilot/Gemini CLI 도구는 Docker 이미지에 포함되지 않습니다.
**실행:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
그런 다음 `http://localhost:3100/`을 여세요.
@ -308,7 +309,7 @@ OpenPencil은 처음부터 **Rust**로 다시 작성되었습니다 ([#129](http
- **네이티브 접근성** — 브라우저의 접근성 트리에 의존하는 대신 macOS, Windows, Linux에서는 AccessKit을, 웹에서는 DOM 미러를 사용합니다.
- **타입 검사된 단일 워크스페이스** — MCP 호스트, CLI, AI 제공자, 코드 생성, Figma 가져오기, Git 통합이 모두 단일 Rust 워크스페이스 안에 있으며, CI에서 `cargo-deny`로 공급망을 검증합니다.
> **상태:** TypeScript 에디터는 `v0.7.5`에서 은퇴하여 이제 git 히스토리에만 남아 있으며, 이 저장소는 Rust 워크스페이스입니다. `v0.8.1` Rust 릴리스는 활발히 개발 중입니다 (아래 로드맵 참고).
> **상태:** TypeScript 에디터는 `v0.7.5`에서 은퇴하여 이제 git 히스토리에만 남아 있으며, 이 저장소는 Rust 워크스페이스입니다. Rust 제품은 활발히 개발 중입니다 (아래 로드맵 참고).
## 프로젝트 구조

View file

@ -241,14 +241,15 @@ Tagged Rust releases publish a single web-host image. The retired TypeScript ima
| Image | Includes |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle, and CanvasKit assets |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle, and CanvasKit assets |
The web UI exposes built-in agent profiles only; Claude/Codex/OpenCode/Copilot/Gemini CLI tooling is not bundled into Docker images.
**Run:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
Then open `http://localhost:3100/`.
@ -446,7 +447,7 @@ OpenPencil was rewritten from the ground up in **Rust** ([#129](https://github.c
- **Native accessibility** — AccessKit on macOS, Windows, and Linux, plus a DOM mirror on web, instead of leaning on a browser's a11y tree.
- **One type-checked workspace** — the MCP host, CLI, AI providers, code generation, Figma import, and Git integration all live in a single Rust workspace, with `cargo-deny` supply-chain gating in CI.
> **Status:** the TypeScript editor was retired at `v0.7.5` and lives only in git history; this repository is the Rust workspace. The Rust `v0.8` release line is under active development (see the Roadmap below).
> **Status:** the TypeScript editor was retired at `v0.7.5` and lives only in git history; this repository is the Rust workspace. The Rust product is under active development (see the Roadmap below).
## Project Structure

View file

@ -123,14 +123,15 @@ Releases Rust com tag publicam uma única imagem de web host. As imagens TypeScr
| Imagem | Inclui |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle e assets do CanvasKit |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle e assets do CanvasKit |
A UI web expõe apenas perfis de agente integrados; as ferramentas Claude/Codex/OpenCode/Copilot/Gemini CLI não são incluídas nas imagens Docker.
**Executar:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
Depois abra `http://localhost:3100/`.
@ -308,7 +309,7 @@ O OpenPencil foi reescrito do zero em **Rust** ([#129](https://github.com/ZSeven
- **Acessibilidade nativa** — AccessKit no macOS, Windows e Linux, mais um espelho DOM na web, em vez de depender da árvore de acessibilidade de um navegador.
- **Um workspace com verificação de tipos** — o host MCP, CLI, provedores de AI, geração de código, importação do Figma e integração com Git vivem em um único workspace Rust, com o `cargo-deny` fazendo controle da cadeia de suprimentos na CI.
> **Status:** o editor TypeScript foi descontinuado na `v0.7.5` e existe apenas no histórico do Git; este repositório é o workspace Rust. O lançamento Rust `v0.8.1` está em desenvolvimento ativo (consulte o Roadmap abaixo).
> **Status:** o editor TypeScript foi descontinuado na `v0.7.5` e existe apenas no histórico do Git; este repositório é o workspace Rust. O produto em Rust está em desenvolvimento ativo (consulte o Roadmap abaixo).
## Estrutura do Projeto

View file

@ -123,14 +123,15 @@ cargo run -p op-host-desktop
| Образ | Содержит |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle и ресурсы CanvasKit |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle и ресурсы CanvasKit |
Веб-интерфейс показывает только встроенные профили агентов; инструменты Claude/Codex/OpenCode/Copilot/Gemini CLI не входят в Docker-образы.
**Запуск:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
Затем откройте `http://localhost:3100/`.
@ -308,7 +309,7 @@ OpenPencil переписан с нуля на **Rust** ([#129](https://github.c
- **Нативная доступность** — AccessKit на macOS, Windows и Linux, плюс DOM-зеркало на вебе, вместо опоры на дерево доступности браузера.
- **Одно типизированное пространство** — хост MCP, CLI, AI-провайдеры, генерация кода, импорт Figma и интеграция с Git — всё в одном Rust-пространстве с контролем цепочки поставок через `cargo-deny` в CI.
> **Статус:** редактор на TypeScript был выведен из эксплуатации в `v0.7.5` и сохранился только в истории git; этот репозиторий — это Rust-пространство. Релиз `v0.8.1` на Rust находится в активной разработке (см. [Дорожная карта](#дорожная-карта) ниже).
> **Статус:** редактор на TypeScript был выведен из эксплуатации в `v0.7.5` и сохранился только в истории git; этот репозиторий — это Rust-пространство. Продукт на Rust находится в активной разработке (см. [Дорожная карта](#дорожная-карта) ниже).
## Структура проекта

View file

@ -123,14 +123,15 @@ Rust release ที่มี tag จะเผยแพร่ image แบบ web
| Image | รวม |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle และ CanvasKit assets |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle และ CanvasKit assets |
Web UI แสดงเฉพาะ built-in agent profiles เท่านั้น เครื่องมือ Claude/Codex/OpenCode/Copilot/Gemini CLI จะไม่ถูกบันเดิลใน Docker images
**รัน:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
จากนั้นเปิด `http://localhost:3100/`
@ -308,7 +309,7 @@ OpenPencil ถูกเขียนใหม่ตั้งแต่ต้นด
- **Accessibility แบบ native** — AccessKit บน macOS, Windows และ Linux พร้อม DOM mirror บนเว็บ แทนที่จะพึ่งพา a11y tree ของ browser
- **Workspace ที่ตรวจสอบ type เดียว** — MCP host, CLI, AI providers, code generation, Figma import และ Git integration ทั้งหมดอยู่ใน Rust workspace เดียว พร้อม `cargo-deny` ตรวจสอบ supply-chain ใน CI
> **สถานะ:** editor แบบ TypeScript ถูกเลิกใช้ที่ `v0.7.5` และเหลืออยู่เพียงใน git history เท่านั้น รีโปนี้คือ Rust workspace รุ่น Rust `v0.8.1` อยู่ระหว่างการพัฒนาอย่างต่อเนื่อง (ดู Roadmap ด้านล่าง)
> **สถานะ:** editor แบบ TypeScript ถูกเลิกใช้ที่ `v0.7.5` และเหลืออยู่เพียงใน git history เท่านั้น รีโปนี้คือ Rust workspace ผลิตภัณฑ์ Rust อยู่ระหว่างการพัฒนาอย่างต่อเนื่อง (ดู Roadmap ด้านล่าง)
## โครงสร้างโปรเจกต์

View file

@ -123,14 +123,15 @@ Etiketli Rust sürümleri tek bir web host görüntüsü yayımlar. AI CLI'ları
| Görüntü | İçerik |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle ve CanvasKit varlıkları |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle ve CanvasKit varlıkları |
Web UI yalnızca yerleşik agent profillerini gösterir; Claude/Codex/OpenCode/Copilot/Gemini CLI araçları Docker görüntülerine dahil değildir.
**Çalıştır:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
Ardından `http://localhost:3100/` adresini açın.
@ -308,7 +309,7 @@ OpenPencil, sıfırdan **Rust** ile yeniden yazıldı ([#129](https://github.com
- **Yerel erişilebilirlik** — tarayıcının a11y ağacına güvenmek yerine macOS, Windows ve Linux'ta AccessKit; web'de ise bir DOM aynası.
- **Tek tip denetimli çalışma alanı** — MCP sunucusu, CLI, AI sağlayıcıları, kod üretimi, Figma içe aktarma ve Git entegrasyonu; CI'da `cargo-deny` tedarik zinciri denetimi ile tek bir Rust çalışma alanında bulunur.
> **Durum:** TypeScript editörü `v0.7.5` sürümünde kullanımdan kaldırıldı ve yalnızca git geçmişinde bulunuyor; bu depo artık Rust çalışma alanıdır. `v0.8.1` Rust sürümü etkin geliştirme aşamasındadır (aşağıdaki Yol Haritası'na bakın).
> **Durum:** TypeScript editörü `v0.7.5` sürümünde kullanımdan kaldırıldı ve yalnızca git geçmişinde bulunuyor; bu depo artık Rust çalışma alanıdır. Rust ürünü etkin geliştirme aşamasındadır (aşağıdaki Yol Haritası'na bakın).
## Proje Yapısı

View file

@ -123,14 +123,15 @@ Các bản phát hành Rust có tag chỉ phát hành một image web host. Các
| Image | Bao gồm |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host, wasm bundle và tài nguyên CanvasKit |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle và tài nguyên CanvasKit |
Web UI chỉ hiển thị các built-in agent profiles; công cụ Claude/Codex/OpenCode/Copilot/Gemini CLI không được đóng gói trong Docker images.
**Chạy:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
Sau đó mở `http://localhost:3100/`.
@ -308,7 +309,7 @@ OpenPencil đã được viết lại từ đầu bằng **Rust** ([#129](https:
- **Trợ năng gốc** — AccessKit trên macOS, Windows và Linux, cộng với DOM mirror trên web, thay vì dựa vào cây a11y của browser.
- **Một workspace có kiểm tra kiểu** — MCP host, CLI, nhà cung cấp AI, tạo mã, nhập Figma và tích hợp Git đều nằm trong một Rust workspace duy nhất, với `cargo-deny` kiểm soát chuỗi cung ứng trong CI.
> **Trạng thái:** editor TypeScript đã bị khai tử tại `v0.7.5` và chỉ còn tồn tại trong lịch sử git; repo này chính là Rust workspace. Bản phát hành Rust `v0.8.1` đang được phát triển tích cực (xem Lộ trình bên dưới).
> **Trạng thái:** editor TypeScript đã bị khai tử tại `v0.7.5` và chỉ còn tồn tại trong lịch sử git; repo này chính là Rust workspace. Sản phẩm Rust đang được phát triển tích cực (xem Lộ trình bên dưới).
## Cấu trúc dự án

View file

@ -123,14 +123,15 @@ cargo run -p op-host-desktop
| 映像檔 | 包含 |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host、wasm bundle 和 CanvasKit 資源 |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host、wasm bundle 和 CanvasKit 資源 |
Web UI 僅公開內建 agent profilesDocker 映像檔不再內建 Claude/Codex/OpenCode/Copilot/Gemini CLI 工具。
**執行:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
然後開啟 `http://localhost:3100/`
@ -308,7 +309,7 @@ OpenPencil 已以 **Rust** 從頭重寫完成([#129](https://github.com/ZSeven
- **原生無障礙支援** — 在 macOS、Windows 和 Linux 使用 AccessKit在 Web 上使用 DOM 鏡像,而非依賴瀏覽器的 a11y 樹狀結構。
- **單一型別檢查 workspace** — MCP 宿主、CLI、AI 供應商、程式碼生成、Figma 匯入和 Git 整合全部位於單一 Rust workspace並由 CI 中的 `cargo-deny` 進行供應鏈管控。
> **狀態:** TypeScript 版編輯器已在 `v0.7.5` 退役,僅存於 Git 歷史紀錄中;本存放庫即為 Rust workspace。`v0.8.1` 的 Rust 版本正在積極開發中(請見下方路線圖)。
> **狀態:** TypeScript 版編輯器已在 `v0.7.5` 退役,僅存於 Git 歷史紀錄中;本存放庫即為 Rust workspace。Rust 產品正在積極開發中(請見下方路線圖)。
## 專案結構

View file

@ -123,14 +123,15 @@ cargo run -p op-host-desktop
| 镜像 | 包含 |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:v0.8.1` | Rust web host、wasm bundle 和 CanvasKit 资源 |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host、wasm bundle 和 CanvasKit 资源 |
Web UI 只暴露内置 agent profilesDocker 镜像不再内置 Claude/Codex/OpenCode/Copilot/Gemini CLI 工具。
**运行:**
```bash
docker run -d -p 3100:3100 ghcr.io/zseven-w/openpencil-web:v0.8.1
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
然后打开 `http://localhost:3100/`
@ -308,7 +309,7 @@ OpenPencil 已从头用 **Rust** 完成重写([#129](https://github.com/ZSeven
- **原生无障碍** — macOS、Windows 和 Linux 上通过 AccessKit 实现Web 端通过 DOM 镜像实现,而非依赖浏览器自身的无障碍树。
- **单一类型检查工作区** — MCP 宿主、CLI、AI 提供商、代码生成、Figma 导入和 Git 集成全部位于同一个 Rust workspace并在 CI 中通过 `cargo-deny` 进行供应链管控。
> **状态:** TypeScript 版编辑器已在 `v0.7.5` 退役,仅存在于 Git 历史中;本仓库即为 Rust workspace。`v0.8.1` 版本的 Rust 发布正在积极开发中(参见下方路线图)。
> **状态:** TypeScript 版编辑器已在 `v0.7.5` 退役,仅存在于 Git 历史中;本仓库即为 Rust workspace。Rust 产品正在积极开发中(参见下方路线图)。
## 项目结构

View file

@ -758,14 +758,13 @@ mod tests {
#[test]
fn replace_paths_with_polyline_inherits_first_source_style() {
let src = r##"{
"version": "__OPENPENCIL_VERSION__",
"version": "1.0.0",
"children": [
{"type":"rectangle","id":"n10","x":0,"y":0,"width":20,"height":20,
"fill":[{"type":"solid","color":"#ff0000"}]},
{"type":"rectangle","id":"n11","x":10,"y":0,"width":20,"height":20}
]
}"##;
let src = src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"));
let doc = jian_ops_schema::load_str(&src)
.expect("fixture parses")
.value;

View file

@ -0,0 +1,103 @@
repo=$(new_repo ordinary_dynamic_rust_fixture 0.8.1)
printf '%s\n' \
'let src = src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"));' \
>> "$repo/crates/op-editor-core/src/host_support.rs"
run_guard "$repo"
assert_status 1 'ordinary dynamic Rust fixture'
assert_contains 'crates/op-editor-core/src/host_support.rs:1: error: ordinary test fixtures must use stable 1.0.0 instead of CARGO_PKG_VERSION' \
'ordinary dynamic Rust fixture'
assert_no_success_output 'ordinary dynamic Rust fixture'
pass 'ordinary Rust fixtures cannot masquerade as product-version producers'
repo=$(new_repo dynamic_rust_fixture_balanced_count 0.8.1)
cat > "$repo/crates/op-editor-core/src/host_support.rs" <<'RUST'
pub fn sample() {
let src = src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"));
}
pub fn starter() {
}
#[cfg(test)]
mod tests {
let src = src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"));
}
RUST
run_guard "$repo"
assert_status 1 'dynamic Rust fixture with balanced count'
assert_contains 'crates/op-editor-core/src/host_support.rs:1: error: ordinary test fixtures must use stable 1.0.0 instead of CARGO_PKG_VERSION' \
'dynamic Rust fixture with balanced count'
assert_no_success_output 'dynamic Rust fixture with balanced count'
pass 'a dynamic test fixture cannot replace one of the two production producers'
repo=$(new_repo cargo_manifest_literal_workspace_version 0.8.1)
sed -i.bak 's/version[.]workspace = true/version = "0.8.1"/' \
"$repo/crates/example/Cargo.toml"
rm "$repo/crates/example/Cargo.toml.bak"
run_guard "$repo"
assert_status 1 'Cargo manifest literal workspace version'
assert_contains 'crates/example/Cargo.toml:3: error: local op-* package must declare exactly one active version.workspace = true in [package]' \
'Cargo manifest literal workspace version'
assert_no_success_output 'Cargo manifest literal workspace version'
pass 'metadata equality cannot hide a literal local package version'
repo=$(new_repo cargo_manifest_missing_workspace_version 0.8.1)
sed -i.bak '/version[.]workspace = true/d' "$repo/crates/example/Cargo.toml"
rm "$repo/crates/example/Cargo.toml.bak"
run_guard "$repo"
assert_status 1 'Cargo manifest missing workspace version'
assert_contains 'crates/example/Cargo.toml:1: error: local op-* package must declare exactly one active version.workspace = true in [package]' \
'Cargo manifest missing workspace version'
assert_no_success_output 'Cargo manifest missing workspace version'
pass 'local op-* manifests must inherit the workspace version'
repo=$(new_repo cargo_manifest_commented_workspace_version 0.8.1)
sed -i.bak 's/^version[.]workspace = true/# version.workspace = true/' \
"$repo/crates/example/Cargo.toml"
rm "$repo/crates/example/Cargo.toml.bak"
run_guard "$repo"
assert_status 1 'Cargo manifest commented workspace version'
assert_contains 'crates/example/Cargo.toml:1: error: local op-* package must declare exactly one active version.workspace = true in [package]' \
'Cargo manifest commented workspace version'
assert_no_success_output 'Cargo manifest commented workspace version'
pass 'commented inheritance declarations do not satisfy the manifest guard'
repo=$(new_repo readme_numeric_docker_tag 0.8.1)
printf '%s\n' 'docker pull ghcr.io/zseven-w/openpencil-web:v0.8.2' >> "$repo/README.md"
run_guard "$repo"
assert_status 1 'README numeric Docker tag'
assert_contains 'README.md:' 'README numeric Docker tag'
assert_contains 'error: top-level READMEs must not contain active product SemVer releases; use vX.Y.Z or the workspace-version reader' \
'README numeric Docker tag'
assert_no_success_output 'README numeric Docker tag'
pass 'top-level README Docker tags must stay version-neutral'
repo=$(new_repo readme_active_status_version 0.8.1)
printf '%s\n' 'The Rust v0.8.2 release is under active development.' >> "$repo/README.md"
run_guard "$repo"
assert_status 1 'README active status version'
assert_contains 'README.md:' 'README active status version'
assert_contains 'error: top-level READMEs must not contain active product SemVer releases; use vX.Y.Z or the workspace-version reader' \
'README active status version'
assert_no_success_output 'README active status version'
pass 'top-level README status text cannot pin an active product version'
repo=$(new_repo readme_version_like_substring 0.8.1)
printf '%s\n' 'The identifier build0.8.2candidate is not a release.' >> "$repo/README.md"
run_guard "$repo"
assert_status 0 'README version-like substring'
pass 'README version-like substrings inside larger identifiers are allowed'
repo=$(new_repo readme_historical_typescript_version 0.8.1)
printf '%s\n' 'The retired TypeScript line ended at v0.7.5.' >> "$repo/README.md"
run_guard "$repo"
assert_status 0 'README historical TypeScript version'
pass 'the explicit retired TypeScript v0.7.5 history remains allowed'
repo=$(new_repo version_sync_ci_missing_readmes 0.8.1)
sed -i.bak '/README[*][.]md/d' "$repo/.github/workflows/version-sync.yml"
rm "$repo/.github/workflows/version-sync.yml.bak"
run_guard "$repo"
assert_status 1 'version-sync CI missing README paths'
assert_contains '.github/workflows/version-sync.yml:1: error: version-sync CI must run for top-level README changes in pull requests and pushes' \
'version-sync CI missing README paths'
assert_no_success_output 'version-sync CI missing README paths'
pass 'version-sync CI covers every top-level README input'

View file

@ -149,6 +149,60 @@ reject_example_semver_tokens() {
fi
}
validate_top_level_readmes() {
semver_pattern='(?<![0-9A-Za-z.])v?(?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:[.][0-9A-Za-z-]+)*)?(?:[+][0-9A-Za-z-]+(?:[.][0-9A-Za-z-]+)*)?(?![0-9A-Za-z]|[.][0-9A-Za-z])'
readme_files=(README*.md)
for file in "${readme_files[@]}"; do
rg_status=0
matches=$(rg --pcre2 --only-matching --line-number --with-filename \
--color never -- "$semver_pattern" "$file") || rg_status=$?
if [[ "$rg_status" -gt 1 ]]; then
printf '%s:1: error: failed to scan README version policy (rg status %s)\n' \
"$file" "$rg_status" >&2
errors=1
continue
fi
if [[ -n "$matches" ]]; then
while IFS=: read -r match_file match_line token; do
if [[ "$token" == v0.7.5 ]]; then
continue
fi
printf '%s:%s: error: top-level READMEs must not contain active product SemVer releases; use vX.Y.Z or the workspace-version reader\n' \
"$match_file" "$match_line" >&2
errors=1
done <<< "$matches"
fi
done
}
validate_version_sync_ci_readme_paths() {
ci_workflow=.github/workflows/version-sync.yml
if [[ ! -f "$ci_workflow" ]]; then
report_missing "$ci_workflow" \
'version-sync CI must run for top-level README changes in pull requests and pushes'
return
fi
read -r pull_request_readmes push_readmes < <(
awk '
/^ pull_request:[[:space:]]*$/ { event = "pull_request"; next }
/^ push:[[:space:]]*$/ { event = "push"; next }
/^[^[:space:]]/ { event = "" }
/^[[:space:]]*-[[:space:]]+"README[*][.]md"[[:space:]]*$/ {
if (event == "pull_request") pull_request_count++
if (event == "push") push_count++
}
END { print pull_request_count + 0, push_count + 0 }
' "$ci_workflow"
)
if [[ "$pull_request_readmes" != 1 || "$push_readmes" != 1 ]]; then
report_missing "$ci_workflow" \
'version-sync CI must run for top-level README changes in pull requests and pushes'
fi
}
reject_matches() {
mode=$1
file=$2
@ -178,6 +232,68 @@ reject_matches() {
fi
}
validate_manifest_workspace_version() {
manifest=$1
relative_manifest=$2
if [[ ! -f "$manifest" ]]; then
report_missing "$relative_manifest" \
'local op-* package manifest returned by cargo metadata does not exist'
return
fi
manifest_result=$(awk '
BEGIN {
in_package = 0
inheritance_count = 0
package_header_line = 1
declaration_line = 0
}
{
line = $0
sub(/\r$/, "", line)
if (line ~ /^[[:space:]]*\[[^]]+\][[:space:]]*(#.*)?$/) {
header = line
sub(/[[:space:]]*#.*/, "", header)
gsub(/[[:space:]]/, "", header)
in_package = (header == "[package]")
if (in_package && package_header_line == 1) {
package_header_line = NR
}
next
}
if (!in_package || line ~ /^[[:space:]]*#/) {
next
}
code = line
sub(/[[:space:]]*#.*/, "", code)
if (code ~ /^[[:space:]]*version[.]workspace[[:space:]]*=[[:space:]]*true[[:space:]]*$/) {
inheritance_count++
if (declaration_line == 0) declaration_line = NR
next
}
if (declaration_line == 0 &&
code ~ /^[[:space:]]*version([.]workspace)?[[:space:]]*=/) {
declaration_line = NR
}
}
END {
diagnostic_line = declaration_line == 0 ? package_header_line : declaration_line
printf "%d\t%d\n", inheritance_count, diagnostic_line
}
' "$manifest")
IFS=$'\t' read -r inheritance_count diagnostic_line <<< "$manifest_result"
if [[ "$inheritance_count" != 1 ]]; then
printf '%s:%s: error: local op-* package must declare exactly one active version.workspace = true in [package] (found %s)\n' \
"$relative_manifest" "$diagnostic_line" "$inheritance_count" >&2
errors=1
fi
}
validate_workspace_package_versions() {
if ! metadata=$(cargo metadata --no-deps --format-version 1 --locked); then
report_missing Cargo.lock \
@ -208,8 +324,9 @@ validate_workspace_package_versions() {
fi
while IFS=$'\t' read -r manifest package package_version; do
relative_manifest=${manifest#"$repo_root"/}
validate_manifest_workspace_version "$manifest" "$relative_manifest"
if [[ "$package_version" != "$current_version" ]]; then
relative_manifest=${manifest#"$repo_root"/}
printf '%s:1: error: workspace package %s has version %s; expected %s\n' \
"$relative_manifest" "$package" "$package_version" "$current_version" >&2
errors=1
@ -259,12 +376,25 @@ validate_rust_product_version_producers() {
'empty documents must derive their version from CARGO_PKG_VERSION'
host_support=crates/op-editor-core/src/host_support.rs
host_version_count=$(rg --fixed-strings --count-matches -- \
'src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"))' \
"$host_support" || true)
if [[ "$host_version_count" != 3 ]]; then
read -r host_production_version_count host_test_version_count < <(
awk \
-v needle='src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"))' \
'
/^#[[:space:]]*\[cfg\(test\)\][[:space:]]*$/ { in_tests = 1 }
index($0, needle) {
if (in_tests) test_count++
else production_count++
}
END { print production_count + 0, test_count + 0 }
' "$host_support"
)
if [[ "$host_production_version_count" != 2 ]]; then
report_missing "$host_support" \
"expected 3 document templates to derive from CARGO_PKG_VERSION (found ${host_version_count:-0})"
"expected exactly 2 production document templates to derive from CARGO_PKG_VERSION (found ${host_production_version_count:-0})"
fi
if [[ "$host_test_version_count" != 0 ]]; then
report_missing "$host_support" \
'ordinary test fixtures must use stable 1.0.0 instead of CARGO_PKG_VERSION'
fi
cli_source=crates/op-cli/src/app_control_cli.rs
@ -284,6 +414,8 @@ validate_package_versions
validate_release_tag
validate_cli_bundle_version_template
validate_rust_product_version_producers
validate_top_level_readmes
validate_version_sync_ci_readme_paths
if [[ "$current_version" == "$fixture_version" ]]; then
printf 'version-sync: current product version %s equals stable fixture version %s; skipping literal fixture drift scan because stable fixtures and product-version literals are indistinguishable\n' \

View file

@ -224,9 +224,15 @@ JSON
version: env!("CARGO_PKG_VERSION").to_owned(),
RUST
cat > "$repo/crates/op-editor-core/src/host_support.rs" <<'RUST'
pub fn sample() {
let src = src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"));
}
pub fn starter() {
let src = src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"));
let src = src.replace("__OPENPENCIL_VERSION__", env!("CARGO_PKG_VERSION"));
}
#[cfg(test)]
mod tests {
}
RUST
cat > "$repo/crates/op-cli/src/app_control_cli.rs" <<'RUST'
const MINIMAL_DOCUMENT: &str = concat!(env!("CARGO_PKG_VERSION"));
@ -234,6 +240,36 @@ RUST
cat > "$repo/crates/op-host-desktop/Cargo.toml" <<'TOML'
op-host-native = { path = "../op-host-native", features = ["gl-host"] }
TOML
cat > "$repo/crates/example/Cargo.toml" <<'TOML'
[package]
name = "op-example"
version.workspace = true
edition.workspace = true
TOML
cat > "$repo/README.md" <<'MARKDOWN'
| Image | Includes |
| --- | --- |
| `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host |
```bash
VERSION="$(scripts/workspace-version.sh)"
docker run -d -p 3100:3100 "ghcr.io/zseven-w/openpencil-web:v${VERSION}"
```
The TypeScript editor was retired at `v0.7.5`.
MARKDOWN
cat > "$repo/.github/workflows/version-sync.yml" <<'YAML'
name: Version consistency
on:
pull_request:
paths:
- "README*.md"
push:
paths:
- "README*.md"
YAML
cat > "$repo/scripts/bundle-macos.sh" <<'SCRIPT'
#!/usr/bin/env bash
@ -699,6 +735,8 @@ assert_contains 'crates/op-host-desktop/Cargo.toml:1: error: local op-host-nativ
assert_no_success_output 'versioned local product dependency'
pass 'local product dependencies do not repeat the workspace version'
. "$script_dir/check-version-sync-policy.test-cases.sh"
repo=$(new_repo guard_is_read_only 0.8.1)
before_snapshot=$(repo_snapshot "$repo")
run_guard "$repo"