@tom2012/cc-web 2026.4.19-s → 2026.4.19-u

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 (67) hide show
  1. package/README.md +1 -1
  2. package/backend/dist/adapters/claude-adapter.d.ts +1 -1
  3. package/backend/dist/adapters/claude-adapter.d.ts.map +1 -1
  4. package/backend/dist/adapters/claude-adapter.js +169 -11
  5. package/backend/dist/adapters/claude-adapter.js.map +1 -1
  6. package/backend/dist/adapters/gemini-adapter.js +1 -1
  7. package/backend/dist/adapters/gemini-adapter.js.map +1 -1
  8. package/backend/dist/adapters/types.d.ts +4 -1
  9. package/backend/dist/adapters/types.d.ts.map +1 -1
  10. package/backend/dist/index.d.ts.map +1 -1
  11. package/backend/dist/index.js +4 -0
  12. package/backend/dist/index.js.map +1 -1
  13. package/backend/dist/routes/claude.d.ts.map +1 -1
  14. package/backend/dist/routes/claude.js +23 -1
  15. package/backend/dist/routes/claude.js.map +1 -1
  16. package/backend/dist/routes/projects.d.ts.map +1 -1
  17. package/backend/dist/routes/projects.js +26 -0
  18. package/backend/dist/routes/projects.js.map +1 -1
  19. package/backend/dist/routes/skillhub.d.ts +27 -0
  20. package/backend/dist/routes/skillhub.d.ts.map +1 -1
  21. package/backend/dist/routes/skillhub.js +149 -180
  22. package/backend/dist/routes/skillhub.js.map +1 -1
  23. package/backend/dist/routes/sync.d.ts +3 -0
  24. package/backend/dist/routes/sync.d.ts.map +1 -0
  25. package/backend/dist/routes/sync.js +183 -0
  26. package/backend/dist/routes/sync.js.map +1 -0
  27. package/backend/dist/sync-config.d.ts +62 -0
  28. package/backend/dist/sync-config.d.ts.map +1 -0
  29. package/backend/dist/sync-config.js +207 -0
  30. package/backend/dist/sync-config.js.map +1 -0
  31. package/backend/dist/sync-scheduler.d.ts +7 -0
  32. package/backend/dist/sync-scheduler.d.ts.map +1 -0
  33. package/backend/dist/sync-scheduler.js +157 -0
  34. package/backend/dist/sync-scheduler.js.map +1 -0
  35. package/backend/dist/sync-service.d.ts +54 -0
  36. package/backend/dist/sync-service.d.ts.map +1 -0
  37. package/backend/dist/sync-service.js +414 -0
  38. package/backend/dist/sync-service.js.map +1 -0
  39. package/backend/dist/user-prefs.d.ts +3 -0
  40. package/backend/dist/user-prefs.d.ts.map +1 -0
  41. package/backend/dist/user-prefs.js +87 -0
  42. package/backend/dist/user-prefs.js.map +1 -0
  43. package/backend/package-lock.json +26 -0
  44. package/backend/package.json +2 -0
  45. package/frontend/dist/assets/AssistantMessageContent-DuOuKxgH.js +13 -0
  46. package/frontend/dist/assets/{GraphPreview-DqnUioLI.js → GraphPreview-UVA4ODDv.js} +1 -1
  47. package/frontend/dist/assets/MobilePage-8bMFdgD9.js +14 -0
  48. package/frontend/dist/assets/{OfficePreview-DsfkiPFS.js → OfficePreview-DFa568OD.js} +2 -2
  49. package/frontend/dist/assets/{ProjectPage-eUYt7NVa.js → ProjectPage-D23Cx4LX.js} +5 -6
  50. package/frontend/dist/assets/SettingsPage-CTTCafJA.js +13 -0
  51. package/frontend/dist/assets/SkillHubPage-BBWaNxzY.js +13 -0
  52. package/frontend/dist/assets/{chevron-down-9-G7S6iK.js → chevron-down-XjVVezAn.js} +1 -1
  53. package/frontend/dist/assets/{chevron-up-BnktQ0Ve.js → chevron-up-BD4j4icv.js} +1 -1
  54. package/frontend/dist/assets/index-BL3iZx_u.css +1 -0
  55. package/frontend/dist/assets/{index-B7AIJuGG.js → index-Cz7UGH1l.js} +1 -1
  56. package/frontend/dist/assets/index-Qowsi3Ey.js +13 -0
  57. package/frontend/dist/assets/{index-Dn-YLcfD.js → index-hLxTQaCY.js} +10 -10
  58. package/frontend/dist/assets/{jszip.min-wfpG-66r.js → jszip.min-BvfmA-CV.js} +1 -1
  59. package/frontend/dist/assets/{search-Dq8YTmIg.js → search-CdJtkP3F.js} +1 -1
  60. package/frontend/dist/index.html +2 -2
  61. package/package.json +1 -1
  62. package/frontend/dist/assets/AssistantMessageContent-DayURBLZ.js +0 -13
  63. package/frontend/dist/assets/MobilePage-CIA-DkuB.js +0 -14
  64. package/frontend/dist/assets/SettingsPage-CCk3EySa.js +0 -13
  65. package/frontend/dist/assets/SkillHubPage-CRFSy-Cg.js +0 -13
  66. package/frontend/dist/assets/index-CboghLS5.js +0 -7
  67. package/frontend/dist/assets/index-pG308FQn.css +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-scheduler.js","sourceRoot":"","sources":["../src/sync-scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { type SyncDirection } from './sync-config';
2
+ /**
3
+ * rsync-driven sync service.
4
+ *
5
+ * Design choices worth noting:
6
+ *
7
+ * - **SSH options go through a wrapper script**, not through `rsync -e "ssh -p 22 -i …"`.
8
+ * Rsync parses the `-e` value by splitting on whitespace, so any keyPath with a space
9
+ * or an attacker-crafted `-oProxyCommand=…` would escalate self-config to code execution
10
+ * as the ccweb process. A wrapper `sh -c 'exec ssh <hardcoded opts> "$@"'` file written
11
+ * with user values quoted by `shell-quote` equivalent semantics removes this vector
12
+ * entirely.
13
+ * - **Password auth** uses `sshpass -e` wrapping the same script. `SSHPASS` env stays
14
+ * in the parent and is inherited by child only — never appears in argv or logs.
15
+ * - **Concurrency**: one in-flight sync per (user, project); subsequent calls return
16
+ * `{ skipped: true }`.
17
+ * - **Logs**: written via createWriteStream (ordered); file truncated to keep the last
18
+ * ~20 runs, preventing long-term growth.
19
+ * - **bidirectional**: is NOT a safe two-way sync (rsync can't). The push leg is run
20
+ * without --delete and with -u (update-if-newer), so remote-newer files survive the
21
+ * pull leg that follows. Deletions must be handled manually.
22
+ * - **openrsync (macOS 15+)**: shipped at `/usr/bin/rsync`, protocol 29. Doesn't support
23
+ * `--stats`; `-v` output doesn't include per-file lines. We use `-avzi` (itemize
24
+ * changes) which works on both GNU and openrsync, and parses telemetry from formats
25
+ * both emit (`>f`/`<f`-prefixed lines and the `total size is N` tail). A homebrew
26
+ * GNU rsync at `/opt/homebrew/bin/rsync` is preferred when present for richer output.
27
+ */
28
+ export interface SyncResult {
29
+ ok: boolean;
30
+ exitCode: number | null;
31
+ durationMs: number;
32
+ bytes: number;
33
+ filesTransferred: number;
34
+ logTail: string;
35
+ skipped?: true;
36
+ reason?: string;
37
+ }
38
+ /**
39
+ * Sync one project. Bidirectional runs the push leg without --delete (so the
40
+ * following pull can restore remote-newer files), then the pull leg.
41
+ */
42
+ export declare function syncProject(username: string, projectId: string, projectName: string, localPath: string, overrideDirection?: SyncDirection): Promise<SyncResult>;
43
+ export declare function isSyncing(username: string, projectId: string): boolean;
44
+ export declare function listInFlight(username: string): string[];
45
+ /**
46
+ * Non-destructive connection test: runs the wrapper script directly with
47
+ * `<user@host> true`. Uses the identical exec path as rsync's `-e`, so if
48
+ * this succeeds the sync's SSH setup will also succeed.
49
+ */
50
+ export declare function testConnection(username: string): Promise<{
51
+ ok: boolean;
52
+ message: string;
53
+ }>;
54
+ //# sourceMappingURL=sync-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-service.d.ts","sourceRoot":"","sources":["../src/sync-service.ts"],"names":[],"mappings":"AAMA,OAAO,EAEY,KAAK,aAAa,EACpC,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAkSD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,iBAAiB,CAAC,EAAE,aAAa,GAChC,OAAO,CAAC,UAAU,CAAC,CA6DrB;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAEtE;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAOvD;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAwChG"}
@@ -0,0 +1,414 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.syncProject = syncProject;
37
+ exports.isSyncing = isSyncing;
38
+ exports.listInFlight = listInFlight;
39
+ exports.testConnection = testConnection;
40
+ const child_process_1 = require("child_process");
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const os = __importStar(require("os"));
44
+ const crypto = __importStar(require("crypto"));
45
+ const config_1 = require("./config");
46
+ const sync_config_1 = require("./sync-config");
47
+ const LOGS_DIR = path.join(config_1.DATA_DIR, 'sync-logs');
48
+ const WRAP_DIR = path.join(config_1.DATA_DIR, 'sync-ssh');
49
+ const LOG_MAX_BYTES = 2 * 1024 * 1024; // 2 MB per project
50
+ const inFlight = new Map();
51
+ function inFlightKey(username, projectId) {
52
+ return `${username}::${projectId}`;
53
+ }
54
+ function userSlug(username) {
55
+ return crypto.createHash('sha1').update(`ccweb-sync-user:${username}`).digest('hex');
56
+ }
57
+ function ensureLogDir(username) {
58
+ const dir = path.join(LOGS_DIR, userSlug(username));
59
+ if (!fs.existsSync(dir))
60
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
61
+ return dir;
62
+ }
63
+ function ensureWrapDir() {
64
+ if (!fs.existsSync(WRAP_DIR))
65
+ fs.mkdirSync(WRAP_DIR, { recursive: true, mode: 0o700 });
66
+ return WRAP_DIR;
67
+ }
68
+ function resolveKeyPath(p) {
69
+ if (!p)
70
+ return null;
71
+ if (p.startsWith('~'))
72
+ return path.join(os.homedir(), p.slice(1));
73
+ return p;
74
+ }
75
+ /** Test that `sshpass` is on PATH; needed only for password auth. */
76
+ function hasSshpass() {
77
+ try {
78
+ (0, child_process_1.execSync)('command -v sshpass', { stdio: 'ignore', shell: '/bin/sh' });
79
+ return true;
80
+ }
81
+ catch {
82
+ return false;
83
+ }
84
+ }
85
+ let _rsyncBin = null;
86
+ function detectRsyncBin() {
87
+ if (_rsyncBin)
88
+ return _rsyncBin;
89
+ // Prefer homebrew GNU rsync; it has `--stats`, per-file `-v` output, and
90
+ // itemize changes that exactly matches the regex we use.
91
+ const candidates = ['/opt/homebrew/bin/rsync', '/usr/local/bin/rsync', '/usr/bin/rsync', 'rsync'];
92
+ for (const p of candidates) {
93
+ try {
94
+ const out = (0, child_process_1.execSync)(`${p} --version 2>&1 | head -1`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'], shell: '/bin/sh' }).trim();
95
+ if (!out)
96
+ continue;
97
+ const isOpenrsync = /openrsync/i.test(out);
98
+ _rsyncBin = { path: p, isOpenrsync, versionLine: out };
99
+ return _rsyncBin;
100
+ }
101
+ catch { /* try next */ }
102
+ }
103
+ // Last resort — will fail at spawn time with a clear error.
104
+ _rsyncBin = { path: 'rsync', isOpenrsync: false, versionLine: 'unknown' };
105
+ return _rsyncBin;
106
+ }
107
+ // ── SSH wrapper script ───────────────────────────────────────────────────────
108
+ /**
109
+ * POSIX shell single-quoting: wrap in `'…'` and replace any embedded `'`
110
+ * with `'\''`. Safe for all byte strings.
111
+ */
112
+ function shSingleQuote(s) {
113
+ return `'${s.replace(/'/g, `'\\''`)}'`;
114
+ }
115
+ /**
116
+ * Write (or refresh) a per-user SSH wrapper script. Rsync's `-e` takes a
117
+ * single token that it splits on whitespace; by passing it a path to this
118
+ * script, the rsync subprocess exec's the script as a *command*, passing the
119
+ * `[user@host, remote-command...]` tail as positional args. The script
120
+ * itself hardcodes all SSH options in shell-quoted form, so no user value is
121
+ * ever re-tokenized by anything between us and ssh.
122
+ *
123
+ * For password auth the same script prepends `sshpass -e`; SSHPASS is read
124
+ * from the inherited env at run time.
125
+ *
126
+ * Returns the absolute path to the script, written 0700.
127
+ */
128
+ function writeSshWrapper(cfg) {
129
+ ensureWrapDir();
130
+ const knownHostsFile = path.join(os.homedir(), '.ssh', 'known_hosts_ccweb');
131
+ const parts = [];
132
+ if (cfg.authMethod === 'password')
133
+ parts.push('sshpass', '-e');
134
+ parts.push('ssh');
135
+ parts.push('-p', String(cfg.port));
136
+ parts.push('-o', 'StrictHostKeyChecking=accept-new');
137
+ parts.push('-o', `UserKnownHostsFile=${knownHostsFile}`);
138
+ parts.push('-o', 'BatchMode=yes');
139
+ parts.push('-o', 'ConnectTimeout=20');
140
+ if (cfg.authMethod === 'key') {
141
+ const keyPath = resolveKeyPath(cfg.keyPath);
142
+ if (keyPath) {
143
+ parts.push('-i', keyPath);
144
+ parts.push('-o', 'IdentitiesOnly=yes');
145
+ }
146
+ }
147
+ // Quote every component once, here, and never string-concat user data again
148
+ const quoted = parts.map(shSingleQuote).join(' ');
149
+ const script = `#!/bin/sh\nexec ${quoted} "$@"\n`;
150
+ const file = path.join(WRAP_DIR, `${userSlug(cfg.username)}.sh`);
151
+ fs.writeFileSync(file, script, { mode: 0o700 });
152
+ return file;
153
+ }
154
+ // ── Log rotation ────────────────────────────────────────────────────────────
155
+ function rotateLogIfLarge(logFile) {
156
+ try {
157
+ const stat = fs.statSync(logFile);
158
+ if (stat.size > LOG_MAX_BYTES) {
159
+ // Keep the last half by reading tail and overwriting; avoids
160
+ // renaming (which would leave a .old file on disk forever).
161
+ const fd = fs.openSync(logFile, 'r');
162
+ const halfSize = Math.floor(LOG_MAX_BYTES / 2);
163
+ const buf = Buffer.alloc(halfSize);
164
+ fs.readSync(fd, buf, 0, halfSize, stat.size - halfSize);
165
+ fs.closeSync(fd);
166
+ // Align to next newline so we don't start mid-line
167
+ const nl = buf.indexOf(0x0a);
168
+ const tail = nl >= 0 ? buf.subarray(nl + 1) : buf;
169
+ fs.writeFileSync(logFile, Buffer.concat([Buffer.from('===== (older entries rotated) =====\n'), tail]));
170
+ }
171
+ }
172
+ catch { /* missing file or read failure — no-op */ }
173
+ }
174
+ function buildRsyncArgs(cfg, localPath, folderName, excludes, direction, bidirectionalLeg) {
175
+ const wrapper = writeSshWrapper(cfg);
176
+ // `-a` archive, `-v` verbose, `-z` compress, `-i` itemize changes.
177
+ // `-i` prints one `<11-char-flags> path` line per changed path on both GNU
178
+ // and openrsync, so telemetry parsing works identically on both. macOS
179
+ // openrsync doesn't support `--stats`, so we avoid it.
180
+ const args = ['-avzi'];
181
+ args.push('-e', wrapper);
182
+ for (const pat of excludes) {
183
+ const trimmed = pat.trim();
184
+ if (trimmed)
185
+ args.push('--exclude', trimmed);
186
+ }
187
+ const localSpec = localPath.endsWith('/') ? localPath : localPath + '/';
188
+ // path.posix.join on sanitized name; folderName is already validated to
189
+ // contain no `..` / separators.
190
+ const remoteSpec = `${cfg.user}@${cfg.host}:${path.posix.join(cfg.remoteRoot, folderName)}/`;
191
+ if (direction === 'push') {
192
+ // Only the pure-push path uses --delete (mirror semantics). The push leg
193
+ // of "bidirectional" must not delete remote-newer files the pull leg is
194
+ // about to bring back.
195
+ if (!bidirectionalLeg)
196
+ args.push('--delete');
197
+ else
198
+ args.push('-u');
199
+ args.push(localSpec, remoteSpec);
200
+ }
201
+ else {
202
+ // pull: never --delete (protects local work-in-progress)
203
+ args.push(remoteSpec, localSpec);
204
+ }
205
+ const env = { ...process.env };
206
+ if (cfg.authMethod === 'password' && cfg.passwordEnc) {
207
+ const pw = (0, sync_config_1.decryptPassword)(cfg.passwordEnc, cfg.passwordFp);
208
+ if (pw)
209
+ env.SSHPASS = pw;
210
+ }
211
+ return { args, env };
212
+ }
213
+ /**
214
+ * Telemetry parse from rsync -avzi output.
215
+ *
216
+ * - **filesTransferred**: lines beginning with `[<>ch*.]f` (itemize-changes
217
+ * format; the first char indicates direction of update, second char is
218
+ * type=file). Matches both GNU rsync and openrsync output.
219
+ * - **bytes**: prefer `total size is N` (user-facing "how much data moved"),
220
+ * fall back to `sent N bytes` / `received N bytes` depending on direction.
221
+ * `total size is` is authoritative on both rsync variants.
222
+ */
223
+ function parseRsyncOutput(combined, direction) {
224
+ // itemize-changes lines: <11 flag chars> <space> <path>
225
+ // First char: >/< (update local/remote), c (created), h (hardlink), * (message), . (unchanged)
226
+ // Second char: f (file), d (dir), L (symlink), D (device), S (special)
227
+ // We want "file transferred" = first char is >/< and second is f.
228
+ const fileMatches = combined.match(/^[<>ch][fdLDS]\S*\s+\S/gm) ?? [];
229
+ const files = fileMatches.filter((line) => /^[<>ch]f/.test(line)).length;
230
+ // Bytes: prefer total size (user-meaningful), fallback to sent/received.
231
+ const totalMatch = combined.match(/total size is\s+([\d,]+)/i);
232
+ let bytes = 0;
233
+ if (totalMatch) {
234
+ bytes = parseInt(totalMatch[1].replace(/,/g, ''), 10);
235
+ }
236
+ else {
237
+ // sent/received lines: `sent X bytes received Y bytes ...`
238
+ const sentMatch = combined.match(/sent\s+([\d,]+)\s+bytes/i);
239
+ const recvMatch = combined.match(/received\s+([\d,]+)\s+bytes/i);
240
+ const sent = sentMatch ? parseInt(sentMatch[1].replace(/,/g, ''), 10) : 0;
241
+ const recv = recvMatch ? parseInt(recvMatch[1].replace(/,/g, ''), 10) : 0;
242
+ // Push: local sends file data; Pull: local receives file data. Pick the
243
+ // direction-appropriate number rather than `sent` always.
244
+ bytes = direction === 'pull' ? recv : sent;
245
+ }
246
+ return { bytes, files };
247
+ }
248
+ async function runOne(cfg, projectId, folderName, localPath, direction, bidirectionalLeg) {
249
+ const excludes = [...cfg.defaultExcludes, ...(cfg.projectExcludes[projectId] ?? [])];
250
+ const { args, env } = buildRsyncArgs(cfg, localPath, folderName, excludes, direction, bidirectionalLeg);
251
+ if (cfg.authMethod === 'password' && !env.SSHPASS) {
252
+ return { ok: false, exitCode: null, durationMs: 0, bytes: 0, filesTransferred: 0, logTail: '', reason: 'password-decrypt-failed' };
253
+ }
254
+ const logDir = ensureLogDir(cfg.username);
255
+ const logFile = path.join(logDir, `${projectId}.log`);
256
+ rotateLogIfLarge(logFile);
257
+ const bin = detectRsyncBin();
258
+ const startStamp = new Date().toISOString();
259
+ const header = `\n===== ${startStamp} ${direction.toUpperCase()}${bidirectionalLeg ? '(bidi)' : ''} ${folderName} (${bin.versionLine}) =====\n`;
260
+ const started = Date.now();
261
+ return await new Promise((resolve) => {
262
+ let combined = '';
263
+ const logStream = fs.createWriteStream(logFile, { flags: 'a', mode: 0o600 });
264
+ logStream.write(header);
265
+ const child = (0, child_process_1.spawn)(bin.path, args, { env, cwd: os.homedir(), stdio: ['ignore', 'pipe', 'pipe'] });
266
+ const onData = (buf) => {
267
+ const s = buf.toString();
268
+ combined += s;
269
+ logStream.write(s);
270
+ };
271
+ child.stdout.on('data', onData);
272
+ child.stderr.on('data', onData);
273
+ child.on('error', (err) => {
274
+ logStream.write(`spawn error: ${err.message}\n`);
275
+ logStream.end();
276
+ resolve({ ok: false, exitCode: null, durationMs: Date.now() - started, bytes: 0, filesTransferred: 0, logTail: err.message, reason: 'spawn-failed' });
277
+ });
278
+ child.on('close', (code) => {
279
+ logStream.end();
280
+ const ok = code === 0;
281
+ const { bytes, files } = parseRsyncOutput(combined, direction);
282
+ const logTail = combined.split('\n').slice(-30).join('\n');
283
+ resolve({ ok, exitCode: code, durationMs: Date.now() - started, bytes, filesTransferred: files, logTail });
284
+ });
285
+ });
286
+ }
287
+ // ── Public API ──────────────────────────────────────────────────────────────
288
+ /**
289
+ * Sync one project. Bidirectional runs the push leg without --delete (so the
290
+ * following pull can restore remote-newer files), then the pull leg.
291
+ */
292
+ async function syncProject(username, projectId, projectName, localPath, overrideDirection) {
293
+ const key = inFlightKey(username, projectId);
294
+ if (inFlight.has(key)) {
295
+ return { ok: false, exitCode: null, durationMs: 0, bytes: 0, filesTransferred: 0, logTail: '', skipped: true, reason: 'already-syncing' };
296
+ }
297
+ const cfg = (0, sync_config_1.getSyncConfig)(username);
298
+ // Preflight validation — fail fast with a clear reason instead of spawning
299
+ // rsync and watching it error cryptically.
300
+ if (!cfg.host || !cfg.user || !cfg.remoteRoot) {
301
+ return { ok: false, exitCode: null, durationMs: 0, bytes: 0, filesTransferred: 0, logTail: '', reason: 'incomplete-config' };
302
+ }
303
+ // keyPath is OPTIONAL for key auth (empty → default agent / ~/.ssh/id_*).
304
+ // BUT if the user specified one, verify it exists — ssh will otherwise
305
+ // silently ignore a missing -i file and fall back to the agent, creating
306
+ // the illusion that their configured key is being used.
307
+ if (cfg.authMethod === 'key' && cfg.keyPath) {
308
+ const resolved = resolveKeyPath(cfg.keyPath);
309
+ if (resolved && !fs.existsSync(resolved)) {
310
+ return { ok: false, exitCode: null, durationMs: 0, bytes: 0, filesTransferred: 0, logTail: '', reason: 'key-path-not-found' };
311
+ }
312
+ }
313
+ if (cfg.authMethod === 'password' && !hasSshpass()) {
314
+ return { ok: false, exitCode: null, durationMs: 0, bytes: 0, filesTransferred: 0, logTail: '', reason: 'sshpass-not-installed' };
315
+ }
316
+ if (!fs.existsSync(localPath)) {
317
+ return { ok: false, exitCode: null, durationMs: 0, bytes: 0, filesTransferred: 0, logTail: '', reason: 'local-path-missing' };
318
+ }
319
+ // Folder name on the remote: prefer the project display name, fall back to
320
+ // basename then projectId. Must be sanitized or we'd let a project name
321
+ // containing `..` escape the remote root.
322
+ const rawName = projectName || path.basename(localPath) || projectId;
323
+ const folderName = (0, sync_config_1.sanitizeFolderName)(rawName) ?? projectId;
324
+ const direction = overrideDirection ?? cfg.direction;
325
+ const job = (async () => {
326
+ if (direction === 'bidirectional') {
327
+ const push = await runOne(cfg, projectId, folderName, localPath, 'push', true);
328
+ if (!push.ok)
329
+ return push;
330
+ const pull = await runOne(cfg, projectId, folderName, localPath, 'pull', true);
331
+ return {
332
+ ok: pull.ok,
333
+ exitCode: pull.exitCode,
334
+ durationMs: push.durationMs + pull.durationMs,
335
+ bytes: push.bytes + pull.bytes,
336
+ filesTransferred: push.filesTransferred + pull.filesTransferred,
337
+ logTail: `[PUSH]\n${push.logTail}\n[PULL]\n${pull.logTail}`,
338
+ };
339
+ }
340
+ return runOne(cfg, projectId, folderName, localPath, direction, false);
341
+ })();
342
+ inFlight.set(key, job);
343
+ try {
344
+ return await job;
345
+ }
346
+ finally {
347
+ inFlight.delete(key);
348
+ }
349
+ }
350
+ function isSyncing(username, projectId) {
351
+ return inFlight.has(inFlightKey(username, projectId));
352
+ }
353
+ function listInFlight(username) {
354
+ const prefix = `${username}::`;
355
+ const out = [];
356
+ for (const k of inFlight.keys()) {
357
+ if (k.startsWith(prefix))
358
+ out.push(k.slice(prefix.length));
359
+ }
360
+ return out;
361
+ }
362
+ /**
363
+ * Non-destructive connection test: runs the wrapper script directly with
364
+ * `<user@host> true`. Uses the identical exec path as rsync's `-e`, so if
365
+ * this succeeds the sync's SSH setup will also succeed.
366
+ */
367
+ async function testConnection(username) {
368
+ const cfg = (0, sync_config_1.getSyncConfig)(username);
369
+ if (!cfg.host || !cfg.user)
370
+ return { ok: false, message: '未配置 host/user' };
371
+ if (cfg.authMethod === 'key' && cfg.keyPath) {
372
+ const resolved = resolveKeyPath(cfg.keyPath);
373
+ if (resolved && !fs.existsSync(resolved)) {
374
+ return { ok: false, message: `SSH 私钥文件不存在: ${resolved}` };
375
+ }
376
+ }
377
+ if (cfg.authMethod === 'password' && !hasSshpass()) {
378
+ return { ok: false, message: '未安装 sshpass(密码认证需要)。请用 key 认证或安装 sshpass。' };
379
+ }
380
+ if (cfg.authMethod === 'password' && cfg.passwordEnc) {
381
+ const pw = (0, sync_config_1.decryptPassword)(cfg.passwordEnc, cfg.passwordFp);
382
+ if (!pw)
383
+ return { ok: false, message: '密码解密失败(服务端密钥可能已轮换)。请重新输入密码。' };
384
+ }
385
+ const wrapper = writeSshWrapper(cfg);
386
+ const env = { ...process.env };
387
+ if (cfg.authMethod === 'password' && cfg.passwordEnc) {
388
+ const pw = (0, sync_config_1.decryptPassword)(cfg.passwordEnc, cfg.passwordFp);
389
+ if (pw)
390
+ env.SSHPASS = pw;
391
+ }
392
+ return await new Promise((resolve) => {
393
+ let err = '';
394
+ // Invoke the wrapper directly — same exec path as rsync's -e would.
395
+ const child = (0, child_process_1.spawn)(wrapper, [`${cfg.user}@${cfg.host}`, 'true'], { env, stdio: ['ignore', 'ignore', 'pipe'] });
396
+ const timeout = setTimeout(() => {
397
+ try {
398
+ child.kill('SIGTERM');
399
+ }
400
+ catch { /* ignore */ }
401
+ resolve({ ok: false, message: '连接超时(30s)' });
402
+ }, 30000);
403
+ child.stderr.on('data', (b) => { err += b.toString(); });
404
+ child.on('error', (e) => { clearTimeout(timeout); resolve({ ok: false, message: `spawn 失败: ${e.message}` }); });
405
+ child.on('close', (code) => {
406
+ clearTimeout(timeout);
407
+ if (code === 0)
408
+ resolve({ ok: true, message: '连接成功' });
409
+ else
410
+ resolve({ ok: false, message: err.trim() || `ssh 退出码 ${code}` });
411
+ });
412
+ });
413
+ }
414
+ //# sourceMappingURL=sync-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-service.js","sourceRoot":"","sources":["../src/sync-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function getUserPref<T = unknown>(username: string, key: string): T | undefined;
2
+ export declare function setUserPref(username: string, key: string, value: unknown): void;
3
+ //# sourceMappingURL=user-prefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-prefs.d.ts","sourceRoot":"","sources":["../src/user-prefs.ts"],"names":[],"mappings":"AA0CA,wBAAgB,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAGrF;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAK/E"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getUserPref = getUserPref;
37
+ exports.setUserPref = setUserPref;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const config_1 = require("./config");
41
+ /**
42
+ * Per-user preferences persisted across restarts.
43
+ *
44
+ * Shape on disk: `{ [username]: { [key]: value } }`
45
+ *
46
+ * Keeps tiny, non-secret client-side state (project order, ui prefs) in one
47
+ * file rather than scattering one file per user × feature. Not for anything
48
+ * security-sensitive — no auth data here.
49
+ */
50
+ const PREFS_FILE = path.join(config_1.DATA_DIR, 'user-prefs.json');
51
+ let cache = null;
52
+ let cacheMtime = 0;
53
+ function readAll() {
54
+ try {
55
+ const stat = fs.statSync(PREFS_FILE);
56
+ if (cache && stat.mtimeMs === cacheMtime)
57
+ return cache;
58
+ const raw = fs.readFileSync(PREFS_FILE, 'utf-8');
59
+ cache = JSON.parse(raw);
60
+ cacheMtime = stat.mtimeMs;
61
+ return cache;
62
+ }
63
+ catch {
64
+ cache = {};
65
+ cacheMtime = 0;
66
+ return cache;
67
+ }
68
+ }
69
+ function writeAll(prefs) {
70
+ (0, config_1.atomicWriteSync)(PREFS_FILE, JSON.stringify(prefs, null, 2));
71
+ cache = prefs;
72
+ try {
73
+ cacheMtime = fs.statSync(PREFS_FILE).mtimeMs;
74
+ }
75
+ catch { /* ignore */ }
76
+ }
77
+ function getUserPref(username, key) {
78
+ const all = readAll();
79
+ return all[username]?.[key];
80
+ }
81
+ function setUserPref(username, key, value) {
82
+ const all = readAll();
83
+ const forUser = { ...(all[username] ?? {}) };
84
+ forUser[key] = value;
85
+ writeAll({ ...all, [username]: forUser });
86
+ }
87
+ //# sourceMappingURL=user-prefs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-prefs.js","sourceRoot":"","sources":["../src/user-prefs.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,kCAGC;AAED,kCAKC;AApDD,uCAAyB;AACzB,2CAA6B;AAC7B,qCAAqD;AAErD;;;;;;;;GAQG;AAEH,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAQ,EAAE,iBAAiB,CAAC,CAAC;AAI1D,IAAI,KAAK,GAAiB,IAAI,CAAC;AAC/B,IAAI,UAAU,GAAG,CAAC,CAAC;AAEnB,SAAS,OAAO;IACd,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC;QACvD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACjD,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAU,CAAC;QACjC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,GAAG,EAAE,CAAC;QACX,UAAU,GAAG,CAAC,CAAC;QACf,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAY;IAC5B,IAAA,wBAAe,EAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5D,KAAK,GAAG,KAAK,CAAC;IACd,IAAI,CAAC;QAAC,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;AAC9E,CAAC;AAED,SAAgB,WAAW,CAAc,QAAgB,EAAE,GAAW;IACpE,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,OAAO,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAkB,CAAC;AAC/C,CAAC;AAED,SAAgB,WAAW,CAAC,QAAgB,EAAE,GAAW,EAAE,KAAc;IACvE,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,MAAM,OAAO,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACrB,QAAQ,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;AAC5C,CAAC"}