@datalabrotterdam/nova-ai-cli 1.2.0-alpha.1 → 1.2.0-alpha.3
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/CHANGELOG.md +84 -0
- package/README.md +27 -25
- package/dist/chunk-37PMUZ34.js +147 -0
- package/dist/chunk-FMHWW3E6.js +11 -0
- package/dist/{chunk-ZKRZIF3S.js → chunk-NHGIUEIR.js} +15 -215
- package/dist/{headless-ZYUSTZDL.js → headless-OFJFVJ3O.js} +9 -33
- package/dist/index.js +38 -10
- package/dist/{tui-XOKXPXN2.js → tui-LNFSHL4Y.js} +88 -114
- package/dist/update-check-OX6WAPNN.js +19 -0
- package/package.json +21 -38
- package/dist/acp-ZYOQ6PON.js +0 -65
- package/dist/chunk-GZZ7PY3S.js +0 -8878
- package/dist/chunk-JAEXUFAS.js +0 -451
- package/dist/chunk-Q7WL3DXP.js +0 -19
- package/dist/index.d.ts +0 -1
- package/dist/login-6U7QS7EA.js +0 -118
- package/src/acp/web/dist/assets/index-CSccI7lJ.css +0 -1
- package/src/acp/web/dist/assets/index-DlCz3fmq.js +0 -1
- package/src/acp/web/dist/favicon.svg +0 -46
- package/src/acp/web/dist/index.html +0 -32
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# [@datalabrotterdam/nova-ai-cli-v1.2.0-alpha.3](https://github.com/Datalab-Rotterdam/nova-ai-cli/compare/@datalabrotterdam/nova-ai-cli@1.2.0-alpha.2...@datalabrotterdam/nova-ai-cli@1.2.0-alpha.3) (2026-10-04)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **agent:** never overwrite an unreadable settings file when switching a skill ([ca989ef](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/ca989ef1810fc903cea069cdadf3041fe164e364))
|
|
7
|
+
* **cli:** install the command as nova-ai only ([eda8064](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/eda806411af1738ff6f6b1404d23d4e84a74ced8))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **agent,cli:** Nova skill folders, switching skills off, a budgeted skill list ([0891c79](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/0891c79248d3a645d638f12f46928a54652b0941))
|
|
13
|
+
* **cli:** update notice from npm for every channel, cached daily ([c3a0014](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/c3a001473336aac14d216cdeec0bedde4df34427))
|
|
14
|
+
|
|
15
|
+
# [@datalabrotterdam/nova-ai-cli-v1.2.0-alpha.2](https://github.com/Datalab-Rotterdam/nova-ai-cli/compare/@datalabrotterdam/nova-ai-cli@1.2.0-alpha.1...@datalabrotterdam/nova-ai-cli@1.2.0-alpha.2) (2026-10-03)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* release the agent separately as @datalabrotterdam/nova-ai-agent ([32ecfc0](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/32ecfc0faa99bd5bb80cb2eaf2363abc050978f0))
|
|
21
|
+
|
|
22
|
+
# [1.2.0-alpha.1](https://github.com/Datalab-Rotterdam/nova-ai-cli/compare/v1.1.0...v1.2.0-alpha.1) (2026-10-03)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* **acp:** bounded, cancellable client terminals in the workspace ([81f7099](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/81f70996d9dfc8d78e12282def1582ea859f2784))
|
|
28
|
+
* **acp:** isolate background prompt jobs from live session history ([8328a8b](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/8328a8bfa1f22871ef36ec38247987e6effcd044))
|
|
29
|
+
* **acp:** replay loaded sessions faithfully; page session/list ([d576171](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/d5761710890f7b2f5d1b340cdce7faafcd2e3561))
|
|
30
|
+
* **env:** no shells or Docker probes when a session starts ([dc3a449](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/dc3a4495f394c1a16e48e282efd76b765af09999))
|
|
31
|
+
* **mcp:** connect servers in parallel with timeouts and diagnostics ([db4c62c](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/db4c62cd9c8ec0f197ea1ae1ce76adcf9d397ed5))
|
|
32
|
+
* **models:** offer and default to chat models only ([5d3ade2](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/5d3ade2727110ca7555bfdfa5b174c9e75b151f9))
|
|
33
|
+
* **security:** harden sessions, setup auth, credentials, processes and file access ([7f02a1d](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/7f02a1d203128555c4d00e5ab4dc4786329b6225))
|
|
34
|
+
* **tui:** keep printed lines inside the terminal width ([dd5cd0a](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/dd5cd0a40592af392eca797399ce56c0e672110e))
|
|
35
|
+
* **tui:** redraw cleanly after the terminal width changes ([f0b2ec6](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/f0b2ec6d01b0bd8ebcf087330c8bfd82072aa08d))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Features
|
|
39
|
+
|
|
40
|
+
* **acp:** agentInfo and env_var authentication in initialize ([b736e11](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/b736e115542b8fef083f9fc75514586327d3ac49))
|
|
41
|
+
* **acp:** namespace Nova extensions under _nova/ ([bf56cb9](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/bf56cb9e093dc90fc43b44008f1ddd86446a8cd0))
|
|
42
|
+
* **acp:** serialized turns, cancel, shutdown and proper error codes ([6688470](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/66884701af129ff2c1e9ad78b9e572d7ec64cc4b))
|
|
43
|
+
* **acp:** the agent owns permissions; clients only answer its questions ([7db651d](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/7db651d8d4883da2c170a831aeaa2952dc4444ac))
|
|
44
|
+
* **acp:** usage, session info, commands and model options as updates ([21d0816](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/21d08160c558ca9431deff8f8ead25e89a93d21c))
|
|
45
|
+
* added alpha stage on TUI ([3415411](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/3415411986ef4aefc2aa94dbb66fc73710fb6a5d))
|
|
46
|
+
* **cli:** proper entry point, -p/--print, login/logout, help and version ([73c8f94](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/73c8f9472099fa7c3cedccdd3c6a315d809e6a00))
|
|
47
|
+
* **core:** allow multiple tool calls per round ([f6a2171](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/f6a217145efac0722fddc49995808a7ad7bb2508))
|
|
48
|
+
* **core:** compact proactively at 80% of the model context window ([96afcbb](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/96afcbb7b68f4686a9b769bb80a73b00eebfe4a4))
|
|
49
|
+
* **core:** native tool calling with learned per-model text fallback ([6d71193](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/6d7119395b39a45026d676813ad3596382e2611a))
|
|
50
|
+
* **core:** share the ~/.nova-ai project layout with the VS Code extension ([aa75dde](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/aa75dde65218fdbd16b9f329bd849cc9ec608a28))
|
|
51
|
+
* **core:** validate tool args centrally before dispatch ([0a88e3e](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/0a88e3efb0d7c32611979e408b95e659873ec1e5))
|
|
52
|
+
* expand ACP runtime and terminal workflows ([bfbae15](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/bfbae157c301fbc1b7e88f5e267d25c8da126008))
|
|
53
|
+
* **mcp:** surface tool schemas, respect readOnlyHint, hint cwd args ([2b22be3](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/2b22be327b052788936e4badb010844f7ca3d057))
|
|
54
|
+
* **memory:** shared MEMORY.md index + typed notes, compatible with VS Code ([474c916](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/474c91694f4da58400426f39c290ac6888f4aa19))
|
|
55
|
+
* **modes:** plan mode can read, ask and keep the task list ([e253eaa](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/e253eaa66fd02478d61f34e734a27883068bf357))
|
|
56
|
+
* **policy:** agent-side permission policy with trust-gated rule sources ([234cd3a](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/234cd3adf06423c973c52497e5e31f6868d6b19a))
|
|
57
|
+
* **policy:** rule subjects for the extension's tool names ([5c188b6](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/5c188b610ff6e4ba8a715cc2ee10960736493b86))
|
|
58
|
+
* **tools:** add JSON schema validator for tool args ([24764ef](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/24764ef5100c14404f1923f89cc87c3d64de510d))
|
|
59
|
+
* **tools:** declare args schemas on every built-in tool ([79f6283](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/79f62833144f1a6aba9aaa65a2a19f18eb8793ca))
|
|
60
|
+
* **tools:** whitespace-tolerant edit_file with self-correction hints ([a350e14](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/a350e140e92c8469249d4c6297aad8f8161a217f))
|
|
61
|
+
* **tui:** Ink TUI with inline scrollback replaces pi-tui ([0725bae](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/0725bae27790829fd756afbdb5dd20574a1e0f00))
|
|
62
|
+
* **tui:** Shift+Enter inserts a new line where the terminal can report it ([b9c0b70](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/b9c0b7041057e2bdeb1675bbfa33a12fc3a664b9))
|
|
63
|
+
|
|
64
|
+
# [1.1.0](https://github.com/Datalab-Rotterdam/nova-ai-cli/compare/v1.0.1...v1.1.0) (2026-06-23)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### Features
|
|
68
|
+
|
|
69
|
+
* **acp-web:** theme support, favicon, font, and dep bumps ([0576402](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/0576402b6888a2cf6bc93123d733c4163358c63f))
|
|
70
|
+
* **acp:** add MCP server support (stdio/http/sse) ([ba98b0c](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/ba98b0c0b2e2461e8553331cafa1985e7673ee43))
|
|
71
|
+
|
|
72
|
+
## [1.0.1](https://github.com/Datalab-Rotterdam/nova-ai-cli/compare/v1.0.0...v1.0.1) (2026-06-22)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### Bug Fixes
|
|
76
|
+
|
|
77
|
+
* correct npm scope to [@datalabrotterdam](https://github.com/datalabrotterdam) ([6ab6bf8](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/6ab6bf88506cc1d4b778c1a30b123cd532a0a8de))
|
|
78
|
+
|
|
79
|
+
# 1.0.0 (2026-06-22)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
### Features
|
|
83
|
+
|
|
84
|
+
* add ACP agent, tool calling, and alpha release channel ([15d19a7](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/15d19a7998b4651ba9ad279fc2607006ea14ed49))
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="
|
|
3
|
+
<img src="https://raw.githubusercontent.com/Datalab-Rotterdam/nova-ai-cli/main/assets/logo.png" width="96" height="96" alt="Nova logo" />
|
|
4
4
|
|
|
5
5
|
# @datalabrotterdam/nova-ai-cli
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
[](https://agentclientprotocol.com)
|
|
13
13
|
[](https://github.com/Datalab-Rotterdam/nova-ai-cli/issues)
|
|
14
14
|
|
|
15
|
-
[npm](https://www.npmjs.com/package/@datalabrotterdam/nova-ai-cli) · [Issues](https://github.com/Datalab-Rotterdam/nova-ai-cli/issues) · [ACP reference](
|
|
15
|
+
[npm](https://www.npmjs.com/package/@datalabrotterdam/nova-ai-cli) · [Issues](https://github.com/Datalab-Rotterdam/nova-ai-cli/issues) · [ACP reference](https://github.com/Datalab-Rotterdam/nova-ai-cli/blob/main/docs/ACP.md) · [Settings and memory](https://github.com/Datalab-Rotterdam/nova-ai-cli/blob/main/docs/NOVA_HOME.md)
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
@@ -44,6 +44,11 @@ nova-ai # start the terminal UI in your project
|
|
|
44
44
|
Or without installing: `npx @datalabrotterdam/nova-ai-cli login`, then
|
|
45
45
|
`npx @datalabrotterdam/nova-ai-cli`.
|
|
46
46
|
|
|
47
|
+
When a newer version is on npm, the terminal UI says so, and so do `-p` and
|
|
48
|
+
`--version` (on stderr, only in a terminal). npm is asked at most once a day;
|
|
49
|
+
an alpha install also follows the `alpha` channel. `NOVA_NO_UPDATE_CHECK=1`
|
|
50
|
+
turns it off (it is off in CI).
|
|
51
|
+
|
|
47
52
|
```
|
|
48
53
|
nova-ai [options] Interactive terminal UI
|
|
49
54
|
nova-ai -p [options] [prompt] Run one request headless (see nova-ai -p --help)
|
|
@@ -90,7 +95,7 @@ Slash commands: `/help`, `/model`, `/mode`, `/permission`, `/session`,
|
|
|
90
95
|
`/resume`, `/clear`, `/compact`, `/rewind [n]`, `/queue`, `/steer`, `/usage`,
|
|
91
96
|
`/tools`, `/mcp`, `/skills`, `/shell` and `/agent` (background jobs), `/trust`
|
|
92
97
|
and `/exit`. Details:
|
|
93
|
-
[`src/tui/README.md`](
|
|
98
|
+
[`src/tui/README.md`](https://github.com/Datalab-Rotterdam/nova-ai-cli/blob/main/packages/cli/src/tui/README.md).
|
|
94
99
|
|
|
95
100
|
## Headless
|
|
96
101
|
|
|
@@ -131,8 +136,12 @@ always options, client file system and terminals, form questions, plans, usage
|
|
|
131
136
|
and title updates, MCP servers (stdio, HTTP, SSE), image prompts, and three
|
|
132
137
|
login methods (browser, `NOVA_API_KEY`, or `nova-ai login` in a terminal).
|
|
133
138
|
Nova-specific features (prompt queue, rewind, compaction, context usage,
|
|
134
|
-
background jobs) are `_nova/…` extension methods.
|
|
135
|
-
|
|
139
|
+
per-session settings, background jobs) are `_nova/…` extension methods. The agent is also published
|
|
140
|
+
on its own as
|
|
141
|
+
[`@datalabrotterdam/nova-ai-agent`](https://www.npmjs.com/package/@datalabrotterdam/nova-ai-agent)
|
|
142
|
+
(command `nova-ai-agent`), without the terminal UI, for integrations that only
|
|
143
|
+
need ACP. Everything is documented in
|
|
144
|
+
[docs/ACP.md](https://github.com/Datalab-Rotterdam/nova-ai-cli/blob/main/docs/ACP.md).
|
|
136
145
|
|
|
137
146
|
## Security model
|
|
138
147
|
|
|
@@ -149,6 +158,9 @@ background jobs) are `_nova/…` extension methods. Everything is documented in
|
|
|
149
158
|
private `~/.nova-ai/projects/<key>/settings.json`, outside the repository.
|
|
150
159
|
Compound commands (`a && b`, pipes) are checked part by part; substitutions
|
|
151
160
|
and nested shells need an exact rule.
|
|
161
|
+
- **Web pages are fetched only with approval.** `fetch_url` asks every time
|
|
162
|
+
unless a rule allows that URL (a URL can carry data out), and a redirect to
|
|
163
|
+
another site needs its own approval.
|
|
152
164
|
- **File access stays in the workspace** (symlinks resolved); commands run in
|
|
153
165
|
their own process group with a timeout, and the whole tree is stopped on
|
|
154
166
|
cancel.
|
|
@@ -168,11 +180,14 @@ VS Code extension: settings, per-project trust, sessions and memory.
|
|
|
168
180
|
- **Instructions**: `NOVA.md` and `AGENTS.md` in the workspace.
|
|
169
181
|
- **Memory**: a `MEMORY.md` index plus notes, globally and per project,
|
|
170
182
|
through the `memory_read` and `memory_write` tools (writes need approval).
|
|
171
|
-
- **Skills**: `SKILL.md` files under `.
|
|
172
|
-
|
|
183
|
+
- **Skills**: `SKILL.md` files under `.nova-ai/skills` in the workspace or
|
|
184
|
+
`~/.nova-ai/skills` for every project (`.agents`, `.claude` and `.codex`
|
|
185
|
+
skills folders are read too). `/skills` lists them; `/skills off <name>`
|
|
186
|
+
switches one off in this project (`--global`: everywhere). Only names and
|
|
187
|
+
short descriptions go into the prompt; Nova loads a skill when it fits.
|
|
173
188
|
- **MCP servers**: `.mcp.json` or `mcpServers` in `.nova-ai/settings.json`.
|
|
174
189
|
|
|
175
|
-
The complete layout and rule syntax: [docs/NOVA_HOME.md](
|
|
190
|
+
The complete layout and rule syntax: [docs/NOVA_HOME.md](https://github.com/Datalab-Rotterdam/nova-ai-cli/blob/main/docs/NOVA_HOME.md).
|
|
176
191
|
|
|
177
192
|
## Models
|
|
178
193
|
|
|
@@ -191,26 +206,13 @@ hand).
|
|
|
191
206
|
| `NOVA_TOOL_PROTOCOL` | Force `native` or `text` tool calling |
|
|
192
207
|
| `NOVA_NES_MODEL` | Separate model for next-edit suggestions (ACP) |
|
|
193
208
|
| `NOVA_KITTY_KEYBOARD` | `1`/`0`: force the kitty keyboard protocol on or off |
|
|
209
|
+
| `NOVA_NO_UPDATE_CHECK` | Don't ask npm for a newer version (also `NO_UPDATE_NOTIFIER`, or `CI`) |
|
|
194
210
|
|
|
195
211
|
## Development
|
|
196
212
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
npm run build # the login page and the CLI bundle in dist/
|
|
201
|
-
npm run dev # run from source with tsx
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
Tests never touch your `~/.nova-ai` or the real Nova API: they run with a
|
|
205
|
-
throwaway home folder and point the client at a local port. The ACP
|
|
206
|
-
conformance test starts the real `--acp` process against a fake gateway. CI
|
|
207
|
-
runs the suite on Linux, macOS and Windows with Node 22 and 24 (the PTY
|
|
208
|
-
scenario on Linux and macOS). Releases are cut by `semantic-release` from
|
|
209
|
-
`main` and `alpha`.
|
|
210
|
-
|
|
211
|
-
Planned: OIDC login against the Nova platform instead of a pasted API key,
|
|
212
|
-
and Remote Control (driving a running session from the Nova web UI or mobile
|
|
213
|
-
app). The standalone browser UI (`--web`) is experimental.
|
|
213
|
+
This package lives in the [nova-ai-cli repository](https://github.com/Datalab-Rotterdam/nova-ai-cli)
|
|
214
|
+
next to the agent package it depends on; see the repository README for
|
|
215
|
+
building and testing.
|
|
214
216
|
|
|
215
217
|
## License
|
|
216
218
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CLI_PACKAGE_NAME,
|
|
3
|
+
cliVersion
|
|
4
|
+
} from "./chunk-FMHWW3E6.js";
|
|
5
|
+
|
|
6
|
+
// src/update-check.ts
|
|
7
|
+
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
8
|
+
import { dirname, join } from "path";
|
|
9
|
+
import { novaHomeRoot } from "@datalabrotterdam/nova-ai-agent/core/nova-home.js";
|
|
10
|
+
var DIST_TAGS_URL = `https://registry.npmjs.org/-/package/${CLI_PACKAGE_NAME.replace("/", "%2F")}/dist-tags`;
|
|
11
|
+
var DEFAULT_TIMEOUT_MS = 3e3;
|
|
12
|
+
var CACHE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
13
|
+
function updateCachePath() {
|
|
14
|
+
return join(novaHomeRoot(), "update-check.json");
|
|
15
|
+
}
|
|
16
|
+
function updateChecksDisabled(env = process.env) {
|
|
17
|
+
return Boolean(env.NOVA_NO_UPDATE_CHECK || env.NO_UPDATE_NOTIFIER || env.CI);
|
|
18
|
+
}
|
|
19
|
+
async function checkForUpdate(options = {}) {
|
|
20
|
+
try {
|
|
21
|
+
if (updateChecksDisabled(options.env)) return null;
|
|
22
|
+
const currentVersion = options.currentVersion ?? cliVersion();
|
|
23
|
+
if (!currentVersion) return null;
|
|
24
|
+
const distTags = await readDistTags(options);
|
|
25
|
+
if (!distTags) return null;
|
|
26
|
+
return chooseUpdate(currentVersion, distTags);
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function chooseUpdate(currentVersion, distTags) {
|
|
32
|
+
const channel = prereleaseChannel(currentVersion);
|
|
33
|
+
const tags = channel && distTags[channel] ? [channel, "latest"] : ["latest"];
|
|
34
|
+
let best = null;
|
|
35
|
+
for (const tag of tags) {
|
|
36
|
+
const version = distTags[tag];
|
|
37
|
+
if (!version || !isNewerVersion(version, currentVersion)) continue;
|
|
38
|
+
if (!best || isNewerVersion(version, best.version)) best = { tag, version };
|
|
39
|
+
}
|
|
40
|
+
if (!best) return null;
|
|
41
|
+
return {
|
|
42
|
+
currentVersion,
|
|
43
|
+
latestVersion: best.version,
|
|
44
|
+
command: `npm install -g ${CLI_PACKAGE_NAME}@${best.tag}`
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async function readDistTags(options) {
|
|
48
|
+
const now = (options.now ?? Date.now)();
|
|
49
|
+
const cachePath = options.cachePath === void 0 ? updateCachePath() : options.cachePath;
|
|
50
|
+
const cached = cachePath ? readCache(cachePath) : null;
|
|
51
|
+
if (cached && now - cached.checkedAt >= 0 && now - cached.checkedAt < CACHE_MAX_AGE_MS) {
|
|
52
|
+
return cached.distTags;
|
|
53
|
+
}
|
|
54
|
+
const response = await (options.fetchImpl ?? fetch)(DIST_TAGS_URL, {
|
|
55
|
+
headers: { accept: "application/json" },
|
|
56
|
+
signal: AbortSignal.any([
|
|
57
|
+
AbortSignal.timeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS),
|
|
58
|
+
...options.signal ? [options.signal] : []
|
|
59
|
+
])
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) return null;
|
|
62
|
+
const payload = await response.json();
|
|
63
|
+
if (!isDistTags(payload)) return null;
|
|
64
|
+
if (cachePath) writeCache(cachePath, { checkedAt: now, distTags: payload });
|
|
65
|
+
return payload;
|
|
66
|
+
}
|
|
67
|
+
function readCache(path) {
|
|
68
|
+
try {
|
|
69
|
+
const value = JSON.parse(readFileSync(path, "utf8"));
|
|
70
|
+
if (value && typeof value === "object" && typeof value.checkedAt === "number" && isDistTags(value.distTags)) {
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
function writeCache(path, value) {
|
|
78
|
+
try {
|
|
79
|
+
mkdirSync(dirname(path), { recursive: true, mode: 448 });
|
|
80
|
+
writeFileSync(path, `${JSON.stringify(value)}
|
|
81
|
+
`, { mode: 384 });
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function isDistTags(value) {
|
|
86
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.values(value).every((version) => typeof version === "string");
|
|
87
|
+
}
|
|
88
|
+
function prereleaseChannel(version) {
|
|
89
|
+
const parsed = parseVersion(version);
|
|
90
|
+
const first = parsed?.prerelease[0];
|
|
91
|
+
return first && !/^\d+$/.test(first) ? first : null;
|
|
92
|
+
}
|
|
93
|
+
function readInstalledVersion() {
|
|
94
|
+
return cliVersion();
|
|
95
|
+
}
|
|
96
|
+
function isNewerVersion(candidate, current) {
|
|
97
|
+
const next = parseVersion(candidate);
|
|
98
|
+
const installed = parseVersion(current);
|
|
99
|
+
if (!next || !installed) return false;
|
|
100
|
+
for (let index = 0; index < 3; index++) {
|
|
101
|
+
const difference = next.core[index] - installed.core[index];
|
|
102
|
+
if (difference !== 0) return difference > 0;
|
|
103
|
+
}
|
|
104
|
+
return comparePrerelease(next.prerelease, installed.prerelease) > 0;
|
|
105
|
+
}
|
|
106
|
+
function parseVersion(value) {
|
|
107
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(value);
|
|
108
|
+
if (!match) return null;
|
|
109
|
+
return {
|
|
110
|
+
core: [Number(match[1]), Number(match[2]), Number(match[3])],
|
|
111
|
+
prerelease: match[4]?.split(".") ?? []
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function comparePrerelease(left, right) {
|
|
115
|
+
if (left.length === 0 || right.length === 0) {
|
|
116
|
+
if (left.length === right.length) return 0;
|
|
117
|
+
return left.length === 0 ? 1 : -1;
|
|
118
|
+
}
|
|
119
|
+
const length = Math.max(left.length, right.length);
|
|
120
|
+
for (let index = 0; index < length; index++) {
|
|
121
|
+
const leftPart = left[index];
|
|
122
|
+
const rightPart = right[index];
|
|
123
|
+
if (leftPart === void 0 || rightPart === void 0) {
|
|
124
|
+
return leftPart === rightPart ? 0 : leftPart === void 0 ? -1 : 1;
|
|
125
|
+
}
|
|
126
|
+
if (leftPart === rightPart) continue;
|
|
127
|
+
const leftNumber = /^\d+$/.test(leftPart) ? Number(leftPart) : null;
|
|
128
|
+
const rightNumber = /^\d+$/.test(rightPart) ? Number(rightPart) : null;
|
|
129
|
+
if (leftNumber !== null && rightNumber !== null) return leftNumber - rightNumber;
|
|
130
|
+
if (leftNumber !== null || rightNumber !== null) return leftNumber !== null ? -1 : 1;
|
|
131
|
+
return leftPart < rightPart ? -1 : 1;
|
|
132
|
+
}
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
function formatUpdateNotice(update) {
|
|
136
|
+
return `Update available: nova-ai ${update.currentVersion} \u2192 ${update.latestVersion}. Run: ${update.command}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export {
|
|
140
|
+
updateCachePath,
|
|
141
|
+
updateChecksDisabled,
|
|
142
|
+
checkForUpdate,
|
|
143
|
+
chooseUpdate,
|
|
144
|
+
readInstalledVersion,
|
|
145
|
+
isNewerVersion,
|
|
146
|
+
formatUpdateNotice
|
|
147
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/version.ts
|
|
2
|
+
import { readPackageVersion } from "@datalabrotterdam/nova-ai-agent/core/version.js";
|
|
3
|
+
var CLI_PACKAGE_NAME = "@datalabrotterdam/nova-ai-cli";
|
|
4
|
+
function cliVersion() {
|
|
5
|
+
return readPackageVersion(CLI_PACKAGE_NAME, import.meta.url);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
CLI_PACKAGE_NAME,
|
|
10
|
+
cliVersion
|
|
11
|
+
};
|
|
@@ -1,135 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NOVA_METHODS,
|
|
3
|
-
NOVA_NOTIFICATIONS,
|
|
4
|
-
NovaAgent,
|
|
5
|
-
createAgentApp,
|
|
6
|
-
fromElicitationRequest,
|
|
7
|
-
isInteractionMode,
|
|
8
|
-
readSettings,
|
|
9
|
-
resolveWorkspaceFile,
|
|
10
|
-
toElicitationResponse
|
|
11
|
-
} from "./chunk-GZZ7PY3S.js";
|
|
12
|
-
import {
|
|
13
|
-
isWorkspaceTrusted
|
|
14
|
-
} from "./chunk-JAEXUFAS.js";
|
|
15
|
-
|
|
16
|
-
// src/client/in-process.ts
|
|
17
|
-
import * as acp from "@agentclientprotocol/sdk";
|
|
18
|
-
|
|
19
|
-
// src/client/nova-agent-client.ts
|
|
20
|
-
var NovaAgentClient = class {
|
|
21
|
-
constructor(connection) {
|
|
22
|
-
this.connection = connection;
|
|
23
|
-
}
|
|
24
|
-
connection;
|
|
25
|
-
initialize(params) {
|
|
26
|
-
return this.connection.initialize(params);
|
|
27
|
-
}
|
|
28
|
-
newSession(params) {
|
|
29
|
-
return this.connection.newSession(params);
|
|
30
|
-
}
|
|
31
|
-
loadSession(params) {
|
|
32
|
-
return this.connection.loadSession(params);
|
|
33
|
-
}
|
|
34
|
-
resumeSession(params) {
|
|
35
|
-
return this.connection.resumeSession(params);
|
|
36
|
-
}
|
|
37
|
-
closeSession(params) {
|
|
38
|
-
return this.connection.closeSession(params);
|
|
39
|
-
}
|
|
40
|
-
prompt(params) {
|
|
41
|
-
return this.connection.prompt(params);
|
|
42
|
-
}
|
|
43
|
-
cancel(params) {
|
|
44
|
-
return this.connection.cancel(params);
|
|
45
|
-
}
|
|
46
|
-
setSessionMode(params) {
|
|
47
|
-
return this.connection.setSessionMode(params);
|
|
48
|
-
}
|
|
49
|
-
setSessionConfigOption(params) {
|
|
50
|
-
return this.connection.setSessionConfigOption(params);
|
|
51
|
-
}
|
|
52
|
-
queueEnqueue(params) {
|
|
53
|
-
return this.ext(NOVA_METHODS.queueEnqueue, params);
|
|
54
|
-
}
|
|
55
|
-
queueList(params) {
|
|
56
|
-
return this.ext(NOVA_METHODS.queueList, params);
|
|
57
|
-
}
|
|
58
|
-
queueEditBegin(params) {
|
|
59
|
-
return this.ext(NOVA_METHODS.queueEditBegin, params);
|
|
60
|
-
}
|
|
61
|
-
queueUpdate(params) {
|
|
62
|
-
return this.ext(NOVA_METHODS.queueUpdate, params);
|
|
63
|
-
}
|
|
64
|
-
queueRemove(params) {
|
|
65
|
-
return this.ext(NOVA_METHODS.queueRemove, params);
|
|
66
|
-
}
|
|
67
|
-
queueClear(params) {
|
|
68
|
-
return this.ext(NOVA_METHODS.queueClear, params);
|
|
69
|
-
}
|
|
70
|
-
queueTakeNext(params) {
|
|
71
|
-
return this.ext(NOVA_METHODS.queueTakeNext, params);
|
|
72
|
-
}
|
|
73
|
-
sessionCompact(params) {
|
|
74
|
-
return this.ext(
|
|
75
|
-
NOVA_METHODS.sessionCompact,
|
|
76
|
-
params
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
sessionContextUsage(params) {
|
|
80
|
-
return this.ext(NOVA_METHODS.sessionContextUsage, params);
|
|
81
|
-
}
|
|
82
|
-
sessionRewind(params) {
|
|
83
|
-
return this.ext(NOVA_METHODS.sessionRewind, params);
|
|
84
|
-
}
|
|
85
|
-
backgroundStartTerminal(params) {
|
|
86
|
-
return this.ext(NOVA_METHODS.backgroundStartTerminal, params);
|
|
87
|
-
}
|
|
88
|
-
backgroundStartPrompt(params) {
|
|
89
|
-
return this.ext(NOVA_METHODS.backgroundStartPrompt, params);
|
|
90
|
-
}
|
|
91
|
-
backgroundList(params) {
|
|
92
|
-
return this.ext(NOVA_METHODS.backgroundList, params);
|
|
93
|
-
}
|
|
94
|
-
backgroundOutput(params) {
|
|
95
|
-
return this.ext(NOVA_METHODS.backgroundOutput, params);
|
|
96
|
-
}
|
|
97
|
-
backgroundKill(params) {
|
|
98
|
-
return this.ext(NOVA_METHODS.backgroundKill, params);
|
|
99
|
-
}
|
|
100
|
-
backgroundRelease(params) {
|
|
101
|
-
return this.ext(NOVA_METHODS.backgroundRelease, params);
|
|
102
|
-
}
|
|
103
|
-
async ext(method, params) {
|
|
104
|
-
return await this.connection.extMethod(method, params);
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
// src/client/in-process.ts
|
|
109
|
-
function startInProcessAgent(toClient, agent = new NovaAgent()) {
|
|
110
|
-
const toAgent = new TransformStream();
|
|
111
|
-
const toClientStream = new TransformStream();
|
|
112
|
-
const agentConnection = createAgentApp(agent).connect(
|
|
113
|
-
acp.ndJsonStream(toClientStream.writable, toAgent.readable)
|
|
114
|
-
);
|
|
115
|
-
const connection = new acp.ClientSideConnection(
|
|
116
|
-
toClient,
|
|
117
|
-
acp.ndJsonStream(toAgent.writable, toClientStream.readable)
|
|
118
|
-
);
|
|
119
|
-
return {
|
|
120
|
-
agent,
|
|
121
|
-
client: new NovaAgentClient(connection),
|
|
122
|
-
async close() {
|
|
123
|
-
await agent.shutdown().catch(() => {
|
|
124
|
-
});
|
|
125
|
-
agentConnection.close();
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
1
|
// src/tui/settings/workspace-mcp.ts
|
|
131
2
|
import { readFileSync as readFileSync2 } from "fs";
|
|
132
3
|
import { join as join2 } from "path";
|
|
4
|
+
import { isWorkspaceTrusted } from "@datalabrotterdam/nova-ai-agent/core/nova-home.js";
|
|
5
|
+
import { readSettings } from "@datalabrotterdam/nova-ai-agent/core/policy/settings.js";
|
|
133
6
|
|
|
134
7
|
// src/tui/settings/workspace-settings.ts
|
|
135
8
|
import { readFileSync } from "fs";
|
|
@@ -270,93 +143,21 @@ function errorMessage(error, fallback) {
|
|
|
270
143
|
}
|
|
271
144
|
|
|
272
145
|
// src/tui/session/tui-acp-client.ts
|
|
146
|
+
import { NOVA_NOTIFICATIONS } from "@datalabrotterdam/nova-ai-agent/acp/extensions.js";
|
|
273
147
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
274
148
|
import { dirname } from "path";
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
windowsHide: true,
|
|
288
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
289
|
-
};
|
|
290
|
-
const child = options.args?.length ? spawn(command, options.args, common) : spawn(command, { ...common, shell: true });
|
|
291
|
-
liveChildren.add(child);
|
|
292
|
-
const forget = () => liveChildren.delete(child);
|
|
293
|
-
child.once("exit", forget);
|
|
294
|
-
child.once("error", forget);
|
|
295
|
-
return child;
|
|
296
|
-
}
|
|
297
|
-
function killProcessTree(child, signal = "SIGTERM") {
|
|
298
|
-
if (child.pid === void 0) return;
|
|
299
|
-
try {
|
|
300
|
-
if (process.platform === "win32") {
|
|
301
|
-
spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
302
|
-
stdio: "ignore",
|
|
303
|
-
windowsHide: true
|
|
304
|
-
}).on("error", () => {
|
|
305
|
-
});
|
|
306
|
-
} else {
|
|
307
|
-
process.kill(-child.pid, signal);
|
|
308
|
-
}
|
|
309
|
-
} catch {
|
|
310
|
-
try {
|
|
311
|
-
child.kill(signal);
|
|
312
|
-
} catch {
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
function terminateProcessTree(child, graceMs = KILL_GRACE_MS) {
|
|
317
|
-
if (hasExited(child)) return Promise.resolve();
|
|
318
|
-
return new Promise((resolve) => {
|
|
319
|
-
let forceTimer;
|
|
320
|
-
let giveUpTimer;
|
|
321
|
-
const done = () => {
|
|
322
|
-
clearTimeout(forceTimer);
|
|
323
|
-
clearTimeout(giveUpTimer);
|
|
324
|
-
resolve();
|
|
325
|
-
};
|
|
326
|
-
child.once("exit", done);
|
|
327
|
-
killProcessTree(child, "SIGTERM");
|
|
328
|
-
forceTimer = setTimeout(() => {
|
|
329
|
-
killProcessTree(child, "SIGKILL");
|
|
330
|
-
giveUpTimer = setTimeout(done, graceMs);
|
|
331
|
-
}, graceMs);
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
function hasExited(child) {
|
|
335
|
-
return child.exitCode !== null || child.signalCode !== null;
|
|
336
|
-
}
|
|
337
|
-
function installExitHook() {
|
|
338
|
-
if (exitHookInstalled) return;
|
|
339
|
-
exitHookInstalled = true;
|
|
340
|
-
process.once("exit", () => {
|
|
341
|
-
for (const child of liveChildren) {
|
|
342
|
-
if (process.platform === "win32" && child.pid !== void 0) {
|
|
343
|
-
try {
|
|
344
|
-
spawnSync("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
345
|
-
stdio: "ignore",
|
|
346
|
-
windowsHide: true,
|
|
347
|
-
timeout: 2e3
|
|
348
|
-
});
|
|
349
|
-
} catch {
|
|
350
|
-
}
|
|
351
|
-
} else {
|
|
352
|
-
killProcessTree(child, "SIGKILL");
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
liveChildren.clear();
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// src/tui/session/tui-acp-client.ts
|
|
149
|
+
import {
|
|
150
|
+
spawnCommand,
|
|
151
|
+
terminateProcessTree
|
|
152
|
+
} from "@datalabrotterdam/nova-ai-agent/core/process-tree.js";
|
|
153
|
+
import { resolveWorkspaceFile } from "@datalabrotterdam/nova-ai-agent/core/tools/workspace-paths.js";
|
|
154
|
+
import {
|
|
155
|
+
isInteractionMode
|
|
156
|
+
} from "@datalabrotterdam/nova-ai-agent/core/interaction-modes.js";
|
|
157
|
+
import {
|
|
158
|
+
fromElicitationRequest,
|
|
159
|
+
toElicitationResponse
|
|
160
|
+
} from "@datalabrotterdam/nova-ai-agent/acp/user-questions.js";
|
|
360
161
|
var DEFAULT_OUTPUT_LIMIT = 1e5;
|
|
361
162
|
var nextMessageId = 0;
|
|
362
163
|
function uid() {
|
|
@@ -945,7 +746,6 @@ function createStore(initial) {
|
|
|
945
746
|
}
|
|
946
747
|
|
|
947
748
|
export {
|
|
948
|
-
startInProcessAgent,
|
|
949
749
|
readWorkspaceMcpConfiguration,
|
|
950
750
|
workspaceNeedsTrust,
|
|
951
751
|
TuiAcpClient,
|
|
@@ -2,42 +2,18 @@ import {
|
|
|
2
2
|
TuiAcpClient,
|
|
3
3
|
choosePermissionOption,
|
|
4
4
|
createStore,
|
|
5
|
-
readWorkspaceMcpConfiguration
|
|
6
|
-
|
|
7
|
-
} from "./chunk-ZKRZIF3S.js";
|
|
8
|
-
import {
|
|
9
|
-
NOVA_NOTIFICATIONS,
|
|
10
|
-
NovaAgent,
|
|
11
|
-
listStoredSessions,
|
|
12
|
-
loadStoredSession
|
|
13
|
-
} from "./chunk-GZZ7PY3S.js";
|
|
14
|
-
import "./chunk-Q7WL3DXP.js";
|
|
15
|
-
import {
|
|
16
|
-
setWorkspaceTrusted
|
|
17
|
-
} from "./chunk-JAEXUFAS.js";
|
|
5
|
+
readWorkspaceMcpConfiguration
|
|
6
|
+
} from "./chunk-NHGIUEIR.js";
|
|
18
7
|
|
|
19
8
|
// src/headless/index.ts
|
|
20
9
|
import { resolve } from "path";
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
-
// src/client/context-client.ts
|
|
10
|
+
import { NOVA_NOTIFICATIONS } from "@datalabrotterdam/nova-ai-agent/acp/extensions.js";
|
|
24
11
|
import * as acp from "@agentclientprotocol/sdk";
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
readTextFile: (params) => request(acp.methods.client.fs.readTextFile, params),
|
|
31
|
-
writeTextFile: async (params) => await request(acp.methods.client.fs.writeTextFile, params) ?? {},
|
|
32
|
-
createTerminal: (params) => request(acp.methods.client.terminal.create, params),
|
|
33
|
-
terminalOutput: (params) => request(acp.methods.client.terminal.output, params),
|
|
34
|
-
waitForTerminalExit: (params) => request(acp.methods.client.terminal.waitForExit, params),
|
|
35
|
-
killTerminal: async (params) => await request(acp.methods.client.terminal.kill, params) ?? {},
|
|
36
|
-
releaseTerminal: async (params) => await request(acp.methods.client.terminal.release, params) ?? {},
|
|
37
|
-
unstable_createElicitation: (params) => request(acp.methods.client.elicitation.create, params),
|
|
38
|
-
extNotification: (method, params) => context.notify(method, params)
|
|
39
|
-
};
|
|
40
|
-
}
|
|
12
|
+
import { NovaAgent } from "@datalabrotterdam/nova-ai-agent/acp/agent.js";
|
|
13
|
+
import { clientFromContext } from "@datalabrotterdam/nova-ai-agent/client/context-client.js";
|
|
14
|
+
import { startInProcessAgent } from "@datalabrotterdam/nova-ai-agent/client/in-process.js";
|
|
15
|
+
import { setWorkspaceTrusted } from "@datalabrotterdam/nova-ai-agent/core/nova-home.js";
|
|
16
|
+
import { listStoredSessions, loadStoredSession } from "@datalabrotterdam/nova-ai-agent/core/sessions.js";
|
|
41
17
|
|
|
42
18
|
// src/headless/client.ts
|
|
43
19
|
var HeadlessAcpClient = class {
|
|
@@ -235,7 +211,7 @@ ${HEADLESS_HELP}
|
|
|
235
211
|
process.once("SIGINT", onInterrupt);
|
|
236
212
|
try {
|
|
237
213
|
await agent.initialize({
|
|
238
|
-
protocolVersion:
|
|
214
|
+
protocolVersion: acp.PROTOCOL_VERSION,
|
|
239
215
|
clientCapabilities: client.capabilities,
|
|
240
216
|
clientInfo: { name: "nova-ai-cli-headless", version: "1" }
|
|
241
217
|
});
|