basant307/AI_Governance_Project
048
1/**2 * @license3 * Copyright 2025 Qwen Team4 * SPDX-License-Identifier: Apache-2.05 */6 7/**8 * Normalize a raw `tools.disabled` settings array into the canonical9 * deduplicated list the agent / restart paths share.10 *11 * Boot path (`cli/src/config/config.ts`'s `disabledTools` array12 * construction) and MCP restart refresh path13 * (`cli/src/acp-integration/acpAgent.ts` post-`restartMcpServer`14 * settings refresh) must agree byte-for-byte on what counts as15 * "disabled" — without that agreement, `ToolRegistry.has(tool.name)`16 * exact-match check silently re-registers tools whose disabled-name17 * carries whitespace (e.g., `' Foo '` typed in settings.json by hand).18 *19 * Lifted from inline implementations so boot path and MCP restart20 * refresh path share a single implementation.21 *22 * Behavior contract:23 *24 * 1. Non-array `raw` (object / number / boolean / null / undefined)25 * → return `[]`.26 * 2. Non-string entries inside the array → skipped individually27 * (does NOT abort the whole list — e.g., `[42, 'Foo', null]` → `['Foo']`).28 * 3. Each string entry is `.trim()`-ed.29 * 4. Empty-after-trim entries (`''`, `' '`, `'\n'`, `'\t'`) → skipped.30 * 5. Duplicates de-duped, preserving first-occurrence order.31 * Downstream callers materialize the result to `Set<string>`32 * so order is only meaningful for diagnostic output today,33 * but this helper preserves it for any future order-sensitive34 * consumer.35 *36 * The helper does NOT case-fold (e.g., `'Foo'` vs `'foo'` remain37 * distinct) — Stage 1 tool names are case-sensitive throughout38 * `ToolRegistry`, so case-folding here would silently break tool39 * lookups elsewhere. Unicode normalization (`String.prototype.normalize`)40 * is similarly out of scope; if a user pastes a combining-form vs41 * precomposed-form variant they want collapsed, that's a separate42 * decision tracked under workspace settings UX.43 */44export function normalizeDisabledToolList(raw: unknown): string[] {45 if (!Array.isArray(raw)) return [];46 const out: string[] = [];47 const seen = new Set<string>();48 for (const entry of raw) {49 if (typeof entry !== 'string') continue;50 const trimmed = entry.trim();51 if (!trimmed || seen.has(trimmed)) continue;52 seen.add(trimmed);53 out.push(trimmed);54 }55 return out;56}57 