shiva-code 0.4.2 → 0.5.0

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.
@@ -21,8 +21,8 @@ import {
21
21
  parseGitHubUrl,
22
22
  runGh,
23
23
  runGhRaw
24
- } from "./chunk-ZDLLPNCK.js";
25
- import "./chunk-6RAACMKF.js";
24
+ } from "./chunk-IVFCZLBX.js";
25
+ import "./chunk-HIQO2DBA.js";
26
26
  import "./chunk-3RG5ZIWI.js";
27
27
  export {
28
28
  findMentionedIssueNumbers,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  findProject,
3
3
  getProjectName
4
- } from "./chunk-TI6Y3VT4.js";
4
+ } from "./chunk-IDM6KY2R.js";
5
5
 
6
6
  // src/services/data/package-manager.ts
7
7
  import Conf from "conf";
@@ -3,8 +3,8 @@ var CacheService = class _CacheService {
3
3
  cache;
4
4
  // Default TTLs in milliseconds
5
5
  static TTL = {
6
- SESSIONS: 30 * 1e3,
7
- // 30 seconds for sessions
6
+ SESSIONS: 5 * 60 * 1e3,
7
+ // 5 minutes for sessions (optimized for better cache hit rate)
8
8
  GITHUB_ISSUES: 5 * 60 * 1e3,
9
9
  // 5 minutes for GitHub issues
10
10
  GITHUB_PRS: 5 * 60 * 1e3,
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  cache
3
- } from "./chunk-6RAACMKF.js";
3
+ } from "./chunk-HIQO2DBA.js";
4
4
 
5
5
  // src/services/session/manager.ts
6
6
  import * as fs from "fs";
7
+ import * as fsPromises from "fs/promises";
7
8
  import * as path from "path";
8
9
  import * as os from "os";
9
10
  import * as readline from "readline";
@@ -31,26 +32,25 @@ async function getAllClaudeProjects(skipCache = false) {
31
32
  if (!fs.existsSync(projectsPath)) {
32
33
  return [];
33
34
  }
34
- const projects = [];
35
- const entries = fs.readdirSync(projectsPath, { withFileTypes: true });
36
- for (const entry of entries) {
37
- if (!entry.isDirectory()) continue;
35
+ const entries = await fsPromises.readdir(projectsPath, { withFileTypes: true });
36
+ const projectPromises = entries.filter((entry) => entry.isDirectory()).map(async (entry) => {
38
37
  const encodedPath = entry.name;
39
38
  const absolutePath = decodeProjectPath(encodedPath);
40
39
  const projectName = getProjectName(absolutePath);
41
- const sessionIndex = getSessionIndex(encodedPath);
40
+ const sessionIndex = await getSessionIndexAsync(encodedPath);
42
41
  const sessions = sessionIndex?.entries || [];
43
42
  sessions.sort(
44
43
  (a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime()
45
44
  );
46
- projects.push({
45
+ return {
47
46
  encodedPath,
48
47
  absolutePath,
49
48
  projectName,
50
49
  sessions,
51
50
  latestSession: sessions[0]
52
- });
53
- }
51
+ };
52
+ });
53
+ const projects = await Promise.all(projectPromises);
54
54
  projects.sort((a, b) => {
55
55
  const aTime = a.latestSession ? new Date(a.latestSession.modified).getTime() : 0;
56
56
  const bTime = b.latestSession ? new Date(b.latestSession.modified).getTime() : 0;
@@ -78,8 +78,31 @@ function getSessionIndex(encodedPath) {
78
78
  return null;
79
79
  }
80
80
  }
81
- async function findProject(nameOrPath) {
82
- const projects = await getAllClaudeProjects();
81
+ async function getSessionIndexAsync(encodedPath) {
82
+ const indexPath = path.join(
83
+ getClaudeProjectsPath(),
84
+ encodedPath,
85
+ "sessions-index.json"
86
+ );
87
+ try {
88
+ const content = await fsPromises.readFile(indexPath, "utf-8");
89
+ return JSON.parse(content);
90
+ } catch {
91
+ return null;
92
+ }
93
+ }
94
+ async function findProject(nameOrPath, useCache = true) {
95
+ const projects = await getAllClaudeProjects(!useCache);
96
+ const absolutePath = path.resolve(nameOrPath);
97
+ const byPath = projects.find((p) => p.absolutePath === absolutePath);
98
+ if (byPath) return byPath;
99
+ const lowerName = nameOrPath.toLowerCase();
100
+ const byName = projects.find(
101
+ (p) => p.projectName.toLowerCase() === lowerName || p.projectName.toLowerCase().includes(lowerName)
102
+ );
103
+ return byName || null;
104
+ }
105
+ function findProjectFromArray(projects, nameOrPath) {
83
106
  const absolutePath = path.resolve(nameOrPath);
84
107
  const byPath = projects.find((p) => p.absolutePath === absolutePath);
85
108
  if (byPath) return byPath;
@@ -103,6 +126,15 @@ async function findProjectForCurrentDir() {
103
126
  function getSessionFilePath(session) {
104
127
  return session.fullPath;
105
128
  }
129
+ function isSessionCorruptedQuick(session) {
130
+ const filePath = getSessionFilePath(session);
131
+ try {
132
+ const stats = fs.statSync(filePath);
133
+ return stats.size > 100 * 1024 * 1024;
134
+ } catch {
135
+ return true;
136
+ }
137
+ }
106
138
  function isSessionCorrupted(session) {
107
139
  const filePath = getSessionFilePath(session);
108
140
  if (!fs.existsSync(filePath)) {
@@ -288,10 +320,13 @@ export {
288
320
  getAllClaudeProjects,
289
321
  invalidateSessionsCache,
290
322
  getSessionIndex,
323
+ getSessionIndexAsync,
291
324
  findProject,
325
+ findProjectFromArray,
292
326
  findSessionByBranch,
293
327
  findProjectForCurrentDir,
294
328
  getSessionFilePath,
329
+ isSessionCorruptedQuick,
295
330
  isSessionCorrupted,
296
331
  isSessionActive,
297
332
  parseSessionFile,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  cache
3
- } from "./chunk-6RAACMKF.js";
3
+ } from "./chunk-HIQO2DBA.js";
4
4
 
5
5
  // src/services/github/api.ts
6
6
  import { execSync, spawnSync } from "child_process";
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ import {
39
39
  isGhAuthenticated,
40
40
  isGhInstalled,
41
41
  isGitRepo
42
- } from "./chunk-ZDLLPNCK.js";
42
+ } from "./chunk-IVFCZLBX.js";
43
43
  import {
44
44
  addProjectToPackage,
45
45
  createPackage,
@@ -49,11 +49,12 @@ import {
49
49
  getPackageLaunchConfig,
50
50
  getPackageStats,
51
51
  removeProjectFromPackage
52
- } from "./chunk-TQ6O4QB6.js";
52
+ } from "./chunk-5RCSFT5F.js";
53
53
  import {
54
54
  encodeProjectPath,
55
55
  findProject,
56
56
  findProjectForCurrentDir,
57
+ findProjectFromArray,
57
58
  findSessionByBranch,
58
59
  formatDate,
59
60
  formatRelativeTime,
@@ -65,18 +66,19 @@ import {
65
66
  invalidateSessionsCache,
66
67
  isSessionActive,
67
68
  isSessionCorrupted,
69
+ isSessionCorruptedQuick,
68
70
  saveRecoveredContext
69
- } from "./chunk-TI6Y3VT4.js";
71
+ } from "./chunk-IDM6KY2R.js";
70
72
  import {
71
73
  cache
72
- } from "./chunk-6RAACMKF.js";
74
+ } from "./chunk-HIQO2DBA.js";
73
75
  import {
74
76
  __require
75
77
  } from "./chunk-3RG5ZIWI.js";
76
78
 
77
79
  // src/index.ts
78
80
  import { Command as Command35 } from "commander";
79
- import inquirer14 from "inquirer";
81
+ import * as readline from "readline";
80
82
 
81
83
  // src/commands/auth/login.ts
82
84
  import { Command } from "commander";
@@ -6059,11 +6061,12 @@ var startCommand = new Command10("start").description("Projekte starten (mit Git
6059
6061
  return;
6060
6062
  }
6061
6063
  const spinner = ora6("Bereite Projekte vor...").start();
6064
+ const allProjects = await getAllClaudeProjects();
6062
6065
  const launches = [];
6063
6066
  for (const projektArg of projekte) {
6064
6067
  const absolutePath = path3.resolve(projektArg);
6065
6068
  if (fs.existsSync(absolutePath) && fs.statSync(absolutePath).isDirectory()) {
6066
- const project = await findProject(absolutePath);
6069
+ const project = findProjectFromArray(allProjects, absolutePath);
6067
6070
  const latestSession = project?.latestSession;
6068
6071
  launches.push({
6069
6072
  projectPath: absolutePath,
@@ -6072,7 +6075,7 @@ var startCommand = new Command10("start").description("Projekte starten (mit Git
6072
6075
  newSession: options.new || !latestSession
6073
6076
  });
6074
6077
  } else {
6075
- const project = await findProject(projektArg);
6078
+ const project = findProjectFromArray(allProjects, projektArg);
6076
6079
  if (project) {
6077
6080
  if (!fs.existsSync(project.absolutePath)) {
6078
6081
  spinner.warn(`Projektpfad existiert nicht: ${project.absolutePath}`);
@@ -6964,106 +6967,124 @@ function sessionHasAnyTag(sessionId, tags) {
6964
6967
  return sessionTags.some((t) => normalizedTags.includes(t));
6965
6968
  }
6966
6969
 
6970
+ // src/utils/command-wrapper.ts
6971
+ function withCommandErrorHandling(commandName, fn) {
6972
+ return async (...args) => {
6973
+ try {
6974
+ await fn(...args);
6975
+ } catch (error) {
6976
+ const shivaError = fromError(error);
6977
+ logErrorWithSuggestion(shivaError, commandName);
6978
+ process.exit(1);
6979
+ }
6980
+ };
6981
+ }
6982
+ function logErrorWithSuggestion(error, commandName) {
6983
+ if (commandName) {
6984
+ log.error(`[${commandName}] ${error.message}`);
6985
+ } else {
6986
+ log.error(error.message);
6987
+ }
6988
+ if (error.suggestion) {
6989
+ log.info(`\u2192 ${error.suggestion}`);
6990
+ }
6991
+ }
6992
+
6967
6993
  // src/commands/session/sessions.ts
6968
- var sessionsCommand = new Command13("sessions").description("Alle Claude Code Sessions auflisten").option("-a, --all", "Auch leere Projekte zeigen").option("-p, --project <pfad>", "Nur ein bestimmtes Projekt").option("-t, --tag <tag>", "Nach Tag filtern (Komma-getrennt f\xFCr mehrere)").option("-r, --refresh", "Cache invalidieren und neu laden").option("--json", "JSON Output").action(async (options) => {
6994
+ var sessionsCommand = new Command13("sessions").description("Alle Claude Code Sessions auflisten").option("-a, --all", "Auch leere Projekte zeigen").option("-p, --project <pfad>", "Nur ein bestimmtes Projekt").option("-t, --tag <tag>", "Nach Tag filtern (Komma-getrennt f\xFCr mehrere)").option("-r, --refresh", "Cache invalidieren und neu laden").option("--json", "JSON Output").action(withCommandErrorHandling("sessions", async (options) => {
6969
6995
  if (options.refresh) {
6970
6996
  invalidateSessionsCache();
6971
6997
  }
6972
6998
  const spinner = ora9("Lade Sessions...").start();
6973
- try {
6974
- let projects = await getAllClaudeProjects(options.refresh);
6975
- if (options.project) {
6976
- const found = await findProject(options.project);
6977
- if (found) {
6978
- projects = [found];
6979
- } else {
6980
- spinner.fail(`Projekt nicht gefunden: ${options.project}`);
6981
- return;
6982
- }
6983
- }
6984
- if (options.tag) {
6985
- const filterTags = options.tag.split(",").map((t) => t.trim());
6986
- projects = projects.map((project) => ({
6987
- ...project,
6988
- sessions: project.sessions.filter(
6989
- (session) => sessionHasAnyTag(session.sessionId, filterTags)
6990
- )
6991
- })).filter((p) => p.sessions.length > 0);
6992
- }
6993
- if (!options.all) {
6994
- projects = projects.filter((p) => p.sessions.length > 0);
6995
- }
6996
- spinner.stop();
6997
- if (options.json) {
6998
- console.log(JSON.stringify(projects, null, 2));
6999
+ let projects = await getAllClaudeProjects(options.refresh);
7000
+ if (options.project) {
7001
+ const found = await findProject(options.project);
7002
+ if (found) {
7003
+ projects = [found];
7004
+ } else {
7005
+ spinner.fail(`Projekt nicht gefunden: ${options.project}`);
6999
7006
  return;
7000
7007
  }
7008
+ }
7009
+ if (options.tag) {
7010
+ const filterTags = options.tag.split(",").map((t) => t.trim());
7011
+ projects = projects.map((project) => ({
7012
+ ...project,
7013
+ sessions: project.sessions.filter(
7014
+ (session) => sessionHasAnyTag(session.sessionId, filterTags)
7015
+ )
7016
+ })).filter((p) => p.sessions.length > 0);
7017
+ }
7018
+ if (!options.all) {
7019
+ projects = projects.filter((p) => p.sessions.length > 0);
7020
+ }
7021
+ spinner.stop();
7022
+ if (options.json) {
7023
+ console.log(JSON.stringify(projects, null, 2));
7024
+ return;
7025
+ }
7026
+ log.newline();
7027
+ console.log(colors.orange.bold("SHIVA Code - Sessions"));
7028
+ console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
7029
+ log.newline();
7030
+ if (projects.length === 0) {
7031
+ log.dim("Keine Sessions gefunden.");
7001
7032
  log.newline();
7002
- console.log(colors.orange.bold("SHIVA Code - Sessions"));
7003
- console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
7004
- log.newline();
7005
- if (projects.length === 0) {
7006
- log.dim("Keine Sessions gefunden.");
7007
- log.newline();
7008
- log.info("Claude Code Sessions werden automatisch erkannt.");
7009
- return;
7033
+ log.info("Claude Code Sessions werden automatisch erkannt.");
7034
+ return;
7035
+ }
7036
+ for (const project of projects) {
7037
+ const projectExists = await checkProjectExists(project.absolutePath);
7038
+ const projectIcon = projectExists ? "" : colors.yellow(" \u26A0");
7039
+ console.log(colors.bold(`Projekt: ${project.projectName}`) + projectIcon);
7040
+ if (!projectExists) {
7041
+ console.log(colors.dim(` Pfad existiert nicht mehr: ${project.absolutePath}`));
7010
7042
  }
7011
- for (const project of projects) {
7012
- const projectExists = await checkProjectExists(project.absolutePath);
7013
- const projectIcon = projectExists ? "" : colors.yellow(" \u26A0");
7014
- console.log(colors.bold(`Projekt: ${project.projectName}`) + projectIcon);
7015
- if (!projectExists) {
7016
- console.log(colors.dim(` Pfad existiert nicht mehr: ${project.absolutePath}`));
7017
- }
7018
- if (project.sessions.length === 0) {
7019
- log.dim(" Keine Sessions");
7020
- log.newline();
7021
- continue;
7022
- }
7023
- const displaySessions = project.sessions.slice(0, 5);
7024
- for (let i = 0; i < displaySessions.length; i++) {
7025
- const session = displaySessions[i];
7026
- const num = String(i + 1).padStart(2, " ");
7027
- let statusIcon = "";
7028
- if (isSessionActive(session)) {
7029
- statusIcon = colors.green(" [aktiv]");
7030
- } else if (isSessionCorrupted(session)) {
7031
- statusIcon = colors.red(" [corrupted]");
7032
- }
7033
- const branch = session.gitBranch || "main";
7034
- const msgs = `${session.messageCount} msgs`.padEnd(10);
7035
- const time = formatRelativeTime(session.modified);
7036
- let prompt = session.firstPrompt || "";
7037
- if (prompt.length > 40) {
7038
- prompt = prompt.substring(0, 37) + "...";
7039
- }
7040
- prompt = `"${prompt}"`;
7041
- const tags = getSessionTags(session.sessionId);
7042
- const tagsDisplay = tags.length > 0 ? " " + tags.map((t) => colors.magenta(`[${t}]`)).join(" ") : "";
7043
- const line = [
7044
- colors.dim(`${num}.`),
7045
- branch.padEnd(15),
7046
- colors.dim(`(${msgs})`),
7047
- formatDate(session.modified).padEnd(14),
7048
- colors.cyan(prompt),
7049
- statusIcon,
7050
- tagsDisplay
7051
- ].join(" ");
7052
- console.log(` ${line}`);
7053
- }
7054
- if (project.sessions.length > 5) {
7055
- log.dim(` ... und ${project.sessions.length - 5} weitere Sessions`);
7056
- }
7043
+ if (project.sessions.length === 0) {
7044
+ log.dim(" Keine Sessions");
7057
7045
  log.newline();
7046
+ continue;
7058
7047
  }
7059
- const stats = await getSessionStats();
7060
- log.dim(`Total: ${stats.activeProjects} Projekte, ${stats.totalSessions} Sessions`);
7061
- log.newline();
7062
- } catch (error) {
7063
- spinner.fail("Fehler beim Laden der Sessions");
7064
- log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
7065
- }
7066
- });
7048
+ const displaySessions = project.sessions.slice(0, 5);
7049
+ for (let i = 0; i < displaySessions.length; i++) {
7050
+ const session = displaySessions[i];
7051
+ const num = String(i + 1).padStart(2, " ");
7052
+ let statusIcon = "";
7053
+ if (isSessionActive(session)) {
7054
+ statusIcon = colors.green(" [aktiv]");
7055
+ } else if (isSessionCorruptedQuick(session)) {
7056
+ statusIcon = colors.red(" [corrupted]");
7057
+ }
7058
+ const branch = session.gitBranch || "main";
7059
+ const msgs = `${session.messageCount} msgs`.padEnd(10);
7060
+ const time = formatRelativeTime(session.modified);
7061
+ let prompt = session.firstPrompt || "";
7062
+ if (prompt.length > 40) {
7063
+ prompt = prompt.substring(0, 37) + "...";
7064
+ }
7065
+ prompt = `"${prompt}"`;
7066
+ const tags = getSessionTags(session.sessionId);
7067
+ const tagsDisplay = tags.length > 0 ? " " + tags.map((t) => colors.magenta(`[${t}]`)).join(" ") : "";
7068
+ const line = [
7069
+ colors.dim(`${num}.`),
7070
+ branch.padEnd(15),
7071
+ colors.dim(`(${msgs})`),
7072
+ formatDate(session.modified).padEnd(14),
7073
+ colors.cyan(prompt),
7074
+ statusIcon,
7075
+ tagsDisplay
7076
+ ].join(" ");
7077
+ console.log(` ${line}`);
7078
+ }
7079
+ if (project.sessions.length > 5) {
7080
+ log.dim(` ... und ${project.sessions.length - 5} weitere Sessions`);
7081
+ }
7082
+ log.newline();
7083
+ }
7084
+ const stats = await getSessionStats();
7085
+ log.dim(`Total: ${stats.activeProjects} Projekte, ${stats.totalSessions} Sessions`);
7086
+ log.newline();
7087
+ }));
7067
7088
  async function checkProjectExists(path15) {
7068
7089
  try {
7069
7090
  const fs15 = await import("fs");
@@ -8024,13 +8045,13 @@ githubCommand.command("map").description("Aktuellen Branch mit einer Session ver
8024
8045
  initShivaDir(cwd);
8025
8046
  }
8026
8047
  if (!sessionId) {
8027
- const { findProject: findProject2 } = await import("./manager-TQIASXKY.js");
8028
- const project = await findProject2(cwd);
8048
+ const { findProject: findProject3 } = await import("./manager-LXNF7QWT.js");
8049
+ const project = await findProject3(cwd);
8029
8050
  if (!project || project.sessions.length === 0) {
8030
8051
  log.error("Keine Sessions f\xFCr dieses Projekt gefunden");
8031
8052
  return;
8032
8053
  }
8033
- const { formatDate: formatDate2 } = await import("./manager-TQIASXKY.js");
8054
+ const { formatDate: formatDate2 } = await import("./manager-LXNF7QWT.js");
8034
8055
  const choices = project.sessions.slice(0, 10).map((s) => {
8035
8056
  const time = formatDate2(s.modified);
8036
8057
  const msgs = `${s.messageCount} msgs`;
@@ -8120,234 +8141,220 @@ githubCommand.command("mappings").description("Alle Branch-Session Mappings anze
8120
8141
  // src/commands/github/issues.ts
8121
8142
  import { Command as Command16 } from "commander";
8122
8143
  import ora11 from "ora";
8123
- var issuesCommand = new Command16("issues").description("GitHub Issues \xFCber alle Projekte anzeigen").option("-m, --mine", "Nur mir zugewiesene Issues").option("-p, --project <name>", "Nur Issues eines Projekts").option("-a, --all", "Auch geschlossene Issues").option("-l, --limit <n>", "Maximale Anzahl pro Projekt", "10").option("--json", "JSON Output").action(async (options) => {
8144
+ var issuesCommand = new Command16("issues").description("GitHub Issues \xFCber alle Projekte anzeigen").option("-m, --mine", "Nur mir zugewiesene Issues").option("-p, --project <name>", "Nur Issues eines Projekts").option("-a, --all", "Auch geschlossene Issues").option("-l, --limit <n>", "Maximale Anzahl pro Projekt", "10").option("--json", "JSON Output").action(withCommandErrorHandling("issues", async (options) => {
8124
8145
  if (!isGhInstalled()) {
8125
- log.error("gh CLI nicht installiert");
8126
- log.info("Installiere: https://cli.github.com/");
8127
- return;
8146
+ throw Errors.GITHUB_NOT_INSTALLED();
8128
8147
  }
8129
8148
  if (!isGhAuthenticated()) {
8130
- log.error("Nicht mit GitHub angemeldet");
8131
- log.info("Anmelden mit: shiva github login");
8132
- return;
8149
+ throw Errors.GITHUB_NOT_AUTHENTICATED();
8133
8150
  }
8134
8151
  const currentUser = getGhUser();
8135
8152
  const spinner = ora11("Lade Issues...").start();
8136
- try {
8137
- const allProjects = await getAllClaudeProjects();
8138
- let projects = allProjects;
8139
- if (options.project) {
8140
- const found = await findProject(options.project);
8141
- if (found) {
8142
- projects = [found];
8143
- } else {
8144
- spinner.fail(`Projekt nicht gefunden: ${options.project}`);
8145
- return;
8146
- }
8147
- }
8148
- const projectsWithIssues = [];
8149
- const limit = parseInt(options.limit, 10) || 10;
8150
- for (const project of projects) {
8151
- const repo = getRepoInfo(project.absolutePath);
8152
- if (!repo) continue;
8153
- const issueOptions = { limit };
8154
- if (options.mine && currentUser) {
8155
- issueOptions.assignee = currentUser;
8156
- }
8157
- const issues = getOpenIssues(repo.fullName, issueOptions);
8158
- if (issues.length > 0 || options.all) {
8159
- const assignedCount = currentUser ? issues.filter((i) => i.assignees.includes(currentUser)).length : 0;
8160
- projectsWithIssues.push({
8161
- project,
8162
- repo: repo.fullName,
8163
- issues,
8164
- assignedCount
8165
- });
8166
- }
8167
- }
8168
- spinner.stop();
8169
- if (options.json) {
8170
- const output = projectsWithIssues.map((p) => ({
8171
- project: p.project.projectName,
8172
- repo: p.repo,
8173
- issues: p.issues
8174
- }));
8175
- console.log(JSON.stringify(output, null, 2));
8153
+ const allProjects = await getAllClaudeProjects();
8154
+ let projects = allProjects;
8155
+ if (options.project) {
8156
+ const found = await findProject(options.project);
8157
+ if (found) {
8158
+ projects = [found];
8159
+ } else {
8160
+ spinner.fail(`Projekt nicht gefunden: ${options.project}`);
8176
8161
  return;
8177
8162
  }
8178
- log.newline();
8179
- console.log(colors.orange.bold("SHIVA Code - GitHub Issues"));
8180
- console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8181
- log.newline();
8182
- if (projectsWithIssues.length === 0) {
8183
- log.dim("Keine Issues gefunden.");
8184
- if (!options.mine) {
8185
- log.info("Versuche: shiva issues --mine");
8186
- }
8187
- return;
8163
+ }
8164
+ const projectsWithIssues = [];
8165
+ const limit = parseInt(options.limit, 10) || 10;
8166
+ for (const project of projects) {
8167
+ const repo = getRepoInfo(project.absolutePath);
8168
+ if (!repo) continue;
8169
+ const issueOptions = { limit };
8170
+ if (options.mine && currentUser) {
8171
+ issueOptions.assignee = currentUser;
8172
+ }
8173
+ const issues = getOpenIssues(repo.fullName, issueOptions);
8174
+ if (issues.length > 0 || options.all) {
8175
+ const assignedCount = currentUser ? issues.filter((i) => i.assignees.includes(currentUser)).length : 0;
8176
+ projectsWithIssues.push({
8177
+ project,
8178
+ repo: repo.fullName,
8179
+ issues,
8180
+ assignedCount
8181
+ });
8182
+ }
8183
+ }
8184
+ spinner.stop();
8185
+ if (options.json) {
8186
+ const output = projectsWithIssues.map((p) => ({
8187
+ project: p.project.projectName,
8188
+ repo: p.repo,
8189
+ issues: p.issues
8190
+ }));
8191
+ console.log(JSON.stringify(output, null, 2));
8192
+ return;
8193
+ }
8194
+ log.newline();
8195
+ console.log(colors.orange.bold("SHIVA Code - GitHub Issues"));
8196
+ console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8197
+ log.newline();
8198
+ if (projectsWithIssues.length === 0) {
8199
+ log.dim("Keine Issues gefunden.");
8200
+ if (!options.mine) {
8201
+ log.info("Versuche: shiva issues --mine");
8188
8202
  }
8189
- let totalIssues = 0;
8190
- let totalAssigned = 0;
8191
- for (const { project, repo, issues, assignedCount } of projectsWithIssues) {
8192
- totalIssues += issues.length;
8193
- totalAssigned += assignedCount;
8194
- const assignedText = assignedCount > 0 ? colors.green(`, ${assignedCount} assigned`) : "";
8203
+ return;
8204
+ }
8205
+ let totalIssues = 0;
8206
+ let totalAssigned = 0;
8207
+ for (const { project, repo, issues, assignedCount } of projectsWithIssues) {
8208
+ totalIssues += issues.length;
8209
+ totalAssigned += assignedCount;
8210
+ const assignedText = assignedCount > 0 ? colors.green(`, ${assignedCount} assigned`) : "";
8211
+ console.log(
8212
+ colors.bold(`\u{1F4E6} ${project.projectName}`) + colors.dim(` (${issues.length} open${assignedText})`)
8213
+ );
8214
+ for (const issue of issues) {
8215
+ const isAssigned = currentUser && issue.assignees.includes(currentUser);
8216
+ const assigneeText = isAssigned ? colors.green(" [you]") : issue.assignees.length > 0 ? colors.dim(` [@${issue.assignees[0]}]`) : "";
8217
+ let icon = "\u{1F7E1}";
8218
+ if (issue.labels.some((l) => l.toLowerCase().includes("bug"))) {
8219
+ icon = "\u{1F534}";
8220
+ } else if (issue.labels.some((l) => l.toLowerCase().includes("doc"))) {
8221
+ icon = "\u{1F7E2}";
8222
+ } else if (issue.labels.some((l) => l.toLowerCase().includes("feature"))) {
8223
+ icon = "\u{1F7E1}";
8224
+ }
8225
+ const labelsText = issue.labels.length > 0 ? colors.dim(` [${issue.labels.slice(0, 3).join(", ")}]`) : "";
8195
8226
  console.log(
8196
- colors.bold(`\u{1F4E6} ${project.projectName}`) + colors.dim(` (${issues.length} open${assignedText})`)
8227
+ ` ${icon} #${issue.number} ${issue.title.substring(0, 50)}${issue.title.length > 50 ? "..." : ""}${assigneeText}${labelsText}`
8197
8228
  );
8198
- for (const issue of issues) {
8199
- const isAssigned = currentUser && issue.assignees.includes(currentUser);
8200
- const assigneeText = isAssigned ? colors.green(" [you]") : issue.assignees.length > 0 ? colors.dim(` [@${issue.assignees[0]}]`) : "";
8201
- let icon = "\u{1F7E1}";
8202
- if (issue.labels.some((l) => l.toLowerCase().includes("bug"))) {
8203
- icon = "\u{1F534}";
8204
- } else if (issue.labels.some((l) => l.toLowerCase().includes("doc"))) {
8205
- icon = "\u{1F7E2}";
8206
- } else if (issue.labels.some((l) => l.toLowerCase().includes("feature"))) {
8207
- icon = "\u{1F7E1}";
8208
- }
8209
- const labelsText = issue.labels.length > 0 ? colors.dim(` [${issue.labels.slice(0, 3).join(", ")}]`) : "";
8210
- console.log(
8211
- ` ${icon} #${issue.number} ${issue.title.substring(0, 50)}${issue.title.length > 50 ? "..." : ""}${assigneeText}${labelsText}`
8212
- );
8213
- }
8214
- log.newline();
8215
8229
  }
8216
- const summaryText = options.mine ? `Total: ${totalIssues} Issues (dir zugewiesen)` : `Total: ${totalIssues} Issues offen (${totalAssigned} dir zugewiesen)`;
8217
- log.dim(summaryText);
8218
8230
  log.newline();
8219
- log.dim("Session f\xFCr Issue starten: shiva start --issue <nummer>");
8220
- } catch (error) {
8221
- spinner.fail("Fehler beim Laden der Issues");
8222
- log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
8223
8231
  }
8224
- });
8232
+ const summaryText = options.mine ? `Total: ${totalIssues} Issues (dir zugewiesen)` : `Total: ${totalIssues} Issues offen (${totalAssigned} dir zugewiesen)`;
8233
+ log.dim(summaryText);
8234
+ log.newline();
8235
+ log.dim("Session f\xFCr Issue starten: shiva start --issue <nummer>");
8236
+ }));
8225
8237
 
8226
8238
  // src/commands/github/prs.ts
8227
8239
  import { Command as Command17 } from "commander";
8228
8240
  import ora12 from "ora";
8229
- var prsCommand = new Command17("prs").description("GitHub Pull Requests \xFCber alle Projekte anzeigen").option("-m, --mine", "Nur meine PRs").option("-r, --review", "PRs wo ich Reviewer bin").option("-p, --project <name>", "Nur PRs eines Projekts").option("-l, --limit <n>", "Maximale Anzahl pro Projekt", "10").option("--json", "JSON Output").action(async (options) => {
8241
+ var prsCommand = new Command17("prs").description("GitHub Pull Requests \xFCber alle Projekte anzeigen").option("-m, --mine", "Nur meine PRs").option("-r, --review", "PRs wo ich Reviewer bin").option("-p, --project <name>", "Nur PRs eines Projekts").option("-l, --limit <n>", "Maximale Anzahl pro Projekt", "10").option("--json", "JSON Output").action(withCommandErrorHandling("prs", async (options) => {
8230
8242
  if (!isGhInstalled()) {
8231
- log.error("gh CLI nicht installiert");
8232
- log.info("Installiere: https://cli.github.com/");
8233
- return;
8243
+ throw Errors.GITHUB_NOT_INSTALLED();
8234
8244
  }
8235
8245
  if (!isGhAuthenticated()) {
8236
- log.error("Nicht mit GitHub angemeldet");
8237
- log.info("Anmelden mit: shiva github login");
8238
- return;
8246
+ throw Errors.GITHUB_NOT_AUTHENTICATED();
8239
8247
  }
8240
8248
  const currentUser = getGhUser();
8241
8249
  const spinner = ora12("Lade Pull Requests...").start();
8242
- try {
8243
- const allProjects = await getAllClaudeProjects();
8244
- let projects = allProjects;
8245
- if (options.project) {
8246
- const found = await findProject(options.project);
8247
- if (found) {
8248
- projects = [found];
8249
- } else {
8250
- spinner.fail(`Projekt nicht gefunden: ${options.project}`);
8251
- return;
8252
- }
8253
- }
8254
- const projectsWithPRs = [];
8255
- const limit = parseInt(options.limit, 10) || 10;
8256
- for (const project of projects) {
8257
- const repo = getRepoInfo(project.absolutePath);
8258
- if (!repo) continue;
8259
- const prOptions = { limit };
8260
- if (options.mine && currentUser) {
8261
- prOptions.author = currentUser;
8262
- }
8263
- let prs = getOpenPRs(repo.fullName, prOptions);
8264
- if (options.review && currentUser) {
8265
- prs = prs.filter((pr) => pr.author !== currentUser);
8266
- }
8267
- if (prs.length > 0) {
8268
- const myPRsCount = currentUser ? prs.filter((pr) => pr.author === currentUser).length : 0;
8269
- projectsWithPRs.push({
8270
- project,
8271
- repo: repo.fullName,
8272
- prs,
8273
- myPRsCount
8274
- });
8275
- }
8276
- }
8277
- spinner.stop();
8278
- if (options.json) {
8279
- const output = projectsWithPRs.map((p) => ({
8280
- project: p.project.projectName,
8281
- repo: p.repo,
8282
- prs: p.prs
8283
- }));
8284
- console.log(JSON.stringify(output, null, 2));
8250
+ const allProjects = await getAllClaudeProjects();
8251
+ let projects = allProjects;
8252
+ if (options.project) {
8253
+ const found = await findProject(options.project);
8254
+ if (found) {
8255
+ projects = [found];
8256
+ } else {
8257
+ spinner.fail(`Projekt nicht gefunden: ${options.project}`);
8285
8258
  return;
8286
8259
  }
8287
- log.newline();
8288
- console.log(colors.orange.bold("SHIVA Code - Pull Requests"));
8289
- console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8290
- log.newline();
8291
- if (projectsWithPRs.length === 0) {
8292
- log.dim("Keine Pull Requests gefunden.");
8293
- if (!options.mine) {
8294
- log.info("Versuche: shiva prs --mine");
8295
- }
8296
- return;
8260
+ }
8261
+ const limit = parseInt(options.limit, 10) || 10;
8262
+ const projectsWithRepos = projects.map((project) => ({
8263
+ project,
8264
+ repo: getRepoInfo(project.absolutePath)
8265
+ })).filter((p) => p.repo !== null);
8266
+ const prPromises = projectsWithRepos.map(async ({ project, repo }) => {
8267
+ const prOptions = { limit };
8268
+ if (options.mine && currentUser) {
8269
+ prOptions.author = currentUser;
8270
+ }
8271
+ let prs = getOpenPRs(repo.fullName, prOptions);
8272
+ if (options.review && currentUser) {
8273
+ prs = prs.filter((pr) => pr.author !== currentUser);
8274
+ }
8275
+ if (prs.length > 0) {
8276
+ const myPRsCount = currentUser ? prs.filter((pr) => pr.author === currentUser).length : 0;
8277
+ return {
8278
+ project,
8279
+ repo: repo.fullName,
8280
+ prs,
8281
+ myPRsCount
8282
+ };
8297
8283
  }
8298
- let totalPRs = 0;
8299
- let totalMyPRs = 0;
8300
- for (const { project, repo, prs, myPRsCount } of projectsWithPRs) {
8301
- totalPRs += prs.length;
8302
- totalMyPRs += myPRsCount;
8284
+ return null;
8285
+ });
8286
+ const results = await Promise.all(prPromises);
8287
+ const projectsWithPRs = results.filter((p) => p !== null);
8288
+ spinner.stop();
8289
+ if (options.json) {
8290
+ const output = projectsWithPRs.map((p) => ({
8291
+ project: p.project.projectName,
8292
+ repo: p.repo,
8293
+ prs: p.prs
8294
+ }));
8295
+ console.log(JSON.stringify(output, null, 2));
8296
+ return;
8297
+ }
8298
+ log.newline();
8299
+ console.log(colors.orange.bold("SHIVA Code - Pull Requests"));
8300
+ console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8301
+ log.newline();
8302
+ if (projectsWithPRs.length === 0) {
8303
+ log.dim("Keine Pull Requests gefunden.");
8304
+ if (!options.mine) {
8305
+ log.info("Versuche: shiva prs --mine");
8306
+ }
8307
+ return;
8308
+ }
8309
+ let totalPRs = 0;
8310
+ let totalMyPRs = 0;
8311
+ for (const { project, repo, prs, myPRsCount } of projectsWithPRs) {
8312
+ totalPRs += prs.length;
8313
+ totalMyPRs += myPRsCount;
8314
+ console.log(
8315
+ colors.bold(`\u{1F4E6} ${project.projectName}`) + colors.dim(` (${prs.length} open)`)
8316
+ );
8317
+ for (const pr of prs) {
8318
+ const isMine = currentUser && pr.author === currentUser;
8319
+ let statusIcon = "\u{1F7E1}";
8320
+ if (pr.checksStatus === "success" && pr.reviewDecision === "approved") {
8321
+ statusIcon = "\u{1F7E2}";
8322
+ } else if (pr.checksStatus === "failure") {
8323
+ statusIcon = "\u{1F534}";
8324
+ }
8325
+ const ciIcons = {
8326
+ success: colors.green("\u2713"),
8327
+ failure: colors.red("\u2717"),
8328
+ pending: colors.yellow("\u23F3")
8329
+ };
8330
+ const ciText = pr.checksStatus ? ciIcons[pr.checksStatus] || "\u25CB" : "\u25CB";
8331
+ const reviewIcons = {
8332
+ approved: colors.green("\u2713 Approved"),
8333
+ changes_requested: colors.red("\u274C Changes"),
8334
+ review_required: colors.yellow("\u{1F440} Review pending")
8335
+ };
8336
+ const reviewText = pr.reviewDecision ? reviewIcons[pr.reviewDecision] : "";
8337
+ const authorText = isMine ? colors.green("@you") : colors.dim(`@${pr.author}`);
8338
+ const draftText = pr.isDraft ? colors.dim(" [draft]") : "";
8339
+ const title = pr.title.length > 35 ? pr.title.substring(0, 32) + "..." : pr.title;
8340
+ const branchInfo = colors.dim(`${pr.headBranch} \u2192 ${pr.baseBranch}`);
8303
8341
  console.log(
8304
- colors.bold(`\u{1F4E6} ${project.projectName}`) + colors.dim(` (${prs.length} open)`)
8342
+ ` ${statusIcon} #${pr.number} ${title}${draftText}`
8343
+ );
8344
+ console.log(
8345
+ ` ${branchInfo}`
8346
+ );
8347
+ console.log(
8348
+ ` ${ciText} CI ${reviewText} ${authorText}`
8305
8349
  );
8306
- for (const pr of prs) {
8307
- const isMine = currentUser && pr.author === currentUser;
8308
- let statusIcon = "\u{1F7E1}";
8309
- if (pr.checksStatus === "success" && pr.reviewDecision === "approved") {
8310
- statusIcon = "\u{1F7E2}";
8311
- } else if (pr.checksStatus === "failure") {
8312
- statusIcon = "\u{1F534}";
8313
- }
8314
- const ciIcons = {
8315
- success: colors.green("\u2713"),
8316
- failure: colors.red("\u2717"),
8317
- pending: colors.yellow("\u23F3")
8318
- };
8319
- const ciText = pr.checksStatus ? ciIcons[pr.checksStatus] || "\u25CB" : "\u25CB";
8320
- const reviewIcons = {
8321
- approved: colors.green("\u2713 Approved"),
8322
- changes_requested: colors.red("\u274C Changes"),
8323
- review_required: colors.yellow("\u{1F440} Review pending")
8324
- };
8325
- const reviewText = pr.reviewDecision ? reviewIcons[pr.reviewDecision] : "";
8326
- const authorText = isMine ? colors.green("@you") : colors.dim(`@${pr.author}`);
8327
- const draftText = pr.isDraft ? colors.dim(" [draft]") : "";
8328
- const title = pr.title.length > 35 ? pr.title.substring(0, 32) + "..." : pr.title;
8329
- const branchInfo = colors.dim(`${pr.headBranch} \u2192 ${pr.baseBranch}`);
8330
- console.log(
8331
- ` ${statusIcon} #${pr.number} ${title}${draftText}`
8332
- );
8333
- console.log(
8334
- ` ${branchInfo}`
8335
- );
8336
- console.log(
8337
- ` ${ciText} CI ${reviewText} ${authorText}`
8338
- );
8339
- }
8340
- log.newline();
8341
8350
  }
8342
- const summaryText = options.mine ? `Total: ${totalPRs} PRs (deine)` : `Total: ${totalPRs} PRs offen (${totalMyPRs} deine)`;
8343
- log.dim(summaryText);
8344
8351
  log.newline();
8345
- log.dim("PR Session starten: shiva start --pr <nummer>");
8346
- } catch (error) {
8347
- spinner.fail("Fehler beim Laden der PRs");
8348
- log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
8349
8352
  }
8350
- });
8353
+ const summaryText = options.mine ? `Total: ${totalPRs} PRs (deine)` : `Total: ${totalPRs} PRs offen (${totalMyPRs} deine)`;
8354
+ log.dim(summaryText);
8355
+ log.newline();
8356
+ log.dim("PR Session starten: shiva start --pr <nummer>");
8357
+ }));
8351
8358
 
8352
8359
  // src/commands/security/scan.ts
8353
8360
  import { Command as Command18 } from "commander";
@@ -14378,9 +14385,9 @@ hookCommand.command("branch-switch").description("Branch-Wechsel behandeln (f\xF
14378
14385
  if (options.quiet) {
14379
14386
  return;
14380
14387
  }
14381
- const { getCurrentBranch: getCurrentBranch2 } = await import("./api-MT23KCO3.js");
14388
+ const { getCurrentBranch: getCurrentBranch2 } = await import("./api-OEHQTBH7.js");
14382
14389
  const { getSessionForBranch: getSessionForBranch2, hasShivaDir: hasShivaDir2 } = await import("./config-D6M6LI6U.js");
14383
- const { findProject: findProject2, findSessionByBranch: findSessionByBranch2, formatRelativeTime: formatRelativeTime3 } = await import("./manager-TQIASXKY.js");
14390
+ const { findProject: findProject3, findSessionByBranch: findSessionByBranch2, formatRelativeTime: formatRelativeTime3 } = await import("./manager-LXNF7QWT.js");
14384
14391
  const projectPath = process.cwd();
14385
14392
  const newBranch = getCurrentBranch2(projectPath);
14386
14393
  let sessionInfo = null;
@@ -14394,7 +14401,7 @@ hookCommand.command("branch-switch").description("Branch-Wechsel behandeln (f\xF
14394
14401
  }
14395
14402
  }
14396
14403
  if (!sessionInfo) {
14397
- const project = await findProject2(projectPath);
14404
+ const project = await findProject3(projectPath);
14398
14405
  if (project) {
14399
14406
  const indexSession = findSessionByBranch2(project, newBranch);
14400
14407
  if (indexSession) {
@@ -14632,9 +14639,14 @@ function listPackages() {
14632
14639
 
14633
14640
  // src/index.ts
14634
14641
  var program = new Command35();
14635
- program.name("shiva").description("SHIVA Code - Control Station for Claude Code").version("0.4.2");
14642
+ program.name("shiva").description("SHIVA Code - Control Station for Claude Code").version("0.5.0");
14636
14643
  program.addCommand(loginCommand);
14637
14644
  program.addCommand(logoutCommand);
14645
+ program.addCommand(sessionsCommand);
14646
+ program.addCommand(resumeCommand);
14647
+ program.addCommand(restoreCommand);
14648
+ program.addCommand(startCommand);
14649
+ program.addCommand(sessionCommand);
14638
14650
  program.addCommand(initCommand);
14639
14651
  program.addCommand(syncCommand);
14640
14652
  program.addCommand(statusCommand);
@@ -14642,37 +14654,114 @@ program.addCommand(projectsCommand);
14642
14654
  program.addCommand(connectCommand);
14643
14655
  program.addCommand(disconnectCommand);
14644
14656
  program.addCommand(configCommand);
14645
- program.addCommand(hookCommand);
14646
- program.addCommand(sessionsCommand);
14647
- program.addCommand(resumeCommand);
14648
- program.addCommand(restoreCommand);
14649
- program.addCommand(startCommand);
14650
- program.addCommand(packageCommand);
14657
+ program.addCommand(projectCommand);
14651
14658
  program.addCommand(githubCommand);
14652
14659
  program.addCommand(issuesCommand);
14653
14660
  program.addCommand(prsCommand);
14654
14661
  program.addCommand(secretsCommand);
14655
- program.addCommand(statsCommand);
14656
- program.addCommand(workflowCommand);
14657
- program.addCommand(completionsCommand);
14658
- program.addCommand(tagsCommand);
14659
- program.addCommand(exportCommand);
14660
- program.addCommand(importCommand);
14662
+ program.addCommand(scanCommand);
14663
+ program.addCommand(securityCommand);
14661
14664
  program.addCommand(searchCommand);
14662
14665
  program.addCommand(forgetCommand);
14663
14666
  program.addCommand(contextCommand);
14664
- program.addCommand(dockerCommand);
14665
- program.addCommand(projectCommand);
14666
- program.addCommand(securityCommand);
14667
- program.addCommand(scanCommand);
14668
- program.addCommand(sessionCommand);
14667
+ program.addCommand(tagsCommand);
14668
+ program.addCommand(exportCommand);
14669
+ program.addCommand(importCommand);
14670
+ program.addCommand(statsCommand);
14669
14671
  program.addCommand(doctorCommand);
14670
14672
  program.addCommand(upgradeCommand);
14671
14673
  program.addCommand(selfUpdateCommand);
14672
14674
  program.addCommand(telemetryCommand);
14675
+ program.addCommand(completionsCommand);
14676
+ program.addCommand(dockerCommand);
14677
+ program.addCommand(workflowCommand);
14678
+ program.addCommand(hookCommand);
14679
+ program.addCommand(packageCommand);
14673
14680
  program.action(async () => {
14674
14681
  await showDashboard();
14675
14682
  });
14683
+ async function interactiveMenu(choices, shortcuts) {
14684
+ const write = (str) => process.stdout.write(str);
14685
+ const totalLines = 1 + choices.length + 1;
14686
+ return new Promise((resolve13) => {
14687
+ let selectedIndex = 0;
14688
+ let resolved = false;
14689
+ let firstRender = true;
14690
+ const renderMenu = () => {
14691
+ if (!firstRender) {
14692
+ write(`\x1B[${totalLines}A`);
14693
+ }
14694
+ firstRender = false;
14695
+ write("\x1B[?25l");
14696
+ write(`\x1B[K${colors.green("?")} ${colors.bold("Auswahl:")}
14697
+ `);
14698
+ for (let i = 0; i < choices.length; i++) {
14699
+ const isSelected = i === selectedIndex;
14700
+ const prefix = isSelected ? colors.cyan("\u276F ") : " ";
14701
+ const name = isSelected ? colors.cyan(choices[i].name) : choices[i].name;
14702
+ write(`\x1B[K${prefix}${name}
14703
+ `);
14704
+ }
14705
+ write(`\x1B[K${colors.dim("\u2191\u2193 navigate \u2022 \u21B5 select")}
14706
+ `);
14707
+ write("\x1B[?25h");
14708
+ };
14709
+ renderMenu();
14710
+ if (process.stdin.isTTY) {
14711
+ readline.emitKeypressEvents(process.stdin);
14712
+ process.stdin.setRawMode(true);
14713
+ }
14714
+ process.stdin.resume();
14715
+ const cleanup = () => {
14716
+ process.stdin.removeListener("keypress", handler);
14717
+ if (process.stdin.isTTY) {
14718
+ process.stdin.setRawMode(false);
14719
+ }
14720
+ write("\x1B[?25h");
14721
+ };
14722
+ const showSelection = (label) => {
14723
+ write(`\x1B[${totalLines}A`);
14724
+ write("\x1B[J");
14725
+ console.log(`${colors.green("?")} ${colors.bold("Auswahl:")} ${colors.cyan(label)}`);
14726
+ };
14727
+ const handler = (_str, key) => {
14728
+ if (resolved) return;
14729
+ const keyName = key?.name?.toLowerCase() || "";
14730
+ const keyChar = key?.sequence?.toLowerCase() || "";
14731
+ if (key?.ctrl && keyName === "c") {
14732
+ cleanup();
14733
+ console.log("");
14734
+ process.exit(0);
14735
+ }
14736
+ const shortcutType = shortcuts[keyChar] || shortcuts[keyName];
14737
+ if (shortcutType) {
14738
+ resolved = true;
14739
+ cleanup();
14740
+ showSelection(shortcutType);
14741
+ resolve13({ type: shortcutType });
14742
+ return;
14743
+ }
14744
+ if (keyName === "up") {
14745
+ selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : choices.length - 1;
14746
+ renderMenu();
14747
+ } else if (keyName === "down") {
14748
+ selectedIndex = selectedIndex < choices.length - 1 ? selectedIndex + 1 : 0;
14749
+ renderMenu();
14750
+ } else if (keyName === "return") {
14751
+ resolved = true;
14752
+ cleanup();
14753
+ showSelection(choices[selectedIndex].name);
14754
+ resolve13(choices[selectedIndex].value);
14755
+ } else if (keyName === "escape") {
14756
+ resolved = true;
14757
+ cleanup();
14758
+ showSelection("Beenden");
14759
+ resolve13({ type: "quit" });
14760
+ }
14761
+ };
14762
+ process.stdin.on("keypress", handler);
14763
+ });
14764
+ }
14676
14765
  async function showDashboard() {
14677
14766
  console.clear();
14678
14767
  log.newline();
@@ -14727,20 +14816,23 @@ async function showDashboard() {
14727
14816
  value: { type: "separator" }
14728
14817
  });
14729
14818
  choices.push(
14730
- { name: " [S] Alle Sessions anzeigen", value: { type: "sessions" } },
14731
- { name: " [P] Packages verwalten", value: { type: "packages" } },
14732
- { name: " [G] GitHub Issues", value: { type: "issues" } },
14733
- { name: " [R] Pull Requests", value: { type: "prs" } },
14734
- { name: " [C] Config", value: { type: "config" } },
14735
- { name: " [Q] Beenden", value: { type: "quit" } }
14819
+ { name: colors.green("[S]") + " Alle Sessions anzeigen", value: { type: "sessions" } },
14820
+ { name: colors.green("[P]") + " Packages verwalten", value: { type: "packages" } },
14821
+ { name: colors.green("[G]") + " GitHub Issues", value: { type: "issues" } },
14822
+ { name: colors.green("[R]") + " Pull Requests", value: { type: "prs" } },
14823
+ { name: colors.green("[C]") + " Config", value: { type: "config" } },
14824
+ { name: colors.green("[Q]") + " Beenden", value: { type: "quit" } }
14736
14825
  );
14737
- const { selected } = await inquirer14.prompt([{
14738
- type: "list",
14739
- name: "selected",
14740
- message: "Auswahl:",
14741
- choices: choices.filter((c) => c.value.type !== "separator"),
14742
- pageSize: 15
14743
- }]);
14826
+ const shortcuts = {
14827
+ "s": "sessions",
14828
+ "p": "packages",
14829
+ "g": "issues",
14830
+ "r": "prs",
14831
+ "c": "config",
14832
+ "q": "quit"
14833
+ };
14834
+ const menuChoices = choices.filter((c) => c.value.type !== "separator");
14835
+ const selected = await interactiveMenu(menuChoices, shortcuts);
14744
14836
  switch (selected.type) {
14745
14837
  case "resume": {
14746
14838
  const project = selected.data;
@@ -14760,7 +14852,7 @@ async function showDashboard() {
14760
14852
  const packageName = selected.data;
14761
14853
  log.newline();
14762
14854
  log.success(`Starte Package ${packageName}...`);
14763
- const { getPackageLaunchConfig: getPackageLaunchConfig2 } = await import("./package-manager-NARG55B5.js");
14855
+ const { getPackageLaunchConfig: getPackageLaunchConfig2 } = await import("./package-manager-WF3UW2J4.js");
14764
14856
  const launches = await getPackageLaunchConfig2(packageName);
14765
14857
  if (launches.length > 0) {
14766
14858
  await spawnProjects(launches, detectTerminal());
@@ -14796,7 +14888,7 @@ async function showDashboard() {
14796
14888
  function showHelpMenu() {
14797
14889
  log.plain("Verf\xFCgbare Befehle:");
14798
14890
  log.newline();
14799
- console.log(colors.dim(" Control Station:"));
14891
+ console.log(colors.dim(" Session-Verwaltung:"));
14800
14892
  log.plain(" shiva sessions Alle Claude Sessions auflisten");
14801
14893
  log.plain(" shiva resume Session fortsetzen");
14802
14894
  log.plain(" shiva restore Crashed Session wiederherstellen");
@@ -14808,27 +14900,33 @@ function showHelpMenu() {
14808
14900
  log.plain(" shiva issues GitHub Issues anzeigen");
14809
14901
  log.plain(" shiva prs Pull Requests anzeigen");
14810
14902
  log.newline();
14903
+ console.log(colors.dim(" Memory & Context:"));
14904
+ log.plain(" shiva search In Memories suchen");
14905
+ log.plain(" shiva context Context anzeigen");
14906
+ log.plain(" shiva tags Session-Tags verwalten");
14907
+ log.plain(" shiva export Sessions exportieren");
14908
+ log.plain(" shiva import Sessions importieren");
14909
+ log.newline();
14811
14910
  console.log(colors.dim(" Docker Integration:"));
14812
14911
  log.plain(" shiva docker Docker-Modus verwalten");
14813
14912
  log.plain(" shiva start -d In Docker starten");
14814
14913
  log.newline();
14815
- console.log(colors.dim(" Security (Phase 16-17):"));
14914
+ console.log(colors.dim(" Security:"));
14816
14915
  log.plain(" shiva scan Package auf Sicherheit pr\xFCfen");
14916
+ log.plain(" shiva secrets Secrets verwalten");
14817
14917
  log.plain(" shiva start -s In Sandbox starten");
14818
- log.plain(" shiva session Sandbox-Session verwalten");
14819
14918
  log.newline();
14820
- console.log(colors.dim(" Cloud Sync:"));
14821
- log.plain(" shiva login Anmelden");
14919
+ console.log(colors.dim(" Projekt-Verwaltung:"));
14822
14920
  log.plain(" shiva init Projekt initialisieren");
14823
14921
  log.plain(" shiva sync Mit Cloud synchronisieren");
14824
14922
  log.plain(" shiva status Status anzeigen");
14825
14923
  log.plain(" shiva projects Alle Projekte auflisten");
14826
- log.plain(" shiva config sync Settings synchronisieren");
14924
+ log.plain(" shiva config Settings verwalten");
14827
14925
  log.newline();
14828
- console.log(colors.dim(" Utilities:"));
14926
+ console.log(colors.dim(" System:"));
14829
14927
  log.plain(" shiva doctor System-Check");
14830
14928
  log.plain(" shiva upgrade SHIVA aktualisieren");
14831
- log.plain(" shiva telemetry Analytics opt-in/out");
14929
+ log.plain(" shiva stats Analytics anzeigen");
14832
14930
  log.newline();
14833
14931
  log.dim("Hilfe: shiva <befehl> --help");
14834
14932
  }
@@ -3,6 +3,7 @@ import {
3
3
  encodeProjectPath,
4
4
  findProject,
5
5
  findProjectForCurrentDir,
6
+ findProjectFromArray,
6
7
  findSessionByBranch,
7
8
  formatDate,
8
9
  formatRecoveredContextAsMarkdown,
@@ -13,20 +14,23 @@ import {
13
14
  getRecoveredContext,
14
15
  getSessionFilePath,
15
16
  getSessionIndex,
17
+ getSessionIndexAsync,
16
18
  getSessionStats,
17
19
  invalidateSessionsCache,
18
20
  isSessionActive,
19
21
  isSessionCorrupted,
22
+ isSessionCorruptedQuick,
20
23
  parseSessionFile,
21
24
  saveRecoveredContext
22
- } from "./chunk-TI6Y3VT4.js";
23
- import "./chunk-6RAACMKF.js";
25
+ } from "./chunk-IDM6KY2R.js";
26
+ import "./chunk-HIQO2DBA.js";
24
27
  import "./chunk-3RG5ZIWI.js";
25
28
  export {
26
29
  decodeProjectPath,
27
30
  encodeProjectPath,
28
31
  findProject,
29
32
  findProjectForCurrentDir,
33
+ findProjectFromArray,
30
34
  findSessionByBranch,
31
35
  formatDate,
32
36
  formatRecoveredContextAsMarkdown,
@@ -37,10 +41,12 @@ export {
37
41
  getRecoveredContext,
38
42
  getSessionFilePath,
39
43
  getSessionIndex,
44
+ getSessionIndexAsync,
40
45
  getSessionStats,
41
46
  invalidateSessionsCache,
42
47
  isSessionActive,
43
48
  isSessionCorrupted,
49
+ isSessionCorruptedQuick,
44
50
  parseSessionFile,
45
51
  saveRecoveredContext
46
52
  };
@@ -9,9 +9,9 @@ import {
9
9
  getPackageStats,
10
10
  removeProjectFromPackage,
11
11
  updatePackage
12
- } from "./chunk-TQ6O4QB6.js";
13
- import "./chunk-TI6Y3VT4.js";
14
- import "./chunk-6RAACMKF.js";
12
+ } from "./chunk-5RCSFT5F.js";
13
+ import "./chunk-IDM6KY2R.js";
14
+ import "./chunk-HIQO2DBA.js";
15
15
  import "./chunk-3RG5ZIWI.js";
16
16
  export {
17
17
  addProjectToPackage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shiva-code",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "description": "Makes Claude Code Persistent - Cross-Project Memory CLI",
5
5
  "author": "SHIVA AI",
6
6
  "license": "MIT",