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.
Files changed (58) hide show
  1. cync_cli-0.6.0/.github/workflows/release.yml +139 -0
  2. {cync_cli-0.5.0 → cync_cli-0.6.0}/PKG-INFO +16 -3
  3. {cync_cli-0.5.0 → cync_cli-0.6.0}/README.md +15 -2
  4. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/+layout.svelte +2 -1
  5. cync_cli-0.6.0/client/src/routes/docs/+page.svelte +92 -0
  6. cync_cli-0.6.0/packaging/HOMEBREW.md +76 -0
  7. cync_cli-0.6.0/packaging/cync.py +9 -0
  8. cync_cli-0.6.0/packaging/gen_formula.sh +63 -0
  9. {cync_cli-0.5.0 → cync_cli-0.6.0}/pyproject.toml +1 -1
  10. {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/__init__.py +1 -1
  11. {cync_cli-0.5.0 → cync_cli-0.6.0}/.dockerignore +0 -0
  12. {cync_cli-0.5.0 → cync_cli-0.6.0}/.env.example +0 -0
  13. {cync_cli-0.5.0 → cync_cli-0.6.0}/.github/workflows/publish.yml +0 -0
  14. {cync_cli-0.5.0 → cync_cli-0.6.0}/.gitignore +0 -0
  15. {cync_cli-0.5.0 → cync_cli-0.6.0}/Dockerfile +0 -0
  16. {cync_cli-0.5.0 → cync_cli-0.6.0}/LICENSE +0 -0
  17. {cync_cli-0.5.0 → cync_cli-0.6.0}/PRIVACY.md +0 -0
  18. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/.env.example +0 -0
  19. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/.gitignore +0 -0
  20. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/.npmrc +0 -0
  21. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/.vscode/extensions.json +0 -0
  22. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/README.md +0 -0
  23. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/package.json +0 -0
  24. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/pnpm-lock.yaml +0 -0
  25. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/pnpm-workspace.yaml +0 -0
  26. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/app.d.ts +0 -0
  27. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/app.html +0 -0
  28. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/hooks.server.ts +0 -0
  29. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/lib/assets/favicon.svg +0 -0
  30. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/lib/index.ts +0 -0
  31. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/lib/parse.ts +0 -0
  32. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/lib/server/cync.ts +0 -0
  33. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/lib/types.ts +0 -0
  34. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/+layout.server.ts +0 -0
  35. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/+layout.ts +0 -0
  36. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/+page.server.ts +0 -0
  37. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/+page.svelte +0 -0
  38. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/auth/callback/+server.ts +0 -0
  39. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/auth/signout/+server.ts +0 -0
  40. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/login/+page.svelte +0 -0
  41. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/p/[slug]/+page.server.ts +0 -0
  42. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/p/[slug]/+page.svelte +0 -0
  43. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/p/[slug]/c/[id]/+page.server.ts +0 -0
  44. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/p/[slug]/c/[id]/+page.svelte +0 -0
  45. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/src/routes/privacy/+page.svelte +0 -0
  46. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/static/robots.txt +0 -0
  47. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/tsconfig.json +0 -0
  48. {cync_cli-0.5.0 → cync_cli-0.6.0}/client/vite.config.ts +0 -0
  49. {cync_cli-0.5.0 → cync_cli-0.6.0}/scripts/migrate_legacy.py +0 -0
  50. {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/auth.py +0 -0
  51. {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/client.py +0 -0
  52. {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/common.py +0 -0
  53. {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/config.py +0 -0
  54. {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/mcp_server.py +0 -0
  55. {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/server.py +0 -0
  56. {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/storage.py +0 -0
  57. {cync_cli-0.5.0 → cync_cli-0.6.0}/src/cync/supabase_store.py +0 -0
  58. {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.5.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 CLI is on PyPI as **`cync-cli`** (the command is `cync`). No server setup
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 CLI is on PyPI as **`cync-cli`** (the command is `cync`). No server setup
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="/privacy">Privacy</a> · <a href="https://github.com/03hgryan/cync">GitHub</a>
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 &lt;name&gt;</code></td><td>create a project + link this directory</td></tr>
28
+ <tr><td><code>cync link &lt;name&gt;</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 &lt;id&gt;</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 &lt;token&gt;</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/&#123;id&#125;/conversations</code></td><td>conversations in a project</td></tr>
64
+ <tr><td><code>GET /projects/&#123;id&#125;/conversations/&#123;cid&#125;</code></td><td>one conversation (base64 transcript)</td></tr>
65
+ <tr><td><code>PUT /conversations/&#123;cid&#125;</code></td><td>upsert a conversation</td></tr>
66
+ <tr><td><code>DELETE /conversations/&#123;cid&#125;</code> · <code>/projects/&#123;id&#125;</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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cync-cli"
3
- version = "0.5.0"
3
+ version = "0.6.0"
4
4
  description = "Sync Claude Code conversations across machines — GitHub-authed CLI + server (Postgres metadata, R2 blobs)."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,3 +1,3 @@
1
1
  """cync — sync Claude Code conversations across machines."""
2
2
 
3
- __version__ = "0.5.0"
3
+ __version__ = "0.6.0"
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