Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f784e5c
feat(layout): native floating ball with swipe gestures
Oct 17, 2026
5455df4
feat(layout): native floating ball with swipe gestures (conflict reso…
Oct 18, 2026
bb6dfcf
test(layout): cover the floating ball's interactions
Oct 17, 2026
0c06445
fix(layout): keep the floating ball clear of the composer and status bar
Oct 17, 2026
a8a1940
feat(floating-ball): batch v82 P0 — expand gesture vocabulary
Oct 17, 2026
1c8c250
feat(floating-ball): batch v82 P1+P2+P2b — configurable bindings, ges…
Oct 17, 2026
f82b86a
feat(floating-ball): batch v82 P3 — wire 10 new actions with guards a…
Oct 17, 2026
d522432
feat(floating-ball): settings labels i18n + 9 new bindable actions
Oct 17, 2026
dc9e1e4
chore(i18n): rebuild locale files on upstream base — floating-ball se…
Oct 18, 2026
fa04efc
chore(fork): point updater at fork releases + fork signing pubkey + a…
Oct 18, 2026
c63e8ea
ci: trigger workflow registration on fork
Oct 19, 2026
47b8348
ci: fall back to GITHUB_TOKEN when FORK_SYNC_TOKEN absent
Oct 19, 2026
8d1e9b2
ci: push merge with FORK_SYNC_TOKEN (GITHUB_TOKEN lacks workflows scope)
Oct 19, 2026
f8c85c9
ci: keep upstream workflow changes out of deploy branch push (GITHUB_…
Oct 19, 2026
bac24b0
ci: merge upstream locally without pushing back; package all 4 binari…
Oct 19, 2026
cd6ea09
ci: let pnpm/action-setup read packageManager version
Oct 19, 2026
844eb7c
merge: upstream v0.38.0 into deploy/fork-updater (floating-ball + for…
Oct 19, 2026
da6e190
feat(floating-ball): right-panel actions and double-tap rebind (batch…
Oct 19, 2026
7aca33f
fix(floating-ball): show tap/double-tap/long-press rows in bindings UI
Oct 20, 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
12 changes: 12 additions & 0 deletions .github/scripts/upstream-release-trigger.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
# 上游 codeg 发版触发器:personal token 调 repository_dispatch 唤醒 fork 的 fork-release workflow。
# cron 建议:每 6 小时一次(上游更新再频繁也足够及时)。
# 用法:CODEG_DISPATCH_TOKEN=ghp_xxx ./upstream-release-trigger.sh
set -euo pipefail
: "${CODEG_DISPATCH_TOKEN:?need a personal access token with repo scope}"
curl -sS -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $CODEG_DISPATCH_TOKEN" \
https://api.github.com/repos/unixcs/codeg/dispatches \
-d '{"event_type":"upstream-release","client_payload":{}}'
echo "dispatch sent"
192 changes: 192 additions & 0 deletions .github/workflows/fork-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
name: Fork release (auto-sync upstream)

# 当上游 spacering-net/codeg 发布新 release 时自动:
# 1. 在 CI 里把上游 tag 合并进 deploy/fork-updater(含 fork 更新源补丁+悬浮球)
# 2. 构建 linux-x64 服务端包(codeg-server + codeg-mcp + codeg-cli
# + codeg-computer-helper + web 静态资产),与官方 tarball 同构
# 3. 用 fork 自己的 minisign 密钥签名(--app-version 绑定版本)
# 4. 生成 latest.json 并连同 tarball/.sig/.sha256 发到 fork 的同名 release
# tx/dell 上的 codeg 检查的是 fork 的 releases/latest,走它自带的一键更新。
#
# 注意:合并结果**不回推** deploy 分支——GITHUB_TOKEN 无 workflows 权限,
# 合并若带入 .github/workflows 改动,push 必被拒。deploy 分支的源码由
# 人工维护(上游合并有冲突时本地解决后 push),CI 每次都从上游 tag 现合。
# 冲突时合并失败 → job 标红 + 开 issue 通知,需人工解决。

on:
repository_dispatch:
types: [upstream-release]
workflow_dispatch:

permissions:
contents: write
issues: write

concurrency:
group: fork-release
cancel-in-progress: false

env:
ARTIFACT: codeg-server-linux-x64

jobs:
sync-and-release:
runs-on: ubuntu-22.04
timeout-minutes: 90
steps:
- name: Check out deploy branch
uses: actions/checkout@v4
with:
ref: deploy/fork-updater
fetch-depth: 0
token: ${{ secrets.FORK_SYNC_TOKEN || secrets.GITHUB_TOKEN }}

- name: Resolve upstream latest release
id: upstream
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
info=$(gh api repos/spacering-net/codeg/releases/latest --jq '{tag: .tag_name, ver: (.tag_name | ltrimstr("v")), notes: .body}')
echo "tag=$(echo "$info" | jq -r .tag)" >> "$GITHUB_OUTPUT"
echo "ver=$(echo "$info" | jq -r .ver)" >> "$GITHUB_OUTPUT"
echo "$info" | jq -r .notes > /tmp/upstream-notes.md
echo "Upstream: $(echo "$info" | jq -r .tag)"

- name: Skip if fork already has this release
id: skip
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
if gh release view "${{ steps.upstream.outputs.tag }}" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "already=true" >> "$GITHUB_OUTPUT"
echo "Release ${{ steps.upstream.outputs.tag }} already exists on fork — nothing to do."
else
echo "already=false" >> "$GITHUB_OUTPUT"
fi

- name: Merge upstream tag (local only, not pushed back)
if: steps.skip.outputs.already == 'false'
id: merge
run: |
set -euo pipefail
git config user.name "fork-sync-bot"
git config user.email "bot@users.noreply.github.com"
git remote add upstream https://github.com/spacering-net/codeg.git
git fetch upstream "${{ steps.upstream.outputs.tag }}"
if git merge --no-edit FETCH_HEAD; then
echo "merged=true" >> "$GITHUB_OUTPUT"
git log --oneline -1
else
git merge --abort || true
echo "merged=false" >> "$GITHUB_OUTPUT"
fi

- name: Open issue on merge conflict
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh issue create --repo "$GITHUB_REPOSITORY" \
--title "上游 ${{ steps.upstream.outputs.tag }} 合并冲突,需人工介入" \
--body "spacering-net/codeg 发布了 ${{ steps.upstream.outputs.tag }},CI 合并进 deploy/fork-updater 时有冲突,本次未出包。请在本地:git fetch upstream && git merge ${{ steps.upstream.outputs.tag }},解决冲突(保留悬浮球与 fork 更新源补丁)后 push 到 deploy 分支,然后手动重跑 workflow。"

- name: Install pnpm deps
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
uses: pnpm/action-setup@v4

- name: Set up Node
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm

- name: Install dependencies
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
run: pnpm install --frozen-lockfile

- name: Build frontend
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
run: pnpm build

- name: Set up Rust
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
uses: dtolnay/rust-toolchain@stable

- name: Cache cargo
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
uses: swatinem/rust-cache@v2
with:
workspaces: src-tauri

- name: Build server + companions (mirror official release.yml)
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
run: |
set -euo pipefail
cd src-tauri
cargo build --release --bin codeg-server --no-default-features --features server-bin
cargo build --release --bin codeg-mcp --no-default-features --features mcp-bin
cargo build --release --bin codeg-computer-helper --no-default-features --features computer-helper
cargo build --release --bin codeg-cli --no-default-features --features cli-bin
cd ..
mkdir -p dist/${ARTIFACT}
cp src-tauri/target/release/codeg-server dist/${ARTIFACT}/
cp src-tauri/target/release/codeg-mcp dist/${ARTIFACT}/
cp src-tauri/target/release/codeg-computer-helper dist/${ARTIFACT}/
cp src-tauri/target/release/codeg-cli dist/${ARTIFACT}/
chmod +x dist/${ARTIFACT}/*
cp -r out dist/${ARTIFACT}/web
cd dist && tar czf ${ARTIFACT}.tar.gz ${ARTIFACT}

- name: Smoke test packaged artifact
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
run: |
set -euo pipefail
test -x "dist/${ARTIFACT}/codeg-server"
test -x "dist/${ARTIFACT}/codeg-mcp"
test -x "dist/${ARTIFACT}/codeg-computer-helper"
test -x "dist/${ARTIFACT}/codeg-cli"
test -f "dist/${ARTIFACT}/web/index.html"

- name: Sign bundle with fork key
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ""
run: |
set -euo pipefail
pnpm tauri signer sign --app-version "${{ steps.upstream.outputs.ver }}" "dist/${ARTIFACT}.tar.gz"
test -f "dist/${ARTIFACT}.tar.gz.sig"
( cd dist && sha256sum ${ARTIFACT}.tar.gz > ${ARTIFACT}.tar.gz.sha256 )

- name: Build latest.json
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
env:
VER: ${{ steps.upstream.outputs.ver }}
run: |
set -euo pipefail
SIG=$(base64 -w0 "dist/${ARTIFACT}.tar.gz.sig")
URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${{ steps.upstream.outputs.tag }}/${ARTIFACT}.tar.gz"
jq -n --arg v "$VER" --arg s "$SIG" --arg u "$URL" --rawfile n /tmp/upstream-notes.md \
'{version: $v, notes: $n, pub_date: (now | todateiso8601),
platforms: {"linux-x86_64": {signature: $s, url: $u}}}' > dist/latest.json
jq -r '.version, .platforms["linux-x86_64"].url' dist/latest.json

- name: Create fork release and upload
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
env:
GH_TOKEN: ${{ secrets.FORK_SYNC_TOKEN || secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
gh release create "${{ steps.upstream.outputs.tag }}" \
--repo "$GITHUB_REPOSITORY" \
--title "codeg ${{ steps.upstream.outputs.ver }} + floating-ball (fork)" \
--notes "基于上游 ${{ steps.upstream.outputs.tag }},含悬浮球功能与 fork 更新源补丁。仅打包 linux-x64。

$(cat /tmp/upstream-notes.md)" \
"dist/${ARTIFACT}.tar.gz" \
"dist/${ARTIFACT}.tar.gz.sig" \
"dist/${ARTIFACT}.tar.gz.sha256" \
dist/latest.json
2 changes: 1 addition & 1 deletion src-tauri/src/update/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::update::version::trim_v_prefix;
/// Tauri-format minisign public key — copied verbatim from
/// `tauri.conf.json` `plugins.updater.pubkey`. Base64 of the two-line
/// `minisign.pub` file (`untrusted comment:` + `RW…` key line).
const TAURI_PUBKEY_B64: &str = "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDQ4OEM3NkMyMTVENjdBODgKUldTSWV0WVZ3bmFNU0NnSzhpdFg2bXFmMHFidWd1eWpuZ2Y2WmU5QmVXdWVrU0ZpOCt2dnd6WW4K";
const TAURI_PUBKEY_B64: &str = "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDc1OEQ2MDVCMUU3Qjk4MjkKUldRcG1Ic2VXMkNOZFRWMTNRSHpRcGgvWjFBWmVNZVJZWi9MbGpZS1RpSEFBeGJyYTZ0cThUOHkK";

/// Decode an outer base64 wrapper into the inner minisign text file.
fn unwrap_base64(b64: &str) -> Result<String, String> {
Expand Down
4 changes: 2 additions & 2 deletions src-tauri/src/update/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ use crate::app_error::AppCommandError;
/// Update manifest URL — mirrors the `endpoints` entry in `tauri.conf.json`
/// so desktop and server modes consult the same source of truth.
pub const UPDATE_MANIFEST_URL: &str =
"https://github.com/spacering-net/codeg/releases/latest/download/latest.json";
"https://github.com/unixcs/codeg/releases/latest/download/latest.json";

/// Deterministic base for "latest" release assets (server tarballs + their
/// `.sig` detached signatures). Same channel as the manifest.
pub const RELEASE_DOWNLOAD_BASE: &str =
"https://github.com/spacering-net/codeg/releases/latest/download";
"https://github.com/unixcs/codeg/releases/latest/download";

/// Short-timeout client for the small manifest fetch. Proxy env vars are
/// sampled at build time, so `init_proxy_from_db` must run before the first
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDQ4OEM3NkMyMTVENjdBODgKUldTSWV0WVZ3bmFNU0NnSzhpdFg2bXFmMHFidWd1eWpuZ2Y2WmU5QmVXdWVrU0ZpOCt2dnd6WW4K",
"endpoints": [
"https://github.com/spacering-net/codeg/releases/latest/download/latest.json"
"https://github.com/unixcs/codeg/releases/latest/download/latest.json"
],
"requireSignedVersion": true,
"windows": {
Expand Down
Loading