@enruana/claude-orka 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/cli.js +134 -44
  2. package/dist/electron/main/main.js +122 -29
  3. package/dist/electron/main/main.js.map +1 -1
  4. package/dist/electron/preload/preload.js +1 -0
  5. package/dist/electron/preload/preload.js.map +1 -1
  6. package/dist/electron/renderer/assets/main-BMC8JuEx.js +66 -0
  7. package/dist/electron/renderer/index.html +1 -1
  8. package/dist/src/cli/commands/fork.js +1 -1
  9. package/dist/src/cli/commands/fork.js.map +1 -1
  10. package/dist/src/cli/commands/session.d.ts.map +1 -1
  11. package/dist/src/cli/commands/session.js +5 -3
  12. package/dist/src/cli/commands/session.js.map +1 -1
  13. package/dist/src/cli/utils/output.d.ts.map +1 -1
  14. package/dist/src/cli/utils/output.js +13 -10
  15. package/dist/src/cli/utils/output.js.map +1 -1
  16. package/dist/src/core/ClaudeOrka.d.ts +10 -0
  17. package/dist/src/core/ClaudeOrka.d.ts.map +1 -1
  18. package/dist/src/core/ClaudeOrka.js +12 -0
  19. package/dist/src/core/ClaudeOrka.js.map +1 -1
  20. package/dist/src/core/SessionManager.d.ts +10 -0
  21. package/dist/src/core/SessionManager.d.ts.map +1 -1
  22. package/dist/src/core/SessionManager.js +27 -3
  23. package/dist/src/core/SessionManager.js.map +1 -1
  24. package/dist/src/core/StateManager.d.ts +5 -0
  25. package/dist/src/core/StateManager.d.ts.map +1 -1
  26. package/dist/src/core/StateManager.js +49 -0
  27. package/dist/src/core/StateManager.js.map +1 -1
  28. package/dist/src/models/Session.d.ts +9 -0
  29. package/dist/src/models/Session.d.ts.map +1 -1
  30. package/dist/src/utils/tmux.d.ts +1 -1
  31. package/dist/src/utils/tmux.d.ts.map +1 -1
  32. package/dist/src/utils/tmux.js +14 -7
  33. package/dist/src/utils/tmux.js.map +1 -1
  34. package/package.json +1 -1
  35. package/dist/electron/renderer/assets/main-CcTQJJH_.js +0 -66
package/dist/cli.js CHANGED
@@ -3,12 +3,13 @@
3
3
  // src/cli/index.ts
4
4
  import { Command } from "commander";
5
5
  import { readFileSync } from "fs";
6
- import { fileURLToPath as fileURLToPath3 } from "url";
6
+ import { fileURLToPath as fileURLToPath4 } from "url";
7
7
  import { dirname as dirname3, join as join2 } from "path";
8
8
 
9
9
  // src/core/StateManager.ts
10
10
  import path4 from "path";
11
11
  import fs4 from "fs-extra";
12
+ import { fileURLToPath as fileURLToPath2 } from "url";
12
13
 
13
14
  // src/utils/tmux.ts
14
15
  import execa from "execa";
@@ -101,7 +102,7 @@ var TmuxCommands = class {
101
102
  logger.debug(`Creating tmux session: ${name} at ${projectPath}`);
102
103
  await execa("tmux", ["new-session", "-d", "-s", name, "-c", projectPath]);
103
104
  logger.info(`Tmux session created: ${name}`);
104
- await this.applyOrkaTheme(name);
105
+ await this.applyOrkaTheme(name, projectPath);
105
106
  } catch (error) {
106
107
  throw new TmuxError(
107
108
  `Failed to create tmux session: ${name}`,
@@ -113,16 +114,23 @@ var TmuxCommands = class {
113
114
  /**
114
115
  * Apply Claude-Orka custom tmux theme to a session
115
116
  */
116
- static async applyOrkaTheme(sessionName) {
117
+ static async applyOrkaTheme(sessionName, projectPath) {
117
118
  try {
118
119
  const possiblePaths = [
119
- // When installed globally via npm
120
+ // PRIORITY 1: Project-local theme (copied during orka init)
121
+ ...projectPath ? [path2.join(projectPath, ".claude-orka", ".tmux.orka.conf")] : [],
122
+ // PRIORITY 2: Current working directory project
123
+ path2.join(process.cwd(), ".claude-orka", ".tmux.orka.conf"),
124
+ // FALLBACK: Package installation paths
125
+ // When installed globally via npm (dist/ -> package root)
126
+ path2.join(__dirname, "../.tmux.orka.conf"),
127
+ // When running from source (src/utils/ -> package root)
120
128
  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")
129
+ // When running from current working directory (legacy)
130
+ path2.join(process.cwd(), ".tmux.orka.conf")
125
131
  ];
132
+ logger.debug(`Looking for Orka theme config. __dirname: ${__dirname}`);
133
+ logger.debug(`Possible paths: ${possiblePaths.map((p) => path2.resolve(p)).join(", ")}`);
126
134
  let configPath = null;
127
135
  for (const p of possiblePaths) {
128
136
  if (fs2.existsSync(p)) {
@@ -465,7 +473,7 @@ async function detectNewSessionId(previousIds, maxWaitMs = 1e4, pollIntervalMs =
465
473
  return id;
466
474
  }
467
475
  }
468
- await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
476
+ await new Promise((resolve2) => setTimeout(resolve2, pollIntervalMs));
469
477
  }
470
478
  logger.warn("Timeout waiting for new Claude session ID");
471
479
  return null;
@@ -500,6 +508,8 @@ async function listClaudeSessions(projectPath, limit = 20) {
500
508
  }
501
509
 
502
510
  // src/core/StateManager.ts
511
+ var __filename2 = fileURLToPath2(import.meta.url);
512
+ var __dirname2 = path4.dirname(__filename2);
503
513
  var StateManager = class {
504
514
  projectPath;
505
515
  orkaDir;
@@ -516,6 +526,7 @@ var StateManager = class {
516
526
  async initialize() {
517
527
  logger.debug("Initializing StateManager");
518
528
  await this.ensureDirectories();
529
+ await this.copyThemeConfig();
519
530
  if (!await fs4.pathExists(this.statePath)) {
520
531
  logger.info("Creating initial state.json");
521
532
  const initialState = {
@@ -528,6 +539,46 @@ var StateManager = class {
528
539
  }
529
540
  logger.info("StateManager initialized");
530
541
  }
542
+ /**
543
+ * Copy tmux theme config to project's .claude-orka directory
544
+ * This ensures the theme persists across system restarts
545
+ */
546
+ async copyThemeConfig() {
547
+ const destPath = path4.join(this.orkaDir, ".tmux.orka.conf");
548
+ if (await fs4.pathExists(destPath)) {
549
+ logger.debug("Theme config already exists in project");
550
+ return;
551
+ }
552
+ const possibleSources = [
553
+ // When running from dist/ (bundled CLI)
554
+ path4.join(__dirname2, "../.tmux.orka.conf"),
555
+ // When running from src/core/ (development)
556
+ path4.join(__dirname2, "../../.tmux.orka.conf"),
557
+ // Fallback: look in node_modules (when used as dependency)
558
+ path4.join(__dirname2, "../../../.tmux.orka.conf")
559
+ ];
560
+ logger.debug(`Looking for tmux theme. __dirname: ${__dirname2}`);
561
+ let sourcePath = null;
562
+ for (const p of possibleSources) {
563
+ const resolved = path4.resolve(p);
564
+ const exists = await fs4.pathExists(resolved);
565
+ logger.debug(` Checking ${resolved}: ${exists ? "EXISTS" : "not found"}`);
566
+ if (exists) {
567
+ sourcePath = resolved;
568
+ break;
569
+ }
570
+ }
571
+ if (!sourcePath) {
572
+ logger.warn("Could not find tmux theme source file to copy");
573
+ return;
574
+ }
575
+ try {
576
+ await fs4.copy(sourcePath, destPath);
577
+ logger.info(`Tmux theme copied to ${destPath}`);
578
+ } catch (error) {
579
+ logger.warn(`Failed to copy tmux theme: ${error.message}`);
580
+ }
581
+ }
531
582
  /**
532
583
  * Create directory structure
533
584
  */
@@ -808,14 +859,14 @@ var StateManager = class {
808
859
  // src/core/SessionManager.ts
809
860
  import { v4 as uuidv4 } from "uuid";
810
861
  import path5 from "path";
811
- import { fileURLToPath as fileURLToPath2 } from "url";
862
+ import { fileURLToPath as fileURLToPath3 } from "url";
812
863
  import { dirname as dirname2 } from "path";
813
864
  import fs5 from "fs-extra";
814
865
  import { spawn } from "child_process";
815
866
  import execa2 from "execa";
816
- var __filename2 = fileURLToPath2(import.meta.url);
817
- var __dirname2 = dirname2(__filename2);
818
- var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
867
+ var __filename3 = fileURLToPath3(import.meta.url);
868
+ var __dirname3 = dirname2(__filename3);
869
+ var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
819
870
  var SessionManager = class {
820
871
  stateManager;
821
872
  projectPath;
@@ -923,7 +974,7 @@ var SessionManager = class {
923
974
  }
924
975
  logger.info(`Tmux session not found, recovering from Claude session...`);
925
976
  await TmuxCommands.createSession(tmuxSessionId, this.projectPath);
926
- await TmuxCommands.applyOrkaTheme(tmuxSessionId);
977
+ await TmuxCommands.applyOrkaTheme(tmuxSessionId, this.projectPath);
927
978
  if (openTerminal) {
928
979
  await TmuxCommands.openTerminalWindow(tmuxSessionId);
929
980
  }
@@ -940,7 +991,8 @@ var SessionManager = class {
940
991
  session.status = "active";
941
992
  session.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
942
993
  await this.stateManager.replaceSession(session);
943
- const forksToRestore = session.forks.filter((f) => f.status !== "merged");
994
+ const forks = session.forks || [];
995
+ const forksToRestore = forks.filter((f) => f.status === "active" || f.status === "saved");
944
996
  if (forksToRestore.length > 0) {
945
997
  logger.info(`Restoring ${forksToRestore.length} fork(s)...`);
946
998
  for (const fork of forksToRestore) {
@@ -1335,6 +1387,27 @@ Analyze the content and help me integrate the changes and learnings from the for
1335
1387
  return await this.generateForkExport(sessionId, forkId);
1336
1388
  }
1337
1389
  // ==========================================
1390
+ // UI METHODS
1391
+ // ==========================================
1392
+ /**
1393
+ * Save node position for UI persistence
1394
+ * @param sessionId Session ID
1395
+ * @param nodeId Node ID ('main' or fork id)
1396
+ * @param position Position {x, y}
1397
+ */
1398
+ async saveNodePosition(sessionId, nodeId, position) {
1399
+ const session = await this.getSession(sessionId);
1400
+ if (!session) {
1401
+ throw new Error(`Session ${sessionId} not found`);
1402
+ }
1403
+ if (!session.nodePositions) {
1404
+ session.nodePositions = {};
1405
+ }
1406
+ session.nodePositions[nodeId] = position;
1407
+ await this.stateManager.replaceSession(session);
1408
+ logger.debug(`Node position saved: ${nodeId} -> (${position.x}, ${position.y})`);
1409
+ }
1410
+ // ==========================================
1338
1411
  // HELPERS PRIVADOS
1339
1412
  // ==========================================
1340
1413
  /**
@@ -1388,11 +1461,11 @@ Analyze the content and help me integrate the changes and learnings from the for
1388
1461
  }
1389
1462
  const possiblePaths = [
1390
1463
  // Via CLI (bundled): dist -> ./electron/main/main.js
1391
- path5.join(__dirname2, "./electron/main/main.js"),
1464
+ path5.join(__dirname3, "./electron/main/main.js"),
1392
1465
  // Via SDK: dist/src/core -> ../../electron/main/main.js
1393
- path5.join(__dirname2, "../../electron/main/main.js"),
1466
+ path5.join(__dirname3, "../../electron/main/main.js"),
1394
1467
  // Development: src/core -> ../../dist/electron/main/main.js
1395
- path5.join(__dirname2, "../../dist/electron/main/main.js")
1468
+ path5.join(__dirname3, "../../dist/electron/main/main.js")
1396
1469
  ];
1397
1470
  let mainPath = null;
1398
1471
  for (const p of possiblePaths) {
@@ -1406,7 +1479,7 @@ Analyze the content and help me integrate the changes and learnings from the for
1406
1479
  if (!mainPath) {
1407
1480
  const resolvedPaths = possiblePaths.map((p) => path5.resolve(p));
1408
1481
  logger.warn(`Electron main.js not found. Tried paths: ${resolvedPaths.join(", ")}`);
1409
- logger.warn(`Current __dirname: ${__dirname2}`);
1482
+ logger.warn(`Current __dirname: ${__dirname3}`);
1410
1483
  logger.warn("Skipping UI launch");
1411
1484
  return;
1412
1485
  }
@@ -1654,7 +1727,7 @@ var ClaudeOrka = class {
1654
1727
  async generateExportAndMerge(sessionId, forkId, waitTime = 15e3) {
1655
1728
  await this.generateForkExport(sessionId, forkId);
1656
1729
  logger.info(`Waiting ${waitTime}ms for Claude to complete export...`);
1657
- await new Promise((resolve) => setTimeout(resolve, waitTime));
1730
+ await new Promise((resolve2) => setTimeout(resolve2, waitTime));
1658
1731
  await this.merge(sessionId, forkId);
1659
1732
  }
1660
1733
  /**
@@ -1683,6 +1756,18 @@ var ClaudeOrka = class {
1683
1756
  await this.exportAndMerge(sessionId, forkId);
1684
1757
  await this.closeFork(sessionId, forkId);
1685
1758
  }
1759
+ // ==========================================
1760
+ // UI METHODS
1761
+ // ==========================================
1762
+ /**
1763
+ * Save node position for UI persistence
1764
+ * @param sessionId Session ID
1765
+ * @param nodeId Node ID ('main' or fork id)
1766
+ * @param position Position {x, y}
1767
+ */
1768
+ async saveNodePosition(sessionId, nodeId, position) {
1769
+ await this.sessionManager.saveNodePosition(sessionId, nodeId, position);
1770
+ }
1686
1771
  };
1687
1772
 
1688
1773
  // src/cli/utils/output.ts
@@ -1742,16 +1827,17 @@ ${statusEmoji} ${chalk.bold(session.name)}`);
1742
1827
  if (session.status === "active") {
1743
1828
  console.log(` ${chalk.gray("Tmux Session:")} ${session.tmuxSessionId}`);
1744
1829
  }
1745
- if (session.forks.length > 0) {
1746
- console.log(` ${chalk.gray("Forks:")} ${session.forks.length}`);
1830
+ const forks = session.forks || [];
1831
+ if (forks.length > 0) {
1832
+ console.log(` ${chalk.gray("Forks:")} ${forks.length}`);
1747
1833
  console.log(
1748
- ` ${chalk.green("Active:")} ${session.forks.filter((f) => f.status === "active").length}`
1834
+ ` ${chalk.green("Active:")} ${forks.filter((f) => f.status === "active").length}`
1749
1835
  );
1750
1836
  console.log(
1751
- ` ${chalk.yellow("Saved:")} ${session.forks.filter((f) => f.status === "saved").length}`
1837
+ ` ${chalk.yellow("Saved:")} ${forks.filter((f) => f.status === "saved").length}`
1752
1838
  );
1753
1839
  console.log(
1754
- ` ${chalk.blue("Merged:")} ${session.forks.filter((f) => f.status === "merged").length}`
1840
+ ` ${chalk.blue("Merged:")} ${forks.filter((f) => f.status === "merged").length}`
1755
1841
  );
1756
1842
  }
1757
1843
  }
@@ -1799,9 +1885,10 @@ ${statusEmoji} ${chalk.bold(session.name)}`);
1799
1885
  });
1800
1886
  for (const session of sessions) {
1801
1887
  const statusColor = session.status === "active" ? chalk.green : chalk.yellow;
1802
- const activeForks = session.forks.filter((f) => f.status === "active").length;
1803
- const savedForks = session.forks.filter((f) => f.status === "saved").length;
1804
- const mergedForks = session.forks.filter((f) => f.status === "merged").length;
1888
+ const forks = session.forks || [];
1889
+ const activeForks = forks.filter((f) => f.status === "active").length;
1890
+ const savedForks = forks.filter((f) => f.status === "saved").length;
1891
+ const mergedForks = forks.filter((f) => f.status === "merged").length;
1805
1892
  table.push([
1806
1893
  session.name,
1807
1894
  statusColor(session.status),
@@ -1879,10 +1966,11 @@ ${statusEmoji} ${chalk.bold(session.name)}`);
1879
1966
  console.log(
1880
1967
  ` ${chalk.green("Active:")} ${session.activeForks} | ${chalk.yellow("Saved:")} ${session.savedForks} | ${chalk.blue("Merged:")} ${session.mergedForks}`
1881
1968
  );
1882
- if (session.forks.length > 0) {
1969
+ const sessionForks = session.forks || [];
1970
+ if (sessionForks.length > 0) {
1883
1971
  console.log(`
1884
1972
  ${chalk.bold("Forks:")}`);
1885
- for (const fork of session.forks) {
1973
+ for (const fork of sessionForks) {
1886
1974
  const forkEmoji = fork.status === "active" ? "\u2713" : fork.status === "merged" ? "\u{1F500}" : "\u{1F4BE}";
1887
1975
  const forkColor = fork.status === "active" ? chalk.green : fork.status === "merged" ? chalk.blue : chalk.yellow;
1888
1976
  console.log(`
@@ -2012,7 +2100,8 @@ async function selectSession(sessions) {
2012
2100
  sessions.forEach((session, index2) => {
2013
2101
  const statusColor = session.status === "active" ? chalk3.green : chalk3.yellow;
2014
2102
  const status = statusColor(`[${session.status}]`);
2015
- const forkCount = session.forks.length > 0 ? chalk3.gray(` (${session.forks.length} forks)`) : "";
2103
+ const forks = session.forks || [];
2104
+ const forkCount = forks.length > 0 ? chalk3.gray(` (${forks.length} forks)`) : "";
2016
2105
  console.log(` ${chalk3.bold(index2 + 1)}. ${session.name || "Unnamed"} ${status}${forkCount}`);
2017
2106
  console.log(chalk3.gray(` ID: ${session.id.slice(0, 8)}...`));
2018
2107
  console.log();
@@ -2021,8 +2110,8 @@ async function selectSession(sessions) {
2021
2110
  input: process.stdin,
2022
2111
  output: process.stdout
2023
2112
  });
2024
- const answer = await new Promise((resolve) => {
2025
- rl.question(chalk3.cyan("Enter number (or q to quit): "), resolve);
2113
+ const answer = await new Promise((resolve2) => {
2114
+ rl.question(chalk3.cyan("Enter number (or q to quit): "), resolve2);
2026
2115
  });
2027
2116
  rl.close();
2028
2117
  if (answer.toLowerCase() === "q") {
@@ -2062,8 +2151,8 @@ async function selectClaudeSession(sessions) {
2062
2151
  input: process.stdin,
2063
2152
  output: process.stdout
2064
2153
  });
2065
- const answer = await new Promise((resolve) => {
2066
- rl.question(chalk3.cyan("Enter number (or q to quit): "), resolve);
2154
+ const answer = await new Promise((resolve2) => {
2155
+ rl.question(chalk3.cyan("Enter number (or q to quit): "), resolve2);
2067
2156
  });
2068
2157
  rl.close();
2069
2158
  if (answer.toLowerCase() === "q") {
@@ -2161,9 +2250,10 @@ function sessionCommand(program2) {
2161
2250
  Output.json(session2);
2162
2251
  } else {
2163
2252
  Output.session(session2);
2164
- if (session2.forks.length > 0) {
2253
+ const sessionForks = session2.forks || [];
2254
+ if (sessionForks.length > 0) {
2165
2255
  Output.section("\n\u{1F33F} Forks:");
2166
- for (const fork of session2.forks) {
2256
+ for (const fork of sessionForks) {
2167
2257
  Output.fork(fork);
2168
2258
  }
2169
2259
  }
@@ -2285,7 +2375,7 @@ function forkCommand(program2) {
2285
2375
  Output.error(`Session not found: ${sessionId}`);
2286
2376
  process.exit(1);
2287
2377
  }
2288
- let forks = session.forks;
2378
+ let forks = session.forks || [];
2289
2379
  if (options.status) {
2290
2380
  forks = forks.filter((f) => f.status === options.status);
2291
2381
  }
@@ -2699,8 +2789,8 @@ function prepareCommand(program2) {
2699
2789
  input: process.stdin,
2700
2790
  output: process.stdout
2701
2791
  });
2702
- const answer = await new Promise((resolve) => {
2703
- rl.question("Continue? (y/n): ", resolve);
2792
+ const answer = await new Promise((resolve2) => {
2793
+ rl.question("Continue? (y/n): ", resolve2);
2704
2794
  });
2705
2795
  rl.close();
2706
2796
  if (answer.toLowerCase() !== "y") {
@@ -2844,13 +2934,13 @@ async function checkClaudeCLI() {
2844
2934
  }
2845
2935
 
2846
2936
  // src/cli/index.ts
2847
- var __filename3 = fileURLToPath3(import.meta.url);
2848
- var __dirname3 = dirname3(__filename3);
2849
- var packageJsonPath = join2(__dirname3, "../package.json");
2937
+ var __filename4 = fileURLToPath4(import.meta.url);
2938
+ var __dirname4 = dirname3(__filename4);
2939
+ var packageJsonPath = join2(__dirname4, "../package.json");
2850
2940
  try {
2851
2941
  readFileSync(packageJsonPath, "utf-8");
2852
2942
  } catch {
2853
- packageJsonPath = join2(__dirname3, "../../package.json");
2943
+ packageJsonPath = join2(__dirname4, "../../package.json");
2854
2944
  }
2855
2945
  var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
2856
2946
  var version = packageJson.version;