@tiens.nguyen/gu-cli 1.0.799 → 1.0.800

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/cli-token.mjs CHANGED
@@ -299,7 +299,7 @@ export async function promptForToken({
299
299
  ? [`The gu service${trialHost(hostedBase)} sent an answer without a token — Enter on an empty line tries again.`]
300
300
  : []),
301
301
  getOne,
302
- required ? "Paste it here, then Enter." : "Paste it here — or Enter to skip for now.",
302
+ required ? "Paste it here, then Enter. /exit or Ctrl+C quits gu." : "Paste it here — or Enter to skip for now.",
303
303
  ];
304
304
  if (why) {
305
305
  const pricingUrl = `${String(site).replace(/^https?:\/\//, "")}/pricing`;
@@ -323,6 +323,9 @@ export async function promptForToken({
323
323
  const ask1 = () => ask("Input token: ", { prefill: shown, hint, atomic: true, noCancel: required });
324
324
  for (let round = 0; required ? round < maxRounds : round < 2; round++) {
325
325
  const typed = String((await ask1()) ?? "").trim();
326
+ // A way OUT of a required question (task #17): "/exit" is not a token, and treating it as one
327
+ // ("That token was not saved…" and the same question again) left no way to leave gu at all.
328
+ if (/^\/(exit|quit)$/i.test(typed)) return { ok: false, why: "quit" };
326
329
  if (!typed) {
327
330
  if (!required) return { ok: false, why: "skipped" };
328
331
  if (!trialOk) await offer(); // no default: maybe the service is back, or the trial exists now
package/gu-repl.mjs CHANGED
@@ -10839,6 +10839,29 @@ async function ensureTokenForTurn() {
10839
10839
  */
10840
10840
  async function askForCliToken(ct, dir, { why = "" } = {}) {
10841
10841
  console.log("");
10842
+ tokenPromptActive = true; // Ctrl+C now quits gu (see onInterrupt) — task #17
10843
+ try {
10844
+ return await askForCliTokenInner(ct, dir, why);
10845
+ } finally {
10846
+ tokenPromptActive = false;
10847
+ }
10848
+ }
10849
+
10850
+ /**
10851
+ * True while the required token question is on screen. The main loop — the only place "/exit" was
10852
+ * handled — has not started yet, so Ctrl+C and "/exit" must quit from here, or gu cannot be left.
10853
+ */
10854
+ let tokenPromptActive = false;
10855
+
10856
+ /** Leave gu from the token question, the same way "/exit" leaves the main loop. */
10857
+ function quitFromTokenPrompt() {
10858
+ tokenPromptActive = false;
10859
+ releaseScreenAtExit();
10860
+ rl.close();
10861
+ process.exit(0);
10862
+ }
10863
+
10864
+ async function askForCliTokenInner(ct, dir, why) {
10842
10865
  const hostedBase = await tokenHostedBase();
10843
10866
  const pk = ct.publicKey();
10844
10867
  const site = ct.siteUrl();
@@ -10866,6 +10889,7 @@ async function askForCliToken(ct, dir, { why = "" } = {}) {
10866
10889
  },
10867
10890
  });
10868
10891
  console.log("");
10892
+ if (r.why === "quit") quitFromTokenPrompt();
10869
10893
  if (r.ok) {
10870
10894
  licenceBlock = null; // the row only lets an entitled token through
10871
10895
  licenceDecided = true;
@@ -13271,6 +13295,14 @@ async function main() {
13271
13295
  // Ctrl+C while the approval picker is up = decline it (and fall through to also
13272
13296
  // cancel the turn) — otherwise the poll loop stays blocked awaiting a choice.
13273
13297
  if (approvalActive) finishApproval(false);
13298
+ // Ctrl+C at the required token question (task #17): there is nothing to cancel and no ">>" to
13299
+ // go back to, and re-asking ("(/exit to quit)") trapped the user — so it quits gu.
13300
+ if (tokenPromptActive && !following) {
13301
+ eraseFooter();
13302
+ process.stdout.write("\n" + GUTTER + red("^C ") + "\n");
13303
+ quitFromTokenPrompt();
13304
+ return;
13305
+ }
13274
13306
  if (following) {
13275
13307
  // Cancel AND clear. One press does both: the turn stops, and nothing the user typed
13276
13308
  // while waiting survives to appear in the box or fire as the next turn.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gu-cli",
3
- "version": "1.0.799",
3
+ "version": "1.0.800",
4
4
  "description": "Gu CLI — the gu terminal plus the local worker that runs agent / OCR / PDF / embedding jobs on your Mac (Ollama / MLX / OpenAI-compatible).",
5
5
  "type": "module",
6
6
  "license": "MIT",