workon 3.2.1 → 3.2.2

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 CHANGED
@@ -345,18 +345,22 @@ var init_cwd = __esm({
345
345
  const { project, isShellMode, shellCommands } = context;
346
346
  const projectPath = project.path.path;
347
347
  if (isShellMode) {
348
- shellCommands.push(`cd "${projectPath}"`);
348
+ shellCommands.push(`pushd "${projectPath}" > /dev/null`);
349
349
  } else {
350
350
  const shell = process.env.SHELL || "/bin/bash";
351
- spawn(shell, [], {
351
+ const child = spawn(shell, ["-i"], {
352
352
  cwd: projectPath,
353
353
  stdio: "inherit"
354
354
  });
355
+ await new Promise((resolve2, reject) => {
356
+ child.on("close", () => resolve2());
357
+ child.on("error", (err) => reject(err));
358
+ });
355
359
  }
356
360
  },
357
361
  generateShellCommand(context) {
358
362
  const projectPath = context.project.path.path;
359
- return [`cd "${projectPath}"`];
363
+ return [`pushd "${projectPath}" > /dev/null`];
360
364
  }
361
365
  };
362
366
  }
@@ -421,7 +425,7 @@ var init_ide = __esm({
421
425
  const projectPath = project.path.path;
422
426
  const ide = project.ide || "code";
423
427
  if (isShellMode) {
424
- shellCommands.push(`${ide} "${projectPath}" &`);
428
+ shellCommands.push(`set +m; ${ide} "${projectPath}" &>/dev/null &`);
425
429
  } else {
426
430
  spawn2(ide, [projectPath], {
427
431
  detached: true,
@@ -432,7 +436,7 @@ var init_ide = __esm({
432
436
  generateShellCommand(context) {
433
437
  const projectPath = context.project.path.path;
434
438
  const ide = context.project.ide || "code";
435
- return [`${ide} "${projectPath}" &`];
439
+ return [`set +m; ${ide} "${projectPath}" &>/dev/null &`];
436
440
  }
437
441
  };
438
442
  }
@@ -1094,12 +1098,213 @@ var init_registry = __esm({
1094
1098
  }
1095
1099
  });
1096
1100
 
1101
+ // src/lib/sanitize.ts
1102
+ function sanitizeForShell(input6) {
1103
+ if (!input6) return "";
1104
+ return input6.replace(/[^a-zA-Z0-9_\-.]/g, "_");
1105
+ }
1106
+ function escapeForSingleQuotes(input6) {
1107
+ if (!input6) return "";
1108
+ return input6.replace(/'/g, "'\\''");
1109
+ }
1110
+ var init_sanitize = __esm({
1111
+ "src/lib/sanitize.ts"() {
1112
+ "use strict";
1113
+ }
1114
+ });
1115
+
1116
+ // src/lib/tmux.ts
1117
+ import { exec as execCallback, spawn as spawn7 } from "child_process";
1118
+ import { promisify } from "util";
1119
+ var exec, TmuxManager;
1120
+ var init_tmux = __esm({
1121
+ "src/lib/tmux.ts"() {
1122
+ "use strict";
1123
+ init_sanitize();
1124
+ exec = promisify(execCallback);
1125
+ TmuxManager = class {
1126
+ sessionPrefix = "workon-";
1127
+ async isTmuxAvailable() {
1128
+ try {
1129
+ await exec("which tmux");
1130
+ return true;
1131
+ } catch {
1132
+ return false;
1133
+ }
1134
+ }
1135
+ async sessionExists(sessionName) {
1136
+ try {
1137
+ await exec(`tmux has-session -t '${escapeForSingleQuotes(sessionName)}'`);
1138
+ return true;
1139
+ } catch {
1140
+ return false;
1141
+ }
1142
+ }
1143
+ getSessionName(projectName) {
1144
+ return `${this.sessionPrefix}${sanitizeForShell(projectName)}`;
1145
+ }
1146
+ async killSession(sessionName) {
1147
+ try {
1148
+ await exec(`tmux kill-session -t '${escapeForSingleQuotes(sessionName)}'`);
1149
+ return true;
1150
+ } catch {
1151
+ return false;
1152
+ }
1153
+ }
1154
+ async createSplitSession(projectName, projectPath, claudeArgs = []) {
1155
+ const sessionName = this.getSessionName(projectName);
1156
+ const escapedSession = escapeForSingleQuotes(sessionName);
1157
+ const escapedPath = escapeForSingleQuotes(projectPath);
1158
+ if (await this.sessionExists(sessionName)) {
1159
+ await this.killSession(sessionName);
1160
+ }
1161
+ const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
1162
+ const escapedClaudeCmd = escapeForSingleQuotes(claudeCommand);
1163
+ await exec(
1164
+ `tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${escapedClaudeCmd}'`
1165
+ );
1166
+ await exec(`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`);
1167
+ await exec(`tmux select-pane -t '${escapedSession}:0.0'`);
1168
+ return sessionName;
1169
+ }
1170
+ async createThreePaneSession(projectName, projectPath, claudeArgs = [], npmCommand = "npm run dev") {
1171
+ const sessionName = this.getSessionName(projectName);
1172
+ const escapedSession = escapeForSingleQuotes(sessionName);
1173
+ const escapedPath = escapeForSingleQuotes(projectPath);
1174
+ if (await this.sessionExists(sessionName)) {
1175
+ await this.killSession(sessionName);
1176
+ }
1177
+ const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
1178
+ const escapedClaudeCmd = escapeForSingleQuotes(claudeCommand);
1179
+ const escapedNpmCmd = escapeForSingleQuotes(npmCommand);
1180
+ await exec(
1181
+ `tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${escapedClaudeCmd}'`
1182
+ );
1183
+ await exec(`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`);
1184
+ await exec(
1185
+ `tmux split-window -v -t '${escapedSession}:0.1' -c '${escapedPath}' '${escapedNpmCmd}'`
1186
+ );
1187
+ await exec(`tmux set-option -t '${escapedSession}:0.2' remain-on-exit on`);
1188
+ await exec(`tmux resize-pane -t '${escapedSession}:0.2' -y 10`);
1189
+ await exec(`tmux select-pane -t '${escapedSession}:0.0'`);
1190
+ return sessionName;
1191
+ }
1192
+ async createTwoPaneNpmSession(projectName, projectPath, npmCommand = "npm run dev") {
1193
+ const sessionName = this.getSessionName(projectName);
1194
+ const escapedSession = escapeForSingleQuotes(sessionName);
1195
+ const escapedPath = escapeForSingleQuotes(projectPath);
1196
+ const escapedNpmCmd = escapeForSingleQuotes(npmCommand);
1197
+ if (await this.sessionExists(sessionName)) {
1198
+ await this.killSession(sessionName);
1199
+ }
1200
+ await exec(`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}'`);
1201
+ await exec(
1202
+ `tmux split-window -h -t '${escapedSession}' -c '${escapedPath}' '${escapedNpmCmd}'`
1203
+ );
1204
+ await exec(`tmux set-option -t '${escapedSession}:0.1' remain-on-exit on`);
1205
+ await exec(`tmux select-pane -t '${escapedSession}:0.0'`);
1206
+ return sessionName;
1207
+ }
1208
+ async attachToSession(sessionName) {
1209
+ const escapedSession = escapeForSingleQuotes(sessionName);
1210
+ if (process.env.TMUX) {
1211
+ await exec(`tmux switch-client -t '${escapedSession}'`);
1212
+ } else {
1213
+ const isITerm = process.env.TERM_PROGRAM === "iTerm.app" || process.env.LC_TERMINAL === "iTerm2" || !!process.env.ITERM_SESSION_ID;
1214
+ const useiTermIntegration = isITerm && !process.env.TMUX_CC_NOT_SUPPORTED;
1215
+ if (useiTermIntegration) {
1216
+ spawn7("tmux", ["-CC", "attach-session", "-t", sessionName], {
1217
+ stdio: "inherit",
1218
+ detached: true
1219
+ });
1220
+ } else {
1221
+ spawn7("tmux", ["attach-session", "-t", sessionName], {
1222
+ stdio: "inherit",
1223
+ detached: true
1224
+ });
1225
+ }
1226
+ }
1227
+ }
1228
+ buildShellCommands(projectName, projectPath, claudeArgs = []) {
1229
+ const sessionName = this.getSessionName(projectName);
1230
+ const escapedSession = escapeForSingleQuotes(sessionName);
1231
+ const escapedPath = escapeForSingleQuotes(projectPath);
1232
+ const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
1233
+ const escapedClaudeCmd = escapeForSingleQuotes(claudeCommand);
1234
+ return [
1235
+ `# Create tmux split session for ${sanitizeForShell(projectName)}`,
1236
+ `tmux has-session -t '${escapedSession}' 2>/dev/null && tmux kill-session -t '${escapedSession}'`,
1237
+ `tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${escapedClaudeCmd}'`,
1238
+ `tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`,
1239
+ `tmux select-pane -t '${escapedSession}:0.0'`,
1240
+ this.getAttachCommand(sessionName)
1241
+ ];
1242
+ }
1243
+ buildThreePaneShellCommands(projectName, projectPath, claudeArgs = [], npmCommand = "npm run dev") {
1244
+ const sessionName = this.getSessionName(projectName);
1245
+ const escapedSession = escapeForSingleQuotes(sessionName);
1246
+ const escapedPath = escapeForSingleQuotes(projectPath);
1247
+ const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
1248
+ const escapedClaudeCmd = escapeForSingleQuotes(claudeCommand);
1249
+ const escapedNpmCmd = escapeForSingleQuotes(npmCommand);
1250
+ return [
1251
+ `# Create tmux three-pane session for ${sanitizeForShell(projectName)}`,
1252
+ `tmux has-session -t '${escapedSession}' 2>/dev/null && tmux kill-session -t '${escapedSession}'`,
1253
+ `tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${escapedClaudeCmd}'`,
1254
+ `tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`,
1255
+ `tmux split-window -v -t '${escapedSession}:0.1' -c '${escapedPath}' '${escapedNpmCmd}'`,
1256
+ `tmux set-option -t '${escapedSession}:0.2' remain-on-exit on`,
1257
+ `tmux resize-pane -t '${escapedSession}:0.2' -y 10`,
1258
+ `tmux select-pane -t '${escapedSession}:0.0'`,
1259
+ this.getAttachCommand(sessionName)
1260
+ ];
1261
+ }
1262
+ buildTwoPaneNpmShellCommands(projectName, projectPath, npmCommand = "npm run dev") {
1263
+ const sessionName = this.getSessionName(projectName);
1264
+ const escapedSession = escapeForSingleQuotes(sessionName);
1265
+ const escapedPath = escapeForSingleQuotes(projectPath);
1266
+ const escapedNpmCmd = escapeForSingleQuotes(npmCommand);
1267
+ return [
1268
+ `# Create tmux two-pane session with npm for ${sanitizeForShell(projectName)}`,
1269
+ `tmux has-session -t '${escapedSession}' 2>/dev/null && tmux kill-session -t '${escapedSession}'`,
1270
+ `tmux new-session -d -s '${escapedSession}' -c '${escapedPath}'`,
1271
+ `tmux split-window -h -t '${escapedSession}' -c '${escapedPath}' '${escapedNpmCmd}'`,
1272
+ `tmux set-option -t '${escapedSession}:0.1' remain-on-exit on`,
1273
+ `tmux select-pane -t '${escapedSession}:0.0'`,
1274
+ this.getAttachCommand(sessionName)
1275
+ ];
1276
+ }
1277
+ getAttachCommand(sessionName) {
1278
+ const escapedSession = escapeForSingleQuotes(sessionName);
1279
+ if (process.env.TMUX) {
1280
+ return `tmux switch-client -t '${escapedSession}'`;
1281
+ }
1282
+ const isITerm = process.env.TERM_PROGRAM === "iTerm.app" || process.env.LC_TERMINAL === "iTerm2" || process.env.ITERM_SESSION_ID;
1283
+ const useiTermIntegration = isITerm && !process.env.TMUX_CC_NOT_SUPPORTED;
1284
+ if (useiTermIntegration) {
1285
+ return `tmux -CC attach-session -t '${escapedSession}'`;
1286
+ }
1287
+ return `tmux attach-session -t '${escapedSession}'`;
1288
+ }
1289
+ async listWorkonSessions() {
1290
+ try {
1291
+ const { stdout } = await exec('tmux list-sessions -F "#{session_name}"');
1292
+ return stdout.trim().split("\n").filter((session) => session.startsWith(this.sessionPrefix)).map((session) => session.replace(this.sessionPrefix, ""));
1293
+ } catch {
1294
+ return [];
1295
+ }
1296
+ }
1297
+ };
1298
+ }
1299
+ });
1300
+
1097
1301
  // src/types/constants.ts
1098
1302
  var IDE_CHOICES;
1099
1303
  var init_constants = __esm({
1100
1304
  "src/types/constants.ts"() {
1101
1305
  "use strict";
1102
1306
  IDE_CHOICES = [
1307
+ { name: "Cursor", value: "cursor" },
1103
1308
  { name: "Visual Studio Code", value: "vscode" },
1104
1309
  { name: "Visual Studio Code (code)", value: "code" },
1105
1310
  { name: "IntelliJ IDEA", value: "idea" },
@@ -1732,215 +1937,21 @@ var init_interactive = __esm({
1732
1937
  }
1733
1938
  });
1734
1939
 
1735
- // src/commands/index.ts
1736
- init_config();
1737
- init_environment();
1738
- init_registry();
1739
- import { Command as Command8 } from "commander";
1740
- import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
1741
- import { join, dirname } from "path";
1742
- import { fileURLToPath } from "url";
1743
- import loog from "loog";
1744
- import omelette from "omelette";
1745
- import File7 from "phylo";
1746
-
1747
1940
  // src/commands/open.ts
1748
- init_environment();
1941
+ var open_exports = {};
1942
+ __export(open_exports, {
1943
+ createOpenCommand: () => createOpenCommand,
1944
+ runOpen: () => runOpen
1945
+ });
1749
1946
  import { Command } from "commander";
1750
1947
  import File4 from "phylo";
1751
-
1752
- // src/lib/tmux.ts
1753
- import { exec as execCallback, spawn as spawn7 } from "child_process";
1754
- import { promisify } from "util";
1755
-
1756
- // src/lib/sanitize.ts
1757
- function sanitizeForShell(input6) {
1758
- if (!input6) return "";
1759
- return input6.replace(/[^a-zA-Z0-9_\-.]/g, "_");
1760
- }
1761
- function escapeForSingleQuotes(input6) {
1762
- if (!input6) return "";
1763
- return input6.replace(/'/g, "'\\''");
1764
- }
1765
-
1766
- // src/lib/tmux.ts
1767
- var exec = promisify(execCallback);
1768
- var TmuxManager = class {
1769
- sessionPrefix = "workon-";
1770
- async isTmuxAvailable() {
1771
- try {
1772
- await exec("which tmux");
1773
- return true;
1774
- } catch {
1775
- return false;
1776
- }
1777
- }
1778
- async sessionExists(sessionName) {
1779
- try {
1780
- await exec(`tmux has-session -t '${escapeForSingleQuotes(sessionName)}'`);
1781
- return true;
1782
- } catch {
1783
- return false;
1784
- }
1785
- }
1786
- getSessionName(projectName) {
1787
- return `${this.sessionPrefix}${sanitizeForShell(projectName)}`;
1788
- }
1789
- async killSession(sessionName) {
1790
- try {
1791
- await exec(`tmux kill-session -t '${escapeForSingleQuotes(sessionName)}'`);
1792
- return true;
1793
- } catch {
1794
- return false;
1795
- }
1796
- }
1797
- async createSplitSession(projectName, projectPath, claudeArgs = []) {
1798
- const sessionName = this.getSessionName(projectName);
1799
- const escapedSession = escapeForSingleQuotes(sessionName);
1800
- const escapedPath = escapeForSingleQuotes(projectPath);
1801
- if (await this.sessionExists(sessionName)) {
1802
- await this.killSession(sessionName);
1803
- }
1804
- const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
1805
- const escapedClaudeCmd = escapeForSingleQuotes(claudeCommand);
1806
- await exec(
1807
- `tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${escapedClaudeCmd}'`
1808
- );
1809
- await exec(`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`);
1810
- await exec(`tmux select-pane -t '${escapedSession}:0.0'`);
1811
- return sessionName;
1812
- }
1813
- async createThreePaneSession(projectName, projectPath, claudeArgs = [], npmCommand = "npm run dev") {
1814
- const sessionName = this.getSessionName(projectName);
1815
- const escapedSession = escapeForSingleQuotes(sessionName);
1816
- const escapedPath = escapeForSingleQuotes(projectPath);
1817
- if (await this.sessionExists(sessionName)) {
1818
- await this.killSession(sessionName);
1819
- }
1820
- const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
1821
- const escapedClaudeCmd = escapeForSingleQuotes(claudeCommand);
1822
- const escapedNpmCmd = escapeForSingleQuotes(npmCommand);
1823
- await exec(
1824
- `tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${escapedClaudeCmd}'`
1825
- );
1826
- await exec(`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`);
1827
- await exec(
1828
- `tmux split-window -v -t '${escapedSession}:0.1' -c '${escapedPath}' '${escapedNpmCmd}'`
1829
- );
1830
- await exec(`tmux set-option -t '${escapedSession}:0.2' remain-on-exit on`);
1831
- await exec(`tmux resize-pane -t '${escapedSession}:0.2' -y 10`);
1832
- await exec(`tmux select-pane -t '${escapedSession}:0.0'`);
1833
- return sessionName;
1834
- }
1835
- async createTwoPaneNpmSession(projectName, projectPath, npmCommand = "npm run dev") {
1836
- const sessionName = this.getSessionName(projectName);
1837
- const escapedSession = escapeForSingleQuotes(sessionName);
1838
- const escapedPath = escapeForSingleQuotes(projectPath);
1839
- const escapedNpmCmd = escapeForSingleQuotes(npmCommand);
1840
- if (await this.sessionExists(sessionName)) {
1841
- await this.killSession(sessionName);
1842
- }
1843
- await exec(`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}'`);
1844
- await exec(
1845
- `tmux split-window -h -t '${escapedSession}' -c '${escapedPath}' '${escapedNpmCmd}'`
1846
- );
1847
- await exec(`tmux set-option -t '${escapedSession}:0.1' remain-on-exit on`);
1848
- await exec(`tmux select-pane -t '${escapedSession}:0.0'`);
1849
- return sessionName;
1850
- }
1851
- async attachToSession(sessionName) {
1852
- const escapedSession = escapeForSingleQuotes(sessionName);
1853
- if (process.env.TMUX) {
1854
- await exec(`tmux switch-client -t '${escapedSession}'`);
1855
- } else {
1856
- const isITerm = process.env.TERM_PROGRAM === "iTerm.app" || process.env.LC_TERMINAL === "iTerm2" || !!process.env.ITERM_SESSION_ID;
1857
- const useiTermIntegration = isITerm && !process.env.TMUX_CC_NOT_SUPPORTED;
1858
- if (useiTermIntegration) {
1859
- spawn7("tmux", ["-CC", "attach-session", "-t", sessionName], {
1860
- stdio: "inherit",
1861
- detached: true
1862
- });
1863
- } else {
1864
- spawn7("tmux", ["attach-session", "-t", sessionName], {
1865
- stdio: "inherit",
1866
- detached: true
1867
- });
1868
- }
1869
- }
1870
- }
1871
- buildShellCommands(projectName, projectPath, claudeArgs = []) {
1872
- const sessionName = this.getSessionName(projectName);
1873
- const escapedSession = escapeForSingleQuotes(sessionName);
1874
- const escapedPath = escapeForSingleQuotes(projectPath);
1875
- const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
1876
- const escapedClaudeCmd = escapeForSingleQuotes(claudeCommand);
1877
- return [
1878
- `# Create tmux split session for ${sanitizeForShell(projectName)}`,
1879
- `tmux has-session -t '${escapedSession}' 2>/dev/null && tmux kill-session -t '${escapedSession}'`,
1880
- `tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${escapedClaudeCmd}'`,
1881
- `tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`,
1882
- `tmux select-pane -t '${escapedSession}:0.0'`,
1883
- this.getAttachCommand(sessionName)
1884
- ];
1885
- }
1886
- buildThreePaneShellCommands(projectName, projectPath, claudeArgs = [], npmCommand = "npm run dev") {
1887
- const sessionName = this.getSessionName(projectName);
1888
- const escapedSession = escapeForSingleQuotes(sessionName);
1889
- const escapedPath = escapeForSingleQuotes(projectPath);
1890
- const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
1891
- const escapedClaudeCmd = escapeForSingleQuotes(claudeCommand);
1892
- const escapedNpmCmd = escapeForSingleQuotes(npmCommand);
1893
- return [
1894
- `# Create tmux three-pane session for ${sanitizeForShell(projectName)}`,
1895
- `tmux has-session -t '${escapedSession}' 2>/dev/null && tmux kill-session -t '${escapedSession}'`,
1896
- `tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${escapedClaudeCmd}'`,
1897
- `tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`,
1898
- `tmux split-window -v -t '${escapedSession}:0.1' -c '${escapedPath}' '${escapedNpmCmd}'`,
1899
- `tmux set-option -t '${escapedSession}:0.2' remain-on-exit on`,
1900
- `tmux resize-pane -t '${escapedSession}:0.2' -y 10`,
1901
- `tmux select-pane -t '${escapedSession}:0.0'`,
1902
- this.getAttachCommand(sessionName)
1903
- ];
1904
- }
1905
- buildTwoPaneNpmShellCommands(projectName, projectPath, npmCommand = "npm run dev") {
1906
- const sessionName = this.getSessionName(projectName);
1907
- const escapedSession = escapeForSingleQuotes(sessionName);
1908
- const escapedPath = escapeForSingleQuotes(projectPath);
1909
- const escapedNpmCmd = escapeForSingleQuotes(npmCommand);
1910
- return [
1911
- `# Create tmux two-pane session with npm for ${sanitizeForShell(projectName)}`,
1912
- `tmux has-session -t '${escapedSession}' 2>/dev/null && tmux kill-session -t '${escapedSession}'`,
1913
- `tmux new-session -d -s '${escapedSession}' -c '${escapedPath}'`,
1914
- `tmux split-window -h -t '${escapedSession}' -c '${escapedPath}' '${escapedNpmCmd}'`,
1915
- `tmux set-option -t '${escapedSession}:0.1' remain-on-exit on`,
1916
- `tmux select-pane -t '${escapedSession}:0.0'`,
1917
- this.getAttachCommand(sessionName)
1918
- ];
1919
- }
1920
- getAttachCommand(sessionName) {
1921
- const escapedSession = escapeForSingleQuotes(sessionName);
1922
- if (process.env.TMUX) {
1923
- return `tmux switch-client -t '${escapedSession}'`;
1924
- }
1925
- const isITerm = process.env.TERM_PROGRAM === "iTerm.app" || process.env.LC_TERMINAL === "iTerm2" || process.env.ITERM_SESSION_ID;
1926
- const useiTermIntegration = isITerm && !process.env.TMUX_CC_NOT_SUPPORTED;
1927
- if (useiTermIntegration) {
1928
- return `tmux -CC attach-session -t '${escapedSession}'`;
1929
- }
1930
- return `tmux attach-session -t '${escapedSession}'`;
1931
- }
1932
- async listWorkonSessions() {
1933
- try {
1934
- const { stdout } = await exec('tmux list-sessions -F "#{session_name}"');
1935
- return stdout.trim().split("\n").filter((session) => session.startsWith(this.sessionPrefix)).map((session) => session.replace(this.sessionPrefix, ""));
1936
- } catch {
1937
- return [];
1938
- }
1948
+ async function runOpen(projectArg, options, ctx) {
1949
+ const { log } = ctx;
1950
+ if (options.debug) {
1951
+ log.setLogLevel("debug");
1939
1952
  }
1940
- };
1941
-
1942
- // src/commands/open.ts
1943
- init_registry();
1953
+ await processProject(projectArg, options, ctx);
1954
+ }
1944
1955
  function createOpenCommand(ctx) {
1945
1956
  const { config, log } = ctx;
1946
1957
  const command = new Command("open").description("Open a project by passing its project id").argument("[project]", "The id of the project to open (supports project:command syntax)").option("-d, --debug", "Enable debug logging").option("-n, --dry-run", "Show what would happen without executing").option("--shell", "Output shell commands instead of spawning processes").action(async (projectArg, options) => {
@@ -2069,12 +2080,25 @@ async function handleTmuxLayout(project, layout, options, shellCommands, events,
2069
2080
  let tmuxHandled = false;
2070
2081
  if (isShellMode) {
2071
2082
  if (await tmux.isTmuxAvailable()) {
2083
+ const remainingEvents = events.filter((e) => !layout.handledEvents.includes(e));
2084
+ for (const event of remainingEvents) {
2085
+ const eventHandler = EventRegistry.getEventByName(event);
2086
+ if (eventHandler) {
2087
+ const cmds = eventHandler.processing.generateShellCommand({
2088
+ project,
2089
+ isShellMode: true,
2090
+ shellCommands: []
2091
+ });
2092
+ shellCommands.push(...cmds);
2093
+ }
2094
+ }
2072
2095
  const commands = buildLayoutShellCommands(tmux, project, layout);
2073
2096
  shellCommands.push(...commands);
2074
2097
  tmuxHandled = true;
2075
2098
  } else {
2076
2099
  log.debug("Tmux not available, falling back to normal mode");
2077
- buildFallbackCommands(shellCommands, project, layout);
2100
+ const remainingEvents = events.filter((e) => !layout.handledEvents.includes(e));
2101
+ buildFallbackCommandsWithEvents(shellCommands, project, layout, remainingEvents, ctx);
2078
2102
  tmuxHandled = true;
2079
2103
  }
2080
2104
  } else if (!dryRun) {
@@ -2098,7 +2122,7 @@ async function handleTmuxLayout(project, layout, options, shellCommands, events,
2098
2122
  await processEvent(event, { project, isShellMode, shellCommands }, ctx);
2099
2123
  }
2100
2124
  }
2101
- if (!dryRun) {
2125
+ if (!dryRun && !isShellMode) {
2102
2126
  for (const event of events.filter((e) => !layout.handledEvents.includes(e))) {
2103
2127
  await processEvent(event, { project, isShellMode, shellCommands }, ctx);
2104
2128
  }
@@ -2119,14 +2143,19 @@ function buildLayoutShellCommands(tmux, project, layout) {
2119
2143
  return tmux.buildTwoPaneNpmShellCommands(project.name, project.path.path, layout.npmCommand);
2120
2144
  }
2121
2145
  }
2122
- function buildFallbackCommands(shellCommands, project, layout) {
2123
- shellCommands.push(`cd "${project.path.path}"`);
2124
- if (layout.type === "split-claude" || layout.type === "three-pane") {
2125
- const claudeCommand = layout.claudeArgs.length > 0 ? `claude ${layout.claudeArgs.join(" ")}` : "claude";
2126
- shellCommands.push(claudeCommand);
2127
- }
2128
- if (layout.npmCommand) {
2129
- shellCommands.push(layout.npmCommand);
2146
+ function buildFallbackCommandsWithEvents(shellCommands, project, layout, remainingEvents, _ctx) {
2147
+ shellCommands.push(`echo "\u26A0 tmux not available - install with: brew install tmux" >&2`);
2148
+ shellCommands.push(`pushd "${project.path.path}" > /dev/null`);
2149
+ for (const event of remainingEvents) {
2150
+ const eventHandler = EventRegistry.getEventByName(event);
2151
+ if (eventHandler) {
2152
+ const cmds = eventHandler.processing.generateShellCommand({
2153
+ project,
2154
+ isShellMode: true,
2155
+ shellCommands: []
2156
+ });
2157
+ shellCommands.push(...cmds);
2158
+ }
2130
2159
  }
2131
2160
  }
2132
2161
  async function createTmuxSession(tmux, project, layout) {
@@ -2227,6 +2256,27 @@ Available commands for '${projectName}':`);
2227
2256
  console.log(` workon ${projectName}:cwd --shell # Output shell commands
2228
2257
  `);
2229
2258
  }
2259
+ var init_open = __esm({
2260
+ "src/commands/open.ts"() {
2261
+ "use strict";
2262
+ init_environment();
2263
+ init_tmux();
2264
+ init_registry();
2265
+ }
2266
+ });
2267
+
2268
+ // src/commands/index.ts
2269
+ init_config();
2270
+ init_environment();
2271
+ init_registry();
2272
+ init_open();
2273
+ import { Command as Command8 } from "commander";
2274
+ import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
2275
+ import { join, dirname } from "path";
2276
+ import { fileURLToPath } from "url";
2277
+ import loog from "loog";
2278
+ import omelette from "omelette";
2279
+ import File7 from "phylo";
2230
2280
 
2231
2281
  // src/commands/config/index.ts
2232
2282
  import { Command as Command5 } from "commander";
@@ -2644,7 +2694,7 @@ async function addProject(pathArg, options, ctx) {
2644
2694
  return;
2645
2695
  }
2646
2696
  }
2647
- const ide = options.ide || discovery.detectedIde || "vscode";
2697
+ const ide = options.ide || discovery.detectedIde || "code";
2648
2698
  log.debug(`IDE: ${ide}`);
2649
2699
  let relativePath = targetPath;
2650
2700
  if (defaults?.base) {
@@ -2672,6 +2722,9 @@ async function addProject(pathArg, options, ctx) {
2672
2722
  projectConfig.events.npm = scripts.dev ? "dev" : "start";
2673
2723
  }
2674
2724
  }
2725
+ if (discovery.hasClaude) {
2726
+ projectConfig.events.claude = true;
2727
+ }
2675
2728
  config.setProject(projectName, projectConfig);
2676
2729
  log.info(`Added project '${projectName}'`);
2677
2730
  log.info(` Path: ${relativePath}`);
@@ -2686,6 +2739,7 @@ function discoverProject(targetPath, log) {
2686
2739
  name: dirName,
2687
2740
  isNode: false,
2688
2741
  isBun: false,
2742
+ hasClaude: false,
2689
2743
  detectedIde: null,
2690
2744
  packageJson: null
2691
2745
  };
@@ -2711,14 +2765,23 @@ function discoverProject(targetPath, log) {
2711
2765
  log.debug("Detected Bun project (bun.lockb found)");
2712
2766
  }
2713
2767
  const vscodeDir = resolve(targetPath, ".vscode");
2768
+ const cursorDir = resolve(targetPath, ".cursor");
2714
2769
  const ideaDir = resolve(targetPath, ".idea");
2715
- if (existsSync(vscodeDir)) {
2716
- discovery.detectedIde = "vscode";
2770
+ if (existsSync(cursorDir)) {
2771
+ discovery.detectedIde = "cursor";
2772
+ log.debug("Detected Cursor (.cursor directory found)");
2773
+ } else if (existsSync(vscodeDir)) {
2774
+ discovery.detectedIde = "code";
2717
2775
  log.debug("Detected VS Code (.vscode directory found)");
2718
2776
  } else if (existsSync(ideaDir)) {
2719
2777
  discovery.detectedIde = "idea";
2720
2778
  log.debug("Detected IntelliJ IDEA (.idea directory found)");
2721
2779
  }
2780
+ const claudeMdPath = resolve(targetPath, "CLAUDE.md");
2781
+ if (existsSync(claudeMdPath)) {
2782
+ discovery.hasClaude = true;
2783
+ log.debug("Detected Claude Code project (CLAUDE.md found)");
2784
+ }
2722
2785
  return discovery;
2723
2786
  }
2724
2787
 
@@ -2750,7 +2813,7 @@ function createCli() {
2750
2813
  config.set("pkg", packageJson);
2751
2814
  EnvironmentRecognizer.configure(config, log);
2752
2815
  const completion = setupCompletion(config);
2753
- program2.name("workon").description("Work on something great!").version(packageJson.version).argument("[project]", "Project name to open (supports project:command syntax)").option("-d, --debug", "Enable debug logging").option("--completion", "Setup shell tab completion").option("--shell", "Output shell commands for evaluation").option("--init", "Generate shell integration function").hook("preAction", async (thisCommand) => {
2816
+ program2.name("workon").description("Work on something great!").version(packageJson.version).enablePositionalOptions().argument("[project]", "Project name to open (supports project:command syntax)").option("-d, --debug", "Enable debug logging").option("--completion", "Setup shell tab completion").option("--shell", "Output shell commands for evaluation").option("--init", "Generate shell integration function").hook("preAction", async (thisCommand) => {
2754
2817
  const opts = thisCommand.opts();
2755
2818
  if (opts.debug) {
2756
2819
  log.setLogLevel("debug");
@@ -2772,10 +2835,8 @@ function createCli() {
2772
2835
  return;
2773
2836
  }
2774
2837
  if (project) {
2775
- const args = ["open", project];
2776
- if (options.shell) args.push("--shell");
2777
- if (options.debug) args.push("--debug");
2778
- await program2.parseAsync(["node", "workon", ...args]);
2838
+ const { runOpen: runOpen2 } = await Promise.resolve().then(() => (init_open(), open_exports));
2839
+ await runOpen2(project, { debug: options.debug, shell: options.shell }, { config, log });
2779
2840
  return;
2780
2841
  }
2781
2842
  const environment = await EnvironmentRecognizer.recognize(File7.cwd());