@datalabrotterdam/nova-ai-cli 1.2.0-alpha.5 → 1.2.0-alpha.7
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 +27 -0
- package/README.md +29 -3
- package/dist/{chunk-NHGIUEIR.js → chunk-EOPM4RRE.js} +30 -150
- package/dist/{headless-OFJFVJ3O.js → headless-QLCJRT3X.js} +23 -16
- package/dist/index.js +4 -10
- package/dist/{tui-4XTC6VJP.js → tui-HJQOYGHL.js} +362 -212
- package/package.json +5 -3
- package/dist/webui-L4GGMXJ3.js +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
# [@datalabrotterdam/nova-ai-cli-v1.2.0-alpha.7](https://github.com/Datalab-Rotterdam/nova-ai-cli/compare/@datalabrotterdam/nova-ai-cli@1.2.0-alpha.6...@datalabrotterdam/nova-ai-cli@1.2.0-alpha.7) (2026-10-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **agent:** Claude Code compatible hooks ([227fe8b](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/227fe8b273ec2e211e9d57674e76af5c42a473bd))
|
|
7
|
+
* **agent:** install the shared Nova skills ([64139dd](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/64139dd612933343f04f165de1a9ab78832d6864))
|
|
8
|
+
* **agent:** mark and protect bundled skills ([6ef52eb](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/6ef52eb6d048f8a3b4e75686244aabcfd0f62d6e))
|
|
9
|
+
* **agent:** thinking effort for reasoning models ([8551fea](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/8551feacff3e1675f369030e20fb2b5071f0db7f))
|
|
10
|
+
* **agent:** web_search tool ([12985eb](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/12985eb9ca06d6c814d4e0162465c651889d9370))
|
|
11
|
+
* **cli:** /effort slider for thinking models ([8ca67f2](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/8ca67f2f5dcc8f6bff8c36409a2baba5d43c4a02))
|
|
12
|
+
* **cli:** remember the thinking level ([883196c](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/883196c9fdb089f4f26ac82b557cc87dfc0b1c0b))
|
|
13
|
+
* OAuth sign-in for MCP servers ([ba57c79](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/ba57c79642f902ab2bc20f59e4627fb2b774bb4a))
|
|
14
|
+
* the user's agent files as session modes ([3386de8](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/3386de88d07b0351bd1e44960fcacfef26e3d45b))
|
|
15
|
+
|
|
16
|
+
# [@datalabrotterdam/nova-ai-cli-v1.2.0-alpha.6](https://github.com/Datalab-Rotterdam/nova-ai-cli/compare/@datalabrotterdam/nova-ai-cli@1.2.0-alpha.5...@datalabrotterdam/nova-ai-cli@1.2.0-alpha.6) (2026-10-23)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* **cli:** start the session before the first prompt ([0c26456](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/0c26456b8126e3b42a6de2e38212213ae5380e62))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* **agent:** set workspace trust over ACP ([cec4a89](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/cec4a8949a4232f46448219e4d5363289651215d))
|
|
27
|
+
|
|
1
28
|
# [@datalabrotterdam/nova-ai-cli-v1.2.0-alpha.5](https://github.com/Datalab-Rotterdam/nova-ai-cli/compare/@datalabrotterdam/nova-ai-cli@1.2.0-alpha.4...@datalabrotterdam/nova-ai-cli@1.2.0-alpha.5) (2026-10-23)
|
|
2
29
|
|
|
3
30
|
|
package/README.md
CHANGED
|
@@ -79,6 +79,8 @@ row. To select text, hold Shift (Option in some macOS terminals) while dragging.
|
|
|
79
79
|
|
|
80
80
|
- **Modes** (Shift+Tab): `agent` does the work; `plan` reads the code, asks
|
|
81
81
|
questions and builds a task list but changes nothing; `ask` only answers.
|
|
82
|
+
Your own agents (`~/.nova-ai/agents/<name>.agent.md`, the format the VS Code
|
|
83
|
+
extension uses) are extra modes after these; `/mode` lists them.
|
|
82
84
|
- **Permissions**: before an edit or command you choose once, for this
|
|
83
85
|
session, always (saved as an exact rule) or deny. Ctrl+K switches between
|
|
84
86
|
asking, accepting edits, and bypass (never remembered).
|
|
@@ -95,12 +97,12 @@ row. To select text, hold Shift (Option in some macOS terminals) while dragging.
|
|
|
95
97
|
| Enter / Shift+Enter | Send / new line (Shift+Enter where the terminal supports the kitty keyboard protocol: VS Code, kitty, WezTerm, Ghostty, foot, Alacritty, recent iTerm2; Alt+Enter, Ctrl+J or a trailing `\` work everywhere) |
|
|
96
98
|
| Esc | Cancel the running turn |
|
|
97
99
|
| Ctrl+C twice | Exit; prints `nova-ai --resume <id>` |
|
|
98
|
-
| Shift+Tab | Cycle agent / ask / plan |
|
|
100
|
+
| Shift+Tab | Cycle agent / ask / plan and your own agents |
|
|
99
101
|
| Ctrl+R / Ctrl+P / Ctrl+K | Sessions / models / permission mode |
|
|
100
102
|
| Ctrl+O / Ctrl+T / Ctrl+B | Verbose tool output / tool inspector / background jobs |
|
|
101
103
|
| Alt+V | Paste a clipboard image |
|
|
102
104
|
|
|
103
|
-
Slash commands: `/help`, `/model`, `/mode`, `/permission`, `/session`,
|
|
105
|
+
Slash commands: `/help`, `/model`, `/effort` (thinking models), `/mode`, `/permission`, `/session`,
|
|
104
106
|
`/resume`, `/clear`, `/compact`, `/rewind [n]`, `/queue`, `/steer`, `/usage`,
|
|
105
107
|
`/tools`, `/mcp`, `/skills`, `/shell` and `/agent` (background jobs), `/trust`
|
|
106
108
|
and `/exit`. Details:
|
|
@@ -169,7 +171,10 @@ need ACP. Everything is documented in
|
|
|
169
171
|
and nested shells need an exact rule.
|
|
170
172
|
- **Web pages are fetched only with approval.** `fetch_url` asks every time
|
|
171
173
|
unless a rule allows that URL (a URL can carry data out), and a redirect to
|
|
172
|
-
another site needs its own approval.
|
|
174
|
+
another site needs its own approval. `web_search` asks the same way, since
|
|
175
|
+
the query goes to the search providers (You.com, DuckDuckGo; your own
|
|
176
|
+
SearXNG server first when `~/.nova-ai/settings.json` has
|
|
177
|
+
`"webSearch": { "searxngUrl": "https://…" }`).
|
|
173
178
|
- **File access stays in the workspace** (symlinks resolved); commands run in
|
|
174
179
|
their own process group with a timeout, and the whole tree is stopped on
|
|
175
180
|
cancel.
|
|
@@ -194,7 +199,22 @@ VS Code extension: settings, per-project trust, sessions and memory.
|
|
|
194
199
|
skills folders are read too). `/skills` lists them; `/skills off <name>`
|
|
195
200
|
switches one off in this project (`--global`: everywhere). Only names and
|
|
196
201
|
short descriptions go into the prompt; Nova loads a skill when it fits.
|
|
202
|
+
Nova installs its own skills for Word, Excel, PowerPoint and PDF files
|
|
203
|
+
(`nova-docx`, `nova-xlsx`, `nova-pptx`, `nova-pdf`, from
|
|
204
|
+
[nova-ai-skills](https://github.com/Datalab-Rotterdam/nova-ai-skills)) in
|
|
205
|
+
`~/.nova-ai/skills` and keeps them up to date; they need Python 3.
|
|
206
|
+
- **Hooks**: Claude Code's `hooks` format in the same settings files (a
|
|
207
|
+
repository's own only once you trust the workspace): `PreToolUse`,
|
|
208
|
+
`PostToolUse`, `UserPromptSubmit`, `SessionStart` and `Stop`, with Claude
|
|
209
|
+
Code's tool names as matchers, so hooks from `.claude/settings.json` work
|
|
210
|
+
when copied over.
|
|
197
211
|
- **MCP servers**: `.mcp.json` or `mcpServers` in `.nova-ai/settings.json`.
|
|
212
|
+
HTTP servers that use OAuth show "needs sign-in" in `/mcp`; `/mcp login
|
|
213
|
+
<server>` opens the sign-in page in your browser (tokens are kept in
|
|
214
|
+
`~/.nova-ai/mcp-auth`, refreshed automatically), `/mcp logout <server>`
|
|
215
|
+
forgets them. A server that wants a client registered by hand takes
|
|
216
|
+
`"oauth": { "clientId", "clientSecret", "scope", "callbackPort" }` in
|
|
217
|
+
`.mcp.json`.
|
|
198
218
|
|
|
199
219
|
The complete layout and rule syntax: [docs/NOVA_HOME.md](https://github.com/Datalab-Rotterdam/nova-ai-cli/blob/main/docs/NOVA_HOME.md).
|
|
200
220
|
|
|
@@ -207,6 +227,12 @@ to a text protocol for models that don't support it. When the context window
|
|
|
207
227
|
fills up, older messages are summarized automatically (`/compact` does it by
|
|
208
228
|
hand).
|
|
209
229
|
|
|
230
|
+
Thinking models are marked ◆ in the model list. For those with levels the
|
|
231
|
+
status line shows the current one (`· thinking medium`) and `/effort` opens a
|
|
232
|
+
slider (←/→, Enter), or sets one directly (`/effort high`, `/effort off`). The
|
|
233
|
+
choice is remembered like the model; a model without that level uses its own
|
|
234
|
+
default.
|
|
235
|
+
|
|
210
236
|
| Environment | |
|
|
211
237
|
|---|---|
|
|
212
238
|
| `NOVA_API_KEY`, `NOVA_MODEL` | Use this key / model instead of the stored ones |
|
|
@@ -1,149 +1,6 @@
|
|
|
1
|
-
// src/tui/settings/workspace-mcp.ts
|
|
2
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
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";
|
|
6
|
-
|
|
7
|
-
// src/tui/settings/workspace-settings.ts
|
|
8
|
-
import { readFileSync } from "fs";
|
|
9
|
-
import { join } from "path";
|
|
10
|
-
function settingsPath(cwd) {
|
|
11
|
-
return join(cwd, ".nova-ai", "settings.json");
|
|
12
|
-
}
|
|
13
|
-
function readWorkspaceSettings(cwd) {
|
|
14
|
-
try {
|
|
15
|
-
const raw = readFileSync(settingsPath(cwd), "utf8");
|
|
16
|
-
return JSON.parse(raw);
|
|
17
|
-
} catch {
|
|
18
|
-
return {};
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// src/tui/settings/workspace-mcp.ts
|
|
23
|
-
var UNTRUSTED_MCP_MESSAGE = "Not started: MCP servers declared by this workspace only run once you trust it (/trust in the TUI, --trust-workspace headless).";
|
|
24
|
-
function readWorkspaceMcpConfiguration(cwd, options = {}) {
|
|
25
|
-
const configured = readWorkspaceSettings(cwd).mcpServers ?? [];
|
|
26
|
-
const project = readProjectMcpConfiguration(cwd);
|
|
27
|
-
const servers = new Map(configured.map((server) => [server.name, server]));
|
|
28
|
-
for (const server of project.servers) servers.set(server.name, server);
|
|
29
|
-
const declared = [...servers.values()];
|
|
30
|
-
if (declared.length && !(options.trusted ?? isWorkspaceTrusted(cwd))) {
|
|
31
|
-
return {
|
|
32
|
-
servers: [],
|
|
33
|
-
failures: [
|
|
34
|
-
...project.failures,
|
|
35
|
-
...declared.map((server) => ({ serverName: server.name, message: UNTRUSTED_MCP_MESSAGE }))
|
|
36
|
-
],
|
|
37
|
-
untrusted: declared.map((server) => server.name)
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
return { servers: declared, failures: project.failures };
|
|
41
|
-
}
|
|
42
|
-
function workspaceNeedsTrust(cwd) {
|
|
43
|
-
if (isWorkspaceTrusted(cwd)) return false;
|
|
44
|
-
if (readWorkspaceMcpConfiguration(cwd, { trusted: true }).servers.length) return true;
|
|
45
|
-
return loadWorkspaceAllowRules(cwd).length > 0;
|
|
46
|
-
}
|
|
47
|
-
function loadWorkspaceAllowRules(cwd) {
|
|
48
|
-
return ["settings.json", "settings.local.json"].flatMap((name) => {
|
|
49
|
-
const allow = readSettings(join2(cwd, ".nova-ai", name))?.permissions?.allow;
|
|
50
|
-
return Array.isArray(allow) ? allow : [];
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
function readProjectMcpConfiguration(cwd) {
|
|
54
|
-
const path = join2(cwd, ".mcp.json");
|
|
55
|
-
let raw;
|
|
56
|
-
try {
|
|
57
|
-
raw = readFileSync2(path, "utf8");
|
|
58
|
-
} catch (error) {
|
|
59
|
-
if (error.code === "ENOENT") return { servers: [], failures: [] };
|
|
60
|
-
return { servers: [], failures: [{ serverName: ".mcp.json", message: errorMessage(error, "Could not read file") }] };
|
|
61
|
-
}
|
|
62
|
-
let document;
|
|
63
|
-
try {
|
|
64
|
-
document = JSON.parse(raw);
|
|
65
|
-
} catch (error) {
|
|
66
|
-
return { servers: [], failures: [{ serverName: ".mcp.json", message: errorMessage(error, "Invalid JSON") }] };
|
|
67
|
-
}
|
|
68
|
-
const root = asRecord(document);
|
|
69
|
-
const definitions = root ? asRecord(root.mcpServers) : null;
|
|
70
|
-
if (!definitions) {
|
|
71
|
-
return {
|
|
72
|
-
servers: [],
|
|
73
|
-
failures: [{ serverName: ".mcp.json", message: 'Expected an "mcpServers" object.' }]
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
const servers = [];
|
|
77
|
-
const failures = [];
|
|
78
|
-
for (const [name, value] of Object.entries(definitions)) {
|
|
79
|
-
const config = asRecord(value);
|
|
80
|
-
if (config?.disabled === true || config?.enabled === false) continue;
|
|
81
|
-
try {
|
|
82
|
-
servers.push(normalizeProjectServer(name, config));
|
|
83
|
-
} catch (error) {
|
|
84
|
-
failures.push({ serverName: `.mcp.json:${name}`, message: errorMessage(error, "Invalid server configuration") });
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return { servers, failures };
|
|
88
|
-
}
|
|
89
|
-
function normalizeProjectServer(name, config) {
|
|
90
|
-
if (!config) throw new Error("Server definition must be an object.");
|
|
91
|
-
const type = typeof config.type === "string" ? config.type : config.url ? "http" : "stdio";
|
|
92
|
-
if (type === "http" || type === "sse") {
|
|
93
|
-
if (typeof config.url !== "string" || !config.url) throw new Error(`${type} server requires a URL.`);
|
|
94
|
-
try {
|
|
95
|
-
new URL(config.url);
|
|
96
|
-
} catch {
|
|
97
|
-
throw new Error(`${type} server requires a valid URL.`);
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
name,
|
|
101
|
-
type,
|
|
102
|
-
url: config.url,
|
|
103
|
-
headers: normalizePairs(config.headers, "headers")
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
if (type !== "stdio") throw new Error(`Unsupported transport type: ${type}.`);
|
|
107
|
-
if (typeof config.command !== "string" || !config.command) throw new Error("stdio server requires a command.");
|
|
108
|
-
if (config.args !== void 0 && (!Array.isArray(config.args) || !config.args.every((arg) => typeof arg === "string"))) {
|
|
109
|
-
throw new Error("args must be an array of strings.");
|
|
110
|
-
}
|
|
111
|
-
return {
|
|
112
|
-
name,
|
|
113
|
-
command: config.command,
|
|
114
|
-
args: config.args ?? [],
|
|
115
|
-
env: normalizePairs(config.env, "env")
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
function normalizePairs(value, label) {
|
|
119
|
-
if (value === void 0) return [];
|
|
120
|
-
if (Array.isArray(value)) {
|
|
121
|
-
if (!value.every((entry) => {
|
|
122
|
-
const pair = asRecord(entry);
|
|
123
|
-
return typeof pair?.name === "string" && typeof pair.value === "string";
|
|
124
|
-
})) {
|
|
125
|
-
throw new Error(`${label} must contain name/value strings.`);
|
|
126
|
-
}
|
|
127
|
-
return value.map((entry) => {
|
|
128
|
-
const pair = entry;
|
|
129
|
-
return { name: pair.name, value: pair.value };
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
const record = asRecord(value);
|
|
133
|
-
if (!record || !Object.values(record).every((entry) => typeof entry === "string")) {
|
|
134
|
-
throw new Error(`${label} must be an object of string values.`);
|
|
135
|
-
}
|
|
136
|
-
return Object.entries(record).map(([name, entry]) => ({ name, value: entry }));
|
|
137
|
-
}
|
|
138
|
-
function asRecord(value) {
|
|
139
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
140
|
-
}
|
|
141
|
-
function errorMessage(error, fallback) {
|
|
142
|
-
return error instanceof Error && error.message ? `${fallback}: ${error.message}` : fallback;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
1
|
// src/tui/session/tui-acp-client.ts
|
|
146
2
|
import { NOVA_NOTIFICATIONS } from "@datalabrotterdam/nova-ai-agent/acp/extensions.js";
|
|
3
|
+
import { openBrowser } from "@datalabrotterdam/nova-ai-agent/acp/auth-server.js";
|
|
147
4
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
148
5
|
import { dirname } from "path";
|
|
149
6
|
import {
|
|
@@ -151,13 +8,11 @@ import {
|
|
|
151
8
|
terminateProcessTree
|
|
152
9
|
} from "@datalabrotterdam/nova-ai-agent/core/process-tree.js";
|
|
153
10
|
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
11
|
import {
|
|
158
12
|
fromElicitationRequest,
|
|
159
13
|
toElicitationResponse
|
|
160
14
|
} from "@datalabrotterdam/nova-ai-agent/acp/user-questions.js";
|
|
15
|
+
import { INTERACTION_MODES } from "@datalabrotterdam/nova-ai-agent/core/interaction-modes.js";
|
|
161
16
|
var DEFAULT_OUTPUT_LIMIT = 1e5;
|
|
162
17
|
var nextMessageId = 0;
|
|
163
18
|
function uid() {
|
|
@@ -175,6 +30,8 @@ var TuiAcpClient = class {
|
|
|
175
30
|
cwd;
|
|
176
31
|
onBackgroundLifecycle;
|
|
177
32
|
onInteractionModeChange;
|
|
33
|
+
/** The modes the agent offers (built-in, then the user's agent files); set by the runner. */
|
|
34
|
+
modeIds = [...INTERACTION_MODES];
|
|
178
35
|
capabilities = {
|
|
179
36
|
fs: { readTextFile: true, writeTextFile: true },
|
|
180
37
|
terminal: true,
|
|
@@ -235,6 +92,29 @@ var TuiAcpClient = class {
|
|
|
235
92
|
appendUserMessage(text) {
|
|
236
93
|
this.appendMessage({ id: uid(), role: "user", text });
|
|
237
94
|
}
|
|
95
|
+
/** An MCP server's sign-in page: opened in the browser, and printed in case that fails. */
|
|
96
|
+
mcpAuthUrl(params) {
|
|
97
|
+
const { serverName, url } = params ?? {};
|
|
98
|
+
if (typeof serverName !== "string" || typeof url !== "string") return;
|
|
99
|
+
let page;
|
|
100
|
+
try {
|
|
101
|
+
page = new URL(url);
|
|
102
|
+
} catch {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (page.protocol !== "https:" && page.protocol !== "http:") {
|
|
106
|
+
this.appendError(`MCP server "${serverName}" sent a sign-in address that is not a web page; not opened.`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
openBrowser(page.toString());
|
|
110
|
+
this.appendMessage({
|
|
111
|
+
id: uid(),
|
|
112
|
+
role: "assistant",
|
|
113
|
+
streaming: false,
|
|
114
|
+
text: `Sign in to MCP server "${serverName}" in your browser. If it did not open, visit:
|
|
115
|
+
${page}`
|
|
116
|
+
});
|
|
117
|
+
}
|
|
238
118
|
appendError(text) {
|
|
239
119
|
this.appendMessage({ id: uid(), role: "error", text });
|
|
240
120
|
}
|
|
@@ -439,7 +319,7 @@ ${err.message}`;
|
|
|
439
319
|
}
|
|
440
320
|
return;
|
|
441
321
|
case "current_mode_update":
|
|
442
|
-
if (
|
|
322
|
+
if (this.modeIds.includes(update.currentModeId)) {
|
|
443
323
|
this.onInteractionModeChange?.(update.currentModeId);
|
|
444
324
|
}
|
|
445
325
|
return;
|
|
@@ -559,6 +439,8 @@ ${err.message}`;
|
|
|
559
439
|
return this.backgroundUpdate(params);
|
|
560
440
|
case NOVA_NOTIFICATIONS.queueChanged:
|
|
561
441
|
return this.queueChanged(params);
|
|
442
|
+
case NOVA_NOTIFICATIONS.mcpAuthUrl:
|
|
443
|
+
return this.mcpAuthUrl(params);
|
|
562
444
|
default:
|
|
563
445
|
return;
|
|
564
446
|
}
|
|
@@ -746,8 +628,6 @@ function createStore(initial) {
|
|
|
746
628
|
}
|
|
747
629
|
|
|
748
630
|
export {
|
|
749
|
-
readWorkspaceMcpConfiguration,
|
|
750
|
-
workspaceNeedsTrust,
|
|
751
631
|
TuiAcpClient,
|
|
752
632
|
choosePermissionOption,
|
|
753
633
|
createStore
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TuiAcpClient,
|
|
3
3
|
choosePermissionOption,
|
|
4
|
-
createStore
|
|
5
|
-
|
|
6
|
-
} from "./chunk-NHGIUEIR.js";
|
|
4
|
+
createStore
|
|
5
|
+
} from "./chunk-EOPM4RRE.js";
|
|
7
6
|
|
|
8
7
|
// src/headless/index.ts
|
|
9
8
|
import { resolve } from "path";
|
|
@@ -12,7 +11,6 @@ import * as acp from "@agentclientprotocol/sdk";
|
|
|
12
11
|
import { NovaAgent } from "@datalabrotterdam/nova-ai-agent/acp/agent.js";
|
|
13
12
|
import { clientFromContext } from "@datalabrotterdam/nova-ai-agent/client/context-client.js";
|
|
14
13
|
import { startInProcessAgent } from "@datalabrotterdam/nova-ai-agent/client/in-process.js";
|
|
15
|
-
import { setWorkspaceTrusted } from "@datalabrotterdam/nova-ai-agent/core/nova-home.js";
|
|
16
14
|
import { listStoredSessions, loadStoredSession } from "@datalabrotterdam/nova-ai-agent/core/sessions.js";
|
|
17
15
|
|
|
18
16
|
// src/headless/client.ts
|
|
@@ -191,15 +189,19 @@ ${HEADLESS_HELP}
|
|
|
191
189
|
dependencies.agent ?? new NovaAgent()
|
|
192
190
|
);
|
|
193
191
|
const agent = connection.client;
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
serverName
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
192
|
+
const sessionMeta = { "nova-ai-cli/workspaceMcp": options.mcp };
|
|
193
|
+
const reportMcpFailures = (meta) => {
|
|
194
|
+
const failures = toRecord(toRecord(meta)?.["nova-ai-cli/mcp"])?.failures;
|
|
195
|
+
for (const failure of Array.isArray(failures) ? failures : []) {
|
|
196
|
+
const item = toRecord(failure);
|
|
197
|
+
if (typeof item?.serverName !== "string" || typeof item.message !== "string") continue;
|
|
198
|
+
output.write({
|
|
199
|
+
type: "mcp.configuration_error",
|
|
200
|
+
serverName: item.serverName,
|
|
201
|
+
message: item.message
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
};
|
|
203
205
|
let sessionId = null;
|
|
204
206
|
let interrupted = false;
|
|
205
207
|
const onInterrupt = () => {
|
|
@@ -215,18 +217,23 @@ ${HEADLESS_HELP}
|
|
|
215
217
|
clientCapabilities: client.capabilities,
|
|
216
218
|
clientInfo: { name: "nova-ai-cli-headless", version: "1" }
|
|
217
219
|
});
|
|
220
|
+
if (options.trustWorkspace) await agent.workspaceTrust({ cwd: options.cwd, trusted: true });
|
|
218
221
|
if (options.resume) {
|
|
219
|
-
await agent.resumeSession({
|
|
222
|
+
const resumed = await agent.resumeSession({
|
|
220
223
|
sessionId: options.resume,
|
|
221
224
|
cwd: options.cwd,
|
|
222
|
-
mcpServers:
|
|
225
|
+
mcpServers: [],
|
|
226
|
+
_meta: sessionMeta
|
|
223
227
|
});
|
|
228
|
+
reportMcpFailures(resumed._meta);
|
|
224
229
|
sessionId = options.resume;
|
|
225
230
|
} else {
|
|
226
231
|
const created = await agent.newSession({
|
|
227
232
|
cwd: options.cwd,
|
|
228
|
-
mcpServers:
|
|
233
|
+
mcpServers: [],
|
|
234
|
+
_meta: sessionMeta
|
|
229
235
|
});
|
|
236
|
+
reportMcpFailures(created._meta);
|
|
230
237
|
sessionId = created.sessionId;
|
|
231
238
|
}
|
|
232
239
|
await agent.setSessionConfigOption({
|
package/dist/index.js
CHANGED
|
@@ -17,8 +17,7 @@ var MODE_FLAGS = {
|
|
|
17
17
|
"--headless": "print",
|
|
18
18
|
"--setup": "login",
|
|
19
19
|
"--version": "version",
|
|
20
|
-
"-v": "version"
|
|
21
|
-
"--web": "web"
|
|
20
|
+
"-v": "version"
|
|
22
21
|
};
|
|
23
22
|
function parseCli(argv) {
|
|
24
23
|
const first = argv[0];
|
|
@@ -34,7 +33,7 @@ function parseCli(argv) {
|
|
|
34
33
|
const mode = [...modes][0];
|
|
35
34
|
const wantsHelp = options.includes("--help") || options.includes("-h");
|
|
36
35
|
if (!mode) return wantsHelp ? { mode: "help", args: [] } : { mode: "tui", args: argv };
|
|
37
|
-
const drop = /* @__PURE__ */ new Set(["--acp", "--headless", "--setup", "--version", "-v"
|
|
36
|
+
const drop = /* @__PURE__ */ new Set(["--acp", "--headless", "--setup", "--version", "-v"]);
|
|
38
37
|
return { mode, args: argv.filter((arg, index) => !(drop.has(arg) && (end < 0 || index < end))) };
|
|
39
38
|
}
|
|
40
39
|
function versionText() {
|
|
@@ -140,7 +139,7 @@ ${MAIN_HELP}
|
|
|
140
139
|
}
|
|
141
140
|
case "print": {
|
|
142
141
|
const update = startUpdateCheck();
|
|
143
|
-
const { default: runHeadless } = await import("./headless-
|
|
142
|
+
const { default: runHeadless } = await import("./headless-QLCJRT3X.js");
|
|
144
143
|
const code = await runHeadless(command.args);
|
|
145
144
|
if (update) await noticeUpdate(update, 500);
|
|
146
145
|
return code;
|
|
@@ -153,11 +152,6 @@ ${MAIN_HELP}
|
|
|
153
152
|
const { runLogout } = await import("@datalabrotterdam/nova-ai-agent/commands/login.js");
|
|
154
153
|
return runLogout();
|
|
155
154
|
}
|
|
156
|
-
case "web": {
|
|
157
|
-
const { default: runWebUi } = await import("./webui-L4GGMXJ3.js");
|
|
158
|
-
await runWebUi();
|
|
159
|
-
return 0;
|
|
160
|
-
}
|
|
161
155
|
case "tui": {
|
|
162
156
|
let options;
|
|
163
157
|
try {
|
|
@@ -175,7 +169,7 @@ ${MAIN_HELP}
|
|
|
175
169
|
);
|
|
176
170
|
return 2;
|
|
177
171
|
}
|
|
178
|
-
const { default: runChat } = await import("./tui-
|
|
172
|
+
const { default: runChat } = await import("./tui-HJQOYGHL.js");
|
|
179
173
|
return runChat(options);
|
|
180
174
|
}
|
|
181
175
|
}
|