Skip to content

feat: add custom shell-command tools#711

Open
y0usaf wants to merge 1 commit intoPiebald-AI:mainfrom
y0usaf:feat/custom-tools-clean
Open

feat: add custom shell-command tools#711
y0usaf wants to merge 1 commit intoPiebald-AI:mainfrom
y0usaf:feat/custom-tools-clean

Conversation

@y0usaf
Copy link
Copy Markdown
Contributor

@y0usaf y0usaf commented Apr 30, 2026

Summary

  • add settings.customTools support for user-defined shell-command tools
  • inject custom tools into Claude Code's tool list with prompt/schema generation, validation, permission checks, result rendering, and shell execution
  • add Custom Tools UI for creating/editing tools plus README docs and config normalization
  • cover helper detection, injection strategies, generated runtime behavior, duplicate/built-in-name guards, regex-special parameter names, and config validation

Supersedes #648 with a clean branch rebased on current main and without the unrelated native/Nix changes.

Tests

  • bun run lint
  • bunx vitest run src/patches/customTools.test.ts src/tests/config.test.ts

Note: pnpm is not available in this environment. Full bun run test still hits existing Bun/Vitest mock interop failures in unrelated suites (systemPrompts.test.ts, modelCustomizationsToggle.test.ts).

Summary by CodeRabbit

  • New Features

    • Full custom tools system: create, edit, reorder, and run user-defined shell-command tools with parameter schemas, timeouts, working-dir and env overrides; integrated main-menu entry and UI views.
  • Validation & Config

    • Config/schema validation and normalization for custom tools, default settings include empty customTools, and invalid entries are dropped with warnings.
  • Documentation

    • README adds “Custom tools” section, usage, config/schema example, placeholder interpolation behavior, and shell-safety notes.
  • Tests

    • Comprehensive tests for validation, injection strategies, generated tool shape, and runtime execution/error mapping.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a "Custom tools" feature: new Settings types and default, config normalization, UI for listing/editing/reordering tools, bundle patch writer plus helper matchers to inject runtime tool definitions, and tests covering detection, injection, and runtime execution.

Changes

Cohort / File(s) Summary
Docs
README.md
Adds "Custom tools" documentation: TOC link, behavior (verbatim {{param}} interpolation), config example, schema, workflow, and shell-safety notes.
Types & Defaults
src/types.ts, src/defaultSettings.ts
Adds CustomToolParameter/CustomTool types, extends Settings.customTools, adds MainMenuItem.CUSTOM_TOOLS, and sets DEFAULT_SETTINGS.customTools = [].
Config Normalization
src/config.ts
Validates/normalizes settings.customTools: required fields, parameter shape/type checks, optional fields constraints, drops invalid entries with index-specific warnings.
Patch Writers & Helpers
src/patches/customTools.ts, src/patches/helpers.ts, src/patches/index.ts
Adds writeCustomTools(oldFile, customTools) to generate/inject buildTool({...}) tool definitions (prompt/schema, validation, template substitution, spawn with shell/cwd/env/timeout), collision/duplicate guards, two injection strategies; adds getCwdFuncName and findBuildToolFunc helpers and registers custom-tools patch (re-exports helpers).
UI
src/ui/components/CustomToolsView.tsx, src/ui/components/CustomToolEditView.tsx, src/ui/App.tsx, src/ui/components/MainMenu.tsx
Adds CustomToolsView and CustomToolEditView Ink components with keyboard create/edit/delete/reorder, parsing/validation for parameters/env, blocking validation on save, integrates menu and routing.
Tests
src/patches/customTools.test.ts
Adds extensive Vitest suite covering helper detection, both injection strategies, collision handling, emitted code shape, and runtime execution via spawn stubs (parameter validation, template interpolation, timeouts, spawn errors).

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as "CustomToolsView / Edit"
    participant Config as "Settings Normalizer"
    participant Patch as "writeCustomTools"
    participant Bundle as "Bundled Runtime"
    participant Shell as "Shell (spawn)"

    User->>UI: create/edit custom tool
    UI->>Config: update settings.customTools
    User->>Patch: run tweakcc --apply
    Patch->>Config: normalize & validate customTools
    Patch->>Bundle: detect buildTool & cwd helpers in bundle
    Patch->>Bundle: inject generated buildTool(...) code
    User->>Bundle: invoke custom tool at runtime
    Bundle->>Bundle: validate params & interpolate {{param}}
    Bundle->>Shell: spawn(command, { shell, timeout, env, cwd })
    Shell-->>Bundle: stdout / stderr / exitCode
    Bundle-->>User: display tool result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • bl-ue
  • georpar

Poem

🐰 I nibble on templates and tuck parameters tight,
I stitch commands that hop into the night.
I spawn a tiny shell and fetch stdout's light,
return exit codes, stderr, and results polite.
A rabbit's patch — injected neat and bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add custom shell-command tools' directly and concisely describes the main change: introduction of custom shell-command tools as a new feature.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/ui/components/CustomToolEditView.tsx`:
- Around line 239-242: The UI validation currently only checks for duplicate
names using duplicateName (iterating settings.customTools with toolIndex and
name) but doesn't block reserved built-in Claude tool names that
writeCustomTools rejects; update the validation in CustomToolEditView (where
duplicateName is computed and where the save/validation path around name exists)
to also check against the same reserved-name set used by writeCustomTools (e.g.,
the built-in names like "Bash", "Read", "Write") and mark the name invalid if it
matches any reserved value (case/whitespace-normalized), surfacing the error in
the same validation UI before allowing save or injection.
- Around line 276-342: The effect is causing an autosave loop because
updateSettings creates a new settings object (deep copy) so
settings.customTools[toolIndex] gets a new reference and the effect retriggers
via the tool dependency; remove tool from the dependency list and stop
persisting on every keystroke by validating inputs and only calling
updateSettings when the form is valid (e.g. validate
name/command/parsedParameters/parsedEnv and parsedTimeout) or on an explicit
save action (or after a debounce); locate the effect in CustomToolEditView.tsx
(the useEffect that reads tool, toolIndex and calls updateSettings) and change
it to trigger only on validated state changes or save events instead of every
input change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1bcaaa8d-8251-4610-8bfb-0af85a220788

📥 Commits

Reviewing files that changed from the base of the PR and between eb46694 and f6b672b.

📒 Files selected for processing (12)
  • README.md
  • src/config.ts
  • src/defaultSettings.ts
  • src/patches/customTools.test.ts
  • src/patches/customTools.ts
  • src/patches/helpers.ts
  • src/patches/index.ts
  • src/types.ts
  • src/ui/App.tsx
  • src/ui/components/CustomToolEditView.tsx
  • src/ui/components/CustomToolsView.tsx
  • src/ui/components/MainMenu.tsx

Comment thread src/ui/components/CustomToolEditView.tsx
Comment thread src/ui/components/CustomToolEditView.tsx Outdated
@bl-ue
Copy link
Copy Markdown
Member

bl-ue commented Apr 30, 2026

Hi @y0usaf, I'm sorry for neglecting the PRs; we're working on a Piebald release and afterwards we'll spend some time clearing the backlog here.

@y0usaf
Copy link
Copy Markdown
Contributor Author

y0usaf commented Apr 30, 2026

No worries, it's my bad for making messy PRs! Thanks for being patient with me.

@y0usaf y0usaf force-pushed the feat/custom-tools-clean branch from f6b672b to e36765d Compare April 30, 2026 16:07
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/patches/customTools.ts`:
- Around line 330-345: The checks in the customTools validation loop compare raw
tool.name values, allowing case/whitespace variants to slip past; normalize each
tool name (e.g., const normalized = tool.name.trim().toLowerCase()) before using
it for the BUILTIN_TOOL_NAMES.has check and for membership in seenToolNames,
store normalized names in seenToolNames, and keep using the original tool.name
only for user-facing messages; align this normalization with the same logic used
in CustomToolEditView.

In `@src/ui/components/CustomToolEditView.tsx`:
- Around line 541-561: The useInput callback references hasBlockingErrors before
it's initialized when tool is falsy; add an early guard at the top of the
callback (e.g. return early if !tool) so the handler doesn't access
hasBlockingErrors when the component returned early; update the useInput
callback (the function handling key events) to check tool (or otherwise ensure
hasBlockingErrors is defined) before evaluating !hasBlockingErrors and calling
persistTool/onBack so Escape does not cause a runtime error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 744c021d-f13b-4bfb-a03a-d83f14019f2e

📥 Commits

Reviewing files that changed from the base of the PR and between f6b672b and e36765d.

📒 Files selected for processing (12)
  • README.md
  • src/config.ts
  • src/defaultSettings.ts
  • src/patches/customTools.test.ts
  • src/patches/customTools.ts
  • src/patches/helpers.ts
  • src/patches/index.ts
  • src/types.ts
  • src/ui/App.tsx
  • src/ui/components/CustomToolEditView.tsx
  • src/ui/components/CustomToolsView.tsx
  • src/ui/components/MainMenu.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/ui/components/MainMenu.tsx
  • src/ui/App.tsx
  • src/patches/index.ts
  • README.md
  • src/defaultSettings.ts

Comment thread src/patches/customTools.ts
Comment thread src/ui/components/CustomToolEditView.tsx
@y0usaf y0usaf force-pushed the feat/custom-tools-clean branch from e36765d to 4b04e8b Compare April 30, 2026 19:26
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/config.ts (1)

170-304: ⚡ Quick win

Extract custom-tool validation into a shared helper.

This block now mirrors parseTimeoutInput, parseParametersInput, and parseEnvInput in src/ui/components/CustomToolEditView.tsx. Keeping two copies in sync is brittle; the editor can drift from config normalization and start saving tools that the loader later drops. Pull the custom-tool parser/validator into one shared module and reuse it in both paths.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/config.ts` around lines 170 - 304, The normalizeCustomTool function
duplicates validation logic already implemented in parseTimeoutInput,
parseParametersInput, and parseEnvInput inside CustomToolEditView.tsx; extract
the shared validation/parsing for a CustomTool into a new module (e.g.,
src/utils/customToolParser) and have normalizeCustomTool call that shared
parser, and update CustomToolEditView.tsx to import and reuse the same parser
instead of its local helpers; ensure the shared API validates name, description,
command, parameters schema (types/description/required), optional shell,
timeout, workingDir, env, and prompt and returns either a typed CustomTool or a
structured error/nullable result so both normalizeCustomTool and the editor
consume identical validation behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/patches/customTools.ts`:
- Around line 228-235: The checkPermissions implementation currently always
delegates to the Bash tool; update checkPermissions (in the same object that
implements call()) to select the permission checker based on the configured
shell used by call() — look up context.options.tools for a tool whose name
matches the runtime shell (e.g., "PowerShell" or "Pwsh" for PowerShell shells,
"Cmd" or "Command Prompt" for cmd, otherwise "Bash") and call that tool's
checkPermissions with the same args ({command: cmd, timeout: ...}); if no
matching built-in checker exists, return a conservative Promise.resolve response
(e.g., behavior: "deny" or "requireConfirmation"/passthrough per project
convention) rather than always approving via Bash to avoid mismatched parsing
rules.
- Around line 259-272: The async call implementation currently uses spawnSync
(reference: call and spawnSync) which blocks the event loop; change it to use a
non-blocking child process API (e.g., spawn or execFile) and return a Promise
that resolves when the child exits or errors. Replace the spawnSync invocation
and synchronous result handling with spawn/execFile, hook into 'exit'/'close'
and 'error' events and collect stdout/stderr (or use execFile with a callback)
so you can resolve with the same return shape {data:{stdout,stderr,exitCode}},
ensure timeout and cwd/env/stdio are applied appropriately, and preserve
trimming and exitCode fallback logic.
- Around line 163-174: The properties object should be created with a null
prototype to avoid prototype mutation for parameter names like "__proto__";
change the initialization of properties (used alongside required, iterating
tool.parameters) to use an object with no prototype and keep the rest of the
loop that assigns properties[paramName] and pushes to required unchanged so
JSON.stringify({ type: 'object', properties, required }) emits the "__proto__"
key correctly.

---

Nitpick comments:
In `@src/config.ts`:
- Around line 170-304: The normalizeCustomTool function duplicates validation
logic already implemented in parseTimeoutInput, parseParametersInput, and
parseEnvInput inside CustomToolEditView.tsx; extract the shared
validation/parsing for a CustomTool into a new module (e.g.,
src/utils/customToolParser) and have normalizeCustomTool call that shared
parser, and update CustomToolEditView.tsx to import and reuse the same parser
instead of its local helpers; ensure the shared API validates name, description,
command, parameters schema (types/description/required), optional shell,
timeout, workingDir, env, and prompt and returns either a typed CustomTool or a
structured error/nullable result so both normalizeCustomTool and the editor
consume identical validation behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a49a21b3-96dd-4339-a9e6-c67299b92fc4

📥 Commits

Reviewing files that changed from the base of the PR and between e36765d and 4b04e8b.

📒 Files selected for processing (12)
  • README.md
  • src/config.ts
  • src/defaultSettings.ts
  • src/patches/customTools.test.ts
  • src/patches/customTools.ts
  • src/patches/helpers.ts
  • src/patches/index.ts
  • src/types.ts
  • src/ui/App.tsx
  • src/ui/components/CustomToolEditView.tsx
  • src/ui/components/CustomToolsView.tsx
  • src/ui/components/MainMenu.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/defaultSettings.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/ui/components/MainMenu.tsx
  • src/ui/App.tsx
  • src/ui/components/CustomToolsView.tsx
  • README.md
  • src/patches/index.ts

Comment thread src/patches/customTools.ts Outdated
Comment thread src/patches/customTools.ts
Comment thread src/patches/customTools.ts Outdated
@y0usaf y0usaf force-pushed the feat/custom-tools-clean branch from 4b04e8b to 8f3e025 Compare April 30, 2026 19:59
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/ui/components/CustomToolsView.tsx (1)

166-181: 💤 Low value

Using array index as React key.

Using index as the key (line 170) is generally discouraged, but it's acceptable here since:

  1. The list is managed locally with explicit reordering handlers that update selectedIndex in sync
  2. Ink's CLI rendering doesn't involve animations where stale keys would cause visual glitches

Consider adding a unique id field to CustomTool in a future iteration if tools need stable identity across sessions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/components/CustomToolsView.tsx` around lines 166 - 181, The map in
CustomToolsView uses array index as the React key (key={index} in the
customTools.map loop), which can cause unstable identity when items are
reordered; change to a stable unique key by adding an id property to the
CustomTool objects and use tool.id as the key instead, updating any
creation/serialization code that constructs CustomTool to generate a stable id
(e.g., UUID) and ensuring reordering handlers that touch selectedIndex continue
to reference tools by id; references to locate changes: customTools,
selectedIndex, summarizeTool, truncate and the map render block.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/ui/components/CustomToolsView.tsx`:
- Around line 166-181: The map in CustomToolsView uses array index as the React
key (key={index} in the customTools.map loop), which can cause unstable identity
when items are reordered; change to a stable unique key by adding an id property
to the CustomTool objects and use tool.id as the key instead, updating any
creation/serialization code that constructs CustomTool to generate a stable id
(e.g., UUID) and ensuring reordering handlers that touch selectedIndex continue
to reference tools by id; references to locate changes: customTools,
selectedIndex, summarizeTool, truncate and the map render block.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0866d140-3de9-4a2a-b59b-c34e05c15a49

📥 Commits

Reviewing files that changed from the base of the PR and between 4b04e8b and 8f3e025.

📒 Files selected for processing (12)
  • README.md
  • src/config.ts
  • src/defaultSettings.ts
  • src/patches/customTools.test.ts
  • src/patches/customTools.ts
  • src/patches/helpers.ts
  • src/patches/index.ts
  • src/types.ts
  • src/ui/App.tsx
  • src/ui/components/CustomToolEditView.tsx
  • src/ui/components/CustomToolsView.tsx
  • src/ui/components/MainMenu.tsx
✅ Files skipped from review due to trivial changes (3)
  • src/ui/App.tsx
  • README.md
  • src/patches/customTools.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/ui/components/MainMenu.tsx
  • src/ui/components/CustomToolEditView.tsx
  • src/config.ts

@y0usaf y0usaf force-pushed the feat/custom-tools-clean branch from 8f3e025 to 0b30b0e Compare April 30, 2026 21:30
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/ui/components/CustomToolEditView.tsx (1)

62-107: ⚡ Quick win

Move the reserved-name list into shared validation code.

This list now has to stay in sync with BUILTIN_TOOL_NAMES in src/patches/customTools.ts. If they drift, the editor and patcher will disagree again about which names are valid.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/components/CustomToolEditView.tsx` around lines 62 - 107,
RESERVED_TOOL_NAMES (used in CustomToolEditView.tsx) must be factored out and
sourced from a single shared validation module so it stays in sync with
BUILTIN_TOOL_NAMES in src/patches/customTools.ts; create or use a shared file
(e.g., a new exported symbol in a validation/shared module) that exports the
canonical reserved/builtin names (or a single exported BUILTIN_TOOL_NAMES
array/set) and replace the local RESERVED_TOOL_NAMES definition in
CustomToolEditView.tsx with an import of that shared symbol, and update any
consumers to use the shared validator function/constant instead of their own
hardcoded list so both the editor (CustomToolEditView) and the patcher
(customTools.ts) use the same source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/config.ts`:
- Around line 364-374: The current normalization in readConfigFile leaves
built-in-name collisions and duplicate custom tool names that later cause
writeCustomTools to fail; update the normalization pipeline that uses
normalizeCustomTool and the handling of config.settings.customTools to
additionally reject entries whose name is in the reserved/built-in set or that
duplicate an earlier accepted custom tool name: compute or import the
reservedNames (built-in tool names), iterate config.settings.customTools calling
normalizeCustomTool(tool, index) but then drop any nulls and also drop tools
whose name is in reservedNames or alreadySeenNames (track seen names as you
accept them) so only unique, non-reserved CustomTool objects remain before
returning from readConfigFile.

---

Nitpick comments:
In `@src/ui/components/CustomToolEditView.tsx`:
- Around line 62-107: RESERVED_TOOL_NAMES (used in CustomToolEditView.tsx) must
be factored out and sourced from a single shared validation module so it stays
in sync with BUILTIN_TOOL_NAMES in src/patches/customTools.ts; create or use a
shared file (e.g., a new exported symbol in a validation/shared module) that
exports the canonical reserved/builtin names (or a single exported
BUILTIN_TOOL_NAMES array/set) and replace the local RESERVED_TOOL_NAMES
definition in CustomToolEditView.tsx with an import of that shared symbol, and
update any consumers to use the shared validator function/constant instead of
their own hardcoded list so both the editor (CustomToolEditView) and the patcher
(customTools.ts) use the same source of truth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 741eced8-9355-4c09-8bd8-28fe0e4e4d99

📥 Commits

Reviewing files that changed from the base of the PR and between 8f3e025 and 0b30b0e.

📒 Files selected for processing (12)
  • README.md
  • src/config.ts
  • src/defaultSettings.ts
  • src/patches/customTools.test.ts
  • src/patches/customTools.ts
  • src/patches/helpers.ts
  • src/patches/index.ts
  • src/types.ts
  • src/ui/App.tsx
  • src/ui/components/CustomToolEditView.tsx
  • src/ui/components/CustomToolsView.tsx
  • src/ui/components/MainMenu.tsx
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/ui/components/MainMenu.tsx
  • src/ui/App.tsx
  • src/ui/components/CustomToolsView.tsx

Comment thread src/config.ts
Comment on lines +364 to +374
// Validate each customTool entry — drop entries missing required fields.
if (!Array.isArray(config.settings.customTools)) {
console.warn(
'config: customTools must be an array; ignoring invalid value'
);
config.settings.customTools = [];
} else {
config.settings.customTools = config.settings.customTools
.map((tool, index) => normalizeCustomTool(tool, index))
.filter((tool): tool is CustomTool => tool !== null);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject reserved and duplicate tool names during normalization.

Manual or remote configs can still load names that writeCustomTools() rejects later. One built-in-name collision or duplicate currently survives readConfigFile(), then causes the entire custom-tools patch to fail at apply time instead of being filtered here with the other invalid entries.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/config.ts` around lines 364 - 374, The current normalization in
readConfigFile leaves built-in-name collisions and duplicate custom tool names
that later cause writeCustomTools to fail; update the normalization pipeline
that uses normalizeCustomTool and the handling of config.settings.customTools to
additionally reject entries whose name is in the reserved/built-in set or that
duplicate an earlier accepted custom tool name: compute or import the
reservedNames (built-in tool names), iterate config.settings.customTools calling
normalizeCustomTool(tool, index) but then drop any nulls and also drop tools
whose name is in reservedNames or alreadySeenNames (track seen names as you
accept them) so only unique, non-reserved CustomTool objects remain before
returning from readConfigFile.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants