workon 3.2.2 → 3.2.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 +191 -66
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +151 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.js +151 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -11,18 +11,99 @@ var __export = (target, all) => {
|
|
|
11
11
|
|
|
12
12
|
// src/lib/config.ts
|
|
13
13
|
import Conf from "conf";
|
|
14
|
-
|
|
14
|
+
import { openSync, closeSync, unlinkSync, existsSync, mkdirSync } from "fs";
|
|
15
|
+
import { dirname } from "path";
|
|
16
|
+
var TRANSIENT_PROPS, FileLock, Config;
|
|
15
17
|
var init_config = __esm({
|
|
16
18
|
"src/lib/config.ts"() {
|
|
17
19
|
"use strict";
|
|
18
20
|
TRANSIENT_PROPS = ["pkg", "work"];
|
|
19
|
-
|
|
21
|
+
FileLock = class _FileLock {
|
|
22
|
+
lockPath;
|
|
23
|
+
fd = null;
|
|
24
|
+
static LOCK_TIMEOUT_MS = 5e3;
|
|
25
|
+
static RETRY_INTERVAL_MS = 50;
|
|
26
|
+
constructor(configPath) {
|
|
27
|
+
this.lockPath = `${configPath}.lock`;
|
|
28
|
+
}
|
|
29
|
+
async acquire() {
|
|
30
|
+
const startTime = Date.now();
|
|
31
|
+
const lockDir = dirname(this.lockPath);
|
|
32
|
+
if (!existsSync(lockDir)) {
|
|
33
|
+
mkdirSync(lockDir, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
while (Date.now() - startTime < _FileLock.LOCK_TIMEOUT_MS) {
|
|
36
|
+
try {
|
|
37
|
+
this.fd = openSync(this.lockPath, "wx");
|
|
38
|
+
return;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (error.code === "EEXIST") {
|
|
41
|
+
try {
|
|
42
|
+
const stat = await import("fs").then((fs) => fs.promises.stat(this.lockPath));
|
|
43
|
+
const age = Date.now() - stat.mtimeMs;
|
|
44
|
+
if (age > _FileLock.LOCK_TIMEOUT_MS) {
|
|
45
|
+
try {
|
|
46
|
+
unlinkSync(this.lockPath);
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
await new Promise((resolve2) => setTimeout(resolve2, _FileLock.RETRY_INTERVAL_MS));
|
|
53
|
+
} else {
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
throw new Error("Failed to acquire config lock: timeout");
|
|
59
|
+
}
|
|
60
|
+
release() {
|
|
61
|
+
if (this.fd !== null) {
|
|
62
|
+
try {
|
|
63
|
+
closeSync(this.fd);
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
this.fd = null;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
unlinkSync(this.lockPath);
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
Config = class _Config {
|
|
75
|
+
static _instance = null;
|
|
20
76
|
_transient = {};
|
|
77
|
+
// Using definite assignment assertion since singleton pattern may return existing instance
|
|
21
78
|
_store;
|
|
79
|
+
_lock;
|
|
22
80
|
constructor() {
|
|
81
|
+
if (_Config._instance && process.env.NODE_ENV !== "test") {
|
|
82
|
+
return _Config._instance;
|
|
83
|
+
}
|
|
23
84
|
this._store = new Conf({
|
|
24
|
-
projectName: "workon"
|
|
85
|
+
projectName: "workon",
|
|
86
|
+
...process.env.WORKON_CONFIG_DIR && { cwd: process.env.WORKON_CONFIG_DIR }
|
|
25
87
|
});
|
|
88
|
+
this._lock = new FileLock(this._store.path);
|
|
89
|
+
if (process.env.NODE_ENV !== "test") {
|
|
90
|
+
_Config._instance = this;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get the singleton instance (creates one if needed)
|
|
95
|
+
*/
|
|
96
|
+
static getInstance() {
|
|
97
|
+
if (!_Config._instance) {
|
|
98
|
+
_Config._instance = new _Config();
|
|
99
|
+
}
|
|
100
|
+
return _Config._instance;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Reset the singleton instance (for testing purposes)
|
|
104
|
+
*/
|
|
105
|
+
static resetInstance() {
|
|
106
|
+
_Config._instance = null;
|
|
26
107
|
}
|
|
27
108
|
get(key, defaultValue) {
|
|
28
109
|
const rootKey = key.split(".")[0];
|
|
@@ -37,10 +118,9 @@ var init_config = __esm({
|
|
|
37
118
|
this._transient[key] = value;
|
|
38
119
|
} else {
|
|
39
120
|
if (value === void 0) {
|
|
40
|
-
|
|
41
|
-
} else {
|
|
42
|
-
this._store.set(key, value);
|
|
121
|
+
throw new Error(`Cannot set '${key}' to undefined. Use delete() to remove keys.`);
|
|
43
122
|
}
|
|
123
|
+
this._store.set(key, value);
|
|
44
124
|
}
|
|
45
125
|
}
|
|
46
126
|
has(key) {
|
|
@@ -58,6 +138,9 @@ var init_config = __esm({
|
|
|
58
138
|
this._store.delete(key);
|
|
59
139
|
}
|
|
60
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Get all projects. Returns a fresh copy from the store.
|
|
143
|
+
*/
|
|
61
144
|
getProjects() {
|
|
62
145
|
return this.get("projects") ?? {};
|
|
63
146
|
}
|
|
@@ -65,15 +148,50 @@ var init_config = __esm({
|
|
|
65
148
|
const projects = this.getProjects();
|
|
66
149
|
return projects[name];
|
|
67
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Set a project with file locking to prevent race conditions.
|
|
153
|
+
* This ensures atomic read-modify-write operations.
|
|
154
|
+
*/
|
|
155
|
+
async setProjectSafe(name, config) {
|
|
156
|
+
await this._lock.acquire();
|
|
157
|
+
try {
|
|
158
|
+
const freshProjects = this._store.get("projects") ?? {};
|
|
159
|
+
freshProjects[name] = config;
|
|
160
|
+
this._store.set("projects", freshProjects);
|
|
161
|
+
} finally {
|
|
162
|
+
this._lock.release();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Synchronous version of setProject for backwards compatibility.
|
|
167
|
+
* Note: This is less safe than setProjectSafe() in concurrent scenarios.
|
|
168
|
+
* Consider migrating to setProjectSafe() for critical operations.
|
|
169
|
+
*/
|
|
68
170
|
setProject(name, config) {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
this.set("projects",
|
|
171
|
+
const freshProjects = this._store.get("projects") ?? {};
|
|
172
|
+
freshProjects[name] = config;
|
|
173
|
+
this._store.set("projects", freshProjects);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Delete a project with file locking to prevent race conditions.
|
|
177
|
+
*/
|
|
178
|
+
async deleteProjectSafe(name) {
|
|
179
|
+
await this._lock.acquire();
|
|
180
|
+
try {
|
|
181
|
+
const freshProjects = this._store.get("projects") ?? {};
|
|
182
|
+
delete freshProjects[name];
|
|
183
|
+
this._store.set("projects", freshProjects);
|
|
184
|
+
} finally {
|
|
185
|
+
this._lock.release();
|
|
186
|
+
}
|
|
72
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Synchronous version of deleteProject for backwards compatibility.
|
|
190
|
+
*/
|
|
73
191
|
deleteProject(name) {
|
|
74
|
-
const
|
|
75
|
-
delete
|
|
76
|
-
this.set("projects",
|
|
192
|
+
const freshProjects = this._store.get("projects") ?? {};
|
|
193
|
+
delete freshProjects[name];
|
|
194
|
+
this._store.set("projects", freshProjects);
|
|
77
195
|
}
|
|
78
196
|
getDefaults() {
|
|
79
197
|
return this.get("project_defaults");
|
|
@@ -280,7 +398,7 @@ var init_environment = __esm({
|
|
|
280
398
|
}
|
|
281
399
|
static ensureConfigured() {
|
|
282
400
|
if (!this.configured) {
|
|
283
|
-
this.config =
|
|
401
|
+
this.config = Config.getInstance();
|
|
284
402
|
this.log = {
|
|
285
403
|
debug: () => {
|
|
286
404
|
},
|
|
@@ -632,10 +750,10 @@ var init_claude = __esm({
|
|
|
632
750
|
}
|
|
633
751
|
static getClaudeCommand(config) {
|
|
634
752
|
if (typeof config === "boolean" || config === void 0) {
|
|
635
|
-
return "claude";
|
|
753
|
+
return "claude --dangerously-skip-permissions";
|
|
636
754
|
}
|
|
637
755
|
const flags = config.flags || [];
|
|
638
|
-
return flags.length > 0 ? `claude ${flags.join(" ")}` : "claude";
|
|
756
|
+
return flags.length > 0 ? `claude --dangerously-skip-permissions ${flags.join(" ")}` : "claude --dangerously-skip-permissions";
|
|
639
757
|
}
|
|
640
758
|
static get processing() {
|
|
641
759
|
return {
|
|
@@ -1116,6 +1234,9 @@ var init_sanitize = __esm({
|
|
|
1116
1234
|
// src/lib/tmux.ts
|
|
1117
1235
|
import { exec as execCallback, spawn as spawn7 } from "child_process";
|
|
1118
1236
|
import { promisify } from "util";
|
|
1237
|
+
function wrapWithShellFallback(command) {
|
|
1238
|
+
return `${command}; exec $SHELL`;
|
|
1239
|
+
}
|
|
1119
1240
|
var exec, TmuxManager;
|
|
1120
1241
|
var init_tmux = __esm({
|
|
1121
1242
|
"src/lib/tmux.ts"() {
|
|
@@ -1159,9 +1280,9 @@ var init_tmux = __esm({
|
|
|
1159
1280
|
await this.killSession(sessionName);
|
|
1160
1281
|
}
|
|
1161
1282
|
const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
|
|
1162
|
-
const
|
|
1283
|
+
const wrappedClaudeCmd = escapeForSingleQuotes(wrapWithShellFallback(claudeCommand));
|
|
1163
1284
|
await exec(
|
|
1164
|
-
`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${
|
|
1285
|
+
`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${wrappedClaudeCmd}'`
|
|
1165
1286
|
);
|
|
1166
1287
|
await exec(`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`);
|
|
1167
1288
|
await exec(`tmux select-pane -t '${escapedSession}:0.0'`);
|
|
@@ -1175,16 +1296,15 @@ var init_tmux = __esm({
|
|
|
1175
1296
|
await this.killSession(sessionName);
|
|
1176
1297
|
}
|
|
1177
1298
|
const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
|
|
1178
|
-
const
|
|
1179
|
-
const
|
|
1299
|
+
const wrappedClaudeCmd = escapeForSingleQuotes(wrapWithShellFallback(claudeCommand));
|
|
1300
|
+
const wrappedNpmCmd = escapeForSingleQuotes(wrapWithShellFallback(npmCommand));
|
|
1180
1301
|
await exec(
|
|
1181
|
-
`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${
|
|
1302
|
+
`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${wrappedClaudeCmd}'`
|
|
1182
1303
|
);
|
|
1183
1304
|
await exec(`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`);
|
|
1184
1305
|
await exec(
|
|
1185
|
-
`tmux split-window -v -t '${escapedSession}:0.1' -c '${escapedPath}' '${
|
|
1306
|
+
`tmux split-window -v -t '${escapedSession}:0.1' -c '${escapedPath}' '${wrappedNpmCmd}'`
|
|
1186
1307
|
);
|
|
1187
|
-
await exec(`tmux set-option -t '${escapedSession}:0.2' remain-on-exit on`);
|
|
1188
1308
|
await exec(`tmux resize-pane -t '${escapedSession}:0.2' -y 10`);
|
|
1189
1309
|
await exec(`tmux select-pane -t '${escapedSession}:0.0'`);
|
|
1190
1310
|
return sessionName;
|
|
@@ -1193,15 +1313,14 @@ var init_tmux = __esm({
|
|
|
1193
1313
|
const sessionName = this.getSessionName(projectName);
|
|
1194
1314
|
const escapedSession = escapeForSingleQuotes(sessionName);
|
|
1195
1315
|
const escapedPath = escapeForSingleQuotes(projectPath);
|
|
1196
|
-
const
|
|
1316
|
+
const wrappedNpmCmd = escapeForSingleQuotes(wrapWithShellFallback(npmCommand));
|
|
1197
1317
|
if (await this.sessionExists(sessionName)) {
|
|
1198
1318
|
await this.killSession(sessionName);
|
|
1199
1319
|
}
|
|
1200
1320
|
await exec(`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}'`);
|
|
1201
1321
|
await exec(
|
|
1202
|
-
`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}' '${
|
|
1322
|
+
`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}' '${wrappedNpmCmd}'`
|
|
1203
1323
|
);
|
|
1204
|
-
await exec(`tmux set-option -t '${escapedSession}:0.1' remain-on-exit on`);
|
|
1205
1324
|
await exec(`tmux select-pane -t '${escapedSession}:0.0'`);
|
|
1206
1325
|
return sessionName;
|
|
1207
1326
|
}
|
|
@@ -1230,11 +1349,11 @@ var init_tmux = __esm({
|
|
|
1230
1349
|
const escapedSession = escapeForSingleQuotes(sessionName);
|
|
1231
1350
|
const escapedPath = escapeForSingleQuotes(projectPath);
|
|
1232
1351
|
const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
|
|
1233
|
-
const
|
|
1352
|
+
const wrappedClaudeCmd = escapeForSingleQuotes(wrapWithShellFallback(claudeCommand));
|
|
1234
1353
|
return [
|
|
1235
1354
|
`# Create tmux split session for ${sanitizeForShell(projectName)}`,
|
|
1236
1355
|
`tmux has-session -t '${escapedSession}' 2>/dev/null && tmux kill-session -t '${escapedSession}'`,
|
|
1237
|
-
`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${
|
|
1356
|
+
`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${wrappedClaudeCmd}'`,
|
|
1238
1357
|
`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`,
|
|
1239
1358
|
`tmux select-pane -t '${escapedSession}:0.0'`,
|
|
1240
1359
|
this.getAttachCommand(sessionName)
|
|
@@ -1245,15 +1364,14 @@ var init_tmux = __esm({
|
|
|
1245
1364
|
const escapedSession = escapeForSingleQuotes(sessionName);
|
|
1246
1365
|
const escapedPath = escapeForSingleQuotes(projectPath);
|
|
1247
1366
|
const claudeCommand = claudeArgs.length > 0 ? `claude ${claudeArgs.join(" ")}` : "claude";
|
|
1248
|
-
const
|
|
1249
|
-
const
|
|
1367
|
+
const wrappedClaudeCmd = escapeForSingleQuotes(wrapWithShellFallback(claudeCommand));
|
|
1368
|
+
const wrappedNpmCmd = escapeForSingleQuotes(wrapWithShellFallback(npmCommand));
|
|
1250
1369
|
return [
|
|
1251
1370
|
`# Create tmux three-pane session for ${sanitizeForShell(projectName)}`,
|
|
1252
1371
|
`tmux has-session -t '${escapedSession}' 2>/dev/null && tmux kill-session -t '${escapedSession}'`,
|
|
1253
|
-
`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${
|
|
1372
|
+
`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}' '${wrappedClaudeCmd}'`,
|
|
1254
1373
|
`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}'`,
|
|
1255
|
-
`tmux split-window -v -t '${escapedSession}:0.1' -c '${escapedPath}' '${
|
|
1256
|
-
`tmux set-option -t '${escapedSession}:0.2' remain-on-exit on`,
|
|
1374
|
+
`tmux split-window -v -t '${escapedSession}:0.1' -c '${escapedPath}' '${wrappedNpmCmd}'`,
|
|
1257
1375
|
`tmux resize-pane -t '${escapedSession}:0.2' -y 10`,
|
|
1258
1376
|
`tmux select-pane -t '${escapedSession}:0.0'`,
|
|
1259
1377
|
this.getAttachCommand(sessionName)
|
|
@@ -1263,13 +1381,12 @@ var init_tmux = __esm({
|
|
|
1263
1381
|
const sessionName = this.getSessionName(projectName);
|
|
1264
1382
|
const escapedSession = escapeForSingleQuotes(sessionName);
|
|
1265
1383
|
const escapedPath = escapeForSingleQuotes(projectPath);
|
|
1266
|
-
const
|
|
1384
|
+
const wrappedNpmCmd = escapeForSingleQuotes(wrapWithShellFallback(npmCommand));
|
|
1267
1385
|
return [
|
|
1268
1386
|
`# Create tmux two-pane session with npm for ${sanitizeForShell(projectName)}`,
|
|
1269
1387
|
`tmux has-session -t '${escapedSession}' 2>/dev/null && tmux kill-session -t '${escapedSession}'`,
|
|
1270
1388
|
`tmux new-session -d -s '${escapedSession}' -c '${escapedPath}'`,
|
|
1271
|
-
`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}' '${
|
|
1272
|
-
`tmux set-option -t '${escapedSession}:0.1' remain-on-exit on`,
|
|
1389
|
+
`tmux split-window -h -t '${escapedSession}' -c '${escapedPath}' '${wrappedNpmCmd}'`,
|
|
1273
1390
|
`tmux select-pane -t '${escapedSession}:0.0'`,
|
|
1274
1391
|
this.getAttachCommand(sessionName)
|
|
1275
1392
|
];
|
|
@@ -1469,8 +1586,7 @@ async function initProject(defaultName, fromUser, ctx) {
|
|
|
1469
1586
|
ide,
|
|
1470
1587
|
events
|
|
1471
1588
|
};
|
|
1472
|
-
|
|
1473
|
-
config.set("projects", projects);
|
|
1589
|
+
await config.setProjectSafe(name, projectConfig);
|
|
1474
1590
|
log.info("Your project has been initialized.");
|
|
1475
1591
|
log.info(`Use 'workon ${name}' to start working!`);
|
|
1476
1592
|
}
|
|
@@ -1491,8 +1607,7 @@ async function initBranch(defaultName, ctx) {
|
|
|
1491
1607
|
branch
|
|
1492
1608
|
});
|
|
1493
1609
|
const branchConfig = mergedConfig;
|
|
1494
|
-
|
|
1495
|
-
config.set("projects", projects);
|
|
1610
|
+
await config.setProjectSafe(branchName, branchConfig);
|
|
1496
1611
|
log.info("Your branch configuration has been initialized.");
|
|
1497
1612
|
log.info(`Use 'workon ${branchName}' to start working!`);
|
|
1498
1613
|
}
|
|
@@ -1690,7 +1805,7 @@ async function createProjectManage(ctx) {
|
|
|
1690
1805
|
default: true
|
|
1691
1806
|
});
|
|
1692
1807
|
if (confirmed) {
|
|
1693
|
-
config.
|
|
1808
|
+
await config.setProjectSafe(name, projectConfig);
|
|
1694
1809
|
log.info(`Project '${name}' created successfully!`);
|
|
1695
1810
|
}
|
|
1696
1811
|
}
|
|
@@ -1768,7 +1883,7 @@ async function editProjectManage(ctx) {
|
|
|
1768
1883
|
default: true
|
|
1769
1884
|
});
|
|
1770
1885
|
if (confirmed) {
|
|
1771
|
-
config.
|
|
1886
|
+
await config.setProjectSafe(name, updatedConfig);
|
|
1772
1887
|
log.info(`Project '${name}' updated successfully!`);
|
|
1773
1888
|
}
|
|
1774
1889
|
}
|
|
@@ -1794,7 +1909,7 @@ async function deleteProjectManage(ctx) {
|
|
|
1794
1909
|
});
|
|
1795
1910
|
if (deleteAll) {
|
|
1796
1911
|
for (const branch of branches) {
|
|
1797
|
-
config.
|
|
1912
|
+
await config.deleteProjectSafe(branch);
|
|
1798
1913
|
}
|
|
1799
1914
|
}
|
|
1800
1915
|
}
|
|
@@ -1803,7 +1918,7 @@ async function deleteProjectManage(ctx) {
|
|
|
1803
1918
|
default: false
|
|
1804
1919
|
});
|
|
1805
1920
|
if (confirmed) {
|
|
1806
|
-
config.
|
|
1921
|
+
await config.deleteProjectSafe(name);
|
|
1807
1922
|
log.info(`Project '${name}' deleted.`);
|
|
1808
1923
|
}
|
|
1809
1924
|
}
|
|
@@ -1883,7 +1998,7 @@ async function editBranchManage(projectName, ctx) {
|
|
|
1883
1998
|
default: true
|
|
1884
1999
|
});
|
|
1885
2000
|
if (confirmed) {
|
|
1886
|
-
config.
|
|
2001
|
+
await config.setProjectSafe(branchName, updatedConfig);
|
|
1887
2002
|
log.info(`Branch configuration '${branchName}' updated successfully!`);
|
|
1888
2003
|
}
|
|
1889
2004
|
}
|
|
@@ -1908,7 +2023,7 @@ async function deleteBranchManage(projectName, ctx) {
|
|
|
1908
2023
|
default: false
|
|
1909
2024
|
});
|
|
1910
2025
|
if (confirmed) {
|
|
1911
|
-
config.
|
|
2026
|
+
await config.deleteProjectSafe(branchName);
|
|
1912
2027
|
log.info(`Branch configuration '${branchName}' deleted.`);
|
|
1913
2028
|
}
|
|
1914
2029
|
}
|
|
@@ -1996,9 +2111,9 @@ async function processProject(projectParam, options, ctx) {
|
|
|
1996
2111
|
const projectEnv = ProjectEnvironment.load(projectCfg, config.getDefaults());
|
|
1997
2112
|
await switchTo(projectEnv, requestedCommands, options, ctx);
|
|
1998
2113
|
} else {
|
|
1999
|
-
log.
|
|
2000
|
-
|
|
2001
|
-
|
|
2114
|
+
log.error(`Project '${projectName}' not found.`);
|
|
2115
|
+
log.info(`Run 'workon' without arguments to see available projects or create a new one.`);
|
|
2116
|
+
process.exit(1);
|
|
2002
2117
|
}
|
|
2003
2118
|
}
|
|
2004
2119
|
function validateRequestedCommands(requestedCommands, projectConfig, projectName) {
|
|
@@ -2066,7 +2181,8 @@ function resolveCommandDependencies(requestedCommands, project) {
|
|
|
2066
2181
|
}
|
|
2067
2182
|
function getClaudeArgs(project) {
|
|
2068
2183
|
const claudeConfig = project.events.claude;
|
|
2069
|
-
|
|
2184
|
+
const userFlags = typeof claudeConfig === "object" && claudeConfig.flags ? claudeConfig.flags : [];
|
|
2185
|
+
return ["--dangerously-skip-permissions", ...userFlags];
|
|
2070
2186
|
}
|
|
2071
2187
|
async function getNpmCommand(project) {
|
|
2072
2188
|
const npmConfig = project.events.npm;
|
|
@@ -2271,8 +2387,8 @@ init_environment();
|
|
|
2271
2387
|
init_registry();
|
|
2272
2388
|
init_open();
|
|
2273
2389
|
import { Command as Command8 } from "commander";
|
|
2274
|
-
import { readFileSync as readFileSync2, existsSync as
|
|
2275
|
-
import { join, dirname } from "path";
|
|
2390
|
+
import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
|
|
2391
|
+
import { join, dirname as dirname2 } from "path";
|
|
2276
2392
|
import { fileURLToPath } from "url";
|
|
2277
2393
|
import loog from "loog";
|
|
2278
2394
|
import omelette from "omelette";
|
|
@@ -2499,7 +2615,7 @@ async function createProject(ctx) {
|
|
|
2499
2615
|
default: true
|
|
2500
2616
|
});
|
|
2501
2617
|
if (confirmed) {
|
|
2502
|
-
config.
|
|
2618
|
+
await config.setProjectSafe(name, projectConfig);
|
|
2503
2619
|
log.info(`Project '${name}' created successfully!`);
|
|
2504
2620
|
log.info(`Use 'workon ${name}' to start working!`);
|
|
2505
2621
|
} else {
|
|
@@ -2589,7 +2705,7 @@ async function editProject(ctx) {
|
|
|
2589
2705
|
default: true
|
|
2590
2706
|
});
|
|
2591
2707
|
if (confirmed) {
|
|
2592
|
-
config.
|
|
2708
|
+
await config.setProjectSafe(name, updatedConfig);
|
|
2593
2709
|
log.info(`Project '${name}' updated successfully!`);
|
|
2594
2710
|
} else {
|
|
2595
2711
|
log.info("Edit cancelled.");
|
|
@@ -2612,7 +2728,7 @@ async function deleteProject(ctx) {
|
|
|
2612
2728
|
default: false
|
|
2613
2729
|
});
|
|
2614
2730
|
if (confirmed) {
|
|
2615
|
-
config.
|
|
2731
|
+
await config.deleteProjectSafe(name);
|
|
2616
2732
|
log.info(`Project '${name}' deleted.`);
|
|
2617
2733
|
} else {
|
|
2618
2734
|
log.info("Delete cancelled.");
|
|
@@ -2638,7 +2754,7 @@ async function listProjects(ctx) {
|
|
|
2638
2754
|
|
|
2639
2755
|
// src/commands/add.ts
|
|
2640
2756
|
import { Command as Command7 } from "commander";
|
|
2641
|
-
import { existsSync, readFileSync } from "fs";
|
|
2757
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
2642
2758
|
import { basename, resolve } from "path";
|
|
2643
2759
|
import File6 from "phylo";
|
|
2644
2760
|
import { confirm as confirm5 } from "@inquirer/prompts";
|
|
@@ -2660,7 +2776,7 @@ async function addProject(pathArg, options, ctx) {
|
|
|
2660
2776
|
const projects = config.getProjects();
|
|
2661
2777
|
const targetPath = resolve(pathArg);
|
|
2662
2778
|
log.debug(`Resolved path: ${targetPath}`);
|
|
2663
|
-
if (!
|
|
2779
|
+
if (!existsSync2(targetPath)) {
|
|
2664
2780
|
log.error(`Path does not exist: ${targetPath}`);
|
|
2665
2781
|
process.exit(1);
|
|
2666
2782
|
}
|
|
@@ -2725,7 +2841,7 @@ async function addProject(pathArg, options, ctx) {
|
|
|
2725
2841
|
if (discovery.hasClaude) {
|
|
2726
2842
|
projectConfig.events.claude = true;
|
|
2727
2843
|
}
|
|
2728
|
-
config.
|
|
2844
|
+
await config.setProjectSafe(projectName, projectConfig);
|
|
2729
2845
|
log.info(`Added project '${projectName}'`);
|
|
2730
2846
|
log.info(` Path: ${relativePath}`);
|
|
2731
2847
|
log.info(` IDE: ${ide}`);
|
|
@@ -2744,7 +2860,7 @@ function discoverProject(targetPath, log) {
|
|
|
2744
2860
|
packageJson: null
|
|
2745
2861
|
};
|
|
2746
2862
|
const packageJsonPath = resolve(targetPath, "package.json");
|
|
2747
|
-
if (
|
|
2863
|
+
if (existsSync2(packageJsonPath)) {
|
|
2748
2864
|
discovery.isNode = true;
|
|
2749
2865
|
log.debug("Detected Node project (package.json found)");
|
|
2750
2866
|
try {
|
|
@@ -2760,25 +2876,25 @@ function discoverProject(targetPath, log) {
|
|
|
2760
2876
|
}
|
|
2761
2877
|
}
|
|
2762
2878
|
const bunLockPath = resolve(targetPath, "bun.lockb");
|
|
2763
|
-
if (
|
|
2879
|
+
if (existsSync2(bunLockPath)) {
|
|
2764
2880
|
discovery.isBun = true;
|
|
2765
2881
|
log.debug("Detected Bun project (bun.lockb found)");
|
|
2766
2882
|
}
|
|
2767
2883
|
const vscodeDir = resolve(targetPath, ".vscode");
|
|
2768
2884
|
const cursorDir = resolve(targetPath, ".cursor");
|
|
2769
2885
|
const ideaDir = resolve(targetPath, ".idea");
|
|
2770
|
-
if (
|
|
2886
|
+
if (existsSync2(cursorDir)) {
|
|
2771
2887
|
discovery.detectedIde = "cursor";
|
|
2772
2888
|
log.debug("Detected Cursor (.cursor directory found)");
|
|
2773
|
-
} else if (
|
|
2889
|
+
} else if (existsSync2(vscodeDir)) {
|
|
2774
2890
|
discovery.detectedIde = "code";
|
|
2775
2891
|
log.debug("Detected VS Code (.vscode directory found)");
|
|
2776
|
-
} else if (
|
|
2892
|
+
} else if (existsSync2(ideaDir)) {
|
|
2777
2893
|
discovery.detectedIde = "idea";
|
|
2778
2894
|
log.debug("Detected IntelliJ IDEA (.idea directory found)");
|
|
2779
2895
|
}
|
|
2780
2896
|
const claudeMdPath = resolve(targetPath, "CLAUDE.md");
|
|
2781
|
-
if (
|
|
2897
|
+
if (existsSync2(claudeMdPath)) {
|
|
2782
2898
|
discovery.hasClaude = true;
|
|
2783
2899
|
log.debug("Detected Claude Code project (CLAUDE.md found)");
|
|
2784
2900
|
}
|
|
@@ -2787,7 +2903,7 @@ function discoverProject(targetPath, log) {
|
|
|
2787
2903
|
|
|
2788
2904
|
// src/commands/index.ts
|
|
2789
2905
|
var __filename = fileURLToPath(import.meta.url);
|
|
2790
|
-
var __dirname =
|
|
2906
|
+
var __dirname = dirname2(__filename);
|
|
2791
2907
|
function findPackageJson() {
|
|
2792
2908
|
const paths = [
|
|
2793
2909
|
join(__dirname, "../package.json"),
|
|
@@ -2795,7 +2911,7 @@ function findPackageJson() {
|
|
|
2795
2911
|
join(process.cwd(), "package.json")
|
|
2796
2912
|
];
|
|
2797
2913
|
for (const p of paths) {
|
|
2798
|
-
if (
|
|
2914
|
+
if (existsSync3(p)) {
|
|
2799
2915
|
return p;
|
|
2800
2916
|
}
|
|
2801
2917
|
}
|
|
@@ -2935,6 +3051,15 @@ workon() {
|
|
|
2935
3051
|
}
|
|
2936
3052
|
|
|
2937
3053
|
// src/cli.ts
|
|
3054
|
+
if (process.stdout.isTTY) {
|
|
3055
|
+
process.stdout.write("");
|
|
3056
|
+
}
|
|
2938
3057
|
var program = createCli();
|
|
2939
|
-
program.
|
|
3058
|
+
program.parseAsync().catch((error) => {
|
|
3059
|
+
if (error?.name === "ExitPromptError" || error?.message?.includes("SIGINT")) {
|
|
3060
|
+
process.exit(130);
|
|
3061
|
+
}
|
|
3062
|
+
console.error(error);
|
|
3063
|
+
process.exit(1);
|
|
3064
|
+
});
|
|
2940
3065
|
//# sourceMappingURL=cli.js.map
|