@tiens.nguyen/gu-cli 1.0.880 → 1.0.882

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tien Nguyen Song
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,157 +1,210 @@
1
- # @tiens.nguyen/gu-cli
2
-
3
- **gu** is a terminal coding agent for the folder you are in, plus the local worker that runs
4
- agent / OCR / PDF / embedding jobs on your machine (Ollama, MLX or any OpenAI-compatible server).
1
+ <h1 align="center">gu — the coding agent in your terminal</h1>
2
+
3
+ <p align="center">
4
+ <strong>It reads your repo, makes the change, and proves it works.</strong><br>
5
+ Your models — Ollama, MLX or any OpenAI-compatible provider. Your files stay in your folder.
6
+ </p>
7
+
8
+ <p align="center">
9
+ <a href="https://www.npmjs.com/package/@tiens.nguyen/gu-cli"><img alt="npm" src="https://img.shields.io/npm/v/@tiens.nguyen/gu-cli?color=6366f1&label=npm"></a>
10
+ <a href="https://www.npmjs.com/package/@tiens.nguyen/gu-cli"><img alt="downloads" src="https://img.shields.io/npm/dm/@tiens.nguyen/gu-cli?color=6366f1"></a>
11
+ <img alt="node" src="https://img.shields.io/node/v/@tiens.nguyen/gu-cli?color=6366f1">
12
+ <img alt="platforms" src="https://img.shields.io/badge/macOS%20%C2%B7%20Linux%20%C2%B7%20Windows-supported-6366f1">
13
+ <a href="./LICENSE"><img alt="license" src="https://img.shields.io/npm/l/@tiens.nguyen/gu-cli?color=6366f1"></a>
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="https://gucli.com">Website</a> ·
18
+ <a href="https://gucli.com/docs">Docs</a> ·
19
+ <a href="https://gucli.com/pricing">Pricing</a> ·
20
+ <a href="https://gucli.com/support">Support</a>
21
+ </p>
22
+
23
+ <p align="center">
24
+ <a href="https://gucli.com/videos/gu-design-web.mp4">
25
+ <img alt="gu building a web page from one request (click to watch)" src="https://gucli.com/videos/gu-design-web.jpg" width="760">
26
+ </a>
27
+ <br><sub>One request: gu plans, writes the files and checks the result. Click to watch.</sub>
28
+ </p>
29
+
30
+ ## Install
5
31
 
6
32
  ```sh
7
33
  npm install -g @tiens.nguyen/gu-cli
8
- gu # open the REPL in the current folder
34
+ cd your-project
35
+ gu
9
36
  ```
10
37
 
11
- The package installs three commands: `gu` (the terminal REPL), `gu-cli` and `gu-local-worker`
12
- (the same worker CLI). Requires Node.js 18 or newer. The install tries to put npm's global bin
13
- folder on your PATH, but npm 11 skips install scripts it was not told to allow (it prints
14
- "install scripts not yet covered by allowScripts"). If `gu` is "command not found" afterwards, run
15
- `npx @tiens.nguyen/gu-cli fix-path` (works even when `gu-cli` itself is not found). `gu-cli fix-path`
16
- also finds what an old install left behind - broken `gu` links, a second gu from another npm, a
17
- shell-profile PATH line pinned to a versioned Homebrew folder - and asks before fixing each
18
- (`--check` only reports). `gu support` sends the support team a request with gu's logs attached.
19
- On Windows, PowerShell's built-in `gu` alias (Get-Unique) shadows this CLI — run
20
- `gu-cli fix-powershell` to drop it.
38
+ The first run asks a few questions: how this machine runs, which model provider to use, and your
39
+ gu token (a free trial is offered). After that, type what you want done.
40
+
41
+ > **`gu: command not found`?** Run `npx @tiens.nguyen/gu-cli fix-path`. See [Troubleshooting](#troubleshooting).
42
+
43
+ ## What it does
44
+
45
+ - **Writes the code, in your terminal.** Ask in plain words; gu reads the repo, edits the files,
46
+ runs the build and the tests, and tells you what it changed.
47
+ - **Your models.** Run [Ollama](https://ollama.com) or MLX on your own machine, or bring any
48
+ OpenAI-compatible provider. Switch at any time with `/model`.
49
+ - **It stays in the repo.** Every edit is a file you can read, diff and revert, and `/undo` puts
50
+ back what a stopped turn changed. No hidden workspace.
51
+ - **Knows your codebase.** Local RAG indexes the folder so the model finds the right files.
52
+ - **Extensible.** [MCP](https://modelcontextprotocol.io) servers, skills (`SKILL.md`), and hooks.
53
+ Already set up for Claude Code? `/switch-skill claude` reuses its `.claude` folder.
54
+ - **Tests in a real browser.** The `browser` tool drives Chrome to check the web pages it builds.
55
+ - **Private by default.** Logs hold no prompts, code or keys unless you run `gu --log`.
21
56
 
22
57
  ## Quick start
23
58
 
24
- 1. `gu login` — browser sign-in; writes `~/.gonext/worker.env`.
25
- (Client Expert machines can instead paste a token from the Account page with `gu-cli token <token>`.)
26
- 2. `gu doctor` — set up and check the models on this machine
27
- (`gu doctor --client` installs only the agent dependencies when the models live on another machine).
28
- 3. `gu` in a project folder, then type a request. Conversation history is saved per folder in
29
- `~/.gonext/sessions` and resumed next time; `/new` starts a fresh one and archives the old one.
59
+ 1. **Sign in.** `gu login` opens the browser. On a private machine, paste a token from your
60
+ [account page](https://gucli.com/account) with `gu-cli token <token>` instead.
61
+ 2. **Check your models.** `gu doctor` sets up and tests the models on this machine.
62
+ (`gu doctor --client` installs only the agent's dependencies, when the models run elsewhere.)
63
+ 3. **Ask.** Run `gu` in a project folder. Conversations are saved per folder and resumed next
64
+ time; `/new` starts a fresh one.
30
65
 
31
- A first install asks how this machine runs (hosted client / MLX host / private). Pass
32
- `--license <pro token>` to choose a pro license up front; without it a first install is private,
33
- meaning the whole stack runs on this machine.
66
+ ## Models
34
67
 
35
- ## The `gu` REPL
68
+ gu uses up to three models, each with its own command:
36
69
 
37
- ```
38
- gu [-v|--verbose] [--log] [--name <text>] [--license <pro token>]
39
- ```
70
+ | Command | Model | Saved |
71
+ | --- | --- | --- |
72
+ | `/model` | **coding**: writes the code | this session (`/quick-models` keeps 2 to flip with ← / →) |
73
+ | `/agent-model` | **agent**: talks to you and plans | this machine |
74
+ | `/embed-model` | **embedding**: RAG (`nomic-embed-text`, `qwen3-embedding`), local or remote | this machine; re-indexes what was indexed |
40
75
 
41
- - `-v, --verbose` shows RAG index-file activity in the bottom bar.
42
- - `--name <text>` draws `<text>` instead of the gu logo in the startup banner (this run only). Letters, digits, space, `-` and `_` become block art; anything else, or a name over 12 characters, is shown as plain text.
43
- - `--log` logs this run in detail to `~/.gonext/worker.log`. Without it only starts, stops and errors are logged.
44
- - Ctrl-C stops following a turn.
76
+ Run `/doctor` any time to check that each one answers.
45
77
 
46
- ### Three models, three commands
78
+ ## Using gu
47
79
 
48
- | Command | Model it switches |
80
+ ```
81
+ gu [-v|--verbose] [--log] [--color] [--name <text>] [--license <pro token>]
82
+ ```
83
+
84
+ | Flag | Effect |
49
85
  | --- | --- |
50
- | `/model` | the CODING model (the one that writes code), for this session |
51
- | `/agent-model` | the AGENT model (the one that talks) — saved on this machine |
52
- | `/embed-model` | the RAG EMBEDDING model (nomic-embed-text / qwen3-embedding) and its server; re-indexes what is already indexed; supports a remote URL + API key |
86
+ | `-v`, `--verbose` | show RAG index activity in the bottom bar |
87
+ | `--log` | log this run in detail to `~/.gonext/worker.log` (default: starts, stops and errors only) |
88
+ | `--color` | colour the live thought and the thinking spinner |
89
+ | `--name <text>` | show `<text>` instead of the gu logo in the banner (this run only) |
90
+ | `--license <token>` | choose a Pro licence on first install |
53
91
 
54
- `/agent-model` saves the model's server URL (`agentModelUrl`) together with its name, so picking a
55
- model from another provider (for example OpenAI) can no longer leave chat pointed at the old
56
- server. After picking, `gu doctor` shows the URL and model that are actually in use.
92
+ Ctrl-C stops the running turn. Type `/` at the prompt to see every command; Tab completes.
57
93
 
58
- ### Slash commands
94
+ <details>
95
+ <summary><strong>All slash commands</strong></summary>
59
96
 
60
97
  | Command | What it does |
61
98
  | --- | --- |
62
- | `/model`, `/agent-model`, `/embed-model` | switch models (see above) |
63
- | `/context-window [tokens\|auto]` | tell gu how big the coding model's context is (hosted models cannot be probed) |
64
- | `/doctor` | check every configured model answers, especially the embedder |
65
- | `/browser [allow\|forget\|install\|cleanup]` | the agent's web browser (UI tests): it asks before first use, then works in your Chrome through the gu extension or, with nothing installed, in gu's own Chrome window; `allow`/`forget` stop or restart the question for this folder; guide: [browser-extension/README.md](browser-extension/README.md) |
66
- | `/tokens` | break down the last prompt sent to the coding model — how much of it was RAG |
67
- | `/prices [update]` | price and cache tables, and what the last turn and this session cost |
68
- | `/rag` | where this folder's RAG knowledge base lives: local, cloud, or both |
69
- | `/s3 [test]` | set up your own S3 bucket (RAG index, generated PDFs/downloads) and check the AWS keys |
70
- | `/proxy [show\|set\|on\|off\|clear\|test]` | route model calls through an HTTP proxy (local calls always go direct) |
71
- | `/test-auto` | toggle auto-test (verify and fix until it passes) for this folder |
99
+ | `/model`, `/quick-models`, `/agent-model`, `/embed-model` | switch models (see [Models](#models)) |
100
+ | `/context-window [tokens\|auto]` | tell gu how big the coding model's context is (hosted models can't be probed) |
101
+ | `/doctor` | check that every configured model answers, especially the embedder |
102
+ | `/new` | start a new conversation in this folder (the old one is archived) |
72
103
  | `/undo [runId]` | put back the files the last stopped turn changed, from its backups (asks first) |
104
+ | `/test-auto` | toggle auto-test for this folder: verify and fix until it passes |
105
+ | `/browser [allow\|forget\|install\|cleanup]` | the agent's web browser, through the gu Chrome extension or gu's own Chrome window ([guide](browser-extension/README.md)) |
106
+ | `/shells` | long commands the agent left running in the background: status, output, stop one |
107
+ | `/rag` | where this folder's RAG index lives: local, cloud or both |
108
+ | `/tokens` | break down the last prompt sent to the coding model, including how much was RAG |
109
+ | `/prices [update]` | price tables, and what the last turn and this session cost |
110
+ | `/budget` | your API provider budgets and balances (Pro) |
111
+ | `/mcp [list\|tools\|add\|remove\|enable\|disable\|approve\|allow\|disallow\|reconnect]` | MCP servers, and which of their tools run without asking |
112
+ | `/hooks [list\|approve\|unapprove]` | commands gu runs on `onStart`, `onAsk`, `onToolDone`, `onTurnEnd` |
113
+ | `/switch-skill [claude\|gu]` | use Claude Code's (`.claude`) or gu's (`.gonext`) skills, MCP servers and hooks in this folder |
114
+ | `/skills-copy-to-claude [--dry-run] [name…]` | copy gu's skills into Claude Code's folders |
115
+ | `/proxy [show\|set\|on\|off\|clear\|test]` | route model calls through an HTTP proxy (local calls go direct) |
116
+ | `/s3 [test]` | use your own S3 bucket for the RAG index and generated files |
73
117
  | `/server` | pick a deployment server (host/user) for this session |
74
- | `/host-mode` | undo client mode — run agent turns on this machine again |
75
- | `/save-settings [name\|path]`, `/load-settings [name\|path]` | move providers, models and key names (no secrets) to another machine |
76
- | `/save-preset [name]`, `/open-presets [name]`, `/use-presets [name]` | presets: your whole setup, keys included, to copy to another computer, edit, and apply (backs up first) |
77
- | `/hooks [list\|approve\|unapprove]` | commands gu runs on onStart, onAsk, onToolDone, onTurnEnd |
78
- | `/mcp [list\|tools\|add\|remove\|enable\|disable\|approve\|allow\|disallow\|reconnect]` | manage MCP servers and which of their tools run without asking |
79
- | `/switch-skill [claude\|gu]` | use Claude Code's (`.claude`) or gu's own (`.gonext`) skills, MCP servers and hooks for this folder |
118
+ | `/host-mode` | undo client mode: run agent turns on this machine again |
119
+ | `/save-settings`, `/load-settings` | move providers, models and key *names* (no secrets) to another machine |
120
+ | `/save-preset`, `/open-presets`, `/use-presets` | your whole setup, keys included, to copy, edit and apply (backs up first) |
80
121
  | `/clear-logs` | show what logs, RAG indexes and old API versions take on disk, then ask what to clear |
81
- | `/new` | start a new conversation in this folder (the old one is archived) |
82
- | `/help`, `/exit` (`/quit`) | list commands / quit |
122
+ | `/support` | send the support team a request with gu's logs attached (secrets masked; shows what goes first) |
123
+ | `/help`, `/exit` | list commands / quit |
124
+
125
+ Each skill in `~/.gonext/skills/<name>/SKILL.md` (or the folder's `.gonext/skills`) is a slash command too.
83
126
 
84
- Each skill in `~/.gonext/skills/<name>/SKILL.md` (and the folder's `.gonext/skills`) is also a
85
- slash command of its own. Run `/help` in the REPL for the list your version offers.
127
+ </details>
86
128
 
87
- ## Shell commands
129
+ <details>
130
+ <summary><strong>Shell commands</strong></summary>
88
131
 
89
132
  ```
90
- gu status worker + a table of the running model servers
91
- gu start | stop | restart run the polling daemon in the background (stop --models: model servers too)
92
- gu logs [--lines N] [-f] tail the daemon log; gu logs <port|pid|chat|embed> [-f] tails a model server's log
93
- gu doctor [--client] set up models here
94
- gu rag test the embedder end-to-end and list knowledge bases
95
- gu rag plan [path] is RAG worth it here? files / chars / chunks -> estimated index time
96
- gu rag --test can this machine embed and retrieve?
97
- gu api <start|stop|restart|status|upgrade> the local API (Local / Client Expert only)
133
+ gu status worker status and the running model servers
134
+ gu start | stop | restart the background worker (stop --models: model servers too)
135
+ gu logs [--lines N] [-f] tail the worker log; gu logs <port|pid|chat|embed> for a model server
136
+ gu doctor [--client] set up and check models on this machine
137
+ gu rag [plan [path] | --test] test the embedder, list knowledge bases, estimate index time
138
+ gu api <start|stop|restart|status|upgrade> the local API (private machines)
98
139
  gu workspace revert [runId] undo an agent run's file edits from its backups
99
- gu test-proxy can this machine route model calls through a proxy?
100
- gu mongo migrate-from-docker macOS: move a Docker MongoDB to native (Homebrew)
140
+ gu support send a support request with masked logs
141
+ gu test-proxy check model calls through a proxy
142
+ gu mongo migrate-from-docker macOS: move a Docker MongoDB to Homebrew
101
143
  gu clear [--scratch|--keep-history] [--yes] back to a fresh machine (asks first)
102
- gu fix-path | fix-powershell repair PATH / drop PowerShell's `gu` alias
144
+ gu fix-path | fix-powershell repair PATH / remove PowerShell's `gu` alias
103
145
  ```
104
146
 
105
- `gu-cli` accepts the same commands, plus `login [--api-base <url>]`, `set <workerKey> [--api-base <url>]`,
106
- `token [<token>]`, `ws-ping-test` and `simulate-chat [text...]`.
107
- `gu api restart` runs the installed version; an upgrade changes the files, not a process that is already serving.
147
+ `gu-cli` takes the same commands, plus `login [--api-base <url>]`, `set <workerKey>`,
148
+ `token [<token>]`, `ws-ping-test` and `simulate-chat [text…]`.
149
+
150
+ </details>
108
151
 
109
- ## Files and settings
152
+ ## Where gu keeps things
110
153
 
111
154
  | Path | Contents |
112
155
  | --- | --- |
113
- | `~/.gonext/worker.env` | sign-in: worker key and API base |
114
- | `~/.gonext/sessions/` | per-folder conversation history (`archive/` holds old conversations) |
115
- | `~/.gonext/worker.log` | worker log (detailed with `--log`) |
116
- | `~/.gonext/local-api.log` | the local API's log |
156
+ | `~/.gonext/worker.env` | sign-in: worker key and API address |
157
+ | `~/.gonext/sessions/` | conversation history per folder (`archive/` holds old ones) |
158
+ | `~/.gonext/worker.log`, `~/.gonext/local-api.log` | logs |
117
159
  | `~/.gonext/mcp.json` | MCP servers and their allow rules |
118
- | `~/.gonext/skills/`, `.gonext/skills` | skills (global / this folder) |
160
+ | `~/.gonext/skills/`, `<folder>/.gonext/skills/` | skills: everywhere / this folder only |
161
+
162
+ ## Plans
163
+
164
+ Every new computer gets a **free trial**. After it, the **Free** plan covers 1 device and **Pro**
165
+ covers more, plus provider budgets. Current prices: [gucli.com/pricing](https://gucli.com/pricing).
119
166
 
120
- ## Worker modes
167
+ ## Troubleshooting
121
168
 
122
- The background worker polls the API for jobs queued from the web app and runs them on this machine.
169
+ **`gu: command not found` after install.** npm 11 skips install scripts it wasn't told to allow,
170
+ so the step that adds npm's bin folder to your PATH may not have run. Run
171
+ `npx @tiens.nguyen/gu-cli fix-path`. It also finds what an old install left behind (broken links,
172
+ a second gu from another npm, a PATH line pinned to an old Homebrew folder) and asks before
173
+ fixing each one. `--check` only reports.
123
174
 
124
- ### Agent chat
175
+ **Windows: `gu` runs `Get-Unique`.** PowerShell has a built-in `gu` alias. Run `gu-cli fix-powershell`.
125
176
 
126
- Choosing **Agent** under the composer in the web app hands your prompt to a
127
- [smolagents](https://github.com/huggingface/smolagents) agent running on your local model. It
128
- needs `pip install smolagents certifi` in the worker's Python environment (`certifi` gives
129
- HTTPS a trusted CA bundle on macOS). Agent mode is blocked for cloud models; pick a local
130
- MLX or Ollama model first. The script is `gonext_agent_chat.py`.
177
+ **Node version.** Node.js 18+ runs the CLI. A private machine (API and database on this
178
+ computer) needs **Node.js 20.19+**.
131
179
 
132
- ### API check / HTTP probe
180
+ **A change in a model or setting seems ignored.** `gu doctor` shows the model and URL actually in use.
133
181
 
134
- - **Tools (`tool_only`)**: the worker runs the HTTP request itself, measures status, latency, headers and
135
- body, classifies it (2xx/3xx/4xx/5xx/timeout/network_error), and the local model writes a one-line summary.
136
- - **Agents (`agentic`)**: a smolagents agent writes the summary; the measurement stays the source of truth.
182
+ **Still stuck?** Run `gu support` (or `/support` in gu, or click **? support** in the footer). It
183
+ sends the team your request with gu's logs attached, secrets masked, and shows you what goes
184
+ before sending.
137
185
 
138
- ### Environment variables
186
+ <details>
187
+ <summary><strong>Advanced: worker jobs and environment variables</strong></summary>
188
+
189
+ The background worker also runs jobs queued from the [web app](https://gucli.com) on this machine:
190
+
191
+ - **Agent chat**: choosing **Agent** in the web app runs a
192
+ [smolagents](https://github.com/huggingface/smolagents) agent on your local model
193
+ (`pip install smolagents certifi`). Cloud models are not allowed here; pick a local MLX or Ollama model.
194
+ - **API checks**: the worker makes the HTTP request itself, measures status, latency and body,
195
+ and a local model writes a one-line summary.
139
196
 
140
197
  | Variable | Meaning |
141
198
  | --- | --- |
142
- | `GONEXT_API_BASE`, `GONEXT_WORKER_KEY` | API URL and worker key (normally from `~/.gonext/worker.env`) |
143
- | `GONEXT_PROBE_PYTHON` | Python for smolagents scripts (default: `GONEXT_MLX_LM_PYTHON` or `python3`) |
144
- | `GONEXT_MLX_LM_PYTHON` | Python for the MLX LM native probe (default `python3`) |
145
- | `GONEXT_OCR_MODEL_PATH` | local GLM-OCR-bf16 directory (default `~/mlx-models/GLM-OCR-bf16`) |
146
- | `GONEXT_OCR_DEBUG=1` | print raw OCR stdout/stderr snippets |
147
- | `GONEXT_SIMULATE_TEXT` | default reply body for `simulate-chat` |
199
+ | `GONEXT_API_BASE`, `GONEXT_WORKER_KEY` | API address and worker key (normally from `~/.gonext/worker.env`) |
200
+ | `GONEXT_PROBE_PYTHON` | Python for agent scripts (default: `GONEXT_MLX_LM_PYTHON` or `python3`) |
201
+ | `GONEXT_MLX_LM_PYTHON` | Python for the MLX probe (default `python3`) |
202
+ | `GONEXT_OCR_MODEL_PATH` | local GLM-OCR directory (default `~/mlx-models/GLM-OCR-bf16`) |
203
+ | `GONEXT_OCR_DEBUG=1` | print raw OCR output |
204
+ | `GONEXT_SIMULATE_TEXT` | default reply for `simulate-chat` |
148
205
 
149
- ## Development
206
+ </details>
150
207
 
151
- ```sh
152
- npm test # python unittest + node --test
153
- npm run preflight # checks before a release
154
- npm run publish:org # npm publish --access public
155
- ```
208
+ ## License
156
209
 
157
- Source and issues: https://github.com/tiennsloit/gu
210
+ [MIT](./LICENSE) © Tien Nguyen Song
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,17 +1,28 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gu-cli",
3
- "version": "1.0.880",
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
- "type": "module",
6
- "license": "MIT",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/tiennsloit/gu.git"
10
- },
11
- "homepage": "https://github.com/tiennsloit/gu#readme",
3
+ "version": "1.0.882",
4
+ "description": "gu: the coding agent in your terminal. It reads your repo, makes the change and runs the tests, with your own models (Ollama, MLX or any OpenAI-compatible provider). macOS, Linux and Windows.",
5
+ "keywords": [
6
+ "ai",
7
+ "coding-agent",
8
+ "cli",
9
+ "terminal",
10
+ "llm",
11
+ "ollama",
12
+ "mlx",
13
+ "openai",
14
+ "agent",
15
+ "mcp",
16
+ "rag",
17
+ "code-assistant"
18
+ ],
19
+ "homepage": "https://gucli.com",
12
20
  "bugs": {
13
- "url": "https://github.com/tiennsloit/gu/issues"
21
+ "url": "https://gucli.com/support"
14
22
  },
23
+ "license": "MIT",
24
+ "author": "Tien Nguyen Song",
25
+ "type": "module",
15
26
  "bin": {
16
27
  "gu-cli": "gu-cli.mjs",
17
28
  "gu-local-worker": "gu-cli.mjs",