@askalf/claude-sync 0.0.3 → 0.2.0
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 +105 -38
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +332 -35
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +31 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -2
- package/dist/config.js.map +1 -1
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +2 -1
- package/dist/format.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/project.d.ts +39 -8
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +98 -15
- package/dist/project.js.map +1 -1
- package/dist/session.d.ts +17 -5
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +25 -12
- package/dist/session.js.map +1 -1
- package/dist/ssh.d.ts +66 -0
- package/dist/ssh.d.ts.map +1 -0
- package/dist/ssh.js +216 -0
- package/dist/ssh.js.map +1 -0
- package/dist/transport.d.ts +40 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +63 -0
- package/dist/transport.js.map +1 -1
- package/package.json +3 -3
package/dist/ssh.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH transport — `.ccsync` files live in a directory on a remote host,
|
|
3
|
+
* reached over SSH. The target audience is "I run Claude Code on a dev
|
|
4
|
+
* server AND on my laptop"; the round-trip validation showed manual `scp`
|
|
5
|
+
* shuttling was the real friction, so this makes the remote box a
|
|
6
|
+
* first-class transport.
|
|
7
|
+
*
|
|
8
|
+
* Mechanics: every operation is one (or a few) `ssh host <command>` calls,
|
|
9
|
+
* where <command> is a small POSIX shell pipeline (mkdir / cat / mv /
|
|
10
|
+
* find). The remote layout is identical to the filesystem transport —
|
|
11
|
+
* `<dir>/<encoded-project-key>/<sessionId>-<machine>.ccsync` — so the two
|
|
12
|
+
* backends are wire-compatible (a server on `fs` and a laptop on `ssh`
|
|
13
|
+
* pointed at the same dir sync cleanly).
|
|
14
|
+
*
|
|
15
|
+
* Quoting: ssh concatenates its command args with spaces and hands the
|
|
16
|
+
* result to the remote login shell, which re-parses it. So every
|
|
17
|
+
* interpolated value is POSIX single-quoted via `shQuote`; file *lists*
|
|
18
|
+
* are never interpolated (we `find` them remotely and read by path).
|
|
19
|
+
*
|
|
20
|
+
* Testability: the actual `ssh` invocation sits behind `SshExecutor`.
|
|
21
|
+
* Tests inject a fake executor (to assert command construction) or a
|
|
22
|
+
* local-shell executor (to run the real pipelines against a temp dir
|
|
23
|
+
* without an sshd). `realSshExecutor` is the production one.
|
|
24
|
+
*/
|
|
25
|
+
import { spawnSync } from 'node:child_process';
|
|
26
|
+
import { createHash } from 'node:crypto';
|
|
27
|
+
import { tmpdir, homedir } from 'node:os';
|
|
28
|
+
import { join } from 'node:path';
|
|
29
|
+
import { encodeProjectDir } from './project.js';
|
|
30
|
+
import { parseCcsync, serializeCcsync } from './format.js';
|
|
31
|
+
/** POSIX single-quote `s` for safe interpolation into a remote shell
|
|
32
|
+
* command: wrap in '…' and rewrite each embedded ' as '\'' . */
|
|
33
|
+
export function shQuote(s) {
|
|
34
|
+
return `'${s.split("'").join("'\\''")}'`;
|
|
35
|
+
}
|
|
36
|
+
/** Strip leading and/or trailing `/` with a linear two-pointer scan — NOT
|
|
37
|
+
* `/\/+$/`, which is a polynomial-ReDoS vector on the config-derived path
|
|
38
|
+
* (CodeQL flags it). */
|
|
39
|
+
function trimSlashes(s, leading, trailing) {
|
|
40
|
+
let lo = 0;
|
|
41
|
+
let hi = s.length;
|
|
42
|
+
if (leading)
|
|
43
|
+
while (lo < hi && s[lo] === '/')
|
|
44
|
+
lo++;
|
|
45
|
+
if (trailing)
|
|
46
|
+
while (hi > lo && s[hi - 1] === '/')
|
|
47
|
+
hi--;
|
|
48
|
+
return s.slice(lo, hi);
|
|
49
|
+
}
|
|
50
|
+
/** Join remote (POSIX) path segments with `/`, trimming stray slashes but
|
|
51
|
+
* preserving a leading `/` on the first segment (absolute remote dirs). */
|
|
52
|
+
export function posixJoin(...parts) {
|
|
53
|
+
return parts
|
|
54
|
+
.map((p, i) => (i === 0 ? trimSlashes(p, false, true) : trimSlashes(p, true, true)))
|
|
55
|
+
.filter((p) => p.length > 0)
|
|
56
|
+
.join('/');
|
|
57
|
+
}
|
|
58
|
+
function expandHome(p) {
|
|
59
|
+
return p === '~' || p.startsWith('~/') ? join(homedir(), p.slice(1)) : p;
|
|
60
|
+
}
|
|
61
|
+
/** Build the `ssh` argv (everything before the remote command). Pure +
|
|
62
|
+
* exported so it can be unit-tested without spawning. */
|
|
63
|
+
export function buildSshArgs(cfg, controlPath) {
|
|
64
|
+
const args = [];
|
|
65
|
+
if (cfg.port)
|
|
66
|
+
args.push('-p', String(cfg.port));
|
|
67
|
+
if (cfg.identityFile)
|
|
68
|
+
args.push('-i', expandHome(cfg.identityFile));
|
|
69
|
+
// BatchMode: never block on a password/passphrase prompt — fail fast so
|
|
70
|
+
// `watch` / scripts don't hang. ConnectTimeout bounds an unreachable host.
|
|
71
|
+
args.push('-o', 'BatchMode=yes', '-o', 'ConnectTimeout=10');
|
|
72
|
+
if (controlPath) {
|
|
73
|
+
// Multiplex over one connection so the many small round-trips a single
|
|
74
|
+
// pull makes don't each pay a full TCP+auth handshake.
|
|
75
|
+
args.push('-o', 'ControlMaster=auto', '-o', `ControlPath=${controlPath}`, '-o', 'ControlPersist=60');
|
|
76
|
+
}
|
|
77
|
+
args.push(cfg.user ? `${cfg.user}@${cfg.host}` : cfg.host);
|
|
78
|
+
return args;
|
|
79
|
+
}
|
|
80
|
+
/** ControlMaster socket path for connection reuse — POSIX only (Windows
|
|
81
|
+
* OpenSSH historically lacks Unix-socket multiplexing, so we skip it and
|
|
82
|
+
* pay per-call connection cost there). */
|
|
83
|
+
function controlPathFor(cfg) {
|
|
84
|
+
if (process.platform === 'win32')
|
|
85
|
+
return undefined;
|
|
86
|
+
const id = createHash('sha256')
|
|
87
|
+
.update(`${cfg.user ?? ''}@${cfg.host}:${cfg.port ?? 22}`)
|
|
88
|
+
.digest('hex')
|
|
89
|
+
.slice(0, 12);
|
|
90
|
+
return join(tmpdir(), `cs-ssh-${id}`);
|
|
91
|
+
}
|
|
92
|
+
/** Production executor: shells out to the system `ssh`. */
|
|
93
|
+
export function realSshExecutor(cfg) {
|
|
94
|
+
const baseArgs = buildSshArgs(cfg, controlPathFor(cfg));
|
|
95
|
+
return {
|
|
96
|
+
run(remoteCommand, input) {
|
|
97
|
+
const r = spawnSync('ssh', [...baseArgs, remoteCommand], {
|
|
98
|
+
input,
|
|
99
|
+
encoding: 'utf-8',
|
|
100
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
101
|
+
});
|
|
102
|
+
if (r.error)
|
|
103
|
+
return { status: 1, stdout: '', stderr: r.error.message };
|
|
104
|
+
return { status: r.status ?? 1, stdout: r.stdout ?? '', stderr: r.stderr ?? '' };
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** Parse `find -printf '%T@\t%f\n'` output into {mtimeMs, name} rows. */
|
|
109
|
+
function parseFindRows(out) {
|
|
110
|
+
const rows = [];
|
|
111
|
+
for (const line of out.split('\n')) {
|
|
112
|
+
if (!line)
|
|
113
|
+
continue;
|
|
114
|
+
const tab = line.indexOf('\t');
|
|
115
|
+
if (tab < 0)
|
|
116
|
+
continue;
|
|
117
|
+
const mt = parseFloat(line.slice(0, tab));
|
|
118
|
+
const name = line.slice(tab + 1);
|
|
119
|
+
if (!name || !Number.isFinite(mt))
|
|
120
|
+
continue;
|
|
121
|
+
rows.push({ mtimeMs: mt * 1000, name });
|
|
122
|
+
}
|
|
123
|
+
return rows;
|
|
124
|
+
}
|
|
125
|
+
export class SshTransport {
|
|
126
|
+
cfg;
|
|
127
|
+
exec;
|
|
128
|
+
constructor(cfg, exec) {
|
|
129
|
+
this.cfg = cfg;
|
|
130
|
+
this.exec = exec ?? realSshExecutor(cfg);
|
|
131
|
+
}
|
|
132
|
+
describe() {
|
|
133
|
+
const who = this.cfg.user ? `${this.cfg.user}@${this.cfg.host}` : this.cfg.host;
|
|
134
|
+
const port = this.cfg.port && this.cfg.port !== 22 ? `:${this.cfg.port}` : '';
|
|
135
|
+
return `ssh ${who}${port} ${this.cfg.dir}`;
|
|
136
|
+
}
|
|
137
|
+
push(file) {
|
|
138
|
+
const enc = encodeProjectDir(file.projectKey);
|
|
139
|
+
const dir = posixJoin(this.cfg.dir, enc);
|
|
140
|
+
const name = `${file.sessionId}-${file.machineName}.ccsync`;
|
|
141
|
+
const path = posixJoin(dir, name);
|
|
142
|
+
const tmp = `${path}.tmp`;
|
|
143
|
+
// mkdir -p, stream content to a tmp file via stdin, atomic rename.
|
|
144
|
+
const cmd = `mkdir -p ${shQuote(dir)} && cat > ${shQuote(tmp)} && mv -f ${shQuote(tmp)} ${shQuote(path)}`;
|
|
145
|
+
const r = this.exec.run(cmd, serializeCcsync(file));
|
|
146
|
+
if (r.status !== 0) {
|
|
147
|
+
throw new Error(`ssh push failed (${this.describe()}): ${r.stderr.trim() || `exit ${r.status}`}`);
|
|
148
|
+
}
|
|
149
|
+
return `${this.describe()} → ${enc}/${name}`;
|
|
150
|
+
}
|
|
151
|
+
listProjectKeys() {
|
|
152
|
+
const cmd = `find ${shQuote(this.cfg.dir)} -mindepth 1 -maxdepth 1 -type d -printf '%f\\n' 2>/dev/null`;
|
|
153
|
+
const r = this.exec.run(cmd);
|
|
154
|
+
return r.stdout.split('\n').map((s) => s.trim()).filter(Boolean).sort();
|
|
155
|
+
}
|
|
156
|
+
listEntries(projectKey, selfMachineName) {
|
|
157
|
+
const enc = encodeProjectDir(projectKey);
|
|
158
|
+
const dir = posixJoin(this.cfg.dir, enc);
|
|
159
|
+
const listCmd = `find ${shQuote(dir)} -mindepth 1 -maxdepth 1 -type f -name '*.ccsync' ` +
|
|
160
|
+
`-printf '%T@\\t%f\\n' 2>/dev/null`;
|
|
161
|
+
const rows = parseFindRows(this.exec.run(listCmd).stdout);
|
|
162
|
+
const entries = [];
|
|
163
|
+
for (const row of rows) {
|
|
164
|
+
const content = this.readFile(posixJoin(dir, row.name));
|
|
165
|
+
if (content == null)
|
|
166
|
+
continue;
|
|
167
|
+
let file;
|
|
168
|
+
try {
|
|
169
|
+
file = parseCcsync(content);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
continue; // malformed / mid-write — skip quietly, like the fs transport
|
|
173
|
+
}
|
|
174
|
+
if (file.machineName === selfMachineName)
|
|
175
|
+
continue;
|
|
176
|
+
entries.push({ path: `${this.describe()}/${enc}/${row.name}`, file, mtime: row.mtimeMs });
|
|
177
|
+
}
|
|
178
|
+
entries.sort((a, b) => b.mtime - a.mtime);
|
|
179
|
+
return entries;
|
|
180
|
+
}
|
|
181
|
+
listMachines() {
|
|
182
|
+
const counts = new Map();
|
|
183
|
+
// Files live exactly two levels under the root: <dir>/<key>/<file>.
|
|
184
|
+
const listCmd = `find ${shQuote(this.cfg.dir)} -mindepth 2 -maxdepth 2 -type f -name '*.ccsync' 2>/dev/null`;
|
|
185
|
+
const paths = this.exec.run(listCmd).stdout.split('\n').map((s) => s.trim()).filter(Boolean);
|
|
186
|
+
for (const p of paths) {
|
|
187
|
+
const content = this.readFile(p);
|
|
188
|
+
if (content == null)
|
|
189
|
+
continue;
|
|
190
|
+
try {
|
|
191
|
+
const file = parseCcsync(content);
|
|
192
|
+
counts.set(file.machineName, (counts.get(file.machineName) ?? 0) + 1);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// skip malformed
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return counts;
|
|
199
|
+
}
|
|
200
|
+
health() {
|
|
201
|
+
const cmd = `test -d ${shQuote(this.cfg.dir)} && echo DIR_OK || echo DIR_MISSING`;
|
|
202
|
+
const r = this.exec.run(cmd);
|
|
203
|
+
if (!r.stdout.includes('DIR_OK') && !r.stdout.includes('DIR_MISSING')) {
|
|
204
|
+
return { ok: false, detail: `unreachable: ${r.stderr.trim() || `ssh exit ${r.status}`}` };
|
|
205
|
+
}
|
|
206
|
+
if (r.stdout.includes('DIR_MISSING')) {
|
|
207
|
+
return { ok: true, detail: `${this.describe()} (remote dir absent — created on first push)` };
|
|
208
|
+
}
|
|
209
|
+
return { ok: true, detail: this.describe() };
|
|
210
|
+
}
|
|
211
|
+
readFile(remotePath) {
|
|
212
|
+
const r = this.exec.run(`cat -- ${shQuote(remotePath)} 2>/dev/null`);
|
|
213
|
+
return r.status === 0 ? r.stdout : null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=ssh.js.map
|
package/dist/ssh.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh.js","sourceRoot":"","sources":["../src/ssh.ts"],"names":[],"mappings":"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"}
|
package/dist/transport.d.ts
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* `pull` picks the newest non-self file per session id.
|
|
19
19
|
*/
|
|
20
20
|
import type { CcsyncFile } from './format.js';
|
|
21
|
+
import type { TransportConfig } from './config.js';
|
|
21
22
|
export declare function projectSubdir(syncDir: string, projectKey: string): string;
|
|
22
23
|
/** Write a .ccsync file into the project's transport subdir. The
|
|
23
24
|
* filename includes the machine name so the receiver can tell who
|
|
@@ -34,6 +35,45 @@ export interface TransportEntry {
|
|
|
34
35
|
* `selfMachineName`) are omitted — pull is for receiving OTHER
|
|
35
36
|
* machines' work, not echoing your own. */
|
|
36
37
|
export declare function listTransport(syncDir: string, projectKey: string, selfMachineName: string): TransportEntry[];
|
|
38
|
+
/** Tally `machineName` → file count across every `.ccsync` in the
|
|
39
|
+
* transport (all projects). Used by `doctor` to catch the
|
|
40
|
+
* duplicate-machineName footgun: `pull` self-filters files whose
|
|
41
|
+
* machineName matches this machine's, so if two machines share a name —
|
|
42
|
+
* e.g. both defaulted to the same hostname — pull silently imports
|
|
43
|
+
* nothing. Malformed files are skipped quietly. */
|
|
44
|
+
export declare function listTransportMachines(syncDir: string): Map<string, number>;
|
|
45
|
+
export interface TransportHealth {
|
|
46
|
+
ok: boolean;
|
|
47
|
+
detail: string;
|
|
48
|
+
}
|
|
49
|
+
export interface Transport {
|
|
50
|
+
/** Write a .ccsync into the transport; return a human-readable location. */
|
|
51
|
+
push(file: CcsyncFile): string;
|
|
52
|
+
/** Newest-first entries for a project key, excluding self-authored files. */
|
|
53
|
+
listEntries(projectKey: string, selfMachineName: string): TransportEntry[];
|
|
54
|
+
/** All project keys (encoded form) present in the transport. */
|
|
55
|
+
listProjectKeys(): string[];
|
|
56
|
+
/** machineName → file count across the whole transport. */
|
|
57
|
+
listMachines(): Map<string, number>;
|
|
58
|
+
/** One-line description for banners / doctor. */
|
|
59
|
+
describe(): string;
|
|
60
|
+
/** Reachability + presence check for `doctor`. */
|
|
61
|
+
health(): TransportHealth;
|
|
62
|
+
}
|
|
63
|
+
/** Filesystem transport — thin object wrapper over the functions above so
|
|
64
|
+
* it satisfies the `Transport` interface. */
|
|
65
|
+
export declare class FsTransport implements Transport {
|
|
66
|
+
private readonly dir;
|
|
67
|
+
constructor(dir: string);
|
|
68
|
+
push(file: CcsyncFile): string;
|
|
69
|
+
listEntries(projectKey: string, selfMachineName: string): TransportEntry[];
|
|
70
|
+
listProjectKeys(): string[];
|
|
71
|
+
listMachines(): Map<string, number>;
|
|
72
|
+
describe(): string;
|
|
73
|
+
health(): TransportHealth;
|
|
74
|
+
}
|
|
75
|
+
/** Build the concrete transport for a resolved config. */
|
|
76
|
+
export declare function createTransport(tc: TransportConfig): Transport;
|
|
37
77
|
/** List all project keys present in the transport. Used by the CLI's
|
|
38
78
|
* `pull` (no args) form to fan out across every known project. */
|
|
39
79
|
export declare function listProjectKeys(syncDir: string): string[];
|
package/dist/transport.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;;gBAGgB;AAChB,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAWzE;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;4CAG4C;AAC5C,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,GACtB,cAAc,EAAE,CA0BlB;AAED;;;;;oDAKoD;AACpD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAkB1E;AAQD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,4EAA4E;IAC5E,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;IAC/B,6EAA6E;IAC7E,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,cAAc,EAAE,CAAC;IAC3E,gEAAgE;IAChE,eAAe,IAAI,MAAM,EAAE,CAAC;IAC5B,2DAA2D;IAC3D,YAAY,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,iDAAiD;IACjD,QAAQ,IAAI,MAAM,CAAC;IACnB,kDAAkD;IAClD,MAAM,IAAI,eAAe,CAAC;CAC3B;AAED;8CAC8C;AAC9C,qBAAa,WAAY,YAAW,SAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,MAAM;IAExC,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;IAG9B,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,cAAc,EAAE;IAG1E,eAAe,IAAI,MAAM,EAAE;IAG3B,YAAY,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAGnC,QAAQ,IAAI,MAAM;IAGlB,MAAM,IAAI,eAAe;CAK1B;AAED,0DAA0D;AAC1D,wBAAgB,eAAe,CAAC,EAAE,EAAE,eAAe,GAAG,SAAS,CAG9D;AAED;mEACmE;AACnE,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAWzD"}
|
package/dist/transport.js
CHANGED
|
@@ -21,6 +21,7 @@ import { existsSync, mkdirSync, readdirSync, statSync, writeFileSync, readFileSy
|
|
|
21
21
|
import { join } from 'node:path';
|
|
22
22
|
import { encodeProjectDir } from './project.js';
|
|
23
23
|
import { parseCcsync, serializeCcsync } from './format.js';
|
|
24
|
+
import { SshTransport } from './ssh.js';
|
|
24
25
|
export function projectSubdir(syncDir, projectKey) {
|
|
25
26
|
return join(syncDir, encodeProjectDir(projectKey));
|
|
26
27
|
}
|
|
@@ -73,6 +74,68 @@ export function listTransport(syncDir, projectKey, selfMachineName) {
|
|
|
73
74
|
result.sort((a, b) => b.mtime - a.mtime);
|
|
74
75
|
return result;
|
|
75
76
|
}
|
|
77
|
+
/** Tally `machineName` → file count across every `.ccsync` in the
|
|
78
|
+
* transport (all projects). Used by `doctor` to catch the
|
|
79
|
+
* duplicate-machineName footgun: `pull` self-filters files whose
|
|
80
|
+
* machineName matches this machine's, so if two machines share a name —
|
|
81
|
+
* e.g. both defaulted to the same hostname — pull silently imports
|
|
82
|
+
* nothing. Malformed files are skipped quietly. */
|
|
83
|
+
export function listTransportMachines(syncDir) {
|
|
84
|
+
const counts = new Map();
|
|
85
|
+
if (!existsSync(syncDir))
|
|
86
|
+
return counts;
|
|
87
|
+
for (const sub of readdirSync(syncDir, { withFileTypes: true })) {
|
|
88
|
+
if (!sub.isDirectory())
|
|
89
|
+
continue;
|
|
90
|
+
const dir = join(syncDir, sub.name);
|
|
91
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
92
|
+
if (!entry.isFile() || !entry.name.endsWith('.ccsync'))
|
|
93
|
+
continue;
|
|
94
|
+
try {
|
|
95
|
+
const file = parseCcsync(readFileSync(join(dir, entry.name), 'utf-8'));
|
|
96
|
+
counts.set(file.machineName, (counts.get(file.machineName) ?? 0) + 1);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Shared dir may hold in-progress writes / stale tmp files.
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return counts;
|
|
104
|
+
}
|
|
105
|
+
/** Filesystem transport — thin object wrapper over the functions above so
|
|
106
|
+
* it satisfies the `Transport` interface. */
|
|
107
|
+
export class FsTransport {
|
|
108
|
+
dir;
|
|
109
|
+
constructor(dir) {
|
|
110
|
+
this.dir = dir;
|
|
111
|
+
}
|
|
112
|
+
push(file) {
|
|
113
|
+
return pushToTransport(this.dir, file);
|
|
114
|
+
}
|
|
115
|
+
listEntries(projectKey, selfMachineName) {
|
|
116
|
+
return listTransport(this.dir, projectKey, selfMachineName);
|
|
117
|
+
}
|
|
118
|
+
listProjectKeys() {
|
|
119
|
+
return listProjectKeys(this.dir);
|
|
120
|
+
}
|
|
121
|
+
listMachines() {
|
|
122
|
+
return listTransportMachines(this.dir);
|
|
123
|
+
}
|
|
124
|
+
describe() {
|
|
125
|
+
return this.dir;
|
|
126
|
+
}
|
|
127
|
+
health() {
|
|
128
|
+
return existsSync(this.dir)
|
|
129
|
+
? { ok: true, detail: this.dir }
|
|
130
|
+
: { ok: false, detail: `directory does not exist: ${this.dir}` };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Build the concrete transport for a resolved config. */
|
|
134
|
+
export function createTransport(tc) {
|
|
135
|
+
if (tc.type === 'ssh')
|
|
136
|
+
return new SshTransport(tc);
|
|
137
|
+
return new FsTransport(tc.dir);
|
|
138
|
+
}
|
|
76
139
|
/** List all project keys present in the transport. Used by the CLI's
|
|
77
140
|
* `pull` (no args) form to fan out across every known project. */
|
|
78
141
|
export function listProjectKeys(syncDir) {
|
package/dist/transport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EACL,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EACzE,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,UAAkB;IAC/D,OAAO,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;AACrD,CAAC;AAED;;;gBAGgB;AAChB,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,IAAgB;IAC/D,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACpD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,WAAW,SAAS,CAAC;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACjC,qEAAqE;IACrE,6DAA6D;IAC7D,MAAM,GAAG,GAAG,GAAG,IAAI,MAAM,CAAC;IAC1B,aAAa,CAAC,GAAG,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtB,OAAO,IAAI,CAAC;AACd,CAAC;AAQD;;;4CAG4C;AAC5C,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,UAAkB,EAClB,eAAuB;IAEvB,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAqB,EAAE,CAAC;IAEpC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,SAAS;QACjE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,IAAgB,CAAC;QACrB,IAAI,CAAC;YACH,IAAI,GAAG,WAAW,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,kEAAkE;YAClE,4DAA4D;YAC5D,kCAAkC;YAClC,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,WAAW,KAAK,eAAe;YAAE,SAAS;QACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;mEACmE;AACnE,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,OAAO,OAAO;SACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;SAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACnB,gEAAgE;QAChE,8DAA8D;QAC9D,iEAAiE;QACjE,gDAAgD;SAC/C,IAAI,EAAE,CAAC;AACZ,CAAC"}
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/claude-sync",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "own your sessions — move Claude Code sessions across machines. Part of Own Your Stack.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"claude-sync": "./dist/cli.js"
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
],
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "tsc",
|
|
24
|
-
"test": "node --test test/project.test.mjs test/format.test.mjs test/session.test.mjs test/transport.test.mjs test/cli.test.mjs test/version.test.mjs",
|
|
24
|
+
"test": "node --test test/project.test.mjs test/format.test.mjs test/session.test.mjs test/transport.test.mjs test/config.test.mjs test/ssh.test.mjs test/cli.test.mjs test/watch.test.mjs test/version.test.mjs",
|
|
25
25
|
"typecheck": "tsc --noEmit",
|
|
26
26
|
"audit": "npm audit --production --audit-level=high",
|
|
27
27
|
"prepublishOnly": "npm run build",
|