Skip to content

Commit bfc1257

Browse files
fix(windows): add shell:true to spawn calls and EPERM fallback for rename
- plugin-loader.js: add shell:true to 3 npm spawn calls (ENOENT on Windows) - taskmaster.js: add shell:true to 6 npx/task-master spawn calls - CronTaskStore.ts: catch EPERM/EACCES on rename, fallback to copyFile+unlink Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 6d4f288 commit bfc1257

3 files changed

Lines changed: 27 additions & 8 deletions

File tree

src/cron/storage/CronTaskStore.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { appendFile, mkdir, readFile, rename, writeFile } from "node:fs/promises";
1+
import { appendFile, copyFile, mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
22
import { dirname } from "node:path";
33
import type { GatewayEvent } from "../../gateway/index.js";
44
import type { CronRunRecord, CronTask } from "../protocol/types.js";
@@ -120,7 +120,17 @@ export class CronTaskStore {
120120
await mkdir(dirname(this.paths.tasksFile), { recursive: true });
121121
const tempPath = `${this.paths.tasksFile}.${process.pid}.${Date.now()}.tmp`;
122122
await writeFile(tempPath, JSON.stringify(file, null, 2), "utf-8");
123-
await rename(tempPath, this.paths.tasksFile);
123+
try {
124+
await rename(tempPath, this.paths.tasksFile);
125+
} catch (err: unknown) {
126+
const code = (err as NodeJS.ErrnoException).code;
127+
if (code === "EPERM" || code === "EACCES") {
128+
await copyFile(tempPath, this.paths.tasksFile);
129+
await unlink(tempPath).catch(() => {});
130+
} else {
131+
throw err;
132+
}
133+
}
124134
}
125135
}
126136

ui/server/routes/taskmaster.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,8 @@ router.get('/next/:projectName', async (req, res) => {
478478

479479
const nextTaskCommand = spawn('task-master', ['next'], {
480480
cwd: projectPath,
481-
stdio: ['pipe', 'pipe', 'pipe']
481+
stdio: ['pipe', 'pipe', 'pipe'],
482+
shell: true
482483
});
483484

484485
let stdout = '';
@@ -998,7 +999,8 @@ router.post('/init/:projectName', async (req, res) => {
998999
// Run taskmaster init command
9991000
const initProcess = spawn('npx', ['task-master', 'init'], {
10001001
cwd: projectPath,
1001-
stdio: ['pipe', 'pipe', 'pipe']
1002+
stdio: ['pipe', 'pipe', 'pipe'],
1003+
shell: true
10021004
});
10031005

10041006
let stdout = '';
@@ -1101,7 +1103,8 @@ router.post('/add-task/:projectName', async (req, res) => {
11011103
// Run task-master add-task command
11021104
const addTaskProcess = spawn('npx', args, {
11031105
cwd: projectPath,
1104-
stdio: ['pipe', 'pipe', 'pipe']
1106+
stdio: ['pipe', 'pipe', 'pipe'],
1107+
shell: true
11051108
});
11061109

11071110
let stdout = '';
@@ -1181,7 +1184,8 @@ router.put('/update-task/:projectName/:taskId', async (req, res) => {
11811184
if (status && Object.keys(req.body).length === 1) {
11821185
const setStatusProcess = spawn('npx', ['task-master-ai', 'set-status', `--id=${taskId}`, `--status=${status}`], {
11831186
cwd: projectPath,
1184-
stdio: ['pipe', 'pipe', 'pipe']
1187+
stdio: ['pipe', 'pipe', 'pipe'],
1188+
shell: true
11851189
});
11861190

11871191
let stdout = '';
@@ -1233,7 +1237,8 @@ router.put('/update-task/:projectName/:taskId', async (req, res) => {
12331237

12341238
const updateProcess = spawn('npx', ['task-master-ai', 'update-task', `--id=${taskId}`, `--prompt=${prompt}`], {
12351239
cwd: projectPath,
1236-
stdio: ['pipe', 'pipe', 'pipe']
1240+
stdio: ['pipe', 'pipe', 'pipe'],
1241+
shell: true
12371242
});
12381243

12391244
let stdout = '';
@@ -1332,7 +1337,8 @@ router.post('/parse-prd/:projectName', async (req, res) => {
13321337
// Run task-master parse-prd command
13331338
const parsePRDProcess = spawn('npx', args, {
13341339
cwd: projectPath,
1335-
stdio: ['pipe', 'pipe', 'pipe']
1340+
stdio: ['pipe', 'pipe', 'pipe'],
1341+
shell: true
13361342
});
13371343

13381344
let stdout = '';

ui/server/utils/plugin-loader.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ function runBuildIfNeeded(dir, packageJsonPath, onSuccess, onError) {
109109
const buildProcess = spawn('npm', ['run', 'build'], {
110110
cwd: dir,
111111
stdio: ['ignore', 'pipe', 'pipe'],
112+
shell: true,
112113
});
113114

114115
let stderr = '';
@@ -341,6 +342,7 @@ export function installPluginFromGit(url) {
341342
const npmProcess = spawn('npm', ['install', '--ignore-scripts'], {
342343
cwd: tempDir,
343344
stdio: ['ignore', 'pipe', 'pipe'],
345+
shell: true,
344346
});
345347

346348
npmProcess.on('close', (npmCode) => {
@@ -408,6 +410,7 @@ export function updatePluginFromGit(name) {
408410
const npmProcess = spawn('npm', ['install', '--ignore-scripts'], {
409411
cwd: pluginDir,
410412
stdio: ['ignore', 'pipe', 'pipe'],
413+
shell: true,
411414
});
412415
npmProcess.on('close', (npmCode) => {
413416
if (npmCode !== 0) {

0 commit comments

Comments
 (0)