lazyclaw 3.99.8 → 3.99.9
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/README.md +1 -1
- package/cli.mjs +68 -26
- package/package.json +1 -1
package/README.md
CHANGED
package/cli.mjs
CHANGED
|
@@ -3407,16 +3407,23 @@ async function cmdSetup(_sub, _positional, flags = {}) {
|
|
|
3407
3407
|
try {
|
|
3408
3408
|
await cmdOnboard({ pick: true });
|
|
3409
3409
|
} catch (e) {
|
|
3410
|
+
// Don't kill the process — the setup wizard is often called
|
|
3411
|
+
// from inside cmdLauncher's loop, and a process.exit there
|
|
3412
|
+
// would close the launcher entirely (the surface bug the
|
|
3413
|
+
// user reported as "Setup 누르고 엔터 누르니까 바로 꺼져").
|
|
3414
|
+
// Surface the error and let the caller decide.
|
|
3410
3415
|
process.stderr.write(`onboard error: ${e?.message || e}\n`);
|
|
3411
|
-
|
|
3416
|
+
return;
|
|
3412
3417
|
}
|
|
3413
3418
|
// Re-read config after onboard wrote it. If the user aborted with
|
|
3414
3419
|
// no provider set, bail out early — the rest of the wizard depends
|
|
3415
|
-
// on a provider being configured.
|
|
3420
|
+
// on a provider being configured. `return` (not process.exit) so a
|
|
3421
|
+
// launcher caller can re-prompt or fall back gracefully.
|
|
3416
3422
|
const cfgAfterOnboard = readConfig();
|
|
3417
3423
|
if (!cfgAfterOnboard.provider) {
|
|
3418
|
-
process.stdout.write(`\n ${warn('Setup
|
|
3419
|
-
process.
|
|
3424
|
+
process.stdout.write(`\n ${warn('Setup not completed — provider was not configured.')}\n`);
|
|
3425
|
+
process.stdout.write(` ${dim('Run `lazyclaw setup` again when ready, or pick "Onboard" from the menu for a single-step picker.')}\n\n`);
|
|
3426
|
+
return;
|
|
3420
3427
|
}
|
|
3421
3428
|
process.stdout.write(`\n ${ok('✓ provider:')} ${cfgAfterOnboard.provider} ${dim('model:')} ${cfgAfterOnboard.model || '(default)'}\n\n`);
|
|
3422
3429
|
|
|
@@ -3543,34 +3550,69 @@ async function _runFirstTimeOnboard() {
|
|
|
3543
3550
|
process.stdout.write('\n');
|
|
3544
3551
|
}
|
|
3545
3552
|
|
|
3553
|
+
// Marker exception used by the launcher's process.exit guard. See
|
|
3554
|
+
// _dispatchMenuChoice below for why intercepting process.exit is
|
|
3555
|
+
// the cleanest way to keep the menu loop alive.
|
|
3556
|
+
class _DispatchExit extends Error {
|
|
3557
|
+
constructor(code) {
|
|
3558
|
+
super(`subcommand requested exit ${code}`);
|
|
3559
|
+
this.name = 'DispatchExit';
|
|
3560
|
+
this.exitCode = Number.isFinite(code) ? code : 0;
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3546
3564
|
// Direct dispatch from a launcher pick. Replaces the previous
|
|
3547
3565
|
// `process.argv = [...]; await main()` round-trip so we can reuse
|
|
3548
3566
|
// the launcher across multiple iterations without compounding
|
|
3549
|
-
// state.
|
|
3550
|
-
//
|
|
3567
|
+
// state.
|
|
3568
|
+
//
|
|
3569
|
+
// Subcommand functions across this CLI freely call `process.exit()`
|
|
3570
|
+
// to signal their result — perfectly fine for one-shot CLI use,
|
|
3571
|
+
// fatal to a launcher loop because the first exit kills the whole
|
|
3572
|
+
// process before we can redraw the menu. Intercept process.exit for
|
|
3573
|
+
// the duration of the dispatch and turn it into a thrown exception
|
|
3574
|
+
// the loop can catch + log + continue from. This mirrors how Python
|
|
3575
|
+
// CLI frameworks handle SystemExit when running inside a REPL.
|
|
3551
3576
|
async function _dispatchMenuChoice(argv) {
|
|
3552
3577
|
const sub = argv[0];
|
|
3553
3578
|
const rest = argv.slice(1);
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3579
|
+
const realExit = process.exit.bind(process);
|
|
3580
|
+
process.exit = (code) => { throw new _DispatchExit(code); };
|
|
3581
|
+
try {
|
|
3582
|
+
switch (sub) {
|
|
3583
|
+
case 'chat': return await cmdChat({});
|
|
3584
|
+
case 'agent': return await cmdAgent(rest[0] || '-', {});
|
|
3585
|
+
case 'onboard': return await cmdOnboard({});
|
|
3586
|
+
case 'setup': return await cmdSetup(undefined, rest, {});
|
|
3587
|
+
case 'workspace': return await cmdWorkspace(rest[0], rest.slice(1), {});
|
|
3588
|
+
case 'browse': return await cmdBrowse(rest[0], {});
|
|
3589
|
+
case 'skills': return await cmdSkills(rest[0], rest.slice(1), {});
|
|
3590
|
+
case 'sessions': return await cmdSessions(rest[0], rest.slice(1), {});
|
|
3591
|
+
case 'providers': return await cmdProviders(rest[0], rest.slice(1), {});
|
|
3592
|
+
case 'cron': return await cmdCron(rest[0], rest.slice(1), {});
|
|
3593
|
+
case 'auth': return await cmdAuth(rest[0], rest.slice(1), {});
|
|
3594
|
+
case 'pairing': return await cmdPairing(rest[0], rest.slice(1), {});
|
|
3595
|
+
case 'nodes': return await cmdNodes(rest[0], rest.slice(1), {});
|
|
3596
|
+
case 'message': return await cmdMessage(rest[0], rest.slice(1), {});
|
|
3597
|
+
case 'doctor': return await cmdDoctor();
|
|
3598
|
+
case 'status': return await cmdStatus();
|
|
3599
|
+
case 'help': return cmdHelp();
|
|
3600
|
+
case 'dashboard': return await cmdDashboard({});
|
|
3601
|
+
default: throw new Error(`unknown menu choice: ${sub}`);
|
|
3602
|
+
}
|
|
3603
|
+
} catch (e) {
|
|
3604
|
+
if (e instanceof _DispatchExit) {
|
|
3605
|
+
// Subcommand wanted to exit. Surface a non-zero code so the
|
|
3606
|
+
// user knows something flagged, but DON'T propagate — we want
|
|
3607
|
+
// the launcher loop to continue.
|
|
3608
|
+
if (e.exitCode !== 0) {
|
|
3609
|
+
process.stderr.write(` \x1b[2m(subcommand returned exit code ${e.exitCode})\x1b[0m\n`);
|
|
3610
|
+
}
|
|
3611
|
+
return;
|
|
3612
|
+
}
|
|
3613
|
+
throw e;
|
|
3614
|
+
} finally {
|
|
3615
|
+
process.exit = realExit;
|
|
3574
3616
|
}
|
|
3575
3617
|
}
|
|
3576
3618
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lazyclaw",
|
|
3
|
-
"version": "3.99.
|
|
3
|
+
"version": "3.99.9",
|
|
4
4
|
"description": "Lazy, elegant terminal CLI for chatting with Claude / OpenAI / Gemini / Ollama and orchestrating multi-step LLM workflows. Banner-on-launch, slash-command ghost autocomplete, persistent sessions, local HTTP gateway.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|