From eb9fced1c6636988f7f252c1b2c389c4c451a72a Mon Sep 17 00:00:00 2001 From: Volodymyr Vreshch Date: Fri, 20 Mar 2026 22:10:48 +0100 Subject: [PATCH 1/2] chore: add prettier format:check to CI validation --- .github/workflows/ci.yml | 3 +++ package-lock.json | 17 +++++++++++++++++ package.json | 5 ++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1dd7f0d..9bd4966 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,9 @@ jobs: - name: šŸ” Lint run: npm run lint + - name: šŸ’… Format check + run: npm run format:check + - name: šŸ—ļø Build run: npm run build diff --git a/package-lock.json b/package-lock.json index a654db2..b1aea8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "@typescript-eslint/parser": "^8.46.3", "eslint": "^9.39.1", "jest": "^30.2.0", + "prettier": "^3.8.1", "ts-jest": "^29.4.5", "tsx": "^4.20.6", "typescript": "^5.9.3" @@ -6882,6 +6883,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-format": { "version": "30.3.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", diff --git a/package.json b/package.json index d351ec9..4ae591f 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,9 @@ "test:coverage": "jest --coverage", "verify": "npm run type-check && npm run lint && npm run build && npm run test", "clean": "rm -rf dist coverage", - "prepublishOnly": "npm run verify" + "prepublishOnly": "npm run verify", + "format:check": "prettier --check .", + "format": "prettier --write ." }, "keywords": [ "cli", @@ -62,6 +64,7 @@ "@typescript-eslint/parser": "^8.46.3", "eslint": "^9.39.1", "jest": "^30.2.0", + "prettier": "^3.8.1", "ts-jest": "^29.4.5", "tsx": "^4.20.6", "typescript": "^5.9.3" From b35928ed6f52c3e40a591ccd119baea32fb0a9d2 Mon Sep 17 00:00:00 2001 From: Volodymyr Vreshch Date: Fri, 20 Mar 2026 22:14:05 +0100 Subject: [PATCH 2/2] chore: apply prettier formatting to existing files --- .github/copilot-instructions.md | 8 +-- .github/dependabot.yml | 1 - .github/workflows/ci.yml | 2 +- .github/workflows/publish.yml | 12 ++-- eslint.config.js | 5 +- src/cli.test.ts | 4 +- src/cli.ts | 62 ++++--------------- src/commands/init.test.ts | 8 +-- src/commands/init.ts | 11 +--- src/commands/install.test.ts | 88 +++++++-------------------- src/commands/install.ts | 14 +---- src/commands/list.test.ts | 20 ++---- src/commands/list.ts | 13 +--- src/commands/login.test.ts | 32 +++------- src/commands/login.ts | 33 ++-------- src/commands/logout.test.ts | 20 ++---- src/commands/logout.ts | 6 +- src/commands/publish.test.ts | 49 ++++----------- src/commands/publish.ts | 52 ++++------------ src/commands/run.test.ts | 16 ++--- src/commands/run.ts | 9 +-- src/commands/search.test.ts | 40 +++--------- src/commands/search.ts | 26 ++------ src/commands/update.test.ts | 16 ++--- src/commands/update.ts | 18 ++---- src/commands/whoami.test.ts | 47 ++++---------- src/index.test.ts | 6 +- src/services/auth.service.test.ts | 53 +++++----------- src/services/auth.service.ts | 13 ++-- src/services/registry.service.test.ts | 11 +--- src/services/registry.service.ts | 24 ++------ src/utils/config.test.ts | 14 +---- src/utils/version.ts | 7 +-- 33 files changed, 184 insertions(+), 556 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 5f34d2b..198752a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -70,11 +70,11 @@ **Command Structure**: ```typescript -import { Command } from "commander"; +import { Command } from 'commander'; -export const myCommand = new Command("name") - .description("Command description") - .option("-o, --option ", "Option description") +export const myCommand = new Command('name') + .description('Command description') + .option('-o, --option ', 'Option description') .action(async (options) => { // Implementation }); diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e00d876..b1e4ad1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -32,4 +32,3 @@ updates: all-actions: patterns: - '*' - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bd4966..7edc2c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} - cache: "npm" + cache: 'npm' - name: šŸ“¦ Install dependencies run: npm ci diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b77d87b..91ec189 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,7 +4,7 @@ on: push: branches: [master, main] paths: - - "package.json" + - 'package.json' workflow_dispatch: permissions: @@ -12,7 +12,7 @@ permissions: id-token: write env: - NODE_VERSION: "20" + NODE_VERSION: '20' jobs: detect-changes: @@ -31,7 +31,7 @@ jobs: uses: actions/setup-node@v6 with: node-version: ${{ env.NODE_VERSION }} - cache: "npm" + cache: 'npm' - name: šŸ“¦ Install dependencies run: npm ci @@ -78,7 +78,7 @@ jobs: uses: actions/setup-node@v6 with: node-version: ${{ env.NODE_VERSION }} - cache: "npm" + cache: 'npm' - name: šŸ“¦ Install dependencies run: npm ci @@ -110,8 +110,8 @@ jobs: uses: actions/setup-node@v6 with: node-version: ${{ env.NODE_VERSION }} - cache: "npm" - registry-url: "https://registry.npmjs.org" + cache: 'npm' + registry-url: 'https://registry.npmjs.org' - name: šŸ“¦ Install dependencies run: npm ci diff --git a/eslint.config.js b/eslint.config.js index 2cf8587..9924e01 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -21,10 +21,7 @@ export default [ rules: { '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/explicit-function-return-type': 'warn', - '@typescript-eslint/no-unused-vars': [ - 'error', - { argsIgnorePattern: '^_' }, - ], + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], '@typescript-eslint/naming-convention': [ 'error', { diff --git a/src/cli.test.ts b/src/cli.test.ts index 4eae21e..18f402c 100644 --- a/src/cli.test.ts +++ b/src/cli.test.ts @@ -74,8 +74,6 @@ describe('CLI Commands', () => { encoding: 'utf-8', }); // Either shows no agents found or lists available agents (including global) - expect( - output.includes('No agents found') || output.includes('Available Agents') - ).toBe(true); + expect(output.includes('No agents found') || output.includes('Available Agents')).toBe(true); }); }); diff --git a/src/cli.ts b/src/cli.ts index d6f9f44..5980081 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -19,17 +19,13 @@ import { checkForUpdates } from './utils/version.js'; const displayBanner = (): void => { console.log(); - console.log( - chalk.cyan.bold(' ╔═══════════════════════════════════════════╗') - ); + console.log(chalk.cyan.bold(' ╔═══════════════════════════════════════════╗')); console.log( chalk.cyan.bold(' ā•‘') + chalk.white.bold(' šŸ¤– AgentKit CLI ') + chalk.cyan.bold('ā•‘') ); - console.log( - chalk.cyan.bold(' ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•') - ); + console.log(chalk.cyan.bold(' ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•')); console.log(); }; @@ -43,15 +39,9 @@ const displayVersionInfo = async (): Promise => { const user = await getMe(); const displayName = user.name || user.email; const aliasDisplay = user.verifiedAlias - ? chalk.gray(' (@') + - chalk.green.bold(user.verifiedAlias) + - chalk.gray(')') + ? chalk.gray(' (@') + chalk.green.bold(user.verifiedAlias) + chalk.gray(')') : ''; - console.log( - chalk.gray(' Logged in as: ') + - chalk.green.bold(displayName) + - aliasDisplay - ); + console.log(chalk.gray(' Logged in as: ') + chalk.green.bold(displayName) + aliasDisplay); } else { console.log( chalk.gray(' Status: ') + @@ -105,9 +95,7 @@ const displayVersionInfo = async (): Promise => { const displayCustomHelp = (): void => { console.log( - chalk.white.bold(' Usage: ') + - chalk.cyan('agent') + - chalk.gray(' [command] [options]') + chalk.white.bold(' Usage: ') + chalk.cyan('agent') + chalk.gray(' [command] [options]') ); console.log(); console.log(chalk.white.bold(' Commands:')); @@ -170,24 +158,16 @@ const displayCustomHelp = (): void => { console.log(); console.log(chalk.white.bold(' Options:')); console.log(); + console.log(` ${chalk.cyan.bold('-v, --version')} ${chalk.white('Display version number')}`); console.log( - ` ${chalk.cyan.bold('-v, --version')} ${chalk.white( - 'Display version number' - )}` - ); - console.log( - ` ${chalk.cyan.bold('-h, --help')} ${chalk.white( - 'Display this help message' - )}` + ` ${chalk.cyan.bold('-h, --help')} ${chalk.white('Display this help message')}` ); console.log(); console.log(chalk.white.bold(' Examples:')); console.log(); console.log(chalk.white(' $ ') + chalk.cyan('agent init my-agent')); console.log( - chalk.white(' $ ') + - chalk.cyan('agent run my-agent') + - chalk.white(' "Hello, how are you?"') + chalk.white(' $ ') + chalk.cyan('agent run my-agent') + chalk.white(' "Hello, how are you?"') ); console.log(chalk.white(' $ ') + chalk.cyan('agent list')); console.log(); @@ -232,11 +212,7 @@ program .command('publish') .description('Publish agent to registry') .argument('[path]', 'Path to agent file') - .option( - '-v, --visibility ', - 'Visibility (public or private)', - 'public' - ) + .option('-v, --visibility ', 'Visibility (public or private)', 'public') .option('--version ', 'Override version') .option('-t, --tag ', 'Add tags') .option('-c, --changelog ', 'Changelog message') @@ -262,25 +238,13 @@ program .action(searchCommand); // Auth commands -program - .command('login') - .description('Login to the Agentage registry') - .action(loginCommand); +program.command('login').description('Login to the Agentage registry').action(loginCommand); -program - .command('logout') - .description('Logout from the Agentage registry') - .action(logoutCommand); +program.command('logout').description('Logout from the Agentage registry').action(logoutCommand); -program - .command('whoami') - .description('Display the currently logged in user') - .action(whoamiCommand); +program.command('whoami').description('Display the currently logged in user').action(whoamiCommand); -program - .command('update') - .description('Update the CLI to the latest version') - .action(updateCommand); +program.command('update').description('Update the CLI to the latest version').action(updateCommand); // Handle help flag explicitly if (process.argv.includes('-h') || process.argv.includes('--help')) { diff --git a/src/commands/init.test.ts b/src/commands/init.test.ts index f08b44b..f3ba255 100644 --- a/src/commands/init.test.ts +++ b/src/commands/init.test.ts @@ -71,14 +71,10 @@ describe('initCommand', () => { const consoleError = jest.spyOn(console, 'error').mockImplementation(); const originalWriteFile = require('fs/promises').writeFile; - jest - .spyOn(require('fs/promises'), 'writeFile') - .mockRejectedValue(new Error('Write failed')); + jest.spyOn(require('fs/promises'), 'writeFile').mockRejectedValue(new Error('Write failed')); await expect(initCommand('test')).rejects.toThrow('process.exit called'); - expect(consoleError).toHaveBeenCalledWith( - expect.stringContaining('āŒ Failed: Write failed') - ); + expect(consoleError).toHaveBeenCalledWith(expect.stringContaining('āŒ Failed: Write failed')); expect(mockExit).toHaveBeenCalledWith(1); // Restore diff --git a/src/commands/init.ts b/src/commands/init.ts index 246cb60..c895358 100644 --- a/src/commands/init.ts +++ b/src/commands/init.ts @@ -27,10 +27,7 @@ export interface InitOptions { */ const getGlobalDir = (): string => join(homedir(), '.agentage'); -export const initCommand = async ( - name?: string, - options?: InitOptions -): Promise => { +export const initCommand = async (name?: string, options?: InitOptions): Promise => { const agentName = name || 'my-agent'; const isGlobal = options?.global ?? false; @@ -55,11 +52,7 @@ export const initCommand = async ( console.log(`āœ… Created ${agentFilePath}`); // Create agent.json config file - await writeFile( - configFilePath, - JSON.stringify(agentConfig, null, 2), - 'utf-8' - ); + await writeFile(configFilePath, JSON.stringify(agentConfig, null, 2), 'utf-8'); console.log(`āœ… Created ${configFilePath}`); } catch (error) { console.error(`āŒ Failed: ${(error as Error).message}`); diff --git a/src/commands/install.test.ts b/src/commands/install.test.ts index dd54f52..dc1f5f0 100644 --- a/src/commands/install.test.ts +++ b/src/commands/install.test.ts @@ -63,9 +63,7 @@ describe('installCommand', () => { test('rejects invalid identifier format', async () => { await expect(installCommand('invalid')).rejects.toThrow('process.exit(1)'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('Invalid format') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Invalid format')); }); test('installs agent to local directory when agent.json exists', async () => { @@ -83,15 +81,10 @@ describe('installCommand', () => { await installCommand('testuser/test-agent'); expect(existsSync(join('agents', 'test-agent.agent.md'))).toBe(true); - const content = readFileSync( - join('agents', 'test-agent.agent.md'), - 'utf-8' - ); + const content = readFileSync(join('agents', 'test-agent.agent.md'), 'utf-8'); expect(content).toContain('name: test-agent'); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('Installed') - ); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Installed')); }); test('installs specific version', async () => { @@ -106,10 +99,7 @@ describe('installCommand', () => { await installCommand('testuser/test-agent@2025-11-01'); - const content = readFileSync( - join('agents', 'test-agent.agent.md'), - 'utf-8' - ); + const content = readFileSync(join('agents', 'test-agent.agent.md'), 'utf-8'); expect(content).toContain('version: 2025-11-01'); }); @@ -134,15 +124,10 @@ describe('installCommand', () => { // Expected to exit } - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('already exists') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('already exists')); // Verify file was not overwritten - const content = readFileSync( - join('agents', 'test-agent.agent.md'), - 'utf-8' - ); + const content = readFileSync(join('agents', 'test-agent.agent.md'), 'utf-8'); expect(content).toBe('existing content'); }); @@ -162,10 +147,7 @@ describe('installCommand', () => { await installCommand('testuser/test-agent', { force: true }); - const content = readFileSync( - join('agents', 'test-agent.agent.md'), - 'utf-8' - ); + const content = readFileSync(join('agents', 'test-agent.agent.md'), 'utf-8'); expect(content).toContain('New content'); }); @@ -181,9 +163,7 @@ describe('installCommand', () => { await installCommand('testuser/test-agent', { global: true }); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('Installed') - ); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Installed')); }); test('installs to local directory with --local flag', async () => { @@ -202,45 +182,27 @@ describe('installCommand', () => { }); test('handles 404 error', async () => { - const { - getAgent, - RegistryApiError, - } = require('../services/registry.service.js'); + const { getAgent, RegistryApiError } = require('../services/registry.service.js'); - getAgent.mockRejectedValue( - new RegistryApiError('Not found', 'not_found', 404) - ); + getAgent.mockRejectedValue(new RegistryApiError('Not found', 'not_found', 404)); writeFileSync('agent.json', '{}'); - await expect(installCommand('testuser/nonexistent')).rejects.toThrow( - 'process.exit(1)' - ); + await expect(installCommand('testuser/nonexistent')).rejects.toThrow('process.exit(1)'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('not found') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('not found')); }); test('handles 403 error', async () => { - const { - getAgent, - RegistryApiError, - } = require('../services/registry.service.js'); + const { getAgent, RegistryApiError } = require('../services/registry.service.js'); - getAgent.mockRejectedValue( - new RegistryApiError('Forbidden', 'forbidden', 403) - ); + getAgent.mockRejectedValue(new RegistryApiError('Forbidden', 'forbidden', 403)); writeFileSync('agent.json', '{}'); - await expect(installCommand('testuser/private-agent')).rejects.toThrow( - 'process.exit(1)' - ); + await expect(installCommand('testuser/private-agent')).rejects.toThrow('process.exit(1)'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('Access denied') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Access denied')); }); test('handles version without content', async () => { @@ -253,13 +215,11 @@ describe('installCommand', () => { writeFileSync('agent.json', '{}'); - await expect( - installCommand('testuser/test-agent@2025-11-01') - ).rejects.toThrow('process.exit(1)'); - - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('not available') + await expect(installCommand('testuser/test-agent@2025-11-01')).rejects.toThrow( + 'process.exit(1)' ); + + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('not available')); }); test('handles generic error', async () => { @@ -269,12 +229,8 @@ describe('installCommand', () => { writeFileSync('agent.json', '{}'); - await expect(installCommand('testuser/test-agent')).rejects.toThrow( - 'process.exit(1)' - ); + await expect(installCommand('testuser/test-agent')).rejects.toThrow('process.exit(1)'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('Network error') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Network error')); }); }); diff --git a/src/commands/install.ts b/src/commands/install.ts index 235e90d..d9fc0e3 100644 --- a/src/commands/install.ts +++ b/src/commands/install.ts @@ -3,11 +3,7 @@ import { existsSync } from 'fs'; import { access, mkdir, writeFile } from 'fs/promises'; import { homedir } from 'os'; import { join } from 'path'; -import { - getAgent, - getAgentVersion, - RegistryApiError, -} from '../services/registry.service.js'; +import { getAgent, getAgentVersion, RegistryApiError } from '../services/registry.service.js'; import { parseAgentIdentifier } from '../utils/agent-parser.js'; interface InstallOptions { @@ -107,9 +103,7 @@ export const installCommand = async ( // 6. Success console.log(); - console.log( - chalk.green(`āœ… Installed ${owner}/${name}@${installedVersion}`) - ); + console.log(chalk.green(`āœ… Installed ${owner}/${name}@${installedVersion}`)); console.log(chalk.gray(` Location: ${filePath}`)); console.log(chalk.gray(` Run with: agent run ${name}`)); console.log(); @@ -118,9 +112,7 @@ export const installCommand = async ( if (error.statusCode === 404) { console.error(chalk.red(`āŒ Agent not found: ${identifier}`)); } else if (error.statusCode === 403) { - console.error( - chalk.red('āŒ Access denied. This agent may be private.') - ); + console.error(chalk.red('āŒ Access denied. This agent may be private.')); console.log('Run', chalk.cyan('agent login'), 'to authenticate.'); } else { console.error(chalk.red(`āŒ ${error.message}`)); diff --git a/src/commands/list.test.ts b/src/commands/list.test.ts index aff941b..dfe134c 100644 --- a/src/commands/list.test.ts +++ b/src/commands/list.test.ts @@ -39,9 +39,7 @@ describe('listCommand', () => { await listCommand(); - expect(consoleLog).toHaveBeenCalledWith( - expect.stringContaining('No agents found.') - ); + expect(consoleLog).toHaveBeenCalledWith(expect.stringContaining('No agents found.')); consoleLog.mockRestore(); }); @@ -52,9 +50,7 @@ describe('listCommand', () => { await listCommand(); - expect(consoleLog).toHaveBeenCalledWith( - expect.stringContaining('No agents found.') - ); + expect(consoleLog).toHaveBeenCalledWith(expect.stringContaining('No agents found.')); consoleLog.mockRestore(); }); @@ -111,9 +107,7 @@ content: here`; await listCommand(); expect(consoleLog).toHaveBeenCalledWith('\nšŸ“‹ Available Agents:\n'); - expect(consoleLog).toHaveBeenCalledWith( - expect.stringContaining('āŒ invalid-agent -') - ); + expect(consoleLog).toHaveBeenCalledWith(expect.stringContaining('āŒ invalid-agent -')); consoleLog.mockRestore(); }); @@ -137,9 +131,7 @@ model: gpt-4`; await listCommand(); expect(consoleLog).toHaveBeenCalledWith(' āœ… valid-agent (gpt-4)'); - expect(consoleLog).toHaveBeenCalledWith( - expect.stringContaining('āŒ invalid-agent -') - ); + expect(consoleLog).toHaveBeenCalledWith(expect.stringContaining('āŒ invalid-agent -')); consoleLog.mockRestore(); }); @@ -169,9 +161,7 @@ instructions: Test instructions`; await listCommand(); - expect(consoleLog).toHaveBeenCalledWith( - expect.stringContaining('No agents found.') - ); + expect(consoleLog).toHaveBeenCalledWith(expect.stringContaining('No agents found.')); consoleLog.mockRestore(); }); diff --git a/src/commands/list.ts b/src/commands/list.ts index bb4e74e..86cc888 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -62,17 +62,12 @@ const getAgentPaths = async ( /** * Scan a directory for agent files (.yml and .agent.md) */ -const scanAgentsInDir = async ( - dir: string, - location: 'global' | 'local' -): Promise => { +const scanAgentsInDir = async (dir: string, location: 'global' | 'local'): Promise => { const agents: AgentInfo[] = []; try { const files = await readdir(dir); - const agentFiles = files.filter( - (f) => f.endsWith('.yml') || f.endsWith('.agent.md') - ); + const agentFiles = files.filter((f) => f.endsWith('.yml') || f.endsWith('.agent.md')); for (const file of agentFiles) { const filePath = join(dir, file); @@ -154,9 +149,7 @@ export const listCommand = async (): Promise => { // 3. Display results if (allAgents.length === 0) { - console.log( - 'No agents found. Run ' + chalk.cyan('agent init') + ' to create one.' - ); + console.log('No agents found. Run ' + chalk.cyan('agent init') + ' to create one.'); return; } diff --git a/src/commands/login.test.ts b/src/commands/login.test.ts index 9910052..66a1414 100644 --- a/src/commands/login.test.ts +++ b/src/commands/login.test.ts @@ -17,19 +17,14 @@ jest.mock('open', () => ({ default: jest.fn(), })); -const mockRequestDeviceCode = - authService.requestDeviceCode as jest.MockedFunction< - typeof authService.requestDeviceCode - >; +const mockRequestDeviceCode = authService.requestDeviceCode as jest.MockedFunction< + typeof authService.requestDeviceCode +>; const mockPollForToken = authService.pollForToken as jest.MockedFunction< typeof authService.pollForToken >; -const mockLoadAuth = configUtils.loadAuth as jest.MockedFunction< - typeof configUtils.loadAuth ->; -const mockSaveAuth = configUtils.saveAuth as jest.MockedFunction< - typeof configUtils.saveAuth ->; +const mockLoadAuth = configUtils.loadAuth as jest.MockedFunction; +const mockSaveAuth = configUtils.saveAuth as jest.MockedFunction; const mockGetRegistryUrl = configUtils.getRegistryUrl as jest.MockedFunction< typeof configUtils.getRegistryUrl >; @@ -101,16 +96,11 @@ describe('loginCommand', () => { it('handles login errors', async () => { mockLoadAuth.mockResolvedValue({}); - mockRequestDeviceCode.mockRejectedValue( - new AuthError('Failed', 'request_failed') - ); + mockRequestDeviceCode.mockRejectedValue(new AuthError('Failed', 'request_failed')); await expect(loginCommand()).rejects.toThrow('process.exit called'); - expect(consoleErrorSpy).toHaveBeenCalledWith( - expect.stringContaining('Login failed'), - 'Failed' - ); + expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Login failed'), 'Failed'); }); it('handles expired token error with hint', async () => { @@ -122,9 +112,7 @@ describe('loginCommand', () => { expires_in: 900, interval: 5, }); - mockPollForToken.mockRejectedValue( - new AuthError('Login timed out', 'expired_token') - ); + mockPollForToken.mockRejectedValue(new AuthError('Login timed out', 'expired_token')); await expect(loginCommand()).rejects.toThrow('process.exit called'); @@ -192,9 +180,7 @@ describe('loginCommand', () => { await loginCommand(); - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Login successful') - ); + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Login successful')); }); it('handles browser open failure gracefully', async () => { diff --git a/src/commands/login.ts b/src/commands/login.ts index e27157c..71be877 100644 --- a/src/commands/login.ts +++ b/src/commands/login.ts @@ -1,9 +1,5 @@ import chalk from 'chalk'; -import { - AuthError, - pollForToken, - requestDeviceCode, -} from '../services/auth.service.js'; +import { AuthError, pollForToken, requestDeviceCode } from '../services/auth.service.js'; import { getRegistryUrl, loadAuth, saveAuth } from '../utils/config.js'; /** @@ -35,10 +31,7 @@ export const loginCommand = async (): Promise => { console.log(); console.log(chalk.bold('To complete login:')); console.log(); - console.log( - ' 1. Open:', - chalk.cyan.underline(deviceCode.verification_uri) - ); + console.log(' 1. Open:', chalk.cyan.underline(deviceCode.verification_uri)); console.log(' 2. Enter code:', chalk.bold.yellow(deviceCode.user_code)); console.log(); @@ -48,11 +41,7 @@ export const loginCommand = async (): Promise => { await open.default(deviceCode.verification_uri); console.log(chalk.gray('(Browser opened automatically)')); } catch { - console.log( - chalk.gray( - '(Could not open browser automatically - please open manually)' - ) - ); + console.log(chalk.gray('(Could not open browser automatically - please open manually)')); } console.log(); @@ -76,15 +65,9 @@ export const loginCommand = async (): Promise => { console.log(); if (tokenResponse.user?.name) { - console.log( - chalk.green('āœ… Logged in as'), - chalk.bold(tokenResponse.user.name) - ); + console.log(chalk.green('āœ… Logged in as'), chalk.bold(tokenResponse.user.name)); } else if (tokenResponse.user?.email) { - console.log( - chalk.green('āœ… Logged in as'), - chalk.bold(tokenResponse.user.email) - ); + console.log(chalk.green('āœ… Logged in as'), chalk.bold(tokenResponse.user.email)); } else { console.log(chalk.green('āœ… Login successful!')); } @@ -92,11 +75,7 @@ export const loginCommand = async (): Promise => { if (error instanceof AuthError) { console.error(chalk.red('āŒ Login failed:'), error.message); if (error.code === 'expired_token') { - console.log( - chalk.gray('Run'), - chalk.cyan('agent login'), - chalk.gray('to try again.') - ); + console.log(chalk.gray('Run'), chalk.cyan('agent login'), chalk.gray('to try again.')); } } else { console.error(chalk.red('āŒ Login failed:'), (error as Error).message); diff --git a/src/commands/logout.test.ts b/src/commands/logout.test.ts index f159dcf..1cbc7f1 100644 --- a/src/commands/logout.test.ts +++ b/src/commands/logout.test.ts @@ -6,15 +6,9 @@ import { logoutCommand } from './logout.js'; jest.mock('../services/auth.service.js'); jest.mock('../utils/config.js'); -const mockLogout = authService.logout as jest.MockedFunction< - typeof authService.logout ->; -const mockLoadAuth = configUtils.loadAuth as jest.MockedFunction< - typeof configUtils.loadAuth ->; -const mockClearAuth = configUtils.clearAuth as jest.MockedFunction< - typeof configUtils.clearAuth ->; +const mockLogout = authService.logout as jest.MockedFunction; +const mockLoadAuth = configUtils.loadAuth as jest.MockedFunction; +const mockClearAuth = configUtils.clearAuth as jest.MockedFunction; describe('logoutCommand', () => { let consoleSpy: jest.SpyInstance; @@ -33,9 +27,7 @@ describe('logoutCommand', () => { await logoutCommand(); - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Not logged in') - ); + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Not logged in')); expect(mockClearAuth).not.toHaveBeenCalled(); }); @@ -65,8 +57,6 @@ describe('logoutCommand', () => { await logoutCommand(); expect(mockClearAuth).toHaveBeenCalled(); - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Logged out locally') - ); + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Logged out locally')); }); }); diff --git a/src/commands/logout.ts b/src/commands/logout.ts index ae61e8d..9e31d6b 100644 --- a/src/commands/logout.ts +++ b/src/commands/logout.ts @@ -34,10 +34,6 @@ export const logoutCommand = async (): Promise => { // Even if server logout fails, clear local credentials await clearAuth(); console.log(chalk.green('āœ… Logged out locally.')); - console.log( - chalk.gray( - '(Server logout may have failed, but local credentials cleared)' - ) - ); + console.log(chalk.gray('(Server logout may have failed, but local credentials cleared)')); } }; diff --git a/src/commands/publish.test.ts b/src/commands/publish.test.ts index a38ea80..9b10376 100644 --- a/src/commands/publish.test.ts +++ b/src/commands/publish.test.ts @@ -53,9 +53,7 @@ describe('publishCommand', () => { await expect(publishCommand()).rejects.toThrow('process.exit'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('Not logged in') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Not logged in')); mockExit.mockRestore(); mockConsoleError.mockRestore(); @@ -74,9 +72,7 @@ describe('publishCommand', () => { await expect(publishCommand()).rejects.toThrow('process.exit'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('Session expired') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Session expired')); mockExit.mockRestore(); mockConsoleError.mockRestore(); @@ -114,9 +110,7 @@ You are helpful.`; visibility: 'public', }) ); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('Published') - ); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Published')); mockConsoleLog.mockRestore(); }); @@ -142,9 +136,7 @@ You are helpful.`; await publishCommand(undefined, { dryRun: true }); expect(publishAgent).not.toHaveBeenCalled(); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('Dry run') - ); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Dry run')); mockConsoleLog.mockRestore(); }); @@ -170,9 +162,7 @@ Content`; await expect(publishCommand()).rejects.toThrow('process.exit'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('Invalid agent name') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Invalid agent name')); mockExit.mockRestore(); mockConsoleError.mockRestore(); @@ -280,9 +270,7 @@ Content`; await expect(publishCommand('nonexistent')).rejects.toThrow('process.exit'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('No agent file found') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('No agent file found')); mockExit.mockRestore(); mockConsoleError.mockRestore(); @@ -310,9 +298,7 @@ Content`; await expect(publishCommand()).rejects.toThrow('process.exit'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('must have a name') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('must have a name')); mockExit.mockRestore(); mockConsoleError.mockRestore(); @@ -348,18 +334,13 @@ Content`; test('handles RegistryApiError', async () => { const { getAuthStatus } = require('../utils/config.js'); - const { - publishAgent, - RegistryApiError, - } = require('../services/registry.service.js'); + const { publishAgent, RegistryApiError } = require('../services/registry.service.js'); getAuthStatus.mockResolvedValue({ status: 'authenticated', token: 'test-token', }); - publishAgent.mockRejectedValue( - new RegistryApiError('Version exists', 'version_exists', 409) - ); + publishAgent.mockRejectedValue(new RegistryApiError('Version exists', 'version_exists', 409)); const agentContent = `--- name: my-agent @@ -375,9 +356,7 @@ Content`; await expect(publishCommand()).rejects.toThrow('process.exit'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('Version exists') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Version exists')); mockExit.mockRestore(); mockConsoleError.mockRestore(); @@ -408,12 +387,8 @@ Content`; changelog: 'Initial release', }); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('Tags') - ); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('Changelog') - ); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Tags')); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Changelog')); mockConsoleLog.mockRestore(); }); diff --git a/src/commands/publish.ts b/src/commands/publish.ts index b53ce33..4b5617e 100644 --- a/src/commands/publish.ts +++ b/src/commands/publish.ts @@ -2,15 +2,8 @@ import chalk from 'chalk'; import { existsSync } from 'fs'; import { readdir } from 'fs/promises'; import { join } from 'path'; -import { - publishAgent, - RegistryApiError, -} from '../services/registry.service.js'; -import { - generateDateVersion, - isValidAgentName, - readAgentFile, -} from '../utils/agent-parser.js'; +import { publishAgent, RegistryApiError } from '../services/registry.service.js'; +import { generateDateVersion, isValidAgentName, readAgentFile } from '../utils/agent-parser.js'; import { getAuthStatus } from '../utils/config.js'; interface PublishOptions { @@ -31,9 +24,7 @@ const resolveAgentPath = async (pathArg?: string): Promise => { return pathArg; } // Try adding .agent.md extension - const withExt = pathArg.endsWith('.agent.md') - ? pathArg - : `${pathArg}.agent.md`; + const withExt = pathArg.endsWith('.agent.md') ? pathArg : `${pathArg}.agent.md`; if (existsSync(withExt)) { return withExt; } @@ -52,9 +43,7 @@ const resolveAgentPath = async (pathArg?: string): Promise => { return agentFiles[0]; } if (agentFiles.length > 1) { - console.log( - chalk.yellow('Multiple agent files found. Please specify one:') - ); + console.log(chalk.yellow('Multiple agent files found. Please specify one:')); for (const file of agentFiles) { console.log(` - ${file}`); } @@ -69,9 +58,7 @@ const resolveAgentPath = async (pathArg?: string): Promise => { return join('agents', agentMdFiles[0]); } if (agentMdFiles.length > 1) { - console.log( - chalk.yellow('Multiple agent files found. Please specify one:') - ); + console.log(chalk.yellow('Multiple agent files found. Please specify one:')); for (const file of agentMdFiles) { console.log(` - agents/${file}`); } @@ -107,9 +94,7 @@ export const publishCommand = async ( const agentPath = await resolveAgentPath(pathArg); if (!agentPath) { console.error(chalk.red('āŒ No agent file found.')); - console.log( - 'Specify a path or run from a directory with a .agent.md file.' - ); + console.log('Specify a path or run from a directory with a .agent.md file.'); process.exit(1); } @@ -120,25 +105,18 @@ export const publishCommand = async ( // 4. Validate required fields if (!frontmatter.name) { console.error(chalk.red('āŒ Agent must have a name in frontmatter.')); - console.log( - chalk.gray('Add "name: your-agent-name" to the YAML frontmatter.') - ); + console.log(chalk.gray('Add "name: your-agent-name" to the YAML frontmatter.')); process.exit(1); } if (!isValidAgentName(frontmatter.name)) { console.error(chalk.red('āŒ Invalid agent name.')); - console.log( - chalk.gray( - 'Name must be lowercase alphanumeric with hyphens (e.g., my-agent).' - ) - ); + console.log(chalk.gray('Name must be lowercase alphanumeric with hyphens (e.g., my-agent).')); process.exit(1); } // 5. Determine version - const version = - options.version || frontmatter.version || generateDateVersion(); + const version = options.version || frontmatter.version || generateDateVersion(); const visibility = options.visibility || 'public'; // 6. Dry run check @@ -177,16 +155,8 @@ export const publishCommand = async ( // 8. Success console.log(); - console.log( - chalk.green( - `āœ… Published ${result.owner}/${result.name}@${result.version}` - ) - ); - console.log( - chalk.gray( - ` Install with: agent install ${result.owner}/${result.name}` - ) - ); + console.log(chalk.green(`āœ… Published ${result.owner}/${result.name}@${result.version}`)); + console.log(chalk.gray(` Install with: agent install ${result.owner}/${result.name}`)); console.log(); } catch (error) { if (error instanceof RegistryApiError) { diff --git a/src/commands/run.test.ts b/src/commands/run.test.ts index 0fac657..02346a4 100644 --- a/src/commands/run.test.ts +++ b/src/commands/run.test.ts @@ -35,9 +35,7 @@ variables: {}`; await runCommand('test-agent', 'Hello'); expect(consoleLog).toHaveBeenCalledWith('\nšŸ¤– Running test-agent...\n'); - expect(consoleLog).toHaveBeenCalledWith( - expect.stringContaining('Agent runtime not available') - ); + expect(consoleLog).toHaveBeenCalledWith(expect.stringContaining('Agent runtime not available')); consoleLog.mockRestore(); }); @@ -66,12 +64,8 @@ variables: {}`; }); const consoleError = jest.spyOn(console, 'error').mockImplementation(); - await expect(runCommand('nonexistent')).rejects.toThrow( - 'process.exit called' - ); - expect(consoleError).toHaveBeenCalledWith( - expect.stringContaining('āŒ Failed:') - ); + await expect(runCommand('nonexistent')).rejects.toThrow('process.exit called'); + expect(consoleError).toHaveBeenCalledWith(expect.stringContaining('āŒ Failed:')); expect(mockExit).toHaveBeenCalledWith(1); mockExit.mockRestore(); @@ -90,9 +84,7 @@ model: gpt-4`; const consoleError = jest.spyOn(console, 'error').mockImplementation(); await expect(runCommand('invalid')).rejects.toThrow('process.exit called'); - expect(consoleError).toHaveBeenCalledWith( - expect.stringContaining('āŒ Failed:') - ); + expect(consoleError).toHaveBeenCalledWith(expect.stringContaining('āŒ Failed:')); mockExit.mockRestore(); consoleError.mockRestore(); diff --git a/src/commands/run.ts b/src/commands/run.ts index 1a2bfdf..a10f837 100644 --- a/src/commands/run.ts +++ b/src/commands/run.ts @@ -4,10 +4,7 @@ import { join } from 'path'; import { parse } from 'yaml'; import { agentYamlSchema } from '../schemas/agent.schema.js'; -export const runCommand = async ( - name: string, - prompt?: string -): Promise => { +export const runCommand = async (name: string, prompt?: string): Promise => { try { const agentsDir = 'agents'; const filename = join(agentsDir, `${name}.yml`); @@ -31,9 +28,7 @@ export const runCommand = async ( ) ); console.log( - chalk.gray( - 'To run agents, integrate with an AI provider (OpenAI, Anthropic, etc.) directly.' - ) + chalk.gray('To run agents, integrate with an AI provider (OpenAI, Anthropic, etc.) directly.') ); console.log(); } catch (error) { diff --git a/src/commands/search.test.ts b/src/commands/search.test.ts index a8939c7..a1d3171 100644 --- a/src/commands/search.test.ts +++ b/src/commands/search.test.ts @@ -54,15 +54,9 @@ describe('searchCommand', () => { await searchCommand('test'); expect(mockSearchAgents).toHaveBeenCalledWith('test', 1, 10); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('testuser/test-agent') - ); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('A test agent') - ); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('42 downloads') - ); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('testuser/test-agent')); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('A test agent')); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('42 downloads')); }); test('shows no results message', async () => { @@ -76,9 +70,7 @@ describe('searchCommand', () => { await searchCommand('nonexistent'); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('No agents found') - ); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('No agents found')); }); test('outputs JSON format with --json flag', async () => { @@ -94,9 +86,7 @@ describe('searchCommand', () => { await searchCommand('test', { json: true }); - expect(mockConsoleLog).toHaveBeenCalledWith( - JSON.stringify(mockResult, null, 2) - ); + expect(mockConsoleLog).toHaveBeenCalledWith(JSON.stringify(mockResult, null, 2)); }); test('respects limit and page options', async () => { @@ -131,24 +121,18 @@ describe('searchCommand', () => { await searchCommand('test'); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('--page 2') - ); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('--page 2')); }); test('handles RegistryApiError', async () => { const { RegistryApiError } = require('../services/registry.service.js'); - mockSearchAgents.mockRejectedValue( - new RegistryApiError('Rate limited', 'rate_limit', 429) - ); + mockSearchAgents.mockRejectedValue(new RegistryApiError('Rate limited', 'rate_limit', 429)); const mockConsoleError = jest.spyOn(console, 'error').mockImplementation(); await expect(searchCommand('test')).rejects.toThrow('process.exit(1)'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('Rate limited') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Rate limited')); mockConsoleError.mockRestore(); }); @@ -160,9 +144,7 @@ describe('searchCommand', () => { await expect(searchCommand('test')).rejects.toThrow('process.exit(1)'); - expect(mockConsoleError).toHaveBeenCalledWith( - expect.stringContaining('Network error') - ); + expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Network error')); mockConsoleError.mockRestore(); }); @@ -185,8 +167,6 @@ describe('searchCommand', () => { await searchCommand('test'); - expect(mockConsoleLog).toHaveBeenCalledWith( - expect.stringContaining('No description') - ); + expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('No description')); }); }); diff --git a/src/commands/search.ts b/src/commands/search.ts index 0e106c0..9948a16 100644 --- a/src/commands/search.ts +++ b/src/commands/search.ts @@ -1,8 +1,5 @@ import chalk from 'chalk'; -import { - RegistryApiError, - searchAgents, -} from '../services/registry.service.js'; +import { RegistryApiError, searchAgents } from '../services/registry.service.js'; interface SearchOptions { limit?: string; @@ -13,10 +10,7 @@ interface SearchOptions { /** * Search command - search for agents in registry */ -export const searchCommand = async ( - query: string, - options: SearchOptions = {} -): Promise => { +export const searchCommand = async (query: string, options: SearchOptions = {}): Promise => { try { const limit = options.limit ? parseInt(options.limit, 10) : 10; const page = options.page ? parseInt(options.page, 10) : 1; @@ -38,20 +32,12 @@ export const searchCommand = async ( } // Display results - console.log( - chalk.white.bold( - `Found ${result.total} agent${result.total !== 1 ? 's' : ''}:\n` - ) - ); + console.log(chalk.white.bold(`Found ${result.total} agent${result.total !== 1 ? 's' : ''}:\n`)); for (const agent of result.agents) { console.log(chalk.cyan.bold(` ${agent.owner}/${agent.name}`)); console.log(chalk.gray(` ${agent.description || 'No description'}`)); - console.log( - chalk.gray( - ` v${agent.latestVersion} • ${agent.totalDownloads} downloads` - ) - ); + console.log(chalk.gray(` v${agent.latestVersion} • ${agent.totalDownloads} downloads`)); if (agent.tags && agent.tags.length > 0) { console.log(chalk.gray(` Tags: ${agent.tags.join(', ')}`)); } @@ -62,9 +48,7 @@ export const searchCommand = async ( if (result.hasMore) { console.log( chalk.gray( - `Showing ${result.agents.length} of ${result.total}. Use --page ${ - page + 1 - } for more.` + `Showing ${result.agents.length} of ${result.total}. Use --page ${page + 1} for more.` ) ); } diff --git a/src/commands/update.test.ts b/src/commands/update.test.ts index b3708fa..dfdfcde 100644 --- a/src/commands/update.test.ts +++ b/src/commands/update.test.ts @@ -47,9 +47,7 @@ describe('updateCommand', () => { await updateCommand(); expect(consoleSpy).toHaveBeenCalledWith('šŸ”„ Checking for updates...'); - expect(consoleSpy).toHaveBeenCalledWith( - 'āœ… Already on the latest version (1.0.0)' - ); + expect(consoleSpy).toHaveBeenCalledWith('āœ… Already on the latest version (1.0.0)'); }); it('updates successfully when new version available', async () => { @@ -77,9 +75,7 @@ describe('updateCommand', () => { expect(consoleSpy).toHaveBeenCalledWith( expect.stringContaining('Updating @agentage/cli from 1.0.0 to 2.0.0') ); - expect(consoleSpy).toHaveBeenCalledWith( - 'āœ… Successfully updated to version 2.0.0' - ); + expect(consoleSpy).toHaveBeenCalledWith('āœ… Successfully updated to version 2.0.0'); }); it('handles npm view error', async () => { @@ -98,9 +94,7 @@ describe('updateCommand', () => { await expect(updateCommand()).rejects.toThrow('process.exit called'); - expect(consoleErrorSpy).toHaveBeenCalledWith( - expect.stringContaining('Update failed') - ); + expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Update failed')); expect(processExitSpy).toHaveBeenCalledWith(1); }); @@ -122,9 +116,7 @@ describe('updateCommand', () => { await expect(updateCommand()).rejects.toThrow('process.exit called'); - expect(consoleErrorSpy).toHaveBeenCalledWith( - expect.stringContaining('Update failed') - ); + expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Update failed')); expect(processExitSpy).toHaveBeenCalledWith(1); }); diff --git a/src/commands/update.ts b/src/commands/update.ts index 971f322..7574626 100644 --- a/src/commands/update.ts +++ b/src/commands/update.ts @@ -1,11 +1,7 @@ import chalk from 'chalk'; import { exec } from 'child_process'; import { promisify } from 'util'; -import { - getInstalledVersion, - getLatestVersion, - PACKAGE_NAME, -} from '../utils/version.js'; +import { getInstalledVersion, getLatestVersion, PACKAGE_NAME } from '../utils/version.js'; const execAsync = promisify(exec); @@ -24,16 +20,12 @@ export const updateCommand = async (): Promise => { const latestVersion = await getLatestVersion(); if (latestVersion === 'unknown') { - console.error( - chalk.red('āŒ Failed to fetch latest version from npm registry') - ); + console.error(chalk.red('āŒ Failed to fetch latest version from npm registry')); process.exit(1); } if (previousVersion === latestVersion) { - console.log( - chalk.green(`āœ… Already on the latest version (${latestVersion})`) - ); + console.log(chalk.green(`āœ… Already on the latest version (${latestVersion})`)); return; } @@ -47,9 +39,7 @@ export const updateCommand = async (): Promise => { await execAsync(`npm install -g ${PACKAGE_NAME}@latest`); - console.log( - chalk.green.bold(`āœ… Successfully updated to version ${latestVersion}`) - ); + console.log(chalk.green.bold(`āœ… Successfully updated to version ${latestVersion}`)); } catch (error) { console.error(chalk.red(`āŒ Update failed: ${(error as Error).message}`)); process.exit(1); diff --git a/src/commands/whoami.test.ts b/src/commands/whoami.test.ts index d84eff2..4115a40 100644 --- a/src/commands/whoami.test.ts +++ b/src/commands/whoami.test.ts @@ -13,12 +13,8 @@ jest.mock('../services/auth.service.js', () => { }); jest.mock('../utils/config.js'); -const mockGetMe = authService.getMe as jest.MockedFunction< - typeof authService.getMe ->; -const mockLoadAuth = configUtils.loadAuth as jest.MockedFunction< - typeof configUtils.loadAuth ->; +const mockGetMe = authService.getMe as jest.MockedFunction; +const mockLoadAuth = configUtils.loadAuth as jest.MockedFunction; const mockGetRegistryUrl = configUtils.getRegistryUrl as jest.MockedFunction< typeof configUtils.getRegistryUrl >; @@ -53,9 +49,7 @@ describe('whoamiCommand', () => { await whoamiCommand(); - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Not logged in') - ); + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Not logged in')); }); it('shows expired session when token is locally expired', async () => { @@ -67,9 +61,7 @@ describe('whoamiCommand', () => { await expect(whoamiCommand()).rejects.toThrow('process.exit called'); - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Session expired') - ); + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Session expired')); }); it('displays user info when authenticated', async () => { @@ -91,29 +83,21 @@ describe('whoamiCommand', () => { it('handles session expired error', async () => { mockLoadAuth.mockResolvedValue({ token: 'expired-token' }); - mockGetMe.mockRejectedValue( - new AuthError('Session expired', 'session_expired') - ); + mockGetMe.mockRejectedValue(new AuthError('Session expired', 'session_expired')); await expect(whoamiCommand()).rejects.toThrow('process.exit called'); // The code logs "Session expired." (with period and emoji) - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Session expired') - ); + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Session expired')); }); it('handles not_authenticated error', async () => { mockLoadAuth.mockResolvedValue({ token: 'test-token' }); - mockGetMe.mockRejectedValue( - new AuthError('Not authenticated', 'not_authenticated') - ); + mockGetMe.mockRejectedValue(new AuthError('Not authenticated', 'not_authenticated')); await expect(whoamiCommand()).rejects.toThrow('process.exit called'); - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Not logged in') - ); + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Not logged in')); }); it('handles other AuthError errors', async () => { @@ -122,10 +106,7 @@ describe('whoamiCommand', () => { await expect(whoamiCommand()).rejects.toThrow('process.exit called'); - expect(consoleErrorSpy).toHaveBeenCalledWith( - expect.stringContaining('Error'), - 'Server error' - ); + expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Error'), 'Server error'); }); it('handles non-AuthError errors', async () => { @@ -134,10 +115,7 @@ describe('whoamiCommand', () => { await expect(whoamiCommand()).rejects.toThrow('process.exit called'); - expect(consoleErrorSpy).toHaveBeenCalledWith( - expect.stringContaining('Error'), - 'Network error' - ); + expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Error'), 'Network error'); }); it('displays user without name', async () => { @@ -166,9 +144,6 @@ describe('whoamiCommand', () => { await whoamiCommand(); - expect(consoleSpy).toHaveBeenCalledWith( - ' Alias:', - expect.stringContaining('testuser') - ); + expect(consoleSpy).toHaveBeenCalledWith(' Alias:', expect.stringContaining('testuser')); }); }); diff --git a/src/index.test.ts b/src/index.test.ts index 2139e9f..31df362 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -2,9 +2,9 @@ import { readFileSync } from 'fs'; import { join } from 'path'; // Read package.json directly in test since index.ts uses ESM-specific import.meta -const packageJson = JSON.parse( - readFileSync(join(__dirname, '..', 'package.json'), 'utf-8') -) as { version: string }; +const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8')) as { + version: string; +}; // Mock the index module to avoid import.meta issues in Jest jest.mock('./index.js', () => ({ diff --git a/src/services/auth.service.test.ts b/src/services/auth.service.test.ts index 120696b..52cc082 100644 --- a/src/services/auth.service.test.ts +++ b/src/services/auth.service.test.ts @@ -1,11 +1,5 @@ import * as configUtils from '../utils/config.js'; -import { - AuthError, - getMe, - logout, - pollForToken, - requestDeviceCode, -} from './auth.service.js'; +import { AuthError, getMe, logout, pollForToken, requestDeviceCode } from './auth.service.js'; // Mock the config utils jest.mock('../utils/config.js'); @@ -49,14 +43,11 @@ describe('auth.service', () => { const result = await requestDeviceCode(); expect(result).toEqual(deviceCodeResponse); - expect(mockFetch).toHaveBeenCalledWith( - 'https://dev.agentage.io/api/auth/device/code', - { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ device_id: 'test-device-id-12345678' }), - } - ); + expect(mockFetch).toHaveBeenCalledWith('https://dev.agentage.io/api/auth/device/code', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ device_id: 'test-device-id-12345678' }), + }); }); it('throws AuthError on failure', async () => { @@ -106,9 +97,7 @@ describe('auth.service', () => { json: () => Promise.resolve({ error: 'access_denied' }), }); - await expect(pollForToken('device123', 0.01, 60)).rejects.toThrow( - 'Authorization was denied' - ); + await expect(pollForToken('device123', 0.01, 60)).rejects.toThrow('Authorization was denied'); }); it('throws on expired_token', async () => { @@ -117,9 +106,7 @@ describe('auth.service', () => { json: () => Promise.resolve({ error: 'expired_token' }), }); - await expect(pollForToken('device123', 0.01, 60)).rejects.toThrow( - 'Login timed out' - ); + await expect(pollForToken('device123', 0.01, 60)).rejects.toThrow('Login timed out'); }); it('continues polling on authorization_pending then succeeds', async () => { @@ -191,9 +178,7 @@ describe('auth.service', () => { json: () => Promise.resolve({ error: 'some_error' }), }); - await expect(pollForToken('device123', 0.01, 60)).rejects.toThrow( - 'Authentication failed' - ); + await expect(pollForToken('device123', 0.01, 60)).rejects.toThrow('Authentication failed'); }); }); @@ -213,12 +198,9 @@ describe('auth.service', () => { const result = await getMe(); expect(result).toEqual(user); - expect(mockFetch).toHaveBeenCalledWith( - 'https://dev.agentage.io/api/auth/me', - { - headers: { Authorization: 'Bearer token123' }, - } - ); + expect(mockFetch).toHaveBeenCalledWith('https://dev.agentage.io/api/auth/me', { + headers: { Authorization: 'Bearer token123' }, + }); }); it('throws when not authenticated', async () => { @@ -272,13 +254,10 @@ describe('auth.service', () => { await logout(); - expect(mockFetch).toHaveBeenCalledWith( - 'https://dev.agentage.io/api/auth/logout', - { - method: 'POST', - headers: { Authorization: 'Bearer token123' }, - } - ); + expect(mockFetch).toHaveBeenCalledWith('https://dev.agentage.io/api/auth/logout', { + method: 'POST', + headers: { Authorization: 'Bearer token123' }, + }); }); it('does nothing when not authenticated', async () => { diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts index d132c4b..fe6a4bd 100644 --- a/src/services/auth.service.ts +++ b/src/services/auth.service.ts @@ -10,7 +10,10 @@ import { getAuthToken, getDeviceId, getRegistryUrl } from '../utils/config.js'; * Auth error class */ export class AuthError extends Error { - constructor(message: string, public code: string) { + constructor( + message: string, + public code: string + ) { super(message); this.name = 'AuthError'; } @@ -122,10 +125,7 @@ export const getMe = async (): Promise => { if (!response.ok) { if (response.status === 401) { - throw new AuthError( - 'Session expired. Please login again.', - 'session_expired' - ); + throw new AuthError('Session expired. Please login again.', 'session_expired'); } const error = (await response.json()) as AuthErrorResponse; throw new AuthError( @@ -164,5 +164,4 @@ export const logout = async (): Promise => { /** * Sleep utility */ -const sleep = (ms: number): Promise => - new Promise((resolve) => setTimeout(resolve, ms)); +const sleep = (ms: number): Promise => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/src/services/registry.service.test.ts b/src/services/registry.service.test.ts index 63d7af8..13866b9 100644 --- a/src/services/registry.service.test.ts +++ b/src/services/registry.service.test.ts @@ -169,11 +169,7 @@ describe('Registry Service', () => { const { getAgentVersion } = await import('./registry.service.js'); - const result = await getAgentVersion( - 'testuser', - 'test-agent', - '2025-11-01' - ); + const result = await getAgentVersion('testuser', 'test-agent', '2025-11-01'); expect(result.version).toBe('2025-11-01'); expect(mockFetch).toHaveBeenCalledWith( @@ -211,10 +207,7 @@ describe('Registry Service', () => { }); expect(result.agents).toHaveLength(1); - expect(mockFetch).toHaveBeenCalledWith( - expect.stringContaining('page=1'), - expect.any(Object) - ); + expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining('page=1'), expect.any(Object)); }); test('lists agents without filters', async () => { diff --git a/src/services/registry.service.ts b/src/services/registry.service.ts index 630fd63..945328e 100644 --- a/src/services/registry.service.ts +++ b/src/services/registry.service.ts @@ -27,10 +27,7 @@ export class RegistryApiError extends Error { /** * Make authenticated request to registry API */ -const registryFetch = async ( - path: string, - options: RequestInit = {} -): Promise => { +const registryFetch = async (path: string, options: RequestInit = {}): Promise => { const registryUrl = await getRegistryUrl(); const token = await getAuthToken(); @@ -66,9 +63,7 @@ const registryFetch = async ( /** * Publish an agent to the registry */ -export const publishAgent = async ( - data: PublishRequest -): Promise => { +export const publishAgent = async (data: PublishRequest): Promise => { const response = await registryFetch<{ success: boolean; agent: PublishResponse; @@ -82,10 +77,7 @@ export const publishAgent = async ( /** * Get agent details from registry */ -export const getAgent = async ( - owner: string, - name: string -): Promise => { +export const getAgent = async (owner: string, name: string): Promise => { const response = await registryFetch<{ success: boolean; data: AgentDetail }>( `/api/agents/${encodeURIComponent(owner)}/${encodeURIComponent(name)}` ); @@ -114,11 +106,7 @@ export const getAgentVersion = async ( /** * Search for agents in registry */ -export const searchAgents = async ( - query: string, - page = 1, - limit = 10 -): Promise => { +export const searchAgents = async (query: string, page = 1, limit = 10): Promise => { const params = new URLSearchParams({ q: query, page: String(page), @@ -135,9 +123,7 @@ export const searchAgents = async ( /** * List agents from registry with filters */ -export const listAgents = async ( - filters: ListFilters = {} -): Promise => { +export const listAgents = async (filters: ListFilters = {}): Promise => { const params = new URLSearchParams(); if (filters.page) params.set('page', String(filters.page)); diff --git a/src/utils/config.test.ts b/src/utils/config.test.ts index a4b78c4..daa5b5c 100644 --- a/src/utils/config.test.ts +++ b/src/utils/config.test.ts @@ -65,10 +65,7 @@ describe('config utils', () => { const result = await loadAuth(); expect(result).toEqual(auth); - expect(mockReadFile).toHaveBeenCalledWith( - '/home/testuser/.agentage/auth.json', - 'utf-8' - ); + expect(mockReadFile).toHaveBeenCalledWith('/home/testuser/.agentage/auth.json', 'utf-8'); }); it('returns empty object when file does not exist', async () => { @@ -153,10 +150,7 @@ describe('config utils', () => { const result = await loadAppConfig(); expect(result).toEqual(config); - expect(mockReadFile).toHaveBeenCalledWith( - '/home/testuser/.agentage/config.json', - 'utf-8' - ); + expect(mockReadFile).toHaveBeenCalledWith('/home/testuser/.agentage/config.json', 'utf-8'); }); it('returns empty object when file does not exist', async () => { @@ -380,9 +374,7 @@ describe('config utils', () => { expect(mockWriteFile).toHaveBeenCalled(); const writtenPath = mockWriteFile.mock.calls[0][0] as string; expect(writtenPath).toContain('config.json'); - const savedConfig = JSON.parse( - mockWriteFile.mock.calls[0][1] as string - ) as AppConfig; + const savedConfig = JSON.parse(mockWriteFile.mock.calls[0][1] as string) as AppConfig; expect(savedConfig.deviceId).toBe(result); }); diff --git a/src/utils/version.ts b/src/utils/version.ts index 7d8737e..2ce3ba0 100644 --- a/src/utils/version.ts +++ b/src/utils/version.ts @@ -30,12 +30,9 @@ export interface VersionCheckResult { updateAvailable: boolean; } -export const checkForUpdates = async ( - currentVersion: string -): Promise => { +export const checkForUpdates = async (currentVersion: string): Promise => { const latestVersion = await getLatestVersion(); - const updateAvailable = - latestVersion !== 'unknown' && latestVersion !== currentVersion; + const updateAvailable = latestVersion !== 'unknown' && latestVersion !== currentVersion; return { currentVersion,