@tiens.nguyen/gu-cli 1.0.880 → 1.0.881

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
@@ -293,7 +293,11 @@ export async function promptForToken({
293
293
  // #315: a saved token must also be ENTITLED on this computer. `accept(token)` → { ok } | { ok:false, reason }
294
294
  // — the REPL renews it from this computer (to learn its free time) and runs the licence rule.
295
295
  accept = null,
296
+ // #250: "/support" (typed, or the footer's "? support" link) sends a help request from here —
297
+ // a first install with no token had no other way to reach support. Runs, then asks again.
298
+ onSupport = null,
296
299
  }) {
300
+ const quitLine = (lead) => lead + (onSupport ? "/support asks for help · " : "") + "/exit or Ctrl+C quits gu.";
297
301
  const accountUrl = `${String(site).replace(/^https?:\/\//, "")}/account`;
298
302
  const dev = device === undefined ? await trialDevice().catch(() => null) : device;
299
303
  const getOne = `For a free token for 1 computer, log in at ${accountUrl} and create one — or buy Pro there for more computers.`;
@@ -319,7 +323,7 @@ export async function promptForToken({
319
323
  ? [`The gu service${trialHost(hostedBase)} sent an answer without a token — Enter on an empty line tries again.`]
320
324
  : []),
321
325
  getOne,
322
- required ? "Paste it here, then Enter. /exit or Ctrl+C quits gu." : "Paste it here — or Enter to skip for now.",
326
+ required ? quitLine("Paste it here, then Enter. ") : "Paste it here — or Enter to skip for now.",
323
327
  ];
324
328
  if (why) {
325
329
  const pricingUrl = `${String(site).replace(/^https?:\/\//, "")}/pricing`;
@@ -328,7 +332,7 @@ export async function promptForToken({
328
332
  why,
329
333
  `Remove the computers you no longer use at ${accountUrl}, then start gu again — or Pro allows more computers: ${pricingUrl}`,
330
334
  `Think this is wrong? ${SUPPORT_EMAIL}`,
331
- required ? "/exit or Ctrl+C quits gu." : "Enter to skip for now.",
335
+ required ? quitLine("") : "Enter to skip for now.",
332
336
  ];
333
337
  }
334
338
  hint = overLimit
@@ -365,6 +369,12 @@ export async function promptForToken({
365
369
  // A way OUT of a required question (task #17): "/exit" is not a token, and treating it as one
366
370
  // ("That token was not saved…" and the same question again) left no way to leave gu at all.
367
371
  if (/^\/(exit|quit)$/i.test(typed)) return { ok: false, why: "quit" };
372
+ // #250: help, then the same question again — it does not use up a try.
373
+ if (onSupport && /^\/support$/i.test(typed)) {
374
+ await onSupport();
375
+ if (!required) round--;
376
+ continue;
377
+ }
368
378
  // An empty Enter with no default is also "try again": the service may be back, the trial may exist now (#222).
369
379
  if (!typed && required && !trialOk && !overLimit) await offer();
370
380
  // #219: the over-limit detail, on request only — "?" or an empty Enter, then the same question again.
package/gu-repl.mjs CHANGED
@@ -1642,7 +1642,13 @@ function applyClick({ row, col }) {
1642
1642
  // The footer's "? support" link (#220): the footer is the last rows of the screen, so count from the bottom.
1643
1643
  if (supportLinkTarget && !zonePanel && row === viewportRows() - supportLinkTarget.fromEnd + 1 &&
1644
1644
  col - 1 >= supportLinkTarget.from && col - 1 < supportLinkTarget.to) {
1645
- void runSupport();
1645
+ // #250: the token question is an open ask(), and runSupport stands aside for one — so the
1646
+ // click answers it with "/support" instead; promptForToken runs it and asks again.
1647
+ if (tokenQuestionOpen && askWaiting) {
1648
+ rl.line = "";
1649
+ rl.cursor = 0;
1650
+ submitSyntheticLine("/support");
1651
+ } else void runSupport();
1646
1652
  return;
1647
1653
  }
1648
1654
  if (agentsRowTarget && row === updateRowAbs &&
@@ -8981,11 +8987,12 @@ async function askKeyName(prompt = " key name: ") {
8981
8987
  * "no key" (a local vLLM answers anonymously). `host` names the server in the prompt and decides
8982
8988
  * the shape check's locality: a local server accepts any string, so "abc" is not questioned there.
8983
8989
  */
8984
- async function askServerKey({ host = "", nameHint = '"work", "personal"', optional = false } = {}) {
8990
+ async function askServerKey({ host = "", optional = false } = {}) {
8985
8991
  const ps = await import("./coding-provider-setup.mjs");
8986
8992
  // Esc is said here (#249): the prompt that follows is bare text, with nothing on it saying a
8987
- // way out exists — Esc cancels the whole add, nothing saved.
8988
- console.log("\n" + GUTTER + dim(`A name just tells keys apart — ${nameHint}. Esc to cancel.`));
8993
+ // way out exists — Esc cancels the whole add, nothing saved. (The line explaining what a key
8994
+ // name is for was removed on request.)
8995
+ console.log("\n" + GUTTER + dim("Esc to cancel."));
8989
8996
  const name = (await askKeyName()).trim();
8990
8997
  console.log(GUTTER + dim(SECRET_KEY_HINT));
8991
8998
  const secret = (await askSecret(` API key${host ? ` for ${host}` : ""}${name ? ` (${name})` : ""}: `)).trim();
@@ -12070,6 +12077,7 @@ async function askForCliTokenInner(ct, dir, why, overLimit = false, short = "")
12070
12077
  why,
12071
12078
  overLimit, // #209: the computer limit, not a missing plan — no "paste a Pro token"
12072
12079
  short, // #219: the one short yellow line; the rest is behind "?"
12080
+ onSupport: () => runSupport(), // #250: "/support" or the footer link, before there is a token
12073
12081
  // #315: a token is only good if THIS computer may use it — renew it from here (the server then
12074
12082
  // says how much free time the computer has), save what came back, and run the licence rule.
12075
12083
  accept: async (token) => {
@@ -14643,6 +14651,9 @@ async function main() {
14643
14651
  syncBarPinning();
14644
14652
 
14645
14653
  // #314: private mode with no token — the input row asks for one BEFORE the first ">> ".
14654
+ // #250: the mouse first — the main loop turns it on, but this question comes before the loop,
14655
+ // and without it the footer's "? support" link could not be clicked on a first install.
14656
+ enableClickToPosition();
14646
14657
  try {
14647
14658
  await askTokenAtStart();
14648
14659
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gu-cli",
3
- "version": "1.0.880",
3
+ "version": "1.0.881",
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",