@enruana/claude-orka 0.7.3 → 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 +119 -31
  2. package/dist/electron/main/main.js +112 -21
  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 +9 -5
  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,14 +114,19 @@ 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 = [
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
119
125
  // When installed globally via npm (dist/ -> package root)
120
126
  path2.join(__dirname, "../.tmux.orka.conf"),
121
127
  // When running from source (src/utils/ -> package root)
122
128
  path2.join(__dirname, "../../.tmux.orka.conf"),
123
- // When running from current working directory
129
+ // When running from current working directory (legacy)
124
130
  path2.join(process.cwd(), ".tmux.orka.conf")
125
131
  ];
126
132
  logger.debug(`Looking for Orka theme config. __dirname: ${__dirname}`);
@@ -502,6 +508,8 @@ async function listClaudeSessions(projectPath, limit = 20) {
502
508
  }
503
509
 
504
510
  // src/core/StateManager.ts
511
+ var __filename2 = fileURLToPath2(import.meta.url);
512
+ var __dirname2 = path4.dirname(__filename2);
505
513
  var StateManager = class {
506
514
  projectPath;
507
515
  orkaDir;
@@ -518,6 +526,7 @@ var StateManager = class {
518
526
  async initialize() {
519
527
  logger.debug("Initializing StateManager");
520
528
  await this.ensureDirectories();
529
+ await this.copyThemeConfig();
521
530
  if (!await fs4.pathExists(this.statePath)) {
522
531
  logger.info("Creating initial state.json");
523
532
  const initialState = {
@@ -530,6 +539,46 @@ var StateManager = class {
530
539
  }
531
540
  logger.info("StateManager initialized");
532
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
+ }
533
582
  /**
534
583
  * Create directory structure
535
584
  */
@@ -810,13 +859,13 @@ var StateManager = class {
810
859
  // src/core/SessionManager.ts
811
860
  import { v4 as uuidv4 } from "uuid";
812
861
  import path5 from "path";
813
- import { fileURLToPath as fileURLToPath2 } from "url";
862
+ import { fileURLToPath as fileURLToPath3 } from "url";
814
863
  import { dirname as dirname2 } from "path";
815
864
  import fs5 from "fs-extra";
816
865
  import { spawn } from "child_process";
817
866
  import execa2 from "execa";
818
- var __filename2 = fileURLToPath2(import.meta.url);
819
- var __dirname2 = dirname2(__filename2);
867
+ var __filename3 = fileURLToPath3(import.meta.url);
868
+ var __dirname3 = dirname2(__filename3);
820
869
  var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
821
870
  var SessionManager = class {
822
871
  stateManager;
@@ -925,7 +974,7 @@ var SessionManager = class {
925
974
  }
926
975
  logger.info(`Tmux session not found, recovering from Claude session...`);
927
976
  await TmuxCommands.createSession(tmuxSessionId, this.projectPath);
928
- await TmuxCommands.applyOrkaTheme(tmuxSessionId);
977
+ await TmuxCommands.applyOrkaTheme(tmuxSessionId, this.projectPath);
929
978
  if (openTerminal) {
930
979
  await TmuxCommands.openTerminalWindow(tmuxSessionId);
931
980
  }
@@ -942,7 +991,8 @@ var SessionManager = class {
942
991
  session.status = "active";
943
992
  session.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
944
993
  await this.stateManager.replaceSession(session);
945
- 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");
946
996
  if (forksToRestore.length > 0) {
947
997
  logger.info(`Restoring ${forksToRestore.length} fork(s)...`);
948
998
  for (const fork of forksToRestore) {
@@ -1337,6 +1387,27 @@ Analyze the content and help me integrate the changes and learnings from the for
1337
1387
  return await this.generateForkExport(sessionId, forkId);
1338
1388
  }
1339
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
+ // ==========================================
1340
1411
  // HELPERS PRIVADOS
1341
1412
  // ==========================================
1342
1413
  /**
@@ -1390,11 +1461,11 @@ Analyze the content and help me integrate the changes and learnings from the for
1390
1461
  }
1391
1462
  const possiblePaths = [
1392
1463
  // Via CLI (bundled): dist -> ./electron/main/main.js
1393
- path5.join(__dirname2, "./electron/main/main.js"),
1464
+ path5.join(__dirname3, "./electron/main/main.js"),
1394
1465
  // Via SDK: dist/src/core -> ../../electron/main/main.js
1395
- path5.join(__dirname2, "../../electron/main/main.js"),
1466
+ path5.join(__dirname3, "../../electron/main/main.js"),
1396
1467
  // Development: src/core -> ../../dist/electron/main/main.js
1397
- path5.join(__dirname2, "../../dist/electron/main/main.js")
1468
+ path5.join(__dirname3, "../../dist/electron/main/main.js")
1398
1469
  ];
1399
1470
  let mainPath = null;
1400
1471
  for (const p of possiblePaths) {
@@ -1408,7 +1479,7 @@ Analyze the content and help me integrate the changes and learnings from the for
1408
1479
  if (!mainPath) {
1409
1480
  const resolvedPaths = possiblePaths.map((p) => path5.resolve(p));
1410
1481
  logger.warn(`Electron main.js not found. Tried paths: ${resolvedPaths.join(", ")}`);
1411
- logger.warn(`Current __dirname: ${__dirname2}`);
1482
+ logger.warn(`Current __dirname: ${__dirname3}`);
1412
1483
  logger.warn("Skipping UI launch");
1413
1484
  return;
1414
1485
  }
@@ -1685,6 +1756,18 @@ var ClaudeOrka = class {
1685
1756
  await this.exportAndMerge(sessionId, forkId);
1686
1757
  await this.closeFork(sessionId, forkId);
1687
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
+ }
1688
1771
  };
1689
1772
 
1690
1773
  // src/cli/utils/output.ts
@@ -1744,16 +1827,17 @@ ${statusEmoji} ${chalk.bold(session.name)}`);
1744
1827
  if (session.status === "active") {
1745
1828
  console.log(` ${chalk.gray("Tmux Session:")} ${session.tmuxSessionId}`);
1746
1829
  }
1747
- if (session.forks.length > 0) {
1748
- 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}`);
1749
1833
  console.log(
1750
- ` ${chalk.green("Active:")} ${session.forks.filter((f) => f.status === "active").length}`
1834
+ ` ${chalk.green("Active:")} ${forks.filter((f) => f.status === "active").length}`
1751
1835
  );
1752
1836
  console.log(
1753
- ` ${chalk.yellow("Saved:")} ${session.forks.filter((f) => f.status === "saved").length}`
1837
+ ` ${chalk.yellow("Saved:")} ${forks.filter((f) => f.status === "saved").length}`
1754
1838
  );
1755
1839
  console.log(
1756
- ` ${chalk.blue("Merged:")} ${session.forks.filter((f) => f.status === "merged").length}`
1840
+ ` ${chalk.blue("Merged:")} ${forks.filter((f) => f.status === "merged").length}`
1757
1841
  );
1758
1842
  }
1759
1843
  }
@@ -1801,9 +1885,10 @@ ${statusEmoji} ${chalk.bold(session.name)}`);
1801
1885
  });
1802
1886
  for (const session of sessions) {
1803
1887
  const statusColor = session.status === "active" ? chalk.green : chalk.yellow;
1804
- const activeForks = session.forks.filter((f) => f.status === "active").length;
1805
- const savedForks = session.forks.filter((f) => f.status === "saved").length;
1806
- 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;
1807
1892
  table.push([
1808
1893
  session.name,
1809
1894
  statusColor(session.status),
@@ -1881,10 +1966,11 @@ ${statusEmoji} ${chalk.bold(session.name)}`);
1881
1966
  console.log(
1882
1967
  ` ${chalk.green("Active:")} ${session.activeForks} | ${chalk.yellow("Saved:")} ${session.savedForks} | ${chalk.blue("Merged:")} ${session.mergedForks}`
1883
1968
  );
1884
- if (session.forks.length > 0) {
1969
+ const sessionForks = session.forks || [];
1970
+ if (sessionForks.length > 0) {
1885
1971
  console.log(`
1886
1972
  ${chalk.bold("Forks:")}`);
1887
- for (const fork of session.forks) {
1973
+ for (const fork of sessionForks) {
1888
1974
  const forkEmoji = fork.status === "active" ? "\u2713" : fork.status === "merged" ? "\u{1F500}" : "\u{1F4BE}";
1889
1975
  const forkColor = fork.status === "active" ? chalk.green : fork.status === "merged" ? chalk.blue : chalk.yellow;
1890
1976
  console.log(`
@@ -2014,7 +2100,8 @@ async function selectSession(sessions) {
2014
2100
  sessions.forEach((session, index2) => {
2015
2101
  const statusColor = session.status === "active" ? chalk3.green : chalk3.yellow;
2016
2102
  const status = statusColor(`[${session.status}]`);
2017
- 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)`) : "";
2018
2105
  console.log(` ${chalk3.bold(index2 + 1)}. ${session.name || "Unnamed"} ${status}${forkCount}`);
2019
2106
  console.log(chalk3.gray(` ID: ${session.id.slice(0, 8)}...`));
2020
2107
  console.log();
@@ -2163,9 +2250,10 @@ function sessionCommand(program2) {
2163
2250
  Output.json(session2);
2164
2251
  } else {
2165
2252
  Output.session(session2);
2166
- if (session2.forks.length > 0) {
2253
+ const sessionForks = session2.forks || [];
2254
+ if (sessionForks.length > 0) {
2167
2255
  Output.section("\n\u{1F33F} Forks:");
2168
- for (const fork of session2.forks) {
2256
+ for (const fork of sessionForks) {
2169
2257
  Output.fork(fork);
2170
2258
  }
2171
2259
  }
@@ -2287,7 +2375,7 @@ function forkCommand(program2) {
2287
2375
  Output.error(`Session not found: ${sessionId}`);
2288
2376
  process.exit(1);
2289
2377
  }
2290
- let forks = session.forks;
2378
+ let forks = session.forks || [];
2291
2379
  if (options.status) {
2292
2380
  forks = forks.filter((f) => f.status === options.status);
2293
2381
  }
@@ -2846,13 +2934,13 @@ async function checkClaudeCLI() {
2846
2934
  }
2847
2935
 
2848
2936
  // src/cli/index.ts
2849
- var __filename3 = fileURLToPath3(import.meta.url);
2850
- var __dirname3 = dirname3(__filename3);
2851
- 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");
2852
2940
  try {
2853
2941
  readFileSync(packageJsonPath, "utf-8");
2854
2942
  } catch {
2855
- packageJsonPath = join2(__dirname3, "../../package.json");
2943
+ packageJsonPath = join2(__dirname4, "../../package.json");
2856
2944
  }
2857
2945
  var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
2858
2946
  var version = packageJson.version;
@@ -1,11 +1,12 @@
1
1
  // electron/main/main.ts
2
2
  import { app, BrowserWindow, ipcMain, shell, screen } from "electron";
3
3
  import path6 from "path";
4
- import { fileURLToPath as fileURLToPath3 } from "url";
4
+ import { fileURLToPath as fileURLToPath4 } from "url";
5
5
 
6
6
  // src/core/StateManager.ts
7
7
  import path4 from "path";
8
8
  import fs4 from "fs-extra";
9
+ import { fileURLToPath as fileURLToPath2 } from "url";
9
10
 
10
11
  // src/utils/tmux.ts
11
12
  import execa from "execa";
@@ -98,7 +99,7 @@ var TmuxCommands = class {
98
99
  logger.debug(`Creating tmux session: ${name} at ${projectPath}`);
99
100
  await execa("tmux", ["new-session", "-d", "-s", name, "-c", projectPath]);
100
101
  logger.info(`Tmux session created: ${name}`);
101
- await this.applyOrkaTheme(name);
102
+ await this.applyOrkaTheme(name, projectPath);
102
103
  } catch (error) {
103
104
  throw new TmuxError(
104
105
  `Failed to create tmux session: ${name}`,
@@ -110,14 +111,19 @@ var TmuxCommands = class {
110
111
  /**
111
112
  * Apply Claude-Orka custom tmux theme to a session
112
113
  */
113
- static async applyOrkaTheme(sessionName) {
114
+ static async applyOrkaTheme(sessionName, projectPath) {
114
115
  try {
115
116
  const possiblePaths = [
117
+ // PRIORITY 1: Project-local theme (copied during orka init)
118
+ ...projectPath ? [path2.join(projectPath, ".claude-orka", ".tmux.orka.conf")] : [],
119
+ // PRIORITY 2: Current working directory project
120
+ path2.join(process.cwd(), ".claude-orka", ".tmux.orka.conf"),
121
+ // FALLBACK: Package installation paths
116
122
  // When installed globally via npm (dist/ -> package root)
117
123
  path2.join(__dirname, "../.tmux.orka.conf"),
118
124
  // When running from source (src/utils/ -> package root)
119
125
  path2.join(__dirname, "../../.tmux.orka.conf"),
120
- // When running from current working directory
126
+ // When running from current working directory (legacy)
121
127
  path2.join(process.cwd(), ".tmux.orka.conf")
122
128
  ];
123
129
  logger.debug(`Looking for Orka theme config. __dirname: ${__dirname}`);
@@ -499,6 +505,8 @@ async function listClaudeSessions(projectPath, limit = 20) {
499
505
  }
500
506
 
501
507
  // src/core/StateManager.ts
508
+ var __filename2 = fileURLToPath2(import.meta.url);
509
+ var __dirname2 = path4.dirname(__filename2);
502
510
  var StateManager = class {
503
511
  projectPath;
504
512
  orkaDir;
@@ -515,6 +523,7 @@ var StateManager = class {
515
523
  async initialize() {
516
524
  logger.debug("Initializing StateManager");
517
525
  await this.ensureDirectories();
526
+ await this.copyThemeConfig();
518
527
  if (!await fs4.pathExists(this.statePath)) {
519
528
  logger.info("Creating initial state.json");
520
529
  const initialState = {
@@ -527,6 +536,46 @@ var StateManager = class {
527
536
  }
528
537
  logger.info("StateManager initialized");
529
538
  }
539
+ /**
540
+ * Copy tmux theme config to project's .claude-orka directory
541
+ * This ensures the theme persists across system restarts
542
+ */
543
+ async copyThemeConfig() {
544
+ const destPath = path4.join(this.orkaDir, ".tmux.orka.conf");
545
+ if (await fs4.pathExists(destPath)) {
546
+ logger.debug("Theme config already exists in project");
547
+ return;
548
+ }
549
+ const possibleSources = [
550
+ // When running from dist/ (bundled CLI)
551
+ path4.join(__dirname2, "../.tmux.orka.conf"),
552
+ // When running from src/core/ (development)
553
+ path4.join(__dirname2, "../../.tmux.orka.conf"),
554
+ // Fallback: look in node_modules (when used as dependency)
555
+ path4.join(__dirname2, "../../../.tmux.orka.conf")
556
+ ];
557
+ logger.debug(`Looking for tmux theme. __dirname: ${__dirname2}`);
558
+ let sourcePath = null;
559
+ for (const p of possibleSources) {
560
+ const resolved = path4.resolve(p);
561
+ const exists = await fs4.pathExists(resolved);
562
+ logger.debug(` Checking ${resolved}: ${exists ? "EXISTS" : "not found"}`);
563
+ if (exists) {
564
+ sourcePath = resolved;
565
+ break;
566
+ }
567
+ }
568
+ if (!sourcePath) {
569
+ logger.warn("Could not find tmux theme source file to copy");
570
+ return;
571
+ }
572
+ try {
573
+ await fs4.copy(sourcePath, destPath);
574
+ logger.info(`Tmux theme copied to ${destPath}`);
575
+ } catch (error) {
576
+ logger.warn(`Failed to copy tmux theme: ${error.message}`);
577
+ }
578
+ }
530
579
  /**
531
580
  * Create directory structure
532
581
  */
@@ -807,13 +856,13 @@ var StateManager = class {
807
856
  // src/core/SessionManager.ts
808
857
  import { v4 as uuidv4 } from "uuid";
809
858
  import path5 from "path";
810
- import { fileURLToPath as fileURLToPath2 } from "url";
859
+ import { fileURLToPath as fileURLToPath3 } from "url";
811
860
  import { dirname as dirname2 } from "path";
812
861
  import fs5 from "fs-extra";
813
862
  import { spawn } from "child_process";
814
863
  import execa2 from "execa";
815
- var __filename2 = fileURLToPath2(import.meta.url);
816
- var __dirname2 = dirname2(__filename2);
864
+ var __filename3 = fileURLToPath3(import.meta.url);
865
+ var __dirname3 = dirname2(__filename3);
817
866
  var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
818
867
  var SessionManager = class {
819
868
  stateManager;
@@ -922,7 +971,7 @@ var SessionManager = class {
922
971
  }
923
972
  logger.info(`Tmux session not found, recovering from Claude session...`);
924
973
  await TmuxCommands.createSession(tmuxSessionId, this.projectPath);
925
- await TmuxCommands.applyOrkaTheme(tmuxSessionId);
974
+ await TmuxCommands.applyOrkaTheme(tmuxSessionId, this.projectPath);
926
975
  if (openTerminal) {
927
976
  await TmuxCommands.openTerminalWindow(tmuxSessionId);
928
977
  }
@@ -939,7 +988,8 @@ var SessionManager = class {
939
988
  session.status = "active";
940
989
  session.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
941
990
  await this.stateManager.replaceSession(session);
942
- const forksToRestore = session.forks.filter((f) => f.status !== "merged");
991
+ const forks = session.forks || [];
992
+ const forksToRestore = forks.filter((f) => f.status === "active" || f.status === "saved");
943
993
  if (forksToRestore.length > 0) {
944
994
  logger.info(`Restoring ${forksToRestore.length} fork(s)...`);
945
995
  for (const fork of forksToRestore) {
@@ -1334,6 +1384,27 @@ Analyze the content and help me integrate the changes and learnings from the for
1334
1384
  return await this.generateForkExport(sessionId, forkId);
1335
1385
  }
1336
1386
  // ==========================================
1387
+ // UI METHODS
1388
+ // ==========================================
1389
+ /**
1390
+ * Save node position for UI persistence
1391
+ * @param sessionId Session ID
1392
+ * @param nodeId Node ID ('main' or fork id)
1393
+ * @param position Position {x, y}
1394
+ */
1395
+ async saveNodePosition(sessionId, nodeId, position) {
1396
+ const session = await this.getSession(sessionId);
1397
+ if (!session) {
1398
+ throw new Error(`Session ${sessionId} not found`);
1399
+ }
1400
+ if (!session.nodePositions) {
1401
+ session.nodePositions = {};
1402
+ }
1403
+ session.nodePositions[nodeId] = position;
1404
+ await this.stateManager.replaceSession(session);
1405
+ logger.debug(`Node position saved: ${nodeId} -> (${position.x}, ${position.y})`);
1406
+ }
1407
+ // ==========================================
1337
1408
  // HELPERS PRIVADOS
1338
1409
  // ==========================================
1339
1410
  /**
@@ -1387,11 +1458,11 @@ Analyze the content and help me integrate the changes and learnings from the for
1387
1458
  }
1388
1459
  const possiblePaths = [
1389
1460
  // Via CLI (bundled): dist -> ./electron/main/main.js
1390
- path5.join(__dirname2, "./electron/main/main.js"),
1461
+ path5.join(__dirname3, "./electron/main/main.js"),
1391
1462
  // Via SDK: dist/src/core -> ../../electron/main/main.js
1392
- path5.join(__dirname2, "../../electron/main/main.js"),
1463
+ path5.join(__dirname3, "../../electron/main/main.js"),
1393
1464
  // Development: src/core -> ../../dist/electron/main/main.js
1394
- path5.join(__dirname2, "../../dist/electron/main/main.js")
1465
+ path5.join(__dirname3, "../../dist/electron/main/main.js")
1395
1466
  ];
1396
1467
  let mainPath = null;
1397
1468
  for (const p of possiblePaths) {
@@ -1405,7 +1476,7 @@ Analyze the content and help me integrate the changes and learnings from the for
1405
1476
  if (!mainPath) {
1406
1477
  const resolvedPaths = possiblePaths.map((p) => path5.resolve(p));
1407
1478
  logger.warn(`Electron main.js not found. Tried paths: ${resolvedPaths.join(", ")}`);
1408
- logger.warn(`Current __dirname: ${__dirname2}`);
1479
+ logger.warn(`Current __dirname: ${__dirname3}`);
1409
1480
  logger.warn("Skipping UI launch");
1410
1481
  return;
1411
1482
  }
@@ -1682,13 +1753,25 @@ var ClaudeOrka = class {
1682
1753
  await this.exportAndMerge(sessionId, forkId);
1683
1754
  await this.closeFork(sessionId, forkId);
1684
1755
  }
1756
+ // ==========================================
1757
+ // UI METHODS
1758
+ // ==========================================
1759
+ /**
1760
+ * Save node position for UI persistence
1761
+ * @param sessionId Session ID
1762
+ * @param nodeId Node ID ('main' or fork id)
1763
+ * @param position Position {x, y}
1764
+ */
1765
+ async saveNodePosition(sessionId, nodeId, position) {
1766
+ await this.sessionManager.saveNodePosition(sessionId, nodeId, position);
1767
+ }
1685
1768
  };
1686
1769
 
1687
1770
  // electron/main/main.ts
1688
1771
  import chokidar from "chokidar";
1689
1772
  import execa3 from "execa";
1690
- var __filename3 = fileURLToPath3(import.meta.url);
1691
- var __dirname3 = path6.dirname(__filename3);
1773
+ var __filename4 = fileURLToPath4(import.meta.url);
1774
+ var __dirname4 = path6.dirname(__filename4);
1692
1775
  var windows = /* @__PURE__ */ new Map();
1693
1776
  var taskbarWindows = /* @__PURE__ */ new Map();
1694
1777
  var currentSessionId = null;
@@ -1700,7 +1783,7 @@ function createWindow(sessionId, projectPath) {
1700
1783
  return existingWindow;
1701
1784
  }
1702
1785
  const projectName = path6.basename(projectPath);
1703
- const iconPath = path6.join(__dirname3, "../../../public/icon.png");
1786
+ const iconPath = path6.join(__dirname4, "../../../public/icon.png");
1704
1787
  const mainWindow = new BrowserWindow({
1705
1788
  width: 600,
1706
1789
  height: 800,
@@ -1713,7 +1796,7 @@ function createWindow(sessionId, projectPath) {
1713
1796
  title: `Claude Orka - ${projectName}`,
1714
1797
  icon: iconPath,
1715
1798
  webPreferences: {
1716
- preload: path6.join(__dirname3, "../preload/preload.js"),
1799
+ preload: path6.join(__dirname4, "../preload/preload.js"),
1717
1800
  contextIsolation: true,
1718
1801
  nodeIntegration: false
1719
1802
  }
@@ -1723,7 +1806,7 @@ function createWindow(sessionId, projectPath) {
1723
1806
  if (process.env.NODE_ENV === "development") {
1724
1807
  mainWindow.loadURL("http://localhost:5173");
1725
1808
  } else {
1726
- const indexPath = path6.join(__dirname3, "../renderer/index.html");
1809
+ const indexPath = path6.join(__dirname4, "../renderer/index.html");
1727
1810
  mainWindow.loadFile(indexPath);
1728
1811
  }
1729
1812
  watchStateFile(projectPath, mainWindow);
@@ -1749,7 +1832,7 @@ function createTaskbarWindow(projectPath) {
1749
1832
  const primaryDisplay = screen.getPrimaryDisplay();
1750
1833
  const { width, height } = primaryDisplay.workAreaSize;
1751
1834
  console.log("[Taskbar] Screen size:", width, "x", height);
1752
- const iconPath = path6.join(__dirname3, "../../../public/icon.png");
1835
+ const iconPath = path6.join(__dirname4, "../../../public/icon.png");
1753
1836
  const taskbarWindow = new BrowserWindow({
1754
1837
  width: 80,
1755
1838
  height: 220,
@@ -1767,7 +1850,7 @@ function createTaskbarWindow(projectPath) {
1767
1850
  movable: true,
1768
1851
  icon: iconPath,
1769
1852
  webPreferences: {
1770
- preload: path6.join(__dirname3, "../preload/preload.js"),
1853
+ preload: path6.join(__dirname4, "../preload/preload.js"),
1771
1854
  contextIsolation: true,
1772
1855
  nodeIntegration: false
1773
1856
  }
@@ -1776,7 +1859,7 @@ function createTaskbarWindow(projectPath) {
1776
1859
  console.log("[Taskbar] Loading from dev server: http://localhost:5173/taskbar.html");
1777
1860
  taskbarWindow.loadURL("http://localhost:5173/taskbar.html");
1778
1861
  } else {
1779
- const taskbarPath = path6.join(__dirname3, "../renderer/taskbar.html");
1862
+ const taskbarPath = path6.join(__dirname4, "../renderer/taskbar.html");
1780
1863
  console.log("[Taskbar] Loading from file:", taskbarPath);
1781
1864
  taskbarWindow.loadFile(taskbarPath);
1782
1865
  }
@@ -1894,6 +1977,14 @@ ipcMain.handle("close-fork", async (_, sessionId, forkId) => {
1894
1977
  await orka.initialize();
1895
1978
  await orka.closeFork(sessionId, forkId);
1896
1979
  });
1980
+ ipcMain.handle("save-node-position", async (_, sessionId, nodeId, position) => {
1981
+ if (!currentProjectPath) {
1982
+ throw new Error("No active project");
1983
+ }
1984
+ const orka = new ClaudeOrka(currentProjectPath);
1985
+ await orka.initialize();
1986
+ await orka.saveNodePosition(sessionId, nodeId, position);
1987
+ });
1897
1988
  ipcMain.handle("open-export-file", async (_, exportPath) => {
1898
1989
  if (!currentProjectPath) {
1899
1990
  throw new Error("No active project");