sparkecoder 0.1.6 → 0.1.8
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/agent/index.js +2 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +130 -35
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +125 -34
- package/dist/index.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +125 -34
- package/dist/server/index.js.map +1 -1
- package/dist/tools/index.js +2 -1
- package/dist/tools/index.js.map +1 -1
- package/package.json +4 -1
package/dist/cli.js
CHANGED
|
@@ -1166,7 +1166,8 @@ async function runBackground(command, workingDirectory, options) {
|
|
|
1166
1166
|
cwd: workingDirectory,
|
|
1167
1167
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1168
1168
|
sessionId: options.sessionId,
|
|
1169
|
-
background: true
|
|
1169
|
+
background: true,
|
|
1170
|
+
name: options.name
|
|
1170
1171
|
}, workingDirectory);
|
|
1171
1172
|
const logFile = join2(logDir, "output.log");
|
|
1172
1173
|
const wrappedCommand = `(${command}) 2>&1 | tee -a ${shellEscape(logFile)}`;
|
|
@@ -3989,7 +3990,10 @@ terminals2.post(
|
|
|
3989
3990
|
return c.json({ error: "tmux is not installed. Background terminals require tmux." }, 400);
|
|
3990
3991
|
}
|
|
3991
3992
|
const workingDirectory = body.cwd || session.workingDirectory;
|
|
3992
|
-
const result = await runBackground(body.command, workingDirectory, {
|
|
3993
|
+
const result = await runBackground(body.command, workingDirectory, {
|
|
3994
|
+
sessionId,
|
|
3995
|
+
name: body.name
|
|
3996
|
+
});
|
|
3993
3997
|
return c.json({
|
|
3994
3998
|
id: result.id,
|
|
3995
3999
|
name: body.name || null,
|
|
@@ -4013,7 +4017,7 @@ terminals2.get("/:sessionId/terminals", async (c) => {
|
|
|
4013
4017
|
const running = await isRunning(meta.id);
|
|
4014
4018
|
return {
|
|
4015
4019
|
id: meta.id,
|
|
4016
|
-
name: null,
|
|
4020
|
+
name: meta.name || null,
|
|
4017
4021
|
command: meta.command,
|
|
4018
4022
|
cwd: meta.cwd,
|
|
4019
4023
|
status: running ? "running" : "stopped",
|
|
@@ -4097,10 +4101,17 @@ terminals2.post(
|
|
|
4097
4101
|
"/:sessionId/terminals/:terminalId/write",
|
|
4098
4102
|
zValidator4("json", writeSchema),
|
|
4099
4103
|
async (c) => {
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
+
const terminalId = c.req.param("terminalId");
|
|
4105
|
+
const body = c.req.valid("json");
|
|
4106
|
+
const isRunning2 = await isRunning(terminalId);
|
|
4107
|
+
if (!isRunning2) {
|
|
4108
|
+
return c.json({ error: "Terminal is not running" }, 400);
|
|
4109
|
+
}
|
|
4110
|
+
const success = await sendInput(terminalId, body.input, { pressEnter: false });
|
|
4111
|
+
if (!success) {
|
|
4112
|
+
return c.json({ error: "Failed to write to terminal" }, 500);
|
|
4113
|
+
}
|
|
4114
|
+
return c.json({ success: true, written: body.input.length });
|
|
4104
4115
|
}
|
|
4105
4116
|
);
|
|
4106
4117
|
terminals2.post("/:sessionId/terminals/kill-all", async (c) => {
|
|
@@ -4109,12 +4120,12 @@ terminals2.post("/:sessionId/terminals/kill-all", async (c) => {
|
|
|
4109
4120
|
if (!session) {
|
|
4110
4121
|
return c.json({ error: "Session not found" }, 404);
|
|
4111
4122
|
}
|
|
4112
|
-
const
|
|
4123
|
+
const sessionTerminals = await listSessionTerminals(sessionId, session.workingDirectory);
|
|
4113
4124
|
let killed = 0;
|
|
4114
|
-
for (const
|
|
4115
|
-
const
|
|
4116
|
-
if (
|
|
4117
|
-
const success = await killTerminal(id);
|
|
4125
|
+
for (const terminal of sessionTerminals) {
|
|
4126
|
+
const isRunning2 = await isRunning(terminal.id);
|
|
4127
|
+
if (isRunning2) {
|
|
4128
|
+
const success = await killTerminal(terminal.id);
|
|
4118
4129
|
if (success) killed++;
|
|
4119
4130
|
}
|
|
4120
4131
|
}
|
|
@@ -4467,6 +4478,33 @@ async function findWebPort(preferredPort) {
|
|
|
4467
4478
|
}
|
|
4468
4479
|
return { port: preferredPort, alreadyRunning: false };
|
|
4469
4480
|
}
|
|
4481
|
+
function hasProductionBuild(webDir) {
|
|
4482
|
+
const buildIdPath = join3(webDir, ".next", "BUILD_ID");
|
|
4483
|
+
return existsSync7(buildIdPath);
|
|
4484
|
+
}
|
|
4485
|
+
function runCommand(command, args, cwd, env) {
|
|
4486
|
+
return new Promise((resolve8) => {
|
|
4487
|
+
const child = spawn(command, args, {
|
|
4488
|
+
cwd,
|
|
4489
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4490
|
+
env,
|
|
4491
|
+
shell: true
|
|
4492
|
+
});
|
|
4493
|
+
let output = "";
|
|
4494
|
+
child.stdout?.on("data", (data) => {
|
|
4495
|
+
output += data.toString();
|
|
4496
|
+
});
|
|
4497
|
+
child.stderr?.on("data", (data) => {
|
|
4498
|
+
output += data.toString();
|
|
4499
|
+
});
|
|
4500
|
+
child.on("close", (code) => {
|
|
4501
|
+
resolve8({ success: code === 0, output });
|
|
4502
|
+
});
|
|
4503
|
+
child.on("error", (err) => {
|
|
4504
|
+
resolve8({ success: false, output: err.message });
|
|
4505
|
+
});
|
|
4506
|
+
});
|
|
4507
|
+
}
|
|
4470
4508
|
async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false) {
|
|
4471
4509
|
const webDir = getWebDirectory();
|
|
4472
4510
|
if (!webDir) {
|
|
@@ -4478,39 +4516,90 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false) {
|
|
|
4478
4516
|
if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
|
|
4479
4517
|
return { process: null, port: actualPort };
|
|
4480
4518
|
}
|
|
4481
|
-
const
|
|
4482
|
-
const
|
|
4483
|
-
const
|
|
4519
|
+
const usePnpm = existsSync7(join3(webDir, "pnpm-lock.yaml"));
|
|
4520
|
+
const useNpm = !usePnpm && existsSync7(join3(webDir, "package-lock.json"));
|
|
4521
|
+
const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
|
|
4522
|
+
const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
|
|
4523
|
+
const webEnv = {
|
|
4524
|
+
...cleanEnv,
|
|
4525
|
+
NEXT_PUBLIC_API_URL: `http://127.0.0.1:${apiPort}`
|
|
4526
|
+
};
|
|
4527
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
4528
|
+
let command;
|
|
4529
|
+
let args;
|
|
4530
|
+
if (isProduction) {
|
|
4531
|
+
if (!hasProductionBuild(webDir)) {
|
|
4532
|
+
if (!quiet) console.log(" \u{1F4E6} Building Web UI for production...");
|
|
4533
|
+
const buildArgs = pkgManager === "npx" ? ["next", "build"] : ["run", "build"];
|
|
4534
|
+
const buildResult = await runCommand(pkgManager, buildArgs, webDir, webEnv);
|
|
4535
|
+
if (!buildResult.success) {
|
|
4536
|
+
if (!quiet) console.error(" \u274C Web UI build failed");
|
|
4537
|
+
return { process: null, port: actualPort };
|
|
4538
|
+
}
|
|
4539
|
+
if (!quiet) console.log(" \u2713 Web UI build complete");
|
|
4540
|
+
}
|
|
4541
|
+
command = pkgManager;
|
|
4542
|
+
args = pkgManager === "npx" ? ["next", "start", "-p", String(actualPort)] : ["run", "start", "-p", String(actualPort)];
|
|
4543
|
+
} else {
|
|
4544
|
+
command = pkgManager;
|
|
4545
|
+
args = pkgManager === "npx" ? ["next", "dev", "-p", String(actualPort)] : ["run", "dev", "-p", String(actualPort)];
|
|
4546
|
+
}
|
|
4484
4547
|
const child = spawn(command, args, {
|
|
4485
4548
|
cwd: webDir,
|
|
4486
4549
|
stdio: ["ignore", "pipe", "pipe"],
|
|
4487
|
-
env:
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
},
|
|
4491
|
-
detached: false
|
|
4550
|
+
env: webEnv,
|
|
4551
|
+
detached: false,
|
|
4552
|
+
shell: true
|
|
4492
4553
|
});
|
|
4554
|
+
const startupTimeout = 3e4;
|
|
4493
4555
|
let started = false;
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
if (!
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4556
|
+
let exited = false;
|
|
4557
|
+
let exitCode = null;
|
|
4558
|
+
const startedPromise = new Promise((resolve8) => {
|
|
4559
|
+
const timeout = setTimeout(() => {
|
|
4560
|
+
if (!started && !exited) {
|
|
4561
|
+
resolve8(false);
|
|
4562
|
+
}
|
|
4563
|
+
}, startupTimeout);
|
|
4564
|
+
child.stdout?.on("data", (data) => {
|
|
4565
|
+
const output = data.toString();
|
|
4566
|
+
if (!started && (output.includes("Ready") || output.includes("started") || output.includes("localhost"))) {
|
|
4567
|
+
started = true;
|
|
4568
|
+
clearTimeout(timeout);
|
|
4569
|
+
resolve8(true);
|
|
4570
|
+
}
|
|
4571
|
+
});
|
|
4502
4572
|
child.stderr?.on("data", (data) => {
|
|
4503
4573
|
const output = data.toString();
|
|
4504
4574
|
if (output.toLowerCase().includes("error")) {
|
|
4505
|
-
console.error(` Web UI error: ${output.trim()}`);
|
|
4575
|
+
if (!quiet) console.error(` Web UI error: ${output.trim().slice(0, 200)}`);
|
|
4506
4576
|
}
|
|
4507
4577
|
});
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4578
|
+
child.on("error", (err) => {
|
|
4579
|
+
if (!quiet) console.error(` \u274C Web UI spawn error: ${err.message}`);
|
|
4580
|
+
clearTimeout(timeout);
|
|
4581
|
+
resolve8(false);
|
|
4582
|
+
});
|
|
4583
|
+
child.on("exit", (code) => {
|
|
4584
|
+
exited = true;
|
|
4585
|
+
exitCode = code;
|
|
4586
|
+
if (!started) {
|
|
4587
|
+
clearTimeout(timeout);
|
|
4588
|
+
resolve8(false);
|
|
4589
|
+
}
|
|
4590
|
+
webUIProcess = null;
|
|
4591
|
+
});
|
|
4511
4592
|
});
|
|
4512
4593
|
webUIProcess = child;
|
|
4513
|
-
|
|
4594
|
+
const didStart = await startedPromise;
|
|
4595
|
+
if (!didStart) {
|
|
4596
|
+
if (exited && exitCode !== 0) {
|
|
4597
|
+
if (!quiet) console.error(` \u274C Web UI failed to start (exit code: ${exitCode})`);
|
|
4598
|
+
} else if (!exited) {
|
|
4599
|
+
if (!quiet) console.log(` \u26A0 Web UI startup timed out, continuing anyway...`);
|
|
4600
|
+
}
|
|
4601
|
+
}
|
|
4602
|
+
return { process: child, port: actualPort, started: didStart };
|
|
4514
4603
|
}
|
|
4515
4604
|
function stopWebUI() {
|
|
4516
4605
|
if (webUIProcess) {
|
|
@@ -4604,11 +4693,13 @@ async function startServer(options = {}) {
|
|
|
4604
4693
|
hostname: host
|
|
4605
4694
|
});
|
|
4606
4695
|
let webPort;
|
|
4696
|
+
let webStarted;
|
|
4607
4697
|
if (options.webUI !== false) {
|
|
4608
4698
|
const result = await startWebUI(port, options.webPort || DEFAULT_WEB_PORT, options.quiet);
|
|
4609
4699
|
webPort = result.port;
|
|
4700
|
+
webStarted = result.started;
|
|
4610
4701
|
}
|
|
4611
|
-
return { app, port, host, webPort };
|
|
4702
|
+
return { app, port, host, webPort, webStarted };
|
|
4612
4703
|
}
|
|
4613
4704
|
function stopServer() {
|
|
4614
4705
|
stopWebUI();
|
|
@@ -5274,7 +5365,11 @@ async function runChat(options) {
|
|
|
5274
5365
|
});
|
|
5275
5366
|
serverStartedByUs = true;
|
|
5276
5367
|
const webUrl = `http://localhost:${serverResult.webPort || options.webPort || "6969"}`;
|
|
5277
|
-
|
|
5368
|
+
if (serverResult.webStarted === false) {
|
|
5369
|
+
spinner.warn(`Web UI failed to start at ${chalk.cyan(webUrl)}`);
|
|
5370
|
+
} else {
|
|
5371
|
+
spinner.succeed(`Web UI: ${chalk.cyan(webUrl)}`);
|
|
5372
|
+
}
|
|
5278
5373
|
const cleanup = () => {
|
|
5279
5374
|
if (serverStartedByUs) {
|
|
5280
5375
|
stopServer();
|