ccsini 0.1.23 → 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 +126 -2
  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.23";
27999
+ var VERSION = "0.1.24";
28000
28000
 
28001
28001
  // src/commands/init.ts
28002
28002
  init_source();
@@ -28783,6 +28783,89 @@ async function hooksInstalled(claudeDir) {
28783
28783
  return false;
28784
28784
  }
28785
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
+ }
28786
28869
 
28787
28870
  // src/core/transport.ts
28788
28871
  class CcsiniClient {
@@ -29483,7 +29566,17 @@ function registerDoctorCommand(program2) {
29483
29566
  const config = await loadKeys(configDir);
29484
29567
  console.log(source_default.green(` \u2713 Device: ${config.deviceName} (${config.deviceId.slice(0, 8)}...)`));
29485
29568
  if (await hooksInstalled(claudeDir)) {
29486
- 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
+ }
29487
29580
  } else {
29488
29581
  console.log(source_default.yellow(" \u26A0 Hooks not installed (run 'ccsini init')"));
29489
29582
  allGood = false;
@@ -29556,6 +29649,12 @@ function registerSelfCommands(program2) {
29556
29649
  execSync(cmd, { stdio: "inherit" });
29557
29650
  console.log(`
29558
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 {}
29559
29658
  console.log("Restart your terminal to use the new version.");
29560
29659
  } catch {
29561
29660
  console.error(`
@@ -29822,6 +29921,30 @@ function registerSyncCommands(program2) {
29822
29921
  });
29823
29922
  }
29824
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
+
29825
29948
  // src/index.ts
29826
29949
  var program2 = new Command;
29827
29950
  program2.name("ccsini").description("Claude Code seamless sync across devices").version(VERSION);
@@ -29830,6 +29953,7 @@ registerAutoCommands(program2);
29830
29953
  registerDoctorCommand(program2);
29831
29954
  registerSelfCommands(program2);
29832
29955
  registerSyncCommands(program2);
29956
+ registerHooksCommands(program2);
29833
29957
  program2.command("version").description("Show current version").action(() => {
29834
29958
  console.log(VERSION);
29835
29959
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccsini",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "Claude Code seamless sync across devices",
5
5
  "type": "module",
6
6
  "bin": {