ccsini 0.1.22 → 0.1.24

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 +140 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -27996,7 +27996,7 @@ var {
27996
27996
  } = import__.default;
27997
27997
 
27998
27998
  // src/version.ts
27999
- var VERSION = "0.1.22";
27999
+ var VERSION = "0.1.24";
28000
28000
 
28001
28001
  // src/commands/init.ts
28002
28002
  init_source();
@@ -28750,18 +28750,25 @@ async function installHooks(claudeDir) {
28750
28750
  ...(settings.hooks.PreToolUse ?? []).filter((h) => !h.command?.includes(HOOK_MARKER))
28751
28751
  ];
28752
28752
  settings.hooks.Stop = [
28753
- ...(settings.hooks.Stop ?? []).filter((h) => !h.command?.includes(HOOK_MARKER)),
28753
+ ...(settings.hooks.Stop ?? []).filter((h) => !JSON.stringify(h).includes(HOOK_MARKER)),
28754
28754
  {
28755
- type: "command",
28756
- command: `ccsini auto-push # ${HOOK_MARKER}`
28755
+ hooks: [
28756
+ {
28757
+ type: "command",
28758
+ command: `ccsini auto-push # ${HOOK_MARKER}`
28759
+ }
28760
+ ]
28757
28761
  }
28758
28762
  ];
28759
28763
  settings.hooks.Notification = [
28760
- ...(settings.hooks.Notification ?? []).filter((h) => !h.command?.includes(HOOK_MARKER)),
28764
+ ...(settings.hooks.Notification ?? []).filter((h) => !JSON.stringify(h).includes(HOOK_MARKER)),
28761
28765
  {
28762
- type: "command",
28763
- command: `ccsini auto-pull # ${HOOK_MARKER}`,
28764
- event: "session_start"
28766
+ hooks: [
28767
+ {
28768
+ type: "command",
28769
+ command: `ccsini auto-pull # ${HOOK_MARKER}`
28770
+ }
28771
+ ]
28765
28772
  }
28766
28773
  ];
28767
28774
  await writeFile3(settingsPath, JSON.stringify(settings, null, 2));
@@ -28776,6 +28783,89 @@ async function hooksInstalled(claudeDir) {
28776
28783
  return false;
28777
28784
  }
28778
28785
  }
28786
+ async function fixHooks(claudeDir) {
28787
+ const settingsPath = join3(claudeDir, "settings.json");
28788
+ const details = [];
28789
+ let fixed = 0;
28790
+ let raw;
28791
+ try {
28792
+ raw = await readFile3(settingsPath, "utf-8");
28793
+ } catch {
28794
+ return { fixed, details: ["No settings.json found"] };
28795
+ }
28796
+ let settings;
28797
+ try {
28798
+ settings = JSON.parse(raw);
28799
+ } catch {
28800
+ return { fixed, details: ["settings.json is not valid JSON"] };
28801
+ }
28802
+ if (!settings.hooks)
28803
+ return { fixed, details };
28804
+ for (const hookType of Object.keys(settings.hooks)) {
28805
+ if (!Array.isArray(settings.hooks[hookType]))
28806
+ continue;
28807
+ for (const hookEntry of settings.hooks[hookType]) {
28808
+ if (!JSON.stringify(hookEntry).includes(HOOK_MARKER))
28809
+ continue;
28810
+ if ("matcher" in hookEntry && typeof hookEntry.matcher !== "string") {
28811
+ delete hookEntry.matcher;
28812
+ details.push(`Removed invalid matcher from ${hookType} hook`);
28813
+ fixed++;
28814
+ }
28815
+ if (Array.isArray(hookEntry.hooks)) {
28816
+ for (const innerHook of hookEntry.hooks) {
28817
+ if ("matcher" in innerHook && typeof innerHook.matcher !== "string") {
28818
+ delete innerHook.matcher;
28819
+ details.push(`Removed invalid matcher from ${hookType} inner hook`);
28820
+ fixed++;
28821
+ }
28822
+ }
28823
+ }
28824
+ }
28825
+ }
28826
+ if (fixed > 0) {
28827
+ await writeFile3(settingsPath, JSON.stringify(settings, null, 2));
28828
+ }
28829
+ return { fixed, details };
28830
+ }
28831
+ async function checkHooksHealth(claudeDir) {
28832
+ const settingsPath = join3(claudeDir, "settings.json");
28833
+ const issues = [];
28834
+ let raw;
28835
+ try {
28836
+ raw = await readFile3(settingsPath, "utf-8");
28837
+ } catch {
28838
+ return { healthy: true, issues };
28839
+ }
28840
+ let settings;
28841
+ try {
28842
+ settings = JSON.parse(raw);
28843
+ } catch {
28844
+ issues.push("settings.json is not valid JSON");
28845
+ return { healthy: false, issues };
28846
+ }
28847
+ if (!settings.hooks)
28848
+ return { healthy: true, issues };
28849
+ for (const hookType of Object.keys(settings.hooks)) {
28850
+ if (!Array.isArray(settings.hooks[hookType]))
28851
+ continue;
28852
+ for (const hookEntry of settings.hooks[hookType]) {
28853
+ if (!JSON.stringify(hookEntry).includes(HOOK_MARKER))
28854
+ continue;
28855
+ if ("matcher" in hookEntry && typeof hookEntry.matcher !== "string") {
28856
+ issues.push(`${hookType}: matcher is ${typeof hookEntry.matcher}, expected string`);
28857
+ }
28858
+ if (Array.isArray(hookEntry.hooks)) {
28859
+ for (const innerHook of hookEntry.hooks) {
28860
+ if ("matcher" in innerHook && typeof innerHook.matcher !== "string") {
28861
+ issues.push(`${hookType} inner hook: matcher is ${typeof innerHook.matcher}, expected string`);
28862
+ }
28863
+ }
28864
+ }
28865
+ }
28866
+ }
28867
+ return { healthy: issues.length === 0, issues };
28868
+ }
28779
28869
 
28780
28870
  // src/core/transport.ts
28781
28871
  class CcsiniClient {
@@ -29476,7 +29566,17 @@ function registerDoctorCommand(program2) {
29476
29566
  const config = await loadKeys(configDir);
29477
29567
  console.log(source_default.green(` \u2713 Device: ${config.deviceName} (${config.deviceId.slice(0, 8)}...)`));
29478
29568
  if (await hooksInstalled(claudeDir)) {
29479
- console.log(source_default.green(" \u2713 Hooks installed correctly"));
29569
+ console.log(source_default.green(" \u2713 Hooks installed"));
29570
+ const { healthy, issues } = await checkHooksHealth(claudeDir);
29571
+ if (healthy) {
29572
+ console.log(source_default.green(" \u2713 Hooks format valid"));
29573
+ } else {
29574
+ for (const issue of issues) {
29575
+ console.log(source_default.red(` \u2717 ${issue}`));
29576
+ }
29577
+ console.log(source_default.yellow(" Run 'ccsini hooks fix' to repair"));
29578
+ allGood = false;
29579
+ }
29480
29580
  } else {
29481
29581
  console.log(source_default.yellow(" \u26A0 Hooks not installed (run 'ccsini init')"));
29482
29582
  allGood = false;
@@ -29549,6 +29649,12 @@ function registerSelfCommands(program2) {
29549
29649
  execSync(cmd, { stdio: "inherit" });
29550
29650
  console.log(`
29551
29651
  Updated to v${latest}`);
29652
+ try {
29653
+ const { fixed } = await fixHooks(getClaudeDir());
29654
+ if (fixed > 0) {
29655
+ console.log(`Repaired ${fixed} hook issue${fixed > 1 ? "s" : ""} in Claude Code settings.`);
29656
+ }
29657
+ } catch {}
29552
29658
  console.log("Restart your terminal to use the new version.");
29553
29659
  } catch {
29554
29660
  console.error(`
@@ -29815,6 +29921,30 @@ function registerSyncCommands(program2) {
29815
29921
  });
29816
29922
  }
29817
29923
 
29924
+ // src/commands/hooks.ts
29925
+ init_source();
29926
+ function registerHooksCommands(program2) {
29927
+ const hooksCmd = program2.command("hooks").description("Manage Claude Code hooks");
29928
+ hooksCmd.command("fix").description("Repair broken hook entries in Claude Code settings").action(async () => {
29929
+ const claudeDir = getClaudeDir();
29930
+ console.log(source_default.bold(`
29931
+ Checking hooks...
29932
+ `));
29933
+ const { fixed, details } = await fixHooks(claudeDir);
29934
+ if (fixed === 0) {
29935
+ console.log(source_default.green(` Hooks are already healthy. Nothing to fix.
29936
+ `));
29937
+ return;
29938
+ }
29939
+ for (const detail of details) {
29940
+ console.log(source_default.yellow(` Fixed: ${detail}`));
29941
+ }
29942
+ console.log(source_default.green(`
29943
+ Repaired ${fixed} hook issue${fixed > 1 ? "s" : ""}.
29944
+ `));
29945
+ });
29946
+ }
29947
+
29818
29948
  // src/index.ts
29819
29949
  var program2 = new Command;
29820
29950
  program2.name("ccsini").description("Claude Code seamless sync across devices").version(VERSION);
@@ -29823,6 +29953,7 @@ registerAutoCommands(program2);
29823
29953
  registerDoctorCommand(program2);
29824
29954
  registerSelfCommands(program2);
29825
29955
  registerSyncCommands(program2);
29956
+ registerHooksCommands(program2);
29826
29957
  program2.command("version").description("Show current version").action(() => {
29827
29958
  console.log(VERSION);
29828
29959
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccsini",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "description": "Claude Code seamless sync across devices",
5
5
  "type": "module",
6
6
  "bin": {