Files
zeekay ac2000708d feat: HIP-0300 unified tool architecture (TS + Rust)
Implement 13 canonical tools organized by axis:
- Core (7): fs, exec, code, git, fetch, workspace, ui
- Optional (6): think, memory, hanzo, plan, tasks, mode

Key changes:
- Add src/tools/unified/ with action-routed tool implementations
- Add Rust native tools: exec, git, fetch, code, hanzo, tasks, workspace, computer
- Refactor tool index to default to unified surface (legacy available via enableLegacy)
- Simplify tests to match new architecture (337 tests, 15 suites pass)
- Update LLM.md with HIP-0300 architecture documentation
- Remove legacy shell_tool.rs and ui_tool/ (replaced by exec_tool.rs and computer_tool/)
- Stop tracking rust/target/.rustc_info.json
2026-03-11 11:37:15 -07:00

426 lines
9.6 KiB
TypeScript

/**
* Test specifications for core MCP tools
*/
import { ToolTestSpec } from '../src/types.js';
export const coreToolSpecs: ToolTestSpec[] = [
// File Operations
{
name: 'read',
category: 'files',
description: 'Test file reading functionality',
testCases: [
{
name: 'read existing text file',
input: { path: '/tmp/test-file.txt' },
expect: {
success: true,
content: [
{
type: 'text',
minLength: 0
}
]
},
setup: async () => {
// Create test file
require('fs').writeFileSync('/tmp/test-file.txt', 'Hello, World!');
},
cleanup: async () => {
// Clean up test file
require('fs').unlinkSync('/tmp/test-file.txt');
}
},
{
name: 'read non-existent file',
input: { path: '/non/existent/file.txt' },
expect: {
success: false,
errorPattern: 'ENOENT|no such file'
}
},
{
name: 'read with encoding',
input: { path: '/tmp/test-utf8.txt', encoding: 'utf8' },
expect: {
success: true,
content: [
{
type: 'text',
textPattern: 'UTF-8 content'
}
]
},
setup: async () => {
require('fs').writeFileSync('/tmp/test-utf8.txt', 'UTF-8 content with émojis 🎉');
},
cleanup: async () => {
require('fs').unlinkSync('/tmp/test-utf8.txt');
}
}
]
},
{
name: 'write',
category: 'files',
description: 'Test file writing functionality',
testCases: [
{
name: 'write to new file',
input: { path: '/tmp/test-write.txt', content: 'Test content' },
expect: {
success: true,
content: [
{
type: 'text',
textPattern: 'successfully|written'
}
]
},
cleanup: async () => {
require('fs').unlinkSync('/tmp/test-write.txt');
}
},
{
name: 'overwrite existing file',
input: { path: '/tmp/test-overwrite.txt', content: 'New content' },
expect: {
success: true
},
setup: async () => {
require('fs').writeFileSync('/tmp/test-overwrite.txt', 'Old content');
},
cleanup: async () => {
require('fs').unlinkSync('/tmp/test-overwrite.txt');
}
},
{
name: 'write to invalid path',
input: { path: '/invalid/path/file.txt', content: 'Test' },
expect: {
success: false,
errorPattern: 'ENOENT|permission denied|no such file'
}
}
]
},
{
name: 'list',
category: 'files',
description: 'Test directory listing functionality',
testCases: [
{
name: 'list current directory',
input: { path: '.' },
expect: {
success: true,
content: [
{
type: 'text',
minLength: 10
}
]
}
},
{
name: 'list with hidden files',
input: { path: '.', showHidden: true },
expect: {
success: true
}
},
{
name: 'list non-existent directory',
input: { path: '/non/existent/dir' },
expect: {
success: false,
errorPattern: 'ENOENT|no such file'
}
}
]
},
{
name: 'info',
category: 'files',
description: 'Test file metadata retrieval',
testCases: [
{
name: 'get info for existing file',
input: { path: '/tmp/info-test.txt' },
expect: {
success: true,
content: [
{
type: 'text',
textPattern: 'size|modified|type'
}
]
},
setup: async () => {
require('fs').writeFileSync('/tmp/info-test.txt', 'Test file for info');
},
cleanup: async () => {
require('fs').unlinkSync('/tmp/info-test.txt');
}
},
{
name: 'get info for non-existent file',
input: { path: '/non/existent/file.txt' },
expect: {
success: false,
errorPattern: 'ENOENT|no such file'
}
}
]
},
{
name: 'tree',
category: 'files',
description: 'Test directory tree visualization',
testCases: [
{
name: 'tree of current directory',
input: { path: '.' },
expect: {
success: true,
content: [
{
type: 'text',
minLength: 20
}
]
}
},
{
name: 'tree with depth limit',
input: { path: '.', depth: 2 },
expect: {
success: true
}
}
]
},
// Search Tools
{
name: 'grep',
category: 'search',
description: 'Test grep search functionality',
testCases: [
{
name: 'search in file',
input: { pattern: 'test', files: ['/tmp/grep-test.txt'] },
expect: {
success: true,
content: [
{
type: 'text',
textPattern: 'test'
}
]
},
setup: async () => {
require('fs').writeFileSync('/tmp/grep-test.txt', 'This is a test file\nwith test content');
},
cleanup: async () => {
require('fs').unlinkSync('/tmp/grep-test.txt');
}
},
{
name: 'case insensitive search',
input: { pattern: 'TEST', files: ['/tmp/grep-case.txt'], caseInsensitive: true },
expect: {
success: true,
content: [
{
type: 'text',
textPattern: 'test|TEST'
}
]
},
setup: async () => {
require('fs').writeFileSync('/tmp/grep-case.txt', 'test content');
},
cleanup: async () => {
require('fs').unlinkSync('/tmp/grep-case.txt');
}
},
{
name: 'no matches found',
input: { pattern: 'nonexistent', files: ['/tmp/grep-empty.txt'] },
expect: {
success: true,
content: [
{
type: 'text',
textPattern: 'no matches|not found|0 matches'
}
]
},
setup: async () => {
require('fs').writeFileSync('/tmp/grep-empty.txt', 'some other content');
},
cleanup: async () => {
require('fs').unlinkSync('/tmp/grep-empty.txt');
}
}
]
},
{
name: 'find',
category: 'search',
description: 'Test file finding by pattern',
testCases: [
{
name: 'find by extension',
input: { pattern: '*.txt', directory: '/tmp' },
expect: {
success: true
}
},
{
name: 'find by name pattern',
input: { pattern: 'test-*', directory: '/tmp' },
expect: {
success: true
}
}
]
},
{
name: 'search',
category: 'search',
description: 'Test unified search functionality',
testCases: [
{
name: 'basic text search',
input: { query: 'function', path: '.' },
expect: {
success: true
}
},
{
name: 'search with file type filter',
input: { query: 'export', path: '.', fileTypes: ['ts', 'js'] },
expect: {
success: true
}
}
]
},
// Shell Tools
{
name: 'bash',
category: 'shell',
description: 'Test bash command execution',
testCases: [
{
name: 'simple echo command',
input: { command: 'echo "Hello, World!"' },
expect: {
success: true,
content: [
{
type: 'text',
textPattern: 'Hello, World!'
}
]
}
},
{
name: 'ls command',
input: { command: 'ls -la' },
expect: {
success: true,
content: [
{
type: 'text',
minLength: 10
}
]
}
},
{
name: 'invalid command',
input: { command: 'nonexistentcommand' },
expect: {
success: false,
errorPattern: 'command not found|not recognized'
}
},
{
name: 'command with timeout',
input: { command: 'sleep 0.1', timeout: 1000 },
expect: {
success: true
}
}
]
},
{
name: 'bg',
category: 'shell',
description: 'Test background process execution',
testCases: [
{
name: 'start background process',
input: { command: 'sleep 1' },
expect: {
success: true,
content: [
{
type: 'text',
textPattern: 'background|process|started'
}
]
}
}
]
},
{
name: 'ps',
category: 'shell',
description: 'Test background process listing',
testCases: [
{
name: 'list running processes',
input: {},
expect: {
success: true,
content: [
{
type: 'text',
minLength: 0 // May be empty if no background processes
}
]
}
}
]
},
{
name: 'kill',
category: 'shell',
description: 'Test process termination',
testCases: [
{
name: 'kill non-existent process',
input: { processId: 'nonexistent' },
expect: {
success: false,
errorPattern: 'not found|invalid|does not exist'
}
}
]
}
];