shiva-code 0.1.0 → 0.2.1

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 +195 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command9 } from "commander";
4
+ import { Command as Command10 } from "commander";
5
5
 
6
6
  // src/commands/login.ts
7
7
  import { Command } from "commander";
@@ -656,27 +656,31 @@ import { Command as Command4 } from "commander";
656
656
  import { writeFileSync as writeFileSync2, existsSync as existsSync3 } from "fs";
657
657
  import { resolve as resolve3 } from "path";
658
658
  import ora2 from "ora";
659
- var syncCommand = new Command4("sync").description("Projekt mit Cloud synchronisieren").option("-d, --dir <directory>", "Projektverzeichnis", ".").option("--pull", "Nur von Cloud herunterladen").option("--push", "Nur zu Cloud hochladen").action(async (options) => {
659
+ var syncCommand = new Command4("sync").description("Projekt mit Cloud synchronisieren").option("-d, --dir <directory>", "Projektverzeichnis", ".").option("--pull", "Nur von Cloud herunterladen").option("--push", "Nur zu Cloud hochladen").option("-q, --quiet", "Keine Ausgabe (f\xFCr Hooks)").action(async (options) => {
660
+ const quiet = options.quiet;
660
661
  if (!isAuthenticated()) {
661
- log.error('Nicht angemeldet. Bitte zuerst "shiva login" ausf\xFChren.');
662
+ if (!quiet) log.error('Nicht angemeldet. Bitte zuerst "shiva login" ausf\xFChren.');
663
+ process.exit(1);
662
664
  return;
663
665
  }
664
666
  const projectDir = resolve3(options.dir);
665
667
  if (!existsSync3(projectDir)) {
666
- log.error(`Verzeichnis nicht gefunden: ${projectDir}`);
668
+ if (!quiet) log.error(`Verzeichnis nicht gefunden: ${projectDir}`);
669
+ process.exit(1);
667
670
  return;
668
671
  }
669
- const spinner = ora2("Synchronisiere...").start();
672
+ const spinner = quiet ? null : ora2("Synchronisiere...").start();
670
673
  let scanned;
671
674
  try {
672
675
  scanned = await scanProject(projectDir);
673
676
  } catch (error) {
674
- spinner.fail("Fehler beim Scannen");
677
+ spinner?.fail("Fehler beim Scannen");
678
+ process.exit(1);
675
679
  return;
676
680
  }
677
681
  let project = await api.findProjectByPath(scanned.path);
678
682
  if (!project) {
679
- spinner.text = "Erstelle Projekt...";
683
+ if (spinner) spinner.text = "Erstelle Projekt...";
680
684
  try {
681
685
  const result = await api.createOrUpdateProject({
682
686
  name: scanned.name,
@@ -691,8 +695,9 @@ var syncCommand = new Command4("sync").description("Projekt mit Cloud synchronis
691
695
  });
692
696
  project = await api.getProject(result.projectId);
693
697
  } catch (error) {
694
- spinner.fail("Fehler beim Erstellen");
695
- log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
698
+ spinner?.fail("Fehler beim Erstellen");
699
+ if (!quiet) log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
700
+ process.exit(1);
696
701
  return;
697
702
  }
698
703
  }
@@ -702,7 +707,7 @@ var syncCommand = new Command4("sync").description("Projekt mit Cloud synchronis
702
707
  memories = parsed.memories;
703
708
  }
704
709
  if (!options.pull) {
705
- spinner.text = "Hochladen...";
710
+ if (spinner) spinner.text = "Hochladen...";
706
711
  try {
707
712
  await api.syncProject(project.id, {
708
713
  claude_md_content: scanned.claudeMdContent,
@@ -714,31 +719,35 @@ var syncCommand = new Command4("sync").description("Projekt mit Cloud synchronis
714
719
  memories
715
720
  });
716
721
  } catch (error) {
717
- spinner.fail("Fehler beim Hochladen");
718
- log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
722
+ spinner?.fail("Fehler beim Hochladen");
723
+ if (!quiet) log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
724
+ process.exit(1);
719
725
  return;
720
726
  }
721
727
  }
722
728
  if (!options.push) {
723
- spinner.text = "Aktualisiere CLAUDE.md...";
729
+ if (spinner) spinner.text = "Aktualisiere CLAUDE.md...";
724
730
  try {
725
731
  project = await api.getProject(project.id);
726
732
  const newClaudeMd = generateClaudeMd(scanned, project);
727
733
  const claudeMdPath = resolve3(projectDir, "CLAUDE.md");
728
734
  writeFileSync2(claudeMdPath, newClaudeMd);
729
735
  } catch (error) {
730
- spinner.fail("Fehler beim Aktualisieren");
731
- log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
736
+ spinner?.fail("Fehler beim Aktualisieren");
737
+ if (!quiet) log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
738
+ process.exit(1);
732
739
  return;
733
740
  }
734
741
  }
735
- spinner.succeed("Synchronisiert");
736
- log.newline();
737
- log.tree.item("CLAUDE.md aktualisiert");
738
- log.tree.item(`${project.memories?.length || 0} Memories synchronisiert`);
739
- log.tree.item("Metadata aktualisiert", true);
740
- log.newline();
741
- log.success(`Sync erfolgreich (${(/* @__PURE__ */ new Date()).toLocaleTimeString()})`);
742
+ spinner?.succeed("Synchronisiert");
743
+ if (!quiet) {
744
+ log.newline();
745
+ log.tree.item("CLAUDE.md aktualisiert");
746
+ log.tree.item(`${project.memories?.length || 0} Memories synchronisiert`);
747
+ log.tree.item("Metadata aktualisiert", true);
748
+ log.newline();
749
+ log.success(`Sync erfolgreich (${(/* @__PURE__ */ new Date()).toLocaleTimeString()})`);
750
+ }
742
751
  });
743
752
 
744
753
  // src/commands/status.ts
@@ -1103,8 +1112,169 @@ configCommand.command("reset").description("Konfiguration zur\xFCcksetzen").acti
1103
1112
  log.success("Konfiguration zur\xFCckgesetzt");
1104
1113
  });
1105
1114
 
1115
+ // src/commands/hook.ts
1116
+ import { Command as Command9 } from "commander";
1117
+ import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync } from "fs";
1118
+ import { homedir } from "os";
1119
+ import { join } from "path";
1120
+ var CLAUDE_SETTINGS_PATH = join(homedir(), ".claude", "settings.json");
1121
+ function getClaudeSettings() {
1122
+ if (!existsSync6(CLAUDE_SETTINGS_PATH)) {
1123
+ return {};
1124
+ }
1125
+ try {
1126
+ const content = readFileSync3(CLAUDE_SETTINGS_PATH, "utf-8");
1127
+ return JSON.parse(content);
1128
+ } catch {
1129
+ return {};
1130
+ }
1131
+ }
1132
+ function saveClaudeSettings(settings) {
1133
+ const dir = join(homedir(), ".claude");
1134
+ if (!existsSync6(dir)) {
1135
+ mkdirSync(dir, { recursive: true });
1136
+ }
1137
+ writeFileSync3(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2));
1138
+ }
1139
+ function hasShivaHook(hooks, event) {
1140
+ if (!hooks || !hooks[event]) return false;
1141
+ const eventHooks = hooks[event];
1142
+ return eventHooks.some(
1143
+ (entry) => entry.hooks?.some((h) => h.command?.includes("shiva"))
1144
+ );
1145
+ }
1146
+ function removeShivaHooks(eventHooks) {
1147
+ return eventHooks.filter(
1148
+ (entry) => !entry.hooks?.some((h) => h.command?.includes("shiva"))
1149
+ );
1150
+ }
1151
+ var hookCommand = new Command9("hook").description("Claude Code Hook Integration verwalten");
1152
+ hookCommand.command("install").description("SHIVA Hooks in Claude Code installieren").action(() => {
1153
+ log.brand();
1154
+ const claudePath = join(homedir(), ".claude");
1155
+ if (!existsSync6(claudePath)) {
1156
+ log.error("Claude Code nicht gefunden");
1157
+ log.newline();
1158
+ log.info("Installiere Claude Code:");
1159
+ log.plain(" npm install -g @anthropic-ai/claude-code");
1160
+ log.newline();
1161
+ log.dim("Oder: https://claude.ai/code");
1162
+ return;
1163
+ }
1164
+ const settings = getClaudeSettings();
1165
+ if (!settings.hooks) {
1166
+ settings.hooks = {};
1167
+ }
1168
+ if (hasShivaHook(settings.hooks, "SessionStart") || hasShivaHook(settings.hooks, "Stop")) {
1169
+ log.warn("SHIVA Hooks sind bereits installiert");
1170
+ log.newline();
1171
+ log.info("Zum Neuinstallieren:");
1172
+ log.plain(" shiva hook uninstall");
1173
+ log.plain(" shiva hook install");
1174
+ return;
1175
+ }
1176
+ if (!settings.hooks.SessionStart) {
1177
+ settings.hooks.SessionStart = [];
1178
+ }
1179
+ settings.hooks.SessionStart.push({
1180
+ matcher: {},
1181
+ hooks: [
1182
+ {
1183
+ type: "command",
1184
+ command: "shiva sync --pull --quiet"
1185
+ }
1186
+ ]
1187
+ });
1188
+ if (!settings.hooks.Stop) {
1189
+ settings.hooks.Stop = [];
1190
+ }
1191
+ settings.hooks.Stop.push({
1192
+ matcher: {},
1193
+ hooks: [
1194
+ {
1195
+ type: "command",
1196
+ command: "shiva sync --push --quiet"
1197
+ }
1198
+ ]
1199
+ });
1200
+ saveClaudeSettings(settings);
1201
+ log.success("SHIVA Hooks installiert!");
1202
+ log.newline();
1203
+ log.header("Aktive Hooks");
1204
+ log.tree.item("SessionStart: Memories laden");
1205
+ log.tree.item("Stop: Memories speichern", true);
1206
+ log.newline();
1207
+ log.dim("Claude Code wird nun automatisch mit SHIVA synchronisiert.");
1208
+ log.newline();
1209
+ log.info("Starte Claude Code wie gewohnt:");
1210
+ log.plain(" claude");
1211
+ });
1212
+ hookCommand.command("uninstall").description("SHIVA Hooks aus Claude Code entfernen").action(() => {
1213
+ log.brand();
1214
+ const settings = getClaudeSettings();
1215
+ if (!settings.hooks) {
1216
+ log.info("Keine Hooks installiert");
1217
+ return;
1218
+ }
1219
+ let removed = false;
1220
+ if (settings.hooks.SessionStart) {
1221
+ const before = settings.hooks.SessionStart.length;
1222
+ settings.hooks.SessionStart = removeShivaHooks(settings.hooks.SessionStart);
1223
+ if (settings.hooks.SessionStart.length < before) removed = true;
1224
+ if (settings.hooks.SessionStart.length === 0) delete settings.hooks.SessionStart;
1225
+ }
1226
+ if (settings.hooks.Stop) {
1227
+ const before = settings.hooks.Stop.length;
1228
+ settings.hooks.Stop = removeShivaHooks(settings.hooks.Stop);
1229
+ if (settings.hooks.Stop.length < before) removed = true;
1230
+ if (settings.hooks.Stop.length === 0) delete settings.hooks.Stop;
1231
+ }
1232
+ if (Object.keys(settings.hooks).length === 0) {
1233
+ delete settings.hooks;
1234
+ }
1235
+ saveClaudeSettings(settings);
1236
+ if (removed) {
1237
+ log.success("SHIVA Hooks entfernt");
1238
+ } else {
1239
+ log.info("Keine SHIVA Hooks gefunden");
1240
+ }
1241
+ });
1242
+ hookCommand.command("status").description("Hook-Status anzeigen").action(() => {
1243
+ log.brand();
1244
+ log.header("Hook Status");
1245
+ log.newline();
1246
+ const settings = getClaudeSettings();
1247
+ if (!settings.hooks) {
1248
+ log.listItem("Keine Hooks installiert", "pending");
1249
+ log.newline();
1250
+ log.info("Installieren mit: shiva hook install");
1251
+ return;
1252
+ }
1253
+ const hasSessionStart = hasShivaHook(settings.hooks, "SessionStart");
1254
+ const hasStop = hasShivaHook(settings.hooks, "Stop");
1255
+ if (hasSessionStart) {
1256
+ log.listItem("SessionStart: Memories laden", "synced");
1257
+ } else {
1258
+ log.listItem("SessionStart: nicht aktiv", "pending");
1259
+ }
1260
+ if (hasStop) {
1261
+ log.listItem("Stop: Memories speichern", "synced");
1262
+ } else {
1263
+ log.listItem("Stop: nicht aktiv", "pending");
1264
+ }
1265
+ log.newline();
1266
+ if (hasSessionStart && hasStop) {
1267
+ log.success("SHIVA ist vollst\xE4ndig integriert");
1268
+ } else if (hasSessionStart || hasStop) {
1269
+ log.warn("SHIVA ist teilweise integriert");
1270
+ log.info("Neuinstallation empfohlen: shiva hook install");
1271
+ } else {
1272
+ log.info("Installieren mit: shiva hook install");
1273
+ }
1274
+ });
1275
+
1106
1276
  // src/index.ts
1107
- var program = new Command9();
1277
+ var program = new Command10();
1108
1278
  program.name("shiva").description("SHIVA Code - Makes Claude Code Persistent").version("0.1.0");
1109
1279
  program.addCommand(loginCommand);
1110
1280
  program.addCommand(logoutCommand);
@@ -1115,6 +1285,7 @@ program.addCommand(projectsCommand);
1115
1285
  program.addCommand(connectCommand);
1116
1286
  program.addCommand(disconnectCommand);
1117
1287
  program.addCommand(configCommand);
1288
+ program.addCommand(hookCommand);
1118
1289
  program.action(() => {
1119
1290
  log.brand();
1120
1291
  log.newline();
@@ -1129,6 +1300,7 @@ program.action(() => {
1129
1300
  log.plain(" shiva connect Projekte verbinden");
1130
1301
  log.plain(" shiva disconnect Verbindung trennen");
1131
1302
  log.plain(" shiva config Konfiguration verwalten");
1303
+ log.plain(" shiva hook Claude Code Integration");
1132
1304
  log.newline();
1133
1305
  log.dim("Hilfe: shiva <befehl> --help");
1134
1306
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shiva-code",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Makes Claude Code Persistent - Cross-Project Memory CLI",
5
5
  "author": "SHIVA AI",
6
6
  "license": "MIT",