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 +75 -65
- package/package.json +1 -1
- package/scripts/postinstall.cjs +80 -46
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# cortex
|
|
2
2
|
|
|
3
|
-
**Sync Claude Code sessions between machines
|
|
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
|

|
|
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
|
-
##
|
|
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
|
-
|
|
59
|
+
Share skills, CLAUDE.md, plugins, and chat sessions with your whole team through a shared GitHub repo.
|
|
69
60
|
|
|
70
|
-
|
|
61
|
+
### Tech Lead — one-time setup
|
|
71
62
|
|
|
72
63
|
```bash
|
|
73
|
-
|
|
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
|
|
69
|
+
# Push updated context anytime
|
|
77
70
|
cortex team push
|
|
71
|
+
```
|
|
78
72
|
|
|
79
|
-
|
|
80
|
-
|
|
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
|
|
114
|
+
### Session encryption
|
|
96
115
|
|
|
97
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
122
|
+
---
|
|
106
123
|
|
|
107
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
|
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
|
|
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
|
-
|
|
234
|
+
On `cortex pull` or `cortex team pull`, for each session:
|
|
217
235
|
|
|
218
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
249
|
+
- Claude Code installed on each machine
|
|
240
250
|
|
|
241
251
|
---
|
|
242
252
|
|
package/package.json
CHANGED
package/scripts/postinstall.cjs
CHANGED
|
@@ -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 {
|
|
7
|
-
|
|
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
|
|
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
|
-
|
|
41
|
+
// ── 2. Already in PATH ──────────────────────────────────────────────────────
|
|
42
|
+
if (pathDirs.some((d) => d === binDir)) {
|
|
20
43
|
console.log('\n ✓ cortex installed. Run: cortex --version\n');
|
|
21
|
-
|
|
44
|
+
process.exit(0);
|
|
22
45
|
}
|
|
23
46
|
|
|
24
|
-
//
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
45
|
-
//
|
|
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
|
|
79
|
+
const nvmSh = join(nvmDir, 'nvm.sh');
|
|
48
80
|
const isNvmUser = existsSync(nvmSh);
|
|
49
81
|
|
|
50
|
-
let
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
//
|
|
108
|
+
// Never break the install process
|
|
75
109
|
}
|