@enruana/claude-orka 0.4.4 → 0.4.6

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.
@@ -0,0 +1,127 @@
1
+ # Claude-Orka Custom tmux Theme
2
+ # This configuration is automatically applied to all Claude-Orka sessions
3
+
4
+ # ============================================
5
+ # GENERAL SETTINGS
6
+ # ============================================
7
+
8
+ # Enable mouse support for easier pane navigation
9
+ set -g mouse on
10
+
11
+ # Start windows and panes at 1 (not 0)
12
+ set -g base-index 1
13
+ setw -g pane-base-index 1
14
+
15
+ # Increase scrollback buffer
16
+ set -g history-limit 10000
17
+
18
+ # Reduce escape time (better for vim users)
19
+ set -sg escape-time 0
20
+
21
+ # Enable focus events
22
+ set -g focus-events on
23
+
24
+ # Enable 256 colors
25
+ set -g default-terminal "screen-256color"
26
+
27
+ # ============================================
28
+ # STATUS BAR THEME
29
+ # ============================================
30
+
31
+ # Status bar position
32
+ set -g status-position top
33
+
34
+ # Status bar update interval
35
+ set -g status-interval 1
36
+
37
+ # Status bar colors
38
+ set -g status-style bg=colour234,fg=colour137
39
+
40
+ # Status bar length
41
+ set -g status-left-length 50
42
+ set -g status-right-length 100
43
+
44
+ # Left side: Session name with Orka branding
45
+ set -g status-left '#[fg=colour232,bg=colour208,bold] 🎭 ORKA #[fg=colour208,bg=colour236,nobold] #[fg=colour208,bg=colour236] #S #[fg=colour236,bg=colour234,nobold] '
46
+
47
+ # Right side: Project info and time
48
+ set -g status-right '#[fg=colour236,bg=colour234]#[fg=colour137,bg=colour236] #{pane_current_path} #[fg=colour240,bg=colour236]#[fg=colour250,bg=colour240] %Y-%m-%d #[fg=colour245,bg=colour240]#[fg=colour232,bg=colour245,bold] %H:%M:%S '
49
+
50
+ # Window status format
51
+ setw -g window-status-format '#[fg=colour234,bg=colour236]#[fg=colour137,bg=colour236] #I:#W #[fg=colour236,bg=colour234]'
52
+
53
+ # Current window status format (highlighted)
54
+ setw -g window-status-current-format '#[fg=colour234,bg=colour208]#[fg=colour232,bg=colour208,bold] #I:#W #[fg=colour208,bg=colour234,nobold]'
55
+
56
+ # Window with activity status
57
+ setw -g window-status-activity-style fg=colour166,bg=colour236
58
+
59
+ # ============================================
60
+ # PANE BORDERS
61
+ # ============================================
62
+
63
+ # Pane border colors
64
+ set -g pane-border-style fg=colour236
65
+ set -g pane-active-border-style fg=colour208
66
+
67
+ # Pane border format (show pane title)
68
+ set -g pane-border-format '#[fg=colour208,bg=colour234] #{pane_index} #{pane_current_command} '
69
+ set -g pane-border-status top
70
+
71
+ # ============================================
72
+ # MESSAGES & COMMAND PROMPT
73
+ # ============================================
74
+
75
+ # Command prompt style
76
+ set -g message-style fg=colour232,bg=colour208,bold
77
+
78
+ # Command prompt message style
79
+ set -g message-command-style fg=colour232,bg=colour166
80
+
81
+ # ============================================
82
+ # CLOCK MODE
83
+ # ============================================
84
+
85
+ # Clock color (prefix + t)
86
+ setw -g clock-mode-colour colour208
87
+
88
+ # ============================================
89
+ # WINDOW MODES
90
+ # ============================================
91
+
92
+ # Copy mode highlighting
93
+ setw -g mode-style fg=colour232,bg=colour208
94
+
95
+ # ============================================
96
+ # KEY BINDINGS (Optional enhancements)
97
+ # ============================================
98
+
99
+ # Reload config easily (prefix + r)
100
+ bind r source-file ~/.tmux.conf \; display-message "Config reloaded!"
101
+
102
+ # Better pane splitting (keep current directory)
103
+ bind | split-window -h -c "#{pane_current_path}"
104
+ bind - split-window -v -c "#{pane_current_path}"
105
+
106
+ # Pane navigation with vim-like keys
107
+ bind h select-pane -L
108
+ bind j select-pane -D
109
+ bind k select-pane -U
110
+ bind l select-pane -R
111
+
112
+ # Resize panes with vim-like keys
113
+ bind -r H resize-pane -L 5
114
+ bind -r J resize-pane -D 5
115
+ bind -r K resize-pane -U 5
116
+ bind -r L resize-pane -R 5
117
+
118
+ # ============================================
119
+ # VISUAL INDICATORS
120
+ # ============================================
121
+
122
+ # Bell/Activity
123
+ set -g visual-activity off
124
+ set -g visual-bell off
125
+ set -g visual-silence off
126
+ setw -g monitor-activity on
127
+ set -g bell-action none
package/README.md CHANGED
@@ -136,6 +136,41 @@ orka status
136
136
  - **Fork management** - Create, export, merge, and close forks visually
137
137
  - **Status indicators** - Visual distinction for active, saved, merged, and closed forks
138
138
 
139
+ ### 🎨 Custom tmux Theme
140
+
141
+ - **Automatic branding** - Claude-Orka sessions get a custom orange theme
142
+ - **Enhanced status bar** - Shows session name, project path, and current time
143
+ - **Visual hierarchy** - Distinct colors for active/inactive panes and windows
144
+ - **Mouse support** - Click to select panes and windows
145
+ - **Vim-like navigation** - Optional h/j/k/l keys for pane movement
146
+ - **Persistent configuration** - Theme automatically applied to all new sessions
147
+
148
+ The custom theme makes it easy to distinguish Claude-Orka managed sessions from regular tmux sessions. The orange branding 🎭 appears in the status bar, with the session name and project information clearly visible.
149
+
150
+ **Customization:**
151
+
152
+ To modify the theme, edit `.tmux.orka.conf` in your Claude-Orka installation:
153
+
154
+ ```bash
155
+ # Find your global installation
156
+ npm root -g
157
+ # Edit the config
158
+ vim $(npm root -g)/@enruana/claude-orka/.tmux.orka.conf
159
+ ```
160
+
161
+ Or create your own theme file and source it manually:
162
+ ```bash
163
+ # After creating a session
164
+ tmux source-file ~/.my-custom-theme.conf -t <session-name>
165
+ ```
166
+
167
+ **Key Features of the Theme:**
168
+ - **Orange highlights** (#208) for active windows and Orka branding
169
+ - **Top status bar** with session info
170
+ - **Pane borders** with titles showing current command
171
+ - **Enhanced readability** with high contrast colors
172
+ - **Powerline-style separators** for a modern look
173
+
139
174
  ---
140
175
 
141
176
  ## CLI Reference
package/dist/cli.js CHANGED
@@ -3,12 +3,12 @@
3
3
  // src/cli/index.ts
4
4
  import { Command } from "commander";
5
5
  import { readFileSync } from "fs";
6
- import { fileURLToPath as fileURLToPath2 } from "url";
7
- import { dirname as dirname2, join } from "path";
6
+ import { fileURLToPath as fileURLToPath3 } from "url";
7
+ import { dirname as dirname3, join as join2 } from "path";
8
8
 
9
9
  // src/core/StateManager.ts
10
- import path3 from "path";
11
- import fs3 from "fs-extra";
10
+ import path4 from "path";
11
+ import fs4 from "fs-extra";
12
12
 
13
13
  // src/utils/tmux.ts
14
14
  import execa from "execa";
@@ -68,6 +68,11 @@ var Logger = class {
68
68
  var logger = new Logger();
69
69
 
70
70
  // src/utils/tmux.ts
71
+ import * as path2 from "path";
72
+ import * as fs2 from "fs";
73
+ import { fileURLToPath } from "url";
74
+ var __filename = fileURLToPath(import.meta.url);
75
+ var __dirname = path2.dirname(__filename);
71
76
  var TmuxError = class extends Error {
72
77
  constructor(message, command, originalError) {
73
78
  super(message);
@@ -96,6 +101,7 @@ var TmuxCommands = class {
96
101
  logger.debug(`Creating tmux session: ${name} at ${projectPath}`);
97
102
  await execa("tmux", ["new-session", "-d", "-s", name, "-c", projectPath]);
98
103
  logger.info(`Tmux session created: ${name}`);
104
+ await this.applyOrkaTheme(name);
99
105
  } catch (error) {
100
106
  throw new TmuxError(
101
107
  `Failed to create tmux session: ${name}`,
@@ -104,6 +110,37 @@ var TmuxCommands = class {
104
110
  );
105
111
  }
106
112
  }
113
+ /**
114
+ * Apply Claude-Orka custom tmux theme to a session
115
+ */
116
+ static async applyOrkaTheme(sessionName) {
117
+ try {
118
+ const possiblePaths = [
119
+ // When installed globally via npm
120
+ path2.join(__dirname, "../../.tmux.orka.conf"),
121
+ // When running from source
122
+ path2.join(process.cwd(), ".tmux.orka.conf"),
123
+ // Fallback: check in the module directory
124
+ path2.join(__dirname, "../../../.tmux.orka.conf")
125
+ ];
126
+ let configPath = null;
127
+ for (const p of possiblePaths) {
128
+ if (fs2.existsSync(p)) {
129
+ configPath = p;
130
+ break;
131
+ }
132
+ }
133
+ if (!configPath) {
134
+ logger.warn("Claude-Orka tmux config not found, skipping theme application");
135
+ return;
136
+ }
137
+ logger.debug(`Applying Orka theme from: ${configPath}`);
138
+ await execa("tmux", ["source-file", "-t", sessionName, configPath]);
139
+ logger.info("Claude-Orka theme applied successfully");
140
+ } catch (error) {
141
+ logger.warn("Failed to apply Orka theme, continuing with default tmux theme", error);
142
+ }
143
+ }
107
144
  /**
108
145
  * Abrir una terminal que se adjunte a una sesión tmux existente
109
146
  * (Solo macOS por ahora)
@@ -386,18 +423,18 @@ var TmuxCommands = class {
386
423
  };
387
424
 
388
425
  // src/utils/claude-history.ts
389
- import fs2 from "fs-extra";
426
+ import fs3 from "fs-extra";
390
427
  import os from "os";
391
- import path2 from "path";
392
- var CLAUDE_HISTORY_PATH = path2.join(os.homedir(), ".claude", "history.jsonl");
428
+ import path3 from "path";
429
+ var CLAUDE_HISTORY_PATH = path3.join(os.homedir(), ".claude", "history.jsonl");
393
430
  async function readClaudeHistory() {
394
431
  try {
395
- const exists = await fs2.pathExists(CLAUDE_HISTORY_PATH);
432
+ const exists = await fs3.pathExists(CLAUDE_HISTORY_PATH);
396
433
  if (!exists) {
397
434
  logger.warn(`Claude history file not found: ${CLAUDE_HISTORY_PATH}`);
398
435
  return [];
399
436
  }
400
- const content = await fs2.readFile(CLAUDE_HISTORY_PATH, "utf-8");
437
+ const content = await fs3.readFile(CLAUDE_HISTORY_PATH, "utf-8");
401
438
  const lines = content.trim().split("\n").filter(Boolean);
402
439
  const entries = [];
403
440
  for (const line of lines) {
@@ -440,9 +477,9 @@ var StateManager = class {
440
477
  orkaDir;
441
478
  statePath;
442
479
  constructor(projectPath) {
443
- this.projectPath = path3.resolve(projectPath);
444
- this.orkaDir = path3.join(this.projectPath, ".claude-orka");
445
- this.statePath = path3.join(this.orkaDir, "state.json");
480
+ this.projectPath = path4.resolve(projectPath);
481
+ this.orkaDir = path4.join(this.projectPath, ".claude-orka");
482
+ this.statePath = path4.join(this.orkaDir, "state.json");
446
483
  }
447
484
  /**
448
485
  * Initialize StateManager
@@ -451,7 +488,7 @@ var StateManager = class {
451
488
  async initialize() {
452
489
  logger.debug("Initializing StateManager");
453
490
  await this.ensureDirectories();
454
- if (!await fs3.pathExists(this.statePath)) {
491
+ if (!await fs4.pathExists(this.statePath)) {
455
492
  logger.info("Creating initial state.json");
456
493
  const initialState = {
457
494
  version: "1.0.0",
@@ -467,7 +504,7 @@ var StateManager = class {
467
504
  * Create directory structure
468
505
  */
469
506
  async ensureDirectories() {
470
- await fs3.ensureDir(this.orkaDir);
507
+ await fs4.ensureDir(this.orkaDir);
471
508
  logger.debug("Directories ensured");
472
509
  }
473
510
  /**
@@ -475,7 +512,7 @@ var StateManager = class {
475
512
  */
476
513
  async read() {
477
514
  try {
478
- const content = await fs3.readFile(this.statePath, "utf-8");
515
+ const content = await fs4.readFile(this.statePath, "utf-8");
479
516
  return JSON.parse(content);
480
517
  } catch (error) {
481
518
  logger.error("Failed to read state:", error);
@@ -488,7 +525,7 @@ var StateManager = class {
488
525
  async save(state) {
489
526
  try {
490
527
  state.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
491
- await fs3.writeFile(this.statePath, JSON.stringify(state, null, 2), "utf-8");
528
+ await fs4.writeFile(this.statePath, JSON.stringify(state, null, 2), "utf-8");
492
529
  logger.debug("State saved");
493
530
  } catch (error) {
494
531
  logger.error("Failed to save state:", error);
@@ -704,8 +741,8 @@ var StateManager = class {
704
741
  */
705
742
  async saveContext(type, id, content) {
706
743
  const contextPath = type === "session" ? this.getSessionContextPath(id) : this.getForkContextPath(id);
707
- const fullPath = path3.join(this.projectPath, contextPath);
708
- await fs3.writeFile(fullPath, content, "utf-8");
744
+ const fullPath = path4.join(this.projectPath, contextPath);
745
+ await fs4.writeFile(fullPath, content, "utf-8");
709
746
  logger.info(`Context saved: ${contextPath}`);
710
747
  return contextPath;
711
748
  }
@@ -713,11 +750,11 @@ var StateManager = class {
713
750
  * Leer un contexto desde archivo
714
751
  */
715
752
  async readContext(contextPath) {
716
- const fullPath = path3.join(this.projectPath, contextPath);
717
- if (!await fs3.pathExists(fullPath)) {
753
+ const fullPath = path4.join(this.projectPath, contextPath);
754
+ if (!await fs4.pathExists(fullPath)) {
718
755
  throw new Error(`Context file not found: ${contextPath}`);
719
756
  }
720
- return await fs3.readFile(fullPath, "utf-8");
757
+ return await fs4.readFile(fullPath, "utf-8");
721
758
  }
722
759
  // --- HELPERS ---
723
760
  /**
@@ -742,15 +779,15 @@ var StateManager = class {
742
779
 
743
780
  // src/core/SessionManager.ts
744
781
  import { v4 as uuidv4 } from "uuid";
745
- import path4 from "path";
746
- import { fileURLToPath } from "url";
747
- import { dirname } from "path";
748
- import fs4 from "fs-extra";
782
+ import path5 from "path";
783
+ import { fileURLToPath as fileURLToPath2 } from "url";
784
+ import { dirname as dirname2 } from "path";
785
+ import fs5 from "fs-extra";
749
786
  import { spawn } from "child_process";
750
787
  import { createRequire } from "module";
751
788
  var require2 = createRequire(import.meta.url);
752
- var __filename = fileURLToPath(import.meta.url);
753
- var __dirname = dirname(__filename);
789
+ var __filename2 = fileURLToPath2(import.meta.url);
790
+ var __dirname2 = dirname2(__filename2);
754
791
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
755
792
  var SessionManager = class {
756
793
  stateManager;
@@ -1127,12 +1164,12 @@ var SessionManager = class {
1127
1164
  throw new Error(`Fork ${forkId} not found`);
1128
1165
  }
1129
1166
  logger.info(`Generating export for fork: ${fork.name}`);
1130
- const exportsDir = path4.join(this.projectPath, ".claude-orka", "exports");
1131
- await fs4.ensureDir(exportsDir);
1167
+ const exportsDir = path5.join(this.projectPath, ".claude-orka", "exports");
1168
+ await fs5.ensureDir(exportsDir);
1132
1169
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1133
1170
  const exportName = `fork-${fork.name}-${timestamp}.md`;
1134
1171
  const relativeExportPath = `.claude-orka/exports/${exportName}`;
1135
- const absoluteExportPath = path4.join(this.projectPath, relativeExportPath);
1172
+ const absoluteExportPath = path5.join(this.projectPath, relativeExportPath);
1136
1173
  const prompt = `
1137
1174
  Please generate a complete summary of this fork conversation "${fork.name}" and save it to the file:
1138
1175
  \`${absoluteExportPath}\`
@@ -1208,17 +1245,17 @@ Write the summary in Markdown format and save it to the specified file.
1208
1245
  throw new Error(`Parent ${parentName} is not active. Cannot send merge command.`);
1209
1246
  }
1210
1247
  let contextPath = fork.contextPath;
1211
- let fullPath = path4.join(this.projectPath, contextPath);
1212
- let exists = await fs4.pathExists(fullPath);
1248
+ let fullPath = path5.join(this.projectPath, contextPath);
1249
+ let exists = await fs5.pathExists(fullPath);
1213
1250
  if (!exists) {
1214
1251
  logger.warn(`Export file not found: ${contextPath}. Looking for most recent export...`);
1215
- const exportsDir = path4.join(this.projectPath, ".claude-orka", "exports");
1216
- const files = await fs4.readdir(exportsDir);
1252
+ const exportsDir = path5.join(this.projectPath, ".claude-orka", "exports");
1253
+ const files = await fs5.readdir(exportsDir);
1217
1254
  const forkExports = files.filter((f) => f.startsWith(`fork-${fork.name}-`) && f.endsWith(".md")).sort().reverse();
1218
1255
  if (forkExports.length > 0) {
1219
1256
  contextPath = `.claude-orka/exports/${forkExports[0]}`;
1220
- fullPath = path4.join(this.projectPath, contextPath);
1221
- exists = await fs4.pathExists(fullPath);
1257
+ fullPath = path5.join(this.projectPath, contextPath);
1258
+ exists = await fs5.pathExists(fullPath);
1222
1259
  logger.info(`Using most recent export: ${contextPath}`);
1223
1260
  }
1224
1261
  }
@@ -1298,12 +1335,27 @@ Analyze the content and help me integrate the changes and learnings from the for
1298
1335
  logger.warn("Electron not available, skipping UI launch");
1299
1336
  return;
1300
1337
  }
1301
- let mainPath = path4.join(__dirname, "../../electron/main/main.js");
1302
- if (!fs4.existsSync(mainPath)) {
1303
- mainPath = path4.join(__dirname, "../../dist/electron/main/main.js");
1338
+ const possiblePaths = [
1339
+ // Production (installed globally): dist/core -> ../../dist/electron/main/main.js
1340
+ path5.join(__dirname2, "../../dist/electron/main/main.js"),
1341
+ // Development (running from dist): dist/core -> ../electron/main/main.js
1342
+ path5.join(__dirname2, "../electron/main/main.js"),
1343
+ // Development (running from src): src/core -> ../../dist/electron/main/main.js
1344
+ path5.join(__dirname2, "../../dist/electron/main/main.js"),
1345
+ // Fallback: check relative to package root
1346
+ path5.join(__dirname2, "../../electron/main/main.js")
1347
+ ];
1348
+ let mainPath = null;
1349
+ for (const p of possiblePaths) {
1350
+ if (fs5.existsSync(p)) {
1351
+ mainPath = p;
1352
+ logger.debug(`Found Electron main.js at: ${p}`);
1353
+ break;
1354
+ }
1304
1355
  }
1305
- if (!fs4.existsSync(mainPath)) {
1306
- logger.warn(`Electron main.js not found at ${mainPath}, skipping UI launch`);
1356
+ if (!mainPath) {
1357
+ logger.warn(`Electron main.js not found. Tried paths: ${possiblePaths.join(", ")}`);
1358
+ logger.warn("Skipping UI launch");
1307
1359
  return;
1308
1360
  }
1309
1361
  const electronProcess = spawn(
@@ -1810,8 +1862,8 @@ ${statusEmoji} ${chalk.bold(session.name)}`);
1810
1862
 
1811
1863
  // src/cli/utils/errors.ts
1812
1864
  import chalk2 from "chalk";
1813
- import fs5 from "fs";
1814
- import path5 from "path";
1865
+ import fs6 from "fs";
1866
+ import path6 from "path";
1815
1867
  var CLIError = class extends Error {
1816
1868
  constructor(message, exitCode = 1) {
1817
1869
  super(message);
@@ -1843,8 +1895,8 @@ function validateForkId(forkId) {
1843
1895
  }
1844
1896
  }
1845
1897
  function validateInitialized(projectPath) {
1846
- const orkaDir = path5.join(projectPath, ".claude-orka");
1847
- if (!fs5.existsSync(orkaDir)) {
1898
+ const orkaDir = path6.join(projectPath, ".claude-orka");
1899
+ if (!fs6.existsSync(orkaDir)) {
1848
1900
  throw new CLIError(
1849
1901
  'Project not initialized. Run "orka init" first.',
1850
1902
  2
@@ -2237,8 +2289,8 @@ function mergeCommand(program2) {
2237
2289
 
2238
2290
  // src/cli/commands/doctor.ts
2239
2291
  import execa2 from "execa";
2240
- import fs6 from "fs-extra";
2241
- import path6 from "path";
2292
+ import fs7 from "fs-extra";
2293
+ import path7 from "path";
2242
2294
  import chalk4 from "chalk";
2243
2295
  function doctorCommand(program2) {
2244
2296
  program2.command("doctor").description("Check system dependencies and configuration").action(async () => {
@@ -2249,6 +2301,7 @@ function doctorCommand(program2) {
2249
2301
  results.push(await checkNodeVersion());
2250
2302
  results.push(await checkTmux());
2251
2303
  results.push(await checkClaude());
2304
+ results.push(await checkElectron());
2252
2305
  results.push(await checkProjectInit());
2253
2306
  results.push(await checkWritePermissions());
2254
2307
  results.push(await checkClaudeDir());
@@ -2327,13 +2380,33 @@ async function checkClaude() {
2327
2380
  };
2328
2381
  }
2329
2382
  }
2383
+ async function checkElectron() {
2384
+ try {
2385
+ const { stdout } = await execa2("electron", ["--version"]);
2386
+ const version2 = stdout.trim();
2387
+ return {
2388
+ name: "Electron",
2389
+ status: "pass",
2390
+ message: version2.startsWith("v") ? version2 : `v${version2}`,
2391
+ details: "Required for visual UI"
2392
+ };
2393
+ } catch (error) {
2394
+ return {
2395
+ name: "Electron",
2396
+ status: "warn",
2397
+ message: "Not found",
2398
+ details: "Electron is required for the visual UI (optional)",
2399
+ fix: "Install Electron: npm install -g electron"
2400
+ };
2401
+ }
2402
+ }
2330
2403
  async function checkProjectInit() {
2331
2404
  const projectPath = process.cwd();
2332
- const orkaDir = path6.join(projectPath, ".claude-orka");
2333
- const stateFile = path6.join(orkaDir, "state.json");
2405
+ const orkaDir = path7.join(projectPath, ".claude-orka");
2406
+ const stateFile = path7.join(orkaDir, "state.json");
2334
2407
  try {
2335
- const dirExists = await fs6.pathExists(orkaDir);
2336
- const stateExists = await fs6.pathExists(stateFile);
2408
+ const dirExists = await fs7.pathExists(orkaDir);
2409
+ const stateExists = await fs7.pathExists(stateFile);
2337
2410
  if (dirExists && stateExists) {
2338
2411
  return {
2339
2412
  name: "Project initialization",
@@ -2370,9 +2443,9 @@ async function checkProjectInit() {
2370
2443
  async function checkWritePermissions() {
2371
2444
  const projectPath = process.cwd();
2372
2445
  try {
2373
- const testFile = path6.join(projectPath, ".claude-orka-write-test");
2374
- await fs6.writeFile(testFile, "test");
2375
- await fs6.remove(testFile);
2446
+ const testFile = path7.join(projectPath, ".claude-orka-write-test");
2447
+ await fs7.writeFile(testFile, "test");
2448
+ await fs7.remove(testFile);
2376
2449
  return {
2377
2450
  name: "Write permissions",
2378
2451
  status: "pass",
@@ -2391,11 +2464,11 @@ async function checkWritePermissions() {
2391
2464
  }
2392
2465
  async function checkClaudeDir() {
2393
2466
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
2394
- const claudeDir = path6.join(homeDir, ".claude");
2395
- const historyFile = path6.join(claudeDir, "history.jsonl");
2467
+ const claudeDir = path7.join(homeDir, ".claude");
2468
+ const historyFile = path7.join(claudeDir, "history.jsonl");
2396
2469
  try {
2397
- const dirExists = await fs6.pathExists(claudeDir);
2398
- const historyExists = await fs6.pathExists(historyFile);
2470
+ const dirExists = await fs7.pathExists(claudeDir);
2471
+ const historyExists = await fs7.pathExists(historyFile);
2399
2472
  if (dirExists && historyExists) {
2400
2473
  return {
2401
2474
  name: "Claude directory",
@@ -2487,6 +2560,7 @@ function prepareCommand(program2) {
2487
2560
  console.log(chalk5.bold.cyan("\n\u{1F527} Claude-Orka Preparation\n"));
2488
2561
  console.log("This will help you install required dependencies:\n");
2489
2562
  console.log(" \u2022 tmux (terminal multiplexer)");
2563
+ console.log(" \u2022 Electron (for visual UI)");
2490
2564
  console.log(" \u2022 Claude CLI (if needed)\n");
2491
2565
  if (!options.yes) {
2492
2566
  const rl = readline2.createInterface({
@@ -2506,6 +2580,7 @@ function prepareCommand(program2) {
2506
2580
  console.log(chalk5.gray(`
2507
2581
  Detected: ${system.platform}`));
2508
2582
  await installTmux(system);
2583
+ await installElectron();
2509
2584
  await checkClaudeCLI();
2510
2585
  console.log(chalk5.bold.green("\n\u2713 Preparation complete!\n"));
2511
2586
  console.log("Run " + chalk5.cyan("orka doctor") + " to verify everything is working.");
@@ -2594,6 +2669,31 @@ Error: ${error.message}`));
2594
2669
  console.log(chalk5.cyan(" CentOS: sudo yum install tmux"));
2595
2670
  }
2596
2671
  }
2672
+ async function installElectron() {
2673
+ console.log(chalk5.bold("\n\u26A1 Installing Electron...\n"));
2674
+ try {
2675
+ await execa3("electron", ["--version"]);
2676
+ Output.success("Electron is already installed");
2677
+ return;
2678
+ } catch {
2679
+ }
2680
+ const spinner = ora4("Installing Electron globally...").start();
2681
+ try {
2682
+ await execa3("npm", ["install", "-g", "electron"], {
2683
+ stdio: "ignore"
2684
+ });
2685
+ spinner.succeed("Electron installed globally");
2686
+ } catch (error) {
2687
+ spinner.fail("Failed to install Electron");
2688
+ console.log(chalk5.red(`
2689
+ Error: ${error.message}`));
2690
+ console.log(chalk5.yellow("\nPlease install Electron manually:"));
2691
+ console.log(chalk5.cyan(" npm install -g electron"));
2692
+ console.log(
2693
+ chalk5.gray("\nNote: Electron is required for the visual UI interface.")
2694
+ );
2695
+ }
2696
+ }
2597
2697
  async function checkClaudeCLI() {
2598
2698
  console.log(chalk5.bold("\n\u{1F916} Checking Claude CLI...\n"));
2599
2699
  try {
@@ -2612,13 +2712,13 @@ async function checkClaudeCLI() {
2612
2712
  }
2613
2713
 
2614
2714
  // src/cli/index.ts
2615
- var __filename2 = fileURLToPath2(import.meta.url);
2616
- var __dirname2 = dirname2(__filename2);
2617
- var packageJsonPath = join(__dirname2, "../package.json");
2715
+ var __filename3 = fileURLToPath3(import.meta.url);
2716
+ var __dirname3 = dirname3(__filename3);
2717
+ var packageJsonPath = join2(__dirname3, "../package.json");
2618
2718
  try {
2619
2719
  readFileSync(packageJsonPath, "utf-8");
2620
2720
  } catch {
2621
- packageJsonPath = join(__dirname2, "../../package.json");
2721
+ packageJsonPath = join2(__dirname3, "../../package.json");
2622
2722
  }
2623
2723
  var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
2624
2724
  var version = packageJson.version;