cortex-sync 0.4.6 → 0.4.8

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.
package/README.md CHANGED
@@ -1,13 +1,15 @@
1
1
  # cortex
2
2
 
3
- **Sync Claude Code sessions between machines with automatic path remapping.**
3
+ **Sync Claude Code sessions between machines. Share team context automatically.**
4
4
 
5
- Claude Code stores your session history in `~/.claude/projects/` using absolute paths. Switch from your Mac to a Linux server and those sessions are gone — the paths don't match. `cortex` fixes that.
5
+ Claude Code stores your session history in `~/.claude/projects/` using absolute paths. Switch from your Mac to a Linux server and those sessions are gone — the paths don't match. `cortex` fixes that, and also lets your whole team share sessions, skills, and context through a shared GitHub repo.
6
6
 
7
7
  ```bash
8
8
  npm install -g cortex-sync
9
9
  ```
10
10
 
11
+ Works on **Linux**, **macOS**, and **Windows**. The `cortex` command is available immediately after install — no shell restart needed.
12
+
11
13
  ![cortex demo](demo/demo.gif)
12
14
 
13
15
  ---
@@ -29,7 +31,7 @@ Machine A (Mac) Machine B (Linux)
29
31
 
30
32
  ---
31
33
 
32
- ## Quick start
34
+ ## Quick start — personal sync
33
35
 
34
36
  ```bash
35
37
  # 1. Install
@@ -52,37 +54,54 @@ Open any project on Machine B — Claude Code shows your full session history.
52
54
 
53
55
  ---
54
56
 
55
- ## Commands
56
-
57
- | Command | What it does |
58
- |---|---|
59
- | `cortex init` | Configure storage, email, and passphrase |
60
- | `cortex sync` | Encrypt `~/.claude/` and upload |
61
- | `cortex pull` | Download, decrypt, remap paths |
62
- | `cortex status` | Show what's out of sync (no download) |
63
- | `cortex convert <file> --to <target>` | Convert a Claude Code skill |
64
- | `cortex setup-mcp` | Register cortex as a Claude Code MCP server |
65
-
66
- ---
57
+ ## Team context sharing
67
58
 
68
- ## Team context
59
+ Share skills, CLAUDE.md, plugins, and chat sessions with your whole team through a shared GitHub repo.
69
60
 
70
- Share skills, CLAUDE.md, plugins, and chat sessions with your team via a shared GitHub repo.
61
+ ### Tech Lead one-time setup
71
62
 
72
63
  ```bash
73
- # Tech Lead — one-time setup
64
+ cd your-project/
65
+
66
+ # Initialize the team repo and optionally share your sessions
74
67
  cortex team init --repo https://github.com/your-org/claude-config
75
68
 
76
- # Push your local .claude/ context + sessions (if opted in)
69
+ # Push updated context anytime
77
70
  cortex team push
71
+ ```
78
72
 
79
- # Dev pull team context + sessions
80
- cortex team pull
73
+ During `cortex team init` you are asked once:
74
+ - **Share sessions?** — whether to share your Claude Code sessions with the team
75
+ - **Encrypt?** — whether to encrypt them (AES-256-GCM, recommended)
76
+
77
+ If you choose to share, sessions are uploaded on every `cortex team push`.
78
+
79
+ ### Dev — first-time install
80
+
81
+ ```bash
82
+ cd your-project/
81
83
 
82
- # New dev — first-time install
83
84
  cortex install --repo https://github.com/your-org/claude-config
84
85
  ```
85
86
 
87
+ This single command:
88
+ - Installs team skills into `.claude/skills/`
89
+ - Installs team `CLAUDE.md`
90
+ - Installs required Claude plugins
91
+ - Downloads and installs all team sessions (paths remapped to your machine automatically)
92
+
93
+ Claude Code shows all team sessions natively — no extra steps. Restart Claude Code after running.
94
+
95
+ ### Day-to-day
96
+
97
+ ```bash
98
+ # Pull latest team context + new sessions from teammates
99
+ cortex team pull
100
+
101
+ # Push your updated sessions to the team
102
+ cortex team push
103
+ ```
104
+
86
105
  ### What gets shared
87
106
 
88
107
  | What | Source | Destination |
@@ -92,37 +111,42 @@ cortex install --repo https://github.com/your-org/claude-config
92
111
  | Plugins | Installed Claude plugins | `cortex.json → plugins[]` |
93
112
  | Sessions (opt-in) | `~/.claude/projects/<project>/` | `sessions/<email>/<project-id>/` |
94
113
 
95
- ### Session sharing
114
+ ### Session encryption
96
115
 
97
- During `cortex team init` you are asked once whether to share your Claude Code chat sessions with the team. If you accept:
116
+ Sessions are encrypted with AES-256-GCM using a shared team passphrase. The passphrase is **never stored** share it with teammates via a password manager. Everyone with the passphrase can decrypt each other's sessions.
98
117
 
99
- - Sessions are uploaded on every `cortex team push`
100
- - Teammates get your sessions (paths remapped to their machine) on `cortex team pull`
101
- - Claude Code shows all team sessions natively — no extra steps
118
+ **Two machines, same GitHub user:** Each machine generates unique session IDs, so pushing from two machines never creates duplicates.
102
119
 
103
- You can choose to encrypt sessions with a shared team passphrase (AES-256-GCM). Share the passphrase with your team via a password manager it is never stored by cortex.
120
+ > **Privacy:** Sessions may contain source code, API calls, and sensitive context. Only opt in if your team has a shared understanding that sessions are visible to all members.
104
121
 
105
- **Two machines, same GitHub user:** Each machine generates unique session IDs, so pushing from both machines never creates duplicates.
122
+ ---
106
123
 
107
- > **Privacy:** Sessions may contain source code, API calls, and sensitive context. Only opt in if your team has a shared understanding that sessions are visible to all members.
124
+ ## Commands
125
+
126
+ | Command | What it does |
127
+ |---|---|
128
+ | `cortex init` | Configure storage, email, and passphrase |
129
+ | `cortex sync` | Encrypt `~/.claude/` and upload |
130
+ | `cortex pull` | Download, decrypt, remap paths |
131
+ | `cortex status` | Show what's out of sync (no download) |
132
+ | `cortex team init` | Initialize team repo and set session sharing preference |
133
+ | `cortex team push` | Push skills, CLAUDE.md, and sessions to team repo |
134
+ | `cortex team pull` | Pull team context and sessions from repo |
135
+ | `cortex install` | First-time install from team repo (skills + sessions) |
136
+ | `cortex convert <file> --to <target>` | Convert a Claude Code skill |
137
+ | `cortex setup-mcp` | Register cortex as a Claude Code MCP server |
108
138
 
109
139
  ---
110
140
 
111
141
  ## Claude Code MCP integration
112
142
 
113
- Use `sync`, `pull`, `status`, `convert`, and `init` directly from the Claude Code chat — one command does everything:
143
+ Use `sync`, `pull`, `status`, `convert`, and `init` directly from the Claude Code chat:
114
144
 
115
145
  ```bash
116
- npm install -g cortex-sync
117
- cortex init # configure storage and passphrase
118
146
  cortex setup-mcp # registers cortex in Claude Code automatically
119
147
  ```
120
148
 
121
- That's it. Restart Claude Code and you're done.
122
-
123
- ### What setup-mcp does
124
-
125
- `cortex setup-mcp` detects the binary path, prompts for your passphrase once, and runs `claude mcp add` with the correct arguments — no manual PATH configuration needed.
149
+ Restart Claude Code and you're done.
126
150
 
127
151
  ### Available MCP tools
128
152
 
@@ -134,7 +158,7 @@ That's it. Restart Claude Code and you're done.
134
158
  | `convert` | Convert a skill to Antigravity or Cursor |
135
159
  | `init` | Configure storage (non-interactive) |
136
160
 
137
- ### Environment variables (advanced / manual setup)
161
+ ### Environment variables
138
162
 
139
163
  | Variable | Required for |
140
164
  |---|---|
@@ -148,8 +172,6 @@ That's it. Restart Claude Code and you're done.
148
172
 
149
173
  ### GitHub private repo (recommended)
150
174
 
151
- No OAuth app needed — just a Personal Access Token.
152
-
153
175
  ```bash
154
176
  cortex init
155
177
  # Select "GitHub private repo"
@@ -172,26 +194,24 @@ cortex init
172
194
 
173
195
  ## Skill conversion
174
196
 
175
- Convert Claude Code skills to other AI tool formats using your own Anthropic API key.
197
+ Convert Claude Code skills to other AI tool formats.
176
198
 
177
199
  ```bash
178
200
  # To Antigravity → .agent/skills/<name>/SKILL.md
179
201
  cortex convert ~/.claude/skills/tdd.md --to antigravity --output-dir ./my-project
180
202
 
181
- # To Cursor → .cursorrules (intelligent append, no duplicates across runs)
203
+ # To Cursor → .cursorrules
182
204
  cortex convert ~/.claude/skills/tdd.md --to cursor --output-dir ./my-project
183
205
 
184
206
  # Both at once
185
207
  cortex convert ~/.claude/skills/tdd.md --to all --output-dir ./my-project
186
208
  ```
187
209
 
188
- API key priority: `ANTHROPIC_API_KEY` env → `~/.cortex/api-key.enc` (encrypted) → interactive prompt.
189
-
190
210
  ---
191
211
 
192
212
  ## Security
193
213
 
194
- Everything is encrypted **before** leaving your machine. Your storage provider sees only ciphertext.
214
+ Everything is encrypted **before** leaving your machine.
195
215
 
196
216
  | What | How |
197
217
  |---|---|
@@ -199,44 +219,34 @@ Everything is encrypted **before** leaving your machine. Your storage provider s
199
219
  | Key derivation | PBKDF2, 600,000 iterations, SHA-256 |
200
220
  | Salt | SHA-256(lowercase(your email)) |
201
221
  | Passphrase | Never stored anywhere — derived fresh each session |
202
- | Secret detection | Warns before encrypting if API keys or PEM keys are found in your files |
203
-
204
- The GitHub PAT is stored in `~/.cortex/config.json` (your machine, your user). The Anthropic API key — if you choose to save it — goes to `~/.cortex/api-key.enc`, encrypted with your sync passphrase.
222
+ | Team sessions | Encrypted with shared passphrase, salt = team repo URL |
205
223
 
206
224
  ---
207
225
 
208
226
  ## How path remapping works
209
227
 
210
- Claude Code encodes project paths into directory names by replacing every non-alphanumeric character with `-`:
228
+ Claude Code encodes project paths by replacing every non-alphanumeric character with `-`:
211
229
 
212
230
  ```
213
231
  /home/alice/work/myapp → -home-alice-work-myapp
214
232
  ```
215
233
 
216
- This encoding is **lossy** — it cannot be reversed. `cortex` reads the `cwd` field inside each JSONL session file, which holds the original absolute path, and uses that as the source of truth.
234
+ On `cortex pull` or `cortex team pull`, for each session:
217
235
 
218
- On `cortex pull`, for each project:
236
+ 1. Reads `cwd` from the JSONL to get the original path
237
+ 2. Identifies the project via `git remote.origin.url` or first commit hash
238
+ 3. Rewrites only the 4 structural fields per line: `cwd`, `filePath`, `file_path`, `file.filePath`
219
239
 
220
- 1. Reads `cwd` from the session JSONL to get the original path
221
- 2. Identifies the project via `git remote.origin.url` or `git rev-list --max-parents=0 HEAD`
222
- 3. Looks up your local path in `~/.cortex/path-mappings.json` (prompts once if unknown)
223
- 4. Rewrites only the 4 structural fields per line: `cwd`, `filePath`, `file_path`, `file.filePath`
224
- 5. Renames `~/.claude/projects/<old-encoded>/` → `<new-encoded>/`
240
+ Conversation history and text responses are **never modified**.
225
241
 
226
- Conversation history, command outputs, and text responses are **never modified**.
227
-
228
- For projects without git, drop a `cortex.json` in the project root:
229
-
230
- ```json
231
- { "projectId": "my-unique-id" }
232
- ```
242
+ For projects without git, `cortex` automatically assigns a stable project ID on first `cortex team init` or `cortex team push`.
233
243
 
234
244
  ---
235
245
 
236
246
  ## Requirements
237
247
 
238
248
  - Node.js ≥ 20
239
- - Claude Code installed on each machine you want to sync
249
+ - Claude Code installed on each machine
240
250
 
241
251
  ---
242
252
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortex-sync",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "description": "Sync Claude Code sessions between machines with automatic path remapping and skill conversion",
5
5
  "license": "AGPL-3.0",
6
6
  "type": "module",
@@ -1,75 +1,109 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
+ /**
5
+ * Ensures the `cortex` binary is accessible in PATH after `npm install -g`.
6
+ *
7
+ * Strategy (in order):
8
+ * 1. Windows — Node.js installer always puts npm global bin in PATH. Done.
9
+ * 2. Already in PATH — nothing to do.
10
+ * 3. Symlink into a directory already in PATH (~/.local/bin on Linux, /usr/local/bin on macOS).
11
+ * 4. Fallback: append export PATH / nvm init to every existing shell config found.
12
+ */
13
+
4
14
  const { execSync } = require('child_process');
5
15
  const { join } = require('path');
6
- const { appendFileSync, readFileSync, existsSync } = require('fs');
7
- const { homedir } = require('os');
16
+ const {
17
+ appendFileSync, readFileSync, existsSync,
18
+ symlinkSync, mkdirSync, unlinkSync,
19
+ } = require('fs');
20
+ const { homedir, platform } = require('os');
21
+
22
+ // ── 1. Windows ────────────────────────────────────────────────────────────────
23
+ if (platform() === 'win32') {
24
+ // The official Node.js installer and nvm-windows both add the global bin to
25
+ // the system PATH automatically. Nothing to do.
26
+ console.log('\n ✓ cortex installed. Run: cortex --version\n');
27
+ process.exit(0);
28
+ }
8
29
 
9
30
  try {
31
+ // ── Resolve the actual binary path ──────────────────────────────────────────
10
32
  const prefix = execSync('npm config get prefix', {
11
33
  encoding: 'utf-8',
12
34
  stdio: ['pipe', 'pipe', 'ignore'],
13
35
  }).trim();
14
36
 
15
- const binDir = join(prefix, 'bin');
37
+ const binDir = join(prefix, 'bin');
38
+ const cortexBin = join(binDir, 'cortex');
16
39
  const pathDirs = (process.env.PATH || '').split(':');
17
- const inPath = pathDirs.some((d) => d === binDir);
18
40
 
19
- if (inPath) {
41
+ // ── 2. Already in PATH ──────────────────────────────────────────────────────
42
+ if (pathDirs.some((d) => d === binDir)) {
20
43
  console.log('\n ✓ cortex installed. Run: cortex --version\n');
21
- return;
44
+ process.exit(0);
22
45
  }
23
46
 
24
- // Detect shell config file
25
- const shell = process.env.SHELL || '';
47
+ // ── 3. Symlink into a directory that is already in PATH ─────────────────────
48
+ // Ordered by likelihood: ~/.local/bin (Linux), /usr/local/bin (macOS/Linux)
26
49
  const home = homedir();
27
- let rcFile = null;
28
- if (shell.includes('zsh')) {
29
- rcFile = join(home, '.zshrc');
30
- } else if (shell.includes('bash')) {
31
- rcFile = join(home, '.bashrc');
32
- } else if (shell.includes('fish')) {
33
- rcFile = join(home, '.config', 'fish', 'config.fish');
34
- }
50
+ const symlinkCandidates = [
51
+ join(home, '.local', 'bin'),
52
+ '/usr/local/bin',
53
+ ];
35
54
 
36
- if (!rcFile) {
37
- console.log('\n cortex installed.');
38
- console.log(` Add to your shell config: export PATH="${binDir}:$PATH"\n`);
39
- return;
55
+ for (const dir of symlinkCandidates) {
56
+ if (!pathDirs.some((d) => d === dir)) continue;
57
+ try {
58
+ mkdirSync(dir, { recursive: true });
59
+ const dest = join(dir, 'cortex');
60
+ if (existsSync(dest)) unlinkSync(dest);
61
+ symlinkSync(cortexBin, dest);
62
+ console.log('\n ✓ cortex installed. Run: cortex --version\n');
63
+ process.exit(0);
64
+ } catch { /* no write permission — try next candidate */ }
40
65
  }
41
66
 
42
- const existing = existsSync(rcFile) ? readFileSync(rcFile, 'utf-8') : '';
67
+ // ── 4. Fallback: patch every shell config found ──────────────────────────────
68
+ // Covers zsh, bash (interactive + login), and POSIX profile.
69
+ const rcFiles = [
70
+ join(home, '.zshrc'),
71
+ join(home, '.bashrc'),
72
+ join(home, '.bash_profile'),
73
+ join(home, '.profile'),
74
+ ].filter(existsSync);
43
75
 
44
- // Check if nvm is the reason the bin is not in PATH
45
- // (nvm puts the active version's bin in PATH only when loaded)
76
+ // Detect nvm users: if nvm.sh exists but isn't sourced in any config,
77
+ // add the nvm init block (more robust than a hard-coded version path).
46
78
  const nvmDir = process.env.NVM_DIR || join(home, '.nvm');
47
- const nvmSh = join(nvmDir, 'nvm.sh');
79
+ const nvmSh = join(nvmDir, 'nvm.sh');
48
80
  const isNvmUser = existsSync(nvmSh);
49
81
 
50
- let lineToAdd;
51
- if (isNvmUser && !existing.includes('nvm.sh')) {
52
- // nvm user but nvm not initialized in this shell — add nvm init
53
- lineToAdd =
54
- `\n# nvm (added by cortex-sync)\n` +
55
- `export NVM_DIR="${nvmDir}"\n` +
56
- `[ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"\n`;
57
- } else if (!existing.includes(binDir)) {
58
- // Non-nvm or nvm already initialized — just add the bin path
59
- lineToAdd = `\nexport PATH="${binDir}:$PATH" # added by cortex-sync\n`;
60
- } else {
61
- console.log('\n cortex installed. Reload your shell: source ' + rcFile + '\n');
62
- return;
63
- }
82
+ let patched = false;
83
+ for (const rc of rcFiles) {
84
+ const content = readFileSync(rc, 'utf-8');
64
85
 
65
- appendFileSync(rcFile, lineToAdd);
86
+ if (isNvmUser && !content.includes('nvm.sh')) {
87
+ appendFileSync(rc,
88
+ `\n# nvm (added by cortex-sync)\n` +
89
+ `export NVM_DIR="${nvmDir}"\n` +
90
+ `[ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"\n`,
91
+ );
92
+ patched = true;
93
+ } else if (!content.includes(binDir)) {
94
+ appendFileSync(rc, `\nexport PATH="${binDir}:$PATH" # added by cortex-sync\n`);
95
+ patched = true;
96
+ }
97
+ }
66
98
 
67
- console.log('\n╔════════════════════════════════════════════════╗');
68
- console.log(' cortex installed ✓ ║');
69
- console.log('╚════════════════════════════════════════════════╝');
70
- console.log(`\n Updated ${rcFile} so cortex is always available.`);
71
- console.log('\n Apply now (or open a new terminal):');
72
- console.log(` source ${rcFile}\n`);
99
+ if (patched) {
100
+ console.log('\n cortex installed.');
101
+ console.log(' Open a new terminal (or run: source ~/.zshrc) to use it.\n');
102
+ } else {
103
+ console.log(`\n cortex installed to: ${cortexBin}`);
104
+ console.log(` If "cortex" is not found, add to your shell config:`);
105
+ console.log(` export PATH="${binDir}:$PATH"\n`);
106
+ }
73
107
  } catch {
74
- // never break the install
108
+ // Never break the install process
75
109
  }