forge-cw 0.1.1 → 0.1.3
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/cw/.bundle.json +1 -1
- package/cw/lib/harnesses/claude.sh +1 -1
- package/dist/index.js +73 -3
- package/package.json +3 -3
package/cw/.bundle.json
CHANGED
package/dist/index.js
CHANGED
|
@@ -4332,6 +4332,52 @@ var init_cw_install = __esm({
|
|
|
4332
4332
|
}
|
|
4333
4333
|
});
|
|
4334
4334
|
|
|
4335
|
+
// ../core/dist/port-in-use.js
|
|
4336
|
+
function waitForListening(server) {
|
|
4337
|
+
if (server.listening)
|
|
4338
|
+
return Promise.resolve();
|
|
4339
|
+
return new Promise((resolve5, reject) => {
|
|
4340
|
+
const onError = (err) => {
|
|
4341
|
+
server.off("listening", onListening);
|
|
4342
|
+
reject(err);
|
|
4343
|
+
};
|
|
4344
|
+
const onListening = () => {
|
|
4345
|
+
server.off("error", onError);
|
|
4346
|
+
resolve5();
|
|
4347
|
+
};
|
|
4348
|
+
server.once("error", onError);
|
|
4349
|
+
server.once("listening", onListening);
|
|
4350
|
+
});
|
|
4351
|
+
}
|
|
4352
|
+
async function probePort(port, timeoutMs = 1500) {
|
|
4353
|
+
try {
|
|
4354
|
+
const res = await fetch(`http://127.0.0.1:${port}/api/health`, { signal: AbortSignal.timeout(timeoutMs) });
|
|
4355
|
+
const body = await res.json().catch(() => null);
|
|
4356
|
+
return body?.status === "ok" && typeof body.modules === "number" ? "forge" : "other";
|
|
4357
|
+
} catch (err) {
|
|
4358
|
+
return err.name === "TimeoutError" ? "unresponsive" : "other";
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
function portInUseMessage(port, holder) {
|
|
4362
|
+
const next = `Start on another port with --port ${port + 1} (or FORGE_PORT=${port + 1}).`;
|
|
4363
|
+
const find = `Find it with: lsof -nP -iTCP:${port} -sTCP:LISTEN`;
|
|
4364
|
+
if (holder === "forge")
|
|
4365
|
+
return `Forge is already running at http://localhost:${port}.`;
|
|
4366
|
+
if (holder === "unresponsive") {
|
|
4367
|
+
return [
|
|
4368
|
+
`Port ${port} is taken by a process that does not answer, often a Forge suspended with Ctrl+Z.`,
|
|
4369
|
+
`${find}, then bring it back with \`fg\` in its terminal or stop it with \`kill <pid>\`.`,
|
|
4370
|
+
next
|
|
4371
|
+
].join("\n ");
|
|
4372
|
+
}
|
|
4373
|
+
return [`Port ${port} is in use by another program.`, find, next].join("\n ");
|
|
4374
|
+
}
|
|
4375
|
+
var init_port_in_use = __esm({
|
|
4376
|
+
"../core/dist/port-in-use.js"() {
|
|
4377
|
+
"use strict";
|
|
4378
|
+
}
|
|
4379
|
+
});
|
|
4380
|
+
|
|
4335
4381
|
// ../core/dist/index.js
|
|
4336
4382
|
var dist_exports = {};
|
|
4337
4383
|
__export(dist_exports, {
|
|
@@ -4357,10 +4403,13 @@ __export(dist_exports, {
|
|
|
4357
4403
|
getForgeDir: () => getForgeDir,
|
|
4358
4404
|
liveframeRoutes: () => liveframeRoutes,
|
|
4359
4405
|
pathWithCw: () => pathWithCw,
|
|
4406
|
+
portInUseMessage: () => portInUseMessage,
|
|
4407
|
+
probePort: () => probePort,
|
|
4360
4408
|
quietSqliteWarning: () => quietSqliteWarning,
|
|
4361
4409
|
resolveListenOptions: () => resolveListenOptions,
|
|
4362
4410
|
skillRoutes: () => skillRoutes,
|
|
4363
|
-
supports: () => supports
|
|
4411
|
+
supports: () => supports,
|
|
4412
|
+
waitForListening: () => waitForListening
|
|
4364
4413
|
});
|
|
4365
4414
|
var init_dist = __esm({
|
|
4366
4415
|
"../core/dist/index.js"() {
|
|
@@ -4383,6 +4432,7 @@ var init_dist = __esm({
|
|
|
4383
4432
|
init_pty_routes();
|
|
4384
4433
|
init_liveframe_routes();
|
|
4385
4434
|
init_liveframe();
|
|
4435
|
+
init_port_in_use();
|
|
4386
4436
|
}
|
|
4387
4437
|
});
|
|
4388
4438
|
|
|
@@ -4404,7 +4454,7 @@ var packageRoot = join15(import.meta.dirname, "..");
|
|
|
4404
4454
|
var isCheckout = existsSync14(join15(packageRoot, "src"));
|
|
4405
4455
|
var consoleDist = isCheckout ? join15(packageRoot, "../console/dist") : join15(packageRoot, "console");
|
|
4406
4456
|
async function main() {
|
|
4407
|
-
const { ensureForgeDir: ensureForgeDir2, createForgeServer: createForgeServer2, createDatabase: createDatabase2, resolveListenOptions: resolveListenOptions2, ensureCw: ensureCw2, pathWithCw: pathWithCw2, quietSqliteWarning: quietSqliteWarning2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
4457
|
+
const { ensureForgeDir: ensureForgeDir2, createForgeServer: createForgeServer2, createDatabase: createDatabase2, resolveListenOptions: resolveListenOptions2, ensureCw: ensureCw2, pathWithCw: pathWithCw2, quietSqliteWarning: quietSqliteWarning2, waitForListening: waitForListening2, probePort: probePort2, portInUseMessage: portInUseMessage2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
4408
4458
|
quietSqliteWarning2();
|
|
4409
4459
|
const args = parseArgs(process.argv.slice(2));
|
|
4410
4460
|
const { forgeDir, created } = ensureForgeDir2();
|
|
@@ -4443,6 +4493,23 @@ async function main() {
|
|
|
4443
4493
|
}
|
|
4444
4494
|
const { serve } = await import("@hono/node-server");
|
|
4445
4495
|
const httpServer = serve({ fetch: server.app.fetch, port, hostname: host });
|
|
4496
|
+
try {
|
|
4497
|
+
await waitForListening2(httpServer);
|
|
4498
|
+
} catch (err) {
|
|
4499
|
+
if (err.code !== "EADDRINUSE") throw err;
|
|
4500
|
+
const holder = await probePort2(port);
|
|
4501
|
+
console.log(`
|
|
4502
|
+
${portInUseMessage2(port, holder)}
|
|
4503
|
+
`);
|
|
4504
|
+
if (holder === "forge" && args.open && process.env.FORGE_NO_OPEN !== "1") {
|
|
4505
|
+
try {
|
|
4506
|
+
const open = (await import("open")).default;
|
|
4507
|
+
await open(`http://localhost:${port}`);
|
|
4508
|
+
} catch {
|
|
4509
|
+
}
|
|
4510
|
+
}
|
|
4511
|
+
process.exit(holder === "forge" ? 0 : 1);
|
|
4512
|
+
}
|
|
4446
4513
|
server.attachTerminalWs(httpServer);
|
|
4447
4514
|
console.log(`
|
|
4448
4515
|
Forge Console running at http://localhost:${port}
|
|
@@ -4461,4 +4528,7 @@ ${authToken ? " Auth: bearer token required\n" : ""}
|
|
|
4461
4528
|
}
|
|
4462
4529
|
}
|
|
4463
4530
|
}
|
|
4464
|
-
main().catch(
|
|
4531
|
+
main().catch((err) => {
|
|
4532
|
+
console.error(err);
|
|
4533
|
+
process.exit(1);
|
|
4534
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forge-cw",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A visual dashboard for your coding agents on Claude Code, Codex, Pi or OpenCode. Installs CW for you.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"@types/node": "^22.0.0",
|
|
40
40
|
"esbuild": "^0.25.0",
|
|
41
41
|
"typescript": "^5.8.0",
|
|
42
|
-
"@forge-dev/
|
|
43
|
-
"@forge-dev/
|
|
42
|
+
"@forge-dev/core": "0.1.0",
|
|
43
|
+
"@forge-dev/console": "0.1.0"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "tsc",
|