great-cto 2.67.0 → 2.69.0
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/main.js +42 -11
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -41,6 +41,7 @@ function parseArgs(argv) {
|
|
|
41
41
|
command: "init",
|
|
42
42
|
boardPort: 3141,
|
|
43
43
|
boardNoOpen: false,
|
|
44
|
+
consoleBind: null,
|
|
44
45
|
dir: process.cwd(),
|
|
45
46
|
yes: false,
|
|
46
47
|
dryRun: false,
|
|
@@ -87,8 +88,14 @@ function parseArgs(argv) {
|
|
|
87
88
|
const v = a.slice("--host=".length);
|
|
88
89
|
args.host = (v === "codex" || v === "claude-code") ? v : null;
|
|
89
90
|
}
|
|
91
|
+
else if (a === "--bind")
|
|
92
|
+
args.consoleBind = argv[++i] ?? null;
|
|
93
|
+
else if (a.startsWith("--bind="))
|
|
94
|
+
args.consoleBind = a.slice("--bind=".length) || null;
|
|
90
95
|
else if (a === "board")
|
|
91
96
|
args.command = "board";
|
|
97
|
+
else if (a === "console")
|
|
98
|
+
args.command = "console";
|
|
92
99
|
else if (a === "register")
|
|
93
100
|
args.command = "register";
|
|
94
101
|
else if (a === "ci")
|
|
@@ -187,8 +194,10 @@ async function runRegister(args) {
|
|
|
187
194
|
}
|
|
188
195
|
// ── Board server lifecycle helpers ───────────────────────────────────────────
|
|
189
196
|
/** Absolute path to the board PID file (persists across CLI invocations). */
|
|
190
|
-
function boardPidFilePath() {
|
|
191
|
-
|
|
197
|
+
function boardPidFilePath(surface) {
|
|
198
|
+
// The two surfaces are separate processes with separate lifecycles — a console
|
|
199
|
+
// start must never kill the builder board (and vice versa).
|
|
200
|
+
return join(homedir(), ".great_cto", surface === "console" ? "console.pid" : "board.pid");
|
|
192
201
|
}
|
|
193
202
|
/**
|
|
194
203
|
* Locate the board server.mjs — checks dev layouts then plugin cache versions
|
|
@@ -217,8 +226,8 @@ function findBoardServerPath() {
|
|
|
217
226
|
* Kill the board server recorded in the PID file.
|
|
218
227
|
* Returns true if a live process was terminated.
|
|
219
228
|
*/
|
|
220
|
-
async function killExistingBoard() {
|
|
221
|
-
const pidFile = boardPidFilePath();
|
|
229
|
+
async function killExistingBoard(surface) {
|
|
230
|
+
const pidFile = boardPidFilePath(surface);
|
|
222
231
|
if (!fsExistsSync(pidFile))
|
|
223
232
|
return false;
|
|
224
233
|
const raw = readFileSync(pidFile, "utf8").trim();
|
|
@@ -296,12 +305,12 @@ async function restartBoardAfterUpgrade(port) {
|
|
|
296
305
|
log(` ${green("✓")} board restarted → http://localhost:${port}`);
|
|
297
306
|
}
|
|
298
307
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
299
|
-
async function runBoard(args) {
|
|
308
|
+
async function runBoard(args, surface) {
|
|
300
309
|
const { spawn } = await import("node:child_process");
|
|
301
|
-
// Stop any existing
|
|
302
|
-
const killed = await killExistingBoard();
|
|
310
|
+
// Stop any existing server OF THIS SURFACE (board and console run side by side)
|
|
311
|
+
const killed = await killExistingBoard(surface);
|
|
303
312
|
if (killed) {
|
|
304
|
-
log(` ${dim("stopped previous board server")}`);
|
|
313
|
+
log(` ${dim(surface === "console" ? "stopped previous console server" : "stopped previous board server")}`);
|
|
305
314
|
}
|
|
306
315
|
const serverPath = findBoardServerPath();
|
|
307
316
|
if (!serverPath) {
|
|
@@ -311,20 +320,25 @@ async function runBoard(args) {
|
|
|
311
320
|
const nodeArgs = [serverPath];
|
|
312
321
|
if (args.boardNoOpen)
|
|
313
322
|
nodeArgs.push("--no-open");
|
|
323
|
+
if (surface)
|
|
324
|
+
nodeArgs.push("--surface", surface);
|
|
325
|
+
const env = { ...process.env, BOARD_PORT: String(args.boardPort) };
|
|
326
|
+
if (surface === "console" && args.consoleBind)
|
|
327
|
+
env.GREAT_CTO_HOST = args.consoleBind;
|
|
314
328
|
const child = spawn(process.execPath, nodeArgs, {
|
|
315
|
-
env
|
|
329
|
+
env,
|
|
316
330
|
stdio: "inherit",
|
|
317
331
|
detached: false,
|
|
318
332
|
});
|
|
319
333
|
// Write PID so future invocations (including init upgrades) can find us
|
|
320
334
|
try {
|
|
321
335
|
mkdirSync(join(homedir(), ".great_cto"), { recursive: true });
|
|
322
|
-
writeFileSync(boardPidFilePath(), String(child.pid));
|
|
336
|
+
writeFileSync(boardPidFilePath(surface), String(child.pid));
|
|
323
337
|
}
|
|
324
338
|
catch { /* best-effort */ }
|
|
325
339
|
child.on("exit", code => {
|
|
326
340
|
try {
|
|
327
|
-
unlinkSync(boardPidFilePath());
|
|
341
|
+
unlinkSync(boardPidFilePath(surface));
|
|
328
342
|
}
|
|
329
343
|
catch { /* ignore */ }
|
|
330
344
|
process.exit(code ?? 0);
|
|
@@ -338,6 +352,7 @@ ${bold("Usage:")}
|
|
|
338
352
|
npx great-cto install [options] Same as init
|
|
339
353
|
npx great-cto [init] [options] Detect + bootstrap
|
|
340
354
|
npx great-cto board [--port 3141] [--no-open]
|
|
355
|
+
npx great-cto console [--port 8788] [--bind 0.0.0.0] [--no-open]
|
|
341
356
|
npx great-cto register [--dir PATH]
|
|
342
357
|
npx great-cto ci [path] [--no-archetype] [--no-budget]
|
|
343
358
|
npx great-cto mcp [--sse --port N]
|
|
@@ -352,6 +367,12 @@ ${bold("Board:")}
|
|
|
352
367
|
great-cto board --port 4000 Use a different port
|
|
353
368
|
great-cto board --no-open Start server without opening browser
|
|
354
369
|
|
|
370
|
+
${bold("Operator console (the second surface — invite-only, hostable):")}
|
|
371
|
+
great-cto console Serve ONLY the operator console (no dev board)
|
|
372
|
+
great-cto console --port 8788 Different port
|
|
373
|
+
great-cto console --bind 0.0.0.0 Reachable beyond this machine (tunnel/hosting);
|
|
374
|
+
operators sign in via invite links
|
|
375
|
+
|
|
355
376
|
${bold("Register:")}
|
|
356
377
|
great-cto register Add this repo to ~/.great_cto/projects.json
|
|
357
378
|
(auto-discovered after /audit or /start, but
|
|
@@ -972,6 +993,16 @@ async function main() {
|
|
|
972
993
|
process.exit(1);
|
|
973
994
|
}
|
|
974
995
|
}
|
|
996
|
+
if (args.command === "console") {
|
|
997
|
+
try {
|
|
998
|
+
const code = await runBoard(args, "console");
|
|
999
|
+
process.exit(code);
|
|
1000
|
+
}
|
|
1001
|
+
catch (e) {
|
|
1002
|
+
error(e.message);
|
|
1003
|
+
process.exit(1);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
975
1006
|
if (args.command === "register") {
|
|
976
1007
|
try {
|
|
977
1008
|
const code = await runRegister(args);
|
package/package.json
CHANGED