
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
@probelabs/probe
Advanced tools
A Node.js wrapper for the probe code search tool.
npm install @probelabs/probe
npm install -g @probelabs/probe
During installation, the package will automatically download the appropriate probe binary for your platform.
import { search, query, extract } from '@probelabs/probe';
// Search for code
const searchResults = await search({
path: '/path/to/your/project',
query: 'function',
maxResults: 10
});
// Query for specific code structures
const queryResults = await query({
path: '/path/to/your/project',
pattern: 'function $NAME($$$PARAMS) $$$BODY',
language: 'javascript'
});
// Extract code blocks
const extractResults = await extract({
files: ['/path/to/your/project/src/main.js:42']
});
When installed globally, the probe command will be available directly from the command line:
# Search for code
probe search "function" /path/to/your/project
# Query for specific code structures
probe query "function $NAME($$$PARAMS) $$$BODY" /path/to/your/project
# Extract code blocks
probe extract /path/to/your/project/src/main.js:42
# Run MCP server for AI assistant integration
probe mcp
The package installs the actual probe binary, not a JavaScript wrapper, so you get the full native performance and all features of the original probe CLI.
ProbeAgent provides a high-level AI-powered interface for interacting with your codebase:
import { ProbeAgent } from '@probelabs/probe';
// Create an AI agent for your project
const agent = new ProbeAgent({
sessionId: 'my-session', // Optional: for conversation continuity
path: '/path/to/your/project',
provider: 'anthropic', // or 'openai', 'google'
model: 'claude-sonnet-4-6', // Optional: override model
allowEdit: true, // Optional: enable edit + create tools for code modification
debug: true, // Optional: enable debug logging
allowedTools: ['*'], // Optional: filter available tools (see Tool Filtering below)
enableMcp: true, // Optional: enable MCP tool integration
mcpConfig: { // Optional: MCP configuration (see MCP section below)
mcpServers: {...}
}
});
// Ask questions about your codebase
const answer = await agent.answer("How does authentication work in this codebase?");
console.log(answer);
// The agent maintains conversation history automatically
const followUp = await agent.answer("Can you show me the login implementation?");
console.log(followUp);
// Get token usage statistics
const usage = agent.getTokenUsage();
console.log(`Used ${usage.total} tokens total`);
// Clear conversation history if needed
agent.history = [];
Environment Variables:
# Set your API key for the chosen provider
export ANTHROPIC_API_KEY=your_anthropic_key
export OPENAI_API_KEY=your_openai_key
export GOOGLE_API_KEY=your_google_key
# Optional: Force a specific provider
export FORCE_PROVIDER=anthropic
# Optional: Override model name
export MODEL_NAME=claude-sonnet-4-6
ProbeAgent Features:
ProbeAgent supports three timeout behaviors (graceful, hard, negotiated) for controlling what happens when maxOperationTimeout is reached. The negotiated mode uses an independent observer LLM call that works even when the main loop is blocked by delegates. Delegates inherit timeout settings from the parent and are budget-aware — their timeout is capped to the parent's remaining budget. MCP servers that expose a graceful_stop tool get cooperative shutdown signals.
See Timeout Architecture for the full reference.
ProbeAgent can discover and activate Agent Skills stored inside your repository. Place skills under:
.claude/skills/<skill-name>/SKILL.md.codex/skills/<skill-name>/SKILL.mdskills/<skill-name>/SKILL.md.skills/<skill-name>/SKILL.mdSKILL.md should contain YAML frontmatter followed by Markdown instructions. Example:
---
name: onboarding
description: Help new engineers understand the repo structure and conventions.
---
Use this skill to explain key modules, build steps, and common workflows.
Then in the agent loop you can call:
<listSkills></listSkills>
or:
<useSkill>
<name>onboarding</name>
</useSkill>
ProbeAgent includes comprehensive retry and fallback capabilities for maximum reliability:
import { ProbeAgent } from '@probelabs/probe';
const agent = new ProbeAgent({
path: '/path/to/your/project',
// Configure retry behavior
retry: {
maxRetries: 5, // Retry up to 5 times per provider
initialDelay: 1000, // Start with 1 second delay
maxDelay: 30000, // Cap delays at 30 seconds
backoffFactor: 2 // Double the delay each time
},
// Configure provider fallback
fallback: {
strategy: 'custom',
providers: [
{
provider: 'anthropic',
apiKey: process.env.ANTHROPIC_API_KEY,
model: 'claude-3-7-sonnet-20250219',
maxRetries: 5 // Can override retry config per provider
},
{
provider: 'bedrock',
region: 'us-west-2',
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
model: 'anthropic.claude-sonnet-4-6'
},
{
provider: 'openai',
apiKey: process.env.OPENAI_API_KEY,
model: 'gpt-5.2'
}
],
maxTotalAttempts: 15 // Maximum attempts across all providers
}
});
// API calls automatically retry on failures and fallback to other providers
const answer = await agent.answer("Explain this codebase");
Retry & Fallback Features:
Quick Setup with Auto-Fallback:
# Set all your API keys
export ANTHROPIC_API_KEY=sk-ant-xxx
export OPENAI_API_KEY=sk-xxx
export GOOGLE_API_KEY=xxx
export AUTO_FALLBACK=1 # Enable automatic fallback
export MAX_RETRIES=5 # Configure retry limit
// No configuration needed - uses all available providers automatically!
const agent = new ProbeAgent({
path: '/path/to/your/project',
fallback: { auto: true }
});
See docs/RETRY_AND_FALLBACK.md for complete documentation and examples.
ProbeAgent supports filtering available tools to control what operations the AI can perform. This is useful for security, cost control, or limiting functionality to specific use cases.
import { ProbeAgent } from '@probelabs/probe';
// Allow all tools (default behavior)
const agent1 = new ProbeAgent({
path: '/path/to/project',
allowedTools: ['*'] // or undefined
});
// Allow only specific tools (whitelist mode)
const agent2 = new ProbeAgent({
path: '/path/to/project',
allowedTools: ['search', 'query', 'extract']
});
// Allow all except specific tools (exclusion mode)
const agent3 = new ProbeAgent({
path: '/path/to/project',
allowedTools: ['*', '!bash', '!implement']
});
// Raw AI mode - no tools at all
const agent4 = new ProbeAgent({
path: '/path/to/project',
allowedTools: [] // or use disableTools: true
});
// Convenience flag for raw AI mode (better DX)
const agent5 = new ProbeAgent({
path: '/path/to/project',
disableTools: true // Clearer than allowedTools: []
});
Available Tools:
search - Semantic code searchquery - Tree-sitter pattern matchingextract - Extract code blockssymbols - List all symbols in a file with line numberslistFiles - List files and directoriessearchFiles - Find files by glob patternbash - Execute bash commands (requires enableBash: true)edit - Edit files with text replacement, AST-aware symbol editing, or line-targeted editing (requires allowEdit: true)create - Create new files (requires allowEdit: true)delegate - Delegate tasks to subagents (requires enableDelegate: true)attempt_completion - Signal task completionmcp__* - MCP tools use the mcp__ prefix (e.g., mcp__filesystem__read_file)MCP Tool Filtering:
MCP tools follow the mcp__toolname naming convention. You can:
allowedTools: ['*']allowedTools: ['mcp__filesystem__read_file']allowedTools: ['mcp__filesystem__*'] (using pattern matching)allowedTools: ['*', '!mcp__*']CLI Usage:
# Allow only search and extract tools
probe agent "Explain this code" --allowed-tools search,extract
# Raw AI mode (no tools) - option 1
probe agent "What is this project about?" --allowed-tools none
# Raw AI mode (no tools) - option 2 (better DX)
probe agent "Tell me about this project" --disable-tools
# All tools (default)
probe agent "Analyze the architecture" --allowed-tools all
Notes:
allowEdit, enableBash, enableDelegate)allowedTools must permit a tool for it to be availableallowedTools: [] for pure conversational AI without code analysis toolsProbe provides built-in code modification tools that work across all interfaces. The edit tool supports four modes: text-based find/replace with fuzzy matching, AST-aware symbol replacement, symbol insertion, and line-targeted editing with optional hash-based integrity verification.
CLI Agent:
# Enable with --allow-edit flag
probe agent "Fix the bug in auth.js" --allow-edit --path ./my-project
# Enable with environment variable
ALLOW_EDIT=1 probe agent "Refactor the login flow" --path ./my-project
SDK (ProbeAgent):
import { ProbeAgent } from '@probelabs/probe';
const agent = new ProbeAgent({
path: '/path/to/project',
allowEdit: true, // enables edit + create tools
// hashLines defaults to true when allowEdit is true (line integrity verification)
provider: 'anthropic'
});
// The agent can now modify files when answering questions
const answer = await agent.answer("Fix the off-by-one error in calculateTotal");
SDK (Standalone Tools):
import { editTool, createTool } from '@probelabs/probe';
const edit = editTool({
allowedFolders: ['/path/to/project'],
cwd: '/path/to/project'
});
const create = createTool({
allowedFolders: ['/path/to/project'],
cwd: '/path/to/project'
});
| Mode | Parameters | Use Case |
|---|---|---|
| Text edit | old_string + new_string | Small, precise changes: fix a condition, rename a variable, update a value |
| Symbol replace | symbol + new_string | Replace an entire function/class/method by name (AST-aware, 16 languages) |
| Symbol insert | symbol + new_string + position | Insert new code before or after an existing symbol |
| Line-targeted edit | start_line + new_string | Edit specific lines from extract/search output; ideal for changes inside large functions |
| Parameter | Required | Description |
|---|---|---|
file_path | Yes | Path to the file to edit (absolute or relative to cwd) |
new_string | Yes | Replacement text or new code content |
old_string | No | Text to find and replace. Copy verbatim from the file. |
replace_all | No | Replace all occurrences (default: false, text mode only) |
symbol | No | Code symbol name for AST-aware editing (e.g. "myFunction", "MyClass.myMethod") |
position | No | "before" or "after" — insert near the symbol or line instead of replacing it |
start_line | No | Line reference for line-targeted editing (e.g. "42" or "42:ab" with hash) |
end_line | No | End of line range, inclusive (e.g. "55" or "55:cd"). Defaults to start_line. |
Text edit — find and replace:
await edit.execute({
file_path: 'src/main.js',
old_string: 'return false;',
new_string: 'return true;'
});
// => "Successfully edited src/main.js (1 replacement)"
Text edit — fuzzy matching handles whitespace differences:
// File has: " const x = 1;" (2-space indent)
// Your search string omits the indent — fuzzy matching finds it anyway
await edit.execute({
file_path: 'src/main.js',
old_string: 'const x = 1;',
new_string: ' const x = 2;'
});
// => "Successfully edited src/main.js (1 replacement, matched via line-trimmed)"
Symbol replace — rewrite a function by name:
await edit.execute({
file_path: 'src/utils.js',
symbol: 'calculateTotal',
new_string: `function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}`
});
// => "Successfully replaced symbol "calculateTotal" in src/utils.js (was lines 10-15, now 3 lines)"
Symbol insert — add a new function after an existing one:
await edit.execute({
file_path: 'src/utils.js',
symbol: 'calculateTotal',
position: 'after',
new_string: `function calculateTax(total, rate) {
return total * rate;
}`
});
// => "Successfully inserted 3 lines after symbol "calculateTotal" in src/utils.js (at line 16)"
Line-targeted edit — edit specific lines from extract output:
// After extracting "src/order.js#processOrder" and seeing lines 143-145
await edit.execute({
file_path: 'src/order.js',
start_line: '143',
end_line: '145',
new_string: ' const items = order.items.filter(i => i.active);'
});
// => "Successfully edited src/order.js (lines 143-145 replaced with 1 line)"
Line-targeted edit — with hash integrity verification:
// Use the hash from extract output (e.g. "143:cd") for verification
await edit.execute({
file_path: 'src/order.js',
start_line: '143:cd',
new_string: ' const items = order.items.filter(i => i.active);'
});
// If hash matches: edit succeeds
// If hash doesn't match: error with updated reference for retry
Create a new file:
await create.execute({
file_path: 'src/newModule.js',
content: `export function greet(name) {
return \`Hello, \${name}!\`;
}`
});
// => "Successfully created src/newModule.js (52 bytes)"
new_string to match the original symbol's indentation level.extract/search output to make precise edits inside large functions. Optional hash-based integrity verification detects stale references."file.js#myFunction"), then use the line numbers from the output to surgically edit specific lines with start_line/end_line.search/extract are tracked; edits to unread or modified files are blocked with recovery instructions.allowedFolders.Probe includes a built-in MCP (Model Context Protocol) server for integration with AI assistants:
# Start the MCP server
probe mcp
# With custom timeout
probe mcp --timeout 60
Add to your AI assistant's MCP configuration:
{
"mcpServers": {
"probe": {
"command": "npx",
"args": ["-y", "@probelabs/probe", "mcp"]
}
}
}
When using ProbeAgent programmatically, you can integrate MCP servers to extend the agent's capabilities:
const agent = new ProbeAgent({
enableMcp: true, // Enable MCP support
// Option 1: Provide MCP configuration directly
mcpConfig: {
mcpServers: {
'my-server': {
command: 'node',
args: ['path/to/server.js'],
transport: 'stdio',
enabled: true
}
}
},
// Option 2: Load from config file
mcpConfigPath: '/path/to/mcp-config.json',
// Option 3: Auto-discovery from standard locations
// (~/.mcp/config.json, or via MCP_CONFIG_PATH env var)
});
Note: MCP tools are automatically initialized when needed (lazy initialization), so you don't need to call agent.initialize() when using the SDK.
ProbeAgent now supports Claude Code's claude command for zero-configuration usage in Claude Code environments. See the Claude Code Integration Guide for full details.
import { ProbeAgent } from '@probelabs/probe';
// Works automatically if claude command is installed!
const agent = new ProbeAgent({
allowedFolders: ['/path/to/your/code']
});
await agent.initialize();
const response = await agent.answer('Explain how this codebase works');
ProbeAgent automatically detects and uses Claude Code when:
claude command is available on your systemPriority order:
provider: 'claude-code'For complete documentation, examples, and troubleshooting, see docs/CLAUDE_CODE_INTEGRATION.md.
import { search } from '@probelabs/probe';
const results = await search({
path: '/path/to/your/project',
query: 'function',
// Optional parameters
filesOnly: false,
ignore: ['node_modules', 'dist'],
excludeFilenames: false,
reranker: 'hybrid',
frequencySearch: true,
maxResults: 10,
maxBytes: 1000000,
maxTokens: 40000,
allowTests: false,
noMerge: false,
mergeThreshold: 5,
json: false,
binaryOptions: {
forceDownload: false,
version: '1.0.0'
}
});
path (required): Path to search inquery (required): Search query or queries (string or array of strings)filesOnly: Only output file pathsignore: Patterns to ignore (array of strings)excludeFilenames: Exclude filenames from searchreranker: Reranking method ('hybrid', 'hybrid2', 'bm25', 'tfidf')frequencySearch: Use frequency-based searchmaxResults: Maximum number of resultsmaxBytes: Maximum bytes to returnmaxTokens: Maximum tokens to returnallowTests: Include test filesnoMerge: Don't merge adjacent blocksmergeThreshold: Merge thresholdjson: Return results as parsed JSON instead of stringbinaryOptions: Options for getting the binary
forceDownload: Force download even if binary existsversion: Specific version to downloadimport { query } from '@probelabs/probe';
const results = await query({
path: '/path/to/your/project',
pattern: 'function $NAME($$$PARAMS) $$$BODY',
// Optional parameters
language: 'javascript',
ignore: ['node_modules', 'dist'],
allowTests: false,
maxResults: 10,
format: 'markdown',
json: false,
binaryOptions: {
forceDownload: false,
version: '1.0.0'
}
});
path (required): Path to search inpattern (required): The ast-grep pattern to search forlanguage: Programming language to search inignore: Patterns to ignore (array of strings)allowTests: Include test filesmaxResults: Maximum number of resultsformat: Output format ('markdown', 'plain', 'json', 'color')json: Return results as parsed JSON instead of stringbinaryOptions: Options for getting the binary
forceDownload: Force download even if binary existsversion: Specific version to downloadimport { extract } from '@probelabs/probe';
const results = await extract({
files: [
'/path/to/your/project/src/main.js',
'/path/to/your/project/src/utils.js:42' // Extract from line 42
],
// Optional parameters
allowTests: false,
contextLines: 2,
format: 'markdown',
json: false,
binaryOptions: {
forceDownload: false,
version: '1.0.0'
}
});
files (required): Files to extract from (can include line numbers with colon, e.g., "/path/to/file.rs:10")allowTests: Include test filescontextLines: Number of context lines to includeformat: Output format ('markdown', 'plain', 'json')json: Return results as parsed JSON instead of stringbinaryOptions: Options for getting the binary
forceDownload: Force download even if binary existsversion: Specific version to downloadimport { symbols } from '@probelabs/probe';
const result = await symbols({
files: ['src/main.rs'],
cwd: '/path/to/project',
allowTests: false
});
// result is an array of FileSymbols
// result[0].file => 'src/main.rs'
// result[0].symbols => [{ name, kind, signature, line, end_line, children }, ...]
files (required): Array of file paths to list symbols fromcwd: Working directory for resolving relative pathsallowTests: Include test functions/methods (default: false)binaryOptions: Options for getting the binaryimport { getBinaryPath, setBinaryPath } from '@probelabs/probe';
// Get the path to the probe binary
const binaryPath = await getBinaryPath({
forceDownload: false,
version: '1.0.0'
});
// Manually set the path to the probe binary
setBinaryPath('/path/to/probe/binary');
import { tools } from '@probelabs/probe';
// Vercel AI SDK tools
const { searchTool, queryTool, extractTool } = tools;
// LangChain tools
const searchLangChainTool = tools.createSearchTool();
const queryLangChainTool = tools.createQueryTool();
const extractLangChainTool = tools.createExtractTool();
// Access schemas
const { searchSchema, querySchema, extractSchema } = tools;
// Access default system message
const systemMessage = tools.DEFAULT_SYSTEM_MESSAGE;
searchTool: Tool for searching code using Elasticsearch-like query syntaxqueryTool: Tool for searching code using tree-sitter patternsextractTool: Tool for extracting code blocks from filescreateSearchTool(): Creates a tool for searching code using Elasticsearch-like query syntaxcreateQueryTool(): Creates a tool for searching code using tree-sitter patternscreateExtractTool(): Creates a tool for extracting code blocks from filessearchSchema: Zod schema for search tool parametersquerySchema: Zod schema for query tool parametersextractSchema: Zod schema for extract tool parametersDEFAULT_SYSTEM_MESSAGE: Default system message for AI assistants with instructions on how to use the probe toolsextractSchema: Zod schema for extract tool parametersimport { search } from '@probelabs/probe';
async function basicSearchExample() {
try {
const results = await search({
path: '/path/to/your/project',
query: 'function',
maxResults: 5
});
console.log('Search results:');
console.log(results);
} catch (error) {
console.error('Search error:', error);
}
}
import { search } from '@probelabs/probe';
async function advancedSearchExample() {
try {
const results = await search({
path: '/path/to/your/project',
query: 'config AND (parse OR tokenize)',
ignore: ['node_modules', 'dist'],
reranker: 'hybrid',
frequencySearch: true,
maxResults: 10,
maxTokens: 20000,
allowTests: false
});
console.log('Advanced search results:');
console.log(results);
} catch (error) {
console.error('Advanced search error:', error);
}
}
import { query } from '@probelabs/probe';
async function queryExample() {
try {
// Find all JavaScript functions
const jsResults = await query({
path: '/path/to/your/project',
pattern: 'function $NAME($$$PARAMS) $$$BODY',
language: 'javascript',
maxResults: 5
});
console.log('JavaScript functions:');
console.log(jsResults);
// Find all Rust structs
const rustResults = await query({
path: '/path/to/your/project',
pattern: 'struct $NAME $$$BODY',
language: 'rust',
maxResults: 5
});
console.log('Rust structs:');
console.log(rustResults);
} catch (error) {
console.error('Query error:', error);
}
}
import { extract } from '@probelabs/probe';
async function extractExample() {
try {
const results = await extract({
files: [
'/path/to/your/project/src/main.js',
'/path/to/your/project/src/utils.js:42' // Extract from line 42
],
contextLines: 2,
format: 'markdown'
});
console.log('Extracted code:');
console.log(results);
} catch (error) {
console.error('Extract error:', error);
}
}
When you install this package:
This approach ensures that you get the actual native binary, not a JavaScript wrapper, providing full performance and all features of the original probe CLI.
The package provides built-in tools for integrating with AI SDKs like Vercel AI SDK and LangChain, allowing you to use probe's powerful code search capabilities in AI applications.
import { generateText } from 'ai';
import { tools } from '@probelabs/probe';
// Use the pre-built tools with Vercel AI SDK
async function chatWithAI(userMessage) {
const result = await generateText({
model: provider(modelName),
messages: [{ role: 'user', content: userMessage }],
system: "You are a code intelligence assistant. Use the provided tools to search and analyze code.",
tools: {
search: tools.searchTool,
query: tools.queryTool,
extract: tools.extractTool
},
maxSteps: 15,
temperature: 0.7
});
return result.text;
}
import { ChatOpenAI } from '@langchain/openai';
import { tools } from '@probelabs/probe';
// Create the LangChain tools
const searchTool = tools.createSearchTool();
const queryTool = tools.createQueryTool();
const extractTool = tools.createExtractTool();
// Create a ChatOpenAI instance with tools
const model = new ChatOpenAI({
modelName: "gpt-5.2",
temperature: 0.7
}).withTools([searchTool, queryTool, extractTool]);
// Use the model with tools
async function chatWithAI(userMessage) {
const result = await model.invoke([
{ role: "system", content: "You are a code intelligence assistant. Use the provided tools to search and analyze code." },
{ role: "user", content: userMessage }
]);
return result.content;
}
The package provides a default system message that you can use with your AI assistants:
import { tools } from '@probelabs/probe';
// Use the default system message in your AI application
const systemMessage = tools.DEFAULT_SYSTEM_MESSAGE;
// Example with Vercel AI SDK
const result = await generateText({
model: provider(modelName),
messages: [{ role: 'user', content: userMessage }],
system: tools.DEFAULT_SYSTEM_MESSAGE,
tools: {
search: tools.searchTool,
query: tools.queryTool,
extract: tools.extractTool
}
});
The default system message provides instructions for AI assistants on how to use the probe tools effectively, including search query formatting, tool execution sequence, and best practices.
ISC
If you're migrating from the standalone @probelabs/probe-mcp package, probe mcp is a drop-in replacement:
Old usage:
npx @probelabs/probe-mcp
# or
probe-mcp --timeout 60
New usage (drop-in replacement):
probe mcp
# or
probe mcp --timeout 60
MCP Configuration:
// Old configuration
{
"mcpServers": {
"probe": {
"command": "npx",
"args": ["-y", "@probelabs/probe-mcp"]
}
}
}
// New configuration (drop-in replacement)
{
"mcpServers": {
"probe": {
"command": "npx",
"args": ["-y", "@probelabs/probe", "mcp"]
}
}
}
FAQs
Node.js wrapper for the probe code search tool
We found that @probelabs/probe demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.