@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/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
} from "./chunk-
|
|
3
|
+
cliVersion
|
|
4
|
+
} from "./chunk-FMHWW3E6.js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
7
|
var SUBCOMMANDS = {
|
|
@@ -38,7 +38,7 @@ function parseCli(argv) {
|
|
|
38
38
|
return { mode, args: argv.filter((arg, index) => !(drop.has(arg) && (end < 0 || index < end))) };
|
|
39
39
|
}
|
|
40
40
|
function versionText() {
|
|
41
|
-
return `nova-ai ${
|
|
41
|
+
return `nova-ai ${cliVersion() ?? "unknown"}`;
|
|
42
42
|
}
|
|
43
43
|
var MAIN_HELP = `Nova AI \u2014 agentic coding in your terminal, and an ACP agent for editors.
|
|
44
44
|
|
|
@@ -86,6 +86,28 @@ function parseTuiArgs(args) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// src/index.ts
|
|
89
|
+
function startUpdateCheck() {
|
|
90
|
+
if (!process.stderr.isTTY) return null;
|
|
91
|
+
const abort = new AbortController();
|
|
92
|
+
const result = import("./update-check-OX6WAPNN.js").then(({ checkForUpdate }) => checkForUpdate({ signal: abort.signal })).catch(() => null);
|
|
93
|
+
return { result, cancel: () => abort.abort() };
|
|
94
|
+
}
|
|
95
|
+
async function noticeUpdate(check, waitMs) {
|
|
96
|
+
let timer;
|
|
97
|
+
const update = await Promise.race([
|
|
98
|
+
check.result,
|
|
99
|
+
new Promise((resolve) => {
|
|
100
|
+
timer = setTimeout(() => resolve(null), waitMs);
|
|
101
|
+
})
|
|
102
|
+
]);
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
check.cancel();
|
|
105
|
+
if (!update) return;
|
|
106
|
+
const { formatUpdateNotice } = await import("./update-check-OX6WAPNN.js");
|
|
107
|
+
process.stderr.write(`
|
|
108
|
+
${formatUpdateNotice(update)}
|
|
109
|
+
`);
|
|
110
|
+
}
|
|
89
111
|
async function main() {
|
|
90
112
|
const command = parseCli(process.argv.slice(2));
|
|
91
113
|
switch (command.mode) {
|
|
@@ -99,30 +121,36 @@ ${MAIN_HELP}
|
|
|
99
121
|
process.stdout.write(`${MAIN_HELP}
|
|
100
122
|
`);
|
|
101
123
|
return 0;
|
|
102
|
-
case "version":
|
|
124
|
+
case "version": {
|
|
125
|
+
const update = startUpdateCheck();
|
|
103
126
|
process.stdout.write(`${versionText()}
|
|
104
127
|
`);
|
|
128
|
+
if (update) await noticeUpdate(update, 800);
|
|
105
129
|
return 0;
|
|
130
|
+
}
|
|
106
131
|
case "acp": {
|
|
107
132
|
if (command.args.length) {
|
|
108
133
|
process.stderr.write(`--acp takes no other arguments (got ${command.args.join(" ")}).
|
|
109
134
|
`);
|
|
110
135
|
return 2;
|
|
111
136
|
}
|
|
112
|
-
const { default: runAcp } = await import("
|
|
137
|
+
const { default: runAcp } = await import("@datalabrotterdam/nova-ai-agent/acp/index.js");
|
|
113
138
|
await runAcp();
|
|
114
139
|
return 0;
|
|
115
140
|
}
|
|
116
141
|
case "print": {
|
|
117
|
-
const
|
|
118
|
-
|
|
142
|
+
const update = startUpdateCheck();
|
|
143
|
+
const { default: runHeadless } = await import("./headless-OFJFVJ3O.js");
|
|
144
|
+
const code = await runHeadless(command.args);
|
|
145
|
+
if (update) await noticeUpdate(update, 500);
|
|
146
|
+
return code;
|
|
119
147
|
}
|
|
120
148
|
case "login": {
|
|
121
|
-
const { runLogin } = await import("
|
|
149
|
+
const { runLogin } = await import("@datalabrotterdam/nova-ai-agent/commands/login.js");
|
|
122
150
|
return runLogin(command.args);
|
|
123
151
|
}
|
|
124
152
|
case "logout": {
|
|
125
|
-
const { runLogout } = await import("
|
|
153
|
+
const { runLogout } = await import("@datalabrotterdam/nova-ai-agent/commands/login.js");
|
|
126
154
|
return runLogout();
|
|
127
155
|
}
|
|
128
156
|
case "web": {
|
|
@@ -147,7 +175,7 @@ ${MAIN_HELP}
|
|
|
147
175
|
);
|
|
148
176
|
return 2;
|
|
149
177
|
}
|
|
150
|
-
const { default: runChat } = await import("./tui-
|
|
178
|
+
const { default: runChat } = await import("./tui-LNFSHL4Y.js");
|
|
151
179
|
return runChat(options);
|
|
152
180
|
}
|
|
153
181
|
}
|
|
@@ -1,48 +1,48 @@
|
|
|
1
|
+
import {
|
|
2
|
+
checkForUpdate
|
|
3
|
+
} from "./chunk-37PMUZ34.js";
|
|
4
|
+
import "./chunk-FMHWW3E6.js";
|
|
1
5
|
import {
|
|
2
6
|
TuiAcpClient,
|
|
3
7
|
createStore,
|
|
4
8
|
readWorkspaceMcpConfiguration,
|
|
5
|
-
startInProcessAgent,
|
|
6
9
|
workspaceNeedsTrust
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import {
|
|
9
|
-
INTERACTION_MODES,
|
|
10
|
-
NovaAgent,
|
|
11
|
-
OTHER_OPTION_ID,
|
|
12
|
-
discoverSkills,
|
|
13
|
-
isInteractionMode,
|
|
14
|
-
listStoredSessions,
|
|
15
|
-
loadStoredSession,
|
|
16
|
-
replayHistory,
|
|
17
|
-
resolveModelContextWindow,
|
|
18
|
-
savePermissionMode,
|
|
19
|
-
savedPermissionMode
|
|
20
|
-
} from "./chunk-GZZ7PY3S.js";
|
|
21
|
-
import {
|
|
22
|
-
readPackageVersion
|
|
23
|
-
} from "./chunk-Q7WL3DXP.js";
|
|
24
|
-
import {
|
|
25
|
-
chatModels,
|
|
26
|
-
createNovaClient,
|
|
27
|
-
readCredentials,
|
|
28
|
-
resolveDefaultModel,
|
|
29
|
-
resolveModelSupportsImageInput,
|
|
30
|
-
saveDefaultModel,
|
|
31
|
-
setWorkspaceTrusted
|
|
32
|
-
} from "./chunk-JAEXUFAS.js";
|
|
10
|
+
} from "./chunk-NHGIUEIR.js";
|
|
33
11
|
|
|
34
12
|
// src/tui/index.ts
|
|
35
13
|
import { createInterface } from "readline/promises";
|
|
14
|
+
import { readCredentials } from "@datalabrotterdam/nova-ai-agent/core/credentials.js";
|
|
15
|
+
import { listStoredSessions as listStoredSessions2 } from "@datalabrotterdam/nova-ai-agent/core/sessions.js";
|
|
16
|
+
import { setWorkspaceTrusted as setWorkspaceTrusted2 } from "@datalabrotterdam/nova-ai-agent/core/nova-home.js";
|
|
36
17
|
|
|
37
18
|
// src/tui/ink/app.tsx
|
|
38
19
|
import { Box as Box6, render, Static, Text as Text6, useBoxMetrics, useWindowSize } from "ink";
|
|
39
20
|
import { useEffect, useRef, useState as useState2, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
21
|
+
import { savedPermissionMode } from "@datalabrotterdam/nova-ai-agent/core/policy/settings.js";
|
|
40
22
|
|
|
41
23
|
// src/tui/session/session-runner.ts
|
|
42
24
|
import * as acp from "@agentclientprotocol/sdk";
|
|
43
25
|
import {
|
|
44
26
|
NovaAIError
|
|
45
27
|
} from "@datalabrotterdam/nova-sdk";
|
|
28
|
+
import { createNovaClient } from "@datalabrotterdam/nova-ai-agent/core/nova-client.js";
|
|
29
|
+
import { NovaAgent } from "@datalabrotterdam/nova-ai-agent/acp/agent.js";
|
|
30
|
+
import { startInProcessAgent } from "@datalabrotterdam/nova-ai-agent/client/in-process.js";
|
|
31
|
+
import { replayHistory } from "@datalabrotterdam/nova-ai-agent/core/history.js";
|
|
32
|
+
import { saveDefaultModel } from "@datalabrotterdam/nova-ai-agent/core/credentials.js";
|
|
33
|
+
import {
|
|
34
|
+
savePermissionMode
|
|
35
|
+
} from "@datalabrotterdam/nova-ai-agent/core/policy/settings.js";
|
|
36
|
+
import { loadStoredSession } from "@datalabrotterdam/nova-ai-agent/core/sessions.js";
|
|
37
|
+
import { discoverSkills } from "@datalabrotterdam/nova-ai-agent/core/skills.js";
|
|
38
|
+
import {
|
|
39
|
+
resolveModelContextWindow
|
|
40
|
+
} from "@datalabrotterdam/nova-ai-agent/core/context-compaction.js";
|
|
41
|
+
import {
|
|
42
|
+
chatModels,
|
|
43
|
+
resolveDefaultModel,
|
|
44
|
+
resolveModelSupportsImageInput
|
|
45
|
+
} from "@datalabrotterdam/nova-ai-agent/core/model-capabilities.js";
|
|
46
46
|
|
|
47
47
|
// src/tui/files/file-mentions.ts
|
|
48
48
|
import { statSync } from "fs";
|
|
@@ -1013,82 +1013,6 @@ function fromAgentPermissionMode(mode) {
|
|
|
1013
1013
|
return mode === "bypassPermissions" ? "bypassAll" : mode === "acceptEdits" ? "acceptEdits" : "ask";
|
|
1014
1014
|
}
|
|
1015
1015
|
|
|
1016
|
-
// src/tui/update-check.ts
|
|
1017
|
-
var PACKAGE_NAME = "@datalabrotterdam/nova-ai-cli";
|
|
1018
|
-
var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME.replace("/", "%2F")}/latest`;
|
|
1019
|
-
var DEFAULT_TIMEOUT_MS = 3e3;
|
|
1020
|
-
var UPDATE_COMMAND = "npm install -g @datalabrotterdam/nova-ai-cli@latest";
|
|
1021
|
-
async function checkForUpdate(options = {}) {
|
|
1022
|
-
try {
|
|
1023
|
-
const currentVersion = options.currentVersion ?? readInstalledVersion();
|
|
1024
|
-
if (!currentVersion) return null;
|
|
1025
|
-
const response = await (options.fetchImpl ?? fetch)(REGISTRY_URL, {
|
|
1026
|
-
headers: { accept: "application/json" },
|
|
1027
|
-
signal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
1028
|
-
});
|
|
1029
|
-
if (!response.ok) return null;
|
|
1030
|
-
const payload = await response.json();
|
|
1031
|
-
if (!isVersionPayload(payload)) return null;
|
|
1032
|
-
if (!isNewerVersion(payload.version, currentVersion)) return null;
|
|
1033
|
-
return {
|
|
1034
|
-
currentVersion,
|
|
1035
|
-
latestVersion: payload.version,
|
|
1036
|
-
command: UPDATE_COMMAND
|
|
1037
|
-
};
|
|
1038
|
-
} catch {
|
|
1039
|
-
return null;
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
function readInstalledVersion() {
|
|
1043
|
-
return readPackageVersion();
|
|
1044
|
-
}
|
|
1045
|
-
function isNewerVersion(candidate, current) {
|
|
1046
|
-
const next = parseVersion(candidate);
|
|
1047
|
-
const installed = parseVersion(current);
|
|
1048
|
-
if (!next || !installed) return false;
|
|
1049
|
-
for (let index = 0; index < 3; index++) {
|
|
1050
|
-
const difference = next.core[index] - installed.core[index];
|
|
1051
|
-
if (difference !== 0) return difference > 0;
|
|
1052
|
-
}
|
|
1053
|
-
return comparePrerelease(next.prerelease, installed.prerelease) > 0;
|
|
1054
|
-
}
|
|
1055
|
-
function isVersionPayload(value) {
|
|
1056
|
-
return typeof value === "object" && value !== null && "version" in value && typeof value.version === "string";
|
|
1057
|
-
}
|
|
1058
|
-
function parseVersion(value) {
|
|
1059
|
-
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(
|
|
1060
|
-
value
|
|
1061
|
-
);
|
|
1062
|
-
if (!match) return null;
|
|
1063
|
-
return {
|
|
1064
|
-
core: [Number(match[1]), Number(match[2]), Number(match[3])],
|
|
1065
|
-
prerelease: match[4]?.split(".") ?? []
|
|
1066
|
-
};
|
|
1067
|
-
}
|
|
1068
|
-
function comparePrerelease(left, right) {
|
|
1069
|
-
if (left.length === 0 || right.length === 0) {
|
|
1070
|
-
if (left.length === right.length) return 0;
|
|
1071
|
-
return left.length === 0 ? 1 : -1;
|
|
1072
|
-
}
|
|
1073
|
-
const length = Math.max(left.length, right.length);
|
|
1074
|
-
for (let index = 0; index < length; index++) {
|
|
1075
|
-
const leftPart = left[index];
|
|
1076
|
-
const rightPart = right[index];
|
|
1077
|
-
if (leftPart === void 0 || rightPart === void 0) {
|
|
1078
|
-
return leftPart === rightPart ? 0 : leftPart === void 0 ? -1 : 1;
|
|
1079
|
-
}
|
|
1080
|
-
if (leftPart === rightPart) continue;
|
|
1081
|
-
const leftNumber = /^\d+$/.test(leftPart) ? Number(leftPart) : null;
|
|
1082
|
-
const rightNumber = /^\d+$/.test(rightPart) ? Number(rightPart) : null;
|
|
1083
|
-
if (leftNumber !== null && rightNumber !== null)
|
|
1084
|
-
return leftNumber - rightNumber;
|
|
1085
|
-
if (leftNumber !== null || rightNumber !== null)
|
|
1086
|
-
return leftNumber !== null ? -1 : 1;
|
|
1087
|
-
return leftPart < rightPart ? -1 : 1;
|
|
1088
|
-
}
|
|
1089
|
-
return 0;
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
1016
|
// src/tui/ink/terminal-keyboard.ts
|
|
1093
1017
|
var KITTY_QUERY = "\x1B[?u";
|
|
1094
1018
|
var DEVICE_ATTRIBUTES_QUERY = "\x1B[c";
|
|
@@ -1807,7 +1731,17 @@ function PlanView({
|
|
|
1807
1731
|
] });
|
|
1808
1732
|
}
|
|
1809
1733
|
|
|
1734
|
+
// src/tui/ink/controller.ts
|
|
1735
|
+
import { setWorkspaceTrusted } from "@datalabrotterdam/nova-ai-agent/core/nova-home.js";
|
|
1736
|
+
import {
|
|
1737
|
+
disabledSkillNames,
|
|
1738
|
+
discoverSkills as discoverSkills2,
|
|
1739
|
+
setSkillEnabled
|
|
1740
|
+
} from "@datalabrotterdam/nova-ai-agent/core/skills.js";
|
|
1741
|
+
import { INTERACTION_MODES } from "@datalabrotterdam/nova-ai-agent/core/interaction-modes.js";
|
|
1742
|
+
|
|
1810
1743
|
// src/tui/commands/builtins.ts
|
|
1744
|
+
import { isInteractionMode } from "@datalabrotterdam/nova-ai-agent/core/interaction-modes.js";
|
|
1811
1745
|
var permissionModes = ["ask", "acceptEdits", "bypassAll"];
|
|
1812
1746
|
var builtinCommands = [
|
|
1813
1747
|
{
|
|
@@ -1880,7 +1814,7 @@ var builtinCommands = [
|
|
|
1880
1814
|
},
|
|
1881
1815
|
{
|
|
1882
1816
|
name: "exit",
|
|
1883
|
-
description: "Exit nova-ai
|
|
1817
|
+
description: "Exit nova-ai",
|
|
1884
1818
|
run(ctx) {
|
|
1885
1819
|
ctx.exit();
|
|
1886
1820
|
}
|
|
@@ -1953,9 +1887,20 @@ var builtinCommands = [
|
|
|
1953
1887
|
},
|
|
1954
1888
|
{
|
|
1955
1889
|
name: "skills",
|
|
1956
|
-
description: "
|
|
1957
|
-
run(ctx) {
|
|
1958
|
-
|
|
1890
|
+
description: "List skills, or switch one: /skills on|off <name> [--global]",
|
|
1891
|
+
run(ctx, args) {
|
|
1892
|
+
const words = args.trim().split(/\s+/).filter(Boolean);
|
|
1893
|
+
if (!words.length) {
|
|
1894
|
+
ctx.openSkillInspector();
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
const global = words.includes("--global");
|
|
1898
|
+
const [action, name] = words.filter((word) => word !== "--global");
|
|
1899
|
+
if (action !== "on" && action !== "off" || !name) {
|
|
1900
|
+
ctx.print("Usage: /skills, or /skills on|off <name> [--global]");
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1903
|
+
ctx.print(ctx.switchSkill(name, action === "on", global));
|
|
1959
1904
|
}
|
|
1960
1905
|
},
|
|
1961
1906
|
{
|
|
@@ -2561,6 +2506,7 @@ function walkWithFd(cwd, fdPath, query, signal) {
|
|
|
2561
2506
|
}
|
|
2562
2507
|
|
|
2563
2508
|
// src/tui/session/session-picker.ts
|
|
2509
|
+
import { listStoredSessions } from "@datalabrotterdam/nova-ai-agent/core/sessions.js";
|
|
2564
2510
|
function listSessionsForCwd(cwd) {
|
|
2565
2511
|
return listStoredSessions(cwd);
|
|
2566
2512
|
}
|
|
@@ -2609,6 +2555,9 @@ function formatDateTime(updatedAt) {
|
|
|
2609
2555
|
return Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : "unknown";
|
|
2610
2556
|
}
|
|
2611
2557
|
|
|
2558
|
+
// src/tui/ink/dialogs/state.ts
|
|
2559
|
+
import { OTHER_OPTION_ID } from "@datalabrotterdam/nova-ai-agent/core/user-questions.js";
|
|
2560
|
+
|
|
2612
2561
|
// src/tui/ink/editor/buffer.ts
|
|
2613
2562
|
var segmenter2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
2614
2563
|
function boundaries(text) {
|
|
@@ -4016,15 +3965,38 @@ status: failed - ${failure.message}`);
|
|
|
4016
3965
|
rows.length ? rows.join("\n\n") : "No MCP servers configured for this workspace.\n\nAdd a project .mcp.json or mcpServers to .nova-ai/settings.json; ACP connects them when the session starts."
|
|
4017
3966
|
);
|
|
4018
3967
|
};
|
|
3968
|
+
/** Every discovered skill with its state; switched-off skills stay listed. */
|
|
4019
3969
|
openSkillInspector = () => {
|
|
4020
|
-
const
|
|
3970
|
+
const cwd = this.runner.cwd;
|
|
3971
|
+
const skills = discoverSkills2(cwd);
|
|
3972
|
+
const disabled = disabledSkillNames(cwd);
|
|
3973
|
+
const on = skills.filter((skill) => !disabled.has(skill.name)).length;
|
|
4021
3974
|
this.showText(
|
|
4022
|
-
`Skills (${skills.length})`,
|
|
4023
|
-
skills.length ?
|
|
3975
|
+
`Skills (${on} on, ${skills.length - on} off)`,
|
|
3976
|
+
skills.length ? [
|
|
3977
|
+
...skills.map(
|
|
3978
|
+
(skill) => `${skill.name} [${skill.source}]${disabled.has(skill.name) ? " (off)" : ""}
|
|
4024
3979
|
${skill.description}
|
|
4025
|
-
${skill.path}`
|
|
3980
|
+
${skill.path}`
|
|
3981
|
+
),
|
|
3982
|
+
"/skills off <name> switches one off in this project (--global: everywhere); /skills on <name> switches it back on."
|
|
3983
|
+
].join("\n\n") : "No skills discovered. Add SKILL.md under .nova-ai/skills (or .agents, .claude, .codex skills) in the workspace, or ~/.nova-ai/skills for all projects."
|
|
4026
3984
|
);
|
|
4027
3985
|
};
|
|
3986
|
+
/** /skills on|off <name> [--global]: applies from the next message. */
|
|
3987
|
+
switchSkill = (name, enabled, global) => {
|
|
3988
|
+
const cwd = this.runner.cwd;
|
|
3989
|
+
if (!discoverSkills2(cwd).some((skill) => skill.name === name)) {
|
|
3990
|
+
return `No skill named "${name}". /skills lists them.`;
|
|
3991
|
+
}
|
|
3992
|
+
try {
|
|
3993
|
+
setSkillEnabled(cwd, global ? "global" : "project", name, enabled);
|
|
3994
|
+
} catch (error) {
|
|
3995
|
+
return errorMessage(error, "Could not change the skill.");
|
|
3996
|
+
}
|
|
3997
|
+
const stillOff = enabled && disabledSkillNames(cwd).has(name);
|
|
3998
|
+
return stillOff ? `Switched "${name}" on ${global ? "globally" : "in this project"}, but it is still off ${global ? "in this project" : "globally"} (use ${global ? "/skills on " + name : "/skills on " + name + " --global"}).` : `Skill "${name}" is ${enabled ? "on" : "off"} ${global ? "everywhere" : "in this project"} from the next message.`;
|
|
3999
|
+
};
|
|
4028
4000
|
openUsageInspector = async () => {
|
|
4029
4001
|
this.showText("Context usage", "Calculating context usage...");
|
|
4030
4002
|
try {
|
|
@@ -4111,6 +4083,7 @@ ${skill.path}`).join("\n\n") : "No skills discovered. Add SKILL.md under .agents
|
|
|
4111
4083
|
openToolInspector: this.openToolInspector,
|
|
4112
4084
|
openMcpInspector: this.openMcpInspector,
|
|
4113
4085
|
openSkillInspector: this.openSkillInspector,
|
|
4086
|
+
switchSkill: this.switchSkill,
|
|
4114
4087
|
openUsageInspector: this.openUsageInspector,
|
|
4115
4088
|
steerMessage: (message) => this.runner.steer(message),
|
|
4116
4089
|
queuedMessages: () => this.runner.queuedMessages(),
|
|
@@ -4308,6 +4281,7 @@ function errorMessage(error, fallback) {
|
|
|
4308
4281
|
import { Box as Box5, Text as Text5, useInput as useInput2, usePaste as usePaste2 } from "ink";
|
|
4309
4282
|
import stringWidth2 from "string-width";
|
|
4310
4283
|
import { useMemo, useState } from "react";
|
|
4284
|
+
import { OTHER_OPTION_ID as OTHER_OPTION_ID2 } from "@datalabrotterdam/nova-ai-agent/core/user-questions.js";
|
|
4311
4285
|
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
4312
4286
|
function useDialogInput(handle, isActive) {
|
|
4313
4287
|
const [, setTick] = useState(0);
|
|
@@ -4520,7 +4494,7 @@ function QuestionDialog({
|
|
|
4520
4494
|
/* @__PURE__ */ jsxs5(Text5, { wrap: "truncate-end", children: [
|
|
4521
4495
|
/* @__PURE__ */ jsx5(Text5, { color: palette.primary, children: state.selected === otherIndex ? ">" : " " }),
|
|
4522
4496
|
" ",
|
|
4523
|
-
state.isSelected(question.id,
|
|
4497
|
+
state.isSelected(question.id, OTHER_OPTION_ID2) ? /* @__PURE__ */ jsx5(Text5, { color: palette.success, children: "[x]" }) : "[ ]",
|
|
4524
4498
|
" ",
|
|
4525
4499
|
otherAnswer ? `Other: ${otherAnswer}` : "Other... (write your own answer)"
|
|
4526
4500
|
] }),
|
|
@@ -4766,7 +4740,7 @@ async function runChat(options) {
|
|
|
4766
4740
|
const cwd = process.cwd();
|
|
4767
4741
|
let resume = options.resume;
|
|
4768
4742
|
if (options.continueLast) {
|
|
4769
|
-
resume =
|
|
4743
|
+
resume = listStoredSessions2(cwd)[0]?.sessionId ?? null;
|
|
4770
4744
|
if (!resume) {
|
|
4771
4745
|
console.error(`No earlier session in ${cwd} to continue.`);
|
|
4772
4746
|
return 1;
|
|
@@ -4786,7 +4760,7 @@ ${cwd}`);
|
|
|
4786
4760
|
console.log("Trusting it starts those servers and applies those rules. Only trust code you know.");
|
|
4787
4761
|
const answer = (await prompt.question("Trust this workspace? [y/N] ")).trim().toLowerCase();
|
|
4788
4762
|
if (answer === "y" || answer === "yes") {
|
|
4789
|
-
|
|
4763
|
+
setWorkspaceTrusted2(cwd, true);
|
|
4790
4764
|
} else {
|
|
4791
4765
|
console.log("Not trusted: its MCP servers stay off and its allow rules are ignored. Use /trust later to change this.");
|
|
4792
4766
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
checkForUpdate,
|
|
3
|
+
chooseUpdate,
|
|
4
|
+
formatUpdateNotice,
|
|
5
|
+
isNewerVersion,
|
|
6
|
+
readInstalledVersion,
|
|
7
|
+
updateCachePath,
|
|
8
|
+
updateChecksDisabled
|
|
9
|
+
} from "./chunk-37PMUZ34.js";
|
|
10
|
+
import "./chunk-FMHWW3E6.js";
|
|
11
|
+
export {
|
|
12
|
+
checkForUpdate,
|
|
13
|
+
chooseUpdate,
|
|
14
|
+
formatUpdateNotice,
|
|
15
|
+
isNewerVersion,
|
|
16
|
+
readInstalledVersion,
|
|
17
|
+
updateCachePath,
|
|
18
|
+
updateChecksDisabled
|
|
19
|
+
};
|
package/package.json
CHANGED
|
@@ -1,47 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datalabrotterdam/nova-ai-cli",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.2.0-alpha.3",
|
|
4
|
+
"description": "Agentic coding with DataLab Rotterdam's Nova AI in your terminal: interactive TUI, headless mode, and an ACP agent for editors",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "DataLab Rotterdam",
|
|
7
7
|
"type": "module",
|
|
8
|
-
"main": "dist/index.js",
|
|
9
|
-
"types": "dist/index.d.ts",
|
|
10
|
-
"bin": {
|
|
11
|
-
"nova-ai-cli": "dist/index.js",
|
|
12
|
-
"nova-ai": "dist/index.js"
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"dist",
|
|
16
|
-
"src/acp/web/dist",
|
|
17
|
-
"LICENSE"
|
|
18
|
-
],
|
|
19
8
|
"engines": {
|
|
20
9
|
"node": ">=22.19"
|
|
21
10
|
},
|
|
22
11
|
"repository": {
|
|
23
12
|
"type": "git",
|
|
24
|
-
"url": "git+https://github.com/Datalab-Rotterdam/nova-ai-cli.git"
|
|
13
|
+
"url": "git+https://github.com/Datalab-Rotterdam/nova-ai-cli.git",
|
|
14
|
+
"directory": "packages/cli"
|
|
25
15
|
},
|
|
26
16
|
"bugs": {
|
|
27
17
|
"url": "https://github.com/Datalab-Rotterdam/nova-ai-cli/issues"
|
|
28
18
|
},
|
|
29
|
-
"homepage": "https://github.com/Datalab-Rotterdam/nova-ai-cli#readme",
|
|
30
19
|
"publishConfig": {
|
|
31
20
|
"access": "public"
|
|
32
21
|
},
|
|
22
|
+
"homepage": "https://github.com/Datalab-Rotterdam/nova-ai-cli#readme",
|
|
23
|
+
"bin": {
|
|
24
|
+
"nova-ai": "dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"README.md",
|
|
30
|
+
"CHANGELOG.md"
|
|
31
|
+
],
|
|
33
32
|
"scripts": {
|
|
34
|
-
"build": "
|
|
33
|
+
"build": "tsup",
|
|
35
34
|
"dev": "tsx watch src/index.ts",
|
|
36
|
-
"
|
|
37
|
-
"test
|
|
35
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
36
|
+
"test": "npm run typecheck && npm run test:unit && npm run test:pty",
|
|
37
|
+
"test:unit": "node -e \"require('fs').rmSync('dist-test',{recursive:true,force:true})\" && tsc -p tsconfig.test.json && node --import ./dist-test/test-support/setup-env.js --test --test-timeout=30000 \"dist-test/packages/cli/tests/**/*.test.js\"",
|
|
38
38
|
"test:pty": "tsx tests/tui/pty-runtime-runner.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@agentclientprotocol/sdk": "^0.29.0",
|
|
42
|
+
"@datalabrotterdam/nova-ai-agent": "^1.0.0-alpha.1",
|
|
42
43
|
"@datalabrotterdam/nova-sdk": "^1.3.2",
|
|
43
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
44
|
-
"@sourceregistry/node-webserver": "^1.8.0",
|
|
45
44
|
"chalk": "^5.3.0",
|
|
46
45
|
"cli-highlight": "^2.1.11",
|
|
47
46
|
"diff": "^9.0.0",
|
|
@@ -50,25 +49,9 @@
|
|
|
50
49
|
"react": "^19.3.0",
|
|
51
50
|
"string-width": "^8.3.0"
|
|
52
51
|
},
|
|
53
|
-
"devDependencies": {
|
|
54
|
-
"@semantic-release/changelog": "^6.0.3",
|
|
55
|
-
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
56
|
-
"@semantic-release/git": "^10.0.1",
|
|
57
|
-
"@semantic-release/npm": "^13.1.5",
|
|
58
|
-
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
59
|
-
"@types/node": "^22.20.0",
|
|
60
|
-
"@types/react": "^19.3.0",
|
|
61
|
-
"@xterm/headless": "^6.0.0",
|
|
62
|
-
"ink-testing-library": "^4.0.0",
|
|
63
|
-
"node-pty": "^1.1.0",
|
|
64
|
-
"tsup": "^8.3.0",
|
|
65
|
-
"tsx": "^4.19.0",
|
|
66
|
-
"typescript": "^5.6.0"
|
|
67
|
-
},
|
|
68
|
-
"overrides": {
|
|
69
|
-
"esbuild": "^0.28.1"
|
|
70
|
-
},
|
|
71
52
|
"release": {
|
|
53
|
+
"extends": "semantic-release-monorepo",
|
|
54
|
+
"tagFormat": "@datalabrotterdam/nova-ai-cli@${version}",
|
|
72
55
|
"branches": [
|
|
73
56
|
"main",
|
|
74
57
|
{
|
package/dist/acp-ZYOQ6PON.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NovaAgent,
|
|
3
|
-
createAgentApp
|
|
4
|
-
} from "./chunk-GZZ7PY3S.js";
|
|
5
|
-
import "./chunk-Q7WL3DXP.js";
|
|
6
|
-
import "./chunk-JAEXUFAS.js";
|
|
7
|
-
|
|
8
|
-
// src/acp/index.ts
|
|
9
|
-
import { Readable, Writable } from "stream";
|
|
10
|
-
import * as acp from "@agentclientprotocol/sdk";
|
|
11
|
-
|
|
12
|
-
// src/acp/stdio-guard.ts
|
|
13
|
-
function redirectConsoleToStderr() {
|
|
14
|
-
const methods = ["log", "info", "debug", "dir", "table", "trace"];
|
|
15
|
-
const original = Object.fromEntries(
|
|
16
|
-
methods.map((method) => [method, console[method]])
|
|
17
|
-
);
|
|
18
|
-
const toStderr = (...args) => console.error(...args);
|
|
19
|
-
for (const method of methods) {
|
|
20
|
-
console[method] = toStderr;
|
|
21
|
-
}
|
|
22
|
-
return () => {
|
|
23
|
-
for (const method of methods) {
|
|
24
|
-
console[method] = original[method];
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// src/acp/index.ts
|
|
30
|
-
async function runAcp() {
|
|
31
|
-
redirectConsoleToStderr();
|
|
32
|
-
const agentImpl = new NovaAgent();
|
|
33
|
-
const output = Writable.toWeb(process.stdout);
|
|
34
|
-
const input = Readable.toWeb(process.stdin);
|
|
35
|
-
const stream = acp.ndJsonStream(output, input);
|
|
36
|
-
const connection = createAgentApp(agentImpl).connect(stream);
|
|
37
|
-
installLifecycle(agentImpl, connection.closed);
|
|
38
|
-
await connection.closed;
|
|
39
|
-
}
|
|
40
|
-
function installLifecycle(agent, closed) {
|
|
41
|
-
let shuttingDown = false;
|
|
42
|
-
const shutdown = async (code) => {
|
|
43
|
-
if (shuttingDown) process.exit(code);
|
|
44
|
-
shuttingDown = true;
|
|
45
|
-
const forced = setTimeout(() => process.exit(code), SHUTDOWN_TIMEOUT_MS);
|
|
46
|
-
forced.unref();
|
|
47
|
-
try {
|
|
48
|
-
await agent.shutdown();
|
|
49
|
-
} catch (error) {
|
|
50
|
-
console.error("nova-ai-cli: error during shutdown:", error);
|
|
51
|
-
}
|
|
52
|
-
process.exit(code);
|
|
53
|
-
};
|
|
54
|
-
void closed.then(() => shutdown(0));
|
|
55
|
-
process.on("SIGTERM", () => void shutdown(0));
|
|
56
|
-
process.on("SIGINT", () => void shutdown(130));
|
|
57
|
-
process.on("unhandledRejection", (reason) => {
|
|
58
|
-
console.error("nova-ai-cli: unhandled rejection:", reason);
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
var SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
62
|
-
var acp_default = runAcp;
|
|
63
|
-
export {
|
|
64
|
-
acp_default as default
|
|
65
|
-
};
|