@velaro/cli 1.4.105 → 1.4.107

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.
@@ -321,7 +321,7 @@ test('fetchRetry429 retries only 429 and returns the final response after the re
321
321
  });
322
322
 
323
323
  test('bot_full_diagnostic: errors use the server-side level=ERROR filter, patterns are a separate read; neither is the old text regex', () => {
324
- for (const rel of ['../../mcp/staff-server.js', '../../mcp/server.js']) {
324
+ for (const rel of ['../../mcp/staff-server.js']) { // bot_full_diagnostic is staff-only since MCP 2.0.0
325
325
  const src = fs.readFileSync(path.join(here, rel), 'utf8');
326
326
  const a = src.indexOf('const velaroLoggerP = safeJson');
327
327
  const body = src.slice(a, a + 2600);
@@ -0,0 +1,27 @@
1
+ // Shared helpers for the MCP-parity command groups (diag-groups.js, ops-groups.js).
2
+ export const show = (r) => console.log(typeof r === 'string' ? r : JSON.stringify(r, null, 2));
3
+ export const qs = (o) => {
4
+ const p = new URLSearchParams();
5
+ for (const [k, v] of Object.entries(o)) if (v !== undefined && v !== null && v !== '') p.set(k, String(v));
6
+ const s = p.toString();
7
+ return s ? `?${s}` : '';
8
+ };
9
+ export const run = (fn) => async (argv) => {
10
+ try { await fn(argv); } catch (e) { console.error(`Error: ${e.message}`); process.exit(1); }
11
+ };
12
+ export const needYes = (argv, what) => {
13
+ if (!argv.yes) { console.error(`Refusing to ${what} without --yes.`); process.exit(1); }
14
+ };
15
+ // Build a yargs group body (spread into `{ command: 'name', ...group(...) }` so the parity validator sees the command name): subs = [[command, describe, builderFn|null, handler]]
16
+ export function group(describe, subs) {
17
+ return {
18
+ describe,
19
+ builder: (y) => {
20
+ for (const [command, desc, b, handler] of subs) {
21
+ y.command({ command, describe: desc, builder: b || ((x) => x), handler: run(handler) });
22
+ }
23
+ return y.demandCommand(1, `Specify a subcommand: ${subs.map((s) => s[0].split(' ')[0]).join(' | ')}`);
24
+ },
25
+ handler: () => {},
26
+ };
27
+ }
@@ -42,7 +42,7 @@ import { readFileSync } from 'node:fs';
42
42
  import { fileURLToPath } from 'node:url';
43
43
  import { dirname, join as pjoin } from 'node:path';
44
44
  const root = pjoin(dirname(fileURLToPath(import.meta.url)), '..', '..');
45
- for (const f of ['mcp/server.js', 'mcp/staff-server.js', 'server/Velaro.Admin/Controllers/StaffMcpController.cs']) {
45
+ for (const f of ['mcp/staff-server.js', 'server/Velaro.Admin/Controllers/StaffMcpController.cs']) {
46
46
  test(`${f} registers sign_versions tools`, () => {
47
47
  const s = readFileSync(pjoin(root, f), 'utf8');
48
48
  for (const t of ['sign_versions_list', 'sign_versions_diff', 'sign_versions_upload']) assert.ok(s.includes(t), `${t} missing in ${f}`);
@@ -0,0 +1,36 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { formatSkillUsage } from './commands/skill-usage.js';
4
+
5
+ const sample = {
6
+ siteId: 1032,
7
+ month: '2026-10',
8
+ isTrial: true,
9
+ overageBehavior: 'block',
10
+ usage: [
11
+ { metric: 'ai_tool_calls', name: 'AI Tool Calls', used: 120, limit: 500, unlimited: false, percent: 24, mode: 'Enforce' },
12
+ { metric: 'api_calls', name: 'REST API Calls', used: 9, limit: 0, unlimited: true, percent: 0, mode: 'Observe' },
13
+ ],
14
+ callsBySurface: [{ surface: 'McpStaff', calls: 4 }],
15
+ llmCostThisMonth: [{ keySource: 'byok', costUsd: 1.5, calls: 3 }],
16
+ };
17
+
18
+ test('shows usage against the limit with the gate mode, and marks unlimited metrics', () => {
19
+ const out = formatSkillUsage(sample);
20
+ assert.match(out, /Site 1032, 2026-10 \(trial\), overage: block/);
21
+ assert.match(out, /AI Tool Calls\s+120 \/\s+500\s+24%\s+gate: Enforce/);
22
+ assert.match(out, /REST API Calls\s+9 \/\s+unlimited/);
23
+ });
24
+
25
+ test('lists calls by surface and the LLM cost split, saying BYOK removes LLM cost only', () => {
26
+ const out = formatSkillUsage(sample);
27
+ assert.match(out, /McpStaff\s+4/);
28
+ assert.match(out, /byok\s+\$1\.50 \/ 3 calls/);
29
+ assert.match(out, /BYOK removes this cost only/);
30
+ });
31
+
32
+ test('handles a site with no recorded usage without throwing', () => {
33
+ const out = formatSkillUsage({ siteId: 5, month: '2026-10', overageBehavior: 'warn' });
34
+ assert.match(out, /\(none recorded\)/);
35
+ assert.match(out, /\(none logged\)/);
36
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velaro/cli",
3
- "version": "1.4.105",
3
+ "version": "1.4.107",
4
4
  "description": "Velaro Workspace v20 — command-line interface for managing bots, knowledge base ingestion, MCP API keys, search indexes, and ops health.",
5
5
  "type": "module",
6
6
  "bin": {