@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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- readPackageVersion
4
- } from "./chunk-Q7WL3DXP.js";
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 ${readPackageVersion() ?? "unknown"}`;
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("./acp-ZYOQ6PON.js");
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 { default: runHeadless } = await import("./headless-ZYUSTZDL.js");
118
- return runHeadless(command.args);
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("./login-6U7QS7EA.js");
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("./login-6U7QS7EA.js");
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-XOKXPXN2.js");
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-ZKRZIF3S.js";
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-cli",
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: "Inspect discovered user and workspace skills",
1957
- run(ctx) {
1958
- ctx.openSkillInspector();
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 skills = this.runner.skillSessionStatus();
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 ? skills.map((skill) => `${skill.name} [${skill.source}]
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}`).join("\n\n") : "No skills discovered. Add SKILL.md under .agents/skills, .claude/skills, or .codex/skills in the workspace or user profile."
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, OTHER_OPTION_ID) ? /* @__PURE__ */ jsx5(Text5, { color: palette.success, children: "[x]" }) : "[ ]",
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 = listStoredSessions(cwd)[0]?.sessionId ?? null;
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
- setWorkspaceTrusted(cwd, true);
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.1",
4
- "description": "CLI for DataLab Rotterdam's Nova AI, with an Agent Client Protocol mode for editors/IDEs, backed by @datalabrotterdam/nova-sdk",
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": "npm install --prefix src/acp/web && npm run build --prefix src/acp/web && tsup",
33
+ "build": "tsup",
35
34
  "dev": "tsx watch src/index.ts",
36
- "test": "tsc -p tsconfig.json --noEmit && 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/tests/setup-env.js --test --test-timeout=30000 \"dist-test/tests/**/*.test.js\"",
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
  {
@@ -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
- };