cync-cli 0.5.0__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cync_cli-0.6.0/.github/workflows/release.yml +139 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/PKG-INFO +16 -3
- {cync_cli-0.5.0 → cync_cli-0.6.0}/README.md +15 -2
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/+layout.svelte +2 -1
- cync_cli-0.6.0/client/src/routes/docs/+page.svelte +92 -0
- cync_cli-0.6.0/packaging/HOMEBREW.md +76 -0
- cync_cli-0.6.0/packaging/cync.py +9 -0
- cync_cli-0.6.0/packaging/gen_formula.sh +63 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/pyproject.toml +1 -1
- {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/__init__.py +1 -1
- {cync_cli-0.5.0 → cync_cli-0.6.0}/.dockerignore +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/.env.example +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/.github/workflows/publish.yml +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/.gitignore +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/Dockerfile +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/LICENSE +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/PRIVACY.md +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/.env.example +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/.gitignore +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/.npmrc +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/.vscode/extensions.json +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/README.md +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/package.json +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/pnpm-lock.yaml +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/pnpm-workspace.yaml +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/app.d.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/app.html +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/hooks.server.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/lib/assets/favicon.svg +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/lib/index.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/lib/parse.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/lib/server/cync.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/lib/types.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/+layout.server.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/+layout.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/+page.server.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/+page.svelte +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/auth/callback/+server.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/auth/signout/+server.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/login/+page.svelte +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/p/[slug]/+page.server.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/p/[slug]/+page.svelte +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/p/[slug]/c/[id]/+page.server.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/p/[slug]/c/[id]/+page.svelte +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/privacy/+page.svelte +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/static/robots.txt +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/tsconfig.json +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/client/vite.config.ts +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/scripts/migrate_legacy.py +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/auth.py +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/client.py +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/common.py +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/config.py +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/mcp_server.py +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/server.py +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/storage.py +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/supabase_store.py +0 -0
- {cync_cli-0.5.0 → cync_cli-0.6.0}/supabase/schema.sql +0 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# Build standalone `cync` binaries with PyInstaller and publish them — plus an
|
|
4
|
+
# updated Homebrew formula — to the PUBLIC tap repo. This source repo stays
|
|
5
|
+
# private; only the compiled binaries + formula become public, so
|
|
6
|
+
# `brew install 03hgryan/tap/cync` works for anyone.
|
|
7
|
+
#
|
|
8
|
+
# ── One-time setup ────────────────────────────────────────────────────────────
|
|
9
|
+
# 1. Create a PUBLIC repo `03hgryan/homebrew-tap` (tick "Add a README" so it
|
|
10
|
+
# has an initial commit / default branch).
|
|
11
|
+
# 2. Create a fine-grained PAT scoped to ONLY that repo, permission
|
|
12
|
+
# "Contents: Read and write". Add it to THIS repo as an Actions secret
|
|
13
|
+
# named `HOMEBREW_TAP_TOKEN` (Settings → Secrets and variables → Actions).
|
|
14
|
+
# After that, every `git tag vX.Y.Z && git push --tags` ships binaries + formula.
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
push:
|
|
18
|
+
tags: ["v*"]
|
|
19
|
+
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
build:
|
|
25
|
+
strategy:
|
|
26
|
+
fail-fast: false
|
|
27
|
+
matrix:
|
|
28
|
+
include:
|
|
29
|
+
- os: macos-14 # Apple Silicon
|
|
30
|
+
target: macos-arm64
|
|
31
|
+
- os: macos-13 # Intel
|
|
32
|
+
target: macos-x86_64
|
|
33
|
+
- os: ubuntu-latest
|
|
34
|
+
target: linux-x86_64
|
|
35
|
+
runs-on: ${{ matrix.os }}
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- uses: actions/setup-python@v5
|
|
39
|
+
with:
|
|
40
|
+
python-version: "3.12"
|
|
41
|
+
- name: Install build deps
|
|
42
|
+
run: |
|
|
43
|
+
python -m pip install --upgrade pip
|
|
44
|
+
pip install ".[mcp]" pyinstaller
|
|
45
|
+
- name: Build binary
|
|
46
|
+
run: |
|
|
47
|
+
pyinstaller --onefile --name cync \
|
|
48
|
+
--collect-all mcp \
|
|
49
|
+
--collect-all pydantic \
|
|
50
|
+
--collect-submodules anyio \
|
|
51
|
+
--hidden-import anyio._backends._asyncio \
|
|
52
|
+
--copy-metadata mcp \
|
|
53
|
+
--copy-metadata pydantic \
|
|
54
|
+
packaging/cync.py
|
|
55
|
+
- name: Smoke test
|
|
56
|
+
run: |
|
|
57
|
+
./dist/cync --version
|
|
58
|
+
./dist/cync --help >/dev/null
|
|
59
|
+
# MCP is bundled — prove it starts & imports cleanly (feed EOF so it exits).
|
|
60
|
+
./dist/cync mcp </dev/null 2>mcp_err.txt &
|
|
61
|
+
pid=$!
|
|
62
|
+
sleep 5
|
|
63
|
+
rc=started
|
|
64
|
+
if ! kill -0 "$pid" 2>/dev/null; then
|
|
65
|
+
rc=0; wait "$pid" || rc=$? # exited on its own: EOF→0 is fine, non-zero = crash
|
|
66
|
+
else
|
|
67
|
+
kill "$pid" 2>/dev/null || true; wait "$pid" 2>/dev/null || true
|
|
68
|
+
fi
|
|
69
|
+
if grep -qiE 'traceback|modulenotfound|importerror' mcp_err.txt; then
|
|
70
|
+
echo "::error::MCP failed to import in the bundled binary"; cat mcp_err.txt; exit 1
|
|
71
|
+
fi
|
|
72
|
+
if [ "$rc" != "started" ] && [ "$rc" != "0" ]; then
|
|
73
|
+
echo "::error::cync mcp exited early (rc=$rc) — likely a startup crash"; cat mcp_err.txt; exit 1
|
|
74
|
+
fi
|
|
75
|
+
echo "smoke ok (mcp rc=$rc)"
|
|
76
|
+
- name: Package tarball
|
|
77
|
+
run: tar -C dist -czf "cync-${{ matrix.target }}.tar.gz" cync
|
|
78
|
+
- uses: actions/upload-artifact@v4
|
|
79
|
+
with:
|
|
80
|
+
name: cync-${{ matrix.target }}
|
|
81
|
+
path: cync-${{ matrix.target }}.tar.gz
|
|
82
|
+
|
|
83
|
+
publish-tap:
|
|
84
|
+
needs: build
|
|
85
|
+
runs-on: ubuntu-latest
|
|
86
|
+
steps:
|
|
87
|
+
- uses: actions/checkout@v4 # for packaging/gen_formula.sh
|
|
88
|
+
- uses: actions/download-artifact@v4
|
|
89
|
+
with:
|
|
90
|
+
path: dist
|
|
91
|
+
merge-multiple: true
|
|
92
|
+
- name: Compute checksums
|
|
93
|
+
working-directory: dist
|
|
94
|
+
run: sha256sum *.tar.gz | tee SHA256SUMS
|
|
95
|
+
- name: Check tap token
|
|
96
|
+
env:
|
|
97
|
+
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
|
98
|
+
run: |
|
|
99
|
+
if [ -z "$TAP_TOKEN" ]; then
|
|
100
|
+
echo "::error::HOMEBREW_TAP_TOKEN not set — see the header of .github/workflows/release.yml"
|
|
101
|
+
exit 1
|
|
102
|
+
fi
|
|
103
|
+
# Fail fast on an expired/revoked/wrong-scoped token BEFORE creating the
|
|
104
|
+
# release — otherwise a bad token could upload assets, then 403 the
|
|
105
|
+
# formula push, leaving the tap with binaries but a stale formula.
|
|
106
|
+
code=$(curl -sS -o /dev/null -w '%{http_code}' \
|
|
107
|
+
-H "Authorization: Bearer $TAP_TOKEN" \
|
|
108
|
+
-H "Accept: application/vnd.github+json" \
|
|
109
|
+
https://api.github.com/repos/03hgryan/homebrew-tap)
|
|
110
|
+
if [ "$code" != "200" ]; then
|
|
111
|
+
echo "::error::HOMEBREW_TAP_TOKEN cannot reach 03hgryan/homebrew-tap (HTTP $code) — check it hasn't expired and has Contents: Read and write"
|
|
112
|
+
exit 1
|
|
113
|
+
fi
|
|
114
|
+
echo "tap token OK (repo reachable)"
|
|
115
|
+
- name: Publish binaries to the tap release
|
|
116
|
+
uses: softprops/action-gh-release@v2
|
|
117
|
+
with:
|
|
118
|
+
repository: 03hgryan/homebrew-tap
|
|
119
|
+
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
|
120
|
+
tag_name: ${{ github.ref_name }}
|
|
121
|
+
files: |
|
|
122
|
+
dist/*.tar.gz
|
|
123
|
+
dist/SHA256SUMS
|
|
124
|
+
- name: Update the Homebrew formula
|
|
125
|
+
env:
|
|
126
|
+
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
|
127
|
+
REF_NAME: ${{ github.ref_name }}
|
|
128
|
+
run: |
|
|
129
|
+
VER="${REF_NAME#v}"
|
|
130
|
+
bash packaging/gen_formula.sh "$VER" dist/SHA256SUMS > /tmp/cync.rb
|
|
131
|
+
git clone "https://x-access-token:${TAP_TOKEN}@github.com/03hgryan/homebrew-tap.git" tap
|
|
132
|
+
mkdir -p tap/Formula
|
|
133
|
+
cp /tmp/cync.rb tap/Formula/cync.rb
|
|
134
|
+
cd tap
|
|
135
|
+
git config user.name "github-actions[bot]"
|
|
136
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
137
|
+
git add Formula/cync.rb
|
|
138
|
+
git commit -m "cync ${VER}" || { echo "formula unchanged"; exit 0; }
|
|
139
|
+
git push
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cync-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Sync Claude Code conversations across machines — GitHub-authed CLI + server (Postgres metadata, R2 blobs).
|
|
5
5
|
Project-URL: Homepage, https://github.com/03hgryan/cync
|
|
6
6
|
Project-URL: Repository, https://github.com/03hgryan/cync
|
|
@@ -81,17 +81,30 @@ Browser / CLI ── GitHub login (Supabase Auth) ──┐
|
|
|
81
81
|
|
|
82
82
|
## Install & use (hosted)
|
|
83
83
|
|
|
84
|
-
The
|
|
85
|
-
it points at the hosted cync by default:
|
|
84
|
+
The command is `cync`. No server setup — it points at the hosted cync by default.
|
|
86
85
|
|
|
86
|
+
**Homebrew (macOS/Linux):**
|
|
87
|
+
```bash
|
|
88
|
+
brew install 03hgryan/tap/cync
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**PyPI** (published as `cync-cli`):
|
|
87
92
|
```bash
|
|
88
93
|
pipx install cync-cli # or: uv tool install cync-cli
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Then:
|
|
97
|
+
```bash
|
|
89
98
|
cync login # sign in with GitHub
|
|
90
99
|
cd ~/path/to/your/project
|
|
91
100
|
cync init myproject && cync push # machine A
|
|
92
101
|
cync link myproject && cync pull # machine B → claude --resume
|
|
93
102
|
```
|
|
94
103
|
|
|
104
|
+
> The Homebrew binary is a self-contained PyInstaller build (MCP included) served
|
|
105
|
+
> from the public [`homebrew-tap`](https://github.com/03hgryan/homebrew-tap) repo;
|
|
106
|
+
> see [`packaging/HOMEBREW.md`](packaging/HOMEBREW.md) for how releases are cut.
|
|
107
|
+
|
|
95
108
|
## Self-hosting
|
|
96
109
|
|
|
97
110
|
Prefer your own stack? Point the CLI at your deployment via `CYNC_SERVER_URL`
|
|
@@ -24,17 +24,30 @@ Browser / CLI ── GitHub login (Supabase Auth) ──┐
|
|
|
24
24
|
|
|
25
25
|
## Install & use (hosted)
|
|
26
26
|
|
|
27
|
-
The
|
|
28
|
-
it points at the hosted cync by default:
|
|
27
|
+
The command is `cync`. No server setup — it points at the hosted cync by default.
|
|
29
28
|
|
|
29
|
+
**Homebrew (macOS/Linux):**
|
|
30
|
+
```bash
|
|
31
|
+
brew install 03hgryan/tap/cync
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**PyPI** (published as `cync-cli`):
|
|
30
35
|
```bash
|
|
31
36
|
pipx install cync-cli # or: uv tool install cync-cli
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Then:
|
|
40
|
+
```bash
|
|
32
41
|
cync login # sign in with GitHub
|
|
33
42
|
cd ~/path/to/your/project
|
|
34
43
|
cync init myproject && cync push # machine A
|
|
35
44
|
cync link myproject && cync pull # machine B → claude --resume
|
|
36
45
|
```
|
|
37
46
|
|
|
47
|
+
> The Homebrew binary is a self-contained PyInstaller build (MCP included) served
|
|
48
|
+
> from the public [`homebrew-tap`](https://github.com/03hgryan/homebrew-tap) repo;
|
|
49
|
+
> see [`packaging/HOMEBREW.md`](packaging/HOMEBREW.md) for how releases are cut.
|
|
50
|
+
|
|
38
51
|
## Self-hosting
|
|
39
52
|
|
|
40
53
|
Prefer your own stack? Point the CLI at your deployment via `CYNC_SERVER_URL`
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
<footer
|
|
36
36
|
style="max-width:880px;margin:0 auto;padding:16px 20px;color:#888;font-size:12px;border-top:1px solid #1d2027"
|
|
37
37
|
>
|
|
38
|
-
<a href="/
|
|
38
|
+
<a href="/docs">Docs</a> · <a href="/privacy">Privacy</a> ·
|
|
39
|
+
<a href="https://github.com/03hgryan/cync">GitHub</a>
|
|
39
40
|
</footer>
|
|
40
41
|
|
|
41
42
|
<style>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<h1>cync docs</h1>
|
|
2
|
+
<p class="muted">
|
|
3
|
+
Sync your Claude Code conversations across machines, signed in with GitHub. CLI +
|
|
4
|
+
hosted server; your metadata lives in Postgres, transcripts in R2.
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<h2>Install</h2>
|
|
8
|
+
<pre class="code">brew install 03hgryan/tap/cync # macOS/Linux (Homebrew)
|
|
9
|
+
# or
|
|
10
|
+
pipx install cync-cli # or: uv tool install cync-cli
|
|
11
|
+
|
|
12
|
+
cync login # sign in with GitHub</pre>
|
|
13
|
+
|
|
14
|
+
<h2>Quickstart</h2>
|
|
15
|
+
<pre class="code"># machine A
|
|
16
|
+
cync init myproject # create a project + link this directory
|
|
17
|
+
cync push # upload this repo's conversations
|
|
18
|
+
|
|
19
|
+
# machine B
|
|
20
|
+
cync link myproject
|
|
21
|
+
cync pull # then: claude --resume</pre>
|
|
22
|
+
|
|
23
|
+
<h2>Commands</h2>
|
|
24
|
+
<table>
|
|
25
|
+
<tbody>
|
|
26
|
+
<tr><td><code>cync login</code> / <code>logout</code> / <code>whoami</code></td><td>GitHub auth session</td></tr>
|
|
27
|
+
<tr><td><code>cync init <name></code></td><td>create a project + link this directory</td></tr>
|
|
28
|
+
<tr><td><code>cync link <name></code></td><td>link this directory to an existing project</td></tr>
|
|
29
|
+
<tr><td><code>cync unlink</code></td><td>remove this directory's link</td></tr>
|
|
30
|
+
<tr><td><code>cync status</code></td><td>login, linked project, and local-vs-server sync state</td></tr>
|
|
31
|
+
<tr><td><code>cync push [id]</code></td><td>upload conversation(s)</td></tr>
|
|
32
|
+
<tr><td><code>cync pull [id]</code></td><td>download into <code>~/.claude</code></td></tr>
|
|
33
|
+
<tr><td><code>cync list</code></td><td>list this project's conversations</td></tr>
|
|
34
|
+
<tr><td><code>cync rm <id></code></td><td>delete one server conversation (local copy kept)</td></tr>
|
|
35
|
+
<tr><td><code>cync open</code></td><td>open this project in the web viewer</td></tr>
|
|
36
|
+
<tr><td><code>cync install-hooks</code></td><td>auto-sync via Claude Code hooks</td></tr>
|
|
37
|
+
<tr><td><code>cync project list</code> / <code>rm</code></td><td>manage projects</td></tr>
|
|
38
|
+
</tbody>
|
|
39
|
+
</table>
|
|
40
|
+
|
|
41
|
+
<h2>Auto-sync (hooks)</h2>
|
|
42
|
+
<p>Wire Claude Code to pull on session start and push on session end:</p>
|
|
43
|
+
<pre class="code">cync install-hooks # cync install-hooks --uninstall to remove</pre>
|
|
44
|
+
|
|
45
|
+
<h2>MCP server</h2>
|
|
46
|
+
<p>
|
|
47
|
+
Let Claude (or any MCP host) read your synced conversations <em>as context</em> —
|
|
48
|
+
pull a past chat into the model mid-conversation.
|
|
49
|
+
</p>
|
|
50
|
+
<pre class="code">pipx install 'cync-cli[mcp]'
|
|
51
|
+
cync login</pre>
|
|
52
|
+
<p>Add it to your MCP host (Claude Code <code>.mcp.json</code>, Claude Desktop config, …):</p>
|
|
53
|
+
<pre class="code">{'{'} "mcpServers": {'{'} "cync": {'{'} "command": "cync", "args": ["mcp"] {'}'} {'}'} {'}'}</pre>
|
|
54
|
+
<p class="muted">Tools: <code>list_projects</code>, <code>list_conversations(project)</code>, <code>get_conversation(project, id)</code>.</p>
|
|
55
|
+
|
|
56
|
+
<h2>API (developers)</h2>
|
|
57
|
+
<p>All data endpoints require a Supabase JWT (<code>Authorization: Bearer <token></code>) and are scoped to your user.</p>
|
|
58
|
+
<table>
|
|
59
|
+
<tbody>
|
|
60
|
+
<tr><td><code>GET /health</code> · <code>/config</code></td><td>liveness · public Supabase/web params</td></tr>
|
|
61
|
+
<tr><td><code>POST /projects</code></td><td>create a project <code>{'{'} name {'}'}</code></td></tr>
|
|
62
|
+
<tr><td><code>GET /projects</code></td><td>your projects</td></tr>
|
|
63
|
+
<tr><td><code>GET /projects/{id}/conversations</code></td><td>conversations in a project</td></tr>
|
|
64
|
+
<tr><td><code>GET /projects/{id}/conversations/{cid}</code></td><td>one conversation (base64 transcript)</td></tr>
|
|
65
|
+
<tr><td><code>PUT /conversations/{cid}</code></td><td>upsert a conversation</td></tr>
|
|
66
|
+
<tr><td><code>DELETE /conversations/{cid}</code> · <code>/projects/{id}</code></td><td>delete</td></tr>
|
|
67
|
+
</tbody>
|
|
68
|
+
</table>
|
|
69
|
+
|
|
70
|
+
<h2>Self-hosting</h2>
|
|
71
|
+
<p>
|
|
72
|
+
Prefer your own stack? Deploy the server + your own Supabase + R2 and point the CLI
|
|
73
|
+
at it with <code>CYNC_SERVER_URL</code>. See the
|
|
74
|
+
<a href="https://github.com/03hgryan/cync">GitHub repo</a>.
|
|
75
|
+
</p>
|
|
76
|
+
|
|
77
|
+
<style>
|
|
78
|
+
h2 { margin-top: 28px; font-size: 16px; }
|
|
79
|
+
.code {
|
|
80
|
+
background: #15191f;
|
|
81
|
+
border: 1px solid #1d2027;
|
|
82
|
+
border-radius: 8px;
|
|
83
|
+
padding: 12px 14px;
|
|
84
|
+
overflow-x: auto;
|
|
85
|
+
font: 13px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
86
|
+
white-space: pre;
|
|
87
|
+
}
|
|
88
|
+
table { border-collapse: collapse; width: 100%; }
|
|
89
|
+
td { border-bottom: 1px solid #1d2027; padding: 7px 8px; vertical-align: top; font-size: 13px; }
|
|
90
|
+
td:first-child { white-space: nowrap; padding-right: 16px; }
|
|
91
|
+
p { max-width: 680px; }
|
|
92
|
+
</style>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Homebrew distribution
|
|
2
|
+
|
|
3
|
+
`cync` ships to Homebrew as **standalone binaries** (PyInstaller `--onefile`,
|
|
4
|
+
MCP bundled) so users don't need Python. Because this source repo is **private**
|
|
5
|
+
and `brew` downloads release assets over unauthenticated HTTPS, the binaries and
|
|
6
|
+
the formula live on a separate **public** repo: [`03hgryan/homebrew-tap`].
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
tag v0.6.0 on cync (private)
|
|
10
|
+
│
|
|
11
|
+
▼ .github/workflows/release.yml
|
|
12
|
+
build macos-arm64 / macos-x86_64 / linux-x86_64 (PyInstaller)
|
|
13
|
+
│
|
|
14
|
+
▼ softprops/action-gh-release (via HOMEBREW_TAP_TOKEN)
|
|
15
|
+
03hgryan/homebrew-tap ── releases/v0.6.0/cync-*.tar.gz + SHA256SUMS
|
|
16
|
+
└─ Formula/cync.rb (regenerated, points at those assets)
|
|
17
|
+
│
|
|
18
|
+
▼
|
|
19
|
+
brew install 03hgryan/tap/cync
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## One-time setup
|
|
23
|
+
|
|
24
|
+
1. **Create the tap repo.** New **public** repo `03hgryan/homebrew-tap`, tick
|
|
25
|
+
*"Add a README"* so it has an initial commit (the release step needs a
|
|
26
|
+
default branch to exist).
|
|
27
|
+
|
|
28
|
+
2. **Create a scoped token.** GitHub → Settings → Developer settings →
|
|
29
|
+
**Fine-grained tokens**. Repository access: **only** `homebrew-tap`.
|
|
30
|
+
Permissions: **Contents → Read and write**. Copy the token.
|
|
31
|
+
|
|
32
|
+
3. **Add it to the cync repo.** cync → Settings → Secrets and variables →
|
|
33
|
+
Actions → **New repository secret**, name `HOMEBREW_TAP_TOKEN`, paste the
|
|
34
|
+
token.
|
|
35
|
+
|
|
36
|
+
## Cutting a release
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# bump version in pyproject.toml + src/cync/__init__.py first, commit, then:
|
|
40
|
+
git tag v0.6.0
|
|
41
|
+
git push origin v0.6.0
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
That fires two workflows in parallel:
|
|
45
|
+
- **publish.yml** → PyPI (`cync-cli`)
|
|
46
|
+
- **release.yml** → builds binaries, uploads them + `SHA256SUMS` to the tap's
|
|
47
|
+
release, regenerates `Formula/cync.rb`, and pushes it to the tap.
|
|
48
|
+
|
|
49
|
+
Verify:
|
|
50
|
+
```bash
|
|
51
|
+
brew update
|
|
52
|
+
brew install 03hgryan/tap/cync # or: brew upgrade cync
|
|
53
|
+
cync --version
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Regenerating the formula by hand
|
|
57
|
+
|
|
58
|
+
If you ever need to rebuild the formula outside CI (e.g. the tap push failed),
|
|
59
|
+
download the release's `SHA256SUMS` from the tap and run:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
bash packaging/gen_formula.sh 0.6.0 SHA256SUMS > Formula/cync.rb
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Notes / caveats
|
|
66
|
+
|
|
67
|
+
- **Unsigned binaries.** The PyInstaller output isn't code-signed or notarized.
|
|
68
|
+
Homebrew installs via `curl` (no quarantine xattr), so it runs — but if a user
|
|
69
|
+
ever sees a Gatekeeper block, `xattr -dr com.apple.quarantine $(brew --prefix)/bin/cync`
|
|
70
|
+
clears it. Notarization is a future improvement.
|
|
71
|
+
- **Startup cost.** `--onefile` unpacks to a temp dir on first run each launch;
|
|
72
|
+
fine for a CLI, slightly slower than a native binary.
|
|
73
|
+
- **Platforms.** macOS arm64/x86_64 and Linux x86_64. Add `ubuntu-24.04-arm`
|
|
74
|
+
to the matrix + an `on_linux/on_arm` block in `gen_formula.sh` for Linux ARM.
|
|
75
|
+
|
|
76
|
+
[`03hgryan/homebrew-tap`]: https://github.com/03hgryan/homebrew-tap
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""PyInstaller entry point for the standalone `cync` binary.
|
|
2
|
+
|
|
3
|
+
PyInstaller needs a script path (not a module), so this thin wrapper calls the
|
|
4
|
+
same entry point as the `cync` console script (`cync.client:main`).
|
|
5
|
+
"""
|
|
6
|
+
from cync.client import main
|
|
7
|
+
|
|
8
|
+
if __name__ == "__main__":
|
|
9
|
+
main()
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Generate the Homebrew formula for cync from a SHA256SUMS file.
|
|
3
|
+
#
|
|
4
|
+
# gen_formula.sh <version-without-v> [SHA256SUMS-path] > cync.rb
|
|
5
|
+
#
|
|
6
|
+
# Binaries live on the PUBLIC tap repo's releases (this source repo is private),
|
|
7
|
+
# so the formula's download URLs point there, not at the cync repo.
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
VERSION="${1:?usage: gen_formula.sh <version> [sums-file]}"
|
|
11
|
+
SUMS="${2:-SHA256SUMS}"
|
|
12
|
+
TAP_OWNER="${TAP_OWNER:-03hgryan}"
|
|
13
|
+
TAP_REPO="${TAP_REPO:-homebrew-tap}"
|
|
14
|
+
BASE="https://github.com/${TAP_OWNER}/${TAP_REPO}/releases/download/v${VERSION}"
|
|
15
|
+
|
|
16
|
+
# Pull one checksum out of the `sha256sum` output (format: "<hash> <file>").
|
|
17
|
+
sha() {
|
|
18
|
+
local line
|
|
19
|
+
line=$(grep " cync-$1\.tar\.gz\$" "$SUMS") || {
|
|
20
|
+
echo "gen_formula: no checksum for cync-$1.tar.gz in $SUMS" >&2
|
|
21
|
+
exit 1
|
|
22
|
+
}
|
|
23
|
+
echo "${line%% *}"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
ARM=$(sha macos-arm64)
|
|
27
|
+
INTEL=$(sha macos-x86_64)
|
|
28
|
+
LINUX=$(sha linux-x86_64)
|
|
29
|
+
|
|
30
|
+
cat <<EOF
|
|
31
|
+
class Cync < Formula
|
|
32
|
+
desc "Sync Claude Code conversations across machines"
|
|
33
|
+
homepage "https://cync-topaz.vercel.app/docs"
|
|
34
|
+
version "${VERSION}"
|
|
35
|
+
license "MIT"
|
|
36
|
+
|
|
37
|
+
on_macos do
|
|
38
|
+
on_arm do
|
|
39
|
+
url "${BASE}/cync-macos-arm64.tar.gz"
|
|
40
|
+
sha256 "${ARM}"
|
|
41
|
+
end
|
|
42
|
+
on_intel do
|
|
43
|
+
url "${BASE}/cync-macos-x86_64.tar.gz"
|
|
44
|
+
sha256 "${INTEL}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
on_linux do
|
|
49
|
+
on_intel do
|
|
50
|
+
url "${BASE}/cync-linux-x86_64.tar.gz"
|
|
51
|
+
sha256 "${LINUX}"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def install
|
|
56
|
+
bin.install "cync"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
test do
|
|
60
|
+
assert_match version.to_s, shell_output("#{bin}/cync --version")
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
EOF
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|