@artemiskit/cli 0.1.7 → 0.1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,SAAS,IAAI,OAAO,CAmBnC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,wBAAgB,SAAS,IAAI,OAAO,CAuCnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoLpC,wBAAgB,WAAW,IAAI,OAAO,CAkFrC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyNpC,wBAAgB,WAAW,IAAI,OAAO,CAqFrC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Non-blocking update checker for ArtemisKit CLI
3
+ */
4
+ export interface UpdateInfo {
5
+ currentVersion: string;
6
+ latestVersion: string;
7
+ updateAvailable: boolean;
8
+ }
9
+ /**
10
+ * Check for updates (non-blocking)
11
+ * Returns update info or null if check fails
12
+ */
13
+ export declare function checkForUpdate(): Promise<UpdateInfo | null>;
14
+ /**
15
+ * Get the current CLI version
16
+ */
17
+ export declare function getCurrentVersion(): string;
18
+ /**
19
+ * Format version display string
20
+ */
21
+ export declare function formatVersionDisplay(version: string): string;
22
+ /**
23
+ * Format update available message
24
+ */
25
+ export declare function formatUpdateMessage(current: string, latest: string): string;
26
+ /**
27
+ * Non-blocking update check that prints message if update available
28
+ * Use this to fire-and-forget an update check
29
+ */
30
+ export declare function checkForUpdateAndNotify(): void;
31
+ //# sourceMappingURL=update-checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-checker.d.ts","sourceRoot":"","sources":["../../../src/utils/update-checker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,MAAM,WAAW,UAAU;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAgDD;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAYjE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAW9C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@artemiskit/cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Command-line interface for ArtemisKit LLM evaluation toolkit",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -45,11 +45,11 @@
45
45
  "test": "bun test"
46
46
  },
47
47
  "dependencies": {
48
- "@artemiskit/adapter-openai": "0.1.5",
49
- "@artemiskit/adapter-vercel-ai": "0.1.5",
50
- "@artemiskit/core": "0.1.5",
51
- "@artemiskit/redteam": "0.1.5",
52
- "@artemiskit/reports": "0.1.5",
48
+ "@artemiskit/adapter-openai": "0.1.6",
49
+ "@artemiskit/adapter-vercel-ai": "0.1.6",
50
+ "@artemiskit/core": "0.1.6",
51
+ "@artemiskit/redteam": "0.1.6",
52
+ "@artemiskit/reports": "0.1.6",
53
53
  "chalk": "^5.3.0",
54
54
  "cli-table3": "^0.6.3",
55
55
  "commander": "^12.0.0",
package/src/cli.ts CHANGED
@@ -11,6 +11,7 @@ import { redteamCommand } from './commands/redteam';
11
11
  import { reportCommand } from './commands/report';
12
12
  import { runCommand } from './commands/run';
13
13
  import { stressCommand } from './commands/stress';
14
+ import { checkForUpdate, formatUpdateMessage, formatVersionDisplay } from './utils/update-checker';
14
15
 
15
16
  export function createCLI(): Command {
16
17
  const program = new Command();
@@ -20,7 +21,27 @@ export function createCLI(): Command {
20
21
  .description(
21
22
  'ArtemisKit - Open-source Agent Reliability Toolkit - Test, validate, audit and evaluate LLMs and LLM-driven agents'
22
23
  )
23
- .version(version);
24
+ .version(version, '-v, --version', 'Output the current version')
25
+ .option('-V, --version-check', 'Output version and check for updates')
26
+ .action(async () => {
27
+ // Handle root command with --version-check flag
28
+ const opts = program.opts();
29
+ if (opts.versionCheck) {
30
+ console.log(formatVersionDisplay(version));
31
+ console.log('\nChecking for updates...');
32
+ const updateInfo = await checkForUpdate();
33
+ if (updateInfo?.updateAvailable) {
34
+ console.log(formatUpdateMessage(updateInfo.currentVersion, updateInfo.latestVersion));
35
+ } else if (updateInfo) {
36
+ console.log('You are using the latest version.');
37
+ } else {
38
+ console.log('Could not check for updates (network unavailable).');
39
+ }
40
+ } else {
41
+ // No subcommand provided, show help
42
+ program.help();
43
+ }
44
+ });
24
45
 
25
46
  program.addCommand(initCommand());
26
47
  program.addCommand(runCommand());
@@ -8,6 +8,7 @@ import { join } from 'node:path';
8
8
  import chalk from 'chalk';
9
9
  import { Command } from 'commander';
10
10
  import { createSpinner, icons } from '../ui/index.js';
11
+ import { checkForUpdateAndNotify, getCurrentVersion } from '../utils/update-checker.js';
11
12
 
12
13
  const DEFAULT_CONFIG = `# ArtemisKit Configuration
13
14
  project: my-project
@@ -86,18 +87,54 @@ const ENV_KEYS = [
86
87
  ];
87
88
 
88
89
  function renderWelcomeBanner(): string {
90
+ // Brand color for "KIT" portion: #fb923c (orange)
91
+ const brandColor = chalk.hex('#fb923c');
92
+ const version = getCurrentVersion();
93
+
94
+ // Randomly color each border character white or brand color
95
+ const colorBorderChar = (char: string): string => {
96
+ return Math.random() > 0.5 ? chalk.white(char) : brandColor(char);
97
+ };
98
+
99
+ const colorBorder = (str: string): string => {
100
+ return str.split('').map(colorBorderChar).join('');
101
+ };
102
+
103
+ // All lines are exactly 52 chars inside the borders for perfect alignment
104
+ const topBorder = `╭${'─'.repeat(52)}╮`;
105
+ const bottomBorder = `╰${'─'.repeat(52)}╯`;
106
+ const sideBorderLeft = '│';
107
+ const sideBorderRight = '│';
108
+ const emptyContent = ' '.repeat(52);
109
+
110
+ // Version line: "v0.1.7" centered in brand color
111
+ const versionText = `v${version}`;
112
+ const versionPadding = Math.floor((52 - versionText.length) / 2);
113
+ const versionLine =
114
+ ' '.repeat(versionPadding) +
115
+ brandColor(versionText) +
116
+ ' '.repeat(52 - versionPadding - versionText.length);
117
+
118
+ // Tagline centered
119
+ const tagline = 'Open-source testing toolkit for LLM applications';
120
+ const taglinePadding = Math.floor((52 - tagline.length) / 2);
121
+ const taglineLine =
122
+ ' '.repeat(taglinePadding) +
123
+ chalk.gray(tagline) +
124
+ ' '.repeat(52 - taglinePadding - tagline.length);
125
+
89
126
  const lines = [
90
127
  '',
91
- chalk.cyan(' ╔═══════════════════════════════════════════════════════╗'),
92
- chalk.cyan(' ║ ║'),
93
- chalk.cyan('') +
94
- chalk.bold.white(' 🎯 Welcome to ArtemisKit ') +
95
- chalk.cyan('║'),
96
- chalk.cyan(' ║') +
97
- chalk.gray(' LLM Testing & Evaluation Toolkit ') +
98
- chalk.cyan('║'),
99
- chalk.cyan(' ║ ║'),
100
- chalk.cyan(' ╚═══════════════════════════════════════════════════════╝'),
128
+ ` ${colorBorder(topBorder)}`,
129
+ ` ${colorBorderChar(sideBorderLeft)}${emptyContent}${colorBorderChar(sideBorderRight)}`,
130
+ ` ${colorBorderChar(sideBorderLeft)} ${chalk.bold.white('▄▀█ █▀█ ▀█▀ █▀▀ █▀▄▀█ █ █▀ ')}${brandColor.bold('█▄▀ █ ▀█▀')} ${colorBorderChar(sideBorderRight)}`,
131
+ ` ${colorBorderChar(sideBorderLeft)} ${chalk.bold.white('█▀█ █▀▄ █ ██▄ ▀ █ █ ▄█ ')}${brandColor.bold('█ █ █ █ ')} ${colorBorderChar(sideBorderRight)}`,
132
+ ` ${colorBorderChar(sideBorderLeft)}${emptyContent}${colorBorderChar(sideBorderRight)}`,
133
+ ` ${colorBorderChar(sideBorderLeft)}${versionLine}${colorBorderChar(sideBorderRight)}`,
134
+ ` ${colorBorderChar(sideBorderLeft)}${emptyContent}${colorBorderChar(sideBorderRight)}`,
135
+ ` ${colorBorderChar(sideBorderLeft)}${taglineLine}${colorBorderChar(sideBorderRight)}`,
136
+ ` ${colorBorderChar(sideBorderLeft)}${emptyContent}${colorBorderChar(sideBorderRight)}`,
137
+ ` ${colorBorder(bottomBorder)}`,
101
138
  '',
102
139
  ];
103
140
  return lines.join('\n');
@@ -260,6 +297,9 @@ export function initCommand(): Command {
260
297
 
261
298
  // Show success panel
262
299
  console.log(renderSuccessPanel());
300
+
301
+ // Non-blocking update check (fire and forget)
302
+ checkForUpdateAndNotify();
263
303
  } catch (error) {
264
304
  spinner.fail('Error');
265
305
  console.error(chalk.red(`\n${icons.failed} ${(error as Error).message}`));
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Non-blocking update checker for ArtemisKit CLI
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+ import { version as currentVersion } from '../../package.json';
7
+
8
+ const PACKAGE_NAME = '@artemiskit/cli';
9
+ const NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
10
+ const FETCH_TIMEOUT_MS = 3000; // 3 second timeout to avoid blocking
11
+
12
+ // Brand color
13
+ const brandColor = chalk.hex('#fb923c');
14
+
15
+ export interface UpdateInfo {
16
+ currentVersion: string;
17
+ latestVersion: string;
18
+ updateAvailable: boolean;
19
+ }
20
+
21
+ /**
22
+ * Fetches the latest version from npm registry with a timeout
23
+ */
24
+ async function fetchLatestVersion(): Promise<string | null> {
25
+ const controller = new AbortController();
26
+ const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
27
+
28
+ try {
29
+ const response = await fetch(NPM_REGISTRY_URL, {
30
+ signal: controller.signal,
31
+ headers: {
32
+ Accept: 'application/json',
33
+ },
34
+ });
35
+
36
+ if (!response.ok) {
37
+ return null;
38
+ }
39
+
40
+ const data = (await response.json()) as { version?: string };
41
+ return data.version || null;
42
+ } catch {
43
+ // Silently fail - network issues shouldn't block CLI usage
44
+ return null;
45
+ } finally {
46
+ clearTimeout(timeoutId);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Compares two semver versions
52
+ * Returns true if latest > current
53
+ */
54
+ function isNewerVersion(current: string, latest: string): boolean {
55
+ const currentParts = current.replace(/^v/, '').split('.').map(Number);
56
+ const latestParts = latest.replace(/^v/, '').split('.').map(Number);
57
+
58
+ for (let i = 0; i < 3; i++) {
59
+ const c = currentParts[i] || 0;
60
+ const l = latestParts[i] || 0;
61
+ if (l > c) return true;
62
+ if (l < c) return false;
63
+ }
64
+ return false;
65
+ }
66
+
67
+ /**
68
+ * Check for updates (non-blocking)
69
+ * Returns update info or null if check fails
70
+ */
71
+ export async function checkForUpdate(): Promise<UpdateInfo | null> {
72
+ const latestVersion = await fetchLatestVersion();
73
+
74
+ if (!latestVersion) {
75
+ return null;
76
+ }
77
+
78
+ return {
79
+ currentVersion,
80
+ latestVersion,
81
+ updateAvailable: isNewerVersion(currentVersion, latestVersion),
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Get the current CLI version
87
+ */
88
+ export function getCurrentVersion(): string {
89
+ return currentVersion;
90
+ }
91
+
92
+ /**
93
+ * Format version display string
94
+ */
95
+ export function formatVersionDisplay(version: string): string {
96
+ return `${chalk.bold('ArtemisKit CLI')} ${brandColor(`v${version}`)}`;
97
+ }
98
+
99
+ /**
100
+ * Format update available message
101
+ */
102
+ export function formatUpdateMessage(current: string, latest: string): string {
103
+ return `\n${chalk.yellow('╭─────────────────────────────────────────────────────╮')}\n${chalk.yellow('│')}${chalk.yellow(' Update available! ')}${chalk.gray(`${current}`)}${chalk.yellow(' → ')}${brandColor.bold(`${latest}`)}${' '.repeat(24 - current.length - latest.length)}${chalk.yellow('│')}\n${chalk.yellow('│')}${chalk.white(' Run ')}${chalk.cyan('npm install -g @artemiskit/cli')}${chalk.white(' to update ')}${chalk.yellow('│')}\n${chalk.yellow('╰─────────────────────────────────────────────────────╯')}`;
104
+ }
105
+
106
+ /**
107
+ * Non-blocking update check that prints message if update available
108
+ * Use this to fire-and-forget an update check
109
+ */
110
+ export function checkForUpdateAndNotify(): void {
111
+ // Fire and forget - don't await
112
+ checkForUpdate()
113
+ .then((info) => {
114
+ if (info?.updateAvailable) {
115
+ console.log(formatUpdateMessage(info.currentVersion, info.latestVersion));
116
+ }
117
+ })
118
+ .catch(() => {
119
+ // Silently ignore errors
120
+ });
121
+ }