ccsini 0.1.45 → 0.1.47

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 (2) hide show
  1. package/dist/index.js +116 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28020,7 +28020,7 @@ var {
28020
28020
  } = import__.default;
28021
28021
 
28022
28022
  // src/version.ts
28023
- var VERSION = "0.1.45";
28023
+ var VERSION = "0.1.47";
28024
28024
 
28025
28025
  // src/commands/init.ts
28026
28026
  init_source();
@@ -29355,7 +29355,7 @@ function extractProjects(manifest) {
29355
29355
  lastSyncedAt: manifest.timestamp
29356
29356
  }));
29357
29357
  }
29358
- async function pushSync(client, masterKey, deviceName, configDir, onProgress, sessionOptions) {
29358
+ async function pushSync(client, masterKey, deviceName, configDir, onProgress, sessionOptions, pushOptions) {
29359
29359
  const start = Date.now();
29360
29360
  const claudeDir = getClaudeDir();
29361
29361
  const errors2 = [];
@@ -29380,7 +29380,7 @@ async function pushSync(client, masterKey, deviceName, configDir, onProgress, se
29380
29380
  const diffs = diffManifests(localManifest, remoteManifest);
29381
29381
  const toPush = diffs.filter((d) => d.action === "push" || d.action === "merge");
29382
29382
  progress(`${toPush.length} files to push`);
29383
- if (remoteManifest) {
29383
+ if (remoteManifest && !pushOptions?.skipConflictBackup) {
29384
29384
  const merges = toPush.filter((d) => d.action === "merge" && d.remoteHash);
29385
29385
  for (const diff of merges) {
29386
29386
  try {
@@ -29975,7 +29975,7 @@ function registerAutoCommands(program2) {
29975
29975
  maxPerProject: storedSession.maxPerProject,
29976
29976
  maxFileSize: SESSION_SYNC_DEFAULTS.maxFileSize
29977
29977
  };
29978
- const result = await pushSync(client, masterKey, config.deviceName, configDir, undefined, sessionOptions);
29978
+ const result = await pushSync(client, masterKey, config.deviceName, configDir, undefined, sessionOptions, { skipConflictBackup: true });
29979
29979
  if (result.filesChanged > 0) {
29980
29980
  console.log(`[ccsini] Pushed ${result.filesChanged} files (${result.durationMs}ms)`);
29981
29981
  }
@@ -30124,24 +30124,33 @@ function registerSelfCommands(program2) {
30124
30124
  console.log(`New version available: ${latest}`);
30125
30125
  console.log(`Updating...
30126
30126
  `);
30127
- const cmd = `bun add -g ccsini@${latest}`;
30127
+ let updated = false;
30128
30128
  try {
30129
- execSync2(cmd, { stdio: "inherit" });
30130
- console.log(`
30131
- Updated to v${latest}`);
30129
+ execSync2(`bun add -g ccsini@${latest}`, { stdio: "inherit" });
30130
+ updated = true;
30131
+ } catch {
30132
+ console.log(`Bun failed (registry cache), trying npm...
30133
+ `);
30132
30134
  try {
30133
- const { fixed } = await fixHooks(getClaudeDir());
30134
- if (fixed > 0) {
30135
- console.log(`Repaired ${fixed} hook issue${fixed > 1 ? "s" : ""} in Claude Code settings.`);
30136
- }
30135
+ execSync2(`npm install -g ccsini@${latest}`, { stdio: "inherit" });
30136
+ updated = true;
30137
30137
  } catch {}
30138
- console.log("Restart your terminal to use the new version.");
30139
- } catch {
30138
+ }
30139
+ if (!updated) {
30140
30140
  console.error(`
30141
30141
  Update failed. Try manually:`);
30142
- console.error(` ${cmd}`);
30142
+ console.error(` npm install -g ccsini@${latest}`);
30143
30143
  process.exit(1);
30144
30144
  }
30145
+ console.log(`
30146
+ Updated to v${latest}`);
30147
+ try {
30148
+ const { fixed } = await fixHooks(getClaudeDir());
30149
+ if (fixed > 0) {
30150
+ console.log(`Repaired ${fixed} hook issue${fixed > 1 ? "s" : ""} in Claude Code settings.`);
30151
+ }
30152
+ } catch {}
30153
+ console.log("Restart your terminal to use the new version.");
30145
30154
  });
30146
30155
  program2.command("uninstall").description("Uninstall ccsini from this machine").action(async () => {
30147
30156
  console.log(`Uninstalling ccsini...
@@ -30597,6 +30606,97 @@ function registerSessionsCommand(program2) {
30597
30606
  });
30598
30607
  }
30599
30608
 
30609
+ // src/commands/conflicts.ts
30610
+ import { readdir as readdir2, readFile as readFile9, unlink as unlink2, writeFile as writeFile9 } from "fs/promises";
30611
+ import { join as join12, relative as relative2 } from "path";
30612
+ async function findConflictFiles(dir, base) {
30613
+ base = base ?? dir;
30614
+ const results = [];
30615
+ const entries = await readdir2(dir, { withFileTypes: true });
30616
+ for (const entry of entries) {
30617
+ const full = join12(dir, entry.name);
30618
+ if (entry.isDirectory()) {
30619
+ results.push(...await findConflictFiles(full, base));
30620
+ } else if (entry.name.endsWith(".conflict")) {
30621
+ results.push(relative2(base, full).split("\\").join("/"));
30622
+ }
30623
+ }
30624
+ return results;
30625
+ }
30626
+ function registerConflictsCommand(program2) {
30627
+ program2.command("conflicts").description("List and resolve sync conflicts").option("--keep <side>", "Resolve all: 'local' keeps .conflict, 'remote' discards .conflict").action(async (opts) => {
30628
+ const chalk2 = (await Promise.resolve().then(() => (init_source(), exports_source))).default;
30629
+ const claudeDir = getClaudeDir();
30630
+ const conflictFiles = await findConflictFiles(claudeDir);
30631
+ if (conflictFiles.length === 0) {
30632
+ console.log(chalk2.green("No conflicts found."));
30633
+ return;
30634
+ }
30635
+ console.log(chalk2.bold(`
30636
+ ${conflictFiles.length} conflict(s) found:
30637
+ `));
30638
+ for (const file of conflictFiles) {
30639
+ const original = file.replace(/\.conflict$/, "");
30640
+ console.log(` ${chalk2.yellow("\u26A0")} ${original}`);
30641
+ console.log(chalk2.dim(` conflict: ~/.claude/${file}`));
30642
+ }
30643
+ console.log();
30644
+ if (opts.keep === "remote") {
30645
+ for (const file of conflictFiles) {
30646
+ await unlink2(join12(claudeDir, file));
30647
+ }
30648
+ console.log(chalk2.green(`Resolved ${conflictFiles.length} conflict(s) \u2014 kept remote versions.`));
30649
+ return;
30650
+ }
30651
+ if (opts.keep === "local") {
30652
+ for (const file of conflictFiles) {
30653
+ const conflictPath = join12(claudeDir, file);
30654
+ const originalPath = conflictPath.replace(/\.conflict$/, "");
30655
+ const conflictContent = await readFile9(conflictPath);
30656
+ await writeFile9(originalPath, conflictContent);
30657
+ await unlink2(conflictPath);
30658
+ }
30659
+ console.log(chalk2.green(`Resolved ${conflictFiles.length} conflict(s) \u2014 kept local versions.`));
30660
+ return;
30661
+ }
30662
+ const inquirer2 = await Promise.resolve().then(() => (init_dist16(), exports_dist));
30663
+ for (const file of conflictFiles) {
30664
+ const original = file.replace(/\.conflict$/, "");
30665
+ const conflictPath = join12(claudeDir, file);
30666
+ const originalPath = join12(claudeDir, original);
30667
+ const { action } = await inquirer2.default.prompt([
30668
+ {
30669
+ type: "list",
30670
+ name: "action",
30671
+ message: `${original}:`,
30672
+ choices: [
30673
+ { name: "Keep remote (current file)", value: "remote" },
30674
+ { name: "Keep local (restore from .conflict)", value: "local" },
30675
+ { name: "Skip", value: "skip" }
30676
+ ]
30677
+ }
30678
+ ]);
30679
+ if (action === "remote") {
30680
+ await unlink2(conflictPath);
30681
+ console.log(chalk2.dim(` Kept remote \u2014 deleted ${file}`));
30682
+ } else if (action === "local") {
30683
+ const conflictContent = await readFile9(conflictPath);
30684
+ await writeFile9(originalPath, conflictContent);
30685
+ await unlink2(conflictPath);
30686
+ console.log(chalk2.dim(` Restored local version`));
30687
+ }
30688
+ }
30689
+ const remaining = await findConflictFiles(claudeDir);
30690
+ if (remaining.length === 0) {
30691
+ console.log(chalk2.green(`
30692
+ All conflicts resolved.`));
30693
+ } else {
30694
+ console.log(chalk2.yellow(`
30695
+ ${remaining.length} conflict(s) remaining.`));
30696
+ }
30697
+ });
30698
+ }
30699
+
30600
30700
  // src/commands/menu.ts
30601
30701
  init_source();
30602
30702
  init_dist16();
@@ -30663,6 +30763,7 @@ registerSyncCommands(program2);
30663
30763
  registerHooksCommands(program2);
30664
30764
  registerResetCommand(program2);
30665
30765
  registerSessionsCommand(program2);
30766
+ registerConflictsCommand(program2);
30666
30767
  program2.command("version").description("Show current version").action(() => {
30667
30768
  console.log(VERSION);
30668
30769
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccsini",
3
- "version": "0.1.45",
3
+ "version": "0.1.47",
4
4
  "description": "Claude Code seamless sync across devices",
5
5
  "type": "module",
6
6
  "bin": {