ccsini 0.1.23 → 0.1.25
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/dist/index.js +155 -9
- 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.
|
|
27999
|
+
var VERSION = "0.1.25";
|
|
28000
28000
|
|
|
28001
28001
|
// src/commands/init.ts
|
|
28002
28002
|
init_source();
|
|
@@ -28737,7 +28737,13 @@ function buildDefaultSchema() {
|
|
|
28737
28737
|
// src/hooks/installer.ts
|
|
28738
28738
|
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
28739
28739
|
import { join as join3 } from "path";
|
|
28740
|
-
var HOOK_MARKER = "ccsini
|
|
28740
|
+
var HOOK_MARKER = "ccsini auto-";
|
|
28741
|
+
var OLD_HOOK_MARKER = "ccsini-auto-sync";
|
|
28742
|
+
var OLD_COMMAND_SUFFIX = /\s*#\s*ccsini-auto-sync$/;
|
|
28743
|
+
function isCcsiniHook(hookEntry) {
|
|
28744
|
+
const s = JSON.stringify(hookEntry);
|
|
28745
|
+
return s.includes(HOOK_MARKER) || s.includes(OLD_HOOK_MARKER);
|
|
28746
|
+
}
|
|
28741
28747
|
async function installHooks(claudeDir) {
|
|
28742
28748
|
const settingsPath = join3(claudeDir, "settings.json");
|
|
28743
28749
|
let settings = {};
|
|
@@ -28747,26 +28753,26 @@ async function installHooks(claudeDir) {
|
|
|
28747
28753
|
} catch {}
|
|
28748
28754
|
settings.hooks = settings.hooks ?? {};
|
|
28749
28755
|
settings.hooks.PreToolUse = [
|
|
28750
|
-
...(settings.hooks.PreToolUse ?? []).filter((h) => !h
|
|
28756
|
+
...(settings.hooks.PreToolUse ?? []).filter((h) => !isCcsiniHook(h))
|
|
28751
28757
|
];
|
|
28752
28758
|
settings.hooks.Stop = [
|
|
28753
|
-
...(settings.hooks.Stop ?? []).filter((h) => !
|
|
28759
|
+
...(settings.hooks.Stop ?? []).filter((h) => !isCcsiniHook(h)),
|
|
28754
28760
|
{
|
|
28755
28761
|
hooks: [
|
|
28756
28762
|
{
|
|
28757
28763
|
type: "command",
|
|
28758
|
-
command:
|
|
28764
|
+
command: "ccsini auto-push"
|
|
28759
28765
|
}
|
|
28760
28766
|
]
|
|
28761
28767
|
}
|
|
28762
28768
|
];
|
|
28763
28769
|
settings.hooks.Notification = [
|
|
28764
|
-
...(settings.hooks.Notification ?? []).filter((h) => !
|
|
28770
|
+
...(settings.hooks.Notification ?? []).filter((h) => !isCcsiniHook(h)),
|
|
28765
28771
|
{
|
|
28766
28772
|
hooks: [
|
|
28767
28773
|
{
|
|
28768
28774
|
type: "command",
|
|
28769
|
-
command:
|
|
28775
|
+
command: "ccsini auto-pull"
|
|
28770
28776
|
}
|
|
28771
28777
|
]
|
|
28772
28778
|
}
|
|
@@ -28778,11 +28784,110 @@ async function hooksInstalled(claudeDir) {
|
|
|
28778
28784
|
const raw = await readFile3(join3(claudeDir, "settings.json"), "utf-8");
|
|
28779
28785
|
const settings = JSON.parse(raw);
|
|
28780
28786
|
const allHooks = JSON.stringify(settings.hooks ?? {});
|
|
28781
|
-
return allHooks.includes(HOOK_MARKER);
|
|
28787
|
+
return allHooks.includes(HOOK_MARKER) || allHooks.includes(OLD_HOOK_MARKER);
|
|
28782
28788
|
} catch {
|
|
28783
28789
|
return false;
|
|
28784
28790
|
}
|
|
28785
28791
|
}
|
|
28792
|
+
async function fixHooks(claudeDir) {
|
|
28793
|
+
const settingsPath = join3(claudeDir, "settings.json");
|
|
28794
|
+
const details = [];
|
|
28795
|
+
let fixed = 0;
|
|
28796
|
+
let raw;
|
|
28797
|
+
try {
|
|
28798
|
+
raw = await readFile3(settingsPath, "utf-8");
|
|
28799
|
+
} catch {
|
|
28800
|
+
return { fixed, details: ["No settings.json found"] };
|
|
28801
|
+
}
|
|
28802
|
+
let settings;
|
|
28803
|
+
try {
|
|
28804
|
+
settings = JSON.parse(raw);
|
|
28805
|
+
} catch {
|
|
28806
|
+
return { fixed, details: ["settings.json is not valid JSON"] };
|
|
28807
|
+
}
|
|
28808
|
+
if (!settings.hooks)
|
|
28809
|
+
return { fixed, details };
|
|
28810
|
+
for (const hookType of Object.keys(settings.hooks)) {
|
|
28811
|
+
if (!Array.isArray(settings.hooks[hookType]))
|
|
28812
|
+
continue;
|
|
28813
|
+
for (const hookEntry of settings.hooks[hookType]) {
|
|
28814
|
+
if (!isCcsiniHook(hookEntry))
|
|
28815
|
+
continue;
|
|
28816
|
+
if ("matcher" in hookEntry && typeof hookEntry.matcher !== "string") {
|
|
28817
|
+
delete hookEntry.matcher;
|
|
28818
|
+
details.push(`Removed invalid matcher from ${hookType} hook`);
|
|
28819
|
+
fixed++;
|
|
28820
|
+
}
|
|
28821
|
+
if (typeof hookEntry.command === "string" && OLD_COMMAND_SUFFIX.test(hookEntry.command)) {
|
|
28822
|
+
hookEntry.command = hookEntry.command.replace(OLD_COMMAND_SUFFIX, "");
|
|
28823
|
+
details.push(`Stripped old marker suffix from ${hookType} command`);
|
|
28824
|
+
fixed++;
|
|
28825
|
+
}
|
|
28826
|
+
if (Array.isArray(hookEntry.hooks)) {
|
|
28827
|
+
for (const innerHook of hookEntry.hooks) {
|
|
28828
|
+
if ("matcher" in innerHook && typeof innerHook.matcher !== "string") {
|
|
28829
|
+
delete innerHook.matcher;
|
|
28830
|
+
details.push(`Removed invalid matcher from ${hookType} inner hook`);
|
|
28831
|
+
fixed++;
|
|
28832
|
+
}
|
|
28833
|
+
if (typeof innerHook.command === "string" && OLD_COMMAND_SUFFIX.test(innerHook.command)) {
|
|
28834
|
+
innerHook.command = innerHook.command.replace(OLD_COMMAND_SUFFIX, "");
|
|
28835
|
+
details.push(`Stripped old marker suffix from ${hookType} inner command`);
|
|
28836
|
+
fixed++;
|
|
28837
|
+
}
|
|
28838
|
+
}
|
|
28839
|
+
}
|
|
28840
|
+
}
|
|
28841
|
+
}
|
|
28842
|
+
if (fixed > 0) {
|
|
28843
|
+
await writeFile3(settingsPath, JSON.stringify(settings, null, 2));
|
|
28844
|
+
}
|
|
28845
|
+
return { fixed, details };
|
|
28846
|
+
}
|
|
28847
|
+
async function checkHooksHealth(claudeDir) {
|
|
28848
|
+
const settingsPath = join3(claudeDir, "settings.json");
|
|
28849
|
+
const issues = [];
|
|
28850
|
+
let raw;
|
|
28851
|
+
try {
|
|
28852
|
+
raw = await readFile3(settingsPath, "utf-8");
|
|
28853
|
+
} catch {
|
|
28854
|
+
return { healthy: true, issues };
|
|
28855
|
+
}
|
|
28856
|
+
let settings;
|
|
28857
|
+
try {
|
|
28858
|
+
settings = JSON.parse(raw);
|
|
28859
|
+
} catch {
|
|
28860
|
+
issues.push("settings.json is not valid JSON");
|
|
28861
|
+
return { healthy: false, issues };
|
|
28862
|
+
}
|
|
28863
|
+
if (!settings.hooks)
|
|
28864
|
+
return { healthy: true, issues };
|
|
28865
|
+
for (const hookType of Object.keys(settings.hooks)) {
|
|
28866
|
+
if (!Array.isArray(settings.hooks[hookType]))
|
|
28867
|
+
continue;
|
|
28868
|
+
for (const hookEntry of settings.hooks[hookType]) {
|
|
28869
|
+
if (!isCcsiniHook(hookEntry))
|
|
28870
|
+
continue;
|
|
28871
|
+
if ("matcher" in hookEntry && typeof hookEntry.matcher !== "string") {
|
|
28872
|
+
issues.push(`${hookType}: matcher is ${typeof hookEntry.matcher}, expected string`);
|
|
28873
|
+
}
|
|
28874
|
+
if (typeof hookEntry.command === "string" && OLD_COMMAND_SUFFIX.test(hookEntry.command)) {
|
|
28875
|
+
issues.push(`${hookType}: command has old marker suffix that causes argument errors`);
|
|
28876
|
+
}
|
|
28877
|
+
if (Array.isArray(hookEntry.hooks)) {
|
|
28878
|
+
for (const innerHook of hookEntry.hooks) {
|
|
28879
|
+
if ("matcher" in innerHook && typeof innerHook.matcher !== "string") {
|
|
28880
|
+
issues.push(`${hookType} inner hook: matcher is ${typeof innerHook.matcher}, expected string`);
|
|
28881
|
+
}
|
|
28882
|
+
if (typeof innerHook.command === "string" && OLD_COMMAND_SUFFIX.test(innerHook.command)) {
|
|
28883
|
+
issues.push(`${hookType} inner hook: command has old marker suffix that causes argument errors`);
|
|
28884
|
+
}
|
|
28885
|
+
}
|
|
28886
|
+
}
|
|
28887
|
+
}
|
|
28888
|
+
}
|
|
28889
|
+
return { healthy: issues.length === 0, issues };
|
|
28890
|
+
}
|
|
28786
28891
|
|
|
28787
28892
|
// src/core/transport.ts
|
|
28788
28893
|
class CcsiniClient {
|
|
@@ -29483,7 +29588,17 @@ function registerDoctorCommand(program2) {
|
|
|
29483
29588
|
const config = await loadKeys(configDir);
|
|
29484
29589
|
console.log(source_default.green(` \u2713 Device: ${config.deviceName} (${config.deviceId.slice(0, 8)}...)`));
|
|
29485
29590
|
if (await hooksInstalled(claudeDir)) {
|
|
29486
|
-
console.log(source_default.green(" \u2713 Hooks installed
|
|
29591
|
+
console.log(source_default.green(" \u2713 Hooks installed"));
|
|
29592
|
+
const { healthy, issues } = await checkHooksHealth(claudeDir);
|
|
29593
|
+
if (healthy) {
|
|
29594
|
+
console.log(source_default.green(" \u2713 Hooks format valid"));
|
|
29595
|
+
} else {
|
|
29596
|
+
for (const issue of issues) {
|
|
29597
|
+
console.log(source_default.red(` \u2717 ${issue}`));
|
|
29598
|
+
}
|
|
29599
|
+
console.log(source_default.yellow(" Run 'ccsini hooks fix' to repair"));
|
|
29600
|
+
allGood = false;
|
|
29601
|
+
}
|
|
29487
29602
|
} else {
|
|
29488
29603
|
console.log(source_default.yellow(" \u26A0 Hooks not installed (run 'ccsini init')"));
|
|
29489
29604
|
allGood = false;
|
|
@@ -29556,6 +29671,12 @@ function registerSelfCommands(program2) {
|
|
|
29556
29671
|
execSync(cmd, { stdio: "inherit" });
|
|
29557
29672
|
console.log(`
|
|
29558
29673
|
Updated to v${latest}`);
|
|
29674
|
+
try {
|
|
29675
|
+
const { fixed } = await fixHooks(getClaudeDir());
|
|
29676
|
+
if (fixed > 0) {
|
|
29677
|
+
console.log(`Repaired ${fixed} hook issue${fixed > 1 ? "s" : ""} in Claude Code settings.`);
|
|
29678
|
+
}
|
|
29679
|
+
} catch {}
|
|
29559
29680
|
console.log("Restart your terminal to use the new version.");
|
|
29560
29681
|
} catch {
|
|
29561
29682
|
console.error(`
|
|
@@ -29822,6 +29943,30 @@ function registerSyncCommands(program2) {
|
|
|
29822
29943
|
});
|
|
29823
29944
|
}
|
|
29824
29945
|
|
|
29946
|
+
// src/commands/hooks.ts
|
|
29947
|
+
init_source();
|
|
29948
|
+
function registerHooksCommands(program2) {
|
|
29949
|
+
const hooksCmd = program2.command("hooks").description("Manage Claude Code hooks");
|
|
29950
|
+
hooksCmd.command("fix").description("Repair broken hook entries in Claude Code settings").action(async () => {
|
|
29951
|
+
const claudeDir = getClaudeDir();
|
|
29952
|
+
console.log(source_default.bold(`
|
|
29953
|
+
Checking hooks...
|
|
29954
|
+
`));
|
|
29955
|
+
const { fixed, details } = await fixHooks(claudeDir);
|
|
29956
|
+
if (fixed === 0) {
|
|
29957
|
+
console.log(source_default.green(` Hooks are already healthy. Nothing to fix.
|
|
29958
|
+
`));
|
|
29959
|
+
return;
|
|
29960
|
+
}
|
|
29961
|
+
for (const detail of details) {
|
|
29962
|
+
console.log(source_default.yellow(` Fixed: ${detail}`));
|
|
29963
|
+
}
|
|
29964
|
+
console.log(source_default.green(`
|
|
29965
|
+
Repaired ${fixed} hook issue${fixed > 1 ? "s" : ""}.
|
|
29966
|
+
`));
|
|
29967
|
+
});
|
|
29968
|
+
}
|
|
29969
|
+
|
|
29825
29970
|
// src/index.ts
|
|
29826
29971
|
var program2 = new Command;
|
|
29827
29972
|
program2.name("ccsini").description("Claude Code seamless sync across devices").version(VERSION);
|
|
@@ -29830,6 +29975,7 @@ registerAutoCommands(program2);
|
|
|
29830
29975
|
registerDoctorCommand(program2);
|
|
29831
29976
|
registerSelfCommands(program2);
|
|
29832
29977
|
registerSyncCommands(program2);
|
|
29978
|
+
registerHooksCommands(program2);
|
|
29833
29979
|
program2.command("version").description("Show current version").action(() => {
|
|
29834
29980
|
console.log(VERSION);
|
|
29835
29981
|
});
|