@robota-sdk/agent-tools 3.0.0-beta.79 β 3.0.0-beta.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -15
- package/dist/browser/browser.d.ts +14 -97
- package/dist/browser/browser.d.ts.map +1 -1
- package/dist/browser/browser.js +1 -1
- package/dist/browser/browser.js.map +1 -1
- package/dist/node/index.cjs +2356 -517
- package/dist/node/index.d.cts +1047 -0
- package/dist/node/index.d.cts.map +1 -0
- package/dist/node/index.d.ts +768 -131
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +2326 -510
- package/dist/node/index.js.map +1 -1
- package/package.json +33 -16
package/dist/node/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["DEFAULT_TIMEOUT_MS","DEFAULT_LIMIT","DEFAULT_TIMEOUT_MS"],"sources":["../../src/sandbox/e2b-sandbox-client.ts","../../src/sandbox/in-memory-sandbox-client.ts","../../src/sandbox/workspace-manifest.ts","../../src/registry/tool-registry.ts","../../src/implementations/function-tool/parameter-validator.ts","../../src/implementations/function-tool.ts","../../src/builtins/shell-tool.ts","../../src/builtins/path-guard.ts","../../src/builtins/read-tool.ts","../../src/builtins/atomic-file-write.ts","../../src/builtins/write-tool.ts","../../src/builtins/edit-tool.ts","../../src/builtins/glob-tool.ts","../../src/builtins/grep-tool.ts","../../src/builtins/web-fetch-tool.ts","../../src/builtins/web-search-tool.ts","../../src/builtins/ask-user-question-tool.ts"],"sourcesContent":["import type { ISandboxClient, ISandboxRunOptions, ISandboxRunResult } from './types.js';\n\ninterface IE2BCommandStartOptions {\n timeoutMs?: number;\n cwd?: string;\n background?: false;\n}\n\ninterface IE2BCommandResult {\n stdout?: string;\n stderr?: string;\n exitCode?: number;\n exit_code?: number;\n}\n\ninterface IE2BCommands {\n run(command: string, options?: IE2BCommandStartOptions): Promise<IE2BCommandResult>;\n}\n\ninterface IE2BFiles {\n read(path: string): Promise<string | Uint8Array>;\n write(path: string, content: string): Promise<void>;\n}\n\ninterface IE2BSnapshot {\n snapshotId?: string;\n id?: string;\n}\n\nexport interface IE2BSandboxAdapter {\n sandboxId?: string;\n commands: IE2BCommands;\n files: IE2BFiles;\n pause?(): Promise<boolean | string | void>;\n connect?(): Promise<IE2BSandboxAdapter>;\n createSnapshot?(): Promise<IE2BSnapshot>;\n}\n\nexport interface IE2BSandboxClientOptions {\n sandbox: IE2BSandboxAdapter;\n connectSandbox?: (sandboxId: string) => Promise<IE2BSandboxAdapter>;\n createSandboxFromSnapshot?: (snapshotId: string) => Promise<IE2BSandboxAdapter>;\n}\n\nexport class E2BSandboxClient implements ISandboxClient {\n private sandbox: IE2BSandboxAdapter;\n private readonly connectSandbox?: (sandboxId: string) => Promise<IE2BSandboxAdapter>;\n private readonly createSandboxFromSnapshot?: (snapshotId: string) => Promise<IE2BSandboxAdapter>;\n\n constructor(options: IE2BSandboxClientOptions) {\n this.sandbox = options.sandbox;\n this.connectSandbox = options.connectSandbox;\n this.createSandboxFromSnapshot = options.createSandboxFromSnapshot;\n }\n\n async run(command: string, options?: ISandboxRunOptions): Promise<ISandboxRunResult> {\n const result = await this.sandbox.commands.run(command, {\n background: false,\n timeoutMs: options?.timeoutMs,\n cwd: options?.workingDirectory,\n });\n\n return {\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n exitCode: result.exitCode ?? result.exit_code ?? 0,\n };\n }\n\n async readFile(path: string): Promise<string> {\n const content = await this.sandbox.files.read(path);\n return typeof content === 'string' ? content : Buffer.from(content).toString('utf8');\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n await this.sandbox.files.write(path, content);\n }\n\n async snapshot(): Promise<string> {\n if (this.sandbox.createSnapshot) {\n const snapshot = await this.sandbox.createSnapshot();\n const snapshotId = snapshot.snapshotId ?? snapshot.id;\n if (!snapshotId) {\n throw new Error('E2B createSnapshot() did not return a snapshot id.');\n }\n return snapshotId;\n }\n const sandboxId = this.sandbox.sandboxId;\n if (!sandboxId) {\n throw new Error('E2B sandboxId is required to create a resumable sandbox snapshot.');\n }\n if (!this.sandbox.pause) {\n throw new Error('E2B sandbox adapter does not expose pause().');\n }\n await this.sandbox.pause();\n return sandboxId;\n }\n\n async restore(snapshotId: string): Promise<void> {\n if (this.createSandboxFromSnapshot) {\n this.sandbox = await this.createSandboxFromSnapshot(snapshotId);\n return;\n }\n if (this.connectSandbox) {\n this.sandbox = await this.connectSandbox(snapshotId);\n return;\n }\n if (this.sandbox.sandboxId === snapshotId && this.sandbox.connect) {\n this.sandbox = await this.sandbox.connect();\n return;\n }\n throw new Error(\n 'E2B sandbox restore requires connectSandbox(snapshotId) or sandbox.connect().',\n );\n }\n}\n","import type { ISandboxClient, ISandboxRunOptions, ISandboxRunResult } from './types.js';\n\nexport type TInMemorySandboxRunHandler = (\n command: string,\n options: ISandboxRunOptions | undefined,\n files: ReadonlyMap<string, string>,\n) => Promise<ISandboxRunResult> | ISandboxRunResult;\n\nexport interface IInMemorySandboxClientOptions {\n files?: Record<string, string>;\n runHandler?: TInMemorySandboxRunHandler;\n}\n\nexport class InMemorySandboxClient implements ISandboxClient {\n private readonly files = new Map<string, string>();\n private readonly snapshots = new Map<string, Map<string, string>>();\n private readonly runHandler?: TInMemorySandboxRunHandler;\n private snapshotSequence = 0;\n\n constructor(options: IInMemorySandboxClientOptions = {}) {\n for (const [path, content] of Object.entries(options.files ?? {})) {\n this.files.set(path, content);\n }\n this.runHandler = options.runHandler;\n }\n\n async run(command: string, options?: ISandboxRunOptions): Promise<ISandboxRunResult> {\n if (this.runHandler) {\n return this.runHandler(command, options, this.files);\n }\n return { stdout: '', stderr: '', exitCode: 0 };\n }\n\n async readFile(path: string): Promise<string> {\n const content = this.files.get(path);\n if (content === undefined) {\n throw new Error(`Sandbox file not found: ${path}`);\n }\n return content;\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n this.files.set(path, content);\n }\n\n async snapshot(): Promise<string> {\n const snapshotId = `snapshot-${++this.snapshotSequence}`;\n this.snapshots.set(snapshotId, new Map(this.files));\n return snapshotId;\n }\n\n async restore(snapshotId: string): Promise<void> {\n const snapshot = this.snapshots.get(snapshotId);\n if (!snapshot) {\n throw new Error(`Sandbox snapshot not found: ${snapshotId}`);\n }\n this.files.clear();\n for (const [path, content] of snapshot.entries()) {\n this.files.set(path, content);\n }\n }\n\n getFile(path: string): string | undefined {\n return this.files.get(path);\n }\n}\n","import { readdir, readFile } from 'node:fs/promises';\nimport { isAbsolute, join, posix, resolve } from 'node:path';\n\nimport type {\n ISandboxClient,\n IWorkspaceManifest,\n IWorkspaceManifestAppliedEntry,\n IWorkspaceManifestApplyOptions,\n IWorkspaceManifestApplyResult,\n TWorkspaceManifestEntry,\n} from './types.js';\n\nconst DEFAULT_TARGET_ROOT = '/workspace';\nconst WINDOWS_ABSOLUTE_PATH_PATTERN = /^[A-Za-z]:[\\\\/]/;\nconst SHELL_QUOTE_PATTERN = /'/g;\n\nexport async function applyWorkspaceManifest(\n sandboxClient: ISandboxClient,\n manifest: IWorkspaceManifest,\n options: IWorkspaceManifestApplyOptions = {},\n): Promise<IWorkspaceManifestApplyResult> {\n if (sandboxClient.applyManifest) {\n return sandboxClient.applyManifest(manifest, options);\n }\n\n const targetRoot = normalizeSandboxRoot(options.targetRoot ?? DEFAULT_TARGET_ROOT);\n const appliedEntries: IWorkspaceManifestAppliedEntry[] = [];\n\n for (const [rawPath, entry] of Object.entries(manifest.entries)) {\n const path = validateWorkspaceManifestPath(rawPath);\n const targetPath = joinSandboxPath(targetRoot, path);\n appliedEntries.push(\n await applyManifestEntry(sandboxClient, path, targetPath, targetRoot, entry, options),\n );\n }\n\n return { entries: appliedEntries };\n}\n\nexport function validateWorkspaceManifestPath(path: string): string {\n if (path.length === 0) {\n throw new Error('workspace manifest path must not be empty');\n }\n if (path.includes('\\0')) {\n throw new Error('workspace manifest path must not contain NUL bytes');\n }\n if (path.startsWith('/') || path.startsWith('\\\\') || WINDOWS_ABSOLUTE_PATH_PATTERN.test(path)) {\n throw new Error('workspace manifest path must be workspace-relative');\n }\n\n const parts = path.replace(/\\\\/g, '/').split('/').filter(Boolean);\n if (parts.length === 0) {\n throw new Error('workspace manifest path must not resolve to the workspace root');\n }\n if (parts.some((part) => part === '..')) {\n throw new Error('workspace manifest path cannot contain traversal segments');\n }\n\n const normalizedParts = parts.filter((part) => part !== '.');\n if (normalizedParts.length === 0) {\n throw new Error('workspace manifest path must not resolve to the workspace root');\n }\n\n return normalizedParts.join('/');\n}\n\nasync function applyManifestEntry(\n sandboxClient: ISandboxClient,\n path: string,\n targetPath: string,\n targetRoot: string,\n entry: TWorkspaceManifestEntry,\n options: IWorkspaceManifestApplyOptions,\n): Promise<IWorkspaceManifestAppliedEntry> {\n switch (entry.type) {\n case 'file':\n await writeSandboxFile(sandboxClient, targetPath, targetRoot, entry.content);\n return createAppliedEntry(path, entry.type);\n case 'dir':\n await createSandboxDirectory(sandboxClient, targetPath);\n return createAppliedEntry(path, entry.type);\n case 'localFile':\n await copyLocalFile(sandboxClient, entry.src, targetPath, targetRoot, options);\n return createAppliedEntry(path, entry.type);\n case 'localDir':\n await copyLocalDirectory(sandboxClient, entry.src, targetPath, options);\n return createAppliedEntry(path, entry.type);\n case 'gitRepo':\n await cloneGitRepository(sandboxClient, entry, targetPath);\n return createAppliedEntry(path, entry.type);\n case 's3Mount':\n case 'gcsMount':\n case 'r2Mount':\n case 'azureBlobMount':\n return {\n path,\n type: entry.type,\n status: 'unsupported',\n message: `${entry.type} requires a provider-specific sandbox adapter.`,\n };\n default:\n return assertUnreachable(entry);\n }\n}\n\nfunction createAppliedEntry(\n path: string,\n type: TWorkspaceManifestEntry['type'],\n): IWorkspaceManifestAppliedEntry {\n return { path, type, status: 'applied' };\n}\n\nasync function copyLocalFile(\n sandboxClient: ISandboxClient,\n source: string,\n targetPath: string,\n targetRoot: string,\n options: IWorkspaceManifestApplyOptions,\n): Promise<void> {\n const hostSourcePath = resolveHostSourcePath(source, options.hostRoot);\n const content = await readFile(hostSourcePath, 'utf8');\n await writeSandboxFile(sandboxClient, targetPath, targetRoot, content);\n}\n\nasync function copyLocalDirectory(\n sandboxClient: ISandboxClient,\n source: string,\n targetPath: string,\n options: IWorkspaceManifestApplyOptions,\n): Promise<void> {\n const hostSourcePath = resolveHostSourcePath(source, options.hostRoot);\n await copyLocalDirectoryRecursive(sandboxClient, hostSourcePath, targetPath);\n}\n\nasync function copyLocalDirectoryRecursive(\n sandboxClient: ISandboxClient,\n sourcePath: string,\n targetPath: string,\n): Promise<void> {\n await createSandboxDirectory(sandboxClient, targetPath);\n const entries = await readdir(sourcePath, { withFileTypes: true });\n\n for (const entry of entries) {\n const childSourcePath = join(sourcePath, entry.name);\n const childTargetPath = joinSandboxPath(targetPath, entry.name);\n if (entry.isDirectory()) {\n await copyLocalDirectoryRecursive(sandboxClient, childSourcePath, childTargetPath);\n continue;\n }\n if (entry.isFile()) {\n const content = await readFile(childSourcePath, 'utf8');\n await sandboxClient.writeFile(childTargetPath, content);\n }\n }\n}\n\nasync function cloneGitRepository(\n sandboxClient: ISandboxClient,\n entry: Extract<TWorkspaceManifestEntry, { type: 'gitRepo' }>,\n targetPath: string,\n): Promise<void> {\n const shallowArgs = entry.shallow === false ? '' : ' --depth 1';\n const refArgs = entry.ref ? ` --branch ${quoteShellArg(entry.ref)}` : '';\n await runSandboxCommand(\n sandboxClient,\n `git clone${shallowArgs}${refArgs} ${quoteShellArg(entry.url)} ${quoteShellArg(targetPath)}`,\n );\n}\n\nasync function writeSandboxFile(\n sandboxClient: ISandboxClient,\n targetPath: string,\n targetRoot: string,\n content: string,\n): Promise<void> {\n const parentPath = posix.dirname(targetPath);\n if (parentPath !== targetRoot) {\n await createSandboxDirectory(sandboxClient, parentPath);\n }\n await sandboxClient.writeFile(targetPath, content);\n}\n\nasync function createSandboxDirectory(\n sandboxClient: ISandboxClient,\n targetPath: string,\n): Promise<void> {\n await runSandboxCommand(sandboxClient, `mkdir -p ${quoteShellArg(targetPath)}`);\n}\n\nasync function runSandboxCommand(sandboxClient: ISandboxClient, command: string): Promise<void> {\n const result = await sandboxClient.run(command);\n if (result.exitCode !== 0) {\n throw new Error(\n `workspace manifest command failed: ${command}\\n${result.stderr ?? result.stdout}`,\n );\n }\n}\n\nfunction resolveHostSourcePath(source: string, hostRoot: string | undefined): string {\n return isAbsolute(source) ? resolve(source) : resolve(hostRoot ?? process.cwd(), source);\n}\n\nfunction normalizeSandboxRoot(root: string): string {\n const normalized = root.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n if (!normalized.startsWith('/')) {\n throw new Error('workspace manifest targetRoot must be an absolute sandbox path');\n }\n return normalized.length === 0 ? '/' : normalized;\n}\n\nfunction joinSandboxPath(root: string, path: string): string {\n const normalizedRoot = normalizeSandboxRoot(root);\n if (normalizedRoot === '/') {\n return `/${path}`;\n }\n return `${normalizedRoot}/${path}`;\n}\n\nfunction quoteShellArg(value: string): string {\n return `'${value.replace(SHELL_QUOTE_PATTERN, \"'\\\\''\")}'`;\n}\n\nfunction assertUnreachable(value: never): never {\n throw new Error(`unsupported workspace manifest entry: ${JSON.stringify(value)}`);\n}\n","import { ValidationError } from '@robota-sdk/agent-core';\nimport { logger } from '@robota-sdk/agent-core';\n\nimport type { ITool, IToolRegistry } from '@robota-sdk/agent-core';\nimport type { IToolSchema } from '@robota-sdk/agent-core';\n\n/**\n * Tool registry implementation\n * Manages tool registration, validation, and retrieval\n */\nexport class ToolRegistry implements IToolRegistry {\n private tools = new Map<string, ITool>();\n\n /**\n * Register a tool\n */\n register(tool: ITool): void {\n if (!tool.schema?.name) {\n throw new ValidationError('Tool must have a valid schema with name');\n }\n\n const toolName = tool.schema.name;\n\n // Validate tool schema\n this.validateToolSchema(tool.schema);\n\n // Check for duplicate registration\n if (this.tools.has(toolName)) {\n logger.warn(`Tool \"${toolName}\" is already registered, overriding`, {\n toolName,\n existingTool: this.tools.get(toolName)?.constructor.name,\n });\n }\n\n this.tools.set(toolName, tool);\n logger.debug(`Tool \"${toolName}\" registered successfully`, {\n toolName,\n toolType: tool.constructor.name,\n parameters: Object.keys(tool.schema.parameters?.properties || {}),\n });\n }\n\n /**\n * Unregister a tool\n */\n unregister(name: string): void {\n if (!this.tools.has(name)) {\n logger.warn(`Attempted to unregister non-existent tool \"${name}\"`);\n return;\n }\n\n this.tools.delete(name);\n logger.debug(`Tool \"${name}\" unregistered successfully`);\n }\n\n /**\n * Get tool by name\n */\n get(name: string): ITool | undefined {\n return this.tools.get(name);\n }\n\n /**\n * Get all registered tools\n */\n getAll(): ITool[] {\n return Array.from(this.tools.values());\n }\n\n /**\n * Get tool schemas\n */\n getSchemas(): IToolSchema[] {\n const tools = this.getAll();\n\n // π [TOOL-FLOW] ToolRegistry.getSchemas() - Extracting schemas from tools\n logger.debug('[TOOL-FLOW] ToolRegistry.getSchemas() - Tools before schema extraction', {\n count: tools.length,\n tools: tools.map((t) => ({\n name: t.schema?.name ?? 'unnamed',\n hasSchema: !!t.schema,\n schemaType: typeof t.schema,\n toolType: t.constructor?.name || 'unknown',\n })),\n });\n\n return this.getAll().map((tool) => tool.schema);\n }\n\n /**\n * Check if tool exists\n */\n has(name: string): boolean {\n return this.tools.has(name);\n }\n\n /**\n * Clear all tools\n */\n clear(): void {\n const toolCount = this.tools.size;\n this.tools.clear();\n logger.debug(`Cleared ${toolCount} tools from registry`);\n }\n\n /**\n * Get tool names\n */\n getToolNames(): string[] {\n return Array.from(this.tools.keys());\n }\n\n /**\n * Get tools by pattern\n */\n getToolsByPattern(pattern: string | RegExp): ITool[] {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\n return this.getAll().filter((tool) => regex.test(tool.schema.name));\n }\n\n /**\n * Get tool count\n */\n size(): number {\n return this.tools.size;\n }\n\n /**\n * Validate tool schema\n */\n private validateToolSchema(schema: IToolSchema): void {\n if (!schema.name || typeof schema.name !== 'string') {\n throw new ValidationError('Tool schema must have a valid name');\n }\n\n if (!schema.description || typeof schema.description !== 'string') {\n throw new ValidationError('Tool schema must have a description');\n }\n\n if (\n !schema.parameters ||\n typeof schema.parameters !== 'object' ||\n schema.parameters === null ||\n Array.isArray(schema.parameters)\n ) {\n throw new ValidationError('Tool schema must have parameters object');\n }\n\n if (schema.parameters.type !== 'object') {\n throw new ValidationError('Tool parameters type must be \"object\"');\n }\n\n // Validate parameter properties\n if (schema.parameters.properties) {\n for (const propName of Object.keys(schema.parameters.properties)) {\n const propSchema = schema.parameters.properties[propName];\n if (!propSchema?.type) {\n throw new ValidationError(`Parameter \"${propName}\" must have a type`);\n }\n\n const validTypes = ['string', 'number', 'boolean', 'array', 'object'];\n if (!validTypes.includes(propSchema.type)) {\n throw new ValidationError(\n `Parameter \"${propName}\" has invalid type \"${propSchema.type}\"`,\n );\n }\n }\n }\n\n // Validate required fields exist in properties\n if (schema.parameters.required) {\n const properties = schema.parameters.properties || {};\n for (const requiredField of schema.parameters.required) {\n if (!properties[requiredField]) {\n throw new ValidationError(\n `Required parameter \"${requiredField}\" is not defined in properties`,\n );\n }\n }\n }\n }\n}\n","import type {\n IParameterSchema,\n TToolParameters,\n IParameterValidationResult,\n} from '@robota-sdk/agent-core';\nimport type { TUniversalValue } from '@robota-sdk/agent-core';\n\n/**\n * Validate individual parameter type against its schema.\n * Returns an error string if invalid, undefined if valid.\n */\nexport function validateParameterType(\n key: string,\n value: TUniversalValue,\n schema: IParameterSchema,\n): string | undefined {\n const expectedType = schema['type'];\n\n switch (expectedType) {\n case 'string':\n if (typeof value !== 'string') {\n return `Parameter \"${key}\" must be a string, got ${typeof value}`;\n }\n break;\n\n case 'number':\n if (typeof value !== 'number' || isNaN(value)) {\n return `Parameter \"${key}\" must be a number, got ${typeof value}`;\n }\n break;\n\n case 'boolean':\n if (typeof value !== 'boolean') {\n return `Parameter \"${key}\" must be a boolean, got ${typeof value}`;\n }\n break;\n\n case 'array':\n if (!Array.isArray(value)) {\n return `Parameter \"${key}\" must be an array, got ${typeof value}`;\n }\n // Check array items if specified\n if (schema.items) {\n for (let i = 0; i < value.length; i++) {\n const itemError = validateParameterType(`${key}[${i}]`, value[i], schema.items);\n if (itemError) {\n return itemError;\n }\n }\n }\n break;\n\n case 'object':\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return `Parameter \"${key}\" must be an object, got ${typeof value}`;\n }\n break;\n }\n\n // Check enum constraints\n if (schema.enum && schema.enum.length > 0) {\n const enumValues = schema.enum;\n let isValidEnum = false;\n\n // Type-safe enum checking based on JSONSchemaEnum type\n for (const enumValue of enumValues) {\n if (value === enumValue) {\n isValidEnum = true;\n break;\n }\n }\n\n if (!isValidEnum) {\n return `Parameter \"${key}\" must be one of: ${enumValues.join(', ')}, got ${value}`;\n }\n }\n\n return undefined;\n}\n\n/**\n * Collect all validation errors for the given parameters against a schema.\n */\nexport function getValidationErrors(\n parameters: TToolParameters,\n schemaRequired: string[],\n schemaProperties: Record<string, IParameterSchema>,\n additionalProperties?: boolean | IParameterSchema,\n): string[] {\n const errors: string[] = [];\n\n // Check required parameters\n for (const field of schemaRequired) {\n if (!(field in parameters)) {\n errors.push(`Missing required parameter: ${field}`);\n }\n }\n\n // Check parameter types and constraints\n for (const [key, value] of Object.entries(parameters)) {\n const paramSchema = schemaProperties[key];\n if (!paramSchema) {\n if (additionalProperties === true) {\n continue;\n }\n if (additionalProperties && typeof additionalProperties === 'object') {\n const additionalTypeError = validateParameterType(key, value, additionalProperties);\n if (additionalTypeError) errors.push(additionalTypeError);\n continue;\n }\n errors.push(`Unknown parameter: ${key}`);\n continue;\n }\n\n const typeError = validateParameterType(key, value, paramSchema);\n if (typeError) {\n errors.push(typeError);\n }\n }\n\n return errors;\n}\n\n/**\n * Validate parameters and return a structured result.\n */\nexport function validateToolParameters(\n parameters: TToolParameters,\n schemaRequired: string[],\n schemaProperties: Record<string, IParameterSchema>,\n additionalProperties?: boolean | IParameterSchema,\n): IParameterValidationResult {\n const errors = getValidationErrors(\n parameters,\n schemaRequired,\n schemaProperties,\n additionalProperties,\n );\n return {\n isValid: errors.length === 0,\n errors,\n };\n}\n","import { ToolExecutionError, ValidationError, zodToJsonSchema } from '@robota-sdk/agent-core';\n\nimport { getValidationErrors, validateToolParameters } from './function-tool/parameter-validator';\n\nimport type {\n IFunctionTool,\n IToolResult,\n IToolExecutionContext,\n IParameterValidationResult,\n TToolExecutor,\n TToolParameters,\n IEventService,\n} from '@robota-sdk/agent-core';\nimport type { IToolSchema } from '@robota-sdk/agent-core';\nimport type { TUniversalValue } from '@robota-sdk/agent-core';\nimport type { TypeOf, ZodType } from 'zod';\n\n// Import from Facade pattern modules for type safety\n\n/**\n * Function tool implementation\n * Wraps a JavaScript function as a tool with schema validation\n *\n * Implements IFunctionTool without extending AbstractTool to avoid\n * circular runtime dependency (tools β agents β tools).\n */\nexport class FunctionTool implements IFunctionTool {\n readonly schema: IToolSchema;\n readonly fn: TToolExecutor;\n private eventService: IEventService | undefined;\n\n constructor(schema: IToolSchema, fn: TToolExecutor) {\n this.schema = schema;\n this.fn = fn;\n this.validateConstructorInputs();\n }\n\n /**\n * Get tool name\n */\n getName(): string {\n return this.schema.name;\n }\n\n /**\n * Set EventService for post-construction injection.\n * Accepts EventService as-is without transformation.\n * Caller is responsible for providing properly configured EventService.\n */\n setEventService(eventService: IEventService | undefined): void {\n this.eventService = eventService;\n }\n\n /**\n * Execute the function tool\n */\n async execute(\n parameters: TToolParameters,\n context?: IToolExecutionContext,\n ): Promise<IToolResult> {\n const toolName = this.schema.name;\n\n // Validate parameters before execution\n if (!this.validate(parameters)) {\n const errors = getValidationErrors(\n parameters,\n this.schema.parameters.required || [],\n this.schema.parameters.properties || {},\n this.schema.parameters.additionalProperties,\n );\n throw new ValidationError(`Invalid parameters for tool \"${toolName}\": ${errors.join(', ')}`);\n }\n\n // Execute the function\n const startTime = Date.now();\n let result: TUniversalValue;\n try {\n result = await this.fn(parameters, context);\n } catch (error) {\n if (error instanceof ToolExecutionError || error instanceof ValidationError) {\n throw error;\n }\n\n throw new ToolExecutionError(\n `Function tool execution failed: ${error instanceof Error ? error.message : String(error)}`,\n toolName,\n error instanceof Error ? error : new Error(String(error)),\n {\n parameterCount: Object.keys(parameters || {}).length,\n hasContext: !!context,\n },\n );\n }\n\n const executionTime = Date.now() - startTime;\n\n return {\n success: true,\n data: result,\n metadata: {\n executionTime,\n toolName,\n parameters,\n },\n };\n }\n\n /**\n * Validate parameters (simple boolean result)\n */\n validate(parameters: TToolParameters): boolean {\n return (\n getValidationErrors(\n parameters,\n this.schema.parameters.required || [],\n this.schema.parameters.properties || {},\n this.schema.parameters.additionalProperties,\n ).length === 0\n );\n }\n\n /**\n * Validate tool parameters with detailed result\n */\n validateParameters(parameters: TToolParameters): IParameterValidationResult {\n return validateToolParameters(\n parameters,\n this.schema.parameters.required || [],\n this.schema.parameters.properties || {},\n this.schema.parameters.additionalProperties,\n );\n }\n\n /**\n * Get tool description\n */\n getDescription(): string {\n return this.schema.description;\n }\n\n /**\n * Validate constructor inputs\n */\n private validateConstructorInputs(): void {\n if (!this.schema) {\n throw new ValidationError('Tool schema is required');\n }\n\n if (!this.fn || typeof this.fn !== 'function') {\n throw new ValidationError('Tool function is required and must be a function');\n }\n\n if (!this.schema.name) {\n throw new ValidationError('Tool schema must have a name');\n }\n }\n}\n\n/**\n * Helper function to create a function tool from a simple function\n */\nexport function createFunctionTool(\n name: string,\n description: string,\n parameters: IToolSchema['parameters'],\n fn: TToolExecutor,\n): FunctionTool {\n const schema: IToolSchema = {\n name,\n description,\n parameters,\n };\n\n return new FunctionTool(schema, fn);\n}\n\n/**\n * Helper function to create a function tool from Zod schema\n */\nexport function createZodFunctionTool<S extends ZodType>(\n name: string,\n description: string,\n zodSchema: S,\n fn: TToolExecutor<TypeOf<S>>,\n): FunctionTool {\n // Use comprehensive Zod to JSON schema conversion\n const parameters = zodToJsonSchema(zodSchema);\n\n const schema: IToolSchema = {\n name,\n description,\n parameters,\n };\n\n // Wrap the function with validation and ensure proper parameter handling\n const wrappedFn: TToolExecutor = async (\n parameters: TToolParameters,\n context?: IToolExecutionContext,\n ): Promise<TUniversalValue> => {\n // Use Zod for runtime validation β the executor receives the PARSED, schema-typed value\n // (SDK-009): the runtime guarantee and the compile-time type now flow together.\n const parseResult = zodSchema.safeParse(parameters);\n if (!parseResult.success) {\n throw new ValidationError(`Zod validation failed: ${parseResult.error}`);\n }\n\n const result = await fn(parseResult.data as TypeOf<S>, context);\n // Ensure result is always a string for consistency with core package\n return typeof result === 'string' ? result : JSON.stringify(result);\n };\n\n return new FunctionTool(schema, wrappedFn);\n}\n\n// zodToJsonSchema function moved to Facade pattern schema-converter module\n","/**\n * ShellTool β execute a host shell command via child_process.spawn (TERM-008).\n *\n * Cross-platform: the shell is resolved per OS through `resolvePlatformShell()` (POSIX `sh`/`bash`,\n * Windows PowerShell). The tool name is `Shell` and its description is built dynamically from the\n * resolved shell so the model is told the active shell/OS and writes the right syntax.\n *\n * Returns an IToolInvocationResult JSON string. A non-zero exit is returned as success:true with\n * exitCode set (the command ran, it just exited non-zero β the LLM decides what to do with that).\n */\n\nimport { spawn } from 'node:child_process';\n\nimport { resolvePlatformShell } from '@robota-sdk/agent-core';\nimport { killProcessTree } from '@robota-sdk/agent-process';\nimport { z } from 'zod';\n\n/** POSIX children are spawned detached so a process-group kill reaps grandchildren (CORE-023). */\nconst SPAWN_DETACHED = process.platform !== 'win32';\n\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { FunctionTool } from '../implementations/function-tool';\nimport type { ISandboxToolOptions } from '../sandbox/types.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { IPlatformShell } from '@robota-sdk/agent-core';\n\nconst DEFAULT_TIMEOUT_MS = 120_000; // 2 minutes\n\nconst ShellSchema = z.object({\n command: z.string().describe('The shell command to execute'),\n timeout: z\n .number()\n .optional()\n .describe('Optional timeout in milliseconds (max 600000). Default is 120000 (2 minutes)'),\n workingDirectory: z\n .string()\n .optional()\n .describe('Working directory for the command. Defaults to the current working directory'),\n});\n\ntype TShellArgs = z.infer<typeof ShellSchema>;\n\n/** Build the OS-aware tool description so the model writes syntax the host shell can run. */\nfunction buildShellToolDescription(shell: IPlatformShell): string {\n return [\n `Executes a command in the host shell and returns its output.`,\n ``,\n `Active shell: ${shell.label}. ${shell.syntaxHint}`,\n ``,\n `The working directory persists between commands, but shell state does not.`,\n ``,\n `IMPORTANT: Avoid using this tool to run \\`find\\`, \\`grep\\`, \\`cat\\`, \\`head\\`, \\`tail\\`, \\`sed\\`, \\`awk\\`, or \\`echo\\` commands. Instead, use the appropriate dedicated tool:`,\n ` - File search: Use Glob (NOT find or ls)`,\n ` - Content search: Use Grep (NOT grep or rg)`,\n ` - Read files: Use Read (NOT cat/head/tail)`,\n ` - Edit files: Use Edit (NOT sed/awk)`,\n ``,\n `For simple commands, keep the description brief (5-10 words). For complex commands, include enough context to clarify what the command does.`,\n ``,\n `Output is limited to 30,000 characters. Longer output will be middle-truncated.`,\n ].join('\\n');\n}\n\n/** Run a shell command through the sandbox client, surfacing failures as a structured result. */\nasync function runInSandbox(\n command: string,\n timeout: number,\n workingDirectory: string | undefined,\n options: ISandboxToolOptions,\n): Promise<string> {\n try {\n const sandboxResult = await options.sandboxClient!.run(command, {\n timeoutMs: timeout,\n workingDirectory,\n });\n const output = sandboxResult.stderr\n ? `${sandboxResult.stdout}\\nstderr:\\n${sandboxResult.stderr}`\n : sandboxResult.stdout;\n const result: IToolInvocationResult = {\n success: true,\n output,\n exitCode: sandboxResult.exitCode,\n };\n return JSON.stringify(result);\n } catch (err) {\n // allow-fallback: tool-result contract reports a failed run as success:false + error (faithful surfacing of a terminal failure, not silent recovery)\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n}\n\n/**\n * Run a shell command and return stdout + stderr.\n * Resolves with the IToolInvocationResult JSON string.\n */\nasync function runShell(\n args: TShellArgs,\n options: ISandboxToolOptions = {},\n signal?: AbortSignal,\n): Promise<string> {\n const { command, timeout: rawTimeout = DEFAULT_TIMEOUT_MS, workingDirectory } = args;\n const timeout = Math.min(rawTimeout, 600_000);\n if (options.sandboxClient) {\n return runInSandbox(command, timeout, workingDirectory, options);\n }\n\n const shell = resolvePlatformShell();\n\n if (signal?.aborted) {\n return JSON.stringify({ success: false, output: '', error: 'Aborted before start' });\n }\n\n return new Promise<string>((resolve) => {\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n let timedOut = false;\n let settled = false;\n\n const child = spawn(shell.command, shell.commandArgs(command), {\n cwd: workingDirectory ?? process.cwd(),\n env: process.env,\n stdio: ['pipe', 'pipe', 'pipe'],\n detached: SPAWN_DETACHED,\n });\n\n // RUNTIME-31: the command inherits an open stdin pipe it can block reading on; close it\n // so commands that read stdin (e.g. `cat`) terminate instead of hanging until timeout.\n child.stdin?.end();\n\n child.stdout.on('data', (chunk: Buffer) => {\n stdoutChunks.push(chunk);\n });\n\n child.stderr.on('data', (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n const timer = setTimeout(() => {\n timedOut = true;\n // CORE-023: kill the whole process group with SIGTERMβgraceβSIGKILL so grandchildren\n // are reaped, not just the shell. Fire-and-forget: settle promptly, escalate in background.\n void killProcessTree(child, { processGroup: SPAWN_DETACHED });\n settle({\n success: false,\n output: Buffer.concat(stdoutChunks).toString('utf8'),\n error: `Command timed out after ${timeout}ms`,\n });\n }, timeout);\n\n function settle(result: IToolInvocationResult): void {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n resolve(JSON.stringify(result));\n }\n\n // CORE-018: the run-scoped signal must terminate the underlying work β completing\n // silently after an abort is a cancellation-contract violation. CORE-023: process-group\n // kill reaps grandchildren the bare SIGTERM left orphaned.\n function onAbort(): void {\n void killProcessTree(child, { processGroup: SPAWN_DETACHED });\n settle({\n success: false,\n output: Buffer.concat(stdoutChunks).toString('utf8'),\n error: 'Aborted',\n });\n }\n signal?.addEventListener('abort', onAbort, { once: true });\n\n child.on('error', (err: Error) => {\n settle({\n success: false,\n output: '',\n error: err.message,\n });\n });\n\n child.on('close', (code: number | null) => {\n if (timedOut) {\n settle({\n success: false,\n output: Buffer.concat(stdoutChunks).toString('utf8'),\n error: `Command timed out after ${timeout}ms`,\n exitCode: code ?? undefined,\n });\n return;\n }\n\n const stdout = Buffer.concat(stdoutChunks).toString('utf8');\n const stderr = Buffer.concat(stderrChunks).toString('utf8');\n\n const exitCode = code ?? 0;\n const output = stderr ? `${stdout}\\nstderr:\\n${stderr}` : stdout;\n\n settle({\n success: true,\n output,\n exitCode,\n });\n });\n });\n}\n\n/**\n * Build a host-shell command tool under a given registered name. Both `Shell` and the\n * model-familiar `Bash` are registered as aliases of this one OS-aware implementation\n * (TERM-008): the shell is resolved per OS and the description names the active shell so the\n * model writes the right syntax regardless of which alias it calls.\n */\nfunction createHostShellTool(name: string, options: ISandboxToolOptions): FunctionTool {\n return createZodFunctionTool(\n name,\n buildShellToolDescription(resolvePlatformShell()),\n ShellSchema,\n async (params, context) => {\n return runShell(params, options, context?.signal);\n },\n );\n}\n\n/**\n * Create a `Shell` tool instance β register with the Robota agent tools registry.\n * The description is resolved at creation time for the host's active shell.\n */\nexport function createShellTool(options: ISandboxToolOptions = {}): FunctionTool {\n return createHostShellTool('Shell', options);\n}\n\n/**\n * Create a `Bash` tool instance β the model-familiar alias of the same OS-aware shell tool.\n */\nexport function createBashTool(options: ISandboxToolOptions = {}): FunctionTool {\n return createHostShellTool('Bash', options);\n}\n\n/** `Shell` tool instance β register with the Robota agent tools registry. */\nexport const shellTool = createShellTool();\n\n/** `Bash` tool instance β model-familiar alias of {@link shellTool}. */\nexport const bashTool = createBashTool();\n","import { resolve, sep } from 'node:path';\n\nimport type { IToolInvocationResult } from '../types/tool-result.js';\n\n/**\n * Returns a JSON-serialized IToolInvocationResult error when filePath is outside cwd.\n * Returns undefined when the path is within cwd or cwd is not set.\n */\nexport function checkPathWithinCwd(filePath: string, cwd: string | undefined): string | undefined {\n if (cwd === undefined) return undefined;\n\n const resolved = resolve(filePath);\n const cwdResolved = resolve(cwd);\n\n if (resolved !== cwdResolved && !resolved.startsWith(cwdResolved + sep)) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Access denied: \"${filePath}\" is outside the working directory`,\n };\n return JSON.stringify(result);\n }\n\n return undefined;\n}\n","/**\n * ReadTool β read a file and return its contents with line numbers (cat -n style).\n *\n * Supports offset/limit for partial reads. Detects binary files and refuses to\n * return their raw bytes. Default limit is 2000 lines.\n */\n\nimport { readFile, stat } from 'node:fs/promises';\n\nimport { z } from 'zod';\n\nimport { checkPathWithinCwd } from './path-guard.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { FunctionTool } from '../implementations/function-tool';\nimport type { ISandboxToolOptions } from '../sandbox/types.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\n\nconst DEFAULT_LIMIT = 2000;\n\nconst ReadSchema = z.object({\n filePath: z.string().describe('The absolute path to the file to read'),\n offset: z\n .number()\n .optional()\n .describe(\n 'The line number to start reading from (1-based). Only provide if the file is too large to read at once',\n ),\n limit: z\n .number()\n .optional()\n .describe(\n `The number of lines to read (default: ${DEFAULT_LIMIT}). Only provide if the file is too large to read at once`,\n ),\n});\n\ntype TReadArgs = z.infer<typeof ReadSchema>;\n\n/**\n * Heuristic binary detection: scan the first 8 KB for null bytes.\n */\nfunction isBinary(buffer: Buffer): boolean {\n const checkLength = Math.min(buffer.length, 8192);\n for (let i = 0; i < checkLength; i++) {\n if (buffer[i] === 0) return true;\n }\n return false;\n}\n\n/**\n * Format lines with 1-based line numbers in cat -n style.\n * Pads line number to the width of the highest line number.\n */\nfunction formatWithLineNumbers(lines: string[], startLine: number): string {\n const lastLineNum = startLine + lines.length - 1;\n const width = String(lastLineNum).length;\n return lines\n .map((line, idx) => {\n const lineNum = String(startLine + idx).padStart(width, ' ');\n return `${lineNum}\\t${line}`;\n })\n .join('\\n');\n}\n\nfunction formatReadResult(\n filePath: string,\n content: string,\n startLine: number,\n limit: number,\n): string {\n const allLines = content.split('\\n');\n\n // Remove trailing empty line if file ends with newline (common in Unix files)\n if (allLines[allLines.length - 1] === '') {\n allLines.pop();\n }\n\n const zeroBasedStart = startLine - 1;\n const selectedLines = allLines.slice(zeroBasedStart, zeroBasedStart + limit);\n\n const output = formatWithLineNumbers(selectedLines, startLine);\n\n const totalLines = allLines.length;\n const returnedLines = selectedLines.length;\n const header =\n returnedLines < totalLines\n ? `[File: ${filePath} (lines ${startLine}-${startLine + returnedLines - 1} of ${totalLines})]\\n`\n : `[File: ${filePath} (${totalLines} lines)]\\n`;\n\n const result: IToolInvocationResult = {\n success: true,\n output: header + output,\n };\n return JSON.stringify(result);\n}\n\nasync function readFileTool(args: TReadArgs, options: ISandboxToolOptions = {}): Promise<string> {\n const { filePath, offset, limit = DEFAULT_LIMIT } = args;\n const startLine = offset !== undefined && offset > 0 ? offset : 1;\n\n if (options.sandboxClient) {\n try {\n const content = await options.sandboxClient.readFile(filePath);\n return formatReadResult(filePath, content, startLine, limit);\n } catch (err) {\n // allow-fallback: sandbox read failure β surface as IToolInvocationResult error\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n }\n\n const pathError = checkPathWithinCwd(filePath, options.cwd);\n if (pathError !== undefined) return pathError;\n\n let fileStats: Awaited<ReturnType<typeof stat>> | undefined;\n try {\n fileStats = await stat(filePath);\n } catch (err) {\n // allow-fallback: stat failure means file not found β IToolInvocationResult error\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `File not found: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n if (!fileStats.isFile()) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Path is not a file: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n let buffer: Buffer;\n try {\n buffer = await readFile(filePath);\n } catch (err) {\n // allow-fallback: read failure β IToolInvocationResult error (permissions, locks)\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n\n if (isBinary(buffer)) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Binary file not supported: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n const content = buffer.toString('utf8');\n return formatReadResult(filePath, content, startLine, limit);\n}\n\n/**\n * Create a ReadTool instance β register with Robota agent tools registry.\n */\nexport function createReadTool(options: ISandboxToolOptions = {}): FunctionTool {\n return createZodFunctionTool(\n 'Read',\n 'Reads a file from the local filesystem.\\n\\nBy default, reads up to 2000 lines from the beginning of the file. You can optionally specify offset and limit for partial reads.\\n\\nResults are returned using cat -n format, with line numbers starting at 1.\\n\\nThe file_path parameter must be an absolute path, not a relative path.',\n ReadSchema,\n async (params) => {\n return readFileTool(params, options);\n },\n );\n}\n\n/**\n * ReadTool instance β register with Robota agent tools registry.\n */\nexport const readTool = createReadTool();\n","import { randomBytes } from 'node:crypto';\nimport { chmod, mkdir, rename, rm, stat, writeFile } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\n\nconst TEMP_RANDOM_BYTES = 6;\nconst PRESERVED_MODE_BITS = 0o7777;\nconst MISSING_FILE_ERROR_CODE = 'ENOENT';\n\nfunction createTempFilePath(filePath: string): string {\n const dir = dirname(filePath);\n const name = basename(filePath);\n const suffix = randomBytes(TEMP_RANDOM_BYTES).toString('hex');\n return join(dir, `.${name}.robota-tmp-${process.pid}-${Date.now()}-${suffix}`);\n}\n\nasync function readExistingMode(filePath: string): Promise<number | undefined> {\n try {\n const fileStats = await stat(filePath);\n return fileStats.mode & PRESERVED_MODE_BITS;\n } catch (error) {\n if (error instanceof Error && hasErrorCode(error, MISSING_FILE_ERROR_CODE)) return undefined;\n throw error;\n }\n}\n\nfunction hasErrorCode(error: Error, code: string): boolean {\n return 'code' in error && error.code === code;\n}\n\nexport async function atomicWriteUtf8File(filePath: string, content: string): Promise<void> {\n const dir = dirname(filePath);\n await mkdir(dir, { recursive: true });\n\n const existingMode = await readExistingMode(filePath);\n const tempFilePath = createTempFilePath(filePath);\n try {\n await writeFile(tempFilePath, content, 'utf8');\n if (existingMode !== undefined) {\n await chmod(tempFilePath, existingMode);\n }\n await rename(tempFilePath, filePath);\n } catch (error) {\n await rm(tempFilePath, { force: true }).catch(() => undefined);\n throw error;\n }\n}\n","/**\n * WriteTool β write content to a file, auto-creating parent directories.\n */\n\nimport { z } from 'zod';\n\nimport { atomicWriteUtf8File } from './atomic-file-write.js';\nimport { checkPathWithinCwd } from './path-guard.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { FunctionTool } from '../implementations/function-tool';\nimport type { ISandboxToolOptions } from '../sandbox/types.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\n\nconst WriteSchema = z.object({\n filePath: z.string().describe('The absolute path to the file to write'),\n content: z.string().describe('The content to write to the file'),\n});\n\ntype TWriteArgs = z.infer<typeof WriteSchema>;\n\nasync function writeFileTool(args: TWriteArgs, options: ISandboxToolOptions = {}): Promise<string> {\n const { filePath, content } = args;\n\n if (!options.sandboxClient) {\n const pathError = checkPathWithinCwd(filePath, options.cwd);\n if (pathError !== undefined) return pathError;\n }\n\n try {\n if (options.sandboxClient) {\n await options.sandboxClient.writeFile(filePath, content);\n } else {\n await atomicWriteUtf8File(filePath, content);\n }\n\n const result: IToolInvocationResult = {\n success: true,\n output: `Written ${Buffer.byteLength(content, 'utf8')} bytes to ${filePath}`,\n };\n return JSON.stringify(result);\n } catch (err) {\n // allow-fallback: write failure β IToolInvocationResult error (disk full, permissions)\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n}\n\n/**\n * Create a WriteTool instance β register with Robota agent tools registry.\n */\nexport function createWriteTool(options: ISandboxToolOptions = {}): FunctionTool {\n return createZodFunctionTool(\n 'Write',\n 'Writes a file to the local filesystem. This will overwrite an existing file if one exists.\\n\\nALWAYS prefer the Edit tool for modifying existing files β it only sends the diff. Only use this tool to create new files or for complete rewrites.\\n\\nNEVER create documentation files (*.md) or README files unless explicitly requested by the user.',\n WriteSchema,\n async (params) => {\n return writeFileTool(params, options);\n },\n );\n}\n\n/**\n * WriteTool instance β register with Robota agent tools registry.\n */\nexport const writeTool = createWriteTool();\n","/**\n * EditTool β perform string-replace edits on a file.\n *\n * By default, requires the oldString to appear exactly once in the file\n * (ensuring surgical edits). Pass replaceAll:true to replace all occurrences.\n */\n\nimport { readFile } from 'node:fs/promises';\n\nimport { z } from 'zod';\n\nimport { atomicWriteUtf8File } from './atomic-file-write.js';\nimport { checkPathWithinCwd } from './path-guard.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { FunctionTool } from '../implementations/function-tool';\nimport type { ISandboxToolOptions } from '../sandbox/types.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\n\nconst EditSchema = z.object({\n filePath: z.string().describe('The absolute path to the file to modify'),\n oldString: z\n .string()\n .describe('The text to replace (must be an exact match of existing content)'),\n newString: z.string().describe('The text to replace it with (must be different from old_string)'),\n replaceAll: z\n .boolean()\n .optional()\n .describe(\n 'Replace all occurrences of old_string (default: false). Useful for renaming variables',\n ),\n});\n\ntype TEditArgs = z.infer<typeof EditSchema>;\n\nasync function editFileTool(args: TEditArgs, options: ISandboxToolOptions = {}): Promise<string> {\n const { filePath, oldString, newString, replaceAll = false } = args;\n\n if (!options.sandboxClient) {\n const pathError = checkPathWithinCwd(filePath, options.cwd);\n if (pathError !== undefined) return pathError;\n }\n\n let content: string;\n try {\n content = options.sandboxClient\n ? await options.sandboxClient.readFile(filePath)\n : await readFile(filePath, 'utf8');\n } catch (err) {\n // allow-fallback: read failure before edit β IToolInvocationResult error (file not found)\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `File not found: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n if (!content.includes(oldString)) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `oldString not found in file: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n // Uniqueness check when not in replaceAll mode\n if (!replaceAll) {\n const firstIdx = content.indexOf(oldString);\n const lastIdx = content.lastIndexOf(oldString);\n if (firstIdx !== lastIdx) {\n const occurrences = content.split(oldString).length - 1;\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error:\n `oldString is not unique in file (found ${occurrences} occurrences). ` +\n 'Provide more context to make it unique, or use replaceAll:true.',\n };\n return JSON.stringify(result);\n }\n }\n\n const updated = replaceAll\n ? content.split(oldString).join(newString)\n : content.slice(0, content.indexOf(oldString)) +\n newString +\n content.slice(content.indexOf(oldString) + oldString.length);\n\n try {\n if (options.sandboxClient) {\n await options.sandboxClient.writeFile(filePath, updated);\n } else {\n await atomicWriteUtf8File(filePath, updated);\n }\n } catch (err) {\n // allow-fallback: write failure after edit β IToolInvocationResult error\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n\n const count = replaceAll ? content.split(oldString).length - 1 : 1;\n // Calculate start line number from the original content\n const matchIdx = content.indexOf(oldString);\n const startLine = matchIdx >= 0 ? content.substring(0, matchIdx).split('\\n').length : 1;\n const result: IToolInvocationResult = {\n success: true,\n output: `Replaced ${count} occurrence(s) in ${filePath}`,\n startLine,\n };\n return JSON.stringify(result);\n}\n\n/**\n * Create an EditTool instance β register with Robota agent tools registry.\n */\nexport function createEditTool(options: ISandboxToolOptions = {}): FunctionTool {\n return createZodFunctionTool(\n 'Edit',\n 'Performs exact string replacements in files.\\n\\nYou must use the Read tool at least once before editing. When editing text from Read output, preserve the exact indentation.\\n\\nThe edit will FAIL if old_string is not unique in the file. Either provide more surrounding context to make it unique, or use replace_all to change every instance.\\n\\nALWAYS prefer editing existing files over creating new ones.',\n EditSchema,\n async (params) => {\n return editFileTool(params, options);\n },\n );\n}\n\n/**\n * EditTool instance β register with Robota agent tools registry.\n */\nexport const editTool = createEditTool();\n","/**\n * GlobTool β fast file pattern search using fast-glob.\n *\n * Excludes node_modules and .git by default.\n * Results are sorted by modification time (most recently modified first).\n */\n\nimport { stat } from 'node:fs/promises';\nimport { resolve } from 'node:path';\n\nimport fg from 'fast-glob';\nimport pLimit from 'p-limit';\nimport { z } from 'zod';\n\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IToolInvocationResult } from '../types/tool-result.js';\n\nconst DEFAULT_MAX_RESULTS = 1000;\n\nconst GlobSchema = z.object({\n pattern: z\n .string()\n .describe('The glob pattern to match files against (e.g. \"**/*.ts\", \"src/**/*.tsx\")'),\n path: z\n .string()\n .optional()\n .describe(\n 'The directory to search in. Defaults to the current working directory. Must be a valid directory path if provided',\n ),\n limit: z\n .number()\n .optional()\n .describe(\n 'Maximum number of results to return (default: 1000). Use a smaller limit to save context space',\n ),\n});\n\ntype TGlobArgs = z.infer<typeof GlobSchema>;\n\ninterface IFileWithMtime {\n path: string;\n mtime: number;\n}\n\nasync function globFileTool(args: TGlobArgs): Promise<string> {\n const { pattern, path: basePath } = args;\n const cwd = basePath ? resolve(basePath) : process.cwd();\n\n let matches: string[];\n try {\n matches = await fg(pattern, {\n cwd,\n ignore: ['**/node_modules/**', '**/.git/**'],\n dot: true,\n absolute: false,\n });\n } catch (err) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n\n // Sort by mtime (most recent first); cap concurrent stat calls to avoid I/O explosion\n const limit = pLimit(100);\n const withMtime: IFileWithMtime[] = await Promise.all(\n matches.map((p) =>\n limit(async () => {\n const absPath = resolve(cwd, p);\n try {\n const s = await stat(absPath);\n return { path: p, mtime: s.mtimeMs };\n } catch {\n // allow-fallback: stat failure on a matched path returns mtime=0 (sort-last), not a logic fallback\n return { path: p, mtime: 0 };\n }\n }),\n ),\n );\n\n withMtime.sort((a, b) => b.mtime - a.mtime);\n\n const maxResults = args.limit ?? DEFAULT_MAX_RESULTS;\n const totalMatches = withMtime.length;\n const truncated = totalMatches > maxResults;\n const limited = truncated ? withMtime.slice(0, maxResults) : withMtime;\n const sorted = limited.map((f) => f.path);\n\n let output = sorted.length > 0 ? sorted.join('\\n') : '(no matches)';\n if (truncated) {\n output += `\\n\\n[Showing ${maxResults} of ${totalMatches} matches. Use limit parameter to see more.]`;\n }\n\n const result: IToolInvocationResult = {\n success: true,\n output,\n };\n return JSON.stringify(result);\n}\n\n/**\n * GlobTool instance β register with Robota agent tools registry.\n */\nexport const globTool = createZodFunctionTool(\n 'Glob',\n \"Fast file pattern matching tool that works with any codebase size.\\n\\nSupports glob patterns like '**/*.js' or 'src/**/*.ts'. Returns matching file paths sorted by modification time.\\n\\nUse this tool when you need to find files by name patterns. When doing an open-ended search that may require multiple rounds, use the Agent tool instead.\\n\\nDefault limit is 1000 results. Use the limit parameter if you need fewer results to save context space.\",\n GlobSchema,\n async (params) => {\n return globFileTool(params);\n },\n);\n","/**\n * GrepTool β recursive regex content search.\n *\n * Supports three output modes:\n * - files_with_matches (default): return only file paths that contain a match\n * - content: return matching lines with optional context lines\n * - count: return per-file match counts as \"path:count\" rows\n *\n * headLimit caps the number of result lines; excess is truncated with a marker.\n */\n\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IToolInvocationResult } from '../types/tool-result.js';\n\nconst GrepSchema = z.object({\n pattern: z.string().describe('The regular expression pattern to search for in file contents'),\n path: z\n .string()\n .optional()\n .describe('File or directory to search in. Defaults to the current working directory'),\n glob: z\n .string()\n .optional()\n .describe(\n 'Glob pattern to filter files (e.g. \"*.ts\", \"*.{ts,tsx}\"). Only files matching this pattern will be searched',\n ),\n contextLines: z\n .number()\n .optional()\n .describe(\n 'Number of context lines to show before and after each match. Only applies when outputMode is \"content\". Default: 0',\n ),\n outputMode: z\n .enum(['files_with_matches', 'content', 'count'])\n .optional()\n .describe(\n 'Output mode: \"files_with_matches\" shows only file paths (default), \"content\" shows matching lines with context, \"count\" shows per-file match counts',\n ),\n headLimit: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n 'Maximum number of result lines (file paths, content lines, or count rows) to return. Excess results are truncated with a marker line',\n ),\n});\n\ntype TGrepArgs = z.infer<typeof GrepSchema>;\n\n/** Convert a simple glob to a RegExp for file name filtering. */\nfunction globToRegex(glob: string): RegExp {\n const escaped = glob\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .replace(/\\*\\*/g, '.+')\n .replace(/\\*/g, '[^/]*');\n return new RegExp(`^${escaped}$`);\n}\n\n/** Check if a file name matches an optional glob filter. */\nfunction matchesGlob(filename: string, glob: string | undefined): boolean {\n if (glob === undefined) return true;\n return globToRegex(glob).test(filename);\n}\n\n/** Gather all files under a directory recursively, excluding node_modules/.git. */\nasync function collectFiles(dirPath: string, glob: string | undefined): Promise<string[]> {\n const results: string[] = [];\n\n async function walk(current: string): Promise<void> {\n let entryNames: string[];\n try {\n entryNames = await readdir(current);\n } catch {\n return;\n }\n\n for (const name of entryNames) {\n if (name === 'node_modules' || name === '.git') continue;\n\n const fullPath = join(current, name);\n let fileStat: Awaited<ReturnType<typeof stat>>;\n try {\n fileStat = await stat(fullPath);\n } catch {\n continue;\n }\n\n if (fileStat.isDirectory()) {\n await walk(fullPath);\n } else if (fileStat.isFile()) {\n if (matchesGlob(name, glob)) {\n results.push(fullPath);\n }\n }\n }\n }\n\n await walk(dirPath);\n return results;\n}\n\n/** Search a single file for lines matching the regex. */\nfunction searchFile(\n content: string,\n filePath: string,\n regex: RegExp,\n contextLines: number,\n outputMode: 'files_with_matches' | 'content' | 'count',\n): string[] {\n const lines = content.split('\\n');\n const matchingIndices: number[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n if (regex.test(lines[i])) {\n matchingIndices.push(i);\n }\n }\n\n if (matchingIndices.length === 0) return [];\n\n if (outputMode === 'files_with_matches') {\n return [filePath];\n }\n\n if (outputMode === 'count') {\n return [`${filePath}:${matchingIndices.length}`];\n }\n\n // content mode β include context lines\n const includedIndices = new Set<number>();\n for (const idx of matchingIndices) {\n for (\n let c = Math.max(0, idx - contextLines);\n c <= Math.min(lines.length - 1, idx + contextLines);\n c++\n ) {\n includedIndices.add(c);\n }\n }\n\n const outputLines: string[] = [];\n const sortedIndices = Array.from(includedIndices).sort((a, b) => a - b);\n\n let prevIdx: number | undefined;\n for (const idx of sortedIndices) {\n if (prevIdx !== undefined && idx > prevIdx + 1) {\n outputLines.push('--');\n }\n const lineNum = idx + 1;\n const marker = matchingIndices.includes(idx) ? ':' : '-';\n outputLines.push(`${filePath}:${lineNum}${marker}${lines[idx]}`);\n prevIdx = idx;\n }\n\n return outputLines;\n}\n\nasync function grepFileTool(args: TGrepArgs): Promise<string> {\n const {\n pattern,\n path: searchPath,\n glob,\n contextLines = 0,\n outputMode = 'files_with_matches',\n headLimit,\n } = args;\n const targetPath = searchPath ? resolve(searchPath) : process.cwd();\n\n let regex: RegExp;\n try {\n regex = new RegExp(pattern);\n } catch (err) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Invalid regex pattern: ${pattern}`,\n };\n return JSON.stringify(result);\n }\n\n // Determine whether targetPath is a file or directory\n let targetStat: Awaited<ReturnType<typeof stat>>;\n try {\n targetStat = await stat(targetPath);\n } catch {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Path not found: ${targetPath}`,\n };\n return JSON.stringify(result);\n }\n\n let files: string[];\n if (targetStat.isFile()) {\n files = [targetPath];\n } else {\n files = await collectFiles(targetPath, glob);\n }\n\n const allOutputLines: string[] = [];\n\n for (const filePath of files) {\n let content: string;\n try {\n const buffer = await readFile(filePath);\n // Skip binary files\n const checkLen = Math.min(buffer.length, 8192);\n let hasBinary = false;\n for (let i = 0; i < checkLen; i++) {\n if (buffer[i] === 0) {\n hasBinary = true;\n break;\n }\n }\n if (hasBinary) continue;\n content = buffer.toString('utf8');\n } catch {\n continue;\n }\n\n const fileMatches = searchFile(content, filePath, regex, contextLines, outputMode);\n allOutputLines.push(...fileMatches);\n }\n\n let outputLines = allOutputLines;\n if (headLimit !== undefined && outputLines.length > headLimit) {\n const truncatedCount = outputLines.length - headLimit;\n outputLines = [\n ...outputLines.slice(0, headLimit),\n `(+${truncatedCount} more results truncated by headLimit)`,\n ];\n }\n\n const result: IToolInvocationResult = {\n success: true,\n output: outputLines.length > 0 ? outputLines.join('\\n') : '(no matches)',\n };\n return JSON.stringify(result);\n}\n\n/**\n * GrepTool instance β register with Robota agent tools registry.\n */\nexport const grepTool = createZodFunctionTool(\n 'Grep',\n \"A powerful search tool built on regex matching.\\n\\nSupports full regex syntax (e.g., 'log.*Error', 'function\\\\\\\\s+\\\\\\\\w+'). Filter files with glob parameter (e.g., '*.js', '**/*.tsx').\\n\\nOutput modes: 'content' shows matching lines with context, 'files_with_matches' shows only file paths (default), 'count' shows per-file match counts.\\n\\nUse this tool for ALL search tasks. NEVER invoke grep or rg as a Bash command.\\n\\nUse headLimit to control result size and save context space.\",\n GrepSchema,\n async (params) => {\n return grepFileTool(params);\n },\n);\n","/**\n * WebFetchTool β fetch a URL and return its content as text.\n *\n * HTML is stripped to plain text for readability. Uses Node.js native fetch.\n * Output is capped at 30K chars (same as other tools).\n */\n\nimport { z } from 'zod';\n\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IToolInvocationResult } from '../types/tool-result.js';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst MAX_RESPONSE_BYTES = 5_000_000; // 5 MB max download\n\nconst WebFetchSchema = z.object({\n url: z.string().describe('The URL to fetch'),\n headers: z.record(z.string()).optional().describe('Optional HTTP headers as key-value pairs'),\n});\n\ntype TWebFetchArgs = z.infer<typeof WebFetchSchema>;\n\n/** Strip HTML tags and decode common entities to produce readable text. */\nfunction htmlToText(html: string): string {\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<[^>]+>/g, ' ')\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/ /g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nexport function classifyFetchError(err: unknown): string {\n if (!(err instanceof Error)) return String(err);\n\n if (err.name === 'AbortError') {\n return `Request timed out after ${DEFAULT_TIMEOUT_MS / 1000}s. The server did not respond in time.`;\n }\n\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOTFOUND' || code === 'EAI_AGAIN') {\n return `Network error: DNS resolution failed for this host. The URL may be incorrect or the host does not exist. Do not retry with the same URL.`;\n }\n if (code === 'ECONNREFUSED') {\n return `Network error: Connection refused. The server is not accepting connections at this address. Do not retry with the same URL.`;\n }\n if (code === 'ECONNRESET') {\n return `Network error: Connection was reset by the server. The server may be temporarily unavailable.`;\n }\n if (code === 'ETIMEDOUT') {\n return `Network error: Connection timed out. The server is not reachable within the expected time.`;\n }\n if (code === 'CERT_HAS_EXPIRED' || code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {\n return `Network error: SSL certificate error (${code}). The server's certificate is invalid. Do not retry with the same URL.`;\n }\n\n return `Network error: ${err.message} Check that the URL is correct and the server is reachable.`;\n}\n\nasync function runWebFetch(args: TWebFetchArgs, signal?: AbortSignal): Promise<string> {\n const { url, headers } = args;\n\n try {\n new URL(url);\n } catch {\n // allow-fallback: URL parse failure is a structured tool result, not a thrown error\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Invalid URL: \"${url}\". Fix the URL format before retrying.`,\n };\n return JSON.stringify(result);\n }\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);\n // CORE-018: the run-scoped signal aborts the in-flight request alongside the timeout.\n const fetchSignal = signal ? AbortSignal.any([controller.signal, signal]) : controller.signal;\n\n const response = await fetch(url, {\n headers: {\n 'User-Agent': 'Robota-CLI/3.0',\n ...(headers ?? {}),\n },\n signal: fetchSignal,\n redirect: 'follow',\n });\n\n clearTimeout(timeout);\n\n if (!response.ok) {\n const retryHint =\n response.status >= 500\n ? ' The server is temporarily unavailable β retrying may help.'\n : ' Do not retry with the same URL.';\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `HTTP ${response.status} ${response.statusText}.${retryHint}`,\n };\n return JSON.stringify(result);\n }\n\n const contentType = response.headers.get('content-type') ?? '';\n const buffer = await response.arrayBuffer();\n\n if (buffer.byteLength > MAX_RESPONSE_BYTES) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Response too large: ${buffer.byteLength} bytes (max ${MAX_RESPONSE_BYTES}). Consider fetching a more specific URL or a paginated endpoint.`,\n };\n return JSON.stringify(result);\n }\n\n let text = new TextDecoder().decode(buffer);\n\n // Strip HTML if content-type indicates HTML\n if (contentType.includes('html')) {\n text = htmlToText(text);\n }\n\n const result: IToolInvocationResult = { success: true, output: text };\n return JSON.stringify(result);\n } catch (err) {\n // allow-fallback: fetch errors are structured tool results returned to the LLM, not thrown\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: classifyFetchError(err),\n };\n return JSON.stringify(result);\n }\n}\n\nexport const webFetchTool = createZodFunctionTool(\n 'WebFetch',\n 'Fetch a URL and return its content as text. HTML pages are converted to plain text.',\n WebFetchSchema,\n async (params, context) => runWebFetch(params, context?.signal),\n);\n","/**\n * WebSearchTool β search the web and return results.\n *\n * Uses Brave Search API when BRAVE_API_KEY is set.\n * Returns an error with setup instructions otherwise.\n */\n\nimport { z } from 'zod';\n\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IToolInvocationResult } from '../types/tool-result.js';\n\nconst DEFAULT_LIMIT = 10;\nconst DEFAULT_TIMEOUT_MS = 15_000;\n\nconst WebSearchSchema = z.object({\n query: z.string().describe('The search query'),\n limit: z\n .number()\n .optional()\n .describe(`Maximum number of results to return (default: ${DEFAULT_LIMIT})`),\n});\n\ntype TWebSearchArgs = z.infer<typeof WebSearchSchema>;\n\ninterface IBraveResult {\n title: string;\n url: string;\n description: string;\n}\n\ninterface IBraveResponse {\n web?: {\n results?: IBraveResult[];\n };\n}\n\nasync function runWebSearch(args: TWebSearchArgs, signal?: AbortSignal): Promise<string> {\n const { query, limit = DEFAULT_LIMIT } = args;\n const apiKey = process.env['BRAVE_API_KEY'];\n\n if (!apiKey) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error:\n 'Web search requires BRAVE_API_KEY environment variable. ' +\n 'Get a free API key at https://brave.com/search/api/ (2,000 queries/month free).',\n };\n return JSON.stringify(result);\n }\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);\n // CORE-018: run-scoped signal aborts the in-flight request alongside the timeout.\n const fetchSignal = signal ? AbortSignal.any([controller.signal, signal]) : controller.signal;\n\n const params = new URLSearchParams({\n q: query,\n count: String(Math.min(limit, 20)),\n });\n\n const response = await fetch(`https://api.search.brave.com/res/v1/web/search?${params}`, {\n headers: {\n Accept: 'application/json',\n 'Accept-Encoding': 'gzip',\n 'X-Subscription-Token': apiKey,\n },\n signal: fetchSignal,\n });\n\n clearTimeout(timeout);\n\n if (!response.ok) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Brave Search API error: HTTP ${response.status} ${response.statusText}`,\n };\n return JSON.stringify(result);\n }\n\n const data = (await response.json()) as IBraveResponse;\n const results = (data.web?.results ?? []).map((r) => ({\n title: r.title,\n url: r.url,\n snippet: r.description,\n }));\n\n const result: IToolInvocationResult = {\n success: true,\n output: JSON.stringify(results, null, 2),\n };\n return JSON.stringify(result);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const result: IToolInvocationResult = { success: false, output: '', error: message };\n return JSON.stringify(result);\n }\n}\n\nexport const webSearchTool = createZodFunctionTool(\n 'WebSearch',\n 'Search the web and return results with title, URL, and snippet.',\n WebSearchSchema,\n async (params, context) => runWebSearch(params, context?.signal),\n);\n","/**\n * AskUserQuestionTool β let the model ask the user structured questions mid-turn (CMD-005).\n *\n * Built on the CMD-004 ask seam: each question maps onto the `IActionRequest` SSOT and is issued\n * through the injected `IToolExecutionContext.ask` port; the attached environment renders it (Ink\n * dialog, web modal, programmatic pre-answer) and the answers return as the tool result.\n *\n * Contract points (spec CMD-005):\n * - 1β4 questions per call, asked sequentially (the channel's ask queue renders one at a time).\n * - Cancellation is data, not an exception: a dismissed question yields `{ cancelled: true }` and the\n * remaining unasked questions of the same call are marked cancelled too (no per-item re-prompt).\n * - No `context.ask` (headless/automation): returns `{ unavailable: true, reason }` β never a silent\n * guess, never a thrown error, so the model can continue autonomously.\n */\n\nimport { randomUUID } from 'node:crypto';\n\nimport { z } from 'zod';\n\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { FunctionTool } from '../implementations/function-tool';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { IActionRequest, IToolExecutionContext } from '@robota-sdk/agent-core';\n\nconst MAX_QUESTIONS = 4;\n\nconst QuestionSchema = z.object({\n question: z.string().min(1).describe('The complete question to ask the user.'),\n header: z\n .string()\n .optional()\n .describe('Very short topic label for the question (e.g. \"Auth method\").'),\n options: z\n .array(\n // Models often write bare strings first (observed live) β accept both shapes, no retry needed.\n z.union([\n z.string().min(1).describe('Display text of this choice.'),\n z.object({\n label: z.string().min(1).describe('Display text of this choice.'),\n description: z.string().optional().describe('What choosing this option means.'),\n }),\n ]),\n )\n .optional()\n .describe('Predefined choices (strings or {label, description}). Omit for pure free text.'),\n multiSelect: z\n .boolean()\n .optional()\n .describe('Allow selecting multiple options (default: single select).'),\n allowFreeText: z\n .boolean()\n .optional()\n .describe('Allow a typed custom answer besides the options (default: true).'),\n});\n\nconst AskUserQuestionSchema = z.object({\n questions: z\n .array(QuestionSchema)\n .min(1)\n .max(MAX_QUESTIONS)\n .describe(`Questions to ask the user (1-${MAX_QUESTIONS}), rendered one at a time.`),\n});\n\ntype TQuestion = z.infer<typeof QuestionSchema>;\ntype TAskUserQuestionArgs = z.infer<typeof AskUserQuestionSchema>;\n\nconst ASK_USER_QUESTION_DESCRIPTION = [\n 'Ask the user one or more structured questions and wait for their answers.',\n '',\n 'Use this when you are blocked on a decision only the user can make β ambiguous requirements,',\n 'mutually exclusive approaches, or choices with real trade-offs. Do not use it for decisions with',\n 'a conventional default or facts you can verify yourself.',\n '',\n `Provide 1-${MAX_QUESTIONS} questions. Each question offers predefined options and/or free text:`,\n ' - options + default: user picks one option (or types a custom answer unless allowFreeText: false)',\n ' - multiSelect: true: user may pick several options',\n ' - no options: pure free-text entry',\n '',\n 'The result is a JSON array with one entry per question: the selected option labels in `values`',\n 'and/or the typed answer in `text`, or `cancelled: true` if the user dismissed the question.',\n 'If no interactive user is attached (headless run), the result is `{ unavailable: true }` β',\n 'continue autonomously with your best judgment and say what you assumed.',\n].join('\\n');\n\n/** Per-question outcome in the tool result. */\nexport type TAskUserQuestionAnswer =\n | { question: string; values: string[]; text?: string }\n | { question: string; cancelled: true };\n\n/** The tool result payload (inside IToolInvocationResult.output). */\nexport type TAskUserQuestionOutput =\n | { answers: TAskUserQuestionAnswer[] }\n | { unavailable: true; reason: string };\n\nfunction toActionRequest(question: TQuestion): IActionRequest {\n // Normalize both accepted option shapes (bare string | {label, description}) to one form.\n const options = (question.options ?? []).map((option) =>\n typeof option === 'string' ? { label: option } : option,\n );\n const multi = question.multiSelect === true && options.length > 1;\n return {\n id: `ask_${randomUUID()}`,\n title: question.question,\n ...(question.header !== undefined ? { description: question.header } : {}),\n ...(options.length > 0\n ? {\n options: options.map((o) => ({\n value: o.label,\n label: o.label,\n ...(o.description !== undefined ? { description: o.description } : {}),\n })),\n }\n : {}),\n minSelect: options.length > 0 ? 1 : 0,\n maxSelect: multi ? options.length : 1,\n // Free text is the reference-UX \"Other\" escape hatch; a question without options is free text.\n allowFreeText: question.allowFreeText !== false || options.length === 0,\n };\n}\n\nasync function askQuestions(\n args: TAskUserQuestionArgs,\n ask: NonNullable<IToolExecutionContext['ask']>,\n): Promise<TAskUserQuestionOutput> {\n const answers: TAskUserQuestionAnswer[] = [];\n let dismissed = false;\n for (const question of args.questions) {\n if (dismissed) {\n answers.push({ question: question.question, cancelled: true });\n continue;\n }\n const response = await ask(toActionRequest(question));\n if (response.type === 'cancelled') {\n dismissed = true;\n answers.push({ question: question.question, cancelled: true });\n continue;\n }\n answers.push({\n question: question.question,\n values: [...response.values],\n ...(response.text !== undefined ? { text: response.text } : {}),\n });\n }\n return { answers };\n}\n\n/**\n * Create an `AskUserQuestion` tool instance β register with the Robota agent tools registry.\n */\nexport function createAskUserQuestionTool(): FunctionTool {\n return createZodFunctionTool(\n 'AskUserQuestion',\n ASK_USER_QUESTION_DESCRIPTION,\n AskUserQuestionSchema,\n async (params, context) => {\n const args = params;\n const ask = context?.ask;\n const output: TAskUserQuestionOutput = ask\n ? await askQuestions(args, ask)\n : { unavailable: true, reason: 'no interactive user attached' };\n const result: IToolInvocationResult = { success: true, output: JSON.stringify(output) };\n return JSON.stringify(result);\n },\n );\n}\n\n/** `AskUserQuestion` tool instance β register with the Robota agent tools registry. */\nexport const askUserQuestionTool = createAskUserQuestionTool();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["join","DEFAULT_TIMEOUT_MS","DEFAULT_LIMIT","READ_CHUNK_BYTES","READ_CHUNK_BYTES","DEFAULT_TIMEOUT_MS"],"sources":["../../src/sandbox/e2b-sandbox-client.ts","../../src/sandbox/in-memory-sandbox-client.ts","../../src/sandbox/containment.ts","../../src/sandbox/manifest-enforceability.ts","../../src/sandbox/workspace-manifest.ts","../../src/sandbox/os-sandbox-policy.ts","../../src/sandbox/os-sandbox-seccomp.ts","../../src/sandbox/os-sandbox-client.ts","../../src/retrieval/repo-map-index.ts","../../src/retrieval/repo-map-adapter.ts","../../src/implementations/function-tool.ts","../../src/tool-permission-profiles.ts","../../src/retrieval/retrieval-tool.ts","../../src/computer-use/computer-tool.ts","../../src/computer-use/page-computer-driver.ts","../../src/builtins/shell-tool-description.ts","../../src/builtins/shell-tool.ts","../../src/builtins/path-guard.ts","../../src/builtins/read-tool.ts","../../src/builtins/atomic-file-write.ts","../../src/builtins/write-tool.ts","../../src/builtins/edit-tool.ts","../../src/builtins/glob-tool.ts","../../src/builtins/grep-search.ts","../../src/builtins/isolated-grep-search.ts","../../src/builtins/grep-tool.ts","../../src/builtins/web-fetch-tool.ts","../../src/builtins/brave-search-provider.ts","../../src/builtins/web-search-tool.ts","../../src/builtins/ask-user-question-tool.ts","../../src/builtins/tool-search-matching.ts","../../src/builtins/tool-search-tool.ts"],"sourcesContent":["import type { ISandboxClient, ISandboxRunOptions, ISandboxRunResult } from './types.js';\n\ninterface IE2BCommandStartOptions {\n timeoutMs?: number;\n cwd?: string;\n background?: false;\n}\n\ninterface IE2BCommandResult {\n stdout?: string;\n stderr?: string;\n exitCode?: number;\n exit_code?: number;\n}\n\ninterface IE2BCommands {\n run(command: string, options?: IE2BCommandStartOptions): Promise<IE2BCommandResult>;\n}\n\ninterface IE2BFiles {\n read(path: string): Promise<string | Uint8Array>;\n write(path: string, content: string): Promise<void>;\n}\n\ninterface IE2BSnapshot {\n snapshotId?: string;\n id?: string;\n}\n\nexport interface IE2BSandboxAdapter {\n sandboxId?: string;\n commands: IE2BCommands;\n files: IE2BFiles;\n pause?(): Promise<boolean | string | void>;\n connect?(): Promise<IE2BSandboxAdapter>;\n createSnapshot?(): Promise<IE2BSnapshot>;\n}\n\nexport interface IE2BSandboxClientOptions {\n sandbox: IE2BSandboxAdapter;\n connectSandbox?: (sandboxId: string) => Promise<IE2BSandboxAdapter>;\n createSandboxFromSnapshot?: (snapshotId: string) => Promise<IE2BSandboxAdapter>;\n}\n\nexport class E2BSandboxClient implements ISandboxClient {\n private sandbox: IE2BSandboxAdapter;\n private readonly connectSandbox?: (sandboxId: string) => Promise<IE2BSandboxAdapter>;\n private readonly createSandboxFromSnapshot?: (snapshotId: string) => Promise<IE2BSandboxAdapter>;\n\n constructor(options: IE2BSandboxClientOptions) {\n this.sandbox = options.sandbox;\n this.connectSandbox = options.connectSandbox;\n this.createSandboxFromSnapshot = options.createSandboxFromSnapshot;\n }\n\n async run(command: string, options?: ISandboxRunOptions): Promise<ISandboxRunResult> {\n const result = await this.sandbox.commands.run(command, {\n background: false,\n timeoutMs: options?.timeoutMs,\n cwd: options?.workingDirectory,\n });\n\n return {\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n exitCode: result.exitCode ?? result.exit_code ?? 0,\n };\n }\n\n async readFile(path: string): Promise<string> {\n const content = await this.sandbox.files.read(path);\n return typeof content === 'string' ? content : Buffer.from(content).toString('utf8');\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n await this.sandbox.files.write(path, content);\n }\n\n async snapshot(): Promise<string> {\n if (this.sandbox.createSnapshot) {\n const snapshot = await this.sandbox.createSnapshot();\n const snapshotId = snapshot.snapshotId ?? snapshot.id;\n if (!snapshotId) {\n throw new Error('E2B createSnapshot() did not return a snapshot id.');\n }\n return snapshotId;\n }\n const sandboxId = this.sandbox.sandboxId;\n if (!sandboxId) {\n throw new Error('E2B sandboxId is required to create a resumable sandbox snapshot.');\n }\n if (!this.sandbox.pause) {\n throw new Error('E2B sandbox adapter does not expose pause().');\n }\n await this.sandbox.pause();\n return sandboxId;\n }\n\n async restore(snapshotId: string): Promise<void> {\n if (this.createSandboxFromSnapshot) {\n this.sandbox = await this.createSandboxFromSnapshot(snapshotId);\n return;\n }\n if (this.connectSandbox) {\n this.sandbox = await this.connectSandbox(snapshotId);\n return;\n }\n if (this.sandbox.sandboxId === snapshotId && this.sandbox.connect) {\n this.sandbox = await this.sandbox.connect();\n return;\n }\n throw new Error(\n 'E2B sandbox restore requires connectSandbox(snapshotId) or sandbox.connect().',\n );\n }\n}\n","import type { ISandboxClient, ISandboxRunOptions, ISandboxRunResult } from './types.js';\n\nexport type TInMemorySandboxRunHandler = (\n command: string,\n options: ISandboxRunOptions | undefined,\n files: ReadonlyMap<string, string>,\n) => Promise<ISandboxRunResult> | ISandboxRunResult;\n\nexport interface IInMemorySandboxClientOptions {\n files?: Record<string, string>;\n runHandler?: TInMemorySandboxRunHandler;\n}\n\nexport class InMemorySandboxClient implements ISandboxClient {\n private readonly files = new Map<string, string>();\n private readonly snapshots = new Map<string, Map<string, string>>();\n private readonly runHandler?: TInMemorySandboxRunHandler;\n private snapshotSequence = 0;\n\n constructor(options: IInMemorySandboxClientOptions = {}) {\n for (const [path, content] of Object.entries(options.files ?? {})) {\n this.files.set(path, content);\n }\n this.runHandler = options.runHandler;\n }\n\n async run(command: string, options?: ISandboxRunOptions): Promise<ISandboxRunResult> {\n if (this.runHandler) {\n return this.runHandler(command, options, this.files);\n }\n return { stdout: '', stderr: '', exitCode: 0 };\n }\n\n async readFile(path: string): Promise<string> {\n const content = this.files.get(path);\n if (content === undefined) {\n throw new Error(`Sandbox file not found: ${path}`);\n }\n return content;\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n this.files.set(path, content);\n }\n\n async snapshot(): Promise<string> {\n const snapshotId = `snapshot-${++this.snapshotSequence}`;\n this.snapshots.set(snapshotId, new Map(this.files));\n return snapshotId;\n }\n\n async restore(snapshotId: string): Promise<void> {\n const snapshot = this.snapshots.get(snapshotId);\n if (!snapshot) {\n throw new Error(`Sandbox snapshot not found: ${snapshotId}`);\n }\n this.files.clear();\n for (const [path, content] of snapshot.entries()) {\n this.files.set(path, content);\n }\n }\n\n getFile(path: string): string | undefined {\n return this.files.get(path);\n }\n}\n","/**\n * Where tool execution is contained, named rather than inferred from an absent value (issue #3081).\n *\n * Without a sandbox client every command runs on the host, and \"no client\" read as \"nothing to say\".\n * Naming it lets a host report the choice (`robota doctor`) and lets the tool factories route file\n * tools by one rule instead of each checking for a client.\n */\n\nimport type { ISandboxClient, TSandboxFilesystem } from './types.js';\n\nexport type TExecutionContainment = 'host' | `sandbox-${TSandboxFilesystem}`;\n\nexport function describeExecutionContainment(client: ISandboxClient | undefined): TExecutionContainment {\n if (client === undefined) return 'host';\n return `sandbox-${client.filesystem ?? 'separate'}`;\n}\n\n/** Whether file tools must read and write through the sandbox rather than the host filesystem. */\nexport function routesFilesThroughSandbox(client: ISandboxClient | undefined): boolean {\n return describeExecutionContainment(client) === 'sandbox-separate';\n}\n","import type { IWorkspaceManifest } from './types.js';\n\n/**\n * Refuse a manifest whose security-bearing fields the built-in applicator cannot enforce.\n *\n * Emptiness is what is checked, not presence: `environment: {}` and `permissions: {}` request\n * nothing, so refusing them would fail a caller that asked for no controls at all. `permissions`\n * counts as empty when neither list has an entry β `{ read: [] }` is a declared-but-empty policy,\n * not a policy.\n */\nexport function refuseUnenforceableManifestControls(manifest: IWorkspaceManifest): void {\n const unenforceable: string[] = [];\n\n if (manifest.environment && Object.keys(manifest.environment).length > 0) {\n unenforceable.push('environment');\n }\n\n // Read over the object's VALUES rather than naming `read` and `write`. Naming them is exhaustive\n // today by coincidence, not by construction: adding an `execute?: string[]` member to\n // `IWorkspaceManifestPermissions` would leave a named check silently not covering it, so a manifest\n // requesting `execute` would be accepted and ignored β this function's own defect, reintroduced,\n // with nothing failing.\n //\n // The emptiness rule differs by shape, and treating every member as array-valued would move the\n // coincidence rather than remove it: `.length` on a `boolean` member reads `undefined`, so\n // `{ network: true }` would pass unrefused, and on a `string` member it would refuse by accident.\n // An array can be present and request nothing, so it is judged empty-or-not; anything else is a\n // request by virtue of being there at all β including `false`, which asks for a control this\n // applicator equally cannot apply. This is a runtime boundary of a published package, so a\n // JavaScript caller can supply a member the type does not declare.\n const permissions = manifest.permissions;\n const requestsSomething = (value: string[] | undefined): boolean =>\n Array.isArray(value) ? value.length > 0 : value !== undefined;\n if (permissions && Object.values(permissions).some(requestsSomething)) {\n unenforceable.push('permissions');\n }\n\n if (unenforceable.length === 0) {\n return;\n }\n\n throw new Error(\n `workspace manifest requests ${unenforceable.join(' and ')}, which this sandbox client cannot ` +\n 'enforce. The built-in applicator applies entries only. Supply a sandbox client that ' +\n 'implements applyManifest and honours these fields, or remove them from the manifest β they ' +\n 'were previously accepted and silently ignored, which reported a sandbox policy that was ' +\n 'never applied (issue #2027).',\n );\n}\n","import { readdir, readFile } from 'node:fs/promises';\nimport { isAbsolute, join, posix, resolve } from 'node:path';\n\nimport { refuseUnenforceableManifestControls } from './manifest-enforceability.js';\n\nimport type {\n ISandboxClient,\n IWorkspaceManifest,\n IWorkspaceManifestAppliedEntry,\n IWorkspaceManifestApplyOptions,\n IWorkspaceManifestApplyResult,\n TWorkspaceManifestEntry,\n} from './types.js';\n\nconst DEFAULT_TARGET_ROOT = '/workspace';\nconst WINDOWS_ABSOLUTE_PATH_PATTERN = /^[A-Za-z]:[\\\\/]/;\nconst SHELL_QUOTE_PATTERN = /'/g;\n\nexport async function applyWorkspaceManifest(\n sandboxClient: ISandboxClient,\n manifest: IWorkspaceManifest,\n options: IWorkspaceManifestApplyOptions = {},\n): Promise<IWorkspaceManifestApplyResult> {\n if (sandboxClient.applyManifest) {\n return sandboxClient.applyManifest(manifest, options);\n }\n\n // TOOL-005 / issue #2027. Past this point the built-in applicator is what runs, and it applies\n // ENTRIES only β it has no mechanism for `environment` or `permissions`. Before this check it\n // applied the entries and returned success, so a caller that had asked for an environment\n // allowlist or a read/write policy got a sandbox with neither and no way to find out.\n //\n // A control that is requested and not applied must not be reported as applied, and the failure\n // direction matters: this is a SECURITY surface, so the unenforceable request fails closed rather\n // than warning. It throws before any entry is applied, so a refused manifest leaves nothing\n // half-built.\n //\n // The delegating branch above is deliberately untouched: a client that implements `applyManifest`\n // is claiming ownership of the whole manifest, and this function cannot know what it honoured.\n // Making that claim observable needs a wider apply result and is tracked separately on #2027.\n refuseUnenforceableManifestControls(manifest);\n\n const targetRoot = normalizeSandboxRoot(options.targetRoot ?? DEFAULT_TARGET_ROOT);\n const appliedEntries: IWorkspaceManifestAppliedEntry[] = [];\n\n for (const [rawPath, entry] of Object.entries(manifest.entries)) {\n const path = validateWorkspaceManifestPath(rawPath);\n const targetPath = joinSandboxPath(targetRoot, path);\n appliedEntries.push(\n await applyManifestEntry(sandboxClient, path, targetPath, targetRoot, entry, options),\n );\n }\n\n return { entries: appliedEntries };\n}\n\nexport function validateWorkspaceManifestPath(path: string): string {\n if (path.length === 0) {\n throw new Error('workspace manifest path must not be empty');\n }\n if (path.includes('\\0')) {\n throw new Error('workspace manifest path must not contain NUL bytes');\n }\n if (path.startsWith('/') || path.startsWith('\\\\') || WINDOWS_ABSOLUTE_PATH_PATTERN.test(path)) {\n throw new Error('workspace manifest path must be workspace-relative');\n }\n\n const parts = path.replace(/\\\\/g, '/').split('/').filter(Boolean);\n if (parts.length === 0) {\n throw new Error('workspace manifest path must not resolve to the workspace root');\n }\n if (parts.some((part) => part === '..')) {\n throw new Error('workspace manifest path cannot contain traversal segments');\n }\n\n const normalizedParts = parts.filter((part) => part !== '.');\n if (normalizedParts.length === 0) {\n throw new Error('workspace manifest path must not resolve to the workspace root');\n }\n\n return normalizedParts.join('/');\n}\n\nasync function applyManifestEntry(\n sandboxClient: ISandboxClient,\n path: string,\n targetPath: string,\n targetRoot: string,\n entry: TWorkspaceManifestEntry,\n options: IWorkspaceManifestApplyOptions,\n): Promise<IWorkspaceManifestAppliedEntry> {\n switch (entry.type) {\n case 'file':\n await writeSandboxFile(sandboxClient, targetPath, targetRoot, entry.content);\n return createAppliedEntry(path, entry.type);\n case 'dir':\n await createSandboxDirectory(sandboxClient, targetPath);\n return createAppliedEntry(path, entry.type);\n case 'localFile':\n await copyLocalFile(sandboxClient, entry.src, targetPath, targetRoot, options);\n return createAppliedEntry(path, entry.type);\n case 'localDir':\n await copyLocalDirectory(sandboxClient, entry.src, targetPath, options);\n return createAppliedEntry(path, entry.type);\n case 'gitRepo':\n await cloneGitRepository(sandboxClient, entry, targetPath);\n return createAppliedEntry(path, entry.type);\n case 's3Mount':\n case 'gcsMount':\n case 'r2Mount':\n case 'azureBlobMount':\n return {\n path,\n type: entry.type,\n status: 'unsupported',\n message: `${entry.type} requires a provider-specific sandbox adapter.`,\n };\n default:\n return assertUnreachable(entry);\n }\n}\n\nfunction createAppliedEntry(\n path: string,\n type: TWorkspaceManifestEntry['type'],\n): IWorkspaceManifestAppliedEntry {\n return { path, type, status: 'applied' };\n}\n\nasync function copyLocalFile(\n sandboxClient: ISandboxClient,\n source: string,\n targetPath: string,\n targetRoot: string,\n options: IWorkspaceManifestApplyOptions,\n): Promise<void> {\n const hostSourcePath = resolveHostSourcePath(source, options.hostRoot);\n const content = await readFile(hostSourcePath, 'utf8');\n await writeSandboxFile(sandboxClient, targetPath, targetRoot, content);\n}\n\nasync function copyLocalDirectory(\n sandboxClient: ISandboxClient,\n source: string,\n targetPath: string,\n options: IWorkspaceManifestApplyOptions,\n): Promise<void> {\n const hostSourcePath = resolveHostSourcePath(source, options.hostRoot);\n await copyLocalDirectoryRecursive(sandboxClient, hostSourcePath, targetPath);\n}\n\nasync function copyLocalDirectoryRecursive(\n sandboxClient: ISandboxClient,\n sourcePath: string,\n targetPath: string,\n): Promise<void> {\n await createSandboxDirectory(sandboxClient, targetPath);\n const entries = await readdir(sourcePath, { withFileTypes: true });\n\n for (const entry of entries) {\n const childSourcePath = join(sourcePath, entry.name);\n const childTargetPath = joinSandboxPath(targetPath, entry.name);\n if (entry.isDirectory()) {\n await copyLocalDirectoryRecursive(sandboxClient, childSourcePath, childTargetPath);\n continue;\n }\n if (entry.isFile()) {\n const content = await readFile(childSourcePath, 'utf8');\n await sandboxClient.writeFile(childTargetPath, content);\n }\n }\n}\n\nasync function cloneGitRepository(\n sandboxClient: ISandboxClient,\n entry: Extract<TWorkspaceManifestEntry, { type: 'gitRepo' }>,\n targetPath: string,\n): Promise<void> {\n const shallowArgs = entry.shallow === false ? '' : ' --depth 1';\n const refArgs = entry.ref ? ` --branch ${quoteShellArg(entry.ref)}` : '';\n await runSandboxCommand(\n sandboxClient,\n `git clone${shallowArgs}${refArgs} ${quoteShellArg(entry.url)} ${quoteShellArg(targetPath)}`,\n );\n}\n\nasync function writeSandboxFile(\n sandboxClient: ISandboxClient,\n targetPath: string,\n targetRoot: string,\n content: string,\n): Promise<void> {\n const parentPath = posix.dirname(targetPath);\n if (parentPath !== targetRoot) {\n await createSandboxDirectory(sandboxClient, parentPath);\n }\n await sandboxClient.writeFile(targetPath, content);\n}\n\nasync function createSandboxDirectory(\n sandboxClient: ISandboxClient,\n targetPath: string,\n): Promise<void> {\n await runSandboxCommand(sandboxClient, `mkdir -p ${quoteShellArg(targetPath)}`);\n}\n\nasync function runSandboxCommand(sandboxClient: ISandboxClient, command: string): Promise<void> {\n const result = await sandboxClient.run(command);\n if (result.exitCode !== 0) {\n throw new Error(\n `workspace manifest command failed: ${command}\\n${result.stderr ?? result.stdout}`,\n );\n }\n}\n\nfunction resolveHostSourcePath(source: string, hostRoot: string | undefined): string {\n return isAbsolute(source) ? resolve(source) : resolve(hostRoot ?? process.cwd(), source);\n}\n\n/**\n * Remove every trailing `/`, by index scan.\n *\n * Not `replace(/\\/+$/, '')`: that run has no start anchor, so the engine retries it from every offset inside the\n * run and each retry re-scans to the end β 3.0 s on a 100 K run (`js/polynomial-redos`, SEC-003). The backslash\n * conversion in {@link normalizeSandboxRoot} manufactures such a run from a Windows-style path.\n */\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === '/') end -= 1;\n return value.slice(0, end);\n}\n\nfunction normalizeSandboxRoot(root: string): string {\n const normalized = trimTrailingSlashes(root.replace(/\\\\/g, '/'));\n if (!normalized.startsWith('/')) {\n throw new Error('workspace manifest targetRoot must be an absolute sandbox path');\n }\n return normalized.length === 0 ? '/' : normalized;\n}\n\nfunction joinSandboxPath(root: string, path: string): string {\n const normalizedRoot = normalizeSandboxRoot(root);\n if (normalizedRoot === '/') {\n return `/${path}`;\n }\n return `${normalizedRoot}/${path}`;\n}\n\nfunction quoteShellArg(value: string): string {\n return `'${value.replace(SHELL_QUOTE_PATTERN, \"'\\\\''\")}'`;\n}\n\nfunction assertUnreachable(value: never): never {\n throw new Error(`unsupported workspace manifest entry: ${JSON.stringify(value)}`);\n}\n","/**\n * What an OS-level sandbox lets a command touch, written once per backend (issue #3082).\n *\n * The same policy becomes bubblewrap arguments on Linux and a Seatbelt profile on macOS:\n * - the whole filesystem is readable except the `denyRead` paths;\n * - writes are allowed only inside the workspace, the temporary directories and `allowWrite`;\n * - inside the workspace, the files that configure git, the agent, MCP servers and shells stay\n * read-only, so a confined command cannot change what the next session trusts;\n * - the network is either reachable or not. There is no per-domain allowlist: that needs a proxy\n * process the OS cannot enforce, and a boundary here is only worth what the OS enforces.\n */\n\nimport { PROTECTED_DIRECTORY_NAMES, PROTECTED_FILE_NAMES } from '@robota-sdk/agent-core';\n\nexport interface IOsSandboxPolicy {\n /** The workspace root, real path. Writable. */\n readonly root: string;\n /** Temporary directories, real paths. Writable. */\n readonly tempDirectories: readonly string[];\n /** Further writable paths, absolute. */\n readonly allowWrite: readonly string[];\n /** Paths hidden from the command, absolute, with whether each is a directory. */\n readonly denyRead: readonly { readonly path: string; readonly directory: boolean }[];\n readonly network: boolean;\n}\n\n/** An isolated worktree's files are ordinary workspace files. */\nconst WRITABLE_INSIDE_PROTECTED = ['.robota/worktrees', '.claude/worktrees'];\n\nfunction join(root: string, relative: string): string {\n // A loop, not `/\\/+$/`: that pattern rescans every run of slashes and is quadratic on a long one.\n let end = root.length;\n while (end > 0 && root[end - 1] === '/') end -= 1;\n return `${root.slice(0, end)}/${relative}`;\n}\n\n/**\n * Workspace entries a confined command must not write, relative to the root. `.git` is read-only\n * as a whole: the files that make git run something (config, hooks, `commondir`, per-worktree\n * config) are too many and too easy to add to for a list inside it to stay complete, so git\n * commands that write run unconfined, through the ordinary permission path.\n */\nexport function protectedWorkspaceEntries(): readonly string[] {\n return [...PROTECTED_DIRECTORY_NAMES, ...PROTECTED_FILE_NAMES];\n}\n\nexport interface IBubblewrapInput {\n readonly policy: IOsSandboxPolicy;\n /** Which of `protectedWorkspaceEntries()` and the writable worktree folders exist. */\n readonly exists: (path: string) => boolean;\n /** Entry names in a directory, for the worktrees whose `.git` file must stay put. */\n readonly listDirectory: (path: string) => readonly string[];\n readonly cwd: string;\n readonly command: string;\n readonly args: readonly string[];\n /**\n * The descriptor `bwrap --seccomp` reads the Unix-socket filter from. Required when the network\n * is off: without it a daemon's socket is still reachable.\n */\n readonly seccompDescriptor?: number;\n}\n\n/** The `bwrap` argument vector that runs `command args` under the policy. */\nexport function bubblewrapArguments(input: IBubblewrapInput): string[] {\n const { policy } = input;\n const args = ['--ro-bind', '/', '/', '--dev', '/dev', '--proc', '/proc'];\n for (const path of [policy.root, ...policy.tempDirectories, ...policy.allowWrite]) {\n args.push('--bind-try', path, path);\n }\n // A bind over a path that does not exist would create it on the host, so only existing entries\n // are mounted read-only; the client moves aside one a command creates (see the client).\n for (const entry of protectedWorkspaceEntries()) {\n const path = join(policy.root, entry);\n if (input.exists(path)) args.push('--ro-bind', path, path);\n }\n for (const entry of WRITABLE_INSIDE_PROTECTED) {\n const path = join(policy.root, entry);\n if (!input.exists(path)) continue;\n args.push('--bind', path, path);\n // A worktree's `.git` file says where its repository is; it stays read-only too.\n for (const name of input.listDirectory(path)) {\n const gitFile = join(path, `${name}/.git`);\n if (input.exists(gitFile)) args.push('--ro-bind', gitFile, gitFile);\n }\n }\n for (const hidden of policy.denyRead) {\n if (!input.exists(hidden.path)) continue;\n if (hidden.directory) args.push('--tmpfs', hidden.path);\n else args.push('--ro-bind', '/dev/null', hidden.path);\n }\n if (!policy.network) {\n if (input.seccompDescriptor === undefined) {\n throw new Error('A sandbox without network needs the Unix-socket seccomp filter.');\n }\n args.push('--unshare-net', '--seccomp', String(input.seccompDescriptor));\n }\n // Its own process namespace: a confined command cannot signal or trace the host's processes.\n args.push('--unshare-pid', '--die-with-parent', '--new-session', '--chdir', input.cwd);\n args.push('--', input.command);\n return [...args, ...input.args];\n}\n\nfunction regexEscape(path: string): string {\n return path.replace(/[\\\\^$.*+?()[\\]{}|\"]/g, (char) => `\\\\${char}`);\n}\n\nfunction quote(path: string): string {\n return `\"${path.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * The Seatbelt profile for `sandbox-exec -p`. Later rules win, so the order below is the policy:\n * deny writes, allow the writable places, deny the protected entries again, reopen worktrees.\n */\nexport function seatbeltProfile(policy: IOsSandboxPolicy): string {\n const writable = [policy.root, ...policy.tempDirectories, ...policy.allowWrite]\n .map((path) => `(subpath ${quote(path)})`)\n .join(' ');\n const protectedEntries = protectedWorkspaceEntries().map((entry) => {\n const path = join(policy.root, entry);\n return PROTECTED_FILE_NAMES.includes(entry)\n ? `(literal ${quote(path)})`\n : `(subpath ${quote(path)})`;\n });\n const worktrees = WRITABLE_INSIDE_PROTECTED.map(\n (entry) => `(subpath ${quote(join(policy.root, entry))})`,\n );\n // `.git` itself cannot be renamed or replaced, and neither can a worktree's `.git` file.\n const pinned = [\n `(literal ${quote(join(policy.root, '.git'))})`,\n ...WRITABLE_INSIDE_PROTECTED.map(\n (entry) => `(regex #\"^${regexEscape(join(policy.root, entry))}/[^/]+/\\\\.git$\")`,\n ),\n ];\n const lines = [\n '(version 1)',\n '(allow default)',\n '(deny file-write*)',\n `(allow file-write* ${writable} (literal \"/dev/null\") (regex #\"^/dev/tty\") (regex #\"^/dev/fd/\"))`,\n `(deny file-write* ${protectedEntries.join(' ')})`,\n `(allow file-write* ${worktrees.join(' ')})`,\n `(deny file-write* ${pinned.join(' ')})`,\n ];\n if (policy.denyRead.length > 0) {\n const hidden = policy.denyRead.map((entry) =>\n entry.directory ? `(subpath ${quote(entry.path)})` : `(literal ${quote(entry.path)})`,\n );\n lines.push(`(deny file-read* ${hidden.join(' ')})`);\n }\n if (!policy.network) lines.push('(deny network*)');\n return lines.join('\\n');\n}\n","/**\n * The seccomp filter bubblewrap loads when a confined command has no network (issue #3082).\n *\n * `--unshare-net` removes every network interface, but a Unix socket is a file: a daemon listening\n * on one outside the sandbox (a container engine, the session bus, an ssh agent) is still reachable\n * through the read-only filesystem, and is a way to run anything on the host. The filter refuses\n * creating an `AF_UNIX` socket, and refuses `io_uring_setup`, which could create one without the\n * `socket` system call. A system call from another ABI (x32, 32-bit compat) is refused whole, since\n * its numbers differ and the checks below would not see it. macOS's Seatbelt `(deny network*)`\n * already covers Unix sockets.\n */\n\nconst BPF_LD_W_ABS = 0x20;\nconst BPF_JMP_JEQ_K = 0x15;\nconst BPF_JMP_JSET_K = 0x45;\nconst BPF_RET_K = 0x06;\n\nconst SECCOMP_RET_ALLOW = 0x7fff0000;\nconst SECCOMP_RET_ERRNO = 0x00050000;\nconst EPERM = 1;\nconst EAFNOSUPPORT = 97;\nconst AF_UNIX = 1;\nconst X32_SYSCALL_BIT = 0x40000000;\n\n/** `struct seccomp_data` offsets. */\nconst OFFSET_NR = 0;\nconst OFFSET_ARCH = 4;\nconst OFFSET_ARG0_LOW = 16;\n\ninterface IArchitecture {\n readonly audit: number;\n readonly socket: number;\n readonly ioUringSetup: number;\n}\n\nconst ARCHITECTURES: Readonly<Record<string, IArchitecture>> = {\n x64: { audit: 0xc000003e, socket: 41, ioUringSetup: 425 },\n arm64: { audit: 0xc00000b7, socket: 198, ioUringSetup: 425 },\n};\n\nfunction instruction(code: number, jt: number, jf: number, k: number): number[] {\n return [code, jt, jf, k];\n}\n\n/**\n * The filter as bytes `bwrap --seccomp` reads, or `undefined` for a processor architecture it has\n * no system call numbers for β the caller then refuses to confine rather than confine with a gap.\n */\nexport function unixSocketSeccompFilter(arch: string = process.arch): Uint8Array | undefined {\n const target = ARCHITECTURES[arch];\n if (target === undefined) return undefined;\n const errno = (code: number): number => SECCOMP_RET_ERRNO | code;\n const program = [\n /* 0 */ instruction(BPF_LD_W_ABS, 0, 0, OFFSET_ARCH),\n /* 1 */ instruction(BPF_JMP_JEQ_K, 1, 0, target.audit),\n /* 2 */ instruction(BPF_RET_K, 0, 0, errno(EPERM)),\n /* 3 */ instruction(BPF_LD_W_ABS, 0, 0, OFFSET_NR),\n /* 4 */ instruction(BPF_JMP_JSET_K, 0, 1, X32_SYSCALL_BIT),\n /* 5 */ instruction(BPF_RET_K, 0, 0, errno(EPERM)),\n /* 6 */ instruction(BPF_JMP_JEQ_K, 0, 1, target.ioUringSetup),\n /* 7 */ instruction(BPF_RET_K, 0, 0, errno(EPERM)),\n /* 8 */ instruction(BPF_JMP_JEQ_K, 0, 3, target.socket),\n /* 9 */ instruction(BPF_LD_W_ABS, 0, 0, OFFSET_ARG0_LOW),\n /* 10 */ instruction(BPF_JMP_JEQ_K, 0, 1, AF_UNIX),\n /* 11 */ instruction(BPF_RET_K, 0, 0, errno(EAFNOSUPPORT)),\n /* 12 */ instruction(BPF_RET_K, 0, 0, SECCOMP_RET_ALLOW),\n ];\n // `struct sock_filter`: u16 code, u8 jt, u8 jf, u32 k β little-endian on both architectures.\n const bytes = new Uint8Array(program.length * 8);\n const view = new DataView(bytes.buffer);\n program.forEach(([code, jt, jf, k], index) => {\n view.setUint16(index * 8, code!, true);\n view.setUint8(index * 8 + 2, jt!);\n view.setUint8(index * 8 + 3, jf!);\n view.setUint32(index * 8 + 4, k! >>> 0, true);\n });\n return bytes;\n}\n","/**\n * OS-level confinement of shell commands over the host filesystem (issue #3082): bubblewrap on\n * Linux and WSL2, Seatbelt (`sandbox-exec`) on macOS. Other platforms have no backend; the client\n * reports that instead of pretending.\n *\n * It is a `shared` sandbox client: file tools stay on the host under the path guard, and the shell\n * tool starts the wrapped invocation itself. Settings are live β `/sandbox` changes them for the\n * next command without rebuilding the session.\n */\n\nimport { spawn, spawnSync } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport {\n chmodSync,\n cpSync,\n existsSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n readlinkSync,\n renameSync,\n rmSync,\n symlinkSync,\n readFileSync,\n realpathSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { homedir, tmpdir } from 'node:os';\nimport { basename, isAbsolute, resolve } from 'node:path';\n\nimport { resolvePlatformShell, splitCommandSegments } from '@robota-sdk/agent-core';\n\nimport {\n bubblewrapArguments,\n protectedWorkspaceEntries,\n seatbeltProfile,\n} from './os-sandbox-policy.js';\nimport { unixSocketSeccompFilter } from './os-sandbox-seccomp.js';\n\nimport type { IOsSandboxPolicy } from './os-sandbox-policy.js';\nimport type {\n ICommandInvocation,\n ISandboxClient,\n ISandboxRunOptions,\n ISandboxRunResult,\n} from './types.js';\n\nexport type TOsSandboxBackend = 'bubblewrap' | 'seatbelt';\n\nexport interface IOsSandboxSettings {\n /** Confine shell commands. */\n readonly enabled: boolean;\n /** A confined command runs without a prompt; deny and ask rules still apply first. */\n readonly autoAllowBashIfSandboxed: boolean;\n /** Commands (first word) that run unconfined and take the ordinary permission path. */\n readonly excludedCommands: readonly string[];\n /** Further writable paths: absolute, `~/`-relative, or relative to the workspace. */\n readonly allowWrite: readonly string[];\n /** Paths hidden from confined commands, written the same way. */\n readonly denyRead: readonly string[];\n /** Whether confined commands may reach the network. */\n readonly network: boolean;\n}\n\nexport const DEFAULT_OS_SANDBOX_SETTINGS: IOsSandboxSettings = Object.freeze({\n enabled: false,\n autoAllowBashIfSandboxed: true,\n excludedCommands: [],\n allowWrite: [],\n denyRead: [],\n network: false,\n});\n\n/** What this machine can do, found once at startup. */\nexport interface IOsSandboxAvailability {\n readonly backend?: TOsSandboxBackend;\n /** The backend's executable, when found and working. */\n readonly executable?: string;\n /** What to install or fix, when the platform has a backend but it cannot run. */\n readonly missing: readonly string[];\n /** Set when the platform has no backend at all. */\n readonly unsupportedPlatform?: string;\n}\n\nexport interface IDetectOsSandboxOptions {\n readonly platform?: NodeJS.Platform;\n readonly arch?: string;\n /** Test seam; production runs the probe with `spawnSync`. */\n readonly probe?: (command: string, args: readonly string[]) => { ok: boolean; detail?: string };\n}\n\nconst SEATBELT_EXECUTABLE = '/usr/bin/sandbox-exec';\n\nfunction defaultProbe(command: string, args: readonly string[]): { ok: boolean; detail?: string } {\n const result = spawnSync(command, [...args], { timeout: 5_000, encoding: 'utf8' });\n if (result.error !== undefined) return { ok: false, detail: result.error.message };\n const detail = (result.stderr ?? '').trim().split('\\n')[0];\n return result.status === 0 ? { ok: true } : { ok: false, ...(detail ? { detail } : {}) };\n}\n\n/** Find the platform's backend and check it can actually start a sandbox here. */\nexport function detectOsSandbox(options: IDetectOsSandboxOptions = {}): IOsSandboxAvailability {\n const platform = options.platform ?? process.platform;\n const probe = options.probe ?? defaultProbe;\n if (platform === 'linux') {\n if (unixSocketSeccompFilter(options.arch ?? process.arch) === undefined) {\n return {\n backend: 'bubblewrap',\n missing: [\n `a seccomp filter for ${options.arch ?? process.arch} (x64 and arm64 are supported)`,\n ],\n };\n }\n const check = probe('bwrap', ['--ro-bind', '/', '/', '--dev', '/dev', '--unshare-pid', 'true']);\n if (check.ok) return { backend: 'bubblewrap', executable: 'bwrap', missing: [] };\n const reason = check.detail?.includes('ENOENT')\n ? 'bubblewrap (install the `bubblewrap` package)'\n : `bubblewrap cannot create a sandbox here${check.detail ? `: ${check.detail}` : ''}`;\n return { backend: 'bubblewrap', missing: [reason] };\n }\n if (platform === 'darwin') {\n const check = probe(SEATBELT_EXECUTABLE, ['-p', '(version 1)(allow default)', '/usr/bin/true']);\n if (check.ok) return { backend: 'seatbelt', executable: SEATBELT_EXECUTABLE, missing: [] };\n return {\n backend: 'seatbelt',\n missing: [`sandbox-exec cannot run${check.detail ? `: ${check.detail}` : ''}`],\n };\n }\n return { missing: [], unsupportedPlatform: platform };\n}\n\nexport interface IOsSandboxClientOptions {\n /** The workspace root. */\n readonly root: string;\n readonly availability: IOsSandboxAvailability;\n readonly settings?: Partial<IOsSandboxSettings>;\n readonly homeDirectory?: string;\n}\n\nexport interface IOsSandboxStatus {\n readonly settings: IOsSandboxSettings;\n readonly availability: IOsSandboxAvailability;\n /** Settings ask for confinement and the backend can provide it. */\n readonly active: boolean;\n}\n\nfunction realPathOrSelf(path: string): string {\n try {\n return realpathSync(path);\n } catch {\n return path;\n }\n}\n\nfunction isDirectory(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n\ntype IProtectedEntryState =\n | { readonly path: string; readonly kind: 'missing' | 'present' }\n | { readonly path: string; readonly kind: 'symlink'; readonly target: string };\n\n/** Give the owner read, write and search permission throughout an entry, never following links. */\nfunction grantOwnerAccess(path: string): void {\n const stat = lstatSync(path);\n if (stat.isSymbolicLink()) return;\n chmodSync(path, stat.mode | 0o700);\n if (!stat.isDirectory()) return;\n for (const name of readdirSync(path)) grantOwnerAccess(`${path}/${name}`);\n}\n\nfunction isSymbolicLink(path: string): boolean {\n try {\n return lstatSync(path).isSymbolicLink();\n } catch {\n return false;\n }\n}\n\n/** The program a shell line starts first β what `excludedCommands` names. */\nfunction firstProgram(shellCommand: string): string | undefined {\n return shellCommand.trim().split(/\\s+/)[0];\n}\n\nexport class OsSandboxClient implements ISandboxClient {\n readonly filesystem = 'shared' as const;\n private readonly root: string;\n private readonly availability: IOsSandboxAvailability;\n private readonly homeDirectory: string;\n private current: IOsSandboxSettings;\n private inFlight = 0;\n private baseline: IProtectedEntryState[] = [];\n /** Entries a clean-up could not restore, with the state they must return to. */\n private readonly unresolved = new Map<string, IProtectedEntryState>();\n\n constructor(options: IOsSandboxClientOptions) {\n this.root = realPathOrSelf(options.root);\n this.availability = options.availability;\n this.homeDirectory = options.homeDirectory ?? homedir();\n this.current = { ...DEFAULT_OS_SANDBOX_SETTINGS, ...options.settings };\n }\n\n status(): IOsSandboxStatus {\n return {\n settings: this.current,\n availability: this.availability,\n active: this.current.enabled && this.availability.executable !== undefined,\n };\n }\n\n /** Change the settings for the next command. */\n configure(settings: Partial<IOsSandboxSettings>): void {\n this.current = { ...this.current, ...settings };\n }\n\n /** Whether `shellCommand` would run confined. */\n confines(shellCommand: string): boolean {\n if (!this.status().active) return false;\n // An exclusion names one program; a line that runs anything else with it stays confined.\n if (splitCommandSegments(shellCommand).length !== 1) return true;\n const program = firstProgram(shellCommand);\n return program === undefined || !this.current.excludedCommands.includes(program);\n }\n\n autoApproves(shellCommand: string): boolean {\n if (!this.current.autoAllowBashIfSandboxed || !this.confines(shellCommand)) return false;\n if (this.unresolved.size > 0) return false;\n // A protected entry that is a symlink is only as read-only as every directory on its target's\n // path: one that dangles, or points back into the writable workspace, can be redirected by the\n // command (create the target, or swap a directory along the way). A person decides instead.\n return !this.protectedEntryStates().some(\n (state) => state.kind === 'symlink' && !this.resolvesOutsideWritableWorkspace(state.path),\n );\n }\n\n wrapCommand(invocation: ICommandInvocation, shellCommand: string): ICommandInvocation {\n if (!this.confines(shellCommand)) return invocation;\n const policy = this.policy();\n const executable = this.availability.executable!;\n if (this.availability.backend === 'seatbelt') {\n return {\n command: executable,\n args: ['-p', seatbeltProfile(policy), invocation.command, ...invocation.args],\n cwd: invocation.cwd,\n };\n }\n const filter = policy.network ? undefined : unixSocketSeccompFilter();\n // `.robota` is robota's own state directory: made before the command, so it is mounted\n // read-only and nothing the host writes there is caught up in `restoreProtectedEntries`.\n if (\n !this.protectedEntryStates().some(\n (state) => state.path.endsWith('/.robota') && state.kind === 'symlink',\n )\n ) {\n mkdirSync(`${this.root}/.robota`, { recursive: true });\n }\n // One baseline for every confined command in flight: taken when the first starts, restored\n // against when the last ends. A per-command baseline taken while another command runs would\n // record that command's planted entry as the state to restore.\n const args = bubblewrapArguments({\n policy,\n // A protected entry that is a symlink is not mounted: its target outside the workspace is\n // already read-only, one inside refuses auto-approval, and the link itself is restored\n // after exit if the command replaced it.\n exists: (path) => existsSync(path) && !isSymbolicLink(path),\n listDirectory: (path) => readdirSync(path),\n cwd: invocation.cwd,\n command: invocation.command,\n args: invocation.args,\n ...(filter !== undefined ? { seccompDescriptor: 3 } : {}),\n });\n if (this.inFlight === 0) {\n // An entry a clean-up could not restore keeps its earlier state, so it is never taken for\n // a legitimate one.\n this.baseline = this.protectedEntryStates().map(\n (state) => this.unresolved.get(state.path) ?? state,\n );\n }\n this.inFlight += 1;\n let finished = false;\n return {\n command: executable,\n args,\n cwd: invocation.cwd,\n ...(filter !== undefined ? { inputDescriptors: [filter] } : {}),\n // Restores against the burst's baseline as each command ends, so a planted entry lives no\n // longer than the command that planted it; the baseline itself resets once none is running.\n afterExit: () => {\n if (finished) return undefined;\n finished = true;\n this.inFlight -= 1;\n return this.restoreProtectedEntries(this.baseline);\n },\n };\n }\n\n /**\n * How each protected entry stands before a command: bubblewrap can mount an existing entry\n * read-only, but not one that does not exist yet, and a symlink it mounts through to its target\n * while the link itself stays replaceable. Read with `lstat`, so a dangling link is not \"missing\".\n */\n private protectedEntryStates(): IProtectedEntryState[] {\n return protectedWorkspaceEntries().map((entry) => {\n const path = `${this.root}/${entry}`;\n try {\n const stat = lstatSync(path);\n return stat.isSymbolicLink()\n ? { path, kind: 'symlink' as const, target: readlinkSync(path) }\n : { path, kind: 'present' as const };\n } catch {\n return { path, kind: 'missing' as const };\n }\n });\n }\n\n /**\n * Undo what the command did to protected entries it could reach: one it created where none\n * existed is moved into `.robota/sandbox-quarantine`, and a symlink it replaced is restored. Moved,\n * not deleted, so nothing the host wrote meanwhile is lost.\n */\n /** Whether a path's real location is under the read-only mounts: not the workspace, temp or `allowWrite`. */\n private resolvesOutsideWritableWorkspace(path: string): boolean {\n let real: string;\n try {\n real = realpathSync(path);\n } catch {\n return false;\n }\n const policy = this.policy();\n return ![policy.root, ...policy.tempDirectories, ...policy.allowWrite].some(\n (area) => real === area || real.startsWith(`${area}/`),\n );\n }\n\n /**\n * Never throws: this runs as the command's process closes, and an exception there would take the\n * host down and leave the entry in place. The quarantine is outside the workspace, under the\n * user's `~/.robota`, where the command cannot reach it; what cannot be moved there is removed.\n */\n private restoreProtectedEntries(before: readonly IProtectedEntryState[]): string | undefined {\n const quarantine = `${this.quarantineRoot(before)}/${Date.now()}-${randomUUID()}`;\n const notes: string[] = [];\n for (const state of before) {\n if (state.kind === 'present') continue;\n try {\n const now = this.protectedEntryStates().find((entry) => entry.path === state.path)!;\n if (state.kind === 'missing' && now.kind === 'missing') {\n this.unresolved.delete(state.path);\n continue;\n }\n if (state.kind === 'symlink' && now.kind === 'symlink' && now.target === state.target) {\n this.unresolved.delete(state.path);\n continue;\n }\n if (now.kind !== 'missing') notes.push(this.setAside(state.path, quarantine));\n if (state.kind === 'symlink') symlinkSync(state.target, state.path);\n this.unresolved.delete(state.path);\n } catch (error) {\n // allow-fallback: never thrown into the host. Fail closed instead: the entry keeps its\n // before-state for the next baseline, so it is retried, and nothing is auto-approved\n // until it is gone.\n this.unresolved.set(state.path, state);\n notes.push(\n `could not restore ${state.path} (${error instanceof Error ? error.message : String(error)}); ` +\n 'commands will ask until it is removed',\n );\n }\n }\n if (notes.length === 0) return undefined;\n return (\n `[sandbox] A confined command may not create or replace git, agent, MCP or shell ` +\n `configuration: ${notes.join('; ')}.`\n );\n }\n\n /**\n * Where set-aside entries go: the workspace's own `.robota`, when it was a real directory before\n * the command β then it was mounted read-only, so the command could not reach it, and a rename\n * within one filesystem needs no permission inside the entry. Otherwise the user's `~/.robota`.\n * Decided from the baseline: what is there now may be the command's own replacement.\n */\n private quarantineRoot(before: readonly IProtectedEntryState[]): string {\n const robota = `${this.root}/.robota`;\n const wasDirectory = before.some((state) => state.path === robota && state.kind === 'present');\n return wasDirectory\n ? `${robota}/sandbox-quarantine`\n : `${this.homeDirectory}/.robota/sandbox-quarantine`;\n }\n\n private setAside(path: string, quarantine: string): string {\n const destination = `${quarantine}/${basename(path)}`;\n mkdirSync(quarantine, { recursive: true });\n try {\n renameSync(path, destination);\n } catch (error) {\n // The command may have taken away its own write permission (moving a directory needs it)\n // or the quarantine may be on another filesystem; the owner can always give it back. Not\n // while another confined command runs: it could swap a directory for a symlink between the\n // check and the chmod. The entry is then retried when the last command ends.\n if (this.inFlight > 0) throw error;\n grantOwnerAccess(path);\n if ((error as NodeJS.ErrnoException).code === 'EXDEV') {\n cpSync(path, destination, { recursive: true, verbatimSymlinks: true });\n rmSync(path, { recursive: true, force: true });\n } else {\n renameSync(path, destination);\n }\n }\n return `moved ${path} to ${destination}`;\n }\n\n /** The policy for the current settings, with every path made absolute and real. */\n policy(): IOsSandboxPolicy {\n const absolute = (path: string): string => {\n const expanded =\n path === '~' || path.startsWith('~/') ? `${this.homeDirectory}${path.slice(1)}` : path;\n return realPathOrSelf(isAbsolute(expanded) ? expanded : resolve(this.root, expanded));\n };\n const temp = [...new Set([tmpdir(), '/tmp'].filter(existsSync).map(realPathOrSelf))];\n return {\n root: this.root,\n tempDirectories: temp,\n allowWrite: this.current.allowWrite.map(absolute),\n denyRead: this.current.denyRead.map((path) => {\n const resolved = absolute(path);\n return { path: resolved, directory: isDirectory(resolved) };\n }),\n network: this.current.network,\n };\n }\n\n run(command: string, options: ISandboxRunOptions = {}): Promise<ISandboxRunResult> {\n const shell = resolvePlatformShell();\n const cwd = options.workingDirectory ?? this.root;\n const invocation = this.wrapCommand(\n { command: shell.command, args: shell.commandArgs(command), cwd },\n command,\n );\n return new Promise((resolveRun, reject) => {\n const extra = invocation.inputDescriptors ?? [];\n let child: ReturnType<typeof spawn>;\n try {\n child = spawn(invocation.command, [...invocation.args], {\n cwd: invocation.cwd,\n stdio: ['ignore', 'pipe', 'pipe', ...extra.map(() => 'pipe' as const)],\n ...(options.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),\n });\n } catch (error) {\n invocation.afterExit?.();\n reject(error instanceof Error ? error : new Error(String(error)));\n return;\n }\n extra.forEach((data, index) => {\n const stream = child.stdio[index + 3] as NodeJS.WritableStream | null;\n // bwrap may exit before reading it; that is the command's failure, not the host's.\n stream?.on('error', () => undefined);\n stream?.end(Buffer.from(data));\n });\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (chunk: Buffer) => (stdout += chunk.toString()));\n child.stderr?.on('data', (chunk: Buffer) => (stderr += chunk.toString()));\n child.on('error', (error) => {\n invocation.afterExit?.();\n reject(error);\n });\n child.on('close', (code) => {\n const note = invocation.afterExit?.();\n const out = note === undefined ? stdout : `${stdout}\\n${note}`;\n resolveRun({ stdout: out, ...(stderr ? { stderr } : {}), exitCode: code ?? 1 });\n });\n });\n }\n\n readFile(path: string): Promise<string> {\n return Promise.resolve(readFileSync(path, 'utf8'));\n }\n\n writeFile(path: string, content: string): Promise<void> {\n writeFileSync(path, content, 'utf8');\n return Promise.resolve();\n }\n}\n","/**\n * SELFHOST-003 P2: repo-map index build + persistence.\n *\n * Builds the whole corpus into a parsed index ONCE (via the injected duck-typed parser), and\n * serializes it to a neutral JSON string the surface can persist. Ranking then runs over the index\n * without re-parsing on every `retrieve()`. Neutral: the corpus + parser are supplied by the caller;\n * this module holds no repo paths and no heavy dependency.\n */\n\nimport type {\n IRepoMapIndex,\n IRepoMapIndexChanges,\n IRepoMapIndexEntry,\n IRetrievalCorpusFile,\n IRetrievalSourceParser,\n} from './types.js';\n\n/** Persisted-schema version β bump when `IRepoMapIndex`'s serialized shape changes incompatibly. */\nexport const REPO_MAP_INDEX_VERSION = 1;\n\nexport interface IBuildRepoMapIndexOptions {\n /** Injected source parser (duck-typed; no heavy parser SDK becomes an `agent-tools` dependency). */\n parser: IRetrievalSourceParser;\n /** The corpus to index, supplied from the surface (no repo paths live in this package). */\n corpus: IRetrievalCorpusFile[];\n}\n\n/** Parse one corpus file into an index entry. */\nfunction parseEntry(\n parser: IRetrievalSourceParser,\n file: IRetrievalCorpusFile,\n): IRepoMapIndexEntry {\n const parsed = parser.parse(file.path, file.content);\n return { path: file.path, definitions: parsed.definitions, references: parsed.references };\n}\n\n/** Parse the whole corpus once into a serializable repo-map index. */\nexport function buildRepoMapIndex(options: IBuildRepoMapIndexOptions): IRepoMapIndex {\n return {\n version: REPO_MAP_INDEX_VERSION,\n entries: options.corpus.map((file) => parseEntry(options.parser, file)),\n };\n}\n\n/**\n * Apply corpus changes to a built index INCREMENTALLY (SELFHOST-003 P3): re-parse only the `upserted`\n * files and drop `removed` paths, reusing every unchanged entry. Returns a new index (the input is not\n * mutated). A file present in both `removed` and `upserted` is upserted (re-parse wins); a path repeated\n * within `upserted` is de-duplicated last-wins, so the result always has one entry per path β matching a\n * full rebuild (entry order does not affect ranking). Unchanged entries are REUSED BY REFERENCE; index\n * entries are treated as immutable, so callers must not mutate an entry in place.\n */\nexport function updateRepoMapIndex(\n index: IRepoMapIndex,\n changes: IRepoMapIndexChanges,\n parser: IRetrievalSourceParser,\n): IRepoMapIndex {\n // De-dup upserted by path (last-wins) so a repeated path yields a single, latest entry.\n const upsertedByPath = new Map((changes.upserted ?? []).map((file) => [file.path, file]));\n const touched = new Set<string>([...(changes.removed ?? []), ...upsertedByPath.keys()]);\n const kept = index.entries.filter((entry) => !touched.has(entry.path));\n const upserted = [...upsertedByPath.values()].map((file) => parseEntry(parser, file));\n return { version: index.version, entries: [...kept, ...upserted] };\n}\n\n/** Serialize a built index to a neutral JSON string for persistence by the surface. */\nexport function serializeRepoMapIndex(index: IRepoMapIndex): string {\n return JSON.stringify(index);\n}\n\n/**\n * Restore a built index from its serialized form. Throws on malformed JSON or an unsupported\n * `version` β a stale/incompatible persisted index must be rebuilt, never silently mis-ranked.\n */\nexport function deserializeRepoMapIndex(serialized: string): IRepoMapIndex {\n const parsed = JSON.parse(serialized) as Partial<IRepoMapIndex>;\n if (parsed.version !== REPO_MAP_INDEX_VERSION) {\n throw new Error(\n `Unsupported repo-map index version ${String(parsed.version)} (expected ${REPO_MAP_INDEX_VERSION}); rebuild the index.`,\n );\n }\n if (!Array.isArray(parsed.entries)) {\n throw new Error('Malformed repo-map index: missing `entries`.');\n }\n for (const entry of parsed.entries) {\n if (\n typeof entry?.path !== 'string' ||\n !Array.isArray(entry?.definitions) ||\n !Array.isArray(entry?.references)\n ) {\n throw new Error('Malformed repo-map index: a corrupt entry β rebuild the index.');\n }\n }\n return { version: parsed.version, entries: parsed.entries };\n}\n","/**\n * SELFHOST-003: neutral repo-map ranking adapter β mirrors `InMemorySandboxClient`.\n *\n * Ranks a corpus of source files by graph centrality relative to the active files / mentioned\n * identifiers, within a token budget. It is a NEUTRAL mechanism: it works on ANY repo given a corpus\n * and an injected source parser β it carries no repo paths and no domain content. The heavy parser is\n * injected as the duck-typed `IRetrievalSourceParser` (like `E2BSandboxClient` duck-types the E2B SDK),\n * and the corpus is supplied from the surface.\n *\n * P2 (index build + persistence): the corpus is parsed ONCE into an `IRepoMapIndex` at construction\n * (or supplied prebuilt/persisted via `{ index }`), so `retrieve()` ranks without re-parsing.\n *\n * Ranking model (aider repo-map style): a definition's score is the weighted number of references to it\n * across the corpus, references FROM an active file weighted higher (personalization), plus a boost for\n * a directly-mentioned identifier. Entries are emitted most-relevant-first, truncated to the budget.\n */\n\nimport { buildRepoMapIndex } from './repo-map-index.js';\n\nimport type {\n IRepoMapIndex,\n IRetrievalAdapter,\n IRetrievalCorpusFile,\n IRetrievalParsedFile,\n IRetrievalRankedSymbol,\n IRetrievalRequest,\n IRetrievalResult,\n IRetrievalSourceParser,\n IRetrievalSymbol,\n} from './types.js';\n\n/**\n * Construct from EITHER a prebuilt/persisted `index` (P2) OR a `parser` + `corpus` (parsed once at\n * construction). At least one form must be supplied (else the constructor throws); if both are given,\n * `index` takes precedence.\n */\nexport interface IRepoMapRetrievalAdapterOptions {\n /** Injected source parser (duck-typed) β required when building from a corpus. */\n parser?: IRetrievalSourceParser;\n /** The corpus to index, supplied from the surface β required when building from a corpus. */\n corpus?: IRetrievalCorpusFile[];\n /** A prebuilt/persisted index (SELFHOST-003 P2) β rank over this without re-parsing. */\n index?: IRepoMapIndex;\n}\n\n/** References from an active file weigh more (personalization toward the current focus). */\nconst ACTIVE_FILE_WEIGHT = 3;\n/** A directly-mentioned identifier is a strong relevance signal. */\nconst MENTION_BOOST = 5;\n\n/**\n * Estimate the token cost of one repo-map entry (neutral chars/4 heuristic). Uses the same rendering\n * shape the tool prints (`file:line kind name`) so the budgeted estimate matches the emitted output.\n */\nfunction estimateTokens(symbol: IRetrievalSymbol): number {\n const line = `${symbol.file}:${symbol.line} ${symbol.kind} ${symbol.name}`;\n return Math.max(1, Math.ceil(line.length / 4));\n}\n\nconst symbolKey = (s: IRetrievalSymbol): string => `${s.file}::${s.name}::${s.line}`;\n\nexport class RepoMapRetrievalAdapter implements IRetrievalAdapter {\n private readonly index: IRepoMapIndex;\n\n constructor(options: IRepoMapRetrievalAdapterOptions) {\n if (options.index) {\n this.index = options.index;\n } else if (options.parser && options.corpus) {\n this.index = buildRepoMapIndex({ parser: options.parser, corpus: options.corpus });\n } else {\n throw new Error('RepoMapRetrievalAdapter requires either { index } or { parser, corpus }.');\n }\n }\n\n async retrieve(request: IRetrievalRequest): Promise<IRetrievalResult> {\n const parsed = this.index.entries.map((entry) => ({\n file: entry.path,\n parsed: { definitions: entry.definitions, references: entry.references },\n }));\n const ranked = rankSymbols(parsed, request);\n return selectWithinBudget(ranked, request.tokenBudget);\n }\n}\n\n/** Index every definition in the corpus by its name (a name may be defined in several files). */\nfunction indexDefinitions(\n parsed: ReadonlyArray<{ file: string; parsed: IRetrievalParsedFile }>,\n): Map<string, IRetrievalSymbol[]> {\n const defsByName = new Map<string, IRetrievalSymbol[]>();\n for (const { parsed: file } of parsed) {\n for (const def of file.definitions) {\n const list = defsByName.get(def.name) ?? [];\n list.push(def);\n defsByName.set(def.name, list);\n }\n }\n return defsByName;\n}\n\n/** Score each definition by weighted reference count + personalization + mention boost. */\nfunction rankSymbols(\n parsed: ReadonlyArray<{ file: string; parsed: IRetrievalParsedFile }>,\n request: IRetrievalRequest,\n): IRetrievalRankedSymbol[] {\n const activeFiles = new Set(request.activeFiles ?? []);\n const mentioned = new Set(request.mentionedIdentifiers ?? []);\n const defsByName = indexDefinitions(parsed);\n const scoreByKey = new Map<string, number>();\n const bump = (s: IRetrievalSymbol, delta: number): void => {\n scoreByKey.set(symbolKey(s), (scoreByKey.get(symbolKey(s)) ?? 0) + delta);\n };\n\n // Graph edges: each reference to a defined name credits that name's definitions (skip self-file).\n for (const { file, parsed: source } of parsed) {\n const weight = activeFiles.has(file) ? ACTIVE_FILE_WEIGHT : 1;\n for (const ref of source.references) {\n for (const def of defsByName.get(ref) ?? []) {\n if (def.file !== file) bump(def, weight);\n }\n }\n }\n for (const name of mentioned) {\n for (const def of defsByName.get(name) ?? []) bump(def, MENTION_BOOST);\n }\n\n const ranked: IRetrievalRankedSymbol[] = [];\n for (const defs of defsByName.values()) {\n for (const def of defs) {\n ranked.push({\n ...def,\n score: scoreByKey.get(symbolKey(def)) ?? 0,\n tokens: estimateTokens(def),\n });\n }\n }\n // Deterministic: score desc, then file asc, then line asc, then name asc.\n ranked.sort(\n (a, b) =>\n b.score - a.score ||\n a.file.localeCompare(b.file) ||\n a.line - b.line ||\n a.name.localeCompare(b.name),\n );\n return ranked;\n}\n\n/** Take the most-relevant-first prefix whose cumulative tokens fit the budget. */\nfunction selectWithinBudget(\n ranked: readonly IRetrievalRankedSymbol[],\n tokenBudget: number,\n): IRetrievalResult {\n const symbols: IRetrievalRankedSymbol[] = [];\n let totalTokens = 0;\n for (const entry of ranked) {\n if (totalTokens + entry.tokens > tokenBudget) break;\n symbols.push(entry);\n totalTokens += entry.tokens;\n }\n return { symbols, totalTokens };\n}\n","import { FunctionTool, ValidationError, zodToJsonSchema } from '@robota-sdk/agent-core';\n\nimport type { IToolExecutionContext, TToolExecutor, TToolParameters } from '@robota-sdk/agent-core';\nimport type { IToolSchema } from '@robota-sdk/agent-core';\nimport type { TUniversalValue } from '@robota-sdk/agent-core';\nimport type { TypeOf, ZodType } from 'zod';\n\n// The concrete `FunctionTool` class is owned by @robota-sdk/agent-core (DATA-005 SSOT).\n// These factories construct core's `FunctionTool`; agent-tools owns only the factories\n// and the Zod-flavored wrapper.\n\n/**\n * Helper function to create a function tool from a simple function\n */\nexport function createFunctionTool(\n name: string,\n description: string,\n parameters: IToolSchema['parameters'],\n fn: TToolExecutor,\n): FunctionTool {\n const schema: IToolSchema = {\n name,\n description,\n parameters,\n };\n\n return new FunctionTool(schema, fn);\n}\n\n/**\n * What a tool declares about itself beyond its callable shape (CLI-1990).\n *\n * Optional, and omission is a declaration too: a tool that says nothing is RESIDENT β its schema is\n * sent on every request, which is what every tool in the tree does today.\n */\nexport interface IFunctionToolResidencyOptions {\n /**\n * Withhold this tool's schema from the model until it is loaded by `ToolSearch` or forced by a\n * `toolChoice`. Only honoured while the tool-search policy is engaged, so declaring it on a small\n * tool set costs nothing.\n */\n deferLoading?: boolean;\n}\n\n/**\n * Helper function to create a function tool from Zod schema\n */\nexport function createZodFunctionTool<S extends ZodType>(\n name: string,\n description: string,\n zodSchema: S,\n fn: TToolExecutor<TypeOf<S>>,\n residency: IFunctionToolResidencyOptions = {},\n): FunctionTool {\n // Use comprehensive Zod to JSON schema conversion\n const parameters = zodToJsonSchema(zodSchema);\n\n const schema: IToolSchema = {\n name,\n description,\n parameters,\n // Spread rather than assigned: an absent marker must stay ABSENT, not become `undefined`, so a\n // resident tool's schema is byte-identical to what it was before residency existed.\n ...(residency.deferLoading !== undefined && { deferLoading: residency.deferLoading }),\n };\n\n // Wrap the function with validation and ensure proper parameter handling\n const wrappedFn: TToolExecutor = async (\n parameters: TToolParameters,\n context?: IToolExecutionContext,\n ): Promise<TUniversalValue> => {\n // Use Zod for runtime validation β the executor receives the PARSED, schema-typed value\n // (SDK-009): the runtime guarantee and the compile-time type now flow together.\n const parseResult = zodSchema.safeParse(parameters);\n if (!parseResult.success) {\n throw new ValidationError(`Zod validation failed: ${parseResult.error}`);\n }\n\n const result = await fn(parseResult.data as TypeOf<S>, context);\n // Ensure result is always a string for consistency with core package\n return typeof result === 'string' ? result : JSON.stringify(result);\n };\n\n return new FunctionTool(schema, wrappedFn);\n}\n\n// zodToJsonSchema function moved to Facade pattern schema-converter module\n","/**\n * What the permission system is told about the tools THIS package defines. CORE-030.\n *\n * The classification used to live in `@robota-sdk/agent-core`'s `permission-mode.ts`, as a matrix\n * keyed on a closed union of product tool names β a vendor-neutral foundation holding a product's\n * tool inventory, two layers below the code that defines it, with nothing coupling the two lists.\n * They drifted: `CodebaseRetrieval` is defined here and the matrix had never heard of it, so a\n * read-only retrieval prompted on every call and was refused outright in plan mode.\n *\n * A tool's own package declares what it does. The foundation decides what each MODE does about that\n * kind of action, and neither restates the other's half.\n *\n * `packages/agent-tools/src/__tests__/tool-permission-profiles.test.ts` asserts that every tool this\n * package produces appears here, so adding a tool without classifying it fails rather than silently\n * inheriting the prompt-on-every-call fallback.\n */\n\nimport { registerToolPermissionProfile, type IToolPermissionProfile } from '@robota-sdk/agent-core';\n\n/**\n * Every tool this package defines, and what the permission system needs to know about it.\n *\n * `argument.key` is which argument a pattern like `Read(/src/**)` is matched against, and\n * `argument.kind` how (CORE-049: a URL is parsed, a path is segment-wise, a command is a glob). A tool without\n * one cannot be narrowed by an argument pattern at all β the gate treats such a pattern as\n * unevaluable and prompts rather than proceeding, which is why the ones that CAN be narrowed say so.\n */\nexport const AGENT_TOOL_PERMISSION_PROFILES: Readonly<Record<string, IToolPermissionProfile>> = {\n // Reads and searches: observe, change nothing.\n Read: { argument: { key: 'filePath', kind: 'path' }, riskClass: 'inspect' },\n Glob: { argument: { key: 'pattern', kind: 'text' }, riskClass: 'inspect' },\n Grep: { argument: { key: 'pattern', kind: 'text' }, riskClass: 'inspect' },\n WebFetch: { argument: { key: 'url', kind: 'url' }, riskClass: 'inspect' },\n WebSearch: { argument: { key: 'query', kind: 'text' }, riskClass: 'inspect' },\n // The tool that had no classification at all until now. It reads the codebase and returns\n // excerpts; treating it as unknown meant prompting for every search and refusing it in plan mode,\n // which is the mode where searching is the only thing you CAN do.\n CodebaseRetrieval: { riskClass: 'inspect' },\n // Asking the user changes nothing, and prompting for permission to prompt is not a decision\n // anyone wants to make.\n AskUserQuestion: { riskClass: 'inspect' },\n // CLI-1990: loading a withheld tool SCHEMA is not calling the tool β the tool it loads is gated on\n // its own name when the model actually calls it, exactly as it would be were it never deferred.\n // Classified so a rule naming `ToolSearch` is evaluable rather than falling to 'unevaluable' β\n // prompt, which in plan mode is a refusal to let the agent discover what it may read.\n // `query` is the narrowable argument, matched as text like the other search tools'.\n ToolSearch: { argument: { key: 'query', kind: 'text' }, riskClass: 'inspect' },\n // SELFHOST-010: looking at the screen is perception, decided like a read.\n ComputerView: { riskClass: 'inspect' },\n\n // Workspace changes: what `acceptEdits` exists to stop asking about.\n Write: { argument: { key: 'filePath', kind: 'path' }, riskClass: 'modify' },\n Edit: { argument: { key: 'filePath', kind: 'path' }, riskClass: 'modify' },\n\n // Arbitrary execution, where the blast radius is not bounded by a path.\n Shell: { argument: { key: 'command', kind: 'command' }, riskClass: 'execute', aliases: ['Bash'] },\n // TERM-008: a model-familiar alias of the same implementation, so the same classification β and\n // a rule naming either name governs both.\n Bash: { argument: { key: 'command', kind: 'command' }, riskClass: 'execute', aliases: ['Shell'] },\n // SELFHOST-010: a GUI mutation is not a file edit, so `acceptEdits` must not cover it β which is\n // exactly what classifying it as execution rather than modification says.\n Computer: { riskClass: 'execute' },\n};\n\n/**\n * Tell the permission system about every tool this package defines. Idempotent.\n *\n * Not exported: the one caller is the line below. A registration a consumer could choose to skip is\n * a registration that might not happen, which is the state this change exists to leave behind.\n */\nfunction registerAgentToolPermissionProfiles(): void {\n for (const [toolName, profile] of Object.entries(AGENT_TOOL_PERMISSION_PROFILES)) {\n registerToolPermissionProfile(toolName, profile);\n }\n}\n\n// Registered on import of this module, and each tool module imports it, so a tool's classification\n// exists exactly when the module that defines the tool has loaded. Putting this in the package\n// index instead would tie it to the barrel rather than to the tools.\nregisterAgentToolPermissionProfiles();\n","/**\n * SELFHOST-003: the `CodebaseRetrieval` tool β mirrors the `create*Tool(options)` pattern.\n *\n * Composes over the injected `IRetrievalAdapter` (via `IRetrievalToolOptions`). It carries NO corpus and\n * NO domain content itself β the adapter (built from a surface-supplied parser + corpus) does the\n * ranking. With no adapter the tool reports unavailability (it is added to the default set only when an\n * adapter is present β see `createDefaultTools`).\n */\n\nimport { z } from 'zod';\n\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IRetrievalRankedSymbol, IRetrievalToolOptions } from './types.js';\nimport type { FunctionTool } from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\n/** Default token budget when the caller does not specify one. */\nconst DEFAULT_TOKEN_BUDGET = 1000;\n\nconst RetrievalSchema = z.object({\n activeFiles: z\n .array(z.string())\n .optional()\n .describe(\n 'Repo-relative files currently in focus; the map is ranked toward what they reference.',\n ),\n mentionedIdentifiers: z\n .array(z.string())\n .optional()\n .describe('Symbol names to bias the map toward (e.g. identifiers named in the task).'),\n tokenBudget: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(`Maximum tokens for the returned map (default ${DEFAULT_TOKEN_BUDGET}).`),\n});\n\ntype TRetrievalArgs = z.infer<typeof RetrievalSchema>;\n\n/** Render the ranked symbols as a compact, deterministic repo map. */\nfunction formatRepoMap(symbols: readonly IRetrievalRankedSymbol[]): string {\n return symbols\n .map((symbol) => `${symbol.file}:${symbol.line} ${symbol.kind} ${symbol.name}`)\n .join('\\n');\n}\n\nasync function retrievalTool(\n args: TRetrievalArgs,\n options: IRetrievalToolOptions = {},\n): Promise<string> {\n if (!options.adapter) {\n return 'Codebase retrieval is not available in this session.';\n }\n const result = await options.adapter.retrieve({\n ...(args.activeFiles ? { activeFiles: args.activeFiles } : {}),\n ...(args.mentionedIdentifiers ? { mentionedIdentifiers: args.mentionedIdentifiers } : {}),\n tokenBudget: args.tokenBudget ?? DEFAULT_TOKEN_BUDGET,\n });\n if (result.symbols.length === 0) {\n return 'No relevant symbols found within the token budget.';\n }\n return `Most relevant symbols (~${result.totalTokens} tokens):\\n${formatRepoMap(result.symbols)}`;\n}\n\nexport function createRetrievalTool(options: IRetrievalToolOptions = {}): FunctionTool {\n return createZodFunctionTool(\n 'CodebaseRetrieval',\n 'Retrieve the most relevant slice of the codebase (a ranked repo map of symbols) for the current task, within a token budget. Provide the files you are focused on and/or identifiers named in the task; returns the highest-centrality definitions first.',\n RetrievalSchema,\n async (params) => retrievalTool(params, options),\n );\n}\n","/**\n * SELFHOST-010: the `ComputerView` (perceive) + `Computer` (act) tools β mirror the `create*Tool(options)`\n * pattern, split along the permission boundary.\n *\n * `createComputerTool({ driver })` registers BOTH tool names over one injected `IComputerDriver`. The split\n * is purely the permission-bearing boundary (the repo's own `Read`(auto)-vs-`Shell`(approve) precedent):\n * - `ComputerView` calls `driver.screenshot()` β a perceive with no action argument (gated `auto` like `Read`).\n * - `Computer` takes a single typed mutating `action`, executes it via `driver.act()`, and returns the\n * resulting screenshot so the model re-perceives (gated `approve`/`deny` like `Shell`).\n *\n * The typed action union stays WHOLE in the driver contract (`./types.ts`); this file only maps the\n * tool-boundary argument onto it. With no driver the tools report unavailability β they are added to the\n * default set ONLY when a driver is present (adapter-gated; there is NO host fallback β see\n * `createDefaultTools`).\n */\n\nimport { z } from 'zod';\n\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type {\n IComputerScreenshot,\n IComputerToolOptions,\n TComputerAction,\n TComputerMouseButton,\n} from './types.js';\nimport type { FunctionTool } from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\n/** The tool-boundary result shape returned (as JSON) by both `ComputerView` and `Computer`. */\nexport interface IComputerToolResult {\n success: boolean;\n /** Fresh screenshot after the perceive/act; absent while a takeover pauses perception. */\n screenshot?: IComputerScreenshot;\n /** True when a human takeover suspends the action loop (perception paused). */\n takeover?: boolean;\n /** Error message when the tool could not run (no driver, or an invalid action). */\n error?: string;\n}\n\nconst UNAVAILABLE_MESSAGE = 'Computer use is not available in this session (no driver injected).';\n\nconst MouseButtonSchema = z.enum(['left', 'right', 'middle']);\n\nconst PointSchema = z.object({\n x: z.number(),\n y: z.number(),\n});\n\n/**\n * The `Computer` action argument. A flat object (not a discriminated union) so it converts to JSON schema\n * β `type` selects the action and the remaining fields are validated per type in {@link buildAction}. The\n * strongly-typed discriminated union lives in the driver contract (`TComputerAction`).\n */\nconst ActionSchema = z.object({\n type: z\n .enum(['click', 'double_click', 'type', 'keypress', 'scroll', 'drag', 'wait', 'takeover'])\n .describe('Which action to perform.'),\n x: z.number().optional().describe('X coordinate (click/double_click/scroll).'),\n y: z.number().optional().describe('Y coordinate (click/double_click/scroll).'),\n button: MouseButtonSchema.optional().describe('Mouse button (click/double_click/drag).'),\n text: z.string().optional().describe('Text to type (type).'),\n keys: z.array(z.string()).optional().describe('Keys to press as a chord (keypress).'),\n deltaX: z.number().optional().describe('Horizontal wheel delta (scroll).'),\n deltaY: z.number().optional().describe('Vertical wheel delta (scroll).'),\n path: z.array(PointSchema).optional().describe('Points to drag through (drag).'),\n ms: z.number().optional().describe('Milliseconds to wait (wait).'),\n reason: z.string().optional().describe('Human-readable reason surfaced to the user (takeover).'),\n});\n\ntype TActionArgs = z.infer<typeof ActionSchema>;\n\nconst ComputerSchema = z.object({\n action: ActionSchema.describe('The single mutating action to perform.'),\n});\n\ntype TComputerArgs = z.infer<typeof ComputerSchema>;\n\nconst ComputerViewSchema = z.object({});\n\n/** Raised when the tool-boundary action argument is missing fields the action type requires. */\nclass InvalidComputerActionError extends Error {}\n\nfunction requireNumber(value: number | undefined, field: string, type: string): number {\n if (typeof value !== 'number') {\n throw new InvalidComputerActionError(`Action '${type}' requires numeric '${field}'.`);\n }\n return value;\n}\n\n/** Map the flat tool-boundary argument onto the strongly-typed driver action union. */\nfunction buildAction(args: TActionArgs): TComputerAction {\n const button: TComputerMouseButton | undefined = args.button;\n switch (args.type) {\n case 'click':\n return {\n type: 'click',\n x: requireNumber(args.x, 'x', 'click'),\n y: requireNumber(args.y, 'y', 'click'),\n ...(button ? { button } : {}),\n };\n case 'double_click':\n return {\n type: 'double_click',\n x: requireNumber(args.x, 'x', 'double_click'),\n y: requireNumber(args.y, 'y', 'double_click'),\n ...(button ? { button } : {}),\n };\n case 'type':\n if (typeof args.text !== 'string') {\n throw new InvalidComputerActionError(\"Action 'type' requires 'text'.\");\n }\n return { type: 'type', text: args.text };\n case 'keypress':\n if (!args.keys || args.keys.length === 0) {\n throw new InvalidComputerActionError(\"Action 'keypress' requires non-empty 'keys'.\");\n }\n return { type: 'keypress', keys: args.keys };\n case 'scroll':\n return {\n type: 'scroll',\n x: requireNumber(args.x, 'x', 'scroll'),\n y: requireNumber(args.y, 'y', 'scroll'),\n deltaX: requireNumber(args.deltaX, 'deltaX', 'scroll'),\n deltaY: requireNumber(args.deltaY, 'deltaY', 'scroll'),\n };\n case 'drag':\n if (!args.path || args.path.length < 2) {\n throw new InvalidComputerActionError(\n \"Action 'drag' requires a 'path' of at least two points.\",\n );\n }\n return { type: 'drag', path: args.path, ...(button ? { button } : {}) };\n case 'wait':\n return { type: 'wait', ...(typeof args.ms === 'number' ? { ms: args.ms } : {}) };\n case 'takeover':\n return { type: 'takeover', ...(args.reason ? { reason: args.reason } : {}) };\n default: {\n // Exhaustiveness guard β the enum keeps this unreachable.\n const exhaustive: never = args.type;\n throw new InvalidComputerActionError(`Unknown action type: ${String(exhaustive)}`);\n }\n }\n}\n\n/** `ComputerView` β perceive the current surface (returns a screenshot). Gated `auto` like `Read`. */\nasync function perceive(options: IComputerToolOptions): Promise<string> {\n if (!options.driver) {\n return JSON.stringify({\n success: false,\n error: UNAVAILABLE_MESSAGE,\n } satisfies IComputerToolResult);\n }\n const screenshot = await options.driver.screenshot();\n const result: IComputerToolResult = screenshot\n ? { success: true, screenshot }\n : { success: true, takeover: true };\n return JSON.stringify(result);\n}\n\n/** `Computer` β execute one typed mutating action and return the resulting screenshot. Gated like `Shell`. */\nasync function act(args: TComputerArgs, options: IComputerToolOptions): Promise<string> {\n if (!options.driver) {\n return JSON.stringify({\n success: false,\n error: UNAVAILABLE_MESSAGE,\n } satisfies IComputerToolResult);\n }\n let action: TComputerAction;\n try {\n action = buildAction(args.action);\n } catch (err) {\n return JSON.stringify({\n success: false,\n error: err instanceof Error ? err.message : String(err),\n } satisfies IComputerToolResult);\n }\n const outcome = await options.driver.act(action);\n const result: IComputerToolResult = {\n success: true,\n ...(outcome.screenshot ? { screenshot: outcome.screenshot } : {}),\n ...(outcome.takeover ? { takeover: true } : {}),\n };\n return JSON.stringify(result);\n}\n\n/** Build the `ComputerView` perceive tool over the injected driver. */\nexport function createComputerViewTool(options: IComputerToolOptions = {}): FunctionTool {\n return createZodFunctionTool(\n 'ComputerView',\n 'Perceive the computer/browser surface: capture and return a screenshot of the current screen so you can reason about what to do next. Read-only β it never changes anything.',\n ComputerViewSchema,\n async () => perceive(options),\n );\n}\n\n/** Build the `Computer` act tool over the injected driver. */\nexport function createComputerActTool(options: IComputerToolOptions = {}): FunctionTool {\n return createZodFunctionTool(\n 'Computer',\n 'Perform one mutating action on the computer/browser surface (click, double_click, type, keypress, scroll, drag, wait, or takeover) and return the resulting screenshot. Use `takeover` to hand control to the human for sensitive input (credentials/payment); perception is paused during a takeover.',\n ComputerSchema,\n async (params) => act(params, options),\n );\n}\n\n/**\n * Create BOTH computer-use tools β `ComputerView` (perceive) and `Computer` (act) β over one injected\n * driver. Mirrors `create*Tool(options)`; returns the pair so the assembly layer can spread them into the\n * default set adapter-gated (see `createDefaultTools`).\n */\nexport function createComputerTool(options: IComputerToolOptions = {}): FunctionTool[] {\n return [createComputerViewTool(options), createComputerActTool(options)];\n}\n","/**\n * SELFHOST-010: `PageComputerDriver` β a zero-dependency reference adapter (mirror `E2BSandboxClient`).\n *\n * It implements `IComputerDriver` by duck-typing a browser-page-shaped object via the locally-declared\n * `IBrowserPageAdapter` (`./types.ts`) β it imports NO heavy browser SDK (no Playwright/Puppeteer/CDP). The\n * surface passes the real page object, exactly as the sandbox surface passes a real E2B sandbox to\n * `E2BSandboxClient`. This keeps `agent-tools` neutral (TC-06): the environment lives in the surface.\n *\n * Takeover: `beginTakeover()` pauses perception (subsequent `screenshot()` returns `undefined` and further\n * actions are held) until `endTakeover()` resumes β the halt-for-user loop-suspension shape.\n */\n\nimport type {\n IBrowserPageAdapter,\n IComputerActionResult,\n IComputerDriver,\n IComputerScreenshot,\n TComputerAction,\n} from './types.js';\n\nexport interface IPageComputerDriverOptions {\n /** The real browser page (duck-typed; the surface supplies it). */\n page: IBrowserPageAdapter;\n /** Media type of the captured bytes (default `image/png`). */\n mediaType?: string;\n /** Default wait when a `wait` action omits `ms` (default 500ms). */\n defaultWaitMs?: number;\n}\n\nconst DEFAULT_MEDIA_TYPE = 'image/png';\nconst DEFAULT_WAIT_MS = 500;\n\n/** Encode raw screenshot bytes to base64 (accepts the page's `Uint8Array` or an already-encoded string). */\nfunction encodeScreenshot(bytes: Uint8Array | string): string {\n if (typeof bytes === 'string') {\n return bytes;\n }\n return Buffer.from(bytes).toString('base64');\n}\n\nexport class PageComputerDriver implements IComputerDriver {\n private readonly page: IBrowserPageAdapter;\n private readonly mediaType: string;\n private readonly defaultWaitMs: number;\n private suspended = false;\n\n constructor(options: IPageComputerDriverOptions) {\n this.page = options.page;\n this.mediaType = options.mediaType ?? DEFAULT_MEDIA_TYPE;\n this.defaultWaitMs = options.defaultWaitMs ?? DEFAULT_WAIT_MS;\n }\n\n private async capture(): Promise<IComputerScreenshot> {\n // Honor the configured mediaType so the reported bytes and the label agree (jpeg vs png).\n const type = this.mediaType === 'image/jpeg' ? 'jpeg' : 'png';\n const bytes = await this.page.screenshot({ type });\n return { data: encodeScreenshot(bytes), mediaType: this.mediaType };\n }\n\n private async wait(ms: number): Promise<void> {\n if (this.page.waitForTimeout) {\n await this.page.waitForTimeout(ms);\n return;\n }\n await new Promise<void>((resolve) => setTimeout(resolve, ms));\n }\n\n async screenshot(): Promise<IComputerScreenshot | undefined> {\n // Perception is paused during a takeover so no screenshot captures the human's secret.\n if (this.suspended) {\n return undefined;\n }\n return this.capture();\n }\n\n async act(action: TComputerAction): Promise<IComputerActionResult> {\n if (action.type === 'takeover') {\n await this.beginTakeover(action.reason);\n return { takeover: true };\n }\n\n // While suspended, the action loop is halted β execute nothing and capture nothing.\n if (this.suspended) {\n return { takeover: true };\n }\n\n const { mouse, keyboard } = this.page;\n switch (action.type) {\n case 'click':\n await mouse.click(\n action.x,\n action.y,\n action.button ? { button: action.button } : undefined,\n );\n break;\n case 'double_click':\n await mouse.click(action.x, action.y, {\n clickCount: 2,\n ...(action.button ? { button: action.button } : {}),\n });\n break;\n case 'type':\n await keyboard.type(action.text);\n break;\n case 'keypress':\n // `keys` is a CHORD (e.g. ['Control','a'] = Ctrl+A), not a sequence β press them together via the\n // `'Control+a'` chord form (a single key like ['a'] presses just 'a').\n await keyboard.press(action.keys.join('+'));\n break;\n case 'scroll':\n await mouse.move(action.x, action.y);\n await mouse.wheel(action.deltaX, action.deltaY);\n break;\n case 'drag':\n await this.performDrag(action);\n break;\n case 'wait':\n await this.wait(action.ms ?? this.defaultWaitMs);\n break;\n }\n\n return { screenshot: await this.capture() };\n }\n\n /** Move the pointer along a multi-point path with the button held (mouse down β moves β up). */\n private async performDrag(action: Extract<TComputerAction, { type: 'drag' }>): Promise<void> {\n // Defensive: this reference adapter is public API; a direct caller may bypass the tool boundary's\n // `path.length >= 2` check. A drag needs at least a start + end point.\n if (action.path.length < 2) {\n throw new Error('computer drag requires a path of at least 2 points (start + end)');\n }\n const { mouse } = this.page;\n const [first, ...rest] = action.path;\n const button = action.button ? { button: action.button } : undefined;\n await mouse.move(first.x, first.y);\n await mouse.down(button);\n for (const point of rest) {\n await mouse.move(point.x, point.y);\n }\n await mouse.up(button);\n }\n\n async beginTakeover(_reason?: string): Promise<void> {\n this.suspended = true;\n }\n\n async endTakeover(): Promise<void> {\n this.suspended = false;\n }\n}\n","/**\n * The `Shell`/`Bash` tools' MODEL-FACING DESCRIPTION β the text that tells the model which shell it is\n * writing for and which sibling tool to prefer.\n *\n * Split out of `shell-tool.ts` (SEC-007) when documenting the containment decision pushed that file\n * past the anti-monolith limit. The split is by responsibility: this module owns a model-facing\n * CONTRACT (NEUT-002 β neutral, mechanism-only default text a consumer overrides at the composition\n * root), while `shell-tool.ts` owns process execution. They change for entirely different reasons.\n */\n\nimport type { IPlatformShell } from '@robota-sdk/agent-core';\n\n/**\n * Dedicated-tool routing hints, keyed by the sibling tool's registered name. A hint is only\n * emitted when that sibling is actually part of the registered tool set (NEUT-002) β the\n * description must not route the model to tools that do not exist in a given assembly.\n */\nconst SIBLING_ROUTING_HINTS: ReadonlyArray<{ toolName: string; hint: string }> = [\n { toolName: 'Glob', hint: ' - File search: Use Glob (NOT find or ls)' },\n { toolName: 'Grep', hint: ' - Content search: Use Grep (NOT grep or rg)' },\n { toolName: 'Read', hint: ' - Read files: Use Read (NOT cat/head/tail)' },\n { toolName: 'Edit', hint: ' - Edit files: Use Edit (NOT sed/awk)' },\n];\n\n/**\n * Build the OS-aware tool description so the model writes syntax the host shell can run.\n * When `availableTools` is provided, sibling routing hints are restricted to tools in that set;\n * when omitted, the full default hint set is included (default assembly registers all siblings).\n */\nexport function buildShellToolDescription(\n shell: IPlatformShell,\n availableTools?: readonly string[],\n): string {\n const hints = availableTools\n ? SIBLING_ROUTING_HINTS.filter((entry) => availableTools.includes(entry.toolName))\n : SIBLING_ROUTING_HINTS;\n\n const routingBlock =\n hints.length > 0\n ? [\n `IMPORTANT: Avoid using this tool to run \\`find\\`, \\`grep\\`, \\`cat\\`, \\`head\\`, \\`tail\\`, \\`sed\\`, \\`awk\\`, or \\`echo\\` commands. Instead, use the appropriate dedicated tool:`,\n ...hints.map((entry) => entry.hint),\n ]\n : [];\n\n // TOOL-004: every sentence here describes a mechanism THIS tool enforces. Each command runs in\n // `workingDirectory` (default: the configured root) with no state carried between calls; there is\n // no `description` parameter; output truncation belongs to whichever layer applies it, not here.\n return [\n `Executes a command in the host shell and returns its output.`,\n ``,\n `Active shell: ${shell.label}. ${shell.syntaxHint}`,\n ``,\n `Each command runs in a fresh shell in workingDirectory (default: the configured working directory); no shell state carries over between calls.`,\n ``,\n ...routingBlock,\n ].join('\\n');\n}\n","/**\n * ShellTool β execute a host shell command via child_process.spawn (TERM-008).\n *\n * Cross-platform: the shell is resolved per OS through `resolvePlatformShell()` (POSIX `sh`/`bash`,\n * Windows PowerShell). The tool name is `Shell` and its description is built dynamically from the\n * resolved shell so the model is told the active shell/OS and writes the right syntax.\n *\n * Returns an IToolInvocationResult JSON string. A non-zero exit is returned as success:true with\n * exitCode set (the command ran, it just exited non-zero β the LLM decides what to do with that).\n *\n * ## SEC-007 β why `workingDirectory` is NOT path-contained (a deliberate decision, not an omission)\n *\n * `Read`/`Write`/`Edit` are contained by `checkPathWithinCwd`, and SEC-007 extended that to `Glob`\n * and `Grep`. This tool is deliberately excluded, and the reason is what the tool IS: it runs an\n * arbitrary command in a shell. A guard on `cwd` is undone by the first `cd ..` β or by an absolute\n * path in the command itself β so it would constrain nothing an attacker-controlled command cannot\n * trivially step around, while LOOKING like a boundary in the code and in review.\n *\n * That appearance is the actual hazard. SEC-006's R9 lesson was \"'the guard is still there' is not a\n * verdict\": a check that reads as containment but is not one is worse than no check, because the next\n * reviewer stops asking. The real boundary for this tool is the permission layer (every invocation is\n * permission-gated at call time) and the sandbox seam below β which is why SEC-006 already recorded\n * `js/indirect-command-line-injection` at the spawn site as a false positive on those same grounds.\n *\n * What the containment root DOES do here: it supplies the DEFAULT working directory. Binding a tool\n * to a session root and then silently running its commands in `process.cwd()` was a real defect β an\n * assembly that scoped its file tools to a workspace still ran `Shell` wherever the host process\n * happened to be started.\n */\n\nimport { spawn } from 'node:child_process';\n\nimport {\n createBoundedOutput,\n resolvePlatformShell,\n subprocessTraceEnvironment,\n} from '@robota-sdk/agent-core';\nimport { killProcessTree } from '@robota-sdk/agent-process';\nimport { z } from 'zod';\n\n/** POSIX children are spawned detached so a process-group kill reaps grandchildren (CORE-023). */\nconst SPAWN_DETACHED = process.platform !== 'win32';\n\nimport { buildShellToolDescription } from './shell-tool-description.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { ISandboxBuiltinToolOptions } from './tool-options.js';\nimport type { ICommandInvocation, ISandboxToolOptions } from '../sandbox/types.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { FunctionTool, IPlatformShell, ISubprocessTraceEnv } from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\nconst DEFAULT_TIMEOUT_MS = 120_000; // 2 minutes\n/** ARCH-056: most bytes retained per stream while the child runs (head); the rest is dropped. */\nconst MAX_CAPTURED_OUTPUT_BYTES = 2_000_000;\n\nconst ShellSchema = z.object({\n command: z.string().describe('The shell command to execute'),\n timeout: z\n .number()\n .optional()\n .describe('Optional timeout in milliseconds (max 600000). Default is 120000 (2 minutes)'),\n workingDirectory: z\n .string()\n .optional()\n .describe('Working directory for the command. Defaults to the current working directory'),\n});\n\ntype TShellArgs = z.infer<typeof ShellSchema>;\n\n/** Run a shell command through the sandbox client, surfacing failures as a structured result. */\nasync function runInSandbox(\n command: string,\n timeout: number,\n workingDirectory: string | undefined,\n options: ISandboxToolOptions,\n): Promise<string> {\n try {\n const sandboxResult = await options.sandboxClient!.run(command, {\n timeoutMs: timeout,\n workingDirectory,\n });\n const output = sandboxResult.stderr\n ? `${sandboxResult.stdout}\\nstderr:\\n${sandboxResult.stderr}`\n : sandboxResult.stdout;\n const result: IToolInvocationResult = {\n success: true,\n output,\n exitCode: sandboxResult.exitCode,\n };\n return JSON.stringify(result);\n } catch (err) {\n // allow-fallback: tool-result contract reports a failed run as success:false + error (faithful surfacing of a terminal failure, not silent recovery)\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n}\n\n/**\n * Run a shell command and return stdout + stderr.\n * Resolves with the IToolInvocationResult JSON string.\n */\nasync function runShell(\n args: TShellArgs,\n options: ISandboxToolOptions,\n shell: IPlatformShell,\n signal?: AbortSignal,\n traceEnv?: ISubprocessTraceEnv,\n): Promise<string> {\n const { command, timeout: rawTimeout = DEFAULT_TIMEOUT_MS, workingDirectory } = args;\n const timeout = Math.min(rawTimeout, 600_000);\n // SEC-007: the configured root is the DEFAULT working directory (see the file header for why it is\n // not a boundary). Without this, an assembly that scoped its file tools to a workspace still ran\n // every shell command in whatever directory the host process was started in.\n //\n // ARCH-010 removed a third `?? process.cwd()` link from this chain. `options.cwd` is required now,\n // so that link was unreachable β and an unreachable fallback still reads as a supported one, which\n // is how the ambient-root habit spreads. A caller that means the process directory says so.\n const effectiveCwd = workingDirectory ?? options.cwd;\n if (effectiveCwd === undefined) {\n // Only reachable from a caller that skipped the type β `options.cwd` is required. Refusing beats\n // letting `spawn` silently inherit the process directory, which was the last ambient root in this\n // package and the one contract violation that produced no message at all (ARCH-010).\n return JSON.stringify({\n success: false,\n output: '',\n error:\n 'Shell tool has no working directory: it was constructed without a `cwd` (ARCH-010). This ' +\n 'is an assembly bug β the tool would otherwise run in whatever directory the host process ' +\n 'was started in.',\n });\n }\n // A client that confines a host process in place (`wrapCommand`) keeps the host path below, so\n // timeouts, cancellation, output limits and process-group kill stay this tool's.\n if (options.sandboxClient && options.sandboxClient.wrapCommand === undefined) {\n return runInSandbox(command, timeout, workingDirectory ?? options.cwd, options);\n }\n const hostInvocation: ICommandInvocation = {\n command: shell.command,\n args: shell.commandArgs(command),\n cwd: effectiveCwd,\n };\n const invocation =\n options.sandboxClient?.wrapCommand?.(hostInvocation, command) ?? hostInvocation;\n\n // The invocation's clean-up runs exactly once on every path out β the close below, a spawn that\n // throws, or an abort before start β and never throws into the host.\n let released = false;\n const release = (): string | undefined => {\n if (released) return undefined;\n released = true;\n try {\n return invocation.afterExit?.();\n } catch (error) {\n // allow-fallback: a sandbox's clean-up must never take the host down; it is reported\n return `[sandbox] clean-up failed: ${error instanceof Error ? error.message : String(error)}`;\n }\n };\n\n if (signal?.aborted) {\n release();\n return JSON.stringify({ success: false, output: '', error: 'Aborted before start' });\n }\n\n return new Promise<string>((resolve) => {\n // ARCH-056: memory is bounded WHILE the child writes, not capped after a ten-minute buffer.\n const stdoutOutput = createBoundedOutput({ maxBytes: MAX_CAPTURED_OUTPUT_BYTES });\n const stderrOutput = createBoundedOutput({ maxBytes: MAX_CAPTURED_OUTPUT_BYTES });\n\n let timedOut = false;\n let settled = false;\n\n let child: ReturnType<typeof spawn>;\n try {\n child = spawn(invocation.command, [...invocation.args], {\n cwd: invocation.cwd,\n // A fresh copy carrying this call's trace when the host enabled it; `process.env` itself is\n // never modified, so no other child can inherit the value.\n env:\n traceEnv === undefined ? process.env : subprocessTraceEnvironment(process.env, traceEnv),\n // Descriptors 3, 4, β¦ carry what the invocation hands the process (a sandbox's seccomp filter).\n stdio: [\n 'pipe',\n 'pipe',\n 'pipe',\n ...(invocation.inputDescriptors ?? []).map(() => 'pipe' as const),\n ],\n detached: SPAWN_DETACHED,\n });\n } catch (error) {\n const note = release();\n const message = error instanceof Error ? error.message : String(error);\n resolve(\n JSON.stringify({\n success: false,\n output: note ?? '',\n error: message,\n } satisfies IToolInvocationResult),\n );\n return;\n }\n (invocation.inputDescriptors ?? []).forEach((data, index) => {\n const stream = child.stdio[index + 3] as NodeJS.WritableStream | null;\n // The wrapper may exit before reading it (bwrap refusing a mount); its exit status and stderr\n // report that, and an unhandled pipe error must not take the host down.\n stream?.on('error', () => undefined);\n stream?.end(Buffer.from(data));\n });\n\n // RUNTIME-31: the command inherits an open stdin pipe it can block reading on; close it\n // so commands that read stdin (e.g. `cat`) terminate instead of hanging until timeout.\n child.stdin?.end();\n\n child.stdout?.on('data', (chunk: Buffer) => {\n stdoutOutput.append(chunk);\n });\n\n child.stderr?.on('data', (chunk: Buffer) => {\n stderrOutput.append(chunk);\n });\n\n const timer = setTimeout(() => {\n timedOut = true;\n // CORE-023: kill the whole process group with SIGTERMβgraceβSIGKILL so grandchildren\n // are reaped, not just the shell. Fire-and-forget: settle promptly, escalate in background.\n void killProcessTree(child, { processGroup: SPAWN_DETACHED });\n settle({\n success: false,\n output: stdoutOutput.toString(),\n error: `Command timed out after ${timeout}ms`,\n });\n }, timeout);\n\n function settle(result: IToolInvocationResult): void {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n resolve(JSON.stringify(result));\n }\n\n // CORE-018: the run-scoped signal must terminate the underlying work β completing\n // silently after an abort is a cancellation-contract violation. CORE-023: process-group\n // kill reaps grandchildren the bare SIGTERM left orphaned.\n function onAbort(): void {\n void killProcessTree(child, { processGroup: SPAWN_DETACHED });\n settle({\n success: false,\n output: stdoutOutput.toString(),\n error: 'Aborted',\n });\n }\n signal?.addEventListener('abort', onAbort, { once: true });\n\n child.on('error', (err: Error) => {\n // Only a process that never started is over here; a failed kill leaves it running, and its\n // close releases it.\n if (child.pid === undefined) release();\n settle({\n success: false,\n output: '',\n error: err.message,\n });\n });\n\n child.on('close', (code: number | null) => {\n // Always, even after a timeout or an abort already settled: the sandbox undoes what it must.\n const note = release();\n if (timedOut) {\n settle({\n success: false,\n output: stdoutOutput.toString(),\n error: `Command timed out after ${timeout}ms`,\n exitCode: code ?? undefined,\n });\n return;\n }\n\n const stdout = stdoutOutput.toString();\n const stderr = stderrOutput.toString();\n\n const exitCode = code ?? 0;\n const combined = stderr ? `${stdout}\\nstderr:\\n${stderr}` : stdout;\n const output = note === undefined ? combined : `${combined}\\n${note}`;\n\n settle({\n success: true,\n output,\n exitCode,\n });\n });\n });\n}\n\n/** Options for the shell tool factories (sandbox + description seam + routing-hint derivation). */\nexport interface IShellToolOptions extends ISandboxBuiltinToolOptions {\n /** Host-selected executable; absence uses the neutral platform/SHELL default. */\n shellExecutable?: string;\n /**\n * Registered names of the sibling tools available in this assembly (NEUT-002). When provided,\n * the default description's dedicated-tool routing hints are restricted to this set; when\n * omitted, the full default hint set is used. Ignored when `description` overrides the text.\n */\n availableTools?: readonly string[];\n}\n\n/**\n * Build a host-shell command tool under a given registered name. Both `Shell` and the\n * model-familiar `Bash` are registered as aliases of this one OS-aware implementation\n * (TERM-008): the shell is resolved per OS and the description names the active shell so the\n * model writes the right syntax regardless of which alias it calls.\n */\nfunction createHostShellTool(name: string, options: IShellToolOptions): FunctionTool {\n const shell = resolvePlatformShell({ executable: options.shellExecutable });\n return createZodFunctionTool(\n name,\n options.description ?? buildShellToolDescription(shell, options.availableTools),\n ShellSchema,\n async (params, context) => {\n return runShell(params, options, shell, context?.signal, context?.shellTraceEnv);\n },\n );\n}\n\n/**\n * Create a `Shell` tool instance β register with the Robota agent tools registry.\n * The description is resolved at creation time for the host's active shell.\n */\nexport function createShellTool(options: IShellToolOptions): FunctionTool {\n return createHostShellTool('Shell', options);\n}\n\n/**\n * Create a `Bash` tool instance β the model-familiar alias of the same OS-aware shell tool.\n */\nexport function createBashTool(options: IShellToolOptions): FunctionTool {\n return createHostShellTool('Bash', options);\n}\n","import { resolve } from 'node:path';\n\nimport { isPathInside } from '@robota-sdk/agent-core/node';\n\nimport type { IToolInvocationResult } from '../types/tool-result.js';\n\n/**\n * Returns a JSON-serialized IToolInvocationResult error when filePath is outside cwd, or when NO\n * containment root is configured. Returns undefined only when the path is inside a configured root.\n *\n * This sentence used to end \"or cwd is not set\" β the fail-open default ARCH-010 removed. It sat\n * directly above the two functions that implement the distinction, which is the worst place for a\n * comment to say the opposite of the code.\n *\n * SEC-006: containment is decided on the CANONICAL (symlink-resolved) paths, via the shared\n * `isPathInside` SSOT in agent-core. A purely lexical `resolve()` + `startsWith` comparison let\n * `<cwd>/link/secret` through when `link -> /etc`, because `resolve` does not consult the filesystem\n * and so cannot see a symlink β while the subsequent `readFile`/`writeFile` followed the link out of\n * the sandbox. For `Write`/`Edit` that meant creating files anywhere the process could reach, and\n * since symlinks are ordinary committed git content, pointing the agent at an untrusted clone was\n * enough to arm it.\n *\n * The same defect existed in the CLI's monitor asset server; both now share one implementation,\n * because two containment checks that can disagree are their own defect.\n */\n/**\n * Whether a host path is inside the tool's containment root β the single predicate every builtin\n * asks, whatever it does with the answer.\n *\n * `checkPathWithinCwd` turns a `false` into the tool-result error a tool RETURNS; the enumerating\n * tools (`Glob`, `Grep`) instead SKIP the entry mid-walk and must not fabricate an error per file.\n * Both ask this one question, which asks agent-core's `isPathInside` SSOT β so there is no second\n * containment rule that could disagree with the first (SEC-006's stated defect, SEC-007 keeping it\n * true as the guard's reach widens).\n *\n * `cwd === undefined` means no containment root is configured, and the answer is NO β ARCH-010.\n *\n * This used to return `true` there: with no root, everything was inside it. A guard whose default is\n * \"allow\" is not a guard, it is a guard that has to be remembered, and the architecture audit found\n * three independent layers that had forgotten. `pack-coding` had already written the consequence into\n * its own source β \"file tools constructed with no options carry a DISARMED working-directory guard:\n * their `Read` will happily return `/etc/hostname`\" β and the child-process subagent worker called\n * `createDefaultTools()` with no argument, so a subagent got exactly that. Measured, not inferred:\n * before this change a rootless `Read` of `/etc/hostname` returned the file.\n *\n * Refusing instead means a construction site that forgets the root fails loudly on its first file\n * access rather than silently running unconfined. The root is also required by the tool factories now,\n * so reaching this branch at all is an assembly bug β which is why the error says so specifically\n * rather than reporting an ordinary out-of-root path.\n */\nexport function isWithinCwd(filePath: string, cwd: string | undefined): boolean {\n if (cwd === undefined) return false;\n return isPathInside(cwd, filePath);\n}\n\n/**\n * Where a RELATIVE host path the model supplied is anchored: the containment root, never\n * `process.cwd()` (issue #2429). `Read`/`Write`/`Edit` declare `filePath` absolute, but nothing\n * makes the model comply, and `isPathInside` canonicalises a relative candidate against the PROCESS\n * directory β so a relative path was confined to one root and judged against another. Same rule as\n * `resolveSearchRoot` for the enumerating tools. With no root there is nothing to anchor to; the path\n * is returned as written and `checkPathWithinCwd` refuses it (ARCH-010).\n */\nexport function resolveHostPath(filePath: string, cwd: string | undefined): string {\n if (cwd === undefined) return filePath;\n return resolve(cwd, filePath);\n}\n\nexport function checkPathWithinCwd(filePath: string, cwd: string | undefined): string | undefined {\n if (cwd === undefined) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error:\n `Access denied: \"${filePath}\" cannot be checked because no containment root is ` +\n 'configured for this tool. This is an assembly bug, not a path problem β the tool was ' +\n 'constructed without a `cwd`, so it has no boundary to enforce (ARCH-010).',\n };\n return JSON.stringify(result);\n }\n\n if (!isWithinCwd(filePath, cwd)) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Access denied: \"${filePath}\" is outside the working directory`,\n };\n return JSON.stringify(result);\n }\n\n return undefined;\n}\n\n/**\n * Resolve an LLM-supplied search root for an ENUMERATING tool, and refuse one that escapes (SEC-007).\n *\n * A relative `requested` anchors to the CONTAINMENT ROOT, not to `process.cwd()`: anchoring them to\n * two different directories is how a \"contained\" search silently starts somewhere else. `error`\n * carries the tool-result JSON to return, or is `undefined` when the root is allowed.\n *\n * With no root there is nothing to anchor to, so this refuses rather than reaching for the process\n * directory (ARCH-010). The previous `cwd ?? process.cwd()` was that reach: harmless once the guard\n * below refuses anyway, but it read as a supported fallback, which is the pattern being removed.\n */\nexport function resolveSearchRoot(\n requested: string | undefined,\n cwd: string | undefined,\n): { root: string; error: string | undefined } {\n if (cwd === undefined) {\n return { root: '', error: checkPathWithinCwd(requested ?? '', undefined) };\n }\n const root = requested ? resolve(cwd, requested) : cwd;\n return { root, error: checkPathWithinCwd(root, cwd) };\n}\n","/**\n * ReadTool β read a file and return its contents with line numbers (cat -n style).\n *\n * Supports offset/limit for partial reads. Detects binary files and refuses to\n * return their raw bytes. Default limit is 2000 lines.\n */\n\nimport { open, stat } from 'node:fs/promises';\n\nimport { z } from 'zod';\nimport { ToolExecutionError } from '@robota-sdk/agent-core';\n\nimport { checkPathWithinCwd, resolveHostPath } from './path-guard.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { ISandboxBuiltinToolOptions } from './tool-options.js';\nimport type { ISandboxToolOptions } from '../sandbox/types.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { FunctionTool } from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\nconst DEFAULT_READ_DESCRIPTION =\n 'Reads a file from the local filesystem.\\n\\nBy default, reads up to 2000 lines from the beginning of the file. You can optionally specify offset and limit for partial reads.\\n\\nResults are returned using cat -n format, with line numbers starting at 1.\\n\\nThe filePath parameter must be an absolute path, not a relative path.';\n\nconst DEFAULT_LIMIT = 2000;\nconst MAX_READ_BYTES = 4 * 1024 * 1024;\nconst READ_CHUNK_BYTES = 64 * 1024;\n\n/** A budget refusal is a hard failure so a workflow cannot treat it as file content. */\nexport class ReadByteLimitError extends ToolExecutionError {\n public constructor(public readonly boundary: 'input' | 'output') {\n super(`Read ${boundary} exceeds its UTF-8 byte limit`, 'Read');\n }\n}\n\n/** Abort is a hard failure; the workflow must not accept a partial read. */\nexport class ReadCancelledError extends ToolExecutionError {\n public constructor() {\n super('Read cancelled', 'Read');\n }\n}\n\nconst ReadSchema = z.object({\n filePath: z.string().describe('The absolute path to the file to read'),\n offset: z\n .number()\n .optional()\n .describe(\n 'The line number to start reading from (1-based). Only provide if the file is too large to read at once',\n ),\n limit: z\n .number()\n .optional()\n .describe(\n `The number of lines to read (default: ${DEFAULT_LIMIT}). Only provide if the file is too large to read at once`,\n ),\n});\n\ntype TReadArgs = z.infer<typeof ReadSchema>;\n\n/**\n * Heuristic binary detection: scan the first 8 KB for null bytes.\n */\nfunction isBinary(buffer: Buffer): boolean {\n const checkLength = Math.min(buffer.length, 8192);\n for (let i = 0; i < checkLength; i++) {\n if (buffer[i] === 0) return true;\n }\n return false;\n}\n\n/**\n * Format lines with 1-based line numbers in cat -n style.\n * Pads line number to the width of the highest line number.\n */\nfunction formatWithLineNumbers(lines: string[], startLine: number): string {\n const lastLineNum = startLine + lines.length - 1;\n const width = String(lastLineNum).length;\n return lines\n .map((line, idx) => {\n const lineNum = String(startLine + idx).padStart(width, ' ');\n return `${lineNum}\\t${line}`;\n })\n .join('\\n');\n}\n\nfunction formatReadResult(\n filePath: string,\n content: string,\n startLine: number,\n limit: number,\n): string {\n // Count and select without splitting the entire bounded file into potentially millions of\n // strings. Reject selected text before formatting can amplify many short lines.\n const selectedLines: string[] = [];\n let selectedMinimumBytes = 0;\n let totalLines = 0;\n let lineStart = 0;\n const selectedStart = Math.trunc(startLine - 1);\n const selectedEnd = Math.trunc(startLine - 1 + limit);\n while (lineStart < content.length) {\n const newline = content.indexOf('\\n', lineStart);\n const lineEnd = newline === -1 ? content.length : newline;\n totalLines++;\n if (totalLines > selectedStart && totalLines <= selectedEnd) {\n const line = content.slice(lineStart, lineEnd);\n selectedMinimumBytes += Buffer.byteLength(line, 'utf8')\n + String(startLine + selectedLines.length).length + 1;\n if (selectedMinimumBytes > MAX_READ_BYTES) throw new ReadByteLimitError('output');\n selectedLines.push(line);\n }\n if (newline === -1) break;\n lineStart = newline + 1;\n }\n const returnedLines = selectedLines.length;\n const header =\n returnedLines < totalLines\n ? `[File: ${filePath} (lines ${startLine}-${startLine + returnedLines - 1} of ${totalLines})]\\n`\n : `[File: ${filePath} (${totalLines} lines)]\\n`;\n\n const width = String(startLine + returnedLines - 1).length;\n let outputBytes = Buffer.byteLength(header, 'utf8') + Math.max(0, returnedLines - 1);\n for (const line of selectedLines) outputBytes += width + 1 + Buffer.byteLength(line, 'utf8');\n if (outputBytes > MAX_READ_BYTES) throw new ReadByteLimitError('output');\n const output = formatWithLineNumbers(selectedLines, startLine);\n\n const result: IToolInvocationResult = {\n success: true,\n output: header + output,\n };\n return JSON.stringify(result);\n}\n\nasync function readFileTool(args: TReadArgs, options: ISandboxToolOptions): Promise<string> {\n if (options.signal?.aborted) throw new ReadCancelledError();\n const { offset, limit = DEFAULT_LIMIT } = args;\n // A relative path anchors to the containment root before it is confined or opened (issue #2429).\n const filePath = options.sandboxClient\n ? args.filePath\n : resolveHostPath(args.filePath, options.cwd);\n const startLine = offset !== undefined && offset > 0 ? offset : 1;\n\n if (options.sandboxClient) {\n try {\n const content = await options.sandboxClient.readFile(filePath);\n if (options.signal?.aborted) throw new ReadCancelledError();\n // This API already returns a complete string; admission here still bounds formatting and\n // workflow output, while a streaming sandbox read API is needed to bound provider memory.\n if (Buffer.byteLength(content, 'utf8') > MAX_READ_BYTES) {\n throw new ReadByteLimitError('input');\n }\n return formatReadResult(filePath, content, startLine, limit);\n } catch (err) {\n if (err instanceof ReadByteLimitError || err instanceof ReadCancelledError) throw err;\n // allow-fallback: sandbox read failure β surface as IToolInvocationResult error\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n }\n\n const pathError = checkPathWithinCwd(filePath, options.cwd);\n if (pathError !== undefined) return pathError;\n\n let fileStats: Awaited<ReturnType<typeof stat>> | undefined;\n try {\n fileStats = await stat(filePath);\n } catch (err) {\n // allow-fallback: stat failure means file not found β IToolInvocationResult error\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `File not found: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n if (!fileStats.isFile()) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Path is not a file: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n let buffer = Buffer.alloc(0);\n let binaryFile = false;\n try {\n const handle = await open(filePath, 'r');\n try {\n const chunks: Buffer[] = [];\n const chunk = Buffer.allocUnsafe(READ_CHUNK_BYTES);\n let bytes = 0;\n let binaryCheckedBytes = 0;\n while (bytes <= MAX_READ_BYTES) {\n if (options.signal?.aborted) throw new ReadCancelledError();\n const { bytesRead } = await handle.read(\n chunk, 0, Math.min(chunk.length, MAX_READ_BYTES + 1 - bytes), null,\n );\n if (bytesRead === 0) break;\n const binaryCheckLength = Math.min(bytesRead, 8192 - binaryCheckedBytes);\n if (binaryCheckLength > 0 && isBinary(chunk.subarray(0, binaryCheckLength))) {\n binaryFile = true;\n break;\n }\n binaryCheckedBytes += binaryCheckLength;\n bytes += bytesRead;\n if (bytes > MAX_READ_BYTES) throw new ReadByteLimitError('input');\n chunks.push(Buffer.from(chunk.subarray(0, bytesRead)));\n }\n if (!binaryFile) buffer = Buffer.concat(chunks, bytes);\n } finally {\n await handle.close();\n }\n } catch (err) {\n if (err instanceof ReadByteLimitError || err instanceof ReadCancelledError) throw err;\n // allow-fallback: read failure β IToolInvocationResult error (permissions, locks)\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n\n if (options.signal?.aborted) throw new ReadCancelledError();\n if (binaryFile) {\n const result: IToolInvocationResult = {\n success: false, output: '', error: `Binary file not supported: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n const content = buffer.toString('utf8');\n return formatReadResult(filePath, content, startLine, limit);\n}\n\n/**\n * Create a ReadTool instance β register with Robota agent tools registry.\n */\nexport function createReadTool(options: ISandboxBuiltinToolOptions): FunctionTool {\n return createZodFunctionTool(\n 'Read',\n options.description ?? DEFAULT_READ_DESCRIPTION,\n ReadSchema,\n async (params) => {\n return readFileTool(params, options);\n },\n );\n}\n","import { randomBytes } from 'node:crypto';\nimport { chmod, mkdir, rename, rm, stat, writeFile } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\n\nconst TEMP_RANDOM_BYTES = 6;\nconst PRESERVED_MODE_BITS = 0o7777;\nconst MISSING_FILE_ERROR_CODE = 'ENOENT';\n\n/**\n * NEUT-009: this marker used to carry the consumer's product name, so a neutral tool library wrote\n * that name onto every temporary file it created β inherited by any other product built on it. The\n * marker now says what the file IS, which is all it was ever for.\n *\n * The product name is not quoted here either: the ratchet counts prose, deliberately, because a\n * library whose comments teach the product's layout is coupled to it just as firmly.\n */\nconst TEMP_MARKER = '.atomic-tmp-';\n\nfunction createTempFilePath(filePath: string): string {\n const dir = dirname(filePath);\n const name = basename(filePath);\n const suffix = randomBytes(TEMP_RANDOM_BYTES).toString('hex');\n return join(dir, `.${name}${TEMP_MARKER}${process.pid}-${Date.now()}-${suffix}`);\n}\n\nasync function readExistingMode(filePath: string): Promise<number | undefined> {\n try {\n const fileStats = await stat(filePath);\n return fileStats.mode & PRESERVED_MODE_BITS;\n } catch (error) {\n if (error instanceof Error && hasErrorCode(error, MISSING_FILE_ERROR_CODE)) return undefined;\n throw error;\n }\n}\n\nfunction hasErrorCode(error: Error, code: string): boolean {\n return 'code' in error && error.code === code;\n}\n\nexport async function atomicWriteUtf8File(filePath: string, content: string): Promise<void> {\n const dir = dirname(filePath);\n await mkdir(dir, { recursive: true });\n\n const existingMode = await readExistingMode(filePath);\n const tempFilePath = createTempFilePath(filePath);\n try {\n await writeFile(tempFilePath, content, 'utf8');\n if (existingMode !== undefined) {\n await chmod(tempFilePath, existingMode);\n }\n await rename(tempFilePath, filePath);\n } catch (error) {\n await rm(tempFilePath, { force: true }).catch(() => undefined);\n throw error;\n }\n}\n","/**\n * WriteTool β write content to a file, auto-creating parent directories.\n */\n\nimport { z } from 'zod';\n\nimport { atomicWriteUtf8File } from './atomic-file-write.js';\nimport { checkPathWithinCwd, resolveHostPath } from './path-guard.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { ISandboxBuiltinToolOptions } from './tool-options.js';\nimport type { ISandboxToolOptions } from '../sandbox/types.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { FunctionTool } from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\nconst DEFAULT_WRITE_DESCRIPTION =\n 'Writes a file to the local filesystem. This will overwrite an existing file if one exists.\\n\\nPrefer the Edit tool for modifying existing files β it only sends the changed text. Use this tool to create new files or for complete rewrites.\\n\\nParent directories are created automatically when missing.';\n\nconst WriteSchema = z.object({\n filePath: z.string().describe('The absolute path to the file to write'),\n content: z.string().describe('The content to write to the file'),\n});\n\ntype TWriteArgs = z.infer<typeof WriteSchema>;\n\nasync function writeFileTool(args: TWriteArgs, options: ISandboxToolOptions): Promise<string> {\n const { content } = args;\n // A relative path anchors to the containment root before it is confined or written (issue #2429).\n const filePath = options.sandboxClient\n ? args.filePath\n : resolveHostPath(args.filePath, options.cwd);\n\n if (!options.sandboxClient) {\n const pathError = checkPathWithinCwd(filePath, options.cwd);\n if (pathError !== undefined) return pathError;\n }\n\n try {\n if (options.sandboxClient) {\n await options.sandboxClient.writeFile(filePath, content);\n } else {\n await atomicWriteUtf8File(filePath, content);\n }\n\n const result: IToolInvocationResult = {\n success: true,\n output: `Written ${Buffer.byteLength(content, 'utf8')} bytes to ${filePath}`,\n };\n return JSON.stringify(result);\n } catch (err) {\n // allow-fallback: write failure β IToolInvocationResult error (disk full, permissions)\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n}\n\n/**\n * Create a WriteTool instance β register with Robota agent tools registry.\n */\nexport function createWriteTool(options: ISandboxBuiltinToolOptions): FunctionTool {\n return createZodFunctionTool(\n 'Write',\n options.description ?? DEFAULT_WRITE_DESCRIPTION,\n WriteSchema,\n async (params) => {\n return writeFileTool(params, options);\n },\n );\n}\n","/**\n * EditTool β perform string-replace edits on a file.\n *\n * By default, requires the oldString to appear exactly once in the file\n * (ensuring surgical edits). Pass replaceAll:true to replace all occurrences.\n */\n\nimport { createReadStream } from 'node:fs';\n\nimport { z } from 'zod';\n\nimport { atomicWriteUtf8File } from './atomic-file-write.js';\nimport { checkPathWithinCwd, resolveHostPath } from './path-guard.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { ISandboxBuiltinToolOptions } from './tool-options.js';\nimport type { ISandboxToolOptions } from '../sandbox/types.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { FunctionTool } from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\nconst DEFAULT_EDIT_DESCRIPTION =\n \"Performs exact string replacements in files.\\n\\noldString must exactly match the file's current content, including whitespace and indentation β reading the file first (e.g. with a file-read tool) is the reliable way to copy exact text.\\n\\nThe edit will FAIL if oldString is not unique in the file. Either provide more surrounding context to make it unique, or set replaceAll to change every instance.\";\n\nconst EditSchema = z.object({\n filePath: z.string().describe('The absolute path to the file to modify'),\n oldString: z\n .string()\n .describe('The text to replace (must be an exact match of existing content)'),\n newString: z.string().describe('The text to replace it with (must be different from oldString)'),\n replaceAll: z\n .boolean()\n .optional()\n .describe(\n 'Replace all occurrences of oldString (default: false). Useful for renaming variables',\n ),\n});\n\ntype TEditArgs = z.infer<typeof EditSchema>;\n\n// Same ceiling as Read/Grep (MAX_READ_BYTES / MAX_GREP_FILE_BYTES): a fixed per-operation\n// budget on the whole-string operations (includes/indexOf/split/join) this tool runs on the\n// main thread. Kept as a local constant rather than an import β each builtin tool already\n// carries its own copy of this value; see read-tool.ts and grep-tool.ts.\nconst MAX_EDIT_FILE_BYTES = 4 * 1024 * 1024;\nconst READ_CHUNK_BYTES = 64 * 1024;\n\n/** Marks a refusal that must not surface a partial or crashed read to the caller. */\nclass EditByteLimitError extends Error {\n public constructor(public readonly boundary: 'input' | 'output') {\n super(`Edit ${boundary} exceeds its ${MAX_EDIT_FILE_BYTES}-byte limit`);\n }\n}\n\n/**\n * Read a file as UTF-8 while rejecting as soon as more than `maxBytes` bytes have arrived β\n * before the whole content is materialized. Reading actual bytes off the stream (rather than\n * trusting stat() size) also catches a file that grows after being stat'd, or has no stable\n * size at all (a named pipe).\n */\nasync function readBoundedUtf8File(\n filePath: string,\n maxBytes: number,\n): Promise<string> {\n const stream = createReadStream(filePath, { highWaterMark: READ_CHUNK_BYTES });\n const chunks: Buffer[] = [];\n let bytes = 0;\n try {\n for await (const chunk of stream) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n bytes += buffer.length;\n if (bytes > maxBytes) throw new EditByteLimitError('input');\n chunks.push(buffer);\n }\n } finally {\n stream.destroy();\n }\n return Buffer.concat(chunks, bytes).toString('utf8');\n}\n\nasync function editFileTool(args: TEditArgs, options: ISandboxToolOptions): Promise<string> {\n const { oldString, newString, replaceAll = false } = args;\n // A relative path anchors to the containment root before it is confined or edited (issue #2429).\n const filePath = options.sandboxClient\n ? args.filePath\n : resolveHostPath(args.filePath, options.cwd);\n\n if (!options.sandboxClient) {\n const pathError = checkPathWithinCwd(filePath, options.cwd);\n if (pathError !== undefined) return pathError;\n }\n\n let content: string;\n try {\n if (options.sandboxClient) {\n content = await options.sandboxClient.readFile(filePath);\n // This API already returns a complete string; admission here still bounds the\n // string operations below, while a streaming sandbox read API is needed to bound\n // provider memory the way the host path's stream does.\n if (Buffer.byteLength(content, 'utf8') > MAX_EDIT_FILE_BYTES) throw new EditByteLimitError('input');\n } else {\n content = await readBoundedUtf8File(filePath, MAX_EDIT_FILE_BYTES);\n }\n } catch (err) {\n if (err instanceof EditByteLimitError) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `${err.message}: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n // allow-fallback: read failure before edit β IToolInvocationResult error (file not found)\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `File not found: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n if (!content.includes(oldString)) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `oldString not found in file: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n // Uniqueness check when not in replaceAll mode\n let parts: string[] = [];\n if (replaceAll) {\n parts = content.split(oldString);\n } else {\n const firstIdx = content.indexOf(oldString);\n const lastIdx = content.lastIndexOf(oldString);\n if (firstIdx !== lastIdx) {\n const occurrences = content.split(oldString).length - 1;\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error:\n `oldString is not unique in file (found ${occurrences} occurrences). ` +\n 'Provide more context to make it unique, or use replaceAll:true.',\n };\n return JSON.stringify(result);\n }\n }\n\n // replaceAll can amplify: a newString much longer than oldString, repeated across many\n // occurrences, can produce an output far bigger than the (bounded) input. The expected byte\n // count is cheap to derive from the occurrence count computed above, without materializing\n // the joined string, so the check runs before the write for either mode.\n const count = replaceAll ? parts.length - 1 : 1;\n const oldBytes = Buffer.byteLength(oldString, 'utf8');\n const newBytes = Buffer.byteLength(newString, 'utf8');\n // Decoded length, not raw file bytes: invalid UTF-8 re-encodes as U+FFFD (3 bytes) on write.\n const decodedBytes = Buffer.byteLength(content, 'utf8');\n const expectedOutputBytes = decodedBytes - count * oldBytes + count * newBytes;\n if (expectedOutputBytes > MAX_EDIT_FILE_BYTES) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Edit output exceeds its ${MAX_EDIT_FILE_BYTES}-byte limit: ${filePath}`,\n };\n return JSON.stringify(result);\n }\n\n const updated = replaceAll\n ? parts.join(newString)\n : content.slice(0, content.indexOf(oldString)) +\n newString +\n content.slice(content.indexOf(oldString) + oldString.length);\n\n try {\n if (options.sandboxClient) {\n await options.sandboxClient.writeFile(filePath, updated);\n } else {\n await atomicWriteUtf8File(filePath, updated);\n }\n } catch (err) {\n // allow-fallback: write failure after edit β IToolInvocationResult error\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n\n // Calculate start line number from the original content\n const matchIdx = content.indexOf(oldString);\n const startLine = matchIdx >= 0 ? content.substring(0, matchIdx).split('\\n').length : 1;\n const result: IToolInvocationResult = {\n success: true,\n output: `Replaced ${count} occurrence(s) in ${filePath}`,\n startLine,\n };\n return JSON.stringify(result);\n}\n\n/**\n * Create an EditTool instance β register with Robota agent tools registry.\n */\nexport function createEditTool(options: ISandboxBuiltinToolOptions): FunctionTool {\n return createZodFunctionTool(\n 'Edit',\n options.description ?? DEFAULT_EDIT_DESCRIPTION,\n EditSchema,\n async (params) => {\n return editFileTool(params, options);\n },\n );\n}\n","/**\n * GlobTool β fast file pattern search using fast-glob.\n *\n * Excludes node_modules and .git by default.\n * Results are sorted by modification time (most recently modified first) among the candidates\n * enumerated before any candidate ceiling was hit (see DEFAULT_MAX_GLOB_CANDIDATES) β ordering is\n * not guaranteed across the full match set when the search tree is larger than that ceiling.\n *\n * SEC-007: when a containment root is configured the enumeration is confined to it. Listing the\n * filesystem is a disclosure in its own right β a sandbox that stops the model reading a file but\n * lets it map everything around that file is not a sandbox.\n */\n\nimport { stat } from 'node:fs/promises';\nimport { resolve } from 'node:path';\n\nimport fg from 'fast-glob';\nimport pLimit from 'p-limit';\nimport { z } from 'zod';\n\nimport { isWithinCwd, resolveSearchRoot } from './path-guard.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IContainedBuiltinToolOptions } from './tool-options.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { FunctionTool } from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\nconst DEFAULT_MAX_RESULTS = 1000;\n\n/**\n * Ceiling on how many raw glob matches are pulled off `fast-glob`'s match STREAM before enumeration\n * stops, independent of `limit`/`DEFAULT_MAX_RESULTS`.\n *\n * `fg(pattern)` (the promise form) materializes every match into memory and only then stats and\n * slices to `limit` β a pattern like `**\\/*` under a huge tree allocates and stats the whole match\n * set no matter how small `limit` is. Streaming lets the walk stop as soon as this many CANDIDATES\n * have been seen, so memory and stat fan-out scale with this ceiling, not with the tree.\n */\nexport const DEFAULT_MAX_GLOB_CANDIDATES = 50_000;\n\nconst GlobSchema = z.object({\n pattern: z\n .string()\n .describe('The glob pattern to match files against (e.g. \"**/*.ts\", \"src/**/*.tsx\")'),\n path: z\n .string()\n .optional()\n .describe(\n 'The directory to search in. Defaults to the current working directory. Must be a valid directory path if provided',\n ),\n limit: z\n .number()\n .optional()\n .describe(\n 'Maximum number of results to return (default: 1000). Use a smaller limit to save context space',\n ),\n});\n\ntype TGlobArgs = z.infer<typeof GlobSchema>;\n\ninterface IFileWithMtime {\n path: string;\n mtime: number;\n}\n\n/** Cap on concurrent `stat` calls during the mtime sort, so a large match set cannot storm the FS. */\nconst STAT_CONCURRENCY_LIMIT = 100;\n\n/**\n * Drop every match whose CANONICAL path escapes the containment root, then stat the survivors for the\n * mtime sort, newest first.\n *\n * Containment is decided per RESULT as well as per root (SEC-007): a `..` in the pattern, or an\n * absolute pattern, produces a match the search root never vouched for. Decided canonically through\n * the shared guard β a symlink named `escape` is a plain segment, so no amount of segment validation\n * would catch it.\n */\nasync function containedMatchesByMtime(\n matches: readonly string[],\n cwd: string,\n containmentRoot: string | undefined,\n): Promise<IFileWithMtime[]> {\n const limit = pLimit(STAT_CONCURRENCY_LIMIT);\n const stated = await Promise.all(\n matches.map((p) =>\n limit(async (): Promise<IFileWithMtime | undefined> => {\n const absPath = resolve(cwd, p);\n if (!isWithinCwd(absPath, containmentRoot)) return undefined;\n try {\n return { path: p, mtime: (await stat(absPath)).mtimeMs };\n } catch {\n // allow-fallback: stat failure on a matched path returns mtime=0 (sort-last), not a logic fallback\n return { path: p, mtime: 0 };\n }\n }),\n ),\n );\n return stated\n .filter((entry): entry is IFileWithMtime => entry !== undefined)\n .sort((a, b) => b.mtime - a.mtime);\n}\n\nexport interface IGlobMatchesResult {\n matches: string[];\n /** True when the candidate stream was stopped at `maxCandidates` with more matches unseen. */\n truncated: boolean;\n}\n\n/**\n * Pull matches off `fast-glob`'s streaming API one at a time, stopping at `maxCandidates` instead of\n * materializing the whole match set (see {@link DEFAULT_MAX_GLOB_CANDIDATES}). Exported for tests that\n * need a smaller ceiling than the real default.\n */\nexport async function collectGlobMatches(\n pattern: string,\n options: fg.Options,\n maxCandidates: number,\n): Promise<IGlobMatchesResult> {\n const matches: string[] = [];\n let truncated = false;\n const stream = fg.stream(pattern, options) as unknown as AsyncIterable<string>;\n for await (const entry of stream) {\n if (matches.length >= maxCandidates) {\n truncated = true;\n break;\n }\n matches.push(entry);\n }\n return { matches, truncated };\n}\n\n/**\n * Exported (rather than module-private) so tests can drive it with a `maxCandidates` far smaller than\n * {@link DEFAULT_MAX_GLOB_CANDIDATES} β the real default is too large to exercise cheaply β without\n * adding any test-only knob to the public `createGlobTool` factory or its schema.\n */\nexport async function globFileTool(\n args: TGlobArgs,\n options: IContainedBuiltinToolOptions,\n maxCandidates: number = DEFAULT_MAX_GLOB_CANDIDATES,\n): Promise<string> {\n const { pattern, path: basePath } = args;\n const containmentRoot = options.cwd;\n const { root: cwd, error: rootError } = resolveSearchRoot(basePath, containmentRoot);\n if (rootError) return rootError;\n\n let candidates: IGlobMatchesResult;\n try {\n candidates = await collectGlobMatches(\n pattern,\n {\n cwd,\n ignore: ['**/node_modules/**', '**/.git/**'],\n dot: true,\n absolute: false,\n // A symlinked directory is a BOUNDARY, not a doorway. Descending through one both escapes the\n // sandbox and turns a single Glob call into a whole-disk walk when the link points at `/`.\n //\n // Unconditional since ARCH-010. This used to be `containmentRoot === undefined` β following\n // links when there was no root β but a rootless call now fails at `resolveSearchRoot` above and\n // never reaches here, so that branch described a state that can no longer exist.\n followSymbolicLinks: false,\n },\n maxCandidates,\n );\n } catch (err) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: err instanceof Error ? err.message : String(err),\n };\n return JSON.stringify(result);\n }\n const { matches, truncated: candidatesTruncated } = candidates;\n\n const withMtime = await containedMatchesByMtime(matches, cwd, containmentRoot);\n\n const maxResults = args.limit ?? DEFAULT_MAX_RESULTS;\n const totalMatches = withMtime.length;\n const truncated = totalMatches > maxResults;\n const limited = truncated ? withMtime.slice(0, maxResults) : withMtime;\n const sorted = limited.map((f) => f.path);\n\n let output = sorted.length > 0 ? sorted.join('\\n') : '(no matches)';\n if (truncated) {\n output += `\\n\\n[Showing ${maxResults} of ${totalMatches} matches. Use limit parameter to see more.]`;\n }\n if (candidatesTruncated) {\n output += `\\n\\n[Candidate search stopped early; the search tree has more matches than this tool scans in one call. Results are ordered among the scanned candidates only β narrow the pattern or path to see the rest.]`;\n }\n\n const result: IToolInvocationResult = {\n success: true,\n output,\n };\n return JSON.stringify(result);\n}\n\nconst DEFAULT_GLOB_DESCRIPTION =\n \"Fast file pattern matching tool that works with any codebase size.\\n\\nSupports glob patterns like '**/*.js' or 'src/**/*.ts'. Returns matching file paths sorted by modification time.\\n\\nUse this tool when you need to find files by name patterns.\\n\\nDefault limit is 1000 results. Use the limit parameter if you need fewer results to save context space.\";\n\n/**\n * Create a GlobTool instance β register with Robota agent tools registry.\n */\nexport function createGlobTool(options: IContainedBuiltinToolOptions): FunctionTool {\n return createZodFunctionTool(\n 'Glob',\n options.description ?? DEFAULT_GLOB_DESCRIPTION,\n GlobSchema,\n async (params) => {\n return globFileTool(params, options);\n },\n );\n}\n","/**\n * The `Grep` tool's search internals β file enumeration and per-file matching.\n *\n * Split out of `grep-tool.ts` (SEC-007) when adding containment pushed that file past the\n * anti-monolith limit. The split is by responsibility, not by line count: this module is HOW the\n * search is performed, while `grep-tool.ts` is the tool SURFACE β schema, model-facing description,\n * factory, and the result envelope. Neither half needs to know the other's concerns.\n */\n\nimport { readdir, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { isWithinCwd } from './path-guard.js';\n\n/** Convert a simple glob to a RegExp for file name filtering. */\nfunction globToRegex(glob: string): RegExp {\n const escaped = glob\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .replace(/\\*\\*/g, '.+')\n .replace(/\\*/g, '[^/]*');\n return new RegExp(`^${escaped}$`);\n}\n\n/** Check if a file name matches an optional glob filter. */\nfunction matchesGlob(filename: string, glob: string | undefined): boolean {\n if (glob === undefined) return true;\n return globToRegex(glob).test(filename);\n}\n\n/**\n * Ceiling on how many directory entries `collectFiles` will `stat` before it stops walking.\n *\n * Without a cap, enumeration and stat fan-out scale with the whole tree under the search root,\n * not with any result limit β a directory with millions of files makes every `Grep` call walk and\n * stat millions of entries before `headLimit` ever gets a chance to truncate the OUTPUT. This bounds\n * the WALK itself.\n */\nexport const DEFAULT_MAX_COLLECTED_FILES = 50_000;\n\nexport interface ICollectFilesResult {\n files: string[];\n /** True when the walk stopped at `maxFiles` with more of the tree left unvisited. */\n truncated: boolean;\n}\n\n/**\n * Gather files under a directory recursively, excluding node_modules/.git, stopping once `maxFiles`\n * entries have been visited.\n *\n * `containmentRoot` (SEC-007) drops any entry whose CANONICAL path escapes the root, before it is\n * descended into or read. `stat` follows symlinks, so without this a link inside the root pointing\n * out of it made the whole target tree readable β including, for a symlinked FILE, its contents.\n */\nexport async function collectFiles(\n dirPath: string,\n glob: string | undefined,\n containmentRoot: string | undefined,\n maxFiles: number = DEFAULT_MAX_COLLECTED_FILES,\n): Promise<ICollectFilesResult> {\n const results: string[] = [];\n let visited = 0;\n let truncated = false;\n\n async function walk(current: string): Promise<void> {\n if (truncated) return;\n let entryNames: string[];\n try {\n entryNames = await readdir(current);\n } catch {\n return;\n }\n\n for (const name of entryNames) {\n if (truncated) return;\n if (name === 'node_modules' || name === '.git') continue;\n\n const fullPath = join(current, name);\n if (!isWithinCwd(fullPath, containmentRoot)) continue;\n\n if (visited >= maxFiles) {\n truncated = true;\n return;\n }\n visited++;\n\n let fileStat: Awaited<ReturnType<typeof stat>>;\n try {\n fileStat = await stat(fullPath);\n } catch {\n continue;\n }\n\n if (fileStat.isDirectory()) {\n await walk(fullPath);\n } else if (fileStat.isFile()) {\n if (matchesGlob(name, glob)) {\n results.push(fullPath);\n }\n }\n }\n }\n\n await walk(dirPath);\n return { files: results, truncated };\n}\n\n/** Search a single file for lines matching the regex. */\nexport function searchFile(\n content: string,\n filePath: string,\n regex: RegExp,\n contextLines: number,\n outputMode: 'files_with_matches' | 'content' | 'count',\n maxOutputBytes?: number,\n): string[] {\n const lines = content.split('\\n');\n const matchingIndices: number[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n if (regex.test(lines[i])) {\n matchingIndices.push(i);\n }\n }\n\n if (matchingIndices.length === 0) return [];\n\n if (outputMode === 'files_with_matches') {\n return [filePath];\n }\n\n if (outputMode === 'count') {\n return [`${filePath}:${matchingIndices.length}`];\n }\n\n // content mode β include context lines\n const includedIndices = new Set<number>();\n for (const idx of matchingIndices) {\n for (\n let c = Math.max(0, idx - contextLines);\n c <= Math.min(lines.length - 1, idx + contextLines);\n c++\n ) {\n includedIndices.add(c);\n }\n }\n\n const outputLines: string[] = [];\n let outputBytes = 0;\n const sortedIndices = Array.from(includedIndices).sort((a, b) => a - b);\n\n let prevIdx: number | undefined;\n let matchingCursor = 0;\n for (const idx of sortedIndices) {\n if (prevIdx !== undefined && idx > prevIdx + 1) {\n outputLines.push('--');\n }\n const lineNum = idx + 1;\n while (matchingIndices[matchingCursor] < idx) matchingCursor++;\n const marker = matchingIndices[matchingCursor] === idx ? ':' : '-';\n const row = `${filePath}:${lineNum}${marker}${lines[idx]}`;\n outputBytes += Buffer.byteLength(row, 'utf8') + 1;\n if (maxOutputBytes !== undefined && outputBytes > maxOutputBytes) throw new Error('byte limit');\n outputLines.push(row);\n prevIdx = idx;\n }\n\n return outputLines;\n}\n","import { spawn } from 'node:child_process';\nimport { EventEmitter } from 'node:events';\nimport { tmpdir } from 'node:os';\nimport { Worker } from 'node:worker_threads';\nimport { searchFile } from './grep-search.js';\n\ntype TMode = 'files_with_matches' | 'content' | 'count';\ntype TRequest = {\n id: number;\n content: string;\n filePath: string;\n pattern: string;\n contextLines: number;\n outputMode: TMode;\n};\ntype TResponse = { id: number; matches?: string[]; error?: string };\ninterface IGrepWorker {\n on(event: 'message', listener: (message: TResponse) => void): this;\n on(event: 'error', listener: () => void): this;\n once(event: 'exit', listener: () => void): this;\n postMessage(request: TRequest): void;\n terminate(): Promise<unknown>;\n}\n\nconst BOOTSTRAP = `\nconst { parentPort } = require('node:worker_threads');\nconst searchFile = ${searchFile.toString()};\nlet outputBytes = 0;\nparentPort.on('message', (request) => {\n try {\n const regex = new RegExp(request.pattern);\n const matches = searchFile(request.content, request.filePath, regex, request.contextLines, request.outputMode, 4 * 1024 * 1024);\n let bytes = 0;\n for (const match of matches) { bytes += Buffer.byteLength(match, 'utf8') + 1; if (outputBytes + bytes > 4 * 1024 * 1024) throw new Error('byte limit'); }\n outputBytes += bytes;\n parentPort.postMessage({ id: request.id, matches });\n } catch (error) { parentPort.postMessage({ id: request.id, error: error?.message === 'byte limit' ? 'Grep search exceeded its byte limit' : 'Invalid grep regex execution' }); }\n});\n`;\n\n// Bun cannot use Node's eval Worker consistently; keep the same pure operation in a child process.\nclass GrepProcessWorker extends EventEmitter implements IGrepWorker {\n private readonly child = spawn(\n process.execPath,\n [\n '-e',\n `\nconst searchFile = ${searchFile.toString()};\nconst readline = require('node:readline');\nlet outputBytes = 0;\nreadline.createInterface({ input: process.stdin }).on('line', line => {\n const request = JSON.parse(line);\n try {\n const regex = new RegExp(request.pattern);\n const matches = searchFile(request.content, request.filePath, regex, request.contextLines, request.outputMode, 4 * 1024 * 1024);\n let bytes = 0;\n for (const match of matches) { bytes += Buffer.byteLength(match, 'utf8') + 1; if (outputBytes + bytes > 4 * 1024 * 1024) throw new Error('byte limit'); }\n outputBytes += bytes;\n process.stdout.write(JSON.stringify({ id: request.id, matches }) + String.fromCharCode(10));\n } catch (error) { process.stdout.write(JSON.stringify({ id: request.id, error: error?.message === 'byte limit' ? 'Grep search exceeded its byte limit' : 'Invalid grep regex execution' }) + String.fromCharCode(10)); }\n});\n`,\n ],\n {\n env: {\n BUN_BE_BUN: '1',\n ...(process.env.SystemRoot ? { SystemRoot: process.env.SystemRoot } : {}),\n },\n cwd: tmpdir(),\n stdio: 'pipe',\n },\n );\n private readonly closed: Promise<void>;\n public constructor() {\n super();\n let pending = '';\n this.child.stdout.setEncoding('utf8');\n this.child.stdout.on('data', (chunk: string) => {\n pending += chunk;\n if (Buffer.byteLength(pending, 'utf8') > 24 * 1024 * 1024 + 1024) {\n this.emit('error');\n return;\n }\n let newline: number;\n while ((newline = pending.indexOf('\\n')) >= 0) {\n const line = pending.slice(0, newline);\n pending = pending.slice(newline + 1);\n try {\n this.emit('message', JSON.parse(line));\n } catch {\n this.emit('error');\n }\n }\n });\n this.child.stderr.resume();\n this.child.on('error', () => this.emit('error'));\n this.child.stdin.on('error', () => this.emit('error'));\n this.closed = new Promise<void>((resolve) => {\n this.child.once('close', () => {\n this.emit('exit');\n resolve();\n });\n });\n }\n public postMessage(request: TRequest): void {\n this.child.stdin.write(JSON.stringify(request) + '\\n');\n }\n public async terminate(): Promise<void> {\n if (this.child.exitCode === null && this.child.signalCode === null) this.child.kill('SIGKILL');\n await this.closed;\n }\n}\n\n/** One worker per grep invocation; a deadline or abort terminates it before the failure is exposed. */\nexport class IsolatedGrepSearch {\n private readonly worker: IGrepWorker = process.versions.bun\n ? new GrepProcessWorker()\n : new Worker(BOOTSTRAP, {\n eval: true,\n execArgv: [],\n resourceLimits: { maxOldGenerationSizeMb: 128, maxYoungGenerationSizeMb: 32 },\n });\n private readonly pending = new Map<\n number,\n { resolve: (matches: string[]) => void; reject: (error: Error) => void }\n >();\n private nextId = 0;\n private stopped = false;\n private termination?: Promise<void>;\n private readonly timer: ReturnType<typeof setTimeout>;\n private readonly abort = (): void => {\n void this.stop(new Error('Grep search cancelled'));\n };\n public constructor(\n private readonly pattern: string,\n private readonly signal?: AbortSignal,\n ) {\n this.worker.on('message', (message) => {\n const pending = this.pending.get(message.id);\n if (!pending || this.stopped) return;\n this.pending.delete(message.id);\n if (Array.isArray(message.matches) && message.matches.every((m) => typeof m === 'string'))\n pending.resolve(message.matches);\n else pending.reject(new Error(message.error ?? 'Invalid grep worker response'));\n });\n this.worker.on('error', () => {\n void this.stop(new Error('Grep search worker failed'));\n });\n this.worker.once('exit', () => {\n void this.stop(new Error('Grep search worker exited'));\n });\n this.timer = setTimeout(() => {\n void this.stop(new Error('Grep search timed out'));\n }, 2000);\n signal?.addEventListener('abort', this.abort, { once: true });\n if (signal?.aborted) this.abort();\n }\n public search(\n content: string,\n filePath: string,\n contextLines: number,\n outputMode: TMode,\n ): Promise<string[]> {\n if (this.stopped)\n return Promise.reject(\n new Error(this.signal?.aborted ? 'Grep search cancelled' : 'Grep search timed out'),\n );\n const id = this.nextId++;\n return new Promise<string[]>((resolve, reject) => {\n this.pending.set(id, { resolve, reject });\n try {\n this.worker.postMessage({\n id,\n content,\n filePath,\n pattern: this.pattern,\n contextLines,\n outputMode,\n });\n } catch {\n void this.stop(new Error('Grep search worker failed'));\n }\n });\n }\n public async stop(error?: Error): Promise<void> {\n if (this.termination) return this.termination;\n this.stopped = true;\n clearTimeout(this.timer);\n this.signal?.removeEventListener('abort', this.abort);\n this.termination = (async () => {\n try {\n await this.worker.terminate();\n } catch {\n /* process is already exiting */\n }\n for (const pending of this.pending.values())\n pending.reject(error ?? new Error('Grep search stopped'));\n this.pending.clear();\n })();\n return this.termination;\n }\n}\n","/**\n * GrepTool β recursive regex content search.\n *\n * Supports three output modes:\n * - files_with_matches (default): return only file paths that contain a match\n * - content: return matching lines with optional context lines\n * - count: return per-file match counts as \"path:count\" rows\n *\n * headLimit caps the number of result lines; excess is truncated with a marker.\n *\n * SEC-007: when a containment root is configured the search is confined to it. Grep is the most\n * disclosing of the file tools β `content` mode returns the matching LINES β so it must be contained\n * at least as strictly as `Read`, which it could otherwise stand in for.\n */\n\nimport { createReadStream } from 'node:fs';\nimport { stat } from 'node:fs/promises';\n\nimport { z } from 'zod';\nimport { ToolExecutionError } from '@robota-sdk/agent-core';\n\nimport { collectFiles } from './grep-search.js';\nimport { IsolatedGrepSearch } from './isolated-grep-search.js';\nimport { resolveSearchRoot } from './path-guard.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IContainedBuiltinToolOptions } from './tool-options.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { FunctionTool } from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\nconst GrepSchema = z.object({\n pattern: z.string().describe('The regular expression pattern to search for in file contents'),\n path: z\n .string()\n .optional()\n .describe('File or directory to search in. Defaults to the current working directory'),\n glob: z\n .string()\n .optional()\n .describe(\n 'Glob pattern to filter files (e.g. \"*.ts\", \"*.{ts,tsx}\"). Only files matching this pattern will be searched',\n ),\n contextLines: z\n .number()\n .optional()\n .describe(\n 'Number of context lines to show before and after each match. Only applies when outputMode is \"content\". Default: 0',\n ),\n outputMode: z\n .enum(['files_with_matches', 'content', 'count'])\n .optional()\n .describe(\n 'Output mode: \"files_with_matches\" shows only file paths (default), \"content\" shows matching lines with context, \"count\" shows per-file match counts',\n ),\n headLimit: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n 'Maximum number of result lines (file paths, content lines, or count rows) to return. Excess results are truncated with a marker line',\n ),\n});\n\ntype TGrepArgs = z.infer<typeof GrepSchema>;\n\n/** The matcher consumes one file at a time; keep only a few reads outstanding. */\nconst READ_CONCURRENCY_LIMIT = 8;\nconst MAX_GREP_FILE_BYTES = 4 * 1024 * 1024;\nconst READ_CHUNK_BYTES = 64 * 1024;\n\n/** A grep isolation failure is a hard tool failure, distinct from ordinary no-match/invalid-input results. */\nexport class GrepIsolationError extends ToolExecutionError {\n public constructor(public readonly reason: 'timeout' | 'cancelled' | 'limit' | 'failed') {\n super(\n `Grep search ${reason === 'timeout' ? 'timed out' : reason === 'cancelled' ? 'cancelled' : reason === 'limit' ? 'exceeded its byte limit' : 'worker failed'}`,\n 'Grep',\n );\n }\n}\n\nasync function grepFileTool(args: TGrepArgs, options: IGrepToolOptions): Promise<string> {\n const {\n pattern,\n path: searchPath,\n glob,\n contextLines = 0,\n outputMode = 'files_with_matches',\n headLimit,\n } = args;\n const containmentRoot = options.cwd;\n const { root: targetPath, error: rootError } = resolveSearchRoot(searchPath, containmentRoot);\n if (rootError) return rootError;\n\n try {\n new RegExp(pattern);\n } catch (err) {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Invalid regex pattern: ${pattern}`,\n };\n return JSON.stringify(result);\n }\n\n // Determine whether targetPath is a file or directory\n let targetStat: Awaited<ReturnType<typeof stat>>;\n try {\n targetStat = await stat(targetPath);\n } catch {\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Path not found: ${targetPath}`,\n };\n return JSON.stringify(result);\n }\n\n let files: string[];\n let filesTruncated = false;\n if (targetStat.isFile()) {\n files = [targetPath];\n } else {\n const collected = await collectFiles(targetPath, glob, containmentRoot);\n files = collected.files;\n filesTruncated = collected.truncated;\n }\n\n // A fixed number of readers prevents a directory's file count from creating\n // one promise per file. Result slots retain file-enumeration order (CLI-042).\n const search = new IsolatedGrepSearch(pattern, options.signal);\n const readAbort = new AbortController();\n const abortReads = (): void => readAbort.abort();\n options.signal?.addEventListener('abort', abortReads, { once: true });\n if (options.signal?.aborted) abortReads();\n let perFileMatches: string[][];\n try {\n if (readAbort.signal.aborted) throw new GrepIsolationError('cancelled');\n const orderedMatches = new Array<string[]>(files.length);\n let nextFile = 0;\n let failure: unknown;\n const readAndSearch = async (filePath: string): Promise<string[]> => {\n let content: string;\n try {\n const fileStat = await stat(filePath);\n if (fileStat.size > MAX_GREP_FILE_BYTES) throw new GrepIsolationError('limit');\n // A stream bounds each read and its signal can interrupt a pending read.\n // FileHandle.read has no AbortSignal, so it would weaken cancellation.\n const stream = createReadStream(filePath, {\n highWaterMark: READ_CHUNK_BYTES,\n signal: readAbort.signal,\n });\n const chunks: Buffer[] = [];\n let bytes = 0;\n try {\n for await (const chunk of stream) {\n if (readAbort.signal.aborted) throw new GrepIsolationError('cancelled');\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n bytes += buffer.length;\n if (bytes > MAX_GREP_FILE_BYTES) throw new GrepIsolationError('limit');\n chunks.push(buffer);\n }\n } finally {\n stream.destroy();\n }\n const buffer = Buffer.concat(chunks, bytes);\n // Skip binary files\n const checkLen = Math.min(buffer.length, 8192);\n let hasBinary = false;\n for (let i = 0; i < checkLen; i++) {\n if (buffer[i] === 0) {\n hasBinary = true;\n break;\n }\n }\n if (hasBinary) return [];\n content = buffer.toString('utf8');\n } catch (error) {\n if (error instanceof GrepIsolationError) throw error;\n if (readAbort.signal.aborted) throw new GrepIsolationError('cancelled');\n // allow-fallback: an unreadable file is skipped (pre-existing sequential\n // semantics β same as the old `continue`), not a logic fallback\n return [];\n }\n\n return search.search(content, filePath, contextLines, outputMode);\n };\n const worker = async (): Promise<void> => {\n while (failure === undefined && nextFile < files.length) {\n const index = nextFile++;\n try {\n orderedMatches[index] = await readAndSearch(files[index]);\n } catch (error) {\n if (failure === undefined) {\n failure = error;\n readAbort.abort();\n void search.stop(error instanceof Error ? error : new Error('Grep search failed'));\n }\n }\n }\n };\n await Promise.all(Array.from({ length: Math.min(READ_CONCURRENCY_LIMIT, files.length) }, worker));\n if (failure !== undefined) throw failure;\n perFileMatches = orderedMatches;\n } catch (error) {\n const message = error instanceof Error ? error.message : '';\n throw error instanceof GrepIsolationError\n ? error\n : new GrepIsolationError(\n message.includes('timed out')\n ? 'timeout'\n : message.includes('cancelled')\n ? 'cancelled'\n : message.includes('byte limit')\n ? 'limit'\n : 'failed',\n );\n } finally {\n options.signal?.removeEventListener('abort', abortReads);\n await search.stop();\n }\n\n let outputBytes = 0;\n for (const matches of perFileMatches)\n for (const match of matches) {\n outputBytes += Buffer.byteLength(match, 'utf8') + 1;\n if (outputBytes > 4 * 1024 * 1024) throw new GrepIsolationError('limit');\n }\n const allOutputLines: string[] = perFileMatches.flat();\n\n let outputLines = allOutputLines;\n if (headLimit !== undefined && outputLines.length > headLimit) {\n const truncatedCount = outputLines.length - headLimit;\n outputLines = [\n ...outputLines.slice(0, headLimit),\n `(+${truncatedCount} more results truncated by headLimit)`,\n ];\n }\n if (filesTruncated) {\n outputLines = [\n ...outputLines,\n `[File enumeration stopped early; the search tree has more files than this tool scans in one call. Results may be incomplete β narrow the path or glob.]`,\n ];\n }\n\n const result: IToolInvocationResult = {\n success: true,\n output: outputLines.length > 0 ? outputLines.join('\\n') : '(no matches)',\n };\n return JSON.stringify(result);\n}\n\n/** The registered name of the shell tool this package's default assembly ships (NEUT-002). */\nconst DEFAULT_SHELL_TOOL_NAME = 'Shell';\n\n/** Options for the grep tool factory: containment root + description seam + shell-tool reference. */\nexport interface IGrepToolOptions extends IContainedBuiltinToolOptions {\n /** Cancels the isolated regex search and waits for its worker to exit. */\n signal?: AbortSignal;\n /**\n * Registered name of the shell tool the default description references (default: `Shell`).\n * Ignored when `description` overrides the text.\n */\n shellToolName?: string;\n}\n\n/** Build the default description, referencing the actually-registered shell tool by name. */\nfunction buildGrepDescription(shellToolName: string): string {\n return `A powerful search tool built on regex matching.\\n\\nSupports full regex syntax (e.g., 'log.*Error', 'function\\\\\\\\s+\\\\\\\\w+'). Filter files with glob parameter (e.g., '*.js', '**/*.tsx').\\n\\nOutput modes: 'content' shows matching lines with context, 'files_with_matches' shows only file paths (default), 'count' shows per-file match counts.\\n\\nPrefer this tool over running grep or rg through the ${shellToolName} tool β it returns structured results directly.\\n\\nUse headLimit to control result size and save context space.`;\n}\n\n/**\n * Create a GrepTool instance β register with Robota agent tools registry.\n */\nexport function createGrepTool(options: IGrepToolOptions): FunctionTool {\n return createZodFunctionTool(\n 'Grep',\n options.description ?? buildGrepDescription(options.shellToolName ?? DEFAULT_SHELL_TOOL_NAME),\n GrepSchema,\n async (params) => {\n return grepFileTool(params, options);\n },\n );\n}\n","/**\n * WebFetchTool β fetch a URL and return its content as text.\n *\n * HTML is stripped to plain text for readability. Fetches through the shared egress boundary\n * (`fetchWithEgressPolicy`, #2026): loopback / private / link-local / metadata destinations are\n * refused, redirects are re-validated, and the response is capped while streaming.\n */\n\nimport { fetchWithEgressPolicy } from '@robota-sdk/agent-core/node';\nimport { z } from 'zod';\n\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IBuiltinToolDescriptionOptions } from './tool-options.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { FunctionTool } from '@robota-sdk/agent-core';\nimport type { IEgressDeps, IEgressPolicy } from '@robota-sdk/agent-core/node';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst MAX_RESPONSE_BYTES = 5_000_000; // 5 MB max download\n\nconst WebFetchSchema = z.object({\n url: z.string().describe('The URL to fetch'),\n headers: z.record(z.string()).optional().describe('Optional HTTP headers as key-value pairs'),\n});\n\ntype TWebFetchArgs = z.infer<typeof WebFetchSchema>;\n\n/** #2026: the egress policy this tool fetches under, and the deps a test injects (fetch, DNS lookup). */\nexport interface IWebFetchEgressOptions {\n policy?: IEgressPolicy;\n deps?: IEgressDeps;\n}\n\nexport interface IWebFetchToolOptions extends IBuiltinToolDescriptionOptions {\n egress?: IWebFetchEgressOptions;\n}\n\n/**\n * Remove every `<tag>β¦</tag>` element β the linear equivalent of `replace(/<tag[\\s\\S]*?<\\/tag>/gi, '')`.\n *\n * The regex form is quadratic: every `<tag` with no closing tag after it rescans to end of input, and the scan\n * then restarts at the next one. `htmlToText`'s input is a **response body from an arbitrary URL**, capped only\n * at {@link MAX_RESPONSE_BYTES} (5 MB) β 5 MB of `<script` would have taken minutes. Because the closing tag is\n * searched forward, its absence at one opener means no later opener can have one either, so the scan stops.\n *\n * Case folding is `[A-Z]`-only, not `toLowerCase()`: `toLowerCase()` can change a string's LENGTH (U+0130\n * lowercases to two code units), which would desynchronise the indices from the original text.\n */\nfunction stripElement(html: string, tag: string): string {\n const openTag = `<${tag}`;\n const closeTag = `</${tag}>`;\n const haystack = html.replace(/[A-Z]/g, (c) => c.toLowerCase());\n const parts: string[] = [];\n let cursor = 0;\n for (;;) {\n const open = haystack.indexOf(openTag, cursor);\n if (open < 0) break;\n const close = haystack.indexOf(closeTag, open + openTag.length);\n if (close < 0) break;\n parts.push(html.slice(cursor, open));\n cursor = close + closeTag.length;\n }\n parts.push(html.slice(cursor));\n return parts.join('');\n}\n\n/**\n * Replace every `<β¦>` tag with a space β the linear equivalent of `replace(/<[^>]+>/g, ' ')`.\n *\n * Same defect, same input: `[^>]+` cannot cross a `>`, so a `<` with no `>` after it consumed the rest of the\n * document and then backtracked over it, once per `<`. A page of 200 K `<` characters took 12.6 s; the 5 MB the\n * fetch allows would have taken hours. `close === open + 1` reproduces the regex's `+` (a tag body must be at\n * least one character), so a literal `<>` is left in the text exactly as before.\n */\nfunction stripTags(html: string): string {\n const parts: string[] = [];\n let cursor = 0;\n for (;;) {\n const open = html.indexOf('<', cursor);\n if (open < 0) break;\n const close = html.indexOf('>', open + 1);\n if (close < 0) break;\n if (close === open + 1) {\n parts.push(html.slice(cursor, open + 1));\n cursor = open + 1;\n continue;\n }\n parts.push(html.slice(cursor, open), ' ');\n cursor = close + 1;\n }\n parts.push(html.slice(cursor));\n return parts.join('');\n}\n\n/**\n * The character entities {@link htmlToText} decodes, and the single alternation that matches them.\n *\n * SEC-004 (`js/double-escaping`): decoding these by CHAINED `.replace()` calls with `&` first\n * decodes twice. `&lt;` β how a page encodes the literal text `<` so a browser DISPLAYS it β\n * became `<` after the `&` pass and then `<` after the `<` pass, so a page reading\n * `&lt;script&gt;` came back out of a tag-stripping converter as `<script>`. One pass over\n * one alternation decodes each entity exactly once and never rescans its own output, so the decoder\n * is the inverse of the encoder for every input rather than only for singly-encoded ones.\n */\nconst HTML_ENTITIES: Readonly<Record<string, string>> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '"': '\"',\n ''': \"'\",\n ' ': ' ',\n};\nconst HTML_ENTITY_PATTERN = /&(?:amp|lt|gt|quot|nbsp|#39);/g;\n\n/** Strip HTML tags and decode common entities to produce readable text. */\nfunction htmlToText(html: string): string {\n return stripTags(stripElement(stripElement(html, 'script'), 'style'))\n .replace(HTML_ENTITY_PATTERN, (entity) => HTML_ENTITIES[entity])\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nexport function classifyFetchError(err: unknown): string {\n if (!(err instanceof Error)) return String(err);\n\n if (err.name === 'AbortError') {\n return `Request timed out after ${DEFAULT_TIMEOUT_MS / 1000}s. The server did not respond in time.`;\n }\n\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOTFOUND' || code === 'EAI_AGAIN') {\n return `Network error: DNS resolution failed for this host. The URL may be incorrect or the host does not exist. Do not retry with the same URL.`;\n }\n if (code === 'ECONNREFUSED') {\n return `Network error: Connection refused. The server is not accepting connections at this address. Do not retry with the same URL.`;\n }\n if (code === 'ECONNRESET') {\n return `Network error: Connection was reset by the server. The server may be temporarily unavailable.`;\n }\n if (code === 'ETIMEDOUT') {\n return `Network error: Connection timed out. The server is not reachable within the expected time.`;\n }\n if (code === 'CERT_HAS_EXPIRED' || code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {\n return `Network error: SSL certificate error (${code}). The server's certificate is invalid. Do not retry with the same URL.`;\n }\n\n return `Network error: ${err.message} Check that the URL is correct and the server is reachable.`;\n}\n\nasync function runWebFetch(\n args: TWebFetchArgs,\n egress: IWebFetchEgressOptions,\n signal?: AbortSignal,\n): Promise<string> {\n const { url, headers } = args;\n\n try {\n new URL(url);\n } catch {\n // allow-fallback: URL parse failure is a structured tool result, not a thrown error\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `Invalid URL: \"${url}\". Fix the URL format before retrying.`,\n };\n return JSON.stringify(result);\n }\n\n try {\n // #2026: destination safety, redirect re-validation, the deadline (composed with the CORE-018\n // run-scoped signal) and the streaming byte cap all live in the shared egress boundary.\n const response = await fetchWithEgressPolicy(\n url,\n {\n headers: { 'User-Agent': 'Robota-CLI/3.0', ...(headers ?? {}) },\n signal,\n timeoutMs: DEFAULT_TIMEOUT_MS,\n maxResponseBytes: MAX_RESPONSE_BYTES,\n },\n egress.policy,\n egress.deps,\n );\n\n if (!response.ok) {\n const { rejection } = response;\n const error =\n rejection.reason === 'response_too_large'\n ? `Response too large (max ${MAX_RESPONSE_BYTES} bytes). Consider fetching a more specific URL or a paginated endpoint.`\n : `Blocked by egress policy: ${rejection.message} Do not retry with the same URL.`;\n const result: IToolInvocationResult = { success: false, output: '', error };\n return JSON.stringify(result);\n }\n\n if (response.status < 200 || response.status >= 300) {\n const retryHint =\n response.status >= 500\n ? ' The server is temporarily unavailable β retrying may help.'\n : ' Do not retry with the same URL.';\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: `HTTP ${response.status} ${response.statusText}.${retryHint}`,\n };\n return JSON.stringify(result);\n }\n\n const contentType = response.headers.get('content-type') ?? '';\n let text = new TextDecoder().decode(response.body);\n\n // Strip HTML if content-type indicates HTML\n if (contentType.includes('html')) {\n text = htmlToText(text);\n }\n\n const result: IToolInvocationResult = { success: true, output: text };\n return JSON.stringify(result);\n } catch (err) {\n // allow-fallback: fetch errors are structured tool results returned to the LLM, not thrown\n const result: IToolInvocationResult = {\n success: false,\n output: '',\n error: classifyFetchError(err),\n };\n return JSON.stringify(result);\n }\n}\n\nconst DEFAULT_WEB_FETCH_DESCRIPTION =\n 'Fetch a URL and return its content as text. HTML pages are converted to plain text.';\n\n/**\n * Create a WebFetchTool instance β register with Robota agent tools registry.\n */\nexport function createWebFetchTool(options: IWebFetchToolOptions = {}): FunctionTool {\n const egress = options.egress ?? {};\n return createZodFunctionTool(\n 'WebFetch',\n options.description ?? DEFAULT_WEB_FETCH_DESCRIPTION,\n WebFetchSchema,\n async (params, context) => runWebFetch(params, egress, context?.signal),\n );\n}\n\n/**\n * WebFetchTool instance β register with Robota agent tools registry.\n */\nexport const webFetchTool = createWebFetchTool();\n","/**\n * Brave Search adapter β the default `IWebSearchProvider` (NEUT-008).\n *\n * This file is the ONLY place the Brave endpoint and env-var wiring live; the tool layer\n * (`web-search-tool.ts`) composes over the vendor-free port. Reads `BRAVE_API_KEY` at call\n * time so the environment can be configured after process start.\n */\n\nimport type { IWebSearchProvider, IWebSearchResultItem } from './web-search-provider.js';\n\nconst BRAVE_SEARCH_ENDPOINT = 'https://api.search.brave.com/res/v1/web/search';\n\n/** Brave caps `count` at 20 per request. */\nconst BRAVE_MAX_COUNT = 20;\n\ninterface IBraveResult {\n title: string;\n url: string;\n description: string;\n}\n\ninterface IBraveResponse {\n web?: {\n results?: IBraveResult[];\n };\n}\n\n/**\n * Create the Brave Search provider. Throws from `search()` when `BRAVE_API_KEY` is not set or\n * the API responds with an error β the tool layer surfaces the message as a structured result.\n */\nexport function createBraveSearchProvider(): IWebSearchProvider {\n return {\n async search({ query, limit }, signal?: AbortSignal): Promise<IWebSearchResultItem[]> {\n const apiKey = process.env['BRAVE_API_KEY'];\n if (!apiKey) {\n throw new Error(\n 'Web search requires BRAVE_API_KEY environment variable for the default Brave Search provider, ' +\n 'or inject a custom search provider at the composition root.',\n );\n }\n\n const params = new URLSearchParams({\n q: query,\n count: String(Math.min(limit, BRAVE_MAX_COUNT)),\n });\n\n const response = await fetch(`${BRAVE_SEARCH_ENDPOINT}?${params}`, {\n headers: {\n Accept: 'application/json',\n 'Accept-Encoding': 'gzip',\n 'X-Subscription-Token': apiKey,\n },\n ...(signal ? { signal } : {}),\n });\n\n if (!response.ok) {\n throw new Error(`Brave Search API error: HTTP ${response.status} ${response.statusText}`);\n }\n\n const data = (await response.json()) as IBraveResponse;\n return (data.web?.results ?? []).map((r) => ({\n title: r.title,\n url: r.url,\n snippet: r.description,\n }));\n },\n };\n}\n","/**\n * WebSearchTool β search the web and return results.\n *\n * Vendor-free tool layer (NEUT-008): composes over the duck-typed `IWebSearchProvider` port.\n * The default provider is the vendor-specific default adapter wired at creation time; a custom\n * provider is injected via `createWebSearchTool({ provider })`. Provider failures (missing\n * configuration, HTTP/network errors) are thrown by the provider and surfaced here as\n * structured error results.\n */\n\nimport { z } from 'zod';\n\nimport { createBraveSearchProvider } from './brave-search-provider.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IBuiltinToolDescriptionOptions } from './tool-options.js';\nimport type { IWebSearchProvider, IWebSearchToolProviderOptions } from './web-search-provider.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { FunctionTool } from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\nconst DEFAULT_LIMIT = 10;\nconst DEFAULT_TIMEOUT_MS = 15_000;\n\nconst DEFAULT_WEB_SEARCH_DESCRIPTION =\n 'Search the web and return results with title, URL, and snippet.';\n\nconst WebSearchSchema = z.object({\n query: z.string().describe('The search query'),\n limit: z\n .number()\n .optional()\n .describe(`Maximum number of results to return (default: ${DEFAULT_LIMIT})`),\n});\n\ntype TWebSearchArgs = z.infer<typeof WebSearchSchema>;\n\nasync function runWebSearch(\n args: TWebSearchArgs,\n provider: IWebSearchProvider,\n signal?: AbortSignal,\n): Promise<string> {\n const { query, limit = DEFAULT_LIMIT } = args;\n\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);\n // CORE-018: run-scoped signal aborts the in-flight request alongside the timeout.\n const searchSignal = signal ? AbortSignal.any([controller.signal, signal]) : controller.signal;\n\n try {\n const results = await provider.search({ query, limit }, searchSignal);\n const result: IToolInvocationResult = {\n success: true,\n output: JSON.stringify(results, null, 2),\n };\n return JSON.stringify(result);\n } finally {\n clearTimeout(timeout);\n }\n } catch (err) {\n // allow-fallback: provider failures are structured tool results returned to the LLM, not thrown\n const message = err instanceof Error ? err.message : String(err);\n const result: IToolInvocationResult = { success: false, output: '', error: message };\n return JSON.stringify(result);\n }\n}\n\n/** Options for the web-search tool factory: description seam + provider port injection. */\nexport interface IWebSearchToolOptions\n extends IBuiltinToolDescriptionOptions, IWebSearchToolProviderOptions {}\n\n/**\n * Create a WebSearchTool instance β register with Robota agent tools registry.\n */\nexport function createWebSearchTool(options: IWebSearchToolOptions = {}): FunctionTool {\n const provider = options.provider ?? createBraveSearchProvider();\n return createZodFunctionTool(\n 'WebSearch',\n options.description ?? DEFAULT_WEB_SEARCH_DESCRIPTION,\n WebSearchSchema,\n async (params, context) => runWebSearch(params, provider, context?.signal),\n );\n}\n\n/**\n * WebSearchTool instance β register with Robota agent tools registry.\n */\nexport const webSearchTool = createWebSearchTool();\n","/**\n * AskUserQuestionTool β let the model ask the user structured questions mid-turn (CMD-005).\n *\n * Built on the CMD-004 ask seam: each question maps onto the `IActionRequest` SSOT and is issued\n * through the injected `IToolExecutionContext.ask` port; the attached environment renders it (Ink\n * dialog, web modal, programmatic pre-answer) and the answers return as the tool result.\n *\n * Contract points (spec CMD-005):\n * - 1β4 questions per call, asked sequentially (the channel's ask queue renders one at a time).\n * - Cancellation is data, not an exception: a dismissed question yields `{ cancelled: true }` and the\n * remaining unasked questions of the same call are marked cancelled too (no per-item re-prompt).\n * - No `context.ask` (headless/automation): returns `{ unavailable: true, reason }` β never a silent\n * guess, never a thrown error, so the model can continue autonomously.\n */\n\nimport { randomUUID } from 'node:crypto';\n\nimport { z } from 'zod';\n\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IBuiltinToolDescriptionOptions } from './tool-options.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type { FunctionTool, IActionRequest, IToolExecutionContext } from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\nconst MAX_QUESTIONS = 4;\n\nconst QuestionSchema = z.object({\n question: z.string().min(1).describe('The complete question to ask the user.'),\n header: z\n .string()\n .optional()\n .describe('Very short topic label for the question (e.g. \"Auth method\").'),\n options: z\n .array(\n // Models often write bare strings first (observed live) β accept both shapes, no retry needed.\n z.union([\n z.string().min(1).describe('Display text of this choice.'),\n z.object({\n label: z.string().min(1).describe('Display text of this choice.'),\n description: z.string().optional().describe('What choosing this option means.'),\n }),\n ]),\n )\n .optional()\n .describe('Predefined choices (strings or {label, description}). Omit for pure free text.'),\n multiSelect: z\n .boolean()\n .optional()\n .describe('Allow selecting multiple options (default: single select).'),\n allowFreeText: z\n .boolean()\n .optional()\n .describe('Allow a typed custom answer besides the options (default: true).'),\n});\n\nconst AskUserQuestionSchema = z.object({\n questions: z\n .array(QuestionSchema)\n .min(1)\n .max(MAX_QUESTIONS)\n .describe(`Questions to ask the user (1-${MAX_QUESTIONS}), rendered one at a time.`),\n});\n\ntype TQuestion = z.infer<typeof QuestionSchema>;\ntype TAskUserQuestionArgs = z.infer<typeof AskUserQuestionSchema>;\n\nconst ASK_USER_QUESTION_DESCRIPTION = [\n 'Ask the user one or more structured questions and wait for their answers.',\n '',\n 'Use this when you are blocked on a decision only the user can make β ambiguous requirements,',\n 'mutually exclusive approaches, or choices with real trade-offs. Do not use it for decisions with',\n 'a conventional default or facts you can verify yourself.',\n '',\n `Provide 1-${MAX_QUESTIONS} questions. Each question offers predefined options and/or free text:`,\n ' - options + default: user picks one option (or types a custom answer unless allowFreeText: false)',\n ' - multiSelect: true: user may pick several options',\n ' - no options: pure free-text entry',\n '',\n 'The result is a JSON array with one entry per question: the selected option labels in `values`',\n 'and/or the typed answer in `text`, or `cancelled: true` if the user dismissed the question.',\n 'If no interactive user is attached (headless run), the result is `{ unavailable: true }` β',\n 'continue autonomously with your best judgment and say what you assumed.',\n].join('\\n');\n\n/** Per-question outcome in the tool result. */\nexport type TAskUserQuestionAnswer =\n { question: string; values: string[]; text?: string } | { question: string; cancelled: true };\n\n/** The tool result payload (inside IToolInvocationResult.output). */\nexport type TAskUserQuestionOutput =\n { answers: TAskUserQuestionAnswer[] } | { unavailable: true; reason: string };\n\nfunction toActionRequest(question: TQuestion): IActionRequest {\n // Normalize both accepted option shapes (bare string | {label, description}) to one form.\n const options = (question.options ?? []).map((option) =>\n typeof option === 'string' ? { label: option } : option,\n );\n const multi = question.multiSelect === true && options.length > 1;\n return {\n id: `ask_${randomUUID()}`,\n title: question.question,\n ...(question.header !== undefined ? { description: question.header } : {}),\n ...(options.length > 0\n ? {\n options: options.map((o) => ({\n value: o.label,\n label: o.label,\n ...(o.description !== undefined ? { description: o.description } : {}),\n })),\n }\n : {}),\n minSelect: options.length > 0 ? 1 : 0,\n maxSelect: multi ? options.length : 1,\n // Free text is the reference-UX \"Other\" escape hatch; a question without options is free text.\n allowFreeText: question.allowFreeText !== false || options.length === 0,\n };\n}\n\nasync function askQuestions(\n args: TAskUserQuestionArgs,\n ask: NonNullable<IToolExecutionContext['ask']>,\n): Promise<TAskUserQuestionOutput> {\n const answers: TAskUserQuestionAnswer[] = [];\n let dismissed = false;\n for (const question of args.questions) {\n if (dismissed) {\n answers.push({ question: question.question, cancelled: true });\n continue;\n }\n const response = await ask(toActionRequest(question));\n if (response.type === 'cancelled') {\n dismissed = true;\n answers.push({ question: question.question, cancelled: true });\n continue;\n }\n answers.push({\n question: question.question,\n values: [...response.values],\n ...(response.text !== undefined ? { text: response.text } : {}),\n });\n }\n return { answers };\n}\n\n/**\n * Create an `AskUserQuestion` tool instance β register with the Robota agent tools registry.\n */\nexport function createAskUserQuestionTool(\n options: IBuiltinToolDescriptionOptions = {},\n): FunctionTool {\n return createZodFunctionTool(\n 'AskUserQuestion',\n options.description ?? ASK_USER_QUESTION_DESCRIPTION,\n AskUserQuestionSchema,\n async (params, context) => {\n const args = params;\n const ask = context?.ask;\n const output: TAskUserQuestionOutput = ask\n ? await askQuestions(args, ask)\n : { unavailable: true, reason: 'no interactive user attached' };\n const result: IToolInvocationResult = { success: true, output: JSON.stringify(output) };\n return JSON.stringify(result);\n },\n );\n}\n\n/** `AskUserQuestion` tool instance β register with the Robota agent tools registry. */\nexport const askUserQuestionTool = createAskUserQuestionTool();\n","/**\n * What a `ToolSearch` query matches, and in what order (CLI-1990 Β§ Solution 4).\n *\n * Pure functions over schemas, with no catalog and no tool-execution context, because the ranking is\n * the half worth testing on its own: given the same deferred set and the same query, the same tools\n * come back in the same order. The tool module beside this one owns the I/O β reading the catalog\n * port, loading what matched, shaping the result.\n *\n * The match surface is the reference's own: a tool's name, its description, and its parameters'\n * names and descriptions. An exact name is therefore a valid query, which is what lets a model that\n * already knows what it wants ask for it without a `names` argument.\n */\n\nimport type { IParameterSchema, IToolSchema } from '@robota-sdk/agent-core';\n\n/** Both vendors default a tool search to five results; so does this one. */\nexport const DEFAULT_TOOL_SEARCH_LIMIT = 5;\n\n/**\n * Where a query matched, lowest first β the primary sort key.\n *\n * A tool whose NAME the query names is a better answer than one that merely mentions it in a\n * parameter description, and saying so is what makes \"the top five\" meaningful once a catalog is\n * large enough for the limit to bite.\n */\nconst RANK_EXACT_NAME = 0;\nconst RANK_NAME = 1;\nconst RANK_DESCRIPTION = 2;\nconst RANK_PARAMETER = 3;\n/** Not a match at all β filtered out rather than ranked last. */\nconst RANK_NONE = Number.POSITIVE_INFINITY;\n\n/** Every parameter name and description in a schema, including nested nodes. */\nfunction collectParameterText(node: IParameterSchema, into: string[]): void {\n if (node.description !== undefined) into.push(node.description);\n for (const [name, child] of Object.entries(node.properties ?? {})) {\n into.push(name);\n collectParameterText(child, into);\n }\n if (node.items !== undefined) collectParameterText(node.items, into);\n for (const branch of node.anyOf ?? []) collectParameterText(branch, into);\n}\n\nfunction rankMatch(schema: IToolSchema, query: string): number {\n const name = schema.name.toLowerCase();\n if (name === query) return RANK_EXACT_NAME;\n if (name.includes(query)) return RANK_NAME;\n if (schema.description.toLowerCase().includes(query)) return RANK_DESCRIPTION;\n const parameterText: string[] = [];\n collectParameterText(schema.parameters, parameterText);\n if (parameterText.some((text) => text.toLowerCase().includes(query))) {\n return RANK_PARAMETER;\n }\n return RANK_NONE;\n}\n\n/**\n * The tools a query selects, best match first and capped at `limit`.\n *\n * Ordering is total and deterministic: rank first, then name, so two tools that matched the same way\n * never trade places between calls. An empty query string matches nothing rather than everything β\n * \"search for nothing\" is a question with an empty answer, not a request for the whole catalog.\n */\nexport function matchDeferredTools(\n schemas: readonly IToolSchema[],\n query: string,\n limit: number,\n): IToolSchema[] {\n const needle = query.trim().toLowerCase();\n if (needle.length === 0) return [];\n return schemas\n .map((schema) => ({ schema, rank: rankMatch(schema, needle) }))\n .filter((entry) => entry.rank !== RANK_NONE)\n .sort((a, b) => a.rank - b.rank || (a.schema.name < b.schema.name ? -1 : 1))\n .slice(0, limit)\n .map((entry) => entry.schema);\n}\n","/**\n * ToolSearch β the model-facing half of client-side tool deferral (CLI-1990 Β§ Solution 4).\n *\n * A tool that declares `deferLoading` is withheld from the request entirely while the tool-search\n * policy is engaged, so the model never sees its schema. This tool is how the model gets it back:\n * it searches the withheld catalog by query, or loads an exact list by name, and the runtime marks\n * the matches loaded β so the NEXT round's `tools` array carries their full definitions and they\n * stay callable for the rest of the session.\n *\n * Deliberately an ordinary function tool rather than a vendor block. Anthropic and OpenAI each ship\n * a server-side tool search, but neither reduces the request payload (the API needs every definition\n * to run the search), Gemini has no equivalent at all, and both vendors document a client-executed\n * search as the portable form. One shape therefore runs everywhere and saves both wire bytes and\n * context tokens.\n *\n * Two results are NOT errors, and the distinction is the contract:\n * - a query that matches nothing returns `{ loaded: [], unavailableSources: [] }` β a normal empty\n * answer, mirroring the vendor's own empty `tool_references` array;\n * - an unknown entry in `names` throws, naming the entry, and loads nothing β asking for a tool that\n * does not exist is a mistake to correct, not an empty search.\n *\n * `unavailableSources` is present and empty from day one. MCP-003 (the connection and capability\n * supervisor) fills it with servers that failed or need auth, so a model told \"nothing matched\" can\n * tell that apart from \"the server holding it is down\" β without a contract change here.\n */\n\nimport { TOOL_SEARCH_TOOL_NAME } from '@robota-sdk/agent-core';\nimport { z } from 'zod';\n\nimport { DEFAULT_TOOL_SEARCH_LIMIT, matchDeferredTools } from './tool-search-matching.js';\nimport { createZodFunctionTool } from '../implementations/function-tool';\n\nimport type { IBuiltinToolDescriptionOptions } from './tool-options.js';\nimport type { IToolInvocationResult } from '../types/tool-result.js';\nimport type {\n FunctionTool,\n IDeferredToolCatalog,\n IToolExecutionContext,\n IToolSchema,\n} from '@robota-sdk/agent-core';\n\n// CORE-030: defining a tool and telling the permission system what it does arrive together.\nimport '../tool-permission-profiles.js';\n\n/**\n * The registered name β agent-core's own constant, re-exported under this package's name so the\n * execution layer's unknown-tool remedy and this tool can never name two different things.\n */\nexport const TOOL_SEARCH_NAME = TOOL_SEARCH_TOOL_NAME;\n\nconst ToolSearchSchema = z.object({\n query: z\n .string()\n .optional()\n .describe(\n \"Text matched case-insensitively against each withheld tool's name, description, and its \" +\n \"parameters' names and descriptions. An exact tool name is a valid query.\",\n ),\n names: z\n .array(z.string().min(1))\n .optional()\n .describe(\n 'Exact tool names to load, skipping the search. An unknown name is an error naming it.',\n ),\n limit: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(`Maximum tools to load from a query match (default ${DEFAULT_TOOL_SEARCH_LIMIT}).`),\n});\n\ntype TToolSearchArgs = z.infer<typeof ToolSearchSchema>;\n\n/** What the model gets back: what is now callable, and what could not be consulted. */\nexport interface IToolSearchOutput {\n loaded: Array<{ name: string; description: string }>;\n unavailableSources: string[];\n}\n\nconst TOOL_SEARCH_DESCRIPTION = [\n 'Load tools whose definitions are withheld from your tool list, so you can call them.',\n '',\n 'Some tools are deferred: they exist and are callable, but their schemas are not sent to you until',\n 'you load them here. If a capability you need is not in your tool list, search for it before',\n 'concluding it is unavailable β and if a tool call fails as \"deferred and not yet loaded\", load it',\n 'with this tool and call it again.',\n '',\n ' - query: what you are trying to do (e.g. \"read a spreadsheet\", \"postgres\"). Matched against tool',\n ' names, descriptions, and parameter names and descriptions. An exact tool name works too.',\n ` - names: load exactly these tools, skipping the search. Unknown names are an error.`,\n ` - limit: how many matches to load (default ${DEFAULT_TOOL_SEARCH_LIMIT}).`,\n '',\n 'The result lists what is now loaded; those tools appear in your tool list from your next turn and',\n 'stay available. A query that matches nothing returns an empty list β that is a normal answer, not',\n 'a failure. `unavailableSources` names any tool source that could not be consulted.',\n].join('\\n');\n\n/**\n * The catalog the runtime injects, or a thrown wiring error.\n *\n * Its absence is not a runtime condition to degrade around: `ToolExecutionService` attaches this\n * port to every tool call it issues, so a missing one means this tool was invoked outside the\n * execution loop. Guessing an empty catalog there would report \"nothing matched\" for a search that\n * was never actually run.\n */\nfunction requireCatalog(context: IToolExecutionContext | undefined): IDeferredToolCatalog {\n const catalog = context?.deferredTools;\n if (!catalog) {\n throw new Error(\n `${TOOL_SEARCH_NAME} requires the deferred-tool catalog, which the execution runtime injects; ` +\n 'it was not present, so this tool was called outside the agent execution loop.',\n );\n }\n return catalog;\n}\n\n/** Which schemas this call loads: the exact `names`, else the query's ranked matches. */\nfunction selectTools(args: TToolSearchArgs, catalog: IDeferredToolCatalog): IToolSchema[] {\n if (args.names !== undefined) {\n // Loaded by name, not searched: an unknown entry throws from the catalog, naming it.\n return catalog.loadDeferredTools(args.names);\n }\n if (args.query === undefined) {\n throw new Error(\n `${TOOL_SEARCH_NAME} needs either \"query\" to search for tools or \"names\" to load exact ones.`,\n );\n }\n const matches = matchDeferredTools(\n catalog.listDeferredTools(),\n args.query,\n args.limit ?? DEFAULT_TOOL_SEARCH_LIMIT,\n );\n // An empty match loads nothing, and that is the answer β not an error and not the whole catalog.\n return catalog.loadDeferredTools(matches.map((schema) => schema.name));\n}\n\n/**\n * Create a `ToolSearch` tool instance β register it RESIDENT with the agent's tool registry.\n *\n * It must never itself be deferred: a search tool the model cannot see is a catalog with no way in,\n * which is the state the vendor's own \"at least one tool must stay resident\" invariant forbids.\n */\nexport function createToolSearchTool(options: IBuiltinToolDescriptionOptions = {}): FunctionTool {\n return createZodFunctionTool(\n TOOL_SEARCH_NAME,\n options.description ?? TOOL_SEARCH_DESCRIPTION,\n ToolSearchSchema,\n async (params, context) => {\n const loaded = selectTools(params, requireCatalog(context));\n const output: IToolSearchOutput = {\n loaded: loaded.map(({ name, description }) => ({ name, description })),\n unavailableSources: [],\n };\n const result: IToolInvocationResult = { success: true, output: JSON.stringify(output) };\n return JSON.stringify(result);\n },\n );\n}\n\n/** `ToolSearch` tool instance β register with the Robota agent tools registry. */\nexport const toolSearchTool = createToolSearchTool();\n"],"mappings":"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"}
|