= infra-tools == purpose Provides the concrete tool execution infrastructure: a sandboxed executor that wraps tool calls with file backup/restore, diff computation, and event emission; a dispatching executor that routes tool requests to registered tools; a default tool registry; a shell command tool; and a tool configuration system that maps config to enabled tool instances. == responsibilities * Wrap tool execution with sandbox directory management and file backup/restore * Compute unified diffs for file-affecting tool results * Emit `ToolExecutionStartedEvent`, `ToolExecutionCompletedEvent`, and `ToolExecutionFailedEvent` * Dispatch tool requests by name to registered tool implementations * Register tools by name via `DefaultToolRegistry` * Execute shell commands with timeout, stdout/stderr capture, and executable allowlisting * Convert `ToolConfig` to a list of `Tool` implementations via `buildTools()` == non-responsibilities * Does not define tool contracts — that belongs to `core:tools` * Does not implement filesystem tools — that belongs to `infra:tools:filesystem` * Does not enforce approval gating — that belongs to `core:approvals` * Does not perform workflow-level tool routing == key types === SandboxedToolExecutor * **kind**: class * **purpose**: Decorator around a `ToolExecutor` that handles per-invocation working directories, file backup/restore for file-affecting tools, diff computation, and event emission. Operates on `Dispatchers.IO`. * **fields**: `delegate` (inner executor), `registry`, `eventDispatcher`, `workDir` (default `/tmp/correx-sandbox`) === DispatchingToolExecutor * **kind**: class * **purpose**: Routes a `ToolRequest` to the appropriate `ToolExecutor` by resolving the tool name from a `ToolRegistry`. === DefaultToolRegistry * **kind**: class * **purpose**: Simple map-based `ToolRegistry` built from a vararg or list of `Tool` instances. Keyed by `tool.name`. === ShellTool * **kind**: class * **purpose**: Implements both `Tool` and `ToolExecutor` for shell command execution. Supports executable allowlisting, configurable timeout (default 30s), and working directory. Validates that `argv` is non-empty and the executable is allowed. Tier T2. * **fields**: `allowedExecutables`, `timeoutMs` (default 30000), `workingDir` === DiffUtil * **kind**: object * **purpose**: Computes unified-diff strings from old and new file contents using LCS-based edit detection. Used by `SandboxedToolExecutor` to record changes in tool receipts. === ToolConfig * **kind**: data class * **purpose**: Configuration structure for enabling and parameterizing tools. Contains sub-configs for shell, file_read, file_write, and file_edit tools. * **fields**: `shell`, `fileRead`, `fileWrite`, `fileEdit` === ToolConfig.buildTools() * **kind**: extension function * **purpose**: Converts a `ToolConfig` into a `List` by creating instances for each enabled sub-config. == event flow *Inbound:* `ToolRequest` (from core tools layer) *Outbound:* * `ToolExecutionStartedEvent` — emitted before delegate execution begins * `ToolExecutionCompletedEvent` — includes `ToolReceipt` with exit code, output, metadata, affected entities, duration, tier, and diff * `ToolExecutionFailedEvent` — emitted on execution failure == integration points * `core:events` — `ToolExecutionStartedEvent`, `ToolExecutionCompletedEvent`, `ToolExecutionFailedEvent`, `ToolReceipt`, `ToolRequest`, `ToolInvocationId`, `SessionId` * `core:tools` — `Tool`, `ToolExecutor`, `ToolResult`, `FileAffectingTool`, `ToolRegistry`, `ToolCapability`, `ValidationResult` * `core:approvals` — `Tier` * `infra:tools:filesystem` — `FileReadTool`, `FileWriteTool`, `FileEditTool` == invariants * `SandboxedToolExecutor` computes `affectedPaths` once (before delegate execution) to avoid double-invocation divergence * File backup is performed before delegate execution; on failure, originals are restored; on success, backups are deleted * `ShellTool` rejects executables not in the allowed set with `ValidationResult.Invalid` * All tools default to `enabled = false` in configuration == PlantUML diagram [plantuml, infra-tools, "png"] ---- include::../../diagrams/infra-tools.puml[] ---- == known issues * `SandboxedToolExecutor` cleanup (`cleanWorkingDir`, `restoreOrClean`) is best-effort and may leave files on IO errors * `FileEditTool.patch()` spawns an external `patch` process — not a pure-Kotlin implementation == open questions * Should `SandboxedToolExecutor` support configurable sandbox root resolution? * Should tool timeout be configurable per-tool-type rather than per-call?