Components were created by F4 per master-plan §3.7-§3.9 but never integrated:
the `*ToolCard.tsx` files use the legacy `ManualConfigModal` from
`@/shared/components` (barrel-export root), not the F4 versions in
`@/shared/components/cli`. The 3 files were sitting as dead code.
Removes:
- src/shared/components/cli/BaseUrlSelect.tsx
- src/shared/components/cli/ApiKeySelect.tsx
- src/shared/components/cli/ManualConfigModal.tsx
- tests/unit/ui/BaseUrlSelect.test.tsx
- tests/unit/ui/ApiKeySelect.test.tsx
- tests/unit/ui/ManualConfigModal.test.tsx
Updates `src/shared/components/cli/index.ts` to drop the dead exports.
Kept (actively used by page clients):
- CliToolCard, CliConceptCard, CliComparisonCard
Verified:
- typecheck:core + noimplicit:core clean
- npx eslint src/shared/components/cli/: 0 issues
- check:cycles: clean (212 files, -3 from removed components)
- 50/50 UI tests pass across the 3 kept components + 3 page clients
- 0 residual imports of the 3 removed symbols anywhere in src/ or tests/
Closes code review v3 gap #1 (dead code).
Pre-existing lint error from F8 commit 2d58519ca9 — the new react-hooks/set-state-in-effect rule conservatively flags any setState within useEffect body, even when setState happens async after Promise resolution. The "load remote data on mount" pattern is canonical until React 19 use()/Suspense migration.
Fix adds cancelled-flag pattern to prevent setState after unmount + block-disable with justification comment. Tests still pass 5/5.
Found during code review v2 deep audit — F10 audit reported "lint 0 errors" but only ran focused lint, not full project (which surfaces ~2985 pre-existing warnings + this 1 new error).
- tests/unit/custom-cli-config.test.ts: fix ERR_MODULE_NOT_FOUND — stale import path cli-tools → cli-code (regression from F8 git mv, missed by F10 audit because it only ran curated test subset).
- tests/unit/ui/CliAgentsPage.test.tsx: update vi.mock path to current cli-code location (was no-op mock pointing to deleted path).
- tests/unit/ui/CliToolCard.test.tsx: update URL strings /dashboard/cli-tools/claude → /dashboard/cli-code/claude (cosmetic alignment with new routes).
- src/app/(dashboard)/dashboard/cli-code/components/ToolDetailClient.tsx: remove dead case "cliproxyapi" + unused import (no entry in CLI_TOOLS catalog).
- src/app/(dashboard)/dashboard/cli-agents/CliAgentsPageClient.tsx: replace inline div skeleton with shared <CardSkeleton /> for visual consistency with CliCodePageClient.
- src/app/api/cli-tools/{forge,jcode,deepseek-tui,smelt,pi}-settings/route.ts: replace catch (err: any) with catch (err) + (err as NodeJS.ErrnoException).code narrowing (8 instances, eliminates 8 of 11 implicit-any introductions).
Validated: custom-cli-config.test.ts now 3/3 PASS (was 0/1 FAIL with ERR_MODULE_NOT_FOUND); F1/F3 tests 147/147 PASS; UI tests 25/25 PASS; typecheck:core + noimplicit clean.
- sidebarVisibility.ts: replace cli-tools with cli-code, add cli-agents, keep acp-agents order cli-code→cli-agents→acp-agents→cloud-agents in TOOLS_GROUP; update HIDEABLE_SIDEBAR_ITEM_IDS and DEVELOPER_SHOWN preset
- next.config.mjs: 4 permanent (308) redirects for /dashboard/cli-tools→/dashboard/cli-code and /dashboard/agents→/dashboard/acp-agents (with :path* wildcards)
- pt-BR.json + en.json: add cliCommon, cliCode, cliAgents, acpAgents namespaces (~140 keys each) + sidebar keys for the 3 new IDs
- request.ts: merge EN as namespace-level fallback so 39 non-EN/pt-BR locales display new namespaces in English until translations ship
- Header.tsx: update HEADER_DESCRIPTIONS map to use new HideableSidebarItemId values
- tests: 4 new unit test files (38 assertions), update sidebar-visibility.test.ts omni-proxy item order
Adds 5 new settings route handlers for CLIs introduced by plan 14 that
declare configType:"custom" and need automated config file persistence:
forge (~/.forge/config.toml), jcode (~/.jcode/config.json),
deepseek-tui (~/.config/deepseek-tui/config.toml),
smelt (~/.smelt/config.json), pi (~/.pi/config.json).
Also registers the 5 tools in cliRuntime.ts path table so
getCliPrimaryConfigPath() resolves their config paths correctly.
Each handler follows the established pattern: requireCliToolsAuth guard on
every exported method, Zod body validation on POST, buildErrorBody/
sanitizeErrorMessage on all error paths (Hard Rule #12), fs/promises only
(no exec/spawn — Hard Rule #13), saveCliToolLastConfigured on success.
Integration tests: 7 subtests per handler (401 without auth, 200 GET,
400 missing-baseUrl, 400 missing-model, 200 POST writes file, 200 DELETE,
error sanitization + no exec/spawn static audit).