@datalabrotterdam/nova-ai-cli 1.2.0-alpha.7 → 1.2.0-alpha.8

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 CHANGED
@@ -1,3 +1,10 @@
1
+ # [@datalabrotterdam/nova-ai-cli-v1.2.0-alpha.8](https://github.com/Datalab-Rotterdam/nova-ai-cli/compare/@datalabrotterdam/nova-ai-cli@1.2.0-alpha.7...@datalabrotterdam/nova-ai-cli@1.2.0-alpha.8) (2026-10-24)
2
+
3
+
4
+ ### Features
5
+
6
+ * slash commands from markdown files ([305f111](https://github.com/Datalab-Rotterdam/nova-ai-cli/commit/305f1112c6f8312ab8a0683954c4e5bc88d7b952))
7
+
1
8
  # [@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
9
 
3
10
 
package/README.md CHANGED
@@ -105,7 +105,10 @@ row. To select text, hold Shift (Option in some macOS terminals) while dragging.
105
105
  Slash commands: `/help`, `/model`, `/effort` (thinking models), `/mode`, `/permission`, `/session`,
106
106
  `/resume`, `/clear`, `/compact`, `/rewind [n]`, `/queue`, `/steer`, `/usage`,
107
107
  `/tools`, `/mcp`, `/skills`, `/shell` and `/agent` (background jobs), `/trust`
108
- and `/exit`. Details:
108
+ and `/exit`. Your own commands are markdown files in `~/.nova-ai/commands/` or
109
+ the repository's `.nova-ai/commands/` (Claude Code's format, so
110
+ `.claude/commands` works too): the file is the prompt, `$ARGUMENTS` what you
111
+ type after the command, and they show up in the `/` menu. Details:
109
112
  [`src/tui/README.md`](https://github.com/Datalab-Rotterdam/nova-ai-cli/blob/main/packages/cli/src/tui/README.md).
110
113
 
111
114
  ## Headless
@@ -32,6 +32,8 @@ var TuiAcpClient = class {
32
32
  onInteractionModeChange;
33
33
  /** The modes the agent offers (built-in, then the user's agent files); set by the runner. */
34
34
  modeIds = [...INTERACTION_MODES];
35
+ /** Slash commands the agent understands, such as the user's command files. */
36
+ agentCommands = [];
35
37
  capabilities = {
36
38
  fs: { readTextFile: true, writeTextFile: true },
37
39
  terminal: true,
@@ -318,6 +320,13 @@ ${err.message}`;
318
320
  });
319
321
  }
320
322
  return;
323
+ case "available_commands_update":
324
+ this.agentCommands = update.availableCommands.map(({ name, description, input }) => ({
325
+ name,
326
+ description,
327
+ ...input && "hint" in input && input.hint ? { hint: input.hint } : {}
328
+ }));
329
+ return;
321
330
  case "current_mode_update":
322
331
  if (this.modeIds.includes(update.currentModeId)) {
323
332
  this.onInteractionModeChange?.(update.currentModeId);
@@ -2,7 +2,7 @@ import {
2
2
  TuiAcpClient,
3
3
  choosePermissionOption,
4
4
  createStore
5
- } from "./chunk-EOPM4RRE.js";
5
+ } from "./chunk-KDAUUQBE.js";
6
6
 
7
7
  // src/headless/index.ts
8
8
  import { resolve } from "path";
package/dist/index.js CHANGED
@@ -139,7 +139,7 @@ ${MAIN_HELP}
139
139
  }
140
140
  case "print": {
141
141
  const update = startUpdateCheck();
142
- const { default: runHeadless } = await import("./headless-QLCJRT3X.js");
142
+ const { default: runHeadless } = await import("./headless-BQXK7TNC.js");
143
143
  const code = await runHeadless(command.args);
144
144
  if (update) await noticeUpdate(update, 500);
145
145
  return code;
@@ -169,7 +169,7 @@ ${MAIN_HELP}
169
169
  );
170
170
  return 2;
171
171
  }
172
- const { default: runChat } = await import("./tui-HJQOYGHL.js");
172
+ const { default: runChat } = await import("./tui-TJFV6NC6.js");
173
173
  return runChat(options);
174
174
  }
175
175
  }
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  TuiAcpClient,
12
12
  createStore
13
- } from "./chunk-EOPM4RRE.js";
13
+ } from "./chunk-KDAUUQBE.js";
14
14
 
15
15
  // src/tui/index.ts
16
16
  import { createInterface as createInterface2 } from "readline/promises";
@@ -305,6 +305,10 @@ var SessionRunner = class {
305
305
  get modeIds() {
306
306
  return this.acpClient.modeIds;
307
307
  }
308
+ /** The agent's slash commands (the user's command files); sent as a prompt. */
309
+ get agentCommands() {
310
+ return this.acpClient.agentCommands;
311
+ }
308
312
  /** The agent, served in-process over a real ACP connection (tests may stub it). */
309
313
  agent = new NovaAgent();
310
314
  acpClient;
@@ -1882,7 +1886,7 @@ var builtinCommands = [
1882
1886
  name: "help",
1883
1887
  description: "Show available commands",
1884
1888
  run(ctx) {
1885
- const lines = builtinCommands.filter((c) => c.available?.(ctx) ?? true).map((c) => `/${c.name} \u2014 ${c.description}`);
1889
+ const lines = [...builtinCommands.filter((c) => c.available?.(ctx) ?? true), ...ctx.agentCommands()].map((c) => `/${c.name} \u2014 ${c.description}`);
1886
1890
  ctx.print(lines.join("\n"));
1887
1891
  }
1888
1892
  },
@@ -4362,6 +4366,7 @@ ${skill.path}`
4362
4366
  setModel: (model) => this.setModel(model),
4363
4367
  getInteractionMode: () => this.runner.interactionMode,
4364
4368
  getInteractionModes: () => this.runner.modeIds,
4369
+ agentCommands: () => this.agentCommands(),
4365
4370
  setInteractionMode: (mode) => this.setInteractionMode(mode),
4366
4371
  getPermissionMode: () => this.store.getState().permissionMode,
4367
4372
  setPermissionMode: (mode) => this.setPermissionMode(mode),
@@ -4403,6 +4408,10 @@ ${skill.path}`
4403
4408
  killBackgroundJob: (jobId) => this.runner.killBackgroundJob(jobId),
4404
4409
  releaseBackgroundJob: (jobId) => this.runner.releaseBackgroundJob(jobId)
4405
4410
  };
4411
+ /** The agent's commands the CLI doesn't have itself; a hint is shown after the description. */
4412
+ agentCommands() {
4413
+ return this.runner.agentCommands.filter((command) => !findCommand(command.name)).map(({ name, description, hint }) => ({ name, description: hint ? `${description} ${hint}` : description }));
4414
+ }
4406
4415
  // ------------------------------------------------------------ prompt
4407
4416
  submit = async (text, images = [], pastes = []) => {
4408
4417
  const value = text.trim();
@@ -4422,6 +4431,10 @@ ${skill.path}`
4422
4431
  const name = match?.[1] ?? "";
4423
4432
  const command = findCommand(name);
4424
4433
  if (!command) {
4434
+ if (this.agentCommands().some((agentCommand) => agentCommand.name === name)) {
4435
+ await this.runner.submit(value, images, pastes);
4436
+ return;
4437
+ }
4425
4438
  this.appendError(`Unknown command: /${name}`);
4426
4439
  return;
4427
4440
  }
@@ -4483,7 +4496,7 @@ ${skill.path}`
4483
4496
  const fdPath = resolveFdPath();
4484
4497
  editor.setAutocompleteProvider(
4485
4498
  new WorkspaceAutocompleteProvider(
4486
- () => allCommands(this.commandContext).map((command) => ({
4499
+ () => [...allCommands(this.commandContext), ...this.agentCommands()].map((command) => ({
4487
4500
  name: command.name,
4488
4501
  description: command.description
4489
4502
  })),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalabrotterdam/nova-ai-cli",
3
- "version": "1.2.0-alpha.7",
3
+ "version": "1.2.0-alpha.8",
4
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",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@agentclientprotocol/sdk": "^0.29.0",
42
- "@datalabrotterdam/nova-ai-agent": "^1.0.0-alpha.4",
42
+ "@datalabrotterdam/nova-ai-agent": "^1.0.0-alpha.5",
43
43
  "chalk": "^5.3.0",
44
44
  "cli-highlight": "^2.1.11",
45
45
  "diff": "^9.0.0",