@tiens.nguyen/gu-cli 1.0.754 → 1.0.756
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 +8 -4
- package/gonext_agent_chat.py +0 -2
- package/gu-repl.mjs +7 -3
- package/image-paste.mjs +9 -0
- package/package.json +1 -1
package/cli-token.mjs
CHANGED
|
@@ -289,15 +289,18 @@ export function barNotice({ token, publicKeyB64, mode, now = new Date(), attempt
|
|
|
289
289
|
if (check.ok) {
|
|
290
290
|
const p = check.payload;
|
|
291
291
|
const ended = p.paidUntil && Date.parse(p.paidUntil) <= now.getTime();
|
|
292
|
-
|
|
292
|
+
// SHORT AND CALM (#292: "make it simpler … seems so serious"): the fact, then the one thing to
|
|
293
|
+
// do. `urgent` is what the bar colours by — only these two need the user to act.
|
|
294
|
+
if (ended) return { kind: "plan-ended", urgent: true, text: `Pro ended ${shortDate(p.paidUntil)} · renew at ${pricingUrl}` };
|
|
293
295
|
if (Number.isInteger(p.activeDevices) && p.activeDevices > p.deviceLimit) {
|
|
294
296
|
return {
|
|
295
297
|
kind: "over-limit",
|
|
298
|
+
urgent: true,
|
|
296
299
|
// PLAIN WORDS (asked: "make it simple to understand"). It read "gu is active on 4 devices —
|
|
297
300
|
// Free covers 1", which leaves the reader to work out that "active" means "used gu in the
|
|
298
301
|
// last 30 days" and "covers" means "the plan allows". Kept short: the bar drops it entirely
|
|
299
302
|
// when it does not fit the terminal's width.
|
|
300
|
-
text: `${planName(p.plan)}
|
|
303
|
+
text: `${planName(p.plan)}: ${computers(p.deviceLimit)} · used on ${p.activeDevices} this month`,
|
|
301
304
|
};
|
|
302
305
|
}
|
|
303
306
|
const age = now.getTime() - Date.parse(p.issuedAt);
|
|
@@ -306,9 +309,10 @@ export function barNotice({ token, publicKeyB64, mode, now = new Date(), attempt
|
|
|
306
309
|
return null; // Client mode fetches one by itself; do not complain before it has tried.
|
|
307
310
|
}
|
|
308
311
|
|
|
312
|
+
// ROUTINE, so not an alarm (#292): a token getting old only means updates will stop one day.
|
|
309
313
|
return mode === "expert"
|
|
310
|
-
? { kind: "stale", text: `
|
|
311
|
-
: { kind: "stale", text: "
|
|
314
|
+
? { kind: "stale", urgent: false, text: `gu token is old · get a new one at ${accountUrl}` }
|
|
315
|
+
: { kind: "stale", urgent: false, text: "gu token is old · run gu login" };
|
|
312
316
|
}
|
|
313
317
|
|
|
314
318
|
/** "Free plan" / "Pro plan" — the name a person uses. */
|
package/gonext_agent_chat.py
CHANGED
|
@@ -12950,8 +12950,6 @@ def run_agent_chat(cfg):
|
|
|
12950
12950
|
task_with_hint = _label_failed_images(task_with_hint, _img_failed)
|
|
12951
12951
|
_log(f"attached {len(_turn_images)} image(s) to the question"
|
|
12952
12952
|
+ (f", {len(_img_failed)} could not be opened" if _img_failed else ""))
|
|
12953
|
-
if _turn_images:
|
|
12954
|
-
_emit({"type": "step", "text": f"Sending {len(_turn_images)} image(s) with the question"})
|
|
12955
12953
|
for _lbl, _why in _img_failed:
|
|
12956
12954
|
_emit({"type": "step", "text": f"⚠ {_lbl} not sent — {_why}"})
|
|
12957
12955
|
else:
|
package/gu-repl.mjs
CHANGED
|
@@ -128,7 +128,7 @@ import { unapprovedProjectServers } from "./mcp-command.mjs";
|
|
|
128
128
|
import { readHooks } from "./hooks-config.mjs";
|
|
129
129
|
import { codingBannerLabel, isOllamaCloudUrl, SECRET_KEY_HINT } from "./coding-key-prompt.mjs";
|
|
130
130
|
import { codingChoiceTags, coderDisplayName, coderWhere, whereOfActiveCoder } from "./coding-choice-tags.mjs";
|
|
131
|
-
import { IMAGE_NEEDS_CLAUDE, clipboardImageToFile, fitImageNotice, createImageStore, imagePasteKey, imagePathFromPaste, isClaudeCoderUrl, isImagePasteKey, storeImageFile } from "./image-paste.mjs";
|
|
131
|
+
import { IMAGE_NEEDS_CLAUDE, clipboardImageToFile, fitImageNotice, imageMarkersForDisplay, createImageStore, imagePasteKey, imagePathFromPaste, isClaudeCoderUrl, isImagePasteKey, storeImageFile } from "./image-paste.mjs";
|
|
132
132
|
import {
|
|
133
133
|
isDoubleClick,
|
|
134
134
|
clickRun,
|
|
@@ -2474,7 +2474,10 @@ function frozenZone() {
|
|
|
2474
2474
|
// it whole → the condition above lets the agents count (or nothing) have the row instead.
|
|
2475
2475
|
const len = visibleLen(tokenNotice.text);
|
|
2476
2476
|
const from = width - 1 - len;
|
|
2477
|
-
|
|
2477
|
+
// Yellow only when the user must act (plan ended, over the computer limit); an old token is
|
|
2478
|
+
// routine and reads in the rule's own dim grey (#292 — the yellow line "seems so serious").
|
|
2479
|
+
const paint = tokenNotice.urgent ? yellow : dim;
|
|
2480
|
+
rows[sep] = clipVisible(dim("\u2500".repeat(Math.max(0, from - 1)) + " ") + paint(tokenNotice.text), width - 1);
|
|
2478
2481
|
} else if (agentsIndicator(otherAgents)) {
|
|
2479
2482
|
// …and when there is no update to offer, the same row carries the agents count (task #195).
|
|
2480
2483
|
// THREE THINGS CANNOT SHARE ONE ROW, so they are ranked by how time-critical they are:
|
|
@@ -11423,7 +11426,8 @@ async function main() {
|
|
|
11423
11426
|
// against the ">>" row. Unlike the live block's separator, this one belongs to the
|
|
11424
11427
|
// TRANSCRIPT: the echo is written exactly once per submitted line and never repainted,
|
|
11425
11428
|
// so there is nothing here for a blank to accumulate against.
|
|
11426
|
-
|
|
11429
|
+
// As typed, not as sent: "[Image #1]", never the file path the agent needs (#51).
|
|
11430
|
+
process.stdout.write(PROMPT_PAST + imageMarkersForDisplay(line) + "\n\n");
|
|
11427
11431
|
}
|
|
11428
11432
|
// ESC AT ANY QUESTION LANDS HERE (see PromptCancelled). Every command below is wrapped as
|
|
11429
11433
|
// one block rather than each flow catching for itself, because the request was to be able to
|
package/image-paste.mjs
CHANGED
|
@@ -214,6 +214,15 @@ export function clipboardImageToFile({ home = homedir(), platform = process.plat
|
|
|
214
214
|
return { path: dest };
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
/**
|
|
218
|
+
* A sent line as the USER should see it again: "[Image #1: /Users/…/x.png]" → "[Image #1]".
|
|
219
|
+
* The file path is for the agent, which reads the image from it; on screen it is noise (the echo
|
|
220
|
+
* of the question showed it). Claude Code shows the placeholder the same way.
|
|
221
|
+
*/
|
|
222
|
+
export function imageMarkersForDisplay(text) {
|
|
223
|
+
return String(text ?? "").replace(/\[Image #(\d+): [^\]\n]+\]/g, "[Image #$1]");
|
|
224
|
+
}
|
|
225
|
+
|
|
217
226
|
/** Placeholders shown in the input, and the files behind them. */
|
|
218
227
|
export function createImageStore() {
|
|
219
228
|
const store = new Map(); // token -> absolute path
|
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.756",
|
|
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",
|