@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 +12 -2
- package/gu-repl.mjs +15 -4
- package/package.json +1 -1
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.
|
|
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 ? "
|
|
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
|
-
|
|
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 = "",
|
|
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
|
-
|
|
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.
|
|
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",
|