ContractSearchHandler
`contract:search` — finds class, interface, and enum NAMES across the app's runtime roots and its installed vendor code, so an installed capability exists for the agent BEFORE it guesses an API. The debt this pays (measured on a live cattle run): installed packages existed for execution but not epistemologically — `artifact:contract` reached only the app's own plugins, so the agent deduced vendor APIs, planned probes, and weighed static-analysis errors as an introspection API. Search answers the question that comes before the contract: what is the right name to ask for. Candidates come from the app's declared PSR-4 roots and legacy plugin trees, from `vendor/composer/autoload_psr4.php` (prefixes mapped to directories, PHP files enumerated), and from `autoload_classmap.php` when present — an optimized classmap is never required. Matching is on file and declaration names, and kinds come from the token scanner: no candidate file is ever required or executed by searching it.
ContractSearchHandler::__construct()
public function __construct(Milpa\DevTools\Support\RootResolver $roots = new RootResolver()):Parameters
| Name | Type | Description |
|---|---|---|
| $roots | Milpa\DevTools\Support\RootResolver |
ContractSearchHandler::handle()
public function handle(array $input): arraySearches declared type names and returns up to 25 matches, each with its FQCN, kind, and provenance (`app`, or `vendor` plus the owning package). Each relative path identifies the scanned declaration and can be read with source:page for documentation. When names repeat, the first scanned declaration wins; this does not resolve the runtime autoloader's choice. No match is `ok:false` with a reason, never an exception.
Parameters
| Name | Type | Description |
|---|---|---|
| $input | array<string, mixed> |