adachsoft/directory-scanner-tool

Safe, configurable directory scanner tool for PHP and adachsoft/ai-tool-call integration

Installs: 1

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Forks: 0

pkg:composer/adachsoft/directory-scanner-tool

v0.1.0 2025-12-01 05:36 UTC

This package is not auto-updated.

Last update: 2025-12-02 02:48:22 UTC


README

Safe, configurable directory scanner tool for PHP projects, designed to integrate with the adachsoft/ai-tool-call library and AI agents (e.g. Google Gemini).

It exposes a single tool called directory_scanner that scans a configured base directory, applies exclusions and depth/entry limits, and returns a flat list of file system entries with optional metadata.

First public release is planned as v0.1.0. Version numbers are managed via Git tags / Packagist and follow Semantic Versioning.

Features

  • Safe scanning strictly confined to a configured basePath (no directory traversal above base path).
  • Support for excluded subpaths (e.g. vendor, var/cache, .git).
  • Configurable maximum recursion depth (maxAllowedDepth).
  • Configurable maximum number of returned entries (maxEntries) with truncation indication.
  • Optional inclusion of additional metadata for each entry:
    • file size (bytes),
    • last modification time (ISO 8601 string),
    • future‑ready fields for creation time and permissions.
  • Flat, predictable result structure (items + summary).
  • Ready‑to‑use SPI tool + factory for adachsoft/ai-tool-call.

Requirements

  • PHP 8.3 or higher
  • Composer

The library depends on the following AdachSoft packages at runtime:

  • adachsoft/ai-tool-call
  • adachsoft/filesystem
  • adachsoft/normalized-safe-path

These are installed automatically when you require this package.

Installation

composer require adachsoft/directory-scanner-tool

Concepts and architecture

The core pieces of this library are:

  • DirectoryScannerTool – SPI tool implementation (AdachSoft\AiToolCall\SPI\ToolInterface) that is discovered and executed by adachsoft/ai-tool-call.
  • DirectoryScannerToolFactory – factory used by AiToolCallFacadeBuilder to create configured tool instances based on a ConfigMap.
  • DirectoryScannerService / DirectoryScanRunner – services responsible for scanning the file system and collecting results.
  • PathNormalizationHelper – uses adachsoft/normalized-safe-path to ensure all paths stay inside the configured basePath.

You typically do not construct these objects manually. Instead, you plug the factory into AiToolCallFacadeBuilder and configure the tool using a ConfigMap.

Configuration

The directory scanner is configured by the host application (not by the AI agent) via DirectoryScannerToolFactory and ConfigMap.

Factory configuration (host application)

Example of wiring the tool with AiToolCallFacadeBuilder:

use AdachSoft\AiToolCall\PublicApi\Builder\AiToolCallFacadeBuilder;
use AdachSoft\AiToolCall\SPI\Collection\ConfigMap;
use AdachSoft\DirectoryScannerTool\DirectoryScannerToolFactory;

$factory = new DirectoryScannerToolFactory();

$facade = AiToolCallFacadeBuilder::new()
    ->withSpiFactories([$factory])
    ->withToolConfigs([
        'directory_scanner' => new ConfigMap([
            'basePath' => '/var/www/my-project',
            'excludedPaths' => ['vendor', 'var/cache', '.git'],
            'maxAllowedDepth' => 10,
            'maxEntries' => 5000,
            // Optional defaults for include_* flags when the agent does not specify them
            'defaultIncludeSize' => false,
            'defaultIncludeCreatedAt' => false,
            'defaultIncludeModifiedAt' => false,
            'defaultIncludePermissions' => false,
        ]),
    ])
    ->build();

Supported config keys

All config keys are passed as an array to ConfigMap for tool name directory_scanner:

  • basePath (string, required)

    • Absolute path that acts as the root of all scans.
    • All agent‑provided paths are resolved relative to this base path.
  • excludedPaths (string[]|optional)

    • List of relative paths (from basePath) that should be excluded from scanning.
    • Both the directory itself and all its descendants are excluded.
  • maxAllowedDepth (int, optional, default: 10)

    • Maximum recursion depth allowed by the host application.
    • The effective depth used for a given request is the minimum of this value and the request‑level max_depth parameter (see below).
  • maxEntries (int, optional, default: 5000)

    • Maximum number of entries that will be returned from a single scan.
    • If the limit is reached, scanning stops and summary.truncated_by_max_entries is set to true.
  • defaultIncludeSize (bool, optional, default: false)

  • defaultIncludeCreatedAt (bool, optional, default: false)
  • defaultIncludeModifiedAt (bool, optional, default: false)
  • defaultIncludePermissions (bool, optional, default: false)
    • Default values used when the agent omits corresponding request parameters.

Tool invocation (AI agent request)

Once the tool is registered, AI agents (or your own code) call it through the AdachSoft\AiToolCall\PublicApi\AiToolCallFacade.

Request parameters

The directory_scanner tool exposes the following parameters schema (as seen in DirectoryScannerTool::getDefinition()):

  • path (string, required)

    • Relative path to scan from basePath (e.g. ., src, src/Module).
    • . means "start from the base path itself".
  • recursive (bool, default: false)

    • Whether nested directories should be scanned recursively.
  • max_depth (int|null, default: null)

    • Maximum recursion depth relative to the starting directory.
    • 1 means "only direct children".
    • The actual maximum depth used is min(max_depth, config.maxAllowedDepth).
  • include_size (bool, default: false)

    • Whether to include file size in bytes (for files only).
  • include_created_at (bool, default: false)

    • Reserved for future use (creation time; currently may always be null depending on filesystem).
  • include_modified_at (bool, default: false)

    • Whether to include last modification time as an ISO 8601 string.
  • include_permissions (bool, default: false)

    • Reserved for future use (POSIX‑like permission string); may be null if unavailable.

Example: calling the tool via Public API

use AdachSoft\AiToolCall\PublicApi\Dto\ToolCallRequestDto as PublicToolCallRequestDto;

$request = new PublicToolCallRequestDto(
    toolName: 'directory_scanner',
    parameters: [
        'path' => '.',
        'recursive' => true,
        'max_depth' => 3,
        'include_size' => true,
        'include_modified_at' => true,
    ],
);

$result = $facade->callTool($request);

// $result->toolName === 'directory_scanner'
// $result->result is an array with keys 'items' and 'summary'

$items = $result->result['items'];
$summary = $result->result['summary'];

Response structure

The tool returns a structure containing two top‑level keys: items and summary.

items

items is a flat list of scan entries:

/**
 * @var array<int, array{
 *     path: string,
 *     name: string,
 *     is_file: bool,
 *     is_directory: bool,
 *     size: int|null,
 *     created_at: string|null,
 *     modified_at: string|null,
 *     permissions: string|null,
 * }> $items
 */
$items = $result->result['items'];
  • path – relative path from the configured basePath.
  • name – basename of the entry (file or directory name).
  • is_filetrue if the entry is a file.
  • is_directorytrue if the entry is a directory.
  • size – file size in bytes (only when include_size is true and the entry is a file).
  • created_at – creation time as ISO 8601 string (may be null).
  • modified_at – last modification time as ISO 8601 string (may be null if disabled).
  • permissions – POSIX‑style permissions string (may be null).

summary

summary contains metadata about the scan:

/**
 * @var array{
 *     base_path: string,
 *     requested_path: string,
 *     recursive: bool,
 *     requested_max_depth: int|null,
 *     effective_max_depth: int,
 *     actual_depth_reached: int,
 *     total_entries_found: int,
 *     returned_entries_count: int,
 *     truncated_by_max_entries: bool,
 * } $summary
 */
$summary = $result->result['summary'];
  • base_path – the configured base path used for scanning.
  • requested_path – the path value from the request.
  • recursive – whether recursive scanning was enabled for the request.
  • requested_max_depth – raw max_depth from the request (may be null).
  • effective_max_depth – actual recursion depth limit used after applying config constraints.
  • actual_depth_reached – deepest level reached during the scan.
  • total_entries_found – total number of entries encountered (before truncation).
  • returned_entries_count – number of entries actually returned in items.
  • truncated_by_max_entriestrue if scanning was stopped because maxEntries was reached.

Error handling

The tool uses exceptions from adachsoft/ai-tool-call and its own domain exceptions to signal problems:

  • InvalidToolCallException

    • Thrown when request parameters are invalid (e.g. wrong types, impossible options).
  • ToolExecutionException

    • Wraps domain and filesystem errors that occur during scanning.
    • The original cause is available as the previous exception and usually contains a DirectoryScannerToolException with a more detailed message.
  • DirectoryScannerDomainException

    • Used internally for invalid or unsafe path operations (e.g. attempts to escape basePath).

In typical adachsoft/ai-tool-call setups, these exceptions are translated into structured error responses returned to the AI agent.

Development

To work on the library locally, install dev dependencies and run the checks:

composer install

# Run test suite
vendor/bin/phpunit

# Run static analysis
vendor/bin/phpstan analyse

# Run coding standards fixer (dry run or fix)
PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --dry-run

Versioning

This library follows Semantic Versioning. The first public release is planned as v0.1.0 and will be published as a Git tag (and on Packagist). The composer.json file does not contain an explicit version field; Composer reads version information from VCS tags.

License

This library is open‑source software licensed under the MIT License. See the LICENSE file for full license text.

Author

  • Arkadiusz Adach