shiva-code 0.4.3 → 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,11 +66,12 @@ 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";
@@ -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.3");
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,60 +14654,59 @@ 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
  });
14676
14683
  async function interactiveMenu(choices, shortcuts) {
14684
+ const write = (str) => process.stdout.write(str);
14685
+ const totalLines = 1 + choices.length + 1;
14677
14686
  return new Promise((resolve13) => {
14678
14687
  let selectedIndex = 0;
14679
14688
  let resolved = false;
14689
+ let firstRender = true;
14680
14690
  const renderMenu = () => {
14681
- if (selectedIndex > 0 || choices.length > 0) {
14682
- process.stdout.write(`\x1B[${choices.length + 1}A`);
14691
+ if (!firstRender) {
14692
+ write(`\x1B[${totalLines}A`);
14683
14693
  }
14684
- console.log(colors.green("?") + " " + colors.bold("Auswahl:"));
14694
+ firstRender = false;
14695
+ write("\x1B[?25l");
14696
+ write(`\x1B[K${colors.green("?")} ${colors.bold("Auswahl:")}
14697
+ `);
14685
14698
  for (let i = 0; i < choices.length; i++) {
14686
- const prefix = i === selectedIndex ? colors.cyan("\u276F ") : " ";
14687
- const name = i === selectedIndex ? colors.cyan(choices[i].name) : choices[i].name;
14688
- console.log(prefix + name);
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
+ `);
14689
14704
  }
14690
- console.log(colors.dim("\u2191\u2193 navigate \u2022 \u21B5 select"));
14705
+ write(`\x1B[K${colors.dim("\u2191\u2193 navigate \u2022 \u21B5 select")}
14706
+ `);
14707
+ write("\x1B[?25h");
14691
14708
  };
14692
- console.log(colors.green("?") + " " + colors.bold("Auswahl:"));
14693
- for (let i = 0; i < choices.length; i++) {
14694
- const prefix = i === selectedIndex ? colors.cyan("\u276F ") : " ";
14695
- const name = i === selectedIndex ? colors.cyan(choices[i].name) : choices[i].name;
14696
- console.log(prefix + name);
14697
- }
14698
- console.log(colors.dim("\u2191\u2193 navigate \u2022 \u21B5 select"));
14709
+ renderMenu();
14699
14710
  if (process.stdin.isTTY) {
14700
14711
  readline.emitKeypressEvents(process.stdin);
14701
14712
  process.stdin.setRawMode(true);
@@ -14706,6 +14717,12 @@ async function interactiveMenu(choices, shortcuts) {
14706
14717
  if (process.stdin.isTTY) {
14707
14718
  process.stdin.setRawMode(false);
14708
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)}`);
14709
14726
  };
14710
14727
  const handler = (_str, key) => {
14711
14728
  if (resolved) return;
@@ -14713,14 +14730,14 @@ async function interactiveMenu(choices, shortcuts) {
14713
14730
  const keyChar = key?.sequence?.toLowerCase() || "";
14714
14731
  if (key?.ctrl && keyName === "c") {
14715
14732
  cleanup();
14733
+ console.log("");
14716
14734
  process.exit(0);
14717
14735
  }
14718
- if (shortcuts[keyChar] || shortcuts[keyName]) {
14719
- const shortcutType = shortcuts[keyChar] || shortcuts[keyName];
14736
+ const shortcutType = shortcuts[keyChar] || shortcuts[keyName];
14737
+ if (shortcutType) {
14720
14738
  resolved = true;
14721
14739
  cleanup();
14722
- process.stdout.write(`\x1B[${choices.length + 2}A\x1B[J`);
14723
- console.log(colors.green("?") + " " + colors.bold("Auswahl:") + " " + colors.cyan(shortcutType));
14740
+ showSelection(shortcutType);
14724
14741
  resolve13({ type: shortcutType });
14725
14742
  return;
14726
14743
  }
@@ -14733,13 +14750,12 @@ async function interactiveMenu(choices, shortcuts) {
14733
14750
  } else if (keyName === "return") {
14734
14751
  resolved = true;
14735
14752
  cleanup();
14736
- process.stdout.write(`\x1B[${choices.length + 2}A\x1B[J`);
14737
- console.log(colors.green("?") + " " + colors.bold("Auswahl:") + " " + colors.cyan(choices[selectedIndex].value.type));
14753
+ showSelection(choices[selectedIndex].name);
14738
14754
  resolve13(choices[selectedIndex].value);
14739
14755
  } else if (keyName === "escape") {
14740
14756
  resolved = true;
14741
14757
  cleanup();
14742
- process.stdout.write(`\x1B[${choices.length + 2}A\x1B[J`);
14758
+ showSelection("Beenden");
14743
14759
  resolve13({ type: "quit" });
14744
14760
  }
14745
14761
  };
@@ -14836,7 +14852,7 @@ async function showDashboard() {
14836
14852
  const packageName = selected.data;
14837
14853
  log.newline();
14838
14854
  log.success(`Starte Package ${packageName}...`);
14839
- const { getPackageLaunchConfig: getPackageLaunchConfig2 } = await import("./package-manager-NARG55B5.js");
14855
+ const { getPackageLaunchConfig: getPackageLaunchConfig2 } = await import("./package-manager-WF3UW2J4.js");
14840
14856
  const launches = await getPackageLaunchConfig2(packageName);
14841
14857
  if (launches.length > 0) {
14842
14858
  await spawnProjects(launches, detectTerminal());
@@ -14872,7 +14888,7 @@ async function showDashboard() {
14872
14888
  function showHelpMenu() {
14873
14889
  log.plain("Verf\xFCgbare Befehle:");
14874
14890
  log.newline();
14875
- console.log(colors.dim(" Control Station:"));
14891
+ console.log(colors.dim(" Session-Verwaltung:"));
14876
14892
  log.plain(" shiva sessions Alle Claude Sessions auflisten");
14877
14893
  log.plain(" shiva resume Session fortsetzen");
14878
14894
  log.plain(" shiva restore Crashed Session wiederherstellen");
@@ -14884,27 +14900,33 @@ function showHelpMenu() {
14884
14900
  log.plain(" shiva issues GitHub Issues anzeigen");
14885
14901
  log.plain(" shiva prs Pull Requests anzeigen");
14886
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();
14887
14910
  console.log(colors.dim(" Docker Integration:"));
14888
14911
  log.plain(" shiva docker Docker-Modus verwalten");
14889
14912
  log.plain(" shiva start -d In Docker starten");
14890
14913
  log.newline();
14891
- console.log(colors.dim(" Security (Phase 16-17):"));
14914
+ console.log(colors.dim(" Security:"));
14892
14915
  log.plain(" shiva scan Package auf Sicherheit pr\xFCfen");
14916
+ log.plain(" shiva secrets Secrets verwalten");
14893
14917
  log.plain(" shiva start -s In Sandbox starten");
14894
- log.plain(" shiva session Sandbox-Session verwalten");
14895
14918
  log.newline();
14896
- console.log(colors.dim(" Cloud Sync:"));
14897
- log.plain(" shiva login Anmelden");
14919
+ console.log(colors.dim(" Projekt-Verwaltung:"));
14898
14920
  log.plain(" shiva init Projekt initialisieren");
14899
14921
  log.plain(" shiva sync Mit Cloud synchronisieren");
14900
14922
  log.plain(" shiva status Status anzeigen");
14901
14923
  log.plain(" shiva projects Alle Projekte auflisten");
14902
- log.plain(" shiva config sync Settings synchronisieren");
14924
+ log.plain(" shiva config Settings verwalten");
14903
14925
  log.newline();
14904
- console.log(colors.dim(" Utilities:"));
14926
+ console.log(colors.dim(" System:"));
14905
14927
  log.plain(" shiva doctor System-Check");
14906
14928
  log.plain(" shiva upgrade SHIVA aktualisieren");
14907
- log.plain(" shiva telemetry Analytics opt-in/out");
14929
+ log.plain(" shiva stats Analytics anzeigen");
14908
14930
  log.newline();
14909
14931
  log.dim("Hilfe: shiva <befehl> --help");
14910
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.3",
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",