@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.
- package/dist/cli.js +119 -31
- package/dist/electron/main/main.js +112 -21
- package/dist/electron/main/main.js.map +1 -1
- package/dist/electron/preload/preload.js +1 -0
- package/dist/electron/preload/preload.js.map +1 -1
- package/dist/electron/renderer/assets/main-BMC8JuEx.js +66 -0
- package/dist/electron/renderer/index.html +1 -1
- package/dist/src/cli/commands/fork.js +1 -1
- package/dist/src/cli/commands/fork.js.map +1 -1
- package/dist/src/cli/commands/session.d.ts.map +1 -1
- package/dist/src/cli/commands/session.js +5 -3
- package/dist/src/cli/commands/session.js.map +1 -1
- package/dist/src/cli/utils/output.d.ts.map +1 -1
- package/dist/src/cli/utils/output.js +13 -10
- package/dist/src/cli/utils/output.js.map +1 -1
- package/dist/src/core/ClaudeOrka.d.ts +10 -0
- package/dist/src/core/ClaudeOrka.d.ts.map +1 -1
- package/dist/src/core/ClaudeOrka.js +12 -0
- package/dist/src/core/ClaudeOrka.js.map +1 -1
- package/dist/src/core/SessionManager.d.ts +10 -0
- package/dist/src/core/SessionManager.d.ts.map +1 -1
- package/dist/src/core/SessionManager.js +27 -3
- package/dist/src/core/SessionManager.js.map +1 -1
- package/dist/src/core/StateManager.d.ts +5 -0
- package/dist/src/core/StateManager.d.ts.map +1 -1
- package/dist/src/core/StateManager.js +49 -0
- package/dist/src/core/StateManager.js.map +1 -1
- package/dist/src/models/Session.d.ts +9 -0
- package/dist/src/models/Session.d.ts.map +1 -1
- package/dist/src/utils/tmux.d.ts +1 -1
- package/dist/src/utils/tmux.d.ts.map +1 -1
- package/dist/src/utils/tmux.js +9 -5
- package/dist/src/utils/tmux.js.map +1 -1
- package/package.json +1 -1
- 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
|
|
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
|
|
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
|
|
819
|
-
var
|
|
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
|
|
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(
|
|
1464
|
+
path5.join(__dirname3, "./electron/main/main.js"),
|
|
1394
1465
|
// Via SDK: dist/src/core -> ../../electron/main/main.js
|
|
1395
|
-
path5.join(
|
|
1466
|
+
path5.join(__dirname3, "../../electron/main/main.js"),
|
|
1396
1467
|
// Development: src/core -> ../../dist/electron/main/main.js
|
|
1397
|
-
path5.join(
|
|
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: ${
|
|
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
|
-
|
|
1748
|
-
|
|
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:")} ${
|
|
1834
|
+
` ${chalk.green("Active:")} ${forks.filter((f) => f.status === "active").length}`
|
|
1751
1835
|
);
|
|
1752
1836
|
console.log(
|
|
1753
|
-
` ${chalk.yellow("Saved:")} ${
|
|
1837
|
+
` ${chalk.yellow("Saved:")} ${forks.filter((f) => f.status === "saved").length}`
|
|
1754
1838
|
);
|
|
1755
1839
|
console.log(
|
|
1756
|
-
` ${chalk.blue("Merged:")} ${
|
|
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
|
|
1805
|
-
const
|
|
1806
|
-
const
|
|
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
|
-
|
|
1969
|
+
const sessionForks = session.forks || [];
|
|
1970
|
+
if (sessionForks.length > 0) {
|
|
1885
1971
|
console.log(`
|
|
1886
1972
|
${chalk.bold("Forks:")}`);
|
|
1887
|
-
for (const fork of
|
|
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
|
|
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
|
-
|
|
2253
|
+
const sessionForks = session2.forks || [];
|
|
2254
|
+
if (sessionForks.length > 0) {
|
|
2167
2255
|
Output.section("\n\u{1F33F} Forks:");
|
|
2168
|
-
for (const fork of
|
|
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
|
|
2850
|
-
var
|
|
2851
|
-
var packageJsonPath = join2(
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
816
|
-
var
|
|
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
|
|
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(
|
|
1461
|
+
path5.join(__dirname3, "./electron/main/main.js"),
|
|
1391
1462
|
// Via SDK: dist/src/core -> ../../electron/main/main.js
|
|
1392
|
-
path5.join(
|
|
1463
|
+
path5.join(__dirname3, "../../electron/main/main.js"),
|
|
1393
1464
|
// Development: src/core -> ../../dist/electron/main/main.js
|
|
1394
|
-
path5.join(
|
|
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: ${
|
|
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
|
|
1691
|
-
var
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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");
|