@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 +21 -0
- package/README.md +161 -108
- package/cli-token.mjs +12 -2
- package/gu-repl.mjs +15 -4
- package/package.json +21 -10
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
34
|
+
cd your-project
|
|
35
|
+
gu
|
|
9
36
|
```
|
|
10
37
|
|
|
11
|
-
The
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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`
|
|
25
|
-
|
|
26
|
-
2. `gu doctor`
|
|
27
|
-
(`gu doctor --client` installs only the agent dependencies when the models
|
|
28
|
-
3. `gu` in a project folder
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
68
|
+
gu uses up to three models, each with its own command:
|
|
36
69
|
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
|
|
78
|
+
## Using gu
|
|
47
79
|
|
|
48
|
-
|
|
80
|
+
```
|
|
81
|
+
gu [-v|--verbose] [--log] [--color] [--name <text>] [--license <pro token>]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Flag | Effect |
|
|
49
85
|
| --- | --- |
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
63
|
-
| `/context-window [tokens\|auto]` | tell gu how big the coding model's context is (hosted models
|
|
64
|
-
| `/doctor` | check every configured model answers, especially the embedder |
|
|
65
|
-
| `/
|
|
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
|
|
75
|
-
| `/save-settings
|
|
76
|
-
| `/save-preset
|
|
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
|
-
| `/
|
|
82
|
-
| `/help`, `/exit`
|
|
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
|
-
|
|
85
|
-
slash command of its own. Run `/help` in the REPL for the list your version offers.
|
|
127
|
+
</details>
|
|
86
128
|
|
|
87
|
-
|
|
129
|
+
<details>
|
|
130
|
+
<summary><strong>Shell commands</strong></summary>
|
|
88
131
|
|
|
89
132
|
```
|
|
90
|
-
gu status worker
|
|
91
|
-
gu start | stop | restart
|
|
92
|
-
gu logs [--lines N] [-f] tail the
|
|
93
|
-
gu doctor [--client] set up models
|
|
94
|
-
gu rag
|
|
95
|
-
gu
|
|
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
|
|
100
|
-
gu
|
|
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 /
|
|
144
|
+
gu fix-path | fix-powershell repair PATH / remove PowerShell's `gu` alias
|
|
103
145
|
```
|
|
104
146
|
|
|
105
|
-
`gu-cli`
|
|
106
|
-
`token [<token>]`, `ws-ping-test` and `simulate-chat [text
|
|
107
|
-
|
|
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
|
-
##
|
|
152
|
+
## Where gu keeps things
|
|
110
153
|
|
|
111
154
|
| Path | Contents |
|
|
112
155
|
| --- | --- |
|
|
113
|
-
| `~/.gonext/worker.env` | sign-in: worker key and API
|
|
114
|
-
| `~/.gonext/sessions/` |
|
|
115
|
-
| `~/.gonext/worker.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/`,
|
|
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
|
-
##
|
|
167
|
+
## Troubleshooting
|
|
121
168
|
|
|
122
|
-
|
|
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
|
-
|
|
175
|
+
**Windows: `gu` runs `Get-Unique`.** PowerShell has a built-in `gu` alias. Run `gu-cli fix-powershell`.
|
|
125
176
|
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
180
|
+
**A change in a model or setting seems ignored.** `gu doctor` shows the model and URL actually in use.
|
|
133
181
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
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
|
|
143
|
-
| `GONEXT_PROBE_PYTHON` | Python for
|
|
144
|
-
| `GONEXT_MLX_LM_PYTHON` | Python for the MLX
|
|
145
|
-
| `GONEXT_OCR_MODEL_PATH` | local GLM-OCR
|
|
146
|
-
| `GONEXT_OCR_DEBUG=1` | print raw OCR
|
|
147
|
-
| `GONEXT_SIMULATE_TEXT` | default reply
|
|
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
|
-
|
|
206
|
+
</details>
|
|
150
207
|
|
|
151
|
-
|
|
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
|
-
|
|
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.
|
|
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,17 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiens.nguyen/gu-cli",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
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://
|
|
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",
|