Files
ironclaw/scripts
Illia Polosukhin 5fa60f66b1 feat: discover tool source in working directory during install (#2396)
* feat: discover tool source code in working directory during install

When `tool_install` can't find a tool in the registry, it now searches
common directories relative to the current working directory before
returning "not found":
- tools-src/<name>/
- tool-src/<name>/
- <name>/ (direct subdirectory)

Matches both hyphenated and underscored name variants, and strips/adds
`_tool`/`-tool` suffixes. A directory is only considered a match if it
contains a Cargo.toml.

This lets users say "install portfolio tool" when tool source is at
tool-src/portfolio/ without needing the explicit path.

* style: apply cargo fmt formatting

* fix(extensions): address PR #2396 review feedback

- Restrict local tool source discovery to WASM kinds only; skip non-WASM
  kind hints (McpServer, ChannelRelay, AcpAgent) that can't be built
  from a local Cargo source.
- Refactor candidate name generation to use HashSet, avoiding weird
  combos like `my_portfolio-tool` and `*_tool-tool` from the old suffix
  logic.
- Update NotFound error message to mention all 3 search patterns
  (tools-src/, tool-src/, direct subdir).
- Include source path in InstallResult.message so the user/LLM can
  verify provenance when a tool is installed from a local directory
  instead of the verified registry (confused-deputy mitigation).
- Change local-discovery log from info! to debug! per CLAUDE.md
  REPL/TUI logging rule.
- Extract install_from_local_source() helper and add caller-level
  tests per testing.md ("Test Through the Caller, Not Just the Helper")
  to cover kind defaulting, target_dir routing, and message annotation.

* fix(extensions): resolve wasm artifact via Cargo.toml crate name

Address follow-up review feedback on PR #2396:

1. Suffix-stripping name mismatch (HIGH): when `find_local_tool_source`
   matched a directory via suffix add/strip (e.g. input `portfolio_tool`
   -> dir `portfolio/`), `install_from_local_source` passed `None` for
   `crate_name`, so artifact lookup searched for `<name>.wasm` instead of
   the real `<crate>.wasm` and every suffix-matched install failed. Parse
   `Cargo.toml` from the discovered source and pass `[package].name` as
   `crate_name`.

2. Non-deterministic candidate ordering (MEDIUM): the `HashSet` of name
   variants gave non-deterministic iteration, so directory matches within
   one search dir could vary across runs. Replace with a priority-ordered
   `Vec` + `retain` dedup: canonical underscore form first, hyphen next,
   suffix-adjusted variants last.

Adds a caller-level regression test for the name-mismatch bug and a
determinism test covering the underscore-vs-hyphen ordering.

* style: apply cargo fmt

* fix(extensions): tighten local tool source discovery (PR #2396 review)

- find_local_tool_source_in: require Cargo.toml to be a regular file
  (is_file) rather than merely existing, so a directory named
  Cargo.toml cannot falsely qualify a candidate source directory.

- install_from_local_source: reject non-UTF-8 source paths with a
  clear InstallFailed error instead of silently lossy-converting
  them into a build-dir path that will not resolve.

Addresses Copilot review comments on nearai/ironclaw#2396.

* fix(extensions): drop dead -tool strip branch in local source discovery

`underscore_name` is built via `name.replace('-', "_")`, so the
`underscore_name.strip_suffix("-tool")` fallback can never match — it
was unreachable code. The single `_tool` strip already covers both
`name_tool` and `name-tool` inputs because hyphens are normalized first.

Added `find_local_tool_source_strips_hyphen_tool_suffix` to lock in
that the hyphenated suffix input still resolves to the unsuffixed dir.

Addresses Copilot review comment on nearai/ironclaw#2396.
2026-04-18 12:31:12 +09:00
..