lazyclaw 3.99.12 → 3.99.13

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.
Files changed (2) hide show
  1. package/cli.mjs +20 -2
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -2259,12 +2259,18 @@ async function cmdChat(flags = {}) {
2259
2259
  }
2260
2260
  };
2261
2261
 
2262
+ // Tracks whether the loop ended because the user explicitly typed
2263
+ // /exit (vs. natural EOF / Ctrl-D). When set, cmdChat returns the
2264
+ // 'LAZYCLAW_EXIT' sentinel so cmdLauncher knows to break its outer
2265
+ // menu loop instead of redrawing — /exit means "leave lazyclaw",
2266
+ // not "leave just this chat REPL and bounce back to the menu."
2267
+ let userRequestedExit = false;
2262
2268
  try { for await (const line of rl) {
2263
2269
  const text = line.trim();
2264
2270
  if (!text) { if (useTerminal) rl.prompt(); continue; }
2265
2271
  if (text.startsWith('/')) {
2266
2272
  const r = await handleSlash(text);
2267
- if (r === 'EXIT') break;
2273
+ if (r === 'EXIT') { userRequestedExit = true; break; }
2268
2274
  if (useTerminal) rl.prompt();
2269
2275
  continue;
2270
2276
  }
@@ -2359,6 +2365,11 @@ async function cmdChat(flags = {}) {
2359
2365
  try { process.stdin.pause(); } catch (_) {}
2360
2366
  try { process.stdin.unref(); } catch (_) {}
2361
2367
  }
2368
+ // Sentinel — picked up by cmdLauncher's dispatch loop. Returning
2369
+ // anything else (undefined / EOF) leaves the launcher free to
2370
+ // redraw its menu, which is the right behavior for natural stream
2371
+ // exhaustion (e.g. a script piping prompts on stdin).
2372
+ if (userRequestedExit) return 'LAZYCLAW_EXIT';
2362
2373
  }
2363
2374
 
2364
2375
  // Light wrapper around the daemon — meant for users who installed
@@ -4140,11 +4151,18 @@ async function cmdLauncher() {
4140
4151
  // Dispatch. Errors don't terminate the launcher — they're
4141
4152
  // surfaced as a stderr line and the menu redraws. Lets the
4142
4153
  // user recover from a transient API hiccup without a relaunch.
4154
+ let dispatchResult;
4143
4155
  try {
4144
- await _dispatchMenuChoice(argv);
4156
+ dispatchResult = await _dispatchMenuChoice(argv);
4145
4157
  } catch (e) {
4146
4158
  process.stderr.write(`\n ${accent('✗')} ${e?.message || String(e)}\n`);
4147
4159
  }
4160
+ // Subcommand asked for full lazyclaw exit (currently only chat's
4161
+ // /exit). Break the launcher loop so the finally block tears
4162
+ // down stdin and the process ends naturally — without this, the
4163
+ // user has to /exit out of chat AND pick Quit from the menu to
4164
+ // actually leave.
4165
+ if (dispatchResult === 'LAZYCLAW_EXIT') return;
4148
4166
 
4149
4167
  // Pause before re-drawing so the user can read the subcommand's
4150
4168
  // output. `chat` is the special case: its REPL has already kept
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lazyclaw",
3
- "version": "3.99.12",
3
+ "version": "3.99.13",
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",