@agent-nexus/cli 0.1.5 → 0.1.6
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/README.md +667 -0
- package/dist/index.js +477 -60
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
# @agent-nexus/cli
|
|
2
|
+
|
|
3
|
+
Official CLI for the [Nexus](https://nexusgpt.io) AI agent platform. Manage agents, workflows, deployments, knowledge bases, and more from your terminal.
|
|
4
|
+
|
|
5
|
+
- Wraps the full [Nexus Public API v1](../sdk)
|
|
6
|
+
- 24 command groups, 120+ subcommands
|
|
7
|
+
- Table, record, and JSON output modes
|
|
8
|
+
- Pipe-friendly: stdin input, `--json` output, composable with `jq`
|
|
9
|
+
- Zero config after `nexus auth login`
|
|
10
|
+
- Node.js 18+
|
|
11
|
+
|
|
12
|
+
> **Status: BETA** -- The CLI surface is stable but may evolve before 1.0.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Table of Contents
|
|
17
|
+
|
|
18
|
+
- [Installation](#installation)
|
|
19
|
+
- [Authentication](#authentication)
|
|
20
|
+
- [Quick Start](#quick-start)
|
|
21
|
+
- [Global Options](#global-options)
|
|
22
|
+
- [Input Patterns](#input-patterns)
|
|
23
|
+
- [Output Modes](#output-modes)
|
|
24
|
+
- [Commands](#commands)
|
|
25
|
+
- [Common Patterns](#common-patterns)
|
|
26
|
+
- [SDK Cross-Reference](#sdk-cross-reference)
|
|
27
|
+
- [Error Handling](#error-handling)
|
|
28
|
+
- [Troubleshooting](#troubleshooting)
|
|
29
|
+
- [Configuration Files](#configuration-files)
|
|
30
|
+
- [Related Resources](#related-resources)
|
|
31
|
+
- [License](#license)
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Install globally
|
|
39
|
+
npm install -g @agent-nexus/cli
|
|
40
|
+
|
|
41
|
+
# Or with pnpm
|
|
42
|
+
pnpm add -g @agent-nexus/cli
|
|
43
|
+
|
|
44
|
+
# Or with yarn
|
|
45
|
+
yarn global add @agent-nexus/cli
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Run a one-off command without installing:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx @agent-nexus/cli agent list
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Verify the installation:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
nexus --version
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Upgrade to the latest version:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
nexus upgrade
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
> The CLI checks for updates once per day and prints a notice to stderr when a newer version is available. This check never delays command execution.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Authentication
|
|
71
|
+
|
|
72
|
+
### Interactive Login
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
nexus auth login
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
This opens the Nexus settings page in your browser. Copy your API key and paste it at the prompt. The key is validated against the API before being saved.
|
|
79
|
+
|
|
80
|
+
### Non-Interactive Login
|
|
81
|
+
|
|
82
|
+
For CI/CD or scripting:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Via flag
|
|
86
|
+
nexus auth login --api-key nxs_abc123
|
|
87
|
+
|
|
88
|
+
# Via environment variable (no login needed)
|
|
89
|
+
export NEXUS_API_KEY=nxs_abc123
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Verify Authentication
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
nexus auth whoami
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Prints the API base URL and a masked version of your key (e.g., `nxs_abc1...3def`).
|
|
99
|
+
|
|
100
|
+
### Logout
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
nexus auth logout
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Removes stored credentials from `~/.nexus-mcp/config.json`.
|
|
107
|
+
|
|
108
|
+
### API Key Resolution
|
|
109
|
+
|
|
110
|
+
The CLI resolves the API key in this order (first match wins):
|
|
111
|
+
|
|
112
|
+
| Priority | Source | Example |
|
|
113
|
+
| -------- | ----------------------- | ------------------------------------ |
|
|
114
|
+
| 1 | `--api-key` flag | `nexus agent list --api-key nxs_...` |
|
|
115
|
+
| 2 | `NEXUS_API_KEY` env var | `export NEXUS_API_KEY=nxs_...` |
|
|
116
|
+
| 3 | Config file | Written by `nexus auth login` |
|
|
117
|
+
|
|
118
|
+
### Base URL Resolution
|
|
119
|
+
|
|
120
|
+
| Priority | Source | Default |
|
|
121
|
+
| -------- | ------------------------ | ------------------------------------------------------------------------- |
|
|
122
|
+
| 1 | `--base-url` flag | |
|
|
123
|
+
| 2 | `NEXUS_BASE_URL` env var | |
|
|
124
|
+
| 3 | Config file | |
|
|
125
|
+
| 4 | `NEXUS_ENV` env var | `production` = `https://api.nexusgpt.io`, `dev` = `http://localhost:3001` |
|
|
126
|
+
| 5 | Default | `https://api.nexusgpt.io` |
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Quick Start
|
|
131
|
+
|
|
132
|
+
A complete walkthrough: create an agent, give it a knowledge base, deploy it, and test it.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# 1. Authenticate
|
|
136
|
+
nexus auth login
|
|
137
|
+
|
|
138
|
+
# 2. Create an agent
|
|
139
|
+
nexus agent create \
|
|
140
|
+
--first-name "Support" \
|
|
141
|
+
--last-name "Bot" \
|
|
142
|
+
--role "Customer Support" \
|
|
143
|
+
--prompt "You are a helpful customer support agent. Answer questions using the knowledge base."
|
|
144
|
+
|
|
145
|
+
# 3. Upload a document to the knowledge base
|
|
146
|
+
nexus document upload ./product-faq.pdf
|
|
147
|
+
|
|
148
|
+
# 4. Create a collection (retrieval-augmented generation index)
|
|
149
|
+
nexus collection create --name "Product FAQ"
|
|
150
|
+
|
|
151
|
+
# 5. Attach the document to the collection
|
|
152
|
+
nexus collection attach-documents <collection-id> --document-ids <document-id>
|
|
153
|
+
|
|
154
|
+
# 6. Attach the collection as a tool on the agent
|
|
155
|
+
nexus agent-tool create <agent-id> \
|
|
156
|
+
--type COLLECTION \
|
|
157
|
+
--collection-id <collection-id> \
|
|
158
|
+
--label "FAQ Search"
|
|
159
|
+
|
|
160
|
+
# 7. Deploy the agent as a web widget
|
|
161
|
+
nexus deployment create \
|
|
162
|
+
--name "Support Widget" \
|
|
163
|
+
--type web \
|
|
164
|
+
--agent-id <agent-id>
|
|
165
|
+
|
|
166
|
+
# 8. Test via the emulator
|
|
167
|
+
nexus emulator session create <deployment-id>
|
|
168
|
+
nexus emulator send <deployment-id> <session-id> \
|
|
169
|
+
--text "How do I reset my password?"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
> **Tip:** Add `--json` to any command and pipe to `jq` to extract IDs:
|
|
173
|
+
>
|
|
174
|
+
> ```bash
|
|
175
|
+
> AGENT_ID=$(nexus agent create --first-name Bot --last-name Helper --role QA --json | jq -r '.id')
|
|
176
|
+
> ```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Global Options
|
|
181
|
+
|
|
182
|
+
These flags are available on every command:
|
|
183
|
+
|
|
184
|
+
| Flag | Description |
|
|
185
|
+
| ------------------ | ------------------------------------------------- |
|
|
186
|
+
| `--json` | Output results as JSON (for scripting and piping) |
|
|
187
|
+
| `--api-key <key>` | Override the API key for this invocation |
|
|
188
|
+
| `--base-url <url>` | Override the API base URL |
|
|
189
|
+
| `-v, --version` | Print the CLI version and exit |
|
|
190
|
+
| `--help` | Show help for any command or subcommand |
|
|
191
|
+
|
|
192
|
+
### Environment Variables
|
|
193
|
+
|
|
194
|
+
| Variable | Description |
|
|
195
|
+
| ---------------- | --------------------------------------------------------------- |
|
|
196
|
+
| `NEXUS_API_KEY` | API key (used when `--api-key` flag and config file are absent) |
|
|
197
|
+
| `NEXUS_BASE_URL` | API base URL override |
|
|
198
|
+
| `NEXUS_ENV` | Environment name: `production` (default) or `dev` |
|
|
199
|
+
| `NO_COLOR` | Disable all color output ([no-color.org](https://no-color.org)) |
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Input Patterns
|
|
204
|
+
|
|
205
|
+
The CLI offers flexible input for create and update commands.
|
|
206
|
+
|
|
207
|
+
### The `--body` Flag
|
|
208
|
+
|
|
209
|
+
Most create/update commands accept `--body` for raw JSON input:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Inline JSON
|
|
213
|
+
nexus agent create --body '{"firstName":"Ada","lastName":"Bot","role":"Assistant"}'
|
|
214
|
+
|
|
215
|
+
# From a JSON file
|
|
216
|
+
nexus agent create --body payload.json
|
|
217
|
+
|
|
218
|
+
# From stdin
|
|
219
|
+
cat payload.json | nexus agent create --body -
|
|
220
|
+
echo '{"firstName":"Ada","lastName":"Bot","role":"Assistant"}' | nexus agent create --body -
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Flag-Over-Body Merge
|
|
224
|
+
|
|
225
|
+
When you use both `--body` and individual flags, **flags take precedence**. The body provides defaults; flags override specific fields:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# Body sets firstName and role; --role flag overrides the role field
|
|
229
|
+
nexus agent create \
|
|
230
|
+
--body '{"firstName":"Ada","lastName":"Bot","role":"Assistant"}' \
|
|
231
|
+
--role "Senior Assistant"
|
|
232
|
+
# Result: { firstName: "Ada", lastName: "Bot", role: "Senior Assistant" }
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### File and Stdin Input
|
|
236
|
+
|
|
237
|
+
Flags like `--prompt`, `--content`, and `--description` accept:
|
|
238
|
+
|
|
239
|
+
| Input | Example |
|
|
240
|
+
| ------------ | ---------------------------------------------------------------- |
|
|
241
|
+
| Literal text | `--prompt "You are a helpful agent"` |
|
|
242
|
+
| File path | `--prompt ./system-prompt.md` (auto-detected if the file exists) |
|
|
243
|
+
| Stdin | `--prompt -` (reads from stdin) |
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# Load a prompt from a markdown file
|
|
247
|
+
nexus agent create --first-name Bot --last-name Helper --role QA --prompt ./prompt.md
|
|
248
|
+
|
|
249
|
+
# Pipe a prompt from another command
|
|
250
|
+
generate-prompt | nexus agent update abc-123 --prompt -
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Pagination
|
|
254
|
+
|
|
255
|
+
List commands support pagination:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
nexus agent list --page 2 --limit 50
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The pagination footer shows `total`, `page`, and whether `more available`.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Output Modes
|
|
266
|
+
|
|
267
|
+
### Table (Default for Lists)
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
ID FIRST NAME STATUS
|
|
271
|
+
──────────────────────────────────── ─────────────── ──────
|
|
272
|
+
abc-123-def-456 Support Bot ACTIVE
|
|
273
|
+
ghi-789-jkl-012 Sales Agent DRAFT
|
|
274
|
+
|
|
275
|
+
3 total · page 1 · more available
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Record (Default for Single Resources)
|
|
279
|
+
|
|
280
|
+
```
|
|
281
|
+
ID abc-123-def-456
|
|
282
|
+
Name Support Bot
|
|
283
|
+
Role Customer Support
|
|
284
|
+
Status ACTIVE
|
|
285
|
+
Created 2026-03-15T10:30:00.000Z
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### JSON (`--json`)
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
nexus agent list --json
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
```json
|
|
295
|
+
{
|
|
296
|
+
"data": [{ "id": "abc-123", "firstName": "Support", "lastName": "Bot", "status": "ACTIVE" }],
|
|
297
|
+
"meta": { "total": 3, "page": 1, "hasMore": true }
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
nexus agent get abc-123 --json
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
```json
|
|
306
|
+
{
|
|
307
|
+
"id": "abc-123",
|
|
308
|
+
"firstName": "Support",
|
|
309
|
+
"lastName": "Bot",
|
|
310
|
+
"role": "Customer Support",
|
|
311
|
+
"status": "ACTIVE"
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
> **Important:** Always use `--json` when piping output to `jq` or other tools. The default table output is for humans and will break parsers.
|
|
316
|
+
|
|
317
|
+
### Error Output in JSON Mode
|
|
318
|
+
|
|
319
|
+
When `--json` is active, errors are also returned as JSON:
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{
|
|
323
|
+
"error": {
|
|
324
|
+
"message": "Authentication failed — invalid or missing API key.",
|
|
325
|
+
"hint": "Run \"nexus auth login\" to re-authenticate, or set NEXUS_API_KEY."
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Commands
|
|
333
|
+
|
|
334
|
+
All commands follow the pattern: `nexus <group> <action> [arguments] [options]`
|
|
335
|
+
|
|
336
|
+
### Core Platform
|
|
337
|
+
|
|
338
|
+
| Command | Subcommands | Description |
|
|
339
|
+
| ---------------------------------------------------------- | ----------------------------------------------------------- | ------------------------- |
|
|
340
|
+
| [`auth`](docs/command-reference.md#nexus-auth) | `login` `logout` `whoami` | Authentication |
|
|
341
|
+
| [`agent`](docs/command-reference.md#nexus-agent) | `list` `get` `create` `update` `delete` `duplicate` | AI agent management |
|
|
342
|
+
| [`agent-tool`](docs/command-reference.md#nexus-agent-tool) | `list` `get` `create` `update` `delete` | Agent tool configurations |
|
|
343
|
+
| [`version`](docs/command-reference.md#nexus-version) | `list` `get` `create` `update` `delete` `restore` `publish` | Prompt version management |
|
|
344
|
+
| [`folder`](docs/command-reference.md#nexus-folder) | `list` `create` `update` `delete` `assign` | Agent folder organization |
|
|
345
|
+
| [`model`](docs/command-reference.md#nexus-model) | `list` | Available AI models |
|
|
346
|
+
|
|
347
|
+
### Workflows & Execution
|
|
348
|
+
|
|
349
|
+
| Command | Subcommands | Description |
|
|
350
|
+
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------- |
|
|
351
|
+
| [`workflow`](docs/command-reference.md#nexus-workflow) | `list` `get` `create` `update` `delete` `duplicate` `publish` `unpublish` `validate` `test` | Workflow CRUD and lifecycle |
|
|
352
|
+
| [`workflow node`](docs/command-reference.md#nexus-workflow-node) | `create` `get` `update` `delete` `test` `variables` `output-format` `reload-props` | Workflow node operations |
|
|
353
|
+
| [`workflow edge`](docs/command-reference.md#nexus-workflow-edge) | `create` `delete` | Node connections |
|
|
354
|
+
| [`workflow branch`](docs/command-reference.md#nexus-workflow-branch) | `list` `create` `update` `delete` | Branching logic |
|
|
355
|
+
| [`execution`](docs/command-reference.md#nexus-execution) | `list` `get` `graph` `output` `retry` `export` `node-result` | Workflow execution history |
|
|
356
|
+
|
|
357
|
+
### Knowledge & Documents
|
|
358
|
+
|
|
359
|
+
| Command | Subcommands | Description |
|
|
360
|
+
| ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | --------------------- |
|
|
361
|
+
| [`document`](docs/command-reference.md#nexus-document) | `list` `get` `upload` `create-text` `add-website` `import-google-sheets` `delete` | Knowledge documents |
|
|
362
|
+
| [`collection`](docs/command-reference.md#nexus-collection) | `list` `get` `create` `update` `delete` `search` `documents` `attach-documents` `remove-document` `stats` | Knowledge collections |
|
|
363
|
+
|
|
364
|
+
### Skills & Tasks
|
|
365
|
+
|
|
366
|
+
| Command | Subcommands | Description |
|
|
367
|
+
| ---------------------------------------------------------------- | ------------------------------------------------- | ---------------------- |
|
|
368
|
+
| [`task`](docs/command-reference.md#nexus-task) | `list` `get` `create` `update` `delete` `execute` | AI task management |
|
|
369
|
+
| [`template`](docs/command-reference.md#nexus-template) | `list` `get` `create` `upload` `generate` | Document templates |
|
|
370
|
+
| [`external-tool`](docs/command-reference.md#nexus-external-tool) | `list` `get` `create` `update` `delete` `test` | OpenAPI external tools |
|
|
371
|
+
|
|
372
|
+
### Deployment & Testing
|
|
373
|
+
|
|
374
|
+
| Command | Subcommands | Description |
|
|
375
|
+
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | --------------------------------- |
|
|
376
|
+
| [`deployment`](docs/command-reference.md#nexus-deployment) | `list` `get` `create` `update` `delete` `duplicate` `stats` `embed-config` `embed-config-update` | Agent deployments |
|
|
377
|
+
| [`deployment folder`](docs/command-reference.md#nexus-deployment-folder) | `list` `create` `update` `delete` `assign` | Deployment folder organization |
|
|
378
|
+
| [`emulator`](docs/command-reference.md#nexus-emulator) | `send` | Send messages to test deployments |
|
|
379
|
+
| [`emulator session`](docs/command-reference.md#nexus-emulator-session) | `create` `list` `get` `delete` | Emulator session management |
|
|
380
|
+
| [`emulator scenario`](docs/command-reference.md#nexus-emulator-scenario) | `save` `list` `get` `replay` `delete` | Save and replay test scenarios |
|
|
381
|
+
|
|
382
|
+
### Marketplace & Discovery
|
|
383
|
+
|
|
384
|
+
| Command | Subcommands | Description |
|
|
385
|
+
| ---------------------------------------------- | ------------------------------------------------------------------------ | -------------------------- |
|
|
386
|
+
| [`tool`](docs/command-reference.md#nexus-tool) | `search` `get` `credentials` `connect` `resolve-options` `skills` `test` | Marketplace tool discovery |
|
|
387
|
+
|
|
388
|
+
### Analytics & Operations
|
|
389
|
+
|
|
390
|
+
| Command | Subcommands | Description |
|
|
391
|
+
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | -------------------------- |
|
|
392
|
+
| [`analytics`](docs/command-reference.md#nexus-analytics) | `overview` `feedback` `export` | Organization analytics |
|
|
393
|
+
| [`eval`](docs/command-reference.md#nexus-eval) | (subgroups: `session`, `dataset`, `execute`, `judge`, `results`, `formats`, `judges`) | AI task evaluation |
|
|
394
|
+
| [`ticket`](docs/command-reference.md#nexus-ticket) | `list` `get` `create` `update` `comment` `comments` | Bug and feature tracking |
|
|
395
|
+
| [`phone-number`](docs/command-reference.md#nexus-phone-number) | `search` `buy` `list` `get` `release` | Phone number management |
|
|
396
|
+
| [`prompt-assistant`](docs/command-reference.md#nexus-prompt-assistant) | `chat` `get-thread` `delete-thread` | AI-assisted prompt writing |
|
|
397
|
+
|
|
398
|
+
### Utility
|
|
399
|
+
|
|
400
|
+
| Command | Subcommands | Description |
|
|
401
|
+
| ---------------------------------------------------- | ------------- | ------------------------------ |
|
|
402
|
+
| [`api`](docs/command-reference.md#nexus-api) | (passthrough) | Call any API endpoint directly |
|
|
403
|
+
| [`upgrade`](docs/command-reference.md#nexus-upgrade) | (self-update) | Upgrade the CLI to latest |
|
|
404
|
+
|
|
405
|
+
> **Full reference:** See [docs/command-reference.md](docs/command-reference.md) for complete documentation of every command, option, and example.
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## Common Patterns
|
|
410
|
+
|
|
411
|
+
### Extract IDs with `jq`
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
# Get the ID of a newly created agent
|
|
415
|
+
AGENT_ID=$(nexus agent create \
|
|
416
|
+
--first-name Bot --last-name Helper --role QA --json | jq -r '.id')
|
|
417
|
+
echo "Created agent: $AGENT_ID"
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Pipe JSON Output
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
# List all active agent IDs
|
|
424
|
+
nexus agent list --json | jq -r '.data[] | select(.status == "ACTIVE") | .id'
|
|
425
|
+
|
|
426
|
+
# Count deployments by type
|
|
427
|
+
nexus deployment list --json | jq '.data | group_by(.type) | map({type: .[0].type, count: length})'
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Bulk Operations
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
# Update all agents to use a specific model
|
|
434
|
+
nexus agent list --json | jq -r '.data[].id' | while read id; do
|
|
435
|
+
nexus agent update "$id" --model gpt-4o
|
|
436
|
+
echo "Updated $id"
|
|
437
|
+
done
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Raw API Passthrough
|
|
441
|
+
|
|
442
|
+
For endpoints without a dedicated CLI command:
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
# GET request
|
|
446
|
+
nexus api GET /models
|
|
447
|
+
|
|
448
|
+
# POST with inline body
|
|
449
|
+
nexus api POST /agents --body '{"firstName":"Test","lastName":"Bot","role":"QA"}'
|
|
450
|
+
|
|
451
|
+
# GET with query parameters
|
|
452
|
+
nexus api GET /agents --query page=1 --query limit=5
|
|
453
|
+
|
|
454
|
+
# POST with body from file
|
|
455
|
+
nexus api PATCH /agents/abc-123 --body payload.json
|
|
456
|
+
|
|
457
|
+
# POST with body from stdin
|
|
458
|
+
echo '{"text":"hello"}' | nexus api POST /emulator/dep-1/sessions/s-1/messages --body -
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Suppress Confirmation Prompts (CI/CD)
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
# Skip delete confirmation
|
|
465
|
+
nexus agent delete abc-123 --yes
|
|
466
|
+
|
|
467
|
+
# Preview what would be deleted without executing
|
|
468
|
+
nexus agent delete abc-123 --dry-run
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Load Prompts from Files
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
# Create an agent with a prompt from a markdown file
|
|
475
|
+
nexus agent create \
|
|
476
|
+
--first-name Support --last-name Bot --role "Customer Support" \
|
|
477
|
+
--prompt ./prompts/support-agent.md
|
|
478
|
+
|
|
479
|
+
# Update an agent's prompt from stdin
|
|
480
|
+
cat new-prompt.md | nexus agent update abc-123 --prompt -
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Workflow Build Pipeline
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
# Create, build, validate, test, and publish in one pipeline
|
|
487
|
+
WF_ID=$(nexus workflow create --name "Lead Qualifier" --json | jq -r '.id')
|
|
488
|
+
|
|
489
|
+
nexus workflow node create $WF_ID --type agentInputTrigger --name "Start"
|
|
490
|
+
nexus workflow node create $WF_ID --type aiTask --name "Qualify" \
|
|
491
|
+
--body '{"data":{"taskId":"task-123"}}'
|
|
492
|
+
|
|
493
|
+
nexus workflow validate $WF_ID
|
|
494
|
+
nexus workflow test $WF_ID --input '{"message":"I want to buy 100 units"}'
|
|
495
|
+
nexus workflow publish $WF_ID
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## SDK Cross-Reference
|
|
501
|
+
|
|
502
|
+
Every CLI command maps to an SDK method. Use the SDK (`@agent-nexus/sdk`) when building applications; use the CLI for scripting and exploration.
|
|
503
|
+
|
|
504
|
+
| CLI Command | SDK Equivalent |
|
|
505
|
+
| --------------------------------------- | ----------------------------------------------------- |
|
|
506
|
+
| `nexus agent list` | `client.agents.list()` |
|
|
507
|
+
| `nexus agent get <id>` | `client.agents.get(id)` |
|
|
508
|
+
| `nexus agent create --first-name X ...` | `client.agents.create({ firstName: "X", ... })` |
|
|
509
|
+
| `nexus agent update <id> --role Y` | `client.agents.update(id, { role: "Y" })` |
|
|
510
|
+
| `nexus agent delete <id>` | `client.agents.delete(id)` |
|
|
511
|
+
| `nexus agent-tool list <agentId>` | `client.agents.tools.list(agentId)` |
|
|
512
|
+
| `nexus version list <agentId>` | `client.agents.versions.list(agentId)` |
|
|
513
|
+
| `nexus workflow list` | `client.workflows.list()` |
|
|
514
|
+
| `nexus workflow publish <id>` | `client.workflows.publish(id)` |
|
|
515
|
+
| `nexus document upload <file>` | `client.documents.uploadFile(file)` |
|
|
516
|
+
| `nexus collection create --name X` | `client.documents.createCollection({ name: "X" })` |
|
|
517
|
+
| `nexus deployment create --name X ...` | `client.deployments.create({ name: "X", ... })` |
|
|
518
|
+
| `nexus emulator session create <depId>` | `client.emulator.createSession(depId)` |
|
|
519
|
+
| `nexus emulator send <depId> <sessId>` | `client.emulator.sendMessage(depId, sessId, { ... })` |
|
|
520
|
+
| `nexus tool search --query X` | `client.tools.search({ query: "X" })` |
|
|
521
|
+
| `nexus analytics overview` | `client.analytics.getOverview()` |
|
|
522
|
+
| `nexus model list` | `client.models.list()` |
|
|
523
|
+
| `nexus ticket create --title X ...` | `client.tickets.create({ title: "X", ... })` |
|
|
524
|
+
| `nexus phone-number list` | `client.phoneNumbers.list()` |
|
|
525
|
+
|
|
526
|
+
> **Full SDK documentation:** See [@agent-nexus/sdk README](../sdk/README.md)
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Error Handling
|
|
531
|
+
|
|
532
|
+
The CLI catches all errors and prints actionable messages with hints.
|
|
533
|
+
|
|
534
|
+
### Error Types
|
|
535
|
+
|
|
536
|
+
| Error | Cause | Hint |
|
|
537
|
+
| -------------------------- | ------------------------------------ | ------------------------------------------------------ |
|
|
538
|
+
| **Authentication failed** | Invalid, missing, or expired API key | Run `nexus auth login` or set `NEXUS_API_KEY` |
|
|
539
|
+
| **Not found (404)** | Resource ID doesn't exist | Run `nexus <resource> list` to find valid IDs |
|
|
540
|
+
| **Validation error (422)** | Invalid request body or parameters | Add `--json` to see the `details` field |
|
|
541
|
+
| **Connection error** | Network issue or wrong base URL | Check `--base-url` and network connectivity |
|
|
542
|
+
| **API error (5xx)** | Server-side error | Retry after a moment; report via `nexus ticket create` |
|
|
543
|
+
|
|
544
|
+
### Exit Codes
|
|
545
|
+
|
|
546
|
+
| Code | Meaning |
|
|
547
|
+
| ---- | ------------------------------------------------------------- |
|
|
548
|
+
| `0` | Success |
|
|
549
|
+
| `1` | Any error (authentication, API, validation, connection, etc.) |
|
|
550
|
+
|
|
551
|
+
### Error Format
|
|
552
|
+
|
|
553
|
+
**Human-readable (default):**
|
|
554
|
+
|
|
555
|
+
```
|
|
556
|
+
Error: Authentication failed — invalid or missing API key.
|
|
557
|
+
Run "nexus auth login" to re-authenticate, or set NEXUS_API_KEY.
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**JSON (`--json`):**
|
|
561
|
+
|
|
562
|
+
```json
|
|
563
|
+
{
|
|
564
|
+
"error": {
|
|
565
|
+
"message": "Authentication failed — invalid or missing API key.",
|
|
566
|
+
"hint": "Run \"nexus auth login\" to re-authenticate, or set NEXUS_API_KEY."
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
## Troubleshooting
|
|
574
|
+
|
|
575
|
+
### "No API key found"
|
|
576
|
+
|
|
577
|
+
```
|
|
578
|
+
Error: No API key found. Set NEXUS_API_KEY or run:
|
|
579
|
+
nexus auth login
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
**Fix:** Run `nexus auth login` or set the `NEXUS_API_KEY` environment variable.
|
|
583
|
+
|
|
584
|
+
### "Invalid key format -- keys start with nxs\_"
|
|
585
|
+
|
|
586
|
+
**Fix:** Copy the full API key from Settings > API Keys, including the `nxs_` prefix.
|
|
587
|
+
|
|
588
|
+
### "Could not reach the Nexus API"
|
|
589
|
+
|
|
590
|
+
**Fix:** Check your network connection. If using a custom base URL, verify it:
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
nexus auth whoami # shows the current base URL
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### "Validation failed (HTTP 401)"
|
|
597
|
+
|
|
598
|
+
**Fix:** Your API key may be expired or revoked. Regenerate it at [Settings > API Keys](https://app.nexusgpt.io/app/settings/api-keys) and run `nexus auth login` again.
|
|
599
|
+
|
|
600
|
+
### Colors Not Showing
|
|
601
|
+
|
|
602
|
+
The CLI disables colors when:
|
|
603
|
+
|
|
604
|
+
- `NO_COLOR` environment variable is set
|
|
605
|
+
- `--no-color` flag is passed
|
|
606
|
+
- stdout is not a TTY (e.g., piped to a file or another command)
|
|
607
|
+
|
|
608
|
+
### Update Check Not Working
|
|
609
|
+
|
|
610
|
+
The version check cache is stored at `~/.nexus-mcp/version-check.json`. Delete it to force a fresh check:
|
|
611
|
+
|
|
612
|
+
```bash
|
|
613
|
+
rm ~/.nexus-mcp/version-check.json
|
|
614
|
+
nexus agent list # triggers a new check
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### Upgrade Failed
|
|
618
|
+
|
|
619
|
+
If `nexus upgrade` fails (e.g., permission denied), run the install manually:
|
|
620
|
+
|
|
621
|
+
```bash
|
|
622
|
+
sudo npm install -g @agent-nexus/cli@latest
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
---
|
|
626
|
+
|
|
627
|
+
## Configuration Files
|
|
628
|
+
|
|
629
|
+
| File | Purpose | Permissions |
|
|
630
|
+
| --------------------------------- | ---------------------------------------------------- | ----------- |
|
|
631
|
+
| `~/.nexus-mcp/config.json` | API key and base URL (written by `nexus auth login`) | `0600` |
|
|
632
|
+
| `~/.nexus-mcp/version-check.json` | Update check cache (auto-managed, checked once/day) | `0600` |
|
|
633
|
+
|
|
634
|
+
The `~/.nexus-mcp/` directory is created with `0700` permissions. This path is shared with the [`@nexus/mcp-server`](../mcp-server/) package, so logging in via the CLI also authenticates the MCP server.
|
|
635
|
+
|
|
636
|
+
### Config File Format
|
|
637
|
+
|
|
638
|
+
```json
|
|
639
|
+
{
|
|
640
|
+
"apiKey": "nxs_your_api_key_here",
|
|
641
|
+
"baseUrl": "https://api.nexusgpt.io"
|
|
642
|
+
}
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
## Related Resources
|
|
648
|
+
|
|
649
|
+
| Resource | Link |
|
|
650
|
+
| --------------------- | ------------------------------------------------------------------------------ |
|
|
651
|
+
| SDK | [`@agent-nexus/sdk`](../sdk/README.md) |
|
|
652
|
+
| Product Documentation | [`packages/docs`](../docs/) |
|
|
653
|
+
| Claude Code Skills | [`packages/claude-code-skills`](../claude-code-skills/) |
|
|
654
|
+
| API Reference | `https://api.nexusgpt.io/api/public/v1` |
|
|
655
|
+
| Dashboard | [app.nexusgpt.io](https://app.nexusgpt.io) |
|
|
656
|
+
| CLI Command Reference | [docs/command-reference.md](docs/command-reference.md) |
|
|
657
|
+
| Input/Output Guide | [docs/input-output-patterns.md](docs/input-output-patterns.md) |
|
|
658
|
+
| Common Gotchas | [docs/gotchas.md](docs/gotchas.md) |
|
|
659
|
+
| Recipes | [docs/recipes.md](docs/recipes.md) |
|
|
660
|
+
| Report Issues | `nexus ticket create --type BUG --title "..." --description "..."` |
|
|
661
|
+
| Request Features | `nexus ticket create --type FEATURE_REQUEST --title "..." --description "..."` |
|
|
662
|
+
|
|
663
|
+
---
|
|
664
|
+
|
|
665
|
+
## License
|
|
666
|
+
|
|
667
|
+
[MIT](LICENSE)
|
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ var output_exports = {};
|
|
|
38
38
|
__export(output_exports, {
|
|
39
39
|
color: () => color,
|
|
40
40
|
isJsonMode: () => isJsonMode,
|
|
41
|
+
printContextBanner: () => printContextBanner,
|
|
41
42
|
printList: () => printList,
|
|
42
43
|
printPaginationMeta: () => printPaginationMeta,
|
|
43
44
|
printRecord: () => printRecord,
|
|
@@ -116,6 +117,13 @@ function printPaginationMeta(meta) {
|
|
|
116
117
|
${parts.join(" \xB7 ")}`));
|
|
117
118
|
}
|
|
118
119
|
}
|
|
120
|
+
function printContextBanner(resolved) {
|
|
121
|
+
if (_jsonMode) return;
|
|
122
|
+
if (!process.stderr.isTTY) return;
|
|
123
|
+
const orgPart = resolved.profile.orgName ? ` (${resolved.profile.orgName})` : "";
|
|
124
|
+
const line = `\u25B8 ${resolved.name}${orgPart} \xB7 ${SOURCE_LABELS[resolved.source]}`;
|
|
125
|
+
process.stderr.write(color.dim(line) + "\n");
|
|
126
|
+
}
|
|
119
127
|
function printList(data, meta, columns) {
|
|
120
128
|
if (_jsonMode) {
|
|
121
129
|
console.log(JSON.stringify({ data, meta }, null, 2));
|
|
@@ -126,7 +134,7 @@ function printList(data, meta, columns) {
|
|
|
126
134
|
printPaginationMeta(meta);
|
|
127
135
|
}
|
|
128
136
|
}
|
|
129
|
-
var _jsonMode, NO_COLOR2, color;
|
|
137
|
+
var _jsonMode, NO_COLOR2, color, SOURCE_LABELS;
|
|
130
138
|
var init_output = __esm({
|
|
131
139
|
"src/output.ts"() {
|
|
132
140
|
"use strict";
|
|
@@ -142,6 +150,14 @@ var init_output = __esm({
|
|
|
142
150
|
yellow: (t) => c2("33", t),
|
|
143
151
|
cyan: (t) => c2("36", t)
|
|
144
152
|
};
|
|
153
|
+
SOURCE_LABELS = {
|
|
154
|
+
flag: "flag override",
|
|
155
|
+
env: "env",
|
|
156
|
+
directory: ".nexusrc",
|
|
157
|
+
active: "active",
|
|
158
|
+
default: "default",
|
|
159
|
+
override: "api-key override"
|
|
160
|
+
};
|
|
145
161
|
}
|
|
146
162
|
});
|
|
147
163
|
|
|
@@ -150,7 +166,7 @@ var require_package = __commonJS({
|
|
|
150
166
|
"package.json"(exports2, module2) {
|
|
151
167
|
module2.exports = {
|
|
152
168
|
name: "@agent-nexus/cli",
|
|
153
|
-
version: "0.1.
|
|
169
|
+
version: "0.1.6",
|
|
154
170
|
description: "Official CLI for the Nexus AI agent platform.",
|
|
155
171
|
license: "MIT",
|
|
156
172
|
keywords: [
|
|
@@ -240,12 +256,32 @@ var URL_MAP = {
|
|
|
240
256
|
};
|
|
241
257
|
var CONFIG_DIR = import_node_path.default.join(import_node_os.default.homedir(), ".nexus-mcp");
|
|
242
258
|
var CONFIG_FILE = import_node_path.default.join(CONFIG_DIR, "config.json");
|
|
259
|
+
var NEXUSRC_FILENAME = ".nexusrc";
|
|
260
|
+
var PROFILE_NAME_RE = /^[a-z0-9][a-z0-9_-]{0,31}$/;
|
|
243
261
|
function loadConfig() {
|
|
244
262
|
try {
|
|
245
263
|
const raw = import_node_fs.default.readFileSync(CONFIG_FILE, "utf-8");
|
|
246
|
-
|
|
264
|
+
const parsed = JSON.parse(raw);
|
|
265
|
+
if ("profiles" in parsed && typeof parsed.profiles === "object") {
|
|
266
|
+
return parsed;
|
|
267
|
+
}
|
|
268
|
+
const v1 = parsed;
|
|
269
|
+
if (v1.apiKey) {
|
|
270
|
+
const migrated = {
|
|
271
|
+
activeProfile: "default",
|
|
272
|
+
profiles: {
|
|
273
|
+
default: {
|
|
274
|
+
apiKey: v1.apiKey,
|
|
275
|
+
...v1.baseUrl ? { baseUrl: v1.baseUrl } : {}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
saveConfig(migrated);
|
|
280
|
+
return migrated;
|
|
281
|
+
}
|
|
282
|
+
return emptyConfig();
|
|
247
283
|
} catch {
|
|
248
|
-
return
|
|
284
|
+
return emptyConfig();
|
|
249
285
|
}
|
|
250
286
|
}
|
|
251
287
|
function saveConfig(config) {
|
|
@@ -260,27 +296,159 @@ function clearConfig() {
|
|
|
260
296
|
} catch {
|
|
261
297
|
}
|
|
262
298
|
}
|
|
299
|
+
function emptyConfig() {
|
|
300
|
+
return { activeProfile: "", profiles: {} };
|
|
301
|
+
}
|
|
302
|
+
function getProfile(name) {
|
|
303
|
+
return loadConfig().profiles[name];
|
|
304
|
+
}
|
|
305
|
+
function saveProfile(name, profile) {
|
|
306
|
+
const config = loadConfig();
|
|
307
|
+
config.profiles[name] = profile;
|
|
308
|
+
if (!config.activeProfile || Object.keys(config.profiles).length === 1) {
|
|
309
|
+
config.activeProfile = name;
|
|
310
|
+
}
|
|
311
|
+
saveConfig(config);
|
|
312
|
+
}
|
|
313
|
+
function removeProfile(name) {
|
|
314
|
+
const config = loadConfig();
|
|
315
|
+
if (!(name in config.profiles)) return false;
|
|
316
|
+
delete config.profiles[name];
|
|
317
|
+
if (config.activeProfile === name) {
|
|
318
|
+
const remaining = Object.keys(config.profiles);
|
|
319
|
+
config.activeProfile = remaining[0] ?? "";
|
|
320
|
+
}
|
|
321
|
+
saveConfig(config);
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
function setActiveProfile(name) {
|
|
325
|
+
const config = loadConfig();
|
|
326
|
+
if (!(name in config.profiles)) {
|
|
327
|
+
const available = Object.keys(config.profiles).join(", ");
|
|
328
|
+
throw new Error(
|
|
329
|
+
`Profile "${name}" not found.` + (available ? ` Available: ${available}. Run: nexus auth list` : " Run: nexus auth login")
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
config.activeProfile = name;
|
|
333
|
+
saveConfig(config);
|
|
334
|
+
}
|
|
335
|
+
function listProfiles() {
|
|
336
|
+
const config = loadConfig();
|
|
337
|
+
return { profiles: config.profiles, activeProfile: config.activeProfile };
|
|
338
|
+
}
|
|
339
|
+
function validateProfileName(name) {
|
|
340
|
+
if (!PROFILE_NAME_RE.test(name)) {
|
|
341
|
+
return `Invalid profile name "${name}". Use lowercase letters, numbers, hyphens, underscores (max 32 chars, must start with alphanumeric).`;
|
|
342
|
+
}
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
function slugifyProfileName(input) {
|
|
346
|
+
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32) || "default";
|
|
347
|
+
}
|
|
348
|
+
function findNexusRc(startDir = process.cwd()) {
|
|
349
|
+
let dir = import_node_path.default.resolve(startDir);
|
|
350
|
+
const root = import_node_path.default.parse(dir).root;
|
|
351
|
+
while (true) {
|
|
352
|
+
const rcPath = import_node_path.default.join(dir, NEXUSRC_FILENAME);
|
|
353
|
+
try {
|
|
354
|
+
const raw = import_node_fs.default.readFileSync(rcPath, "utf-8");
|
|
355
|
+
const parsed = JSON.parse(raw);
|
|
356
|
+
if (parsed.profile && typeof parsed.profile === "string") {
|
|
357
|
+
return { profile: parsed.profile, rcPath };
|
|
358
|
+
}
|
|
359
|
+
} catch {
|
|
360
|
+
}
|
|
361
|
+
if (dir === root) break;
|
|
362
|
+
dir = import_node_path.default.dirname(dir);
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
function writeNexusRc(dir, profile) {
|
|
367
|
+
const rcPath = import_node_path.default.join(dir, NEXUSRC_FILENAME);
|
|
368
|
+
import_node_fs.default.writeFileSync(rcPath, JSON.stringify({ profile }, null, 2) + "\n");
|
|
369
|
+
}
|
|
370
|
+
function removeNexusRc(dir) {
|
|
371
|
+
const rcPath = import_node_path.default.join(dir, NEXUSRC_FILENAME);
|
|
372
|
+
try {
|
|
373
|
+
import_node_fs.default.unlinkSync(rcPath);
|
|
374
|
+
return true;
|
|
375
|
+
} catch {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function resolveProfile(opts) {
|
|
380
|
+
const directKey = opts?.apiKey || process.env.NEXUS_API_KEY;
|
|
381
|
+
if (directKey) {
|
|
382
|
+
return {
|
|
383
|
+
name: "override",
|
|
384
|
+
profile: {
|
|
385
|
+
apiKey: directKey,
|
|
386
|
+
baseUrl: opts?.baseUrl || process.env.NEXUS_BASE_URL
|
|
387
|
+
},
|
|
388
|
+
source: "override"
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
const config = loadConfig();
|
|
392
|
+
const profileNames = Object.keys(config.profiles);
|
|
393
|
+
const lookup = (name, source, rcPath) => {
|
|
394
|
+
const profile = config.profiles[name];
|
|
395
|
+
if (!profile) {
|
|
396
|
+
const available = profileNames.join(", ");
|
|
397
|
+
const sourceHint = source === "flag" ? `(from --profile flag)` : source === "env" ? `(from NEXUS_PROFILE env)` : source === "directory" ? `(from .nexusrc at ${rcPath})` : source === "active" ? `(active profile)` : `(default profile)`;
|
|
398
|
+
throw new Error(
|
|
399
|
+
`Profile "${name}" ${sourceHint} not found.` + (available ? ` Available: ${available}. Run: nexus auth list` : " No profiles configured. Run: nexus auth login")
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
return { name, profile, source, rcPath };
|
|
403
|
+
};
|
|
404
|
+
if (opts?.profile) {
|
|
405
|
+
return lookup(opts.profile, "flag");
|
|
406
|
+
}
|
|
407
|
+
if (process.env.NEXUS_PROFILE) {
|
|
408
|
+
return lookup(process.env.NEXUS_PROFILE, "env");
|
|
409
|
+
}
|
|
410
|
+
const rc = findNexusRc();
|
|
411
|
+
if (rc) {
|
|
412
|
+
return lookup(rc.profile, "directory", rc.rcPath);
|
|
413
|
+
}
|
|
414
|
+
if (config.activeProfile && config.profiles[config.activeProfile]) {
|
|
415
|
+
return lookup(config.activeProfile, "active");
|
|
416
|
+
}
|
|
417
|
+
if (config.profiles["default"]) {
|
|
418
|
+
return lookup("default", "default");
|
|
419
|
+
}
|
|
420
|
+
if (profileNames.length > 0) {
|
|
421
|
+
throw new Error(
|
|
422
|
+
`No active profile set. Available: ${profileNames.join(", ")}.
|
|
423
|
+
Run: nexus auth switch <profile>`
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
throw new Error("No profiles configured. Run:\n nexus auth login");
|
|
427
|
+
}
|
|
428
|
+
function resolveApiKey(override) {
|
|
429
|
+
if (override) return override;
|
|
430
|
+
return resolveProfile().profile.apiKey;
|
|
431
|
+
}
|
|
263
432
|
function resolveBaseUrl(override) {
|
|
264
433
|
if (override) return override;
|
|
265
434
|
if (process.env.NEXUS_BASE_URL) return process.env.NEXUS_BASE_URL;
|
|
266
|
-
|
|
267
|
-
|
|
435
|
+
try {
|
|
436
|
+
const resolved = resolveProfile();
|
|
437
|
+
if (resolved.profile.baseUrl) return resolved.profile.baseUrl;
|
|
438
|
+
} catch {
|
|
439
|
+
}
|
|
268
440
|
const env = process.env.NEXUS_ENV ?? "production";
|
|
269
441
|
return URL_MAP[env] ?? URL_MAP.production;
|
|
270
442
|
}
|
|
271
|
-
function resolveApiKey(override) {
|
|
272
|
-
if (override) return override;
|
|
273
|
-
if (process.env.NEXUS_API_KEY) return process.env.NEXUS_API_KEY;
|
|
274
|
-
const config = loadConfig();
|
|
275
|
-
if (config.apiKey) return config.apiKey;
|
|
276
|
-
throw new Error("No API key found. Set NEXUS_API_KEY or run:\n nexus auth login");
|
|
277
|
-
}
|
|
278
443
|
|
|
279
444
|
// src/client.ts
|
|
445
|
+
var _lastResolved = null;
|
|
280
446
|
function createClient(opts) {
|
|
447
|
+
const resolved = resolveProfile(opts);
|
|
448
|
+
_lastResolved = resolved;
|
|
281
449
|
return new import_sdk.NexusClient({
|
|
282
|
-
apiKey:
|
|
283
|
-
baseUrl: resolveBaseUrl(opts?.baseUrl)
|
|
450
|
+
apiKey: resolved.profile.apiKey,
|
|
451
|
+
baseUrl: resolved.profile.baseUrl ?? resolveBaseUrl(opts?.baseUrl)
|
|
284
452
|
});
|
|
285
453
|
}
|
|
286
454
|
|
|
@@ -861,20 +1029,21 @@ var import_promises = __toESM(require("readline/promises"));
|
|
|
861
1029
|
init_output();
|
|
862
1030
|
var SETTINGS_URL = "https://app.nexusgpt.io/app/settings/api-keys";
|
|
863
1031
|
function registerAuthCommands(program2) {
|
|
864
|
-
const auth = program2.command("auth").description("Manage authentication");
|
|
865
|
-
auth.command("login").description("Authenticate with the Nexus API").option("--api-key <key>", "API key (skip interactive prompt)").option("--env <env>", "Environment: dev or production", "production").addHelpText(
|
|
1032
|
+
const auth = program2.command("auth").description("Manage authentication and profiles");
|
|
1033
|
+
auth.command("login").description("Authenticate with the Nexus API and create a profile").option("--api-key <key>", "API key (skip interactive prompt)").option("--profile <name>", "Profile name to save as").option("--env <env>", "Environment: dev or production", "production").addHelpText(
|
|
866
1034
|
"after",
|
|
867
1035
|
`
|
|
868
1036
|
Examples:
|
|
869
1037
|
$ nexus auth login
|
|
870
1038
|
$ nexus auth login --api-key nxs_abc123
|
|
1039
|
+
$ nexus auth login --profile work --api-key nxs_abc123
|
|
871
1040
|
$ nexus auth login --env dev`
|
|
872
1041
|
).action(async (opts) => {
|
|
873
|
-
|
|
1042
|
+
let baseUrl;
|
|
874
1043
|
if (opts.env === "dev") {
|
|
875
|
-
|
|
1044
|
+
baseUrl = "http://localhost:3001";
|
|
876
1045
|
}
|
|
877
|
-
const
|
|
1046
|
+
const resolvedBaseUrl = baseUrl ?? resolveBaseUrl();
|
|
878
1047
|
let apiKey = opts.apiKey;
|
|
879
1048
|
if (!apiKey) {
|
|
880
1049
|
console.log(`Opening ${color.cyan(SETTINGS_URL)} ...`);
|
|
@@ -900,31 +1069,228 @@ Examples:
|
|
|
900
1069
|
return;
|
|
901
1070
|
}
|
|
902
1071
|
console.log("Validating...");
|
|
903
|
-
const
|
|
1072
|
+
const validateRes = await fetch(`${resolvedBaseUrl}/api/public/v1/agents?limit=1`, {
|
|
904
1073
|
headers: { "api-key": apiKey, Accept: "application/json" }
|
|
905
1074
|
});
|
|
906
|
-
if (!
|
|
1075
|
+
if (!validateRes.ok) {
|
|
907
1076
|
console.error(
|
|
908
|
-
color.red("Error:") + ` Validation failed (HTTP ${
|
|
1077
|
+
color.red("Error:") + ` Validation failed (HTTP ${validateRes.status}). Check your key and try again.`
|
|
909
1078
|
);
|
|
910
1079
|
process.exitCode = 1;
|
|
911
1080
|
return;
|
|
912
1081
|
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1082
|
+
let orgName;
|
|
1083
|
+
let orgId;
|
|
1084
|
+
try {
|
|
1085
|
+
const meRes = await fetch(`${resolvedBaseUrl}/api/public/v1/me`, {
|
|
1086
|
+
headers: { "api-key": apiKey, Accept: "application/json" }
|
|
1087
|
+
});
|
|
1088
|
+
if (meRes.ok) {
|
|
1089
|
+
const meJson = await meRes.json();
|
|
1090
|
+
if (meJson.data) {
|
|
1091
|
+
orgName = meJson.data.orgName;
|
|
1092
|
+
orgId = meJson.data.orgId;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
} catch {
|
|
1096
|
+
}
|
|
1097
|
+
if (orgName) {
|
|
1098
|
+
console.log(`Organization: ${color.cyan(orgName)}`);
|
|
1099
|
+
}
|
|
1100
|
+
let profileName = opts.profile;
|
|
1101
|
+
if (!profileName) {
|
|
1102
|
+
const suggested = orgName ? slugifyProfileName(orgName) : "default";
|
|
1103
|
+
const rl = import_promises.default.createInterface({ input: import_node_process.stdin, output: import_node_process.stdout });
|
|
1104
|
+
try {
|
|
1105
|
+
const answer = (await rl.question(`Profile name [${suggested}]: `)).trim();
|
|
1106
|
+
profileName = answer || suggested;
|
|
1107
|
+
} finally {
|
|
1108
|
+
rl.close();
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
const nameError = validateProfileName(profileName);
|
|
1112
|
+
if (nameError) {
|
|
1113
|
+
console.error(color.red("Error:") + " " + nameError);
|
|
1114
|
+
process.exitCode = 1;
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
const existing = getProfile(profileName);
|
|
1118
|
+
if (existing) {
|
|
1119
|
+
const existingLabel = existing.orgName ? ` (${existing.orgName})` : "";
|
|
1120
|
+
const rl = import_promises.default.createInterface({ input: import_node_process.stdin, output: import_node_process.stdout });
|
|
1121
|
+
try {
|
|
1122
|
+
const answer = (await rl.question(
|
|
1123
|
+
`Profile "${profileName}"${existingLabel} already exists. Overwrite? [y/N]: `
|
|
1124
|
+
)).trim();
|
|
1125
|
+
if (answer.toLowerCase() !== "y") {
|
|
1126
|
+
console.log("Aborted.");
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
} finally {
|
|
1130
|
+
rl.close();
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
saveProfile(profileName, {
|
|
1134
|
+
apiKey,
|
|
1135
|
+
...baseUrl ? { baseUrl } : {},
|
|
1136
|
+
...orgName ? { orgName } : {},
|
|
1137
|
+
...orgId ? { orgId } : {}
|
|
1138
|
+
});
|
|
1139
|
+
printSuccess(`Saved profile "${profileName}".`, {
|
|
1140
|
+
...orgName ? { organization: orgName } : {},
|
|
1141
|
+
profile: profileName,
|
|
917
1142
|
config: "~/.nexus-mcp/config.json"
|
|
918
1143
|
});
|
|
1144
|
+
const { profiles } = listProfiles();
|
|
1145
|
+
if (Object.keys(profiles).length > 1) {
|
|
1146
|
+
console.log(
|
|
1147
|
+
"\n" + color.dim("Tip: You have multiple profiles. Consider pinning directories:") + "\n" + color.dim(` nexus auth pin ${profileName} (in your project directory)`)
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
});
|
|
1151
|
+
auth.command("logout").description("Remove stored credentials").argument("[name]", "Specific profile to remove (default: active profile)").option("--all", "Remove all profiles").addHelpText(
|
|
1152
|
+
"after",
|
|
1153
|
+
`
|
|
1154
|
+
Examples:
|
|
1155
|
+
$ nexus auth logout # removes active profile
|
|
1156
|
+
$ nexus auth logout work # removes "work" profile
|
|
1157
|
+
$ nexus auth logout --all # removes all profiles`
|
|
1158
|
+
).action((name, opts) => {
|
|
1159
|
+
if (opts.all) {
|
|
1160
|
+
clearConfig();
|
|
1161
|
+
printSuccess("All profiles removed.");
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
const { activeProfile, profiles } = listProfiles();
|
|
1165
|
+
const target = name ?? activeProfile;
|
|
1166
|
+
if (!target) {
|
|
1167
|
+
console.error(color.red("Error:") + " No active profile. Run: nexus auth login");
|
|
1168
|
+
process.exitCode = 1;
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
if (!removeProfile(target)) {
|
|
1172
|
+
console.error(color.red("Error:") + ` Profile "${target}" not found. Run: nexus auth list`);
|
|
1173
|
+
process.exitCode = 1;
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
const remaining = Object.keys(profiles).filter((p) => p !== target);
|
|
1177
|
+
if (remaining.length === 0) {
|
|
1178
|
+
printSuccess(`Removed profile "${target}". No profiles remaining. Run: nexus auth login`);
|
|
1179
|
+
} else {
|
|
1180
|
+
const { activeProfile: newActive } = listProfiles();
|
|
1181
|
+
printSuccess(`Removed profile "${target}".`, {
|
|
1182
|
+
remaining: remaining.join(", "),
|
|
1183
|
+
...newActive ? { active: newActive } : {}
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
});
|
|
1187
|
+
auth.command("switch").description("Switch the active profile").argument("<name>", "Profile name to activate").addHelpText(
|
|
1188
|
+
"after",
|
|
1189
|
+
`
|
|
1190
|
+
Examples:
|
|
1191
|
+
$ nexus auth switch work
|
|
1192
|
+
$ nexus auth switch personal`
|
|
1193
|
+
).action((name) => {
|
|
1194
|
+
try {
|
|
1195
|
+
setActiveProfile(name);
|
|
1196
|
+
} catch (err) {
|
|
1197
|
+
console.error(color.red("Error:") + " " + err.message);
|
|
1198
|
+
process.exitCode = 1;
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
const profile = getProfile(name);
|
|
1202
|
+
const orgPart = profile?.orgName ? ` (${profile.orgName})` : "";
|
|
1203
|
+
printSuccess(`Switched to "${name}"${orgPart}.`);
|
|
1204
|
+
});
|
|
1205
|
+
auth.command("list").description("List all saved profiles").addHelpText(
|
|
1206
|
+
"after",
|
|
1207
|
+
`
|
|
1208
|
+
Examples:
|
|
1209
|
+
$ nexus auth list`
|
|
1210
|
+
).action(() => {
|
|
1211
|
+
const { profiles, activeProfile } = listProfiles();
|
|
1212
|
+
const names = Object.keys(profiles);
|
|
1213
|
+
if (names.length === 0) {
|
|
1214
|
+
console.log(color.dim("No profiles. Run: nexus auth login"));
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
const rows = names.map((name) => ({
|
|
1218
|
+
marker: name === activeProfile ? "\u25B8" : " ",
|
|
1219
|
+
name,
|
|
1220
|
+
orgName: profiles[name].orgName ?? color.dim("\u2014"),
|
|
1221
|
+
baseUrl: profiles[name].baseUrl ?? "https://api.nexusgpt.io"
|
|
1222
|
+
}));
|
|
1223
|
+
printTable(rows, [
|
|
1224
|
+
{ key: "marker", label: " ", width: 2 },
|
|
1225
|
+
{ key: "name", label: "PROFILE" },
|
|
1226
|
+
{ key: "orgName", label: "ORGANIZATION" },
|
|
1227
|
+
{ key: "baseUrl", label: "BASE URL" }
|
|
1228
|
+
]);
|
|
1229
|
+
});
|
|
1230
|
+
auth.command("pin").description("Pin the current directory to a profile via .nexusrc").argument("<profile>", "Profile name to pin").addHelpText(
|
|
1231
|
+
"after",
|
|
1232
|
+
`
|
|
1233
|
+
Examples:
|
|
1234
|
+
$ nexus auth pin work`
|
|
1235
|
+
).action((profileName) => {
|
|
1236
|
+
const profile = getProfile(profileName);
|
|
1237
|
+
if (!profile) {
|
|
1238
|
+
const { profiles } = listProfiles();
|
|
1239
|
+
const available = Object.keys(profiles).join(", ");
|
|
1240
|
+
console.error(
|
|
1241
|
+
color.red("Error:") + ` Profile "${profileName}" not found.` + (available ? ` Available: ${available}` : " Run: nexus auth login")
|
|
1242
|
+
);
|
|
1243
|
+
process.exitCode = 1;
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
writeNexusRc(process.cwd(), profileName);
|
|
1247
|
+
const orgPart = profile.orgName ? ` (${profile.orgName})` : "";
|
|
1248
|
+
printSuccess(`Pinned this directory to "${profileName}"${orgPart}.`, {
|
|
1249
|
+
file: ".nexusrc"
|
|
1250
|
+
});
|
|
1251
|
+
console.log(color.dim("\n Tip: Consider adding .nexusrc to your .gitignore"));
|
|
1252
|
+
});
|
|
1253
|
+
auth.command("unpin").description("Remove .nexusrc from the current directory").addHelpText(
|
|
1254
|
+
"after",
|
|
1255
|
+
`
|
|
1256
|
+
Examples:
|
|
1257
|
+
$ nexus auth unpin`
|
|
1258
|
+
).action(() => {
|
|
1259
|
+
if (!removeNexusRc(process.cwd())) {
|
|
1260
|
+
console.error(color.red("Error:") + " No .nexusrc found in current directory.");
|
|
1261
|
+
process.exitCode = 1;
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1264
|
+
printSuccess("Removed .nexusrc from current directory.");
|
|
919
1265
|
});
|
|
920
|
-
auth.command("
|
|
1266
|
+
auth.command("status").description("Show resolved profile and how it was determined").addHelpText(
|
|
921
1267
|
"after",
|
|
922
1268
|
`
|
|
923
1269
|
Examples:
|
|
924
|
-
$ nexus auth
|
|
1270
|
+
$ nexus auth status`
|
|
925
1271
|
).action(() => {
|
|
926
|
-
|
|
927
|
-
|
|
1272
|
+
try {
|
|
1273
|
+
const resolved = resolveProfile(program2.optsWithGlobals());
|
|
1274
|
+
const sourceExplanation = {
|
|
1275
|
+
flag: "--profile flag",
|
|
1276
|
+
env: "NEXUS_PROFILE environment variable",
|
|
1277
|
+
directory: `.nexusrc at ${resolved.rcPath}`,
|
|
1278
|
+
active: "active profile in config",
|
|
1279
|
+
default: 'fallback to "default" profile',
|
|
1280
|
+
override: "--api-key flag or NEXUS_API_KEY env"
|
|
1281
|
+
};
|
|
1282
|
+
const orgPart = resolved.profile.orgName ? ` (${resolved.profile.orgName})` : "";
|
|
1283
|
+
console.log(
|
|
1284
|
+
`Using profile ${color.cyan(`"${resolved.name}"`)}${orgPart} \u2014 ${color.dim(sourceExplanation[resolved.source])}`
|
|
1285
|
+
);
|
|
1286
|
+
console.log(
|
|
1287
|
+
` ${color.dim("key:")} ${resolved.profile.apiKey.slice(0, 8)}...${resolved.profile.apiKey.slice(-4)}`
|
|
1288
|
+
);
|
|
1289
|
+
console.log(` ${color.dim("api:")} ${resolved.profile.baseUrl ?? resolveBaseUrl()}`);
|
|
1290
|
+
} catch (err) {
|
|
1291
|
+
console.error(color.red("Error:") + " " + err.message);
|
|
1292
|
+
process.exitCode = 1;
|
|
1293
|
+
}
|
|
928
1294
|
});
|
|
929
1295
|
auth.command("whoami").description("Show current authentication status").addHelpText(
|
|
930
1296
|
"after",
|
|
@@ -933,10 +1299,10 @@ Examples:
|
|
|
933
1299
|
$ nexus auth whoami`
|
|
934
1300
|
).action(async () => {
|
|
935
1301
|
try {
|
|
936
|
-
const
|
|
937
|
-
const baseUrl = resolveBaseUrl();
|
|
1302
|
+
const resolved = resolveProfile(program2.optsWithGlobals());
|
|
1303
|
+
const baseUrl = resolved.profile.baseUrl ?? resolveBaseUrl();
|
|
938
1304
|
const res = await fetch(`${baseUrl}/api/public/v1/agents?limit=1`, {
|
|
939
|
-
headers: { "api-key": apiKey, Accept: "application/json" }
|
|
1305
|
+
headers: { "api-key": resolved.profile.apiKey, Accept: "application/json" }
|
|
940
1306
|
});
|
|
941
1307
|
if (!res.ok) {
|
|
942
1308
|
console.error(
|
|
@@ -946,8 +1312,10 @@ Examples:
|
|
|
946
1312
|
return;
|
|
947
1313
|
}
|
|
948
1314
|
printSuccess("Authenticated.", {
|
|
1315
|
+
profile: resolved.name,
|
|
1316
|
+
...resolved.profile.orgName ? { organization: resolved.profile.orgName } : {},
|
|
949
1317
|
api: baseUrl,
|
|
950
|
-
key: apiKey.slice(0, 8) + "..." + apiKey.slice(-4)
|
|
1318
|
+
key: resolved.profile.apiKey.slice(0, 8) + "..." + resolved.profile.apiKey.slice(-4)
|
|
951
1319
|
});
|
|
952
1320
|
} catch (err) {
|
|
953
1321
|
console.error(color.red("Error:") + " Not logged in. Run: nexus auth login");
|
|
@@ -3353,47 +3721,63 @@ function formatUpdateMessage(current, latest) {
|
|
|
3353
3721
|
IMPORTANT: You MUST update before running any other nexus commands. Results from an outdated CLI may be incorrect.
|
|
3354
3722
|
`;
|
|
3355
3723
|
}
|
|
3724
|
+
async function autoUpdate(currentVersion) {
|
|
3725
|
+
try {
|
|
3726
|
+
const cache = loadCache();
|
|
3727
|
+
let latest = null;
|
|
3728
|
+
if (cache && Date.now() - cache.lastChecked < CHECK_INTERVAL_MS) {
|
|
3729
|
+
latest = cache.latestVersion;
|
|
3730
|
+
} else {
|
|
3731
|
+
latest = await fetchLatestVersion();
|
|
3732
|
+
if (latest) {
|
|
3733
|
+
saveCache({ lastChecked: Date.now(), latestVersion: latest });
|
|
3734
|
+
}
|
|
3735
|
+
}
|
|
3736
|
+
if (!latest || compareSemver(currentVersion, latest) >= 0) {
|
|
3737
|
+
return null;
|
|
3738
|
+
}
|
|
3739
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
3740
|
+
process.stderr.write(`
|
|
3741
|
+
Auto-updating: ${currentVersion} \u2192 ${latest}\u2026
|
|
3742
|
+
`);
|
|
3743
|
+
execSync2(`npm install -g ${PACKAGE_NAME}@latest`, {
|
|
3744
|
+
stdio: "inherit"
|
|
3745
|
+
});
|
|
3746
|
+
return `
|
|
3747
|
+
Successfully auto-updated to ${latest}.
|
|
3748
|
+
`;
|
|
3749
|
+
} catch {
|
|
3750
|
+
return formatUpdateMessage(currentVersion, loadCache()?.latestVersion ?? "latest");
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3356
3753
|
|
|
3357
3754
|
// src/commands/upgrade.ts
|
|
3358
3755
|
var PACKAGE_NAME2 = "@agent-nexus/cli";
|
|
3359
3756
|
function registerUpgradeCommand(program2) {
|
|
3360
3757
|
const currentVersion = require_package().version;
|
|
3361
|
-
program2.command("upgrade").description("Upgrade the Nexus CLI to the latest version").addHelpText(
|
|
3362
|
-
"after",
|
|
3363
|
-
`
|
|
3758
|
+
program2.command("upgrade").description("Upgrade the Nexus CLI to the latest version").addHelpText("after", `
|
|
3364
3759
|
Examples:
|
|
3365
|
-
$ nexus upgrade`
|
|
3366
|
-
).action(async () => {
|
|
3760
|
+
$ nexus upgrade`).action(async () => {
|
|
3367
3761
|
process.stderr.write(`Current version: ${color.cyan(currentVersion)}
|
|
3368
3762
|
`);
|
|
3369
3763
|
process.stderr.write("Checking for updates\u2026\n");
|
|
3370
3764
|
const latest = await fetchLatestVersion();
|
|
3371
3765
|
if (!latest) {
|
|
3372
|
-
process.stderr.write(
|
|
3373
|
-
color.red("Failed to check for updates. Please try again later.\n")
|
|
3374
|
-
);
|
|
3766
|
+
process.stderr.write(color.red("Failed to check for updates. Please try again later.\n"));
|
|
3375
3767
|
process.exitCode = 1;
|
|
3376
3768
|
return;
|
|
3377
3769
|
}
|
|
3378
3770
|
if (compareSemver(currentVersion, latest) >= 0) {
|
|
3379
|
-
printSuccess(
|
|
3380
|
-
`Already up-to-date (${currentVersion}).`,
|
|
3381
|
-
{ version: currentVersion }
|
|
3382
|
-
);
|
|
3771
|
+
printSuccess(`Already up-to-date (${currentVersion}).`, { version: currentVersion });
|
|
3383
3772
|
return;
|
|
3384
3773
|
}
|
|
3385
|
-
process.stderr.write(
|
|
3386
|
-
|
|
3387
|
-
`
|
|
3388
|
-
);
|
|
3774
|
+
process.stderr.write(`Upgrading ${color.yellow(currentVersion)} \u2192 ${color.green(latest)}\u2026
|
|
3775
|
+
`);
|
|
3389
3776
|
try {
|
|
3390
3777
|
(0, import_node_child_process2.execSync)(`npm install -g ${PACKAGE_NAME2}@latest`, {
|
|
3391
3778
|
stdio: "inherit"
|
|
3392
3779
|
});
|
|
3393
|
-
printSuccess(
|
|
3394
|
-
`Successfully upgraded to ${latest}.`,
|
|
3395
|
-
{ from: currentVersion, to: latest }
|
|
3396
|
-
);
|
|
3780
|
+
printSuccess(`Successfully upgraded to ${latest}.`, { from: currentVersion, to: latest });
|
|
3397
3781
|
} catch {
|
|
3398
3782
|
process.stderr.write(
|
|
3399
3783
|
color.red(
|
|
@@ -4182,9 +4566,30 @@ Examples:
|
|
|
4182
4566
|
// src/index.ts
|
|
4183
4567
|
init_output();
|
|
4184
4568
|
var { version: VERSION } = require_package();
|
|
4185
|
-
var program = new import_commander.Command().name("nexus").description("Official CLI for the Nexus AI agent platform").version(VERSION, "-v, --version").option("--json", "Output as JSON").option("--api-key <key>", "Override API key for this invocation").option("--base-url <url>", "Override API base URL").hook("preAction", (thisCommand) => {
|
|
4569
|
+
var program = new import_commander.Command().name("nexus").description("Official CLI for the Nexus AI agent platform").version(VERSION, "-v, --version").option("--json", "Output as JSON").option("--api-key <key>", "Override API key for this invocation").option("--base-url <url>", "Override API base URL").option("--profile <name>", "Use a specific named profile").option("--no-auto-update", "Disable automatic updates when a new version is detected").hook("preAction", (thisCommand) => {
|
|
4186
4570
|
const opts = thisCommand.optsWithGlobals();
|
|
4187
4571
|
if (opts.json) setJsonMode(true);
|
|
4572
|
+
const cmdName = thisCommand.name();
|
|
4573
|
+
const skipBanner = [
|
|
4574
|
+
"auth",
|
|
4575
|
+
"upgrade",
|
|
4576
|
+
"version",
|
|
4577
|
+
"login",
|
|
4578
|
+
"logout",
|
|
4579
|
+
"whoami",
|
|
4580
|
+
"switch",
|
|
4581
|
+
"list",
|
|
4582
|
+
"pin",
|
|
4583
|
+
"unpin",
|
|
4584
|
+
"status"
|
|
4585
|
+
].includes(cmdName);
|
|
4586
|
+
if (!skipBanner && !isJsonMode()) {
|
|
4587
|
+
try {
|
|
4588
|
+
const resolved = resolveProfile(opts);
|
|
4589
|
+
printContextBanner(resolved);
|
|
4590
|
+
} catch {
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4188
4593
|
});
|
|
4189
4594
|
program.addHelpText("before", getBanner(VERSION));
|
|
4190
4595
|
program.configureHelp({
|
|
@@ -4217,10 +4622,22 @@ if (process.argv.length <= 2) {
|
|
|
4217
4622
|
program.help();
|
|
4218
4623
|
}
|
|
4219
4624
|
program.parseAsync(process.argv).then(async () => {
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4625
|
+
if (isJsonMode()) return;
|
|
4626
|
+
const ranCommand = process.argv[2];
|
|
4627
|
+
if (ranCommand === "upgrade") return;
|
|
4628
|
+
const opts = program.opts();
|
|
4629
|
+
if (opts.autoUpdate) {
|
|
4630
|
+
const msg = await autoUpdate(VERSION);
|
|
4631
|
+
if (msg) {
|
|
4632
|
+
const { color: color2 } = await Promise.resolve().then(() => (init_output(), output_exports));
|
|
4633
|
+
process.stderr.write(color2.green(msg));
|
|
4634
|
+
}
|
|
4635
|
+
} else {
|
|
4636
|
+
const updateMsg = await checkForUpdate(VERSION);
|
|
4637
|
+
if (updateMsg) {
|
|
4638
|
+
const { color: color2 } = await Promise.resolve().then(() => (init_output(), output_exports));
|
|
4639
|
+
process.stderr.write(color2.yellow(updateMsg));
|
|
4640
|
+
}
|
|
4224
4641
|
}
|
|
4225
4642
|
}).catch((err) => {
|
|
4226
4643
|
process.exitCode = handleError(err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-nexus/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Official CLI for the Nexus AI agent platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"commander": "^13.0.0",
|
|
33
|
-
"@agent-nexus/sdk": "0.1.
|
|
33
|
+
"@agent-nexus/sdk": "0.1.4"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "24.6.2",
|