@majkapp/majk-chat-basic-tools
v1.0.28
Published
Basic tools package for Magic Chat with filesystem, process, and utility operations
Maintainers
Readme
@majkapp/majk-chat-basic-tools
A comprehensive set of basic tools for Magic Chat that provides essential filesystem operations, process execution, and utility functions. Built using Node.js built-in modules for maximum compatibility and minimal dependencies.
Features
- Bash: Execute bash commands with optional background execution
- KillBash: Terminate background bash processes with different signals
- BashOutput: Monitor and retrieve output from background processes
- LS: List files and directories with detailed information
- Read: Read file contents with configurable limits and offsets
- Glob: Fast file pattern matching using glob patterns
- Grep: Search for text patterns in files using regular expressions
- Edit: Perform exact string replacements in files
- MultiEdit: Make multiple edits to a single file in one operation
- Write: Write content to files with encoding support
- WebFetch: Fetch content from URLs using HTTP/HTTPS
- TodoWrite: Manage structured task lists for session tracking
- ReadToolResult: Read back large tool results that were truncated for LLM context limits
- Pwd: Get the current working directory for tool operations
- Cd: Change the current working directory for tool operations
Working Directory Management
All file and directory operations support both absolute and relative paths. Relative paths are resolved against the current working directory, which defaults to the directory where the CLI was executed.
Key Features
- Relative Path Support: Use
./src/index.js,../docs/readme.md, etc. - Current Directory Tracking: Tools maintain a shared working directory context
- Path Resolution: Automatic resolution of relative paths to absolute paths
- Directory Navigation: Use
cdto change directory,pwdto see current directory
Basic Usage
// Get current working directory
await registry.execute('pwd', {});
// Returns: { current_working_directory: '/Users/project' }
// Change directory
await registry.execute('cd', { path: './src' });
// Now working directory is '/Users/project/src'
// Use relative paths in other tools
await registry.execute('ls', { path: '.' }); // List current directory
await registry.execute('read', { file_path: './index.js' }); // Read file in current dir
await registry.execute('write', {
file_path: '../docs/output.txt', // Write to parent/docs/
content: 'Generated content'
});Path Examples
// Absolute paths (still work as before)
await registry.execute('read', { file_path: '/home/user/project/src/index.js' });
// Relative paths (new functionality)
await registry.execute('read', { file_path: './src/index.js' }); // Current dir/src/index.js
await registry.execute('read', { file_path: '../docs/readme.md' }); // Parent dir/docs/readme.md
await registry.execute('ls', { path: '.' }); // Current directory
await registry.execute('ls', { path: '..' }); // Parent directoryWorking Directory Tools
Pwd Tool
Get the current working directory:
await registry.execute('pwd', {});Returns:
current_working_directory: The directory used for resolving relative pathsprocess_working_directory: The actual Node.js process.cwd()is_same: Whether tool and process directories match
Cd Tool
Change the current working directory:
await registry.execute('cd', { path: './src' }); // Relative change
await registry.execute('cd', { path: '/home/user/docs' }); // Absolute change
await registry.execute('cd', { path: '..' }); // Parent directoryParameters:
path(string, required): Directory to change to (absolute or relative)
Installation
npm install @majkapp/majk-chat-basic-tools @majkapp/majk-chat-coreQuick Start
CLI Integration (Recommended)
The easiest way to use these tools is through the majk-chat CLI:
# Install the CLI globally
npm install -g @majkapp/majk-chat-cli
# Enable core tools for any conversation
majk-chat chat -M "List all JavaScript files and show me package.json" --enable-core-tools
# Start interactive mode with core tools
majk-chat interactive --enable-core-tools
# Customize tool result limits and filtering
majk-chat chat -M "Analyze the codebase" --enable-core-tools --tool-result-limit 4000 --allowed-tools "ls,read,glob,grep"Programmatic Integration
import { ToolRegistry } from '@majkapp/majk-chat-core';
import { registerBasicTools, registerReadOnlyBasicTools } from '@majkapp/majk-chat-basic-tools';
// Create a tool registry
const registry = new ToolRegistry();
// Option 1: Register all basic tools (full access)
registerBasicTools(registry);
// Option 2: Register only read-only tools (safer for untrusted environments)
registerReadOnlyBasicTools(registry);
// Now you can use the registered tools
const result = await registry.execute('read', {
file_path: '/path/to/file.txt'
}, context);Read-Only Tools Registration
For safer operation in untrusted environments or when you want to prevent modifications, use registerReadOnlyBasicTools:
import { registerReadOnlyBasicTools } from '@majkapp/majk-chat-basic-tools';
// Register only tools that don't modify the system
registerReadOnlyBasicTools(registry);
// Available read-only tools:
// - ls, read, glob, grep (file inspection)
// - pwd, cd (navigation)
// - bash_output (monitor processes)
// - todo_write (task management)
// - web_fetch (read web content)
// - read_tool_result (access truncated results)
// These tools are NOT available in read-only mode:
// - bash (cannot execute commands)
// - edit, multi_edit, write (cannot modify files)
// - kill_bash (cannot terminate processes)Individual Tool Usage
import { ReadTool, BashTool } from '@majkapp/majk-chat-basic-tools';
const readTool = new ReadTool();
const bashTool = new BashTool();
// Read a file with specific limits
const readResult = await readTool.execute({
file_path: '/absolute/path/to/file.txt',
offset: 100,
limit: 1000
}, context);
// Execute a bash command
const bashResult = await bashTool.execute({
command: 'ls -la',
working_directory: '/home/user'
}, context);Tool Reference
Bash Tool
Execute bash commands on the local system with optional background execution.
await registry.execute('bash', {
command: 'npm install',
working_directory: '/project',
timeout: 60000,
run_in_background: false
});Parameters:
command(string, required): The bash command to executeworking_directory(string, optional): Working directory for the commandtimeout(number, optional): Timeout in milliseconds (default: 30000, max: 600000)run_in_background(boolean, optional): Run command in background
KillBash Tool
Terminate background bash processes started by the bash tool.
await registry.execute('kill_bash', {
process_id: 'bg_1234567890_abcdef',
signal: 'SIGTERM',
force: true
});Parameters:
process_id(string, required): The background process ID returned by bash toolsignal(string, optional): Signal to send (SIGTERM, SIGKILL, SIGINT, default: SIGTERM)force(boolean, optional): Use SIGKILL if SIGTERM fails (default: false)
BashOutput Tool
Monitor and retrieve output from background bash processes.
// List all background processes
await registry.execute('bash_output', {
list_all: true,
include_finished: true
});
// Get output from specific process
await registry.execute('bash_output', {
process_id: 'bg_1234567890_abcdef',
filter: 'ERROR'
});Parameters:
process_id(string, optional): Process ID to get output fromlist_all(boolean, optional): List all processes instead of getting outputfilter(string, optional): Regex filter for output linesinclude_finished(boolean, optional): Include finished processes in list (default: true)
LS Tool
List files and directories with optional filtering and detailed information.
await registry.execute('ls', {
path: '/absolute/path',
ignore: ['*.tmp', '.git'],
show_hidden: false,
detailed: true
});Parameters:
path(string, required): Absolute path to directoryignore(string[], optional): Glob patterns to ignoreshow_hidden(boolean, optional): Show hidden files (default: false)detailed(boolean, optional): Include file details (default: false)
Read Tool
Read file contents with configurable offset and character limits.
await registry.execute('read', {
file_path: '/absolute/path/to/file.txt',
offset: 0,
limit: 50000,
encoding: 'utf8'
});Parameters:
file_path(string, required): Absolute path to fileoffset(number, optional): Character offset to start reading (default: 0)limit(number, optional): Maximum characters to read (default: 100000)encoding(string, optional): File encoding (utf8, ascii, base64, hex)
Glob Tool
Fast file pattern matching using glob patterns.
await registry.execute('glob', {
pattern: '**/*.js',
path: '/project/src',
case_sensitive: true,
include_hidden: false
});Parameters:
pattern(string, required): Glob pattern (e.g., ".js", "src/**/.ts")path(string, optional): Directory to search (default: current directory)ignore(string[], optional): Patterns to ignorecase_sensitive(boolean, optional): Case sensitive matching (default: true)include_hidden(boolean, optional): Include hidden files (default: false)
Grep Tool
Search for text patterns in files using regular expressions.
await registry.execute('grep', {
pattern: 'function\\s+\\w+',
path: '/project',
file_pattern: '*.js',
case_insensitive: false,
recursive: true,
context_lines: 2
});Parameters:
pattern(string, required): Regular expression patternpath(string, optional): File or directory to searchfile_pattern(string, optional): Glob pattern for files (default: "*")case_insensitive(boolean, optional): Ignore case (default: false)whole_words(boolean, optional): Match whole words only (default: false)line_numbers(boolean, optional): Include line numbers (default: true)context_lines(number, optional): Context lines before/after matches (default: 0)max_matches(number, optional): Maximum matches to return (default: 1000)recursive(boolean, optional): Search recursively (default: true)
Edit Tool
Perform exact string replacements in files.
// Using relative paths (recommended)
await registry.execute('edit', {
file_path: './src/config.js',
old_string: 'const oldValue = 42;',
new_string: 'const newValue = 100;',
replace_all: false,
create_backup: true
});
// Absolute paths also work
await registry.execute('edit', {
file_path: '/home/user/project/src/config.js',
old_string: 'const oldValue = 42;',
new_string: 'const newValue = 100;'
});Parameters:
file_path(string, required): Path to file (absolute or relative)old_string(string, required): Exact text to findnew_string(string, required): Replacement textreplace_all(boolean, optional): Replace all occurrences (default: false)create_backup(boolean, optional): Create backup before editing (default: false)
MultiEdit Tool
Make multiple edits to a single file in one atomic operation.
await registry.execute('multi_edit', {
file_path: '/absolute/path/to/file.js',
edits: [
{
old_string: 'var x = 1;',
new_string: 'let x = 1;'
},
{
old_string: 'var y = 2;',
new_string: 'let y = 2;',
replace_all: true
}
],
create_backup: true
});Parameters:
file_path(string, required): Absolute path to fileedits(EditOperation[], required): Array of edit operationscreate_backup(boolean, optional): Create backup before editing (default: false)
Write Tool
Write content to files with encoding support.
// Using relative paths (recommended)
await registry.execute('write', {
file_path: './output/results.txt',
content: 'File contents here',
encoding: 'utf8',
create_directories: true,
overwrite: true
});
// Absolute paths also work
await registry.execute('write', {
file_path: '/home/user/project/output/results.txt',
content: 'File contents here'
});Parameters:
file_path(string, required): Path to file (absolute or relative)content(string, required): Content to writeencoding(string, optional): File encoding (utf8, ascii, base64, hex)create_directories(boolean, optional): Create parent directories (default: true)overwrite(boolean, optional): Overwrite existing files (default: true)
WebFetch Tool
Fetch content from URLs using HTTP/HTTPS requests.
await registry.execute('web_fetch', {
url: 'https://api.example.com/data',
method: 'GET',
headers: { 'Authorization': 'Bearer token' },
timeout: 30000,
follow_redirects: true
});Parameters:
url(string, required): URL to fetchmethod(string, optional): HTTP method (GET, POST, PUT, DELETE, PATCH)headers(object, optional): HTTP headersbody(string, optional): Request body for POST/PUT/PATCHtimeout(number, optional): Request timeout (default: 30000)follow_redirects(boolean, optional): Follow redirects (default: true)max_response_size(number, optional): Max response size in bytes (default: 10MB)
TodoWrite Tool
Manage structured task lists for session tracking.
await registry.execute('todo_write', {
todos: [
{
content: 'Implement user authentication',
status: 'pending',
activeForm: 'Implementing user authentication',
priority: 'high',
tags: ['auth', 'security']
},
{
content: 'Write unit tests',
status: 'in_progress',
activeForm: 'Writing unit tests'
}
],
instance_id: 'project-123',
action: 'replace'
});Parameters:
todos(TodoItem[], required): Array of todo itemsinstance_id(string, optional): Session identifier (default: "default")action(string, optional): How to handle the list (replace, append, update)
Configuration
You can configure the tools when registering them:
import { registerBasicTools, BasicToolsConfig } from '@majkapp/majk-chat-basic-tools';
const config: BasicToolsConfig = {
bashRequiresConfirmation: true,
writeRequiresConfirmation: true,
webFetchRequiresConfirmation: true,
webFetchTimeout: 30000,
maxReadSize: 100000,
createBackups: false
};
registerBasicTools(registry, config);🔍 Dry Run System
The dry run system provides safe operation planning and approval workflows, allowing you to preview and control tool execution:
Core Components
- DryRunManager: Central coordinator for dry run sessions
- DryRunStore: Storage for planned operations with session management
- Tool Wrappers: Dry run versions of all tools that capture instead of execute
- InteractiveReviewer: CLI interface for reviewing and approving operations
- OperationExecutor: Executes approved operations using real tools
Basic Usage
import { DryRunManager, dryRunStore } from '@majkapp/majk-chat-basic-tools';
// Create a dry run session
const dryRunManager = new DryRunManager(toolRegistry, {
interactive: true,
showPreview: true
});
const sessionId = dryRunManager.startDryRun();
// Now all tool operations will be captured instead of executed
const result = await registry.execute('write', {
file_path: '/tmp/test.txt',
content: 'Hello World'
});
// Result contains planning information instead of actual execution
console.log('Operation planned:', result.output.operationId);
// Review and execute approved operations
await dryRunManager.reviewAndExecute(sessionId, context);Dry Run Tool Wrappers
Each tool has a corresponding dry run wrapper:
- WriteDryRunTool: Simulates file writes, shows content diffs
- EditDryRunTool: Shows edit operations with match counts and previews
- MultiEditDryRunTool: Simulates multiple edits with aggregate effects
- BashDryRunTool: Analyzes commands for safety, shows potential effects
- GenericDryRunTool: Fallback wrapper for any tool
Operation Planning
// Example of planned operation structure
interface PlannedOperation {
id: string;
toolName: string;
args: any;
description: string; // Human-readable description
preview?: string; // Detailed preview (diffs, effects, etc.)
timestamp: Date;
status: 'pending' | 'approved' | 'rejected' | 'executed';
category: 'filesystem' | 'process' | 'network' | 'other';
riskLevel: 'low' | 'medium' | 'high';
}Risk Assessment
The system automatically assesses operation risk:
// High risk examples
- System paths (/usr/, /bin/, /etc/)
- Destructive commands (rm -rf, sudo)
- Large operations (>50KB files, >10 edits)
- Dangerous content (eval, exec, script downloads)
// Medium risk examples
- Config files (.env, package.json)
- Package operations (npm install, git operations)
- Network requests
- Multiple edits (5+ operations)
// Low risk examples
- Simple file reads
- Basic text edits
- Safe bash commands (ls, pwd, echo)Session Management
// Get planned operations
const operations = dryRunStore.getOperations(sessionId);
// Get session statistics
const stats = dryRunStore.getSessionStats(sessionId);
console.log(`${stats.pending} pending, ${stats.approved} approved`);
// Apply review decisions
dryRunStore.applyReviewDecisions(sessionId, [
{ operationId: 'op1', action: 'approve' },
{ operationId: 'op2', action: 'reject' }
]);
// Execute approved operations
const executor = new OperationExecutor(toolRegistry, context);
await executor.executeApprovedOperations(sessionId);CLI Integration
The dry run system integrates seamlessly with the CLI:
# Plan operations without executing
majk-chat chat --dry-run --enable-core-tools -M "Set up a new project"
# Interactive review and execution
majk-chat chat --dry-run-review --enable-core-tools -M "Refactor and test the codebase"Background Process Management
The package includes comprehensive background process management capabilities:
Starting Background Processes
// Start a long-running task in the background
const result = await registry.execute('bash', {
command: 'npm run build && npm test',
working_directory: '/project',
run_in_background: true
});
const processId = result.output.background_id;
console.log(`Started background process: ${processId}`);Monitoring Process Output
// List all background processes
const listResult = await registry.execute('bash_output', {
list_all: true
});
// Get output from a specific process
const outputResult = await registry.execute('bash_output', {
process_id: processId,
filter: 'ERROR' // Optional regex filter
});
console.log('Process status:', outputResult.output.status.running ? 'Running' : 'Finished');
console.log('Output:', outputResult.output.stdout);Terminating Processes
// Graceful termination
await registry.execute('kill_bash', {
process_id: processId,
signal: 'SIGTERM'
});
// Force termination if needed
await registry.execute('kill_bash', {
process_id: processId,
signal: 'SIGTERM',
force: true // Will use SIGKILL if SIGTERM fails
});Process Registry
Direct access to the process registry for advanced use cases:
import { ProcessRegistry } from '@majkapp/majk-chat-basic-tools';
// Get all running processes
const runningProcesses = ProcessRegistry.getRunning();
// Get process status
const status = ProcessRegistry.getStatus(processId);
// Manual cleanup of old processes
ProcessRegistry.cleanup();Tool Result Management
Context management and result truncation is now handled by the ContextManagementExtension in @majkapp/majk-chat-core. The basic-tools package provides the ReadToolResultTool for accessing truncated results.
Automatic Result Truncation (via Core Extension)
import { MajkChatBuilder, ContextManagementExtension } from '@majkapp/majk-chat-core';
import { registerBasicTools } from '@majkapp/majk-chat-basic-tools';
// Setup with automatic truncation via extension
const builder = new MajkChatBuilder()
.withOpenAI()
.withContextManagement({
maxLength: 6000, // Max characters before truncation
conversationId: 'chat-123'
});
// Or use extension directly for custom configuration
const customExtension = new ContextManagementExtension({
maxLength: 8000,
previewLength: 4800,
tailLength: 2400,
conversationId: 'custom-chat'
});
builder.withExtension(customExtension);Reading Stored Results
// Read the full result back in chunks
const readResult = await registry.execute('read_tool_result', {
result_id: 'conv_1234567890_abcdef',
offset: 0,
limit: 5000,
format: 'formatted' // Options: 'raw', 'formatted', 'json'
});
// Navigate through large results
if (readResult.output.reading_info.has_more) {
const nextChunk = await registry.execute('read_tool_result', {
result_id: 'conv_1234567890_abcdef',
offset: readResult.output.reading_info.next_offset,
limit: 5000
});
}Searching Within Results
// Search for specific patterns within stored results
const searchResult = await registry.execute('read_tool_result', {
result_id: 'conv_1234567890_abcdef',
search: 'ERROR|WARN', // Regex pattern
limit: 2000
});
console.log(`Found ${searchResult.output.matches_found} matches`);
searchResult.output.matches.forEach(match => {
console.log(`"${match.match}" at line ${match.line_number}`);
});Listing Stored Results
// List all stored results for the current conversation
const listResult = await registry.execute('read_tool_result', {
result_id: 'dummy',
list_results: true
});
console.log(`${listResult.output.stored_results.length} results available`);
listResult.output.stored_results.forEach(result => {
console.log(`${result.result_id}: ${result.tool_name} (${result.length} chars)`);
});Result Storage Management
Note: Truncation and storage is automatically handled by the ContextManagementExtension in core. The following utilities are available for advanced usage:
Registry Management
import { ResultStorage } from '@majkapp/majk-chat-core';
// Get statistics about stored results
const stats = ResultStorage.getStats();
console.log(`Total results: ${stats.totalResults}`);
console.log(`Total size: ${stats.totalSize} characters`);
// Manual cleanup of conversation results
ResultStorage.clearConversation('old-conversation-id');
// List results for a conversation
const results = ResultStorage.listForConversation('chat-123');ReadToolResult Tool
The read_tool_result tool provides Read-like functionality for stored results:
await registry.execute('read_tool_result', {
result_id: 'conv_1234567890_abcdef', // Required: stored result ID
offset: 1000, // Optional: start position
limit: 2000, // Optional: max characters
format: 'formatted', // Optional: output format
search: 'pattern', // Optional: search within result
list_results: false // Optional: list all results
});Parameters:
result_id(string, required): The stored result ID from truncated outputoffset(number, optional): Character offset to start reading (default: 0)limit(number, optional): Maximum characters to read (default: 10000)format(string, optional): Output format - raw, formatted, json (default: formatted)search(string, optional): Regex pattern to search for within the resultlist_results(boolean, optional): List available results instead of reading
Safety Features
All tools include built-in safety features:
- Path Resolution: Both absolute and relative paths supported with proper resolution
- Working Directory Context: Shared working directory context across all file operations
- Permission Checks: Tools respect filesystem permissions and access controls
- Size Limits: File operations have configurable size limits to prevent memory issues
- Timeout Protection: Network and process operations have configurable timeouts
- Confirmation Requirements: Destructive operations can require user confirmation
- Error Handling: Comprehensive error messages with both original and resolved paths
- Path Information: All file operations return path resolution details for transparency
Integration Examples
Express.js API
import express from 'express';
import { ToolRegistry } from '@majkapp/majk-chat-core';
import { registerBasicTools } from '@majkapp/majk-chat-basic-tools';
const app = express();
const registry = new ToolRegistry();
registerBasicTools(registry);
app.post('/api/tools/:toolName', async (req, res) => {
try {
const result = await registry.execute(
req.params.toolName,
req.body,
{ sessionId: req.headers['session-id'] }
);
res.json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
});CLI Application
#!/usr/bin/env node
import { ToolRegistry } from '@majkapp/majk-chat-core';
import { registerBasicTools } from '@majkapp/majk-chat-basic-tools';
const registry = new ToolRegistry();
registerBasicTools(registry);
async function main() {
const [toolName, ...args] = process.argv.slice(2);
const result = await registry.execute(
toolName,
JSON.parse(args[0] || '{}'),
{ sessionId: 'cli' }
);
console.log(JSON.stringify(result, null, 2));
}
main().catch(console.error);TypeScript Support
The package includes full TypeScript definitions:
import { BashArgs, ReadArgs, EditArgs } from '@majkapp/majk-chat-basic-tools';
// Type-safe tool arguments
const bashArgs: BashArgs = {
command: 'ls -la',
working_directory: '/home'
};
const readArgs: ReadArgs = {
file_path: '/path/to/file.txt',
offset: 0,
limit: 1000
};Error Handling
All tools return structured results:
interface ToolResult {
success: boolean;
output?: any;
error?: string;
metadata?: Record<string, any>;
}Example error handling:
const result = await registry.execute('read', { file_path: '/nonexistent' });
if (!result.success) {
console.error('Tool failed:', result.error);
} else {
console.log('File content:', result.output.content);
}Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass:
npm test - Submit a pull request
License
MIT
