diff --git a/build.ts b/build.ts index 7b2169e0a..349a21e7e 100644 --- a/build.ts +++ b/build.ts @@ -118,7 +118,39 @@ const cliBun = join(outdir, 'cli-bun.js') const cliNode = join(outdir, 'cli-node.js') await writeFile(cliBun, '#!/usr/bin/env bun\nimport "./cli.js"\n') -await writeFile(cliNode, '#!/usr/bin/env node\nimport "./cli.js"\n') + +// Node.js entry needs a Bun API polyfill because Bun.build({ target: 'bun' }) +// emits globalThis.Bun references (e.g. Bun.$ shell tag in computer-use-input, +// Bun.which in chunk-ys6smqg9) that crash at import time under plain Node.js. +const NODE_BUN_POLYFILL = `#!/usr/bin/env node +// Bun API polyfill for Node.js runtime +if (typeof globalThis.Bun === "undefined") { + const { execFileSync } = await import("child_process"); + const { resolve, delimiter } = await import("path"); + const { accessSync, constants: { X_OK } } = await import("fs"); + function which(bin) { + const isWin = process.platform === "win32"; + const pathExt = isWin ? (process.env.PATHEXT || ".EXE").split(";") : [""]; + for (const dir of (process.env.PATH || "").split(delimiter)) { + for (const ext of pathExt) { + const candidate = resolve(dir, bin + ext); + try { accessSync(candidate, X_OK); return candidate; } catch {} + } + } + return null; + } + // Bun.$ is the shell template tag (e.g. $\`osascript ...\`). Only used by + // computer-use-input/darwin — stub it so the top-level destructuring + // \`var { $ } = globalThis.Bun\` doesn't crash. + function $(parts, ...args) { + throw new Error("Bun.$ shell API is not available in Node.js. Use Bun runtime for this feature."); + } + globalThis.Bun = { which, $ }; +} +import "./cli.js" +` +await writeFile(cliNode, NODE_BUN_POLYFILL) +// NOTE: when new Bun-specific globals appear in bundled output, add them here. // Make both executable const { chmodSync } = await import('fs') diff --git a/bun.lock b/bun.lock index 15bdb4caa..652e46baf 100644 --- a/bun.lock +++ b/bun.lock @@ -28,6 +28,9 @@ "@aws-sdk/credential-providers": "^3.1020.0", "@azure/identity": "^4.13.1", "@biomejs/biome": "^2.4.10", + "@claude-code-best/agent-tools": "workspace:*", + "@claude-code-best/builtin-tools": "workspace:*", + "@claude-code-best/mcp-client": "workspace:*", "@commander-js/extra-typings": "^14.0.0", "@growthbook/growthbook": "^1.6.5", "@langfuse/otel": "^5.1.0", @@ -176,10 +179,24 @@ "wrap-ansi": "^10.0.0", }, }, + "packages/agent-tools": { + "name": "@claude-code-best/agent-tools", + "version": "1.0.0", + "dependencies": { + "zod": "^3.25.0", + }, + }, "packages/audio-capture-napi": { "name": "audio-capture-napi", "version": "1.0.0", }, + "packages/builtin-tools": { + "name": "@claude-code-best/builtin-tools", + "version": "1.0.0", + "dependencies": { + "@claude-code-best/agent-tools": "workspace:*", + }, + }, "packages/color-diff-napi": { "name": "color-diff-napi", "version": "1.0.0", @@ -194,6 +211,18 @@ "sharp": "^0.33.5", }, }, + "packages/mcp-client": { + "name": "@claude-code-best/mcp-client", + "version": "1.0.0", + "dependencies": { + "@claude-code-best/agent-tools": "workspace:*", + "@modelcontextprotocol/sdk": "^1.29.0", + "lodash-es": "^4.17.21", + "lru-cache": "^10.0.0", + "p-map": "^4.0.0", + "zod": "^3.25.0", + }, + }, "packages/modifiers-napi": { "name": "modifiers-napi", "version": "1.0.0", @@ -410,6 +439,12 @@ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.11", "https://registry.npmmirror.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.11.tgz", { "os": "win32", "cpu": "x64" }, "sha512-A8D3JM/00C2KQgUV3oj8Ba15EHEYwebAGCy5Sf9GAjr5Y3+kJIYOiESoqRDeuRZueuMdCsbLZIUqmPhpYXJE9A=="], + "@claude-code-best/agent-tools": ["@claude-code-best/agent-tools@workspace:packages/agent-tools"], + + "@claude-code-best/builtin-tools": ["@claude-code-best/builtin-tools@workspace:packages/builtin-tools"], + + "@claude-code-best/mcp-client": ["@claude-code-best/mcp-client@workspace:packages/mcp-client"], + "@commander-js/extra-typings": ["@commander-js/extra-typings@14.0.0", "https://registry.npmmirror.com/@commander-js/extra-typings/-/extra-typings-14.0.0.tgz", { "peerDependencies": { "commander": "~14.0.0" } }, "sha512-hIn0ncNaJRLkZrxBIp5AsW/eXEHNKYQBh0aPdoUqNgD+Io3NIykQqpKFyKcuasZhicGaEZJX/JBSIkZ4e5x8Dg=="], "@emnapi/core": ["@emnapi/core@1.9.2", "https://registry.npmmirror.com/@emnapi/core/-/core-1.9.2.tgz", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="], @@ -1074,6 +1109,8 @@ "agent-base": ["agent-base@8.0.0", "https://registry.npmmirror.com/agent-base/-/agent-base-8.0.0.tgz", {}, "sha512-QT8i0hCz6C/KQ+KTAbSNwCHDGdmUJl2tp2ZpNlGSWCfhUNVbYG2WLE3MdZGBAgXPV4GAvjGMxo+C1hroyxmZEg=="], + "aggregate-error": ["aggregate-error@3.1.0", "https://registry.npmmirror.com/aggregate-error/-/aggregate-error-3.1.0.tgz", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], + "ajv": ["ajv@8.18.0", "https://registry.npmmirror.com/ajv/-/ajv-8.18.0.tgz", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], "ajv-formats": ["ajv-formats@3.0.1", "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-3.0.1.tgz", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], @@ -1160,6 +1197,8 @@ "cjs-module-lexer": ["cjs-module-lexer@2.2.0", "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", {}, "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ=="], + "clean-stack": ["clean-stack@2.2.0", "https://registry.npmmirror.com/clean-stack/-/clean-stack-2.2.0.tgz", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="], + "cli-boxes": ["cli-boxes@4.0.1", "https://registry.npmmirror.com/cli-boxes/-/cli-boxes-4.0.1.tgz", {}, "sha512-5IOn+jcCEHEraYolBPs/sT4BxYCe2nHg374OPiItB1O96KZFseS2gthU4twyYzeDcFew4DaUM/xwc5BQf08JJw=="], "cli-highlight": ["cli-highlight@2.1.11", "https://registry.npmmirror.com/cli-highlight/-/cli-highlight-2.1.11.tgz", { "dependencies": { "chalk": "^4.0.0", "highlight.js": "^10.7.1", "mz": "^2.4.0", "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", "yargs": "^16.0.0" }, "bin": { "highlight": "bin/highlight" } }, "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg=="], @@ -2142,6 +2181,14 @@ "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@claude-code-best/agent-tools/zod": ["zod@3.25.76", "https://registry.npmmirror.com/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@claude-code-best/mcp-client/lru-cache": ["lru-cache@10.4.3", "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "@claude-code-best/mcp-client/p-map": ["p-map@4.0.0", "https://registry.npmmirror.com/p-map/-/p-map-4.0.0.tgz", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="], + + "@claude-code-best/mcp-client/zod": ["zod@3.25.76", "https://registry.npmmirror.com/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@fastify/otel/@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.212.0", "https://registry.npmmirror.com/@opentelemetry/instrumentation/-/instrumentation-0.212.0.tgz", { "dependencies": { "@opentelemetry/api-logs": "0.212.0", "import-in-the-middle": "^2.0.6", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg=="], "@fastify/proxy-addr/ipaddr.js": ["ipaddr.js@2.3.0", "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.3.0.tgz", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="], @@ -2282,6 +2329,8 @@ "@typespec/ts-http-runtime/https-proxy-agent": ["https-proxy-agent@7.0.6", "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + "aggregate-error/indent-string": ["indent-string@4.0.0", "https://registry.npmmirror.com/indent-string/-/indent-string-4.0.0.tgz", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + "ansi-escapes/type-fest": ["type-fest@0.21.3", "https://registry.npmmirror.com/type-fest/-/type-fest-0.21.3.tgz", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], "chrome-mcp-shared/zod": ["zod@3.25.76", "https://registry.npmmirror.com/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], diff --git a/docs/extensibility/mcp-configuration.mdx b/docs/extensibility/mcp-configuration.mdx new file mode 100644 index 000000000..c696096f9 --- /dev/null +++ b/docs/extensibility/mcp-configuration.mdx @@ -0,0 +1,346 @@ +--- +title: "MCP 配置 - 多来源合并、作用域与策略管控" +description: "详细说明 Claude Code MCP 配置的来源层次、合并优先级、传输类型、企业策略管控、插件集成和保留名称机制。" +keywords: ["MCP", "配置", "settings.json", ".mcp.json", "企业策略", "插件"] +--- + +## 配置来源与作用域 + +Claude Code 的 MCP 配置来自多个来源,每个来源对应一个 `scope`(作用域)。配置按优先级合并,高优先级来源的同名配置覆盖低优先级。 + +### 来源列表 + +| 来源 | Scope | 文件/接口 | 说明 | +|------|-------|----------|------| +| 企业管控 | `enterprise` | 系统管理路径 `managed-mcp.json` | **排他模式**:存在时忽略所有其他来源 | +| 本地项目 | `local` | `/.claude/settings.local.json` | 项目级私有配置(不提交到 VCS) | +| 项目配置 | `project` | `/.mcp.json` | 项目级共享配置(可提交到 VCS) | +| 用户全局 | `user` | `~/.claude/settings.json` | 用户级配置,所有项目共享 | +| 插件 | `dynamic` | 插件 manifest 中 `.mcp.json` / `.mcpb` | 插件提供的 MCP 服务器 | +| claude.ai | `claudeai` | 通过 API 获取 | claude.ai 网页端配置的连接器 | +| 内置动态 | `dynamic` | 代码中注册 | Computer Use / Chrome 等内置服务器 | +| IDE SDK | `sdk` | IDE 传入 | VS Code / JetBrains 嵌入模式 | + +### 合并优先级(从低到高) + +``` +claude.ai 连接器 ← 最低优先级 + ↓ 去重 +插件服务器 + ↓ 去重 +用户全局配置 + ↓ +项目配置(.mcp.json) ← 需要用户审批 + ↓ +本地项目配置 + ↓ +动态配置(内置 MCP) ← 最高优先级 +``` + +`Object.assign({}, dedupedPluginServers, userServers, approvedProjectServers, localServers)` 实现合并——后出现的同名键覆盖前者。 + +## 企业管控模式 + +当 `managed-mcp.json` 文件存在时,进入 **排他模式**: + +```typescript +// config.ts:1084 +if (doesEnterpriseMcpConfigExist()) { + // 只返回企业配置,忽略所有用户/项目/插件/claude.ai 配置 + return { servers: filtered, errors: [] } +} +``` + +特性: +- 路径由系统管理决定(`getManagedFilePath()` + `managed-mcp.json`) +- 覆盖所有用户级、项目级、插件和 claude.ai 配置 +- 仍然应用策略过滤(allowlist/denylist) +- 无法通过 CLI 添加新服务器(`addMcpConfig` 会拒绝) + +## 传输类型与配置 Schema + +### stdio(默认) + +启动子进程,通过 stdin/stdout JSON-RPC 通信。 + +```json +{ + "my-server": { + "command": "npx", + "args": ["-y", "@my-org/mcp-server"], + "env": { "API_KEY": "..." } + } +} +``` + +`type` 字段可省略(默认为 `stdio`)。环境变量通过 `env` 传递给子进程,会与当前进程环境合并。 + +**Windows 注意**:使用 `npx` 需要包装为 `cmd /c npx`,否则会报错。 + +### SSE(Server-Sent Events) + +通过 HTTP SSE 连接远程 MCP 服务器。 + +```json +{ + "my-remote": { + "type": "sse", + "url": "https://mcp.example.com/sse", + "headers": { "Authorization": "Bearer ..." }, + "oauth": { + "clientId": "...", + "authServerMetadataUrl": "https://auth.example.com/.well-known/oauth-authorization-server" + } + } +} +``` + +支持 OAuth 认证流程。认证失败时进入 `needs-auth` 状态,15 分钟 TTL 缓存避免重复提示。 + +### HTTP(Streamable HTTP) + +HTTP 流式传输。 + +```json +{ + "my-http": { + "type": "http", + "url": "https://mcp.example.com/mcp", + "headers": { "X-API-Key": "..." } + } +} +``` + +支持与 SSE 相同的 OAuth 配置。 + +### WebSocket + +```json +{ + "my-ws": { + "type": "ws", + "url": "wss://mcp.example.com/ws" + } +} +``` + +### IDE 专用类型(内部) + +`sse-ide` 和 `ws-ide` 是 IDE 扩展专用类型,不由用户直接配置。 + +- `sse-ide`:使用 lockfile token 认证 +- `ws-ide`:使用 `X-Claude-Code-Ide-Authorization` header + +### SDK 类型(内部) + +`type: "sdk"` 由 IDE 嵌入模式传入,不经过保留名称检查和企业管控排他限制。 + +### claude.ai 代理类型(内部) + +`type: "claudeai-proxy"` 由 claude.ai 网页端配置的连接器使用,通过 OAuth bearer token 认证并支持 401 重试。 + +## 配置操作 + +### 添加 MCP 服务器 + +通过 CLI 命令 `claude mcp add` 或 API 调用 `addMcpConfig()`: + +```bash +# 添加到用户配置 +claude mcp add my-server -s user -- npx @my-org/mcp-server + +# 添加到项目配置 +claude mcp add my-server -s project -- npx @my-org/mcp-server + +# 添加 HTTP 类型 +claude mcp add my-remote -s user -t http -u https://mcp.example.com/mcp +``` + +添加时的验证流程: + +1. **名称校验**:只允许字母、数字、连字符和下划线 +2. **保留名检查**:`claude-in-chrome` 和 `computer-use` 被保留 +3. **企业管控检查**:企业模式下拒绝添加 +4. **Schema 验证**:Zod 校验配置格式 +5. **策略检查**:denylist 拒绝、allowlist 验证 + +### 移除 MCP 服务器 + +```bash +claude mcp remove my-server -s user +``` + +### 列出 MCP 服务器 + +```bash +claude mcp list +``` + +## 项目配置审批 + +`.mcp.json` 中的项目配置需要用户显式审批才能生效: + +```typescript +// config.ts:1166 +const approvedProjectServers: Record = {} +for (const [name, config] of Object.entries(projectServers)) { + if (getProjectMcpServerStatus(name) === 'approved') { + approvedProjectServers[name] = config + } +} +``` + +首次打开项目时,Claude Code 会提示用户审批 `.mcp.json` 中的每个服务器。审批状态持久化在本地配置中。 + +## 插件 MCP 集成 + +插件通过 manifest 中的 `.mcp.json` 或 `.mcpb` 文件声明 MCP 服务器: + +```typescript +// 插件 MCP 加载流程 +const pluginResult = await loadAllPluginsCacheOnly() +const pluginServerResults = await Promise.all( + pluginResult.enabled.map(plugin => getPluginMcpServers(plugin, mcpErrors)) +) +``` + +### 插件命名空间 + +插件 MCP 服务器名格式为 `plugin::`,不会与手动配置的名称冲突。 + +### 去重机制 + +插件服务器通过内容签名去重(`dedupPluginMcpServers`): + +- **stdio 类型**:签名 = `stdio:` + JSON.stringify([command, ...args]) +- **URL 类型**:签名 = `url:` + 原始 URL(unwrap CCR proxy URL) +- **sdk 类型**:签名为 null,不去重 + +去重规则: +1. 手动配置优先于插件配置 +2. 先加载的插件优先于后加载的 +3. 被抑制的插件服务器在 `/plugin` UI 中显示提示 + +### claude.ai 连接器去重 + +claude.ai 连接器使用相同的内容签名机制去重(`dedupClaudeAiMcpServers`): +- 仅启用的手动配置参与去重(禁用的手动配置不应抑制连接器) +- 连接器名格式为 `claude.ai ` + +## 策略管控 + +### Allowlist / Denylist + +企业策略通过 allowlist 和 denylist 控制可用的 MCP 服务器: + +```typescript +// config.ts:1243 - 最终策略过滤 +for (const [name, serverConfig] of Object.entries(configs)) { + if (!isMcpServerAllowedByPolicy(name, serverConfig)) { + continue // 跳过策略禁止的服务器 + } + filtered[name] = serverConfig +} +``` + +策略检查考虑: +- 服务器名称匹配 +- stdio 类型的 command + args 匹配 +- URL 类型的 URL 模式匹配(支持通配符) + +### 插件专用模式 + +`isRestrictedToPluginOnly('mcp')` 启用时,只允许插件提供的 MCP 服务器——用户/项目级配置被忽略。 + +## 环境变量展开 + +MCP 配置中的环境变量支持 `$VAR` 和 `${VAR}` 语法展开: + +```json +{ + "my-server": { + "command": "npx", + "args": ["@my-org/mcp-server"], + "env": { + "API_KEY": "$MY_API_KEY", + "DB_URL": "${DATABASE_URL}" + } + } +} +``` + +展开时缺失的变量会生成警告信息,但不阻止配置加载。 + +## 内置 MCP 动态注册 + +内置 MCP 服务器在 `main.tsx` 启动流程中动态注入配置: + +### Computer Use MCP + +```typescript +// src/utils/computerUse/setup.ts +export function setupComputerUseMCP(): { + mcpConfig: Record + allowedTools: string[] +} { + return { + mcpConfig: { + "computer-use": { + type: "stdio", + command: process.execPath, + args: ["--computer-use-mcp"], + scope: "dynamic", + } + }, + allowedTools: ["mcp__computer-use__screenshot", ...] + } +} +``` + +启用条件: +- Feature flag `CHICAGO_MCP` 开启 +- `getPlatform() !== "unknown"`(macOS/Windows/Linux) +- 非非交互式会话 +- GrowthBook gate `getChicagoEnabled()` 返回 true + +### Claude in Chrome MCP + +```typescript +// 类似 Computer Use,在 main.tsx 中注册 +const { mcpConfig, allowedTools, systemPrompt } = setupClaudeInChrome() +dynamicMcpConfig = { ...dynamicMcpConfig, ...mcpConfig } +``` + +启用条件: +- `--chrome` 参数或 `claudeInChromeDefaultEnabled` 配置 +- Chrome 扩展已安装 + +### VSCode SDK MCP + +IDE 嵌入模式通过初始化消息传入 `type:'sdk'` 的配置,由 `setupVscodeSdkMcp()` 设置双向通知。 + +## 保留名称 + +以下 MCP 服务器名称被保留,用户无法手动配置同名服务器: + +| 名称 | 用途 | 检查条件 | +|------|------|---------| +| `claude-in-chrome` | Chrome 浏览器控制 | 始终检查 | +| `computer-use` | 桌面自动化 | `CHICAGO_MCP` feature flag 开启时检查 | +| `claude-vscode` | VSCode IDE 集成 | 由 SDK 传入,不经过名称检查 | + +保留名检查在两个位置: +1. `addMcpConfig()`(`config.ts:636-648`)— 运行时拒绝 +2. `main.tsx` 启动检查(`main.tsx:2351-2368`)— 启动时退出 + +## 关键源文件索引 + +| 文件 | 职责 | +|------|------| +| `src/services/mcp/config.ts` | 配置管理核心:合并、去重、策略、添加/删除 | +| `src/services/mcp/types.ts` | Zod Schema 定义、类型声明 | +| `src/services/mcp/client.ts` | 连接管理、传输层选择 | +| `src/utils/plugins/mcpPluginIntegration.ts` | 插件 MCP 配置加载 | +| `src/utils/computerUse/setup.ts` | Computer Use 动态注册 | +| `src/utils/claudeInChrome/common.ts` | Chrome MCP 保留名与工具名 | +| `src/services/mcp/vscodeSdkMcp.ts` | VSCode SDK 双向通知 | diff --git a/docs/extensibility/mcp-protocol.mdx b/docs/extensibility/mcp-protocol.mdx index 2b8d26719..cbf106463 100644 --- a/docs/extensibility/mcp-protocol.mdx +++ b/docs/extensibility/mcp-protocol.mdx @@ -1,25 +1,32 @@ --- title: "MCP 协议 - 连接管理、工具发现与执行链路" -description: "从源码角度解析 Claude Code 的 MCP 集成:7 种传输层实现、connectToServer 的 memoize 缓存、工具发现的 LRU 策略、认证状态机、以及 MCP 工具如何进入权限检查链路。" -keywords: ["MCP", "Model Context Protocol", "工具扩展", "MCP 客户端", "工具发现"] +description: "从源码角度解析 Claude Code 的 MCP 集成:内置 MCP 与外部 MCP 的区别、7 种传输层实现、connectToServer 的 memoize 缓存、工具发现的 LRU 策略、认证状态机、以及 MCP 工具如何进入权限检查链路。" +keywords: ["MCP", "Model Context Protocol", "工具扩展", "MCP 客户端", "工具发现", "内置 MCP", "外部 MCP"] --- -{/* 本章目标:从源码角度揭示 MCP 客户端的连接管理、工具发现协议和执行链路 */} +{/* 本章目标:从源码角度揭示 MCP 客户端的两种运行模式(内置/外部)、连接管理、工具发现协议和执行链路 */} ## 架构总览:从配置到可用工具 ``` -settings.json: { mcpServers: { "my-db": { command: "npx", args: [...] } } } +配置层(多来源合并) + ├── settings.json: { mcpServers: { "my-db": { command: "npx", args: [...] } } } ← 外部 + ├── .mcp.json: 项目级 MCP 配置 ← 外部 + ├── 插件 manifest (.mcp.json / .mcpb) ← 外部(插件) + ├── claude.ai connectors ← 外部(远程) + ├── enterprise managed-mcp.json ← 外部(企业管控) + ├── setupComputerUseMCP() / setupClaudeInChrome() ← 内置(动态注册) + └── SDK 传入 (type:'sdk') ← 内置(IDE 嵌入) ↓ -getAllMcpConfigs() ← enterprise 独占或合并 user/project/local + plugin + claude.ai +getAllMcpConfigs() ← enterprise 独占 或 合并 user/project/local + plugin + claude.ai ↓ useManageMCPConnections() ← React Hook 管理连接生命周期 ↓ connectToServer(name, config) ← memoize 缓存(lodash memoize) - ├── 创建 Transport(stdio/sse/http/...) - ├── new Client() ← @modelcontextprotocol/sdk - ├── client.connect(transport) ← 超时控制(MCP_TIMEOUT, 默认 30s) - └── 返回 MCPServerConnection ← { connected | failed | needs-auth | pending } + ├── 判断:内置 MCP → InProcessTransport(同进程) + ├── 判断:外部 stdio → StdioClientTransport(子进程) + ├── 判断:远程 SSE/HTTP/WS → 网络传输 + └── 返回 MCPServerConnection ← { connected | failed | needs-auth | pending | disabled } ↓ fetchToolsForClient(client) ← LRU(20) 缓存 ├── client.request({ method: 'tools/list' }) @@ -30,19 +37,208 @@ assembleToolPool() ← 合并内置工具 + MCP 工具 工具名格式: mcp____ ← buildMcpToolName() ``` +## 两种 MCP 模式:内置 vs 外部 + +Claude Code 的 MCP 实现区分 **内置 MCP 服务器** 和 **外部 MCP 服务器**。两者使用相同的客户端协议和工具发现机制,但在连接方式、生命周期管理和配置来源上完全不同。 + +### 内置 MCP 服务器 + +内置 MCP 服务器由 Claude Code 自身提供,无需用户手动配置。它们在启动时自动注册为 `dynamic` scope 的配置,并在同进程内运行。 + +| 服务器 | 名称 | 包路径 | Feature Flag | 启用方式 | +|--------|------|--------|-------------|---------| +| Computer Use | `computer-use` | `@ant/computer-use-mcp` | `CHICAGO_MCP` | GrowthBook gate + macOS + interactive | +| Claude in Chrome | `claude-in-chrome` | `@ant/claude-for-chrome-mcp` | — | `--chrome` 参数或 `claudeInChromeDefaultEnabled` 配置 | +| VSCode SDK | `claude-vscode` | — | — | IDE 嵌入模式 (type:`sdk`) | + +#### InProcessTransport:零开销同进程通信 + +内置服务器通过 `InProcessTransport`(`src/services/mcp/InProcessTransport.ts`)运行,**不启动子进程**: + +```typescript +// 创建一对 linked transport —— 消息在两端之间直接传递 +const [clientTransport, serverTransport] = createLinkedTransportPair() + +// server 端连接到 serverTransport +inProcessServer = createComputerUseMcpServerForCli() +await inProcessServer.connect(serverTransport) + +// client 端使用 clientTransport(与外部 MCP 的 Client 相同接口) +transport = clientTransport +``` + +`InProcessTransport` 的核心设计: +- `send()` 通过 `queueMicrotask()` 异步投递消息到对端,避免同步请求/响应的栈深度问题 +- `close()` 双向关闭,任一端关闭都会触发两端的 `onclose` 回调 +- 无网络开销、无 IPC 序列化、无进程启动时间 + +#### 动态注册流程 + +内置服务器在 `main.tsx` 的启动流程中注册,注入 `dynamicMcpConfig`: + +```typescript +// main.tsx: Computer Use MCP 动态注册 +if (feature("CHICAGO_MCP") && getPlatform() !== "unknown" && !getIsNonInteractiveSession()) { + const { getChicagoEnabled } = await import("src/utils/computerUse/gates.js") + if (getChicagoEnabled()) { + const { setupComputerUseMCP } = await import("src/utils/computerUse/setup.js") + const { mcpConfig, allowedTools } = setupComputerUseMCP() + dynamicMcpConfig = { ...dynamicMcpConfig, ...mcpConfig } + allowedTools.push(...cuTools) + } +} +``` + +`setupComputerUseMCP()` 返回的配置(`src/utils/computerUse/setup.ts`): + +```typescript +{ + "computer-use": { + type: "stdio", // 类型标记为 stdio(但 client.ts 会拦截为 InProcessTransport) + command: process.execPath, + args: ["--computer-use-mcp"], + scope: "dynamic", // 动态作用域,不持久化 + } +} +``` + +#### 连接时拦截 + +`connectToServer()` 在 `client.ts:906-944` 中根据服务器名拦截内置服务器: + +```typescript +// Chrome MCP — 在 process 内运行,避免 ~325MB 子进程 +if (isClaudeInChromeMCPServer(name)) { + const { createChromeContext } = await import('../../utils/claudeInChrome/mcpServer.js') + const { createClaudeForChromeMcpServer } = await import('@ant/claude-for-chrome-mcp') + const { createLinkedTransportPair } = await import('./InProcessTransport.js') + const context = createChromeContext(config.env) + inProcessServer = createClaudeForChromeMcpServer(context) + const [clientTransport, serverTransport] = createLinkedTransportPair() + await inProcessServer.connect(serverTransport) + transport = clientTransport +} + +// Computer Use MCP — 同理 +if (feature('CHICAGO_MCP') && isComputerUseMCPServer(name)) { + const { createComputerUseMcpServerForCli } = await import('../../utils/computerUse/mcpServer.js') + const { createLinkedTransportPair } = await import('./InProcessTransport.js') + inProcessServer = await createComputerUseMcpServerForCli() + const [clientTransport, serverTransport] = createLinkedTransportPair() + await inProcessServer.connect(serverTransport) + transport = clientTransport +} +``` + +#### 保留名称保护 + +内置服务器的名称被保留,用户无法手动添加同名配置(`config.ts:636-648`): + +```typescript +// 添加 MCP 配置时检查保留名 +if (isClaudeInChromeMCPServer(name)) { + throw new Error(`Cannot add MCP server "${name}": this name is reserved.`) +} +if (feature('CHICAGO_MCP') && isComputerUseMCPServer(name)) { + throw new Error(`Cannot add MCP server "${name}": this name is reserved.`) +} +``` + +启动时也有全局检查(`main.tsx:2351-2368`):如果用户配置中包含保留名(非 `type:'sdk'`),直接 `process.exit(1)`。 + +#### VSCode SDK MCP + +VSCode SDK MCP 是特殊的内置模式。IDE(如 VS Code、JetBrains)通过嵌入方式启动 Claude Code,并传入 `type:'sdk'` 的 MCP 配置。这类配置: +- 不经过保留名称检查(IDE 可以使用任意名称) +- 不参与 enterprise MCP 的排他控制 +- 通过 VSCode SDK transport 连接 +- 支持双向通知(如 `file_updated`、`experiment_gates`) + +```typescript +// src/services/mcp/vscodeSdkMcp.ts +export function setupVscodeSdkMcp(sdkClients: MCPServerConnection[]): void { + const client = sdkClients.find(client => client.name === 'claude-vscode') + if (client && client.type === 'connected') { + // 注册 log_event 通知处理器 + client.client.setNotificationHandler(LogEventNotificationSchema(), ...) + // 发送实验门控到 VSCode + client.client.notification({ method: 'experiment_gates', params: { gates } }) + } +} +``` + +### 外部 MCP 服务器 + +外部 MCP 服务器由用户在配置文件中声明,通过子进程或网络连接运行。 + +#### 配置来源 + +| 来源 | Scope | 文件位置 | 优先级 | +|------|-------|---------|--------| +| 项目配置 | `project` | `/.mcp.json` | 最高(同名覆盖) | +| 本地配置 | `local` | `/.claude/settings.local.json` | 高 | +| 用户配置 | `user` | `~/.claude/settings.json` | 中 | +| 插件 | `dynamic` | 插件 manifest 中 `.mcp.json` | 中 | +| claude.ai | `claudeai` | 通过 API 获取 | 低 | +| 企业管控 | `enterprise` | 系统管理路径 `managed-mcp.json` | 排他(存在时覆盖全部) | + +#### 配置示例 + +```json +// settings.json / .mcp.json 中的 MCP 配置 +{ + "mcpServers": { + // stdio 类型 — 启动子进程 + "my-database": { + "command": "npx", + "args": ["@my-org/db-mcp-server"], + "env": { "DB_URL": "postgres://..." } + }, + + // HTTP 流类型 — 远程服务器 + "remote-api": { + "type": "http", + "url": "https://api.example.com/mcp" + }, + + // SSE 类型 — Server-Sent Events + "realtime-feed": { + "type": "sse", + "url": "https://feed.example.com/sse" + }, + + // WebSocket 类型 + "ws-service": { + "type": "ws", + "url": "wss://ws.example.com/mcp" + } + } +} +``` + +#### 配置合并与去重 + +`getAllMcpConfigs()`(`config.ts`)按优先级合并多个来源的配置: + +1. 企业管控配置存在时,**独占返回**(忽略所有其他来源) +2. 否则合并:user → project → local → plugin → claude.ai +3. 插件与手动配置去重:通过 `getMcpServerSignature()` 生成内容签名(基于 command/args/url),插件配置被同名手动配置抑制 +4. `addScopeToServers()` 为每个配置项标注来源 scope + ## 7 种传输层实现 `connectToServer()`(`client.ts:596-1643`)根据 `config.type` 分发到不同的 Transport 实现: | 传输类型 | Transport 类 | 适用场景 | 认证方式 | |----------|-------------|---------|---------| -| `stdio`(默认) | `StdioClientTransport` | 本地子进程 | 无 | +| `stdio`(默认) | `StdioClientTransport` | 外部本地子进程 | 无 | | `sse` | `SSEClientTransport` | 远程 SSE 服务 | `ClaudeAuthProvider` + OAuth | | `http` | `StreamableHTTPClientTransport` | HTTP 流 | `ClaudeAuthProvider` + OAuth | | `sse-ide` | `SSEClientTransport` | IDE 集成 | lockfile token | | `ws-ide` | `WebSocketTransport` | IDE WebSocket | `X-Claude-Code-Ide-Authorization` | | `ws` | `WebSocketTransport` | WebSocket 服务 | session ingress token | | `claudeai-proxy` | `StreamableHTTPClientTransport` | claude.ai 代理 | OAuth bearer + 401 重试 | +| InProcess(内置) | `InProcessTransport` | Computer Use / Chrome | 无(同进程) | ### stdio 传输的进程管理 @@ -112,9 +308,17 @@ timer.unref?.() // 不阻止进程退出 ```typescript const fullyQualifiedName = buildMcpToolName(client.name, tool.name) -// 结果: "mcp__my-db__query" +// 结果: "mcp__my-database__query" ``` +### 内置 MCP 的工具发现 + +内置 MCP 服务器虽然使用 InProcessTransport,但工具发现流程与外部服务器完全一致: + +- **Computer Use**:`createComputerUseMcpServerForCli()` 在 `src/utils/computerUse/mcpServer.ts` 中构建 MCP Server 对象,注册 `ListToolsRequestSchema` handler。工具描述包含平台特定的已安装应用列表(1s 超时枚举)。 +- **Claude in Chrome**:`createClaudeForChromeMcpServer()` 在 `@ant/claude-for-chrome-mcp` 包中构建 Server,提供 17+ 个浏览器控制工具。 +- **VSCode SDK**:由 IDE 端提供工具列表,通过 SDK transport 传递。 + ### 工具描述截断 MCP 工具描述上限 2048 字符(`MAX_MCP_DESCRIPTION_LENGTH`)。OpenAPI 生成的 MCP 服务器曾观察到 15-60KB 的描述文档。 @@ -134,6 +338,8 @@ MCP 工具描述上限 2048 字符(`MAX_MCP_DESCRIPTION_LENGTH`)。OpenAPI MCP 工具默认返回 `{ behavior: 'passthrough' }`(`client.ts:1816-1834`),意味着它们始终进入权限确认流程。工具名使用 `mcp__` 前缀精确匹配权限规则。 +内置 MCP 服务器的工具通过 `allowedTools` 列表自动授权——在 `main.tsx` 启动时加入,绕过普通权限提示。例如 Computer Use 工具的 `request_access` 自行处理会话级审批。 + ## MCP 工具的执行链路 ``` @@ -169,23 +375,33 @@ getRemoteMcpServerConnectionBatchSize() // 默认 20 本地 MCP 服务器(stdio)是重量级的子进程,默认限制 3 个并发连接。远程服务器是轻量级 HTTP 请求,允许 20 个并发。 -## 实际配置示例 - -```json -// settings.json 中的 MCP 配置 -{ - "mcpServers": { - "my-database": { - "command": "npx", - "args": ["@my-org/db-mcp-server"], - "env": { "DB_URL": "postgres://..." } - }, - "remote-api": { - "type": "http", - "url": "https://api.example.com/mcp" - } - } -} -``` - -配置后,AI 的工具列表中会出现 `mcp__my-database__query` 和 `mcp__remote-api__*` 工具——与内置工具使用相同的权限检查链路和 UI 渲染。 +## 内置 vs 外部 MCP 对比总结 + +| 维度 | 内置 MCP | 外部 MCP | +|------|---------|---------| +| **Transport** | `InProcessTransport`(同进程) | stdio / SSE / HTTP / WebSocket | +| **配置来源** | `setupComputerUseMCP()` / `setupClaudeInChrome()` 等动态注册 | settings.json / .mcp.json / 插件 / claude.ai | +| **Scope** | `dynamic` | `user` / `project` / `local` / `enterprise` / `claudeai` | +| **进程模型** | 同进程,零开销 | 子进程(stdio)或网络连接 | +| **名称保护** | 保留名,用户不可添加同名 | 自由命名(字母数字 + `-_`) | +| **生命周期** | 随 CLI 启停 | 连接缓存 + 按需重连 | +| **权限** | `allowedTools` 自动授权 | `passthrough` 进入权限确认 | +| **Feature Flag** | `CHICAGO_MCP`(Computer Use)等 | 无(始终可用) | +| **工具发现** | 与外部相同(MCP 协议) | 标准 MCP `tools/list` | +| **清理** | `inProcessServer.close()` | 信号升级策略 SIGINT→SIGTERM→SIGKILL | + +## 关键源文件索引 + +| 文件 | 职责 | +|------|------| +| `src/services/mcp/client.ts` | 核心客户端:connectToServer、fetchToolsForClient、MCPTool.call | +| `src/services/mcp/config.ts` | 配置管理:getAllMcpConfigs、addMcpConfig、removeMcpConfig | +| `src/services/mcp/types.ts` | 类型定义:配置 Schema、连接状态类型 | +| `src/services/mcp/InProcessTransport.ts` | 内置 MCP 传输层:linked transport pair | +| `src/services/mcp/vscodeSdkMcp.ts` | VSCode SDK MCP:双向通知、实验门控 | +| `src/services/mcp/useManageMCPConnections.ts` | React Hook:连接生命周期、重连 | +| `src/utils/computerUse/mcpServer.ts` | Computer Use MCP Server 构建 | +| `src/utils/computerUse/setup.ts` | Computer Use 动态注册 | +| `src/utils/claudeInChrome/mcpServer.ts` | Chrome MCP Server 构建 + Bridge 配置 | +| `src/tools/MCPTool/MCPTool.ts` | MCP 工具包装:统一 Tool 接口 | +| `src/entrypoints/mcp.ts` | MCP server 入口(Claude Code 作为 MCP server) | diff --git a/mint.json b/mint.json index 277167e1c..b341d2632 100644 --- a/mint.json +++ b/mint.json @@ -86,6 +86,7 @@ "group": "可扩展性", "pages": [ "docs/extensibility/mcp-protocol", + "docs/extensibility/mcp-configuration", "docs/extensibility/hooks", "docs/extensibility/skills", "docs/extensibility/custom-agents" @@ -177,21 +178,7 @@ ] } ], - "excludes": [ - "docs/test-plans/**", - "docs/testing-spec.md", - "docs/REVISION-PLAN.md", - "docs/feature-exploration-plan.md", - "docs/ultraplan-implementation.md", - "docs/features/feature-flags-audit-complete.md", - "docs/features/feature-flags-codex-review.md", - "docs/features/growthbook-enablement-plan.md", - "docs/features/computer-use-architecture-v2.md", - "docs/features/computer-use-mcp-test-report.md", - "docs/features/computer-use-tools-reference.md", - "docs/features/computer-use-windows-enhancement.md", - "docs/features/lan-pipes-implementation.md" - ], + "excludes": [], "footerSocials": { "github": "https://github.com/anthropics/claude-code" } diff --git a/package.json b/package.json index 636ec7b24..038e1cc16 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,9 @@ "@anthropic-ai/sdk": "^0.80.0", "@anthropic-ai/vertex-sdk": "^0.14.4", "@anthropic/ink": "workspace:*", + "@claude-code-best/builtin-tools": "workspace:*", + "@claude-code-best/agent-tools": "workspace:*", + "@claude-code-best/mcp-client": "workspace:*", "@aws-sdk/client-bedrock": "^3.1020.0", "@aws-sdk/client-bedrock-runtime": "^3.1020.0", "@aws-sdk/client-sts": "^3.1020.0", diff --git a/packages/@ant/ink/docs/01-getting-started.md b/packages/@ant/ink/docs/01-getting-started.md new file mode 100644 index 000000000..26ef6aba4 --- /dev/null +++ b/packages/@ant/ink/docs/01-getting-started.md @@ -0,0 +1,176 @@ +# Chapter 1: Getting Started + +## Installation + +`@anthropic/ink` is a workspace package. It is consumed internally and not published to npm. + +```json +{ + "dependencies": { + "@anthropic/ink": "workspace:*" + } +} +``` + +### Peer Dependencies + +- `react` ^19.2.4 +- `react-reconciler` ^0.33.0 + +### Key Dependencies + +| Package | Purpose | +|---------|---------| +| `chalk` | ANSI color generation | +| `cli-boxes` | Border style definitions | +| `get-east-asian-width` | CJK character width measurement | +| `wrap-ansi` | ANSI-aware word wrapping | +| `bidi-js` | Bidirectional text support | +| `lodash-es` | Utility functions (throttle, noop) | +| `signal-exit` | Process exit handler cleanup | +| `emoji-regex` | Emoji width handling | + +## Basic Rendering + +### `render(node, options?)` + +The primary entry point. Renders a React element tree to the terminal. + +```tsx +import { render } from '@anthropic/ink' +import { Box, Text } from '@anthropic/ink' + +const { unmount, rerender, waitUntilExit } = await render( + + Hello, World! + +) +``` + +**Parameters:** +- `node` -- `ReactNode` to render +- `options` -- `RenderOptions | NodeJS.WriteStream` (optional) + +**Returns:** `Promise` with: +- `rerender(node)` -- Replace the root node +- `unmount()` -- Unmount and clean up +- `waitUntilExit()` -- `Promise` that resolves on unmount +- `cleanup()` -- Remove from instance registry + +### `renderSync(node, options?)` + +Synchronous version of render. Same API, returns `Instance` directly (no Promise). + +```tsx +import { renderSync } from '@anthropic/ink' + +const instance = renderSync() +// instance.rerender, instance.unmount, etc. +``` + +### `createRoot(options?)` + +Creates a managed Ink root without immediately rendering. Similar to `react-dom`'s `createRoot`. + +```tsx +import { createRoot } from '@anthropic/ink' + +const root = await createRoot({ exitOnCtrlC: false }) + +// Later, render into it +root.render() + +// You can re-render into the same root +root.render() + +// Clean up +root.unmount() +``` + +**Returns:** `Promise` with: +- `render(node)` -- Mount or update the tree +- `unmount()` -- Unmount +- `waitUntilExit()` -- `Promise` + +## RenderOptions + +```ts +type RenderOptions = { + /** Output stream. Default: process.stdout */ + stdout?: NodeJS.WriteStream + + /** Input stream. Default: process.stdin */ + stdin?: NodeJS.ReadStream + + /** Error stream. Default: process.stderr */ + stderr?: NodeJS.WriteStream + + /** Handle Ctrl+C to exit. Default: true */ + exitOnCtrlC?: boolean + + /** Patch console methods to prevent Ink output mixing. Default: true */ + patchConsole?: boolean + + /** Called after each frame render with timing info. */ + onFrame?: (event: FrameEvent) => void +} +``` + +## Basic Concepts + +### Component Tree + +Ink renders React components to a terminal using a custom reconciler. The tree structure maps to terminal output: + +```tsx + + Header + + Left + Right + + +``` + +This produces terminal output with Flexbox layout (via Yoga). + +### Rendering Pipeline + +1. **React Reconciler** -- Standard React reconciliation; diffs virtual tree +2. **Yoga Layout** -- Computes Flexbox positions/ sizes for every node +3. **Render to Output** -- Walks the DOM tree, emits styled text into an `Output` buffer +4. **Screen Diff** -- Compares new frame against previous frame in a screen buffer +5. **Terminal Write** -- Emits minimal ANSI escape sequences to update only changed cells + +### Module System + +Import everything from the package root: + +```tsx +// Core rendering +import { render, createRoot, renderSync } from '@anthropic/ink' + +// Components (base, no theme) +import { BaseBox, BaseText, ScrollBox, Button, Link, Newline, Spacer } from '@anthropic/ink' + +// Theme-aware components (recommended) +import { Box, Text } from '@anthropic/ink' + +// Hooks +import { useApp, useInput, useTerminalSize, useInterval } from '@anthropic/ink' + +// Theme +import { ThemeProvider, useTheme, color } from '@anthropic/ink' + +// Keybindings +import { useKeybinding, KeybindingProvider } from '@anthropic/ink' +``` + +### Naming Convention: Base vs Theme-aware + +The package exports both raw and theme-aware versions of core components: + +- **`BaseBox`** / **`BaseText`** -- Raw components that only accept raw color values (`rgb(...)`, `#hex`, `ansi:...`, `ansi256(...)`) +- **`Box`** / **`Text`** -- Theme-aware wrappers that accept both theme keys (`'claude'`, `'success'`, `'error'`) and raw color values + +Always prefer the theme-aware versions unless you have a specific reason to use raw components. diff --git a/packages/@ant/ink/docs/02-layout.md b/packages/@ant/ink/docs/02-layout.md new file mode 100644 index 000000000..246987edc --- /dev/null +++ b/packages/@ant/ink/docs/02-layout.md @@ -0,0 +1,348 @@ +# Chapter 2: Layout System + +Ink uses [Yoga](https://yogalayout.com/) (Facebook's cross-platform layout engine) to implement CSS Flexbox in the terminal. Every layout is flexbox-based -- there is no CSS Grid or flow layout. + +## Box Component + +`Box` is the fundamental layout primitive. It is the terminal equivalent of `
`. + +```tsx +import { Box, Text } from '@anthropic/ink' + + + Left + Right + +``` + +### Box Props (Styles) + +All layout props are passed directly as JSX props (no `style={}` wrapper needed): + +#### Flex Direction + +Controls the main axis direction. + +```tsx +... // Left to right (default) +... // Top to bottom +... // Right to left +... // Bottom to top +``` + +#### Flex Grow / Shrink / Basis + +```tsx +... // Grow to fill available space +... // Don't shrink below intrinsic size +... // Initial size before flex distribution +... // Percentage basis +``` + +Default values: `flexGrow={0}`, `flexShrink={1}`, `flexBasis=auto`. + +#### Flex Wrap + +```tsx +... // Single line (default) +... // Multiple lines +... // Reverse cross-axis stacking +``` + +#### Alignment + +```tsx +... // Cross-axis start +... // Cross-axis center +... // Cross-axis end +... // Stretch to fill (default) + +... // Override parent's alignItems +... +... +... // Inherit from parent +``` + +#### Justify Content + +```tsx +... // Main-axis start (default) +... // Main-axis end +... // Center +... // Equal gaps, no edges +... // Equal gaps with edges +... // Evenly distributed +``` + +#### Gap + +Spacing between children (only accepts integers): + +```tsx +... // Both row and column gap +... // Gap between columns only +... // Gap between rows only +``` + +#### Padding + +Inner spacing (only accepts integers): + +```tsx +... // All sides +... // Left and right +... // Top and bottom +... // Left only +... // Right only +... // Top only +... // Bottom only +``` + +#### Margin + +Outer spacing (only accepts integers): + +```tsx +... // All sides +... // Left and right +... // Top and bottom +... // Left only +... // Right only +... // Top only +... // Bottom only +``` + +> **Note:** Fractional values for padding, margin, and gap are not supported. Ink will emit warnings if non-integer values are used. + +#### Width & Height + +```tsx +... // Fixed 40 characters wide +... // Fixed 10 rows tall +... // 50% of parent's width +... // Full parent width +``` + +#### Min/Max Dimensions + +```tsx +... +... +... +... +``` + +Percentage values are supported: `minWidth="30%"`. + +#### Position + +```tsx +... +... +... // Default +``` + +Position `absolute` removes the element from normal flow and positions it relative to its nearest positioned ancestor. Useful for overlays. + +#### Display + +```tsx +... // Visible (default) +... // Hidden (removed from layout) +``` + +#### Border + +```tsx +... // Thin border +... // Double-line border +... // Rounded corners +... // Bold border +... // Mixed +... // Mixed +... // ASCII art border +``` + +Control individual sides and colors: + +```tsx + + ... + +``` + +Per-side colors: + +```tsx + +``` + +Border text (labels in the border): + +```tsx + +``` + +#### Background + +```tsx +... +``` + +#### Overflow + +```tsx +... // Content expands container (default) +... // Clip without scrolling +... // Enable scrolling (use ScrollBox) +``` + +`overflowX` and `overflowY` control each axis independently. + +#### Opaque + +```tsx +... +``` + +Fills the box interior with spaces (using terminal's default background) before rendering children. Useful for absolute-positioned overlays where gaps would otherwise be transparent. + +#### NoSelect + +```tsx +... // Exclude from text selection +... // Exclude from column 0 to box edge +``` + +Only affects alt-screen text selection. Useful for gutters (line numbers, diff markers). + +## Spacer + +`Spacer` fills all available space along the main axis (equivalent to `flexGrow: 1`). + +```tsx + + Left + + Right + +``` + +## Newline + +Inserts line breaks. + +```tsx + + Line 1 + + Line 2 + + Line 4 (after double break) + +``` + +## Layout Examples + +### Two-column layout + +```tsx + + + Left column + + + Right column + + +``` + +### Centered content + +```tsx + + Centered! + +``` + +### Sticky footer + +```tsx + + + Scrollable content area + + + Status bar at bottom + + +``` + +### Bordered panel with title + +```tsx + + Panel Title + Panel content goes here. + +``` + +## NoSelect + +Wraps a region to exclude it from text selection in alt-screen mode. A convenience wrapper around `Box` with `noSelect` set. + +```tsx +import { NoSelect } from '@anthropic/ink' + + + + 1 │ + + selectable code here + +``` + +### Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `children` | `ReactNode` | - | Content | +| `fromLeftEdge` | `boolean` | `false` | Extend exclusion from column 0 to box's right edge | + +Accepts all `BoxProps` except `noSelect`. + +## BaseBox vs ThemedBox + +Two versions of Box are exported: + +- **`BaseBox`** (imported as `BaseBox`) -- Raw box, color props accept only raw `Color` values +- **`Box`** (themed, imported as `Box`) -- Theme-aware, color props accept `keyof Theme | Color` + +```tsx +// Raw + + +// Theme-aware (resolves 'permission' to the current theme's blue) + +``` diff --git a/packages/@ant/ink/docs/03-text-and-styling.md b/packages/@ant/ink/docs/03-text-and-styling.md new file mode 100644 index 000000000..96b355808 --- /dev/null +++ b/packages/@ant/ink/docs/03-text-and-styling.md @@ -0,0 +1,238 @@ +# Chapter 3: Text & Styling + +## Text Component + +`Text` renders styled text content. It supports colors, emphasis, and text wrapping. + +```tsx +import { Text } from '@anthropic/ink' + +Operation complete +``` + +### Text Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `color` | `keyof Theme \| Color` | - | Foreground color | +| `backgroundColor` | `keyof Theme` | - | Background color (theme-aware) | +| `bold` | `boolean` | `false` | Bold text | +| `dimColor` | `boolean` | `false` | Dim text (uses theme's `inactive` color) | +| `italic` | `boolean` | `false` | Italic text | +| `underline` | `boolean` | `false` | Underlined text | +| `strikethrough` | `boolean` | `false` | Strikethrough text | +| `inverse` | `boolean` | `false` | Swap foreground/background | +| `wrap` | `TextWrap` | `'wrap'` | Wrapping/truncation mode | +| `children` | `ReactNode` | - | Text content | + +> **Note:** `bold` and `dimColor` are mutually exclusive (ANSI terminals cannot render both simultaneously). + +### BaseText vs ThemedText + +- **`BaseText`** -- Accepts raw `Color` values only +- **`Text`** (default export) -- Theme-aware, accepts `keyof Theme | Color` for `color`, and `keyof Theme` for `backgroundColor` + +```tsx +// Raw color +Red text + +// Theme key (resolved to current theme palette) +Error message + +// Mixed +Custom red +``` + +### Text Wrap Modes + +```tsx +... // Word-wrap at container width (default) +... // Wrap + trim trailing whitespace +... // Truncate with "..." at end +... // Same as "end" +... // Truncate (no ellipsis) +... // "start...end" +... // Same as "middle" +... // "...text" +``` + +### TextHoverColorContext + +Uncolored `Text` children inherit a hover color from context: + +```tsx +import { TextHoverColorContext } from '@anthropic/ink' + + + Uncolored text gets the suggestion color + This stays red + +``` + +Precedence: explicit `color` > `TextHoverColorContext` > `dimColor`. + +## Color System + +### Raw Color Formats + +Four formats are supported for raw color values: + +```tsx +// RGB +Bright red + +// Hex +Bright red + +// ANSI 256-color +Red from 256-color palette + +// Named ANSI 16-color +Red +Bright green +``` + +### ANSI Named Colors + +Full list of `ansi:` prefixed names: + +| Name | Color | +|------|-------| +| `ansi:black` | Black | +| `ansi:red` | Red | +| `ansi:green` | Green | +| `ansi:yellow` | Yellow | +| `ansi:blue` | Blue | +| `ansi:magenta` | Magenta | +| `ansi:cyan` | Cyan | +| `ansi:white` | White | +| `ansi:blackBright` | Dark gray | +| `ansi:redBright` | Bright red | +| `ansi:greenBright` | Bright green | +| `ansi:yellowBright` | Bright yellow | +| `ansi:blueBright` | Bright blue | +| `ansi:magentaBright` | Bright magenta | +| `ansi:cyanBright` | Bright cyan | +| `ansi:whiteBright` | Bright white | + +## Utility Functions + +### `color(colorValue, themeName, type?)` + +Curried theme-aware color function. Resolves theme keys to raw color values. + +```tsx +import { color } from '@anthropic/ink' + +const paint = color('error', 'dark') // Returns (text: string) => string +console.log(paint('failed')) // 'failed' wrapped in ANSI red codes + +const paintFg = color('rgb(255,0,0)', 'dark', 'foreground') +const paintBg = color('success', 'dark', 'background') +``` + +Parameters: +- `c` -- `keyof Theme | Color | undefined` -- Theme key or raw color +- `theme` -- `ThemeName` -- Current theme +- `type` -- `'foreground' | 'background'` (default `'foreground'`) + +### `stringWidth(text)` + +Measures the visual width of a string in terminal columns, accounting for: +- CJK characters (2 columns each) +- Emoji (2 columns each) +- ANSI escape sequences (0 columns) + +```tsx +import { stringWidth } from '@anthropic/ink' + +stringWidth('hello') // 5 +stringWidth('你好') // 4 +stringWidth('\x1b[31mhi') // 2 (ANSI codes ignored) +``` + +### `wrapText(text, width, textWrap)` + +Wraps text to a given width with the specified wrapping mode. + +```tsx +import { wrapText } from '@anthropic/ink' + +wrapText('Hello World', 5, 'wrap') // 'Hello\nWorld' +wrapText('Hello World', 8, 'end') // 'Hello...' +``` + +### `wrapAnsi(text, width)` + +Wraps text containing ANSI escape codes while preserving styling. + +```tsx +import { wrapAnsi } from '@anthropic/ink' + +wrapAnsi('\x1b[31mHello World\x1b[0m', 5) +// Wraps at word boundaries, keeps color codes intact +``` + +### `measureElement(node)` + +Measures a rendered DOM element's dimensions. + +```tsx +import { measureElement } from '@anthropic/ink' + +const { width, height } = measureElement(domElement) +``` + +## Link Component + +Renders an OSC 8 terminal hyperlink (clickable URL in supported terminals). + +```tsx +import { Link } from '@anthropic/ink' + + + example.com + +``` + +Props: +- `url` -- `string` (required) -- Target URL +- `children` -- `ReactNode` -- Display content +- `fallback` -- `ReactNode` -- Shown when hyperlinks are unsupported + +## RawAnsi Component + +Renders pre-formatted ANSI strings directly into the layout. + +```tsx +import { RawAnsi } from '@anthropic/ink' + + +``` + +Props: +- `lines` -- `string[]` -- Pre-rendered ANSI lines (one terminal row each) +- `width` -- `number` -- Column width the producer wrapped to + +## Border Rendering + +### `renderBorder(box, output, options?)` + +Low-level border rendering function used internally by Box. + +```tsx +import { renderBorder } from '@anthropic/ink' +import type { BorderTextOptions } from '@anthropic/ink' +``` + +Border styles available (from `cli-boxes`): +- `single` -- Thin lines `─│┌┐└┘` +- `double` -- Double lines `═║╔╗╚╝` +- `round` -- Rounded corners `─│╭╮╰╯` +- `bold` -- Bold lines `━┃┏┓┗┛` +- `singleDouble` -- Single horizontal, double vertical +- `doubleSingle` -- Double horizontal, single vertical +- `classic` -- ASCII `─|++++` diff --git a/packages/@ant/ink/docs/04-theme-system.md b/packages/@ant/ink/docs/04-theme-system.md new file mode 100644 index 000000000..de0f33cb8 --- /dev/null +++ b/packages/@ant/ink/docs/04-theme-system.md @@ -0,0 +1,213 @@ +# Chapter 4: Theme System + +The theme system provides consistent, accessible color palettes across the application. It supports dark mode, light mode, ANSI-only terminals, and colorblind-accessible variants. + +## ThemeProvider + +Wraps the application to provide theme context. + +```tsx +import { ThemeProvider } from '@anthropic/ink' + +function App() { + return ( + saveConfig(setting)}> + + + ) +} +``` + +### Props + +| Prop | Type | Description | +|------|------|-------------| +| `children` | `ReactNode` | Child components | +| `initialState` | `ThemeSetting` | Initial theme (default: loads from config) | +| `onThemeSave` | `(setting: ThemeSetting) => void` | Called when theme is saved | + +### Theme Configuration Injection + +Before mounting, inject config persistence callbacks: + +```tsx +import { setThemeConfigCallbacks } from '@anthropic/ink' + +setThemeConfigCallbacks({ + loadTheme: () => configStore.get('theme', 'dark'), + saveTheme: (setting) => configStore.set('theme', setting), +}) +``` + +## Theme Settings + +```ts +type ThemeSetting = 'auto' | 'dark' | 'light' | 'light-daltonized' | 'dark-daltonized' | 'light-ansi' | 'dark-ansi' +type ThemeName = 'dark' | 'light' | 'light-daltonized' | 'dark-daltonized' | 'light-ansi' | 'dark-ansi' +``` + +| Theme | Description | +|-------|-------------| +| `dark` | Dark theme with RGB colors (default) | +| `light` | Light theme with RGB colors | +| `dark-daltonized` | Colorblind-accessible dark theme | +| `light-daltonized` | Colorblind-accessible light theme | +| `dark-ansi` | Dark theme using only 16 ANSI colors | +| `light-ansi` | Light theme using only 16 ANSI colors | +| `auto` | Follows terminal's dark/light mode (resolved at runtime) | + +## Theme Hooks + +### `useTheme()` + +Returns the resolved theme name and setter. + +```tsx +const [currentTheme, setTheme] = useTheme() +// currentTheme: ThemeName (never 'auto') +// setTheme: (setting: ThemeSetting) => void +``` + +### `useThemeSetting()` + +Returns the raw setting (may be `'auto'`). + +```tsx +const setting = useThemeSetting() // 'auto' | 'dark' | ... +``` + +### `usePreviewTheme()` + +Returns preview controls for a theme picker UI. + +```tsx +const { setPreviewTheme, savePreview, cancelPreview } = usePreviewTheme() + +// Show preview +setPreviewTheme('light') + +// User confirms +savePreview() + +// User cancels +cancelPreview() +``` + +## Theme Color Palette + +Every theme defines these semantic color keys: + +### Brand & Identity + +| Key | Purpose | +|-----|---------| +| `claude` | Brand orange | +| `claudeShimmer` | Lighter brand orange (animated) | +| `permission` | Permission/blue | +| `permissionShimmer` | Lighter permission blue | +| `autoAccept` | Electric violet | +| `planMode` | Teal/sage | +| `ide` | Muted blue | + +### Semantic Colors + +| Key | Purpose | +|-----|---------| +| `text` | Primary text color | +| `inverseText` | Text on inverse backgrounds | +| `inactive` | Dimmed/disabled elements | +| `inactiveShimmer` | Lighter inactive | +| `subtle` | Very subtle text | +| `suggestion` | Interactive/accent | +| `background` | General background accent | +| `success` | Positive/success | +| `error` | Negative/error | +| `warning` | Caution/warning | +| `warningShimmer` | Lighter warning | +| `merged` | Merged state | + +### Diff Colors + +| Key | Purpose | +|-----|---------| +| `diffAdded` | Added lines background | +| `diffRemoved` | Removed lines background | +| `diffAddedDimmed` | Dimmed added | +| `diffRemovedDimmed` | Dimmed removed | +| `diffAddedWord` | Word-level added | +| `diffRemovedWord` | Word-level removed | + +### UI Colors + +| Key | Purpose | +|-----|---------| +| `promptBorder` | Input prompt border | +| `promptBorderShimmer` | Lighter prompt border | +| `bashBorder` | Shell block border | +| `selectionBg` | Text selection highlight background | +| `userMessageBackground` | User message background | +| `userMessageBackgroundHover` | User message hover | +| `messageActionsBackground` | Action buttons background | + +### Agent Colors + +| Key | Purpose | +|-----|---------| +| `red_FOR_SUBAGENTS_ONLY` | Agent color assignment | +| `blue_FOR_SUBAGENTS_ONLY` | Agent color assignment | +| `green_FOR_SUBAGENTS_ONLY` | Agent color assignment | +| `yellow_FOR_SUBAGENTS_ONLY` | Agent color assignment | +| `purple_FOR_SUBAGENTS_ONLY` | Agent color assignment | +| `orange_FOR_SUBAGENTS_ONLY` | Agent color assignment | +| `pink_FOR_SUBAGENTS_ONLY` | Agent color assignment | +| `cyan_FOR_SUBAGENTS_ONLY` | Agent color assignment | + +## Using Theme Colors in Components + +### ThemedText + +```tsx +Operation complete +Failed! +Claude says... +Secondary info +Highlighted +``` + +### ThemedBox + +```tsx + + Themed content + +``` + +### color() Utility + +```tsx +import { color, useTheme } from '@anthropic/ink' + +function MyComponent() { + const [themeName] = useTheme() + const paint = color('success', themeName) + // paint('text') returns ANSI-colored string +} +``` + +## Daltonized Themes + +The daltonized themes (`light-daltonized`, `dark-daltonized`) are designed for users with protanopia/deuteranopia: + +- Green/red diffs replaced with blue/red +- Status colors use blue instead of green +- Warning colors adjusted for better distinction +- All color pairs verified for sufficient contrast + +## System Theme Detection + +When `ThemeSetting` is `'auto'`: + +1. Seeds from `$COLORFGBG` environment variable +2. Queries terminal via OSC 11 for live background color +3. Watches for changes (terminal theme switch) in real-time +4. Resolves to `'dark'` or `'light'` based on detected brightness diff --git a/packages/@ant/ink/docs/05-design-system.md b/packages/@ant/ink/docs/05-design-system.md new file mode 100644 index 000000000..7709ad6b9 --- /dev/null +++ b/packages/@ant/ink/docs/05-design-system.md @@ -0,0 +1,390 @@ +# Chapter 5: Design System Components + +Pre-built theme-aware UI components for common terminal interface patterns. + +## Dialog + +Modal dialog with border, title, and keyboard navigation. + +```tsx +import { Dialog } from '@anthropic/ink' + + setShowDialog(false)} + color="warning" +> + Are you sure you want to proceed? + +``` + +### Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `title` | `ReactNode` | - | Dialog title (required) | +| `subtitle` | `ReactNode` | - | Optional subtitle | +| `children` | `ReactNode` | - | Dialog body content | +| `onCancel` | `() => void` | - | Called on Esc/n (required) | +| `color` | `keyof Theme` | `'permission'` | Title and border color | +| `hideInputGuide` | `boolean` | `false` | Hide the keyboard hint footer | +| `hideBorder` | `boolean` | `false` | Render without Pane border | +| `inputGuide` | `(exitState) => ReactNode` | - | Custom input guide footer | +| `isCancelActive` | `boolean` | `true` | Enable/disable cancel keybindings | + +### Keyboard Shortcuts + +- **Enter** -- Confirm (consumer handles this) +- **Esc / n** -- Cancel (calls `onCancel`) +- **Ctrl+C / Ctrl+D** -- Double-press to exit + +### Custom Input Guide + +```tsx + ( + exitState.pending + ? Press {exitState.keyName} again to exit + : Press Enter to save, Esc to cancel + )} +> + ... + +``` + +## Pane + +Bordered container with themed top border. + +```tsx +import { Pane } from '@anthropic/ink' + + + Content inside a bordered pane + +``` + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `children` | `ReactNode` | - | Content | +| `color` | `keyof Theme` | `'permission'` | Top border color | + +## ProgressBar + +Visual progress indicator. + +```tsx +import { ProgressBar } from '@anthropic/ink' + + +``` + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `ratio` | `number` | - | Progress 0..1 (required) | +| `width` | `number` | - | Character width (required) | +| `fillColor` | `keyof Theme` | - | Filled portion color | +| `emptyColor` | `keyof Theme` | - | Empty portion color | + +## Spinner + +Animated loading spinner. No props. + +```tsx +import { Spinner } from '@anthropic/ink' + + + + Loading... + +``` + +## LoadingState + +Loading message with spinner and optional subtitle. + +```tsx +import { LoadingState } from '@anthropic/ink' + + +``` + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `message` | `string` | - | Loading message (required) | +| `bold` | `boolean` | `false` | Bold message | +| `dimColor` | `boolean` | `false` | Dimmed message | +| `subtitle` | `string` | - | Secondary text below | + +## StatusIcon + +Semantic status indicator with icon and color. + +```tsx +import { StatusIcon } from '@anthropic/ink' + + +Build complete +``` + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `status` | `'success' \| 'error' \| 'warning' \| 'info' \| 'pending' \| 'loading'` | - | Status type (required) | +| `withSpace` | `boolean` | `false` | Add trailing space | + +Status icons: +- `success` -- Green checkmark +- `error` -- Red cross +- `warning` -- Yellow warning +- `info` -- Blue info +- `pending` -- Dimmed circle +- `loading` -- Dimmed ellipsis + +## FuzzyPicker + +Full-featured fuzzy search selector with preview support. + +```tsx +import { FuzzyPicker } from '@anthropic/ink' + + f.path} + renderItem={(f, focused) => {f.name}} + onQueryChange={(q) => setFilteredFiles(filterFiles(q))} + onSelect={(f) => openFile(f)} + onCancel={() => setShowPicker(false)} +/> +``` + +### Props + +| Prop | Type | Description | +|------|------|-------------| +| `title` | `string` | Picker title (required) | +| `items` | `readonly T[]` | Items to display (required) | +| `getKey` | `(item: T) => string` | Unique key extractor (required) | +| `renderItem` | `(item: T, isFocused: boolean) => ReactNode` | Item renderer (required) | +| `onQueryChange` | `(query: string) => void` | Filter callback (required) | +| `onSelect` | `(item: T) => void` | Enter key handler (required) | +| `onCancel` | `() => void` | Esc handler (required) | +| `renderPreview` | `(item: T) => ReactNode` | Preview panel renderer | +| `previewPosition` | `'bottom' \| 'right'` | Preview placement | +| `visibleCount` | `number` | Max visible items | +| `direction` | `'down' \| 'up'` | Item ordering | +| `onTab` | `PickerAction` | Tab key handler | +| `onShiftTab` | `PickerAction` | Shift+Tab handler | +| `onFocus` | `(item: T \| undefined) => void` | Focus change callback | +| `emptyMessage` | `string \| ((query: string) => string)` | Empty state message | +| `matchLabel` | `string` | Status line below list | +| `placeholder` | `string` | Input placeholder | +| `initialQuery` | `string` | Initial search query | +| `selectAction` | `string` | Action label for byline | +| `extraHints` | `ReactNode` | Additional keyboard hints | + +## Tabs / Tab + +Tabbed interface with keyboard navigation. + +```tsx +import { Tabs, Tab } from '@anthropic/ink' + + + + + + + + + +``` + +### Tabs Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `children` | `ReactElement[]` | - | Tab elements | +| `title` | `string` | - | Header title | +| `color` | `keyof Theme` | - | Active tab indicator color | +| `defaultTab` | `string` | - | Initial tab id | +| `selectedTab` | `string` | - | Controlled selected tab | +| `onTabChange` | `(tabId: string) => void` | - | Tab change callback | +| `hidden` | `boolean` | `false` | Hide tab headers | +| `useFullWidth` | `boolean` | `false` | Use full terminal width | +| `banner` | `ReactNode` | - | Banner below tab headers | +| `disableNavigation` | `boolean` | `false` | Disable keyboard nav | +| `initialHeaderFocused` | `boolean` | `true` | Start with header focused | +| `contentHeight` | `number` | - | Fixed content height | +| `navFromContent` | `boolean` | `false` | Allow Tab/Arrow from content | + +### Tab Props + +| Prop | Type | Description | +|------|------|-------------| +| `title` | `string` | Tab label (required) | +| `id` | `string` | Tab identifier | +| `children` | `ReactNode` | Tab content | + +### Tab Hooks + +```tsx +import { useTabsWidth, useTabHeaderFocus } from '@anthropic/ink' + +const width = useTabsWidth() // Available content width +const focused = useTabHeaderFocus() // Whether tab header is focused +``` + +## ListItem + +Selectable list item with focus/selection indicators. + +```tsx +import { ListItem } from '@anthropic/ink' + + + {item.label} + +``` + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `isFocused` | `boolean` | - | Keyboard focus (required) | +| `isSelected` | `boolean` | `false` | Checked/active state | +| `children` | `ReactNode` | - | Content | +| `description` | `string` | - | Secondary text below | +| `styled` | `boolean` | `true` | Auto-style based on state | +| `disabled` | `boolean` | `false` | Dimmed, non-interactive | +| `showScrollDown` | `boolean` | `false` | Scroll-down hint arrow | +| `showScrollUp` | `boolean` | `false` | Scroll-up hint arrow | +| `declareCursor` | `boolean` | `true` | Declare terminal cursor | + +## SearchBox + +Search input with theme-aware styling. + +```tsx +import { SearchBox } from '@anthropic/ink' + + +``` + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `query` | `string` | - | Current search text | +| `placeholder` | `string` | - | Placeholder text | +| `isFocused` | `boolean` | - | Focus state | +| `isTerminalFocused` | `boolean` | - | Terminal focus state | +| `prefix` | `string` | - | Input prefix label | +| `width` | `number \| string` | - | Input width | +| `cursorOffset` | `number` | - | Cursor position offset | +| `borderless` | `boolean` | `false` | Remove border | + +## Divider + +Horizontal/vertical divider line. + +```tsx +import { Divider } from '@anthropic/ink' + + + +``` + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `width` | `number` | Terminal width | Divider width | +| `color` | `keyof Theme` | Dimmed | Line color | +| `char` | `string` | `'─'` | Line character | +| `padding` | `number` | `0` | Width reduction | +| `title` | `string` | - | Centered title text | + +## Byline + +Footer with middot-separated items. + +```tsx +import { Byline } from '@anthropic/ink' + + + + + +``` + +## KeyboardShortcutHint + +Display a keyboard shortcut with its action. + +```tsx +import { KeyboardShortcutHint } from '@anthropic/ink' + + + +``` + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `shortcut` | `string` | - | Key or chord to display | +| `action` | `string` | - | Action description | +| `parens` | `boolean` | `false` | Wrap in parentheses | +| `bold` | `boolean` | `false` | Bold shortcut text | + +## ConfigurableShortcutHint + +Displays a shortcut hint that reads the actual keybinding from config. + +```tsx +import { ConfigurableShortcutHint } from '@anthropic/ink' + + +``` + +| Prop | Type | Description | +|------|------|-------------| +| `action` | `string` | Keybinding action name | +| `context` | `string` | Keybinding context | +| `fallback` | `string` | Default shortcut if unbound | +| `description` | `string` | Action description | +| `parens` | `boolean` | Wrap in parentheses | +| `bold` | `boolean` | Bold shortcut text | + +## Ratchet + +Animated counter component that prevents layout jumps. + +```tsx +import { Ratchet } from '@anthropic/ink' + + + {count} + +``` + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `children` | `ReactNode` | - | Content | +| `lock` | `'always' \| 'offscreen'` | `'always'` | Width locking strategy. `'always'` locks always; `'offscreen'` only locks when the element is scrolled off-screen | diff --git a/packages/@ant/ink/docs/06-scrolling.md b/packages/@ant/ink/docs/06-scrolling.md new file mode 100644 index 000000000..9edfcc410 --- /dev/null +++ b/packages/@ant/ink/docs/06-scrolling.md @@ -0,0 +1,189 @@ +# Chapter 6: Scrolling + +## ScrollBox + +A scrollable container with imperative scroll API, viewport culling, and sticky scroll support. + +```tsx +import { ScrollBox } from '@anthropic/ink' +import type { ScrollBoxHandle } from '@anthropic/ink' + +function MessageList({ messages }) { + const scrollRef = useRef(null) + + // Auto-scroll to bottom on new messages + useEffect(() => { + scrollRef.current?.scrollToBottom() + }, [messages.length]) + + return ( + + {messages.map(msg => ( + {msg.text} + ))} + + ) +} +``` + +### Props + +ScrollBox accepts all Box layout props except `textWrap`, `overflow`, `overflowX`, `overflowY` (these are managed internally): + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `ref` | `Ref` | - | Imperative handle | +| `stickyScroll` | `boolean` | `false` | Auto-follow new content | +| *(layout props)* | `Styles` | - | Width, height, padding, etc. | + +### ScrollBoxHandle (Imperative API) + +```ts +interface ScrollBoxHandle { + // Absolute positioning + scrollTo(y: number): void + scrollToElement(el: DOMElement, offset?: number): void + scrollToBottom(): void + + // Relative positioning + scrollBy(dy: number): void + + // Query state + getScrollTop(): number + getPendingDelta(): number + getScrollHeight(): number + getFreshScrollHeight(): number + getViewportHeight(): number + getViewportTop(): number + isSticky(): boolean + + // Events + subscribe(listener: () => void): () => void + + // Virtual scroll support + setClampBounds(min?: number, max?: number): void +} +``` + +### Method Details + +#### `scrollTo(y)` + +Jump to an absolute position. Breaks sticky scroll. + +```tsx +scrollRef.current?.scrollTo(0) // Scroll to top +``` + +#### `scrollBy(dy)` + +Scroll by a relative amount. Accumulates deltas for smooth scrolling. + +```tsx +scrollRef.current?.scrollBy(3) // Scroll down 3 rows +scrollRef.current?.scrollBy(-5) // Scroll up 5 rows +``` + +#### `scrollToElement(el, offset?)` + +Scroll so a specific DOM element is at the viewport top. More reliable than `scrollTo` because it reads the element's position at render time (avoids stale layout values). + +```tsx +const elementRef = useRef(null) +scrollRef.current?.scrollToElement(elementRef.current!, 2) +``` + +#### `scrollToBottom()` + +Pin scroll to bottom. Enables sticky mode. + +```tsx +scrollRef.current?.scrollToBottom() +``` + +#### `isSticky()` + +Returns `true` when scroll is pinned to the bottom. + +```tsx +if (scrollRef.current?.isSticky()) { + // User hasn't scrolled up +} +``` + +#### `subscribe(listener)` + +Subscribe to imperative scroll changes. Returns unsubscribe function. + +```tsx +useEffect(() => { + return scrollRef.current?.subscribe(() => { + console.log('Scroll position changed') + }) +}, []) +``` + +### Sticky Scroll + +When `stickyScroll` is enabled: + +1. Scroll automatically follows new content at the bottom +2. User scroll (via `scrollBy`/`scrollTo`) breaks stickiness +3. `scrollToBottom()` re-enables stickiness +4. Content growth at the bottom is detected and followed automatically + +```tsx + + {/* New items auto-scroll to bottom */} + {items.map(renderItem)} + +``` + +### Viewport Culling + +ScrollBox only renders children that intersect the visible viewport. Children outside the viewport are still mounted in React but skipped during terminal rendering. This makes large lists performant. + +### Virtual Scrolling + +For very large lists, use `setClampBounds` in combination with a virtual scrolling hook: + +```tsx +const scrollRef = useRef(null) + +// After computing visible range +scrollRef.current?.setClampBounds(firstVisibleRow, lastVisibleRow) +``` + +This prevents burst `scrollTo` calls from showing blank space beyond mounted content. + +### Scroll Events + +ScrollBox bypasses React state for scroll operations. Instead: +1. `scrollTo`/`scrollBy` mutate `scrollTop` directly on the DOM node +2. The node is marked dirty +3. A microtask-deferred render fires to coalesce multiple scroll events +4. The Ink renderer reads `scrollTop` during layout + +This avoids React reconciler overhead per wheel event. + +### Integration with Mouse Wheel + +In alt-screen mode, mouse wheel events are captured by the `App` component and forwarded to the focused ScrollBox: + +``` +Wheel event → App.handleMouseEvent → ScrollBox.scrollBy(delta) +``` + +### Layout Structure + +ScrollBox creates a two-level DOM structure: + +``` +ink-box (overflow: scroll, constrained height) +└── Box (flexGrow: 1, flexShrink: 0, width: 100%) + ├── Child 1 + ├── Child 2 + └── ... +``` + +The outer `ink-box` is the viewport with constrained size. The inner `Box` grows to fit all content. The renderer computes `scrollHeight` from the inner box and translates content by `-scrollTop`. diff --git a/packages/@ant/ink/docs/07-user-input.md b/packages/@ant/ink/docs/07-user-input.md new file mode 100644 index 000000000..dc46aff07 --- /dev/null +++ b/packages/@ant/ink/docs/07-user-input.md @@ -0,0 +1,267 @@ +# Chapter 7: User Input + +## useInput + +The primary hook for handling keyboard input. + +```tsx +import { useInput } from '@anthropic/ink' + +function MyComponent() { + useInput((input, key, event) => { + if (input === 'q') { + // 'q' key pressed + } + if (key.leftArrow) { + // Left arrow + } + if (key.ctrl && input === 'c') { + // Ctrl+C (only if exitOnCtrlC is false) + } + if (key.meta && input === 'b') { + // Alt+B (Option+B on Mac) + } + if (key.shift && input === 'Tab') { + // Shift+Tab + } + }) + + return Press keys... +} +``` + +### Signature + +```ts +function useInput( + handler: (input: string, key: Key, event: InputEvent) => void, + options?: { isActive?: boolean } +): void +``` + +### Parameters + +- **`input`** (`string`) -- The character entered. Empty string for non-printable keys (arrows, function keys). For paste events, the entire pasted text. +- **`key`** (`Key`) -- Parsed key metadata (see below) +- **`event`** (`InputEvent`) -- Raw event with `stopImmediatePropagation()` + +### Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `isActive` | `boolean` | `true` | Enable/disable input handling | + +### Key Object + +```ts +type Key = { + upArrow: boolean + downArrow: boolean + leftArrow: boolean + rightArrow: boolean + pageDown: boolean + pageUp: boolean + wheelUp: boolean // Mouse wheel in alt-screen + wheelDown: boolean // Mouse wheel in alt-screen + home: boolean + end: boolean + return: boolean + escape: boolean + ctrl: boolean + shift: boolean + fn: boolean + tab: boolean + backspace: boolean + delete: boolean + meta: boolean // Alt / Option + super: boolean // Cmd (macOS) / Win key +} +``` + +### Event Propagation + +Multiple `useInput` handlers form a chain. Call `event.stopImmediatePropagation()` to prevent downstream handlers from receiving the event: + +```tsx +useInput((input, key, event) => { + if (input === 'j') { + // Consumed by this handler + event.stopImmediatePropagation() + } + // Other handlers won't see 'j' +}) + +useInput((input, key) => { + // This won't fire for 'j' +}) +``` + +### Raw Mode + +`useInput` automatically enables raw mode on stdin when active. Raw mode is reference-counted -- it stays enabled as long as any hook has `isActive: true`. + +In raw mode: +- Keystrokes don't echo +- Ctrl+C is not sent as signal (app must handle it) +- Line buffering is disabled + +## InputEvent + +```ts +class InputEvent extends Event { + readonly input: string + readonly key: Key + readonly keypress: ParsedKey // Raw parsed keypress data +} +``` + +## KeyboardEvent + +DOM-like keyboard event dispatched to focused elements: + +```ts +class KeyboardEvent extends Event { + readonly key: Key +} +``` + +Used with `Box`'s `onKeyDown` and `onKeyDownCapture` props: + +```tsx + { + if (event.key.return) { + handleSubmit() + } + }} +> + Press Enter to submit + +``` + +## Key Parsing + +Ink supports multiple keyboard protocols: + +### Standard Escape Sequences +- Arrow keys, function keys, Home/End, Page Up/Down +- Ctrl+letter combinations +- Shift, Alt, Meta modifiers + +### Kitty Keyboard Protocol (CSI u) +Extended key reporting with full modifier support: +- Distinguishes Ctrl+Shift+A from Ctrl+A +- Reports Super (Cmd/Win) key +- Sends key release events + +### xterm modifyOtherKeys +Alternative extended key reporting for xterm-compatible terminals. + +### Application Keypad Mode +Numpad keys mapped to their digit characters. + +## Paste Detection + +When `Bracketed Paste` mode is enabled (DECSET 2004), pasted text is delivered as a single `InputEvent` with the full text in `input`. This distinguishes paste from rapid typing: + +```tsx +useInput((input, key, event) => { + if (event.keypress.paste) { + // User pasted text -- handle as a batch + handlePaste(input) + } else { + // Regular keypress + handleKey(input, key) + } +}) +``` + +## Mouse Events (Alt-Screen Only) + +In alternate screen mode, mouse events are parsed and dispatched: + +### Click Events + +```tsx + { + console.log(`Clicked at (${event.x}, ${event.y})`) + event.stopImmediatePropagation() + }} +> + Click me + +``` + +### Hover Events + +```tsx + setHovered(true)} + onMouseLeave={() => setHovered(false)} +> + {hovered ? 'Hovered!' : 'Hover me'} + +``` + +Hover events use `mouseenter`/`mouseleave` semantics (no bubbling between children). + +### Wheel Events + +Mouse wheel events arrive as `Key.wheelUp`/`Key.wheelDown`: + +```tsx +useInput((input, key) => { + if (key.wheelUp) scrollUp() + if (key.wheelDown) scrollDown() +}) +``` + +## useStdin + +Lower-level access to the stdin stream. + +```tsx +import { useStdin } from '@anthropic/ink' + +const { + stdin, // Raw stdin stream + setRawMode, // (enabled: boolean) => void + isRawModeSupported, // boolean + internal_exitOnCtrlC, // boolean + internal_eventEmitter, // EventEmitter | undefined + internal_querier, // Terminal querier +} = useStdin() +``` + +> **Prefer `useInput` for keyboard handling.** `useStdin` is for advanced use cases like terminal querying or custom event handling. + +## Button Component + +Interactive button that responds to keyboard and mouse: + +```tsx +import { Button } from '@anthropic/ink' + + +``` + +Button receives a render prop with state: + +```ts +type ButtonState = { + focused: boolean // Has keyboard focus + hovered: boolean // Mouse is over it (alt-screen) + active: boolean // True for 100ms after activation (flash effect) +} +``` + +Activation triggers: Enter key, Space key, or mouse click. diff --git a/packages/@ant/ink/docs/08-keybindings.md b/packages/@ant/ink/docs/08-keybindings.md new file mode 100644 index 000000000..092ff7caf --- /dev/null +++ b/packages/@ant/ink/docs/08-keybindings.md @@ -0,0 +1,302 @@ +# Chapter 8: Keybinding System + +The keybinding system provides configurable, context-aware keyboard shortcuts with chord sequence support. + +## Architecture + +``` +KeybindingSetup (loads config) + └── KeybindingProvider (provides context) + ├── useKeybinding(action, handler) + ├── useKeybindings({ action: handler }) + ├── useKeybindingContext() + └── useRegisterKeybindingContext(name, isActive) +``` + +## KeybindingSetup + +Loads and validates keybinding configuration at app startup. + +```tsx +import { KeybindingSetup } from '@anthropic/ink' + + parseUserKeybindings(configFile)} + subscribeToChanges={(cb) => watchConfigFile(cb)} + onWarnings={(warnings, isReload) => { + warnings.forEach(w => console.warn(w.message)) + }} +> + + +``` + +### Props + +| Prop | Type | Description | +|------|------|-------------| +| `children` | `ReactNode` | App tree | +| `loadBindings` | `() => KeybindingsLoadResult` | Load bindings from config | +| `subscribeToChanges` | `(cb) => unsubscribe` | Watch for config changes | +| `initWatcher` | `() => void \| Promise` | One-time setup (optional) | +| `onWarnings` | `(warnings, isReload) => void` | Validation warnings (optional) | +| `onDebugLog` | `(message) => void` | Debug logging (optional) | + +### KeybindingsLoadResult + +```ts +type KeybindingsLoadResult = { + bindings: ParsedBinding[] + warnings: KeybindingWarning[] +} +``` + +### KeybindingWarning + +```ts +type KeybindingWarning = { + type: 'parse_error' | 'duplicate' | 'reserved' | 'invalid_context' | 'invalid_action' + severity: 'error' | 'warning' + message: string + key?: string + context?: string + action?: string + suggestion?: string +} +``` + +## KeybindingProvider + +Context provider that holds binding state and resolution logic. Automatically provided by `KeybindingSetup`. + +## useKeybinding + +Register a handler for a keybinding action. + +```tsx +import { useKeybinding } from '@anthropic/ink' + +function MyComponent() { + useKeybinding('app:toggleTodos', () => { + setShowTodos(prev => !prev) + }, { context: 'Global' }) + + // Return false to NOT consume the event (allow propagation) + useKeybinding('scroll:lineDown', () => { + if (!hasContent) return false // Don't consume + scrollBy(1) + }) +} +``` + +### Signature + +```ts +function useKeybinding( + action: string, + handler: () => void | false | Promise, + options?: { context?: string; isActive?: boolean } +): void +``` + +### Handler Return Values + +| Return | Effect | +|--------|--------| +| `undefined` / `void` | Event consumed, stop propagation | +| `false` | Event NOT consumed, propagate to other handlers | +| `Promise` | Async handler, treated as consumed | + +## useKeybindings + +Register multiple handlers in one hook (reduces `useInput` overhead). + +```tsx +import { useKeybindings } from '@anthropic/ink' + +useKeybindings({ + 'chat:submit': () => handleSubmit(), + 'chat:cancel': () => handleCancel(), + 'scroll:pageDown': () => { + scrollBy(viewportHeight) + }, + 'scroll:lineDown': () => { + if (!hasContent) return false + scrollBy(1) + }, +}, { context: 'Chat' }) +``` + +## Keybinding Contexts + +Contexts allow the same key to perform different actions depending on what's active. + +```tsx +// Register a context as active +import { useRegisterKeybindingContext } from '@anthropic/ink' + +function ThemePicker({ isOpen }) { + useRegisterKeybindingContext('ThemePicker', isOpen) + + // While open, 'ThemePicker' context bindings take precedence + useKeybinding('picker:select', handleSelect, { context: 'ThemePicker' }) + + return isOpen ? : null +} +``` + +Context resolution order: +1. Registered active contexts (most recent first) +2. The hook's own `context` parameter +3. `'Global'` (always checked last) + +## Chord Sequences + +Keybindings support multi-key sequences (chords): + +``` +"ctrl+k ctrl+s" → Save (press Ctrl+K, then Ctrl+S) +"ctrl+k ctrl+c" → Close (press Ctrl+K, then Ctrl+C) +``` + +When a chord prefix is pressed: +- `result.type === 'chord_started'` -- Show "Ctrl+K ..." pending indicator +- Next key completes or cancels the chord +- `result.type === 'chord_cancelled'` -- Invalid key, reset + +## KeybindingContext Hook + +```tsx +import { useKeybindingContext, useOptionalKeybindingContext } from '@anthropic/ink' + +const ctx = useKeybindingContext() +// ctx.resolve(input, key, contexts) → ResolveResult +// ctx.bindings → ParsedBinding[] +// ctx.pendingChord → ParsedKeystroke[] | null +// ctx.activeContexts → Set +// ctx.getDisplayText(action, context) → string | undefined +// ctx.invokeAction(action) → boolean +// ctx.registerHandler(registration) → () => void (unsubscribe) + +// Returns null outside provider (no throw) +const optionalCtx = useOptionalKeybindingContext() +``` + +## Parser Functions + +Parse and format keybinding strings: + +```tsx +import { + parseKeystroke, + parseChord, + keystrokeToString, + chordToString, + keystrokeToDisplayString, + chordToDisplayString, + parseBindings, +} from '@anthropic/ink' +``` + +### `parseKeystroke(str)` + +Parse a single keystroke string: + +```ts +parseKeystroke('ctrl+shift+enter') +// → { key: 'enter', ctrl: true, alt: false, shift: true, meta: false, super: false } +``` + +### `parseChord(str)` + +Parse a chord (space-separated keystrokes): + +```ts +parseChord('ctrl+k ctrl+s') +// → [{ key: 'k', ctrl: true, ... }, { key: 's', ctrl: true, ... }] +``` + +### `keystrokeToString(ks)` / `chordToString(chord)` + +Convert parsed keystroke/chord back to string. + +### `keystrokeToDisplayString(ks)` / `chordToDisplayString(chord)` + +Convert to human-readable display string (platform-aware). + +### `parseBindings(blocks)` + +Parse a keybinding configuration: + +```ts +parseBindings([ + { + context: 'Global', + bindings: { + 'ctrl+s': 'app:save', + 'ctrl+k ctrl+s': 'app:saveAs', + } + } +]) +// → ParsedBinding[] +``` + +## Match Functions + +```tsx +import { getKeyName, matchesKeystroke, matchesBinding } from '@anthropic/ink' +``` + +### `getKeyName(input, key)` + +Get the canonical key name from raw input: + +```ts +getKeyName('\x1b[A', { upArrow: true }) // 'up' +``` + +### `matchesKeystroke(input, key, target)` + +Check if raw input matches a parsed keystroke: + +```ts +matchesKeystroke('s', { ctrl: true, shift: false }, { key: 's', ctrl: true }) +``` + +### `matchesBinding(input, key, binding)` + +Check if raw input matches any keystroke in a binding's chord. + +## Resolver Functions + +```tsx +import { resolveKey, resolveKeyWithChordState, getBindingDisplayText } from '@anthropic/ink' +``` + +### `resolveKey(input, key, contexts, bindings)` + +Resolve input to a binding action: + +```ts +const result = resolveKey('s', { ctrl: true, shift: false }, ['Global'], bindings) +// result.type: 'match' | 'none' | 'unbound' +// result.action: string (when type === 'match') +``` + +### `resolveKeyWithChordState(input, key, contexts, bindings, pendingChord)` + +Resolve with chord state: + +```ts +const result = resolveKeyWithChordState('k', key, ['Global'], bindings, null) +// result.type: 'match' | 'none' | 'unbound' | 'chord_started' | 'chord_cancelled' +// result.pending: ParsedKeystroke[] (when type === 'chord_started') +``` + +### `getBindingDisplayText(action, context, bindings)` + +Get the display string for a binding: + +```ts +getBindingDisplayText('app:save', 'Global', bindings) // 'Ctrl+S' +``` diff --git a/packages/@ant/ink/docs/09-hooks-reference.md b/packages/@ant/ink/docs/09-hooks-reference.md new file mode 100644 index 000000000..16c4bbc18 --- /dev/null +++ b/packages/@ant/ink/docs/09-hooks-reference.md @@ -0,0 +1,407 @@ +# Chapter 9: Hooks Reference + +Complete API reference for all hooks exported by `@anthropic/ink`. + +--- + +## Application Hooks + +### `useApp()` + +Access app-level operations. + +```ts +function useApp(): { + exit: (error?: Error) => void +} +``` + +Example: +```tsx +const { exit } = useApp() +// Gracefully unmount and exit +exit() +``` + +### `useStdin()` + +Access the stdin stream and raw mode control. + +```ts +function useStdin(): { + stdin: NodeJS.ReadStream + isRawModeSupported: boolean + setRawMode: (enabled: boolean) => void + internal_exitOnCtrlC: boolean + internal_eventEmitter: EventEmitter | undefined + internal_querier: TerminalQuerier | null +} +``` + +> Prefer `useInput` for keyboard handling. + +--- + +## Input Hooks + +### `useInput(handler, options?)` + +Handle keyboard input. See [Chapter 7](./07-user-input.md) for full details. + +```ts +function useInput( + handler: (input: string, key: Key, event: InputEvent) => void, + options?: { isActive?: boolean } +): void +``` + +--- + +## Terminal Hooks + +### `useTerminalSize()` + +Get current terminal dimensions. + +```ts +function useTerminalSize(): { + columns: number + rows: number +} +``` + +Throws if used outside ``. + +### `useTerminalFocus()` + +Track whether the terminal window is focused. + +```ts +function useTerminalFocus(): boolean +``` + +Uses DECSET 1004 focus reporting. Returns `true` when focused. + +### `useTerminalTitle(title)` + +Set the terminal window title. + +```ts +function useTerminalTitle(title: string | null): void +``` + +Pass `null` to clear the title. + +### `useTerminalViewport()` + +Track element visibility in the terminal viewport. + +```ts +function useTerminalViewport(): [ + ref: (element: DOMElement | null) => void, + entry: { isVisible: boolean } +] +``` + +Example: +```tsx +const [viewportRef, { isVisible }] = useTerminalViewport() + + + {isVisible ? 'Visible' : 'Scrolled off'} + +``` + +### `useTabStatus(kind)` + +Set tab status indicator in terminal tab bar (OSC 21337). + +```ts +type TabStatusKind = 'idle' | 'busy' | 'waiting' +function useTabStatus(kind: TabStatusKind | null): void +``` + +### `useTerminalNotification()` + +Send terminal notifications (iTerm2, Kitty, Ghostty, bell). + +```ts +function useTerminalNotification(): { + notifyITerm2: (opts: { message: string; title?: string }) => void + notifyKitty: (opts: { message: string; title: string; id: number }) => void + notifyGhostty: (opts: { message: string; title: string }) => void + notifyBell: () => void + progress: (state: Progress['state'] | null, percentage?: number) => void +} +``` + +Requires `TerminalWriteProvider` in the tree. + +Progress states: `'running'`, `'completed'`, `'error'`, `'indeterminate'`, `null` (clear). + +--- + +## Animation & Timing Hooks + +### `useInterval(callback, intervalMs)` + +Clock-backed interval timer. + +```ts +function useInterval(callback: () => void, intervalMs: number | null): void +``` + +Pass `null` to pause. Shares the application clock for efficient batching. + +### `useAnimationTimer(intervalMs)` + +Returns the current clock time, updating at the given interval. + +```ts +function useAnimationTimer(intervalMs: number): number +``` + +Subscribes as non-keepAlive -- won't keep the clock running on its own. + +### `useAnimationFrame(intervalMs?)` + +Synchronized animation hook that pauses when offscreen. + +```ts +function useAnimationFrame( + intervalMs?: number | null, // default 16 +): [ref: (element: DOMElement | null) => void, time: number] +``` + +Returns a ref callback (attach to animated element) and the current animation time. All instances share the same clock. Pass `null` to pause. + +```tsx +const [ref, time] = useAnimationFrame(120) +const frame = Math.floor(time / 120) % FRAMES.length +return {FRAMES[frame]} +``` + +### `useTimeout(delayMs, resetTrigger?)` + +One-shot timer. + +```ts +function useTimeout(delay: number, resetTrigger?: number): boolean +``` + +Returns `true` when the timeout has elapsed. Change `resetTrigger` to restart. + +### `useMinDisplayTime(value, minMs)` + +Ensure a value is displayed for at least `minMs` milliseconds. + +```ts +function useMinDisplayTime(value: T, minMs: number): T +``` + +Holds the previous value until `minMs` has elapsed, then switches to the new value. + +Example: +```tsx +// Keep showing "Loading" for at least 300ms to prevent flash +const displayValue = useMinDisplayTime(isLoading ? 'loading' : 'done', 300) +``` + +--- + +## Interaction Hooks + +### `useDoublePress(setPending, onDoublePress, onFirstPress?)` + +Detect double-press (double-click equivalent for keyboard). + +```ts +export const DOUBLE_PRESS_TIMEOUT_MS = 800 + +function useDoublePress( + setPending: (pending: boolean) => void, + onDoublePress: () => void, + onFirstPress?: () => void +): () => void // Returns the press handler +``` + +Example: +```tsx +const [pendingExit, setPendingExit] = useState(false) +const handlePress = useDoublePress( + setPendingExit, + () => exit(), // Double press + () => {}, // First press +) + +useInput((input, key) => { + if (key.escape) handlePress() +}) +``` + +### `useExitOnCtrlCD(options?)` + +Handle Ctrl+C / Ctrl+D with double-press confirmation. + +```ts +type ExitState = { + pending: boolean + keyName: 'Ctrl-C' | 'Ctrl-D' | null +} + +function useExitOnCtrlCDWithKeybindings( + onExit?: () => void, + onInterrupt?: () => boolean, + isActive?: boolean +): ExitState +``` + +Example: +```tsx +const exitState = useExitOnCtrlCDWithKeybindings( + () => exit(), + () => { /* return true to prevent exit */ } +) + +if (exitState.pending) { + return Press {exitState.keyName} again to exit +} +``` + +--- + +## Selection Hooks (Alt-Screen Only) + +### `useSelection()` + +Text selection operations. + +```ts +function useSelection(): { + copySelection: () => string + copySelectionNoClear: () => string + clearSelection: () => void + hasSelection: () => boolean + getState: () => SelectionState | null + subscribe: (cb: () => void) => () => void + shiftAnchor: (dRow: number, minRow: number, maxRow: number) => void + shiftSelection: (dRow: number, minRow: number, maxRow: number) => void + moveFocus: (move: FocusMove) => void + captureScrolledRows: (firstRow: number, lastRow: number, side: 'above' | 'below') => void + setSelectionBgColor: (color: string) => void +} +``` + +### `useHasSelection()` + +Reactive boolean for selection state. + +```ts +function useHasSelection(): boolean +``` + +Re-renders when selection is created or cleared. + +--- + +## Search Hooks + +### `useSearchHighlight()` + +Set and manage search highlighting. + +```ts +function useSearchHighlight(): { + setQuery: (query: string) => void + scanElement: (el: DOMElement) => MatchPosition[] + setPositions: (state: { positions: MatchPosition[]; rowOffset: number; currentIdx: number } | null) => void +} +``` + +### `useSearchInput(options)` + +Search input handler with cursor management. + +```ts +type UseSearchInputOptions = { + isActive: boolean + onExit: () => void + onCancel?: () => void + onExitUp?: () => void + columns?: number + passthroughCtrlKeys?: string[] + initialQuery?: string + backspaceExitsOnEmpty?: boolean +} + +type UseSearchInputReturn = { + query: string + setQuery: (q: string) => void + cursorOffset: number + handleKeyDown: (e: KeyboardEvent) => void +} + +function useSearchInput(options: UseSearchInputOptions): UseSearchInputReturn +``` + +--- + +## Cursor Hooks + +### `useDeclaredCursor(options)` + +Park the terminal cursor at a specific position for IME and accessibility. + +```ts +function useDeclaredCursor({ + line: number, + column: number, + active: boolean +}): (element: DOMElement | null) => void +``` + +Returns a ref callback. Position is relative to the ref'd element. + +Example: +```tsx +const cursorRef = useDeclaredCursor({ + line: 0, + column: cursorPosition, + active: isFocused, +}) + +return ... +``` + +--- + +## Tab Status Hooks + +### `useTabStatus(kind)` + +Set tab status indicator (OSC 21337) for terminal tab bars. + +```ts +type TabStatusKind = 'idle' | 'busy' | 'waiting' + +function useTabStatus(kind: TabStatusKind | null): void +``` + +Pass `null` to clear. + +--- + +## Viewport Hooks + +### `useTerminalViewport()` + +Track element visibility within the terminal viewport. + +```ts +function useTerminalViewport(): [ + ref: (element: DOMElement | null) => void, + entry: { isVisible: boolean } +] +``` + +Returns a ref callback and visibility state. diff --git a/packages/@ant/ink/docs/10-events-and-focus.md b/packages/@ant/ink/docs/10-events-and-focus.md new file mode 100644 index 000000000..74b524122 --- /dev/null +++ b/packages/@ant/ink/docs/10-events-and-focus.md @@ -0,0 +1,232 @@ +# Chapter 10: Events & Focus + +## Event System + +Ink implements a DOM-like event system with capture/bubble phases, propagation control, and prioritized dispatch. + +### Event Classes + +All events extend the base `Event` class: + +```ts +class Event { + stopImmediatePropagation(): void +} +``` + +### InputEvent + +Emitted for every keystroke or input action. + +```ts +class InputEvent extends Event { + readonly input: string // Character(s) entered + readonly key: Key // Parsed key metadata + readonly keypress: ParsedKey // Raw keypress data +} +``` + +### KeyboardEvent + +DOM-like keyboard event for focused elements. + +```ts +class KeyboardEvent extends Event { + readonly key: Key +} +``` + +Dispatched via `onKeyDown` / `onKeyDownCapture` on `Box`. + +### ClickEvent + +Mouse click event (alt-screen only). + +```ts +class ClickEvent extends Event { + readonly x: number // Column (0-indexed) + readonly y: number // Row (0-indexed) +} +``` + +Clicks bubble from the deepest hit Box up through ancestors. + +### FocusEvent + +Focus change event. + +```ts +class FocusEvent extends Event { + readonly relatedTarget: DOMElement | null +} +``` + +### TerminalFocusEvent + +Terminal window focus change. + +```ts +class TerminalFocusEvent extends Event { + readonly type: 'terminalfocus' | 'terminalblur' +} +``` + +### ResizeEvent + +Terminal resize event (internal). + +### PasteEvent + +Pasted text event (bracketed paste mode). + +## Event Dispatch Flow + +``` +stdin data → parse-keypress → InputEvent + ↓ + App.handleInput (useInput handlers) + ↓ + Box.onKeyDown (focused element, bubble) +``` + +### Capture and Bubble Phases + +```tsx + { + // Capture phase: fires top-down + console.log('Parent captures key') + }} + onKeyDown={(e) => { + // Bubble phase: fires bottom-up + console.log('Parent receives bubbled key') + }} +> + { + // Target: fires first in bubble phase + console.log('Child handles key') + e.stopImmediatePropagation() // Stop here + }} + > + Focus here + + +``` + +### Event Propagation Methods + +| Method | Effect | +|--------|--------| +| `event.stopImmediatePropagation()` | Stop all subsequent handlers | +| `event.preventDefault()` | Not supported in terminal context | + +## FocusManager + +DOM-like focus management system. + +### How Focus Works + +1. Elements with `tabIndex >= 0` participate in Tab/Shift+Tab cycling +2. Elements with `tabIndex === -1` are programmatically focusable only +3. Elements with `autoFocus` receive focus on mount +4. Clicking a focusable element focuses it + +### Focus API + +```ts +class FocusManager { + activeElement: DOMElement | null + + focus(node: DOMElement): void + blur(): void + focusNext(root: DOMElement): void // Tab + focusPrevious(root: DOMElement): void // Shift+Tab + + handleNodeRemoved(node: DOMElement, root: DOMElement): void + handleAutoFocus(node: DOMElement): void + handleClickFocus(node: DOMElement): void + + enable(): void + disable(): void +} +``` + +### Tab Navigation + +```tsx + + + + + +``` + +### Auto Focus + +```tsx + + Receives focus immediately on mount + +``` + +### Focus Events + +```tsx + console.log('Got focus')} + onBlur={(e) => console.log('Lost focus')} + onFocusCapture={(e) => console.log('Capture: focus in')} + onBlurCapture={(e) => console.log('Capture: focus out')} +> + Focusable element + +``` + +## Hit Testing + +Mouse click/hover resolution: + +1. Screen coordinates are mapped to DOM elements via Yoga layout +2. The deepest element at the click position is the target +3. Click events bubble upward through ancestors +4. Hover events use `mouseenter`/`mouseleave` semantics (no bubbling between children) + +### Click Hit Testing + +```ts +dispatchClick(rootNode, col, row): void +``` + +Walks the DOM tree, finds the deepest Box at (col, row), fires `onClick`, then bubbles to ancestors. + +### Hover Hit Testing + +```ts +dispatchHover(rootNode, col, row, hoveredNodes): void +``` + +Tracks which nodes are under the pointer. Fires `onMouseEnter`/`onMouseLeave` as the pointer moves between elements. + +## EventEmitter + +Custom event emitter for internal use: + +```ts +class EventEmitter { + on(event: string, handler: Function): void + off(event: string, handler: Function): void + emit(event: string, ...args: any[]): void + removeListener(event: string, handler: Function): void +} +``` + +Used internally by the Ink instance for `input` events. diff --git a/packages/@ant/ink/docs/11-core-architecture.md b/packages/@ant/ink/docs/11-core-architecture.md new file mode 100644 index 000000000..ae9467326 --- /dev/null +++ b/packages/@ant/ink/docs/11-core-architecture.md @@ -0,0 +1,301 @@ +# Chapter 11: Core Architecture + +This chapter covers the internal rendering pipeline, DOM model, and screen buffer system. This is advanced material -- most users only need the component and hooks APIs. + +## Rendering Pipeline + +``` +React Component Tree + ↓ (React reconciler) +Ink DOM Tree (virtual terminal DOM) + ↓ (Yoga layout) +Positioned DOM Tree (computed x, y, width, height) + ↓ (renderNodeToOutput) +Output Buffer (styled characters) + ↓ (renderer → Screen) +Screen Buffer (Int32Array of cells) + ↓ (diffEach) +ANSI Diff Patches (minimal escape sequences) + ↓ (writeDiffToTerminal) +Terminal stdout +``` + +### Frame Lifecycle + +Each render cycle (`onRender`) follows these phases: + +1. **React Commit** -- React reconciles the virtual tree; host config updates Ink DOM +2. **Yoga Layout** -- All dirty nodes have their styles applied and layout computed +3. **Renderer** -- Creates Output buffer, calls `renderNodeToOutput` for the full tree +4. **Screen Diff** -- New frame is compared against previous frame cell-by-cell +5. **Optimize** -- Patches are merged and ordered for minimal cursor movement +6. **Write** -- ANSI escape sequences are written to stdout + +### Frame Timing + +```ts +const FRAME_INTERVAL_MS = 16 // ~60fps cap +``` + +Renders are throttled. Multiple state updates in one frame are batched. + +### Double Buffering + +Two frames are maintained: + +- **`frontFrame`** -- The currently displayed frame +- **`backFrame`** -- The frame being rendered + +After rendering, they are swapped. This prevents partial updates from being visible. + +## Ink DOM + +### Node Types + +```ts +type ElementNames = + | 'ink-root' // Root container + | 'ink-box' // Box component + | 'ink-text' // Text component + | 'ink-virtual-text' // Intermediate text wrapper + | 'ink-link' // Link component + | 'ink-raw-ansi' // Raw ANSI content +``` + +### DOMElement + +```ts +type DOMElement = { + nodeName: ElementNames + attributes: Record + childNodes: DOMNode[] // DOMElement | TextNode + yogaNode?: LayoutNode // Yoga layout node + textStyles?: TextStyles // Inherited text styles + + // Scroll state + scrollTop?: number + scrollHeight?: number + scrollViewportHeight?: number + scrollViewportTop?: number + stickyScroll?: boolean + pendingScrollDelta?: number + scrollAnchor?: { el: DOMElement; offset: number } + + // Dirty tracking + dirty: boolean + + // Event handlers (stored separately) + onClick?: (event: ClickEvent) => void + onFocus?: (event: FocusEvent) => void + onBlur?: (event: FocusEvent) => void + onKeyDown?: (event: KeyboardEvent) => void + onMouseEnter?: () => void + onMouseLeave?: () => void +} +``` + +### TextNode + +```ts +type TextNode = { + nodeName: '#text' + nodeValue: string + yogaNode?: LayoutNode +} +``` + +### DOM Operations + +```ts +// Node creation +createNode(nodeName: string): DOMElement +createTextNode(text: string): TextNode + +// Tree manipulation +appendChildNode(parent: DOMElement, child: DOMNode): void +insertBeforeNode(parent: DOMElement, child: DOMNode, before: DOMNode): void +removeChildNode(parent: DOMElement, child: DOMNode): void + +// Attribute manipulation +setAttribute(node: DOMElement, key: string, value: unknown): void +setStyle(node: DOMElement, style: Styles): void +setTextStyles(node: DOMElement, styles: TextStyles): void + +// Dirty tracking +markDirty(node: DOMElement): void +scheduleRenderFrom(node: DOMElement): void +``` + +## Screen Buffer + +### Cell Storage + +The screen buffer uses packed `Int32Array` storage for memory efficiency: + +```ts +type Screen = { + width: number + height: number + cells: Int32Array // 2 Int32s per cell: [charId, packed_style_hyperlink_width] + cells64: BigInt64Array // For bulk fill operations + charPool: CharPool // String interning + stylePool: StylePool // ANSI code interning + hyperlinkPool: HyperlinkPool + emptyStyleId: number + damage: Rectangle | undefined // Bounding box of changed cells + noSelect: Uint8Array // Per-cell no-select bitmap + softWrap: Int32Array // Per-row soft-wrap markers +} +``` + +### Cell Width + +```ts +enum CellWidth { + Narrow = 0, // Regular character (1 column) + Wide = 1, // CJK/emoji (2 columns) + SpacerTail = 2, // Right half of wide character + SpacerHead = 3, // Soft-wrapped wide character +} +``` + +### Style Pool + +ANSI style codes are interned for efficiency: + +```ts +class StylePool { + intern(codes: AnsiCode[]): number // Returns compact ID + get(id: number): AnsiCode[] + transition(from: number, to: number): string // Cached ANSI transition + withInverse(id: number): number // Selection overlay + setSelectionBg(bg: AnsiCode): void // Theme-aware selection bg +} +``` + +### Diff Algorithm + +```ts +diffEach(prev: Screen, next: Screen, callback: (x, y, oldCell, newCell) => void): void +``` + +Only iterates cells within the damage bounding box. Unchanged regions are skipped entirely. + +### Screen Operations + +```ts +createScreen(width, height, stylePool, charPool, hyperlinkPool): Screen +setCellAt(screen, x, y, cell): void +cellAt(screen, x, y): Cell +clearRegion(screen, x, y, width, height): void +blitRegion(dst, src, x, y, maxX, maxY): void +shiftRows(screen, top, bottom, n): void +``` + +## Layout Engine + +### Yoga Integration + +Ink wraps Facebook's Yoga layout engine for Flexbox computation: + +```ts +// Layout node types +enum LayoutDisplay { Flex, None } +enum LayoutPositionType { Absolute, Relative } +enum LayoutOverflow { Visible, Hidden, Scroll } +enum LayoutFlexDirection { Row, Column, RowReverse, ColumnReverse } +enum LayoutWrap { NoWrap, Wrap, WrapReverse } +enum LayoutAlign { FlexStart, Center, FlexEnd, Stretch } +enum LayoutJustify { FlexStart, Center, FlexEnd, SpaceBetween, SpaceAround, SpaceEvenly } +enum LayoutEdge { Top, Bottom, Left, Right, Start, End, Horizontal, Vertical, All } +enum LayoutGutter { Column, Row, All } +``` + +### Style Application + +Styles from React props are applied to Yoga nodes during the commit phase: + +```ts +function styles(node: LayoutNode, style: Styles, resolvedStyle?: Styles): void +``` + +This function maps each CSS-like prop to the corresponding Yoga setter. + +## Output Buffer + +Intermediate rendering target before screen diff: + +```ts +class Output { + write(text: string, x: number, y: number, styles: TextStyles): void + wrap(width: number, textWrap: TextWrap): void +} +``` + +`renderNodeToOutput` walks the DOM tree and writes styled characters into this buffer. + +## Reconciler + +Custom React reconciler that bridges React and the Ink DOM: + +- **Host config** -- Defines how React operations map to Ink DOM mutations +- **Concurrent mode** -- Supports `ConcurrentRoot` for React 19 features +- **Yoga integration** -- Applies styles during commit phase +- **DevTools** -- Connected in development mode + +### Host Config Methods + +| Method | Purpose | +|--------|---------| +| `createInstance` | Create `ink-box`, `ink-text`, etc. | +| `createTextInstance` | Create `#text` node | +| `appendChildNode` | Add child to parent | +| `removeChildNode` | Remove child from parent | +| `insertBefore` | Insert child before sibling | +| `commitUpdate` | Update element attributes/styles | +| `commitTextUpdate` | Update text content | +| `getPublicInstance` | Return DOMElement for refs | + +## Performance Optimizations + +1. **String Interning** -- CharPool deduplicates character strings across frames +2. **Style Caching** -- StylePool caches ANSI transition strings +3. **Damage Tracking** -- Only diff cells within the changed bounding box +4. **Bulk Operations** -- `Int32Array.set()` for fast region blit +5. **Throttled Rendering** -- Frame rate capped at ~60fps +6. **Viewport Culling** -- ScrollBox only renders visible children +7. **Microtask Coalescing** -- Multiple scroll deltas merged into one render + +## Frame Events + +Debug instrumentation for render performance: + +```ts +type FrameEvent = { + durationMs: number + phases: { + renderer: number // Yoga + renderNodeToOutput + diff: number // Screen diff + optimize: number // Patch optimization + write: number // Terminal write + patches: number // Number of ANSI patches + yoga: number // Yoga layout time + commit: number // React commit time + yogaVisited: number // Yoga nodes visited + yogaMeasured: number // Yoga nodes measured + yogaCacheHits: number // Cached measurements + yogaLive: number // Active Yoga nodes + } + flickers: FlickerReason[] +} +``` + +Enable with `onFrame` in RenderOptions: + +```tsx +render(, { + onFrame: (event) => { + console.log(`Frame: ${event.durationMs}ms`) + } +}) +``` diff --git a/packages/@ant/ink/docs/12-terminal-integration.md b/packages/@ant/ink/docs/12-terminal-integration.md new file mode 100644 index 000000000..4ecd33b26 --- /dev/null +++ b/packages/@ant/ink/docs/12-terminal-integration.md @@ -0,0 +1,381 @@ +# Chapter 12: Terminal Integration + +This chapter covers terminal-specific features: alternate screen, mouse tracking, clipboard, notifications, and terminal querying. + +## Alternate Screen + +Enter a fullscreen alternate screen buffer (like vim, less, htop). + +```tsx +import { AlternateScreen } from '@anthropic/ink' + + + + Fullscreen content + + +``` + +### Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `children` | `ReactNode` | - | Content | +| `mouseTracking` | `boolean` | `true` | Enable SGR mouse tracking | + +### Behavior + +On mount: +1. Enters DEC 1049 alternate screen buffer +2. Hides cursor +3. Enables mouse tracking (if `mouseTracking=true`) +4. Constrains rendering height to terminal rows + +On unmount: +1. Exits alternate screen buffer +2. Shows cursor +3. Disables mouse tracking +4. Restores original terminal content + +### Mouse Tracking Modes + +When enabled: +- **Mode 1003** -- Button press/release + motion (hover) +- **Mode 1006** -- SGR extended mouse format (coordinates > 223) +- **Wheel events** -- Scroll up/down + +### External Editor Handoff + +The Ink instance supports pausing for an external editor: + +```ts +// Pause Ink, run external command, resume +ink.enterAlternateScreen() // Save state +// ... external editor runs ... +ink.reassertTerminalModes() // Restore on resume +``` + +This is triggered by Ctrl+Z (SIGTSTP) and SIGCONT. + +## Mouse Events + +### Click Events + +```tsx + { + console.log(`Clicked at col=${event.x}, row=${event.y}`) + event.stopImmediatePropagation() +}}> + Clickable area + +``` + +### Multi-Click + +Double-click selects a word, triple-click selects a line. Handled by the App component: + +```ts +// App prop +onMultiClick: (col: number, row: number, count: 2 | 3) => void +``` + +### Hover Events + +```tsx + setHovered(true)} + onMouseLeave={() => setHovered(false)} +> + {hovered ? 'Hovered!' : 'Hover me'} + +``` + +Hover uses `mouseenter`/`mouseleave` semantics (no bubbling between children). + +### Drag-to-Select + +In alt-screen mode, click-drag creates a text selection: + +```ts +// App prop +onSelectionDrag: (col: number, row: number) => void +``` + +## Clipboard + +### OSC 52 Clipboard + +```tsx +import { setClipboard } from '@anthropic/ink' + +await setClipboard('Copied text') +``` + +### Copy Selection + +```tsx +const { copySelection } = useSelection() +const text = copySelection() // Copies to clipboard and clears highlight +``` + +### Copy Without Clear + +```tsx +const { copySelectionNoClear } = useSelection() +const text = copySelectionNoClear() // Copies but keeps highlight +``` + +## Terminal Notifications + +Send desktop notifications from the terminal. + +```tsx +import { useTerminalNotification } from '@anthropic/ink' + +function MyComponent() { + const { notifyBell, progress } = useTerminalNotification() + + // Terminal bell (audible/system notification) + notifyBell() + + // Progress bar in terminal title/tab + progress('running', 65) // 65% complete + progress('completed') // Done + progress('error') // Error state + progress('indeterminate') // Unknown progress + progress(null) // Clear +} +``` + +### Terminal-Specific Notifications + +```tsx +const { notifyITerm2, notifyKitty, notifyGhostty } = useTerminalNotification() + +// iTerm2 +notifyITerm2({ message: 'Build complete', title: 'My App' }) + +// Kitty +notifyKitty({ message: 'Build complete', title: 'My App', id: 1 }) + +// Ghostty +notifyGhostty({ message: 'Build complete', title: 'My App' }) +``` + +## Terminal Queries + +### Background Color (OSC 11) + +Used for auto-theme detection: + +```ts +import { getTerminalBackground } from '@anthropic/ink' +const bg = await getTerminalBackground() +// e.g., 'rgb:0000/0000/0000' (dark) or 'rgb:ffff/ffff/ffff' (light) +``` + +### Terminal Version (XTVERSION) + +```ts +import { isXtermJs, setXtversionName, getXtversionName } from '@anthropic/ink' +``` + +### Feature Detection + +```ts +import { supportsHyperlinks } from '@anthropic/ink' + +if (supportsHyperlinks()) { + // OSC 8 hyperlinks supported +} + +import { supportsExtendedKeys } from '@anthropic/ink' + +if (supportsExtendedKeys()) { + // Kitty keyboard protocol / modifyOtherKeys available +} +``` + +## Terminal Focus + +Track terminal window focus/unfocus: + +```tsx +import { useTerminalFocus } from '@anthropic/ink' + +const isFocused = useTerminalFocus() +``` + +Low-level API: + +```ts +import { getTerminalFocused, subscribeTerminalFocus } from '@anthropic/ink' + +getTerminalFocused() // boolean +subscribeTerminalFocus((focused: boolean) => { + // Called on focus change +}) +``` + +Uses DECSET 1004 focus reporting. + +## Terminal Title + +Set the terminal window title: + +```tsx +import { useTerminalTitle } from '@anthropic/ink' + +useTerminalTitle('My App - Dashboard') +``` + +Clear: + +```tsx +useTerminalTitle(null) +``` + +## Terminal I/O Sequences + +Low-level ANSI sequence constants for advanced use. + +### Cursor Control + +```ts +import { + SHOW_CURSOR, + HIDE_CURSOR, + CURSOR_HOME, +} from '@anthropic/ink' + +// cursorPosition(row, col) -- Move cursor to absolute position +// cursorMove(dx, dy) -- Move cursor relative +``` + +### Screen Control + +```ts +import { + ENTER_ALT_SCREEN, + EXIT_ALT_SCREEN, + ERASE_SCREEN, +} from '@anthropic/ink' +``` + +### Mouse Control + +```ts +import { + ENABLE_MOUSE_TRACKING, + DISABLE_MOUSE_TRACKING, +} from '@anthropic/ink' +``` + +### Keyboard Protocols + +```ts +import { + ENABLE_KITTY_KEYBOARD, + DISABLE_KITTY_KEYBOARD, + ENABLE_MODIFY_OTHER_KEYS, + DISABLE_MODIFY_OTHER_KEYS, +} from '@anthropic/ink' +``` + +### Clipboard & Tab Status + +```ts +import { + CLEAR_ITERM2_PROGRESS, + CLEAR_TAB_STATUS, + CLEAR_TERMINAL_TITLE, + wrapForMultiplexer, +} from '@anthropic/ink' +``` + +`wrapForMultiplexer` wraps OSC sequences for tmux compatibility. + +## Terminal Compatibility + +### Supported Terminals + +| Terminal | Features | +|----------|----------| +| iTerm2 | Full support (hyperlinks, notifications, progress) | +| Kitty | Full support (keyboard protocol, notifications) | +| Ghostty | Full support | +| WezTerm | Full support | +| Alacritty | Most features | +| Windows Terminal | Most features | +| Apple Terminal | 256-color fallback | +| xterm.js (VS Code) | Detected and special-cased | +| tmux | Wrapped sequences via `wrapForMultiplexer` | +| Screen | Basic support | + +### Feature Degradation + +The framework gracefully degrades: +- No true color → Falls back to ANSI 16-color themes +- No OSC 52 → Clipboard operations silently fail +- No mouse tracking → Click/hover events are no-ops +- No extended keys → Standard escape sequences used +- No bracketed paste → Paste detected by timing heuristic + +### Synchronized Output + +```ts +import { isSynchronizedOutputSupported } from '@anthropic/ink' + +if (isSynchronizedOutputSupported()) { + // BSU/ESU for tear-free rendering +} +``` + +Uses DECSET 2026 synchronized output to prevent partial frame display. + +### Bracketed Paste + +Uses DECSET 2004 to distinguish paste events from rapid typing. Automatically enabled by the App component. + +## Text Selection (Alt-Screen) + +### Selection State + +```ts +type SelectionState = { + anchor: Point | null // Drag start + focus: Point | null // Current position + isDragging: boolean + anchorSpan: { lo: Point; hi: Point; kind: 'word' | 'line' } | null + scrolledOffAbove: string[] // Text scrolled out above + scrolledOffBelow: string[] // Text scrolled out below +} +``` + +### Selection Operations + +- **Click-drag** -- Free-form selection +- **Double-click** -- Word selection +- **Triple-click** -- Line selection +- **Shift+Arrow** -- Extend selection from keyboard +- **Drag-to-scroll** -- Auto-scroll when dragging near edges + +### noSelect Regions + +Exclude areas from selection (gutters, line numbers): + +```tsx + + 1 │ + + + code here {/* Only this is selectable */} + +``` + +### Soft-Wrap Awareness + +Selection correctly handles text that was wrapped across multiple rows: +- Wrapped lines are joined when copied +- Trailing whitespace is trimmed +- The `softWrap` bitmap tracks which rows are continuations diff --git a/packages/@ant/ink/docs/README.md b/packages/@ant/ink/docs/README.md new file mode 100644 index 000000000..423fe9acd --- /dev/null +++ b/packages/@ant/ink/docs/README.md @@ -0,0 +1,46 @@ +# @anthropic/ink Documentation + +A terminal React rendering framework for building rich command-line interfaces. + +## Architecture Overview + +`@anthropic/ink` is a forked/internal Ink framework that renders React components directly to the terminal using ANSI escape sequences. It uses Yoga (via a custom layout engine) for Flexbox layout, a custom React reconciler for terminal DOM, and a screen-buffer differ for efficient updates. + +### Three-Layer Architecture + +``` +┌─────────────────────────────────────────┐ +│ Layer 3: Theme │ +│ ThemeProvider, ThemedBox, ThemedText, │ +│ Dialog, FuzzyPicker, ProgressBar, etc. │ +├─────────────────────────────────────────┤ +│ Layer 2: Components │ +│ Box, Text, ScrollBox, Button, Link, │ +│ Newline, Spacer, AlternateScreen │ +├─────────────────────────────────────────┤ +│ Layer 1: Core │ +│ Reconciler, Layout (Yoga), Terminal │ +│ I/O, Screen Buffer, Event System │ +└─────────────────────────────────────────┘ +``` + +- **Core** (`src/core/`) -- Rendering engine: React reconciler, Yoga flexbox layout, terminal I/O, screen buffer with diff-based updates, event system (keyboard, mouse, focus, click). +- **Components** (`src/components/`) -- UI primitives: `Box`, `Text`, `ScrollBox`, `Button`, `Link`, `Newline`, `Spacer`, etc. Plus context providers (`App`, `StdinContext`). +- **Theme** (`src/theme/`) -- Theme system: `ThemeProvider`, theme-aware `Box`/`Text` wrappers, and design-system components (`Dialog`, `FuzzyPicker`, `ProgressBar`, `Tabs`, etc.). + +### Documentation + +| Chapter | File | Contents | +|---------|------|----------| +| 1 | [Getting Started](./01-getting-started.md) | Installation, rendering, basic concepts | +| 2 | [Layout System](./02-layout.md) | Box, Flexbox, Yoga, positioning, dimensions | +| 3 | [Text & Styling](./03-text-and-styling.md) | Text component, colors, text wrapping, ANSI styling | +| 4 | [Theme System](./04-theme-system.md) | ThemeProvider, themes, ThemedBox, ThemedText, color() | +| 5 | [Design System Components](./05-design-system.md) | Dialog, ProgressBar, FuzzyPicker, Tabs, Spinner, etc. | +| 6 | [Scrolling](./06-scrolling.md) | ScrollBox, sticky scroll, imperative scroll API | +| 7 | [User Input](./07-user-input.md) | useInput, Key types, raw mode, mouse events | +| 8 | [Keybinding System](./08-keybindings.md) | KeybindingProvider, useKeybinding, chord sequences, parser | +| 9 | [Hooks Reference](./09-hooks-reference.md) | All hooks with full API signatures | +| 10 | [Events & Focus](./10-events-and-focus.md) | Event system, FocusManager, click/hover, tab navigation | +| 11 | [Core Architecture](./11-core-architecture.md) | Reconciler, screen buffer, terminal I/O, rendering pipeline | +| 12 | [Terminal Integration](./12-terminal-integration.md) | Alternate screen, mouse tracking, clipboard, notifications | diff --git a/packages/agent-tools/package.json b/packages/agent-tools/package.json new file mode 100644 index 000000000..83e3e124c --- /dev/null +++ b/packages/agent-tools/package.json @@ -0,0 +1,11 @@ +{ + "name": "@claude-code-best/agent-tools", + "version": "1.0.0", + "private": true, + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "dependencies": { + "zod": "^3.25.0" + } +} diff --git a/packages/agent-tools/src/__tests__/compat.test.ts b/packages/agent-tools/src/__tests__/compat.test.ts new file mode 100644 index 000000000..4ffd4a6e7 --- /dev/null +++ b/packages/agent-tools/src/__tests__/compat.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, test } from 'bun:test' +import type { CoreTool, Tool, Tools, AnyObject, ToolResult, ValidationResult, PermissionResult } from '@claude-code-best/agent-tools' +import type { Tool as HostTool } from '../../src/Tool.js' + +describe('agent-tools compatibility', () => { + test('CoreTool structural compatibility with host Tool', () => { + // The host's Tool should structurally satisfy CoreTool + // because it has all required fields (name, call, description, etc.) + // This test verifies the type-level compatibility at runtime + const mockHostTool: HostTool = { + name: 'test', + aliases: [], + searchHint: 'test tool', + inputSchema: {} as any, + async call() { return { data: 'ok' } as any }, + async description() { return 'test' }, + async prompt() { return 'test prompt' }, + isConcurrencySafe: () => false, + isEnabled: () => true, + isReadOnly: () => false, + async checkPermissions() { return { behavior: 'allow' as const, updatedInput: {} } }, + toAutoClassifierInput: () => '', + userFacingName: () => 'test', + maxResultSizeChars: 100000, + mapToolResultToToolResultBlockParam: () => ({ type: 'tool_result', tool_use_id: '1', content: 'ok' }), + renderToolUseMessage: () => null, + } + + // This assignment should work if HostTool structurally extends CoreTool + const coreTool: CoreTool = mockHostTool as CoreTool + expect(coreTool.name).toBe('test') + expect(coreTool.isEnabled()).toBe(true) + }) +}) diff --git a/packages/agent-tools/src/__tests__/registry.test.ts b/packages/agent-tools/src/__tests__/registry.test.ts new file mode 100644 index 000000000..c35aa9d1e --- /dev/null +++ b/packages/agent-tools/src/__tests__/registry.test.ts @@ -0,0 +1,63 @@ +import { describe, expect, test } from 'bun:test' +import { findToolByName, toolMatchesName } from '../registry.js' +import type { CoreTool, Tools } from '../types.js' + +describe('toolMatchesName', () => { + test('matches primary name', () => { + expect(toolMatchesName({ name: 'bash' }, 'bash')).toBe(true) + }) + + test('does not match different name', () => { + expect(toolMatchesName({ name: 'bash' }, 'read')).toBe(false) + }) + + test('matches alias', () => { + expect(toolMatchesName({ name: 'bash', aliases: ['shell', 'sh'] }, 'shell')).toBe(true) + expect(toolMatchesName({ name: 'bash', aliases: ['shell', 'sh'] }, 'sh')).toBe(true) + }) + + test('handles empty aliases', () => { + expect(toolMatchesName({ name: 'bash', aliases: [] }, 'bash')).toBe(true) + expect(toolMatchesName({ name: 'bash', aliases: [] }, 'shell')).toBe(false) + }) + + test('handles undefined aliases', () => { + expect(toolMatchesName({ name: 'bash' }, 'bash')).toBe(true) + expect(toolMatchesName({ name: 'bash' }, 'shell')).toBe(false) + }) +}) + +describe('findToolByName', () => { + const tools: Tools = [ + { name: 'bash' } as CoreTool, + { name: 'read', aliases: ['cat'] } as CoreTool, + { name: 'write', aliases: ['edit'] } as CoreTool, + ] + + test('finds tool by primary name', () => { + expect(findToolByName(tools, 'bash')?.name).toBe('bash') + }) + + test('finds tool by alias', () => { + expect(findToolByName(tools, 'cat')?.name).toBe('read') + expect(findToolByName(tools, 'edit')?.name).toBe('write') + }) + + test('returns undefined for unknown name', () => { + expect(findToolByName(tools, 'unknown')).toBeUndefined() + }) + + test('handles empty tools array', () => { + expect(findToolByName([], 'bash')).toBeUndefined() + }) + + test('returns first match for duplicate names', () => { + const dupTools: Tools = [ + { name: 'tool', aliases: ['a'] } as CoreTool, + { name: 'tool', aliases: ['b'] } as CoreTool, + ] + const found = findToolByName(dupTools, 'tool') + expect(found).toBeDefined() + expect(found!.aliases).toContain('a') + }) +}) diff --git a/packages/agent-tools/src/index.ts b/packages/agent-tools/src/index.ts new file mode 100644 index 000000000..3a9ce1334 --- /dev/null +++ b/packages/agent-tools/src/index.ts @@ -0,0 +1,18 @@ +// agent-tools — Tool interface definitions and registry utilities +// Pure types + pure functions, zero runtime dependencies + +export type { + AnyObject, + ToolInputJSONSchema, + ToolProgressData, + ToolProgress, + ToolCallProgress, + ToolResult, + ValidationResult, + PermissionResult, + CoreTool, + Tool, + Tools, +} from './types.js' + +export { findToolByName, toolMatchesName } from './registry.js' diff --git a/packages/agent-tools/src/registry.ts b/packages/agent-tools/src/registry.ts new file mode 100644 index 000000000..e1038bc8c --- /dev/null +++ b/packages/agent-tools/src/registry.ts @@ -0,0 +1,21 @@ +import type { CoreTool, Tools } from './types.js' + +/** + * Checks if a tool matches the given name (primary name or alias). + */ +export function toolMatchesName( + tool: { name: string; aliases?: string[] }, + name: string, +): boolean { + return tool.name === name || (tool.aliases?.includes(name) ?? false) +} + +/** + * Finds a tool by name or alias from a list of tools. + */ +export function findToolByName( + tools: Tools, + name: string, +): CoreTool | undefined { + return tools.find(t => toolMatchesName(t, name)) +} diff --git a/packages/agent-tools/src/types.ts b/packages/agent-tools/src/types.ts new file mode 100644 index 000000000..611be167e --- /dev/null +++ b/packages/agent-tools/src/types.ts @@ -0,0 +1,221 @@ +// agent-tools — Core Tool interface definitions +// Protocol-level types, independent of any host framework + +import type { z } from 'zod/v4' + +// ============================================================================ +// Schema types +// ============================================================================ + +/** + * Zod schema type for any object with string keys. + * Used as the Input generic constraint for Tool. + */ +export type AnyObject = z.ZodType<{ [key: string]: unknown }> + +/** + * JSON Schema format for MCP tool input schemas. + * MCP servers provide this directly instead of Zod schemas. + */ +export type ToolInputJSONSchema = { + [x: string]: unknown + type: 'object' + properties?: { + [x: string]: unknown + } +} + +// ============================================================================ +// Progress types +// ============================================================================ + +/** + * Progress data from a running tool. Host defines concrete subtypes. + * Typed as `any` at the protocol level — the host assigns real shapes. + */ +export type ToolProgressData = any + +/** + * A progress event from a tool execution. + */ +export type ToolProgress

= { + toolUseID: string + data: P +} + +/** + * Callback for receiving progress updates during tool execution. + */ +export type ToolCallProgress

= ( + progress: ToolProgress

, +) => void + +// ============================================================================ +// Result types +// ============================================================================ + +/** + * Result returned by a tool's call() method. + * @template T - The output data type + * @template Message - The message type (host-specific, defaults to unknown) + */ +export type ToolResult = { + data: T + newMessages?: Message[] + contextModifier?: (context: any) => any + /** MCP protocol metadata (structuredContent, _meta) */ + mcpMeta?: { + _meta?: Record + structuredContent?: Record + } +} + +// ============================================================================ +// Validation & Permission types +// ============================================================================ + +/** + * Result of tool input validation. + */ +export type ValidationResult = + | { result: true } + | { result: false; message: string; errorCode: number } + +/** + * Result of a permission check for a tool invocation. + */ +export type PermissionResult = + | { behavior: 'allow'; updatedInput: Record } + | { behavior: 'deny'; message: string } + | { behavior: 'passthrough' } + +// ============================================================================ +// Core Tool interface +// ============================================================================ + +/** + * The host-agnostic core Tool interface. + * + * This defines the protocol-level contract for any tool — independent of + * React rendering, specific context types, or host infrastructure. + * + * The host (Claude Code) extends this with render methods, richer context + * types, and other host-specific features. Host tools structurally satisfy + * this interface because they implement all required fields. + * + * @template Input - Zod schema type for tool input + * @template Output - Tool output data type + * @template P - Tool progress data type + * @template Context - Tool execution context type (host-specific) + */ +export interface CoreTool< + Input extends AnyObject = AnyObject, + Output = unknown, + P extends ToolProgressData = ToolProgressData, + Context = unknown, +> { + // ── Identity ── + readonly name: string + aliases?: string[] + searchHint?: string + + // ── Schema ── + readonly inputSchema: Input + readonly inputJSONSchema?: ToolInputJSONSchema + outputSchema?: z.ZodType + + // ── Execution ── + call( + args: z.infer, + context: Context, + canUseTool: (...args: any[]) => Promise, + parentMessage: any, + onProgress?: ToolCallProgress

, + ): Promise> + + // ── Description ── + description( + input: z.infer, + options: { + isNonInteractiveSession: boolean + toolPermissionContext: any + tools: readonly CoreTool[] + }, + ): Promise + + prompt(options: { + getToolPermissionContext: () => Promise + tools: readonly CoreTool[] + agents: any[] + allowedAgentTypes?: string[] + }): Promise + + // ── Behavioral properties ── + isConcurrencySafe(input: z.infer): boolean + isEnabled(): boolean + isReadOnly(input: z.infer): boolean + isDestructive?(input: z.infer): boolean + isOpenWorld?(input: z.infer): boolean + interruptBehavior?(): 'cancel' | 'block' + requiresUserInteraction?(): boolean + + // ── MCP markers ── + isMcp?: boolean + isLsp?: boolean + readonly shouldDefer?: boolean + readonly alwaysLoad?: boolean + mcpInfo?: { serverName: string; toolName: string } + + // ── Permissions ── + validateInput?( + input: z.infer, + context: Context, + ): Promise + + checkPermissions( + input: z.infer, + context: Context, + ): Promise + + // ── Utility ── + inputsEquivalent?(a: z.infer, b: z.infer): boolean + getPath?(input: z.infer): string + toAutoClassifierInput(input: z.infer): unknown + backfillObservableInput?(input: Record): void + + // ── Output ── + maxResultSizeChars: number + userFacingName(input: Partial> | undefined): string + mapToolResultToToolResultBlockParam( + content: Output, + toolUseID: string, + ): any + + // ── Optional output helpers ── + isResultTruncated?(output: Output): boolean + getToolUseSummary?(input: Partial> | undefined): string | null + getActivityDescription?( + input: Partial> | undefined, + ): string | null + isTransparentWrapper?(): boolean + isSearchOrReadCommand?(input: z.infer): { + isSearch: boolean + isRead: boolean + isList?: boolean + } +} + +/** + * A tool with a generic context type. + * This is the default export — hosts can specify their own Context type. + */ +export type Tool< + Input extends AnyObject = AnyObject, + Output = unknown, + P extends ToolProgressData = ToolProgressData, +> = CoreTool + +/** + * A collection of tools. + */ +export type Tools = readonly CoreTool[] diff --git a/packages/builtin-tools/package.json b/packages/builtin-tools/package.json new file mode 100644 index 000000000..88dac6d49 --- /dev/null +++ b/packages/builtin-tools/package.json @@ -0,0 +1,16 @@ +{ + "name": "@claude-code-best/builtin-tools", + "version": "1.0.0", + "private": true, + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts", + "./tools/*": "./src/tools/*", + "./utils": "./src/utils.ts" + }, + "dependencies": { + "@claude-code-best/agent-tools": "workspace:*" + } +} diff --git a/packages/builtin-tools/src/index.ts b/packages/builtin-tools/src/index.ts new file mode 100644 index 000000000..8609978c6 --- /dev/null +++ b/packages/builtin-tools/src/index.ts @@ -0,0 +1,70 @@ +// builtin-tools — All tool implementations for Claude Code +// This barrel file re-exports the main tool constants and utilities. +// For specific submodules, use deep imports: 'builtin-tools/tools/XTool/XTool.js' + +// ============================================================================= +// Main tool exports (used by src/tools.ts) +// ============================================================================= + +// Core tools +export { AgentTool } from './tools/AgentTool/AgentTool.js' +export { AskUserQuestionTool } from './tools/AskUserQuestionTool/AskUserQuestionTool.js' +export { BashTool } from './tools/BashTool/BashTool.js' +export { BriefTool } from './tools/BriefTool/BriefTool.js' +export { ConfigTool } from './tools/ConfigTool/ConfigTool.js' +export { EnterPlanModeTool } from './tools/EnterPlanModeTool/EnterPlanModeTool.js' +export { EnterWorktreeTool } from './tools/EnterWorktreeTool/EnterWorktreeTool.js' +export { ExitPlanModeV2Tool } from './tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' +export { ExitWorktreeTool } from './tools/ExitWorktreeTool/ExitWorktreeTool.js' +export { FileEditTool } from './tools/FileEditTool/FileEditTool.js' +export { FileReadTool } from './tools/FileReadTool/FileReadTool.js' +export { FileWriteTool } from './tools/FileWriteTool/FileWriteTool.js' +export { GlobTool } from './tools/GlobTool/GlobTool.js' +export { GrepTool } from './tools/GrepTool/GrepTool.js' +export { LSPTool } from './tools/LSPTool/LSPTool.js' +export { ListMcpResourcesTool } from './tools/ListMcpResourcesTool/ListMcpResourcesTool.js' +export { ReadMcpResourceTool } from './tools/ReadMcpResourceTool/ReadMcpResourceTool.js' +export { NotebookEditTool } from './tools/NotebookEditTool/NotebookEditTool.js' +export { SkillTool } from './tools/SkillTool/SkillTool.js' +export { TaskOutputTool } from './tools/TaskOutputTool/TaskOutputTool.js' +export { TaskStopTool } from './tools/TaskStopTool/TaskStopTool.js' +export { TodoWriteTool } from './tools/TodoWriteTool/TodoWriteTool.js' +export { ToolSearchTool } from './tools/ToolSearchTool/ToolSearchTool.js' +export { TungstenTool } from './tools/TungstenTool/TungstenTool.js' +export { WebFetchTool } from './tools/WebFetchTool/WebFetchTool.js' +export { WebSearchTool } from './tools/WebSearchTool/WebSearchTool.js' +export { TestingPermissionTool } from './tools/testing/TestingPermissionTool.js' + +// Feature-gated tools +export { OVERFLOW_TEST_TOOL_NAME } from './tools/OverflowTestTool/OverflowTestTool.js' +export { CtxInspectTool } from './tools/CtxInspectTool/CtxInspectTool.js' +export { ListPeersTool } from './tools/ListPeersTool/ListPeersTool.js' +export { MonitorTool } from './tools/MonitorTool/MonitorTool.js' +export { PowerShellTool } from './tools/PowerShellTool/PowerShellTool.js' +export { PushNotificationTool } from './tools/PushNotificationTool/PushNotificationTool.js' +export { REPLTool } from './tools/REPLTool/REPLTool.js' +export { RemoteTriggerTool } from './tools/RemoteTriggerTool/RemoteTriggerTool.js' +export { ReviewArtifactTool } from './tools/ReviewArtifactTool/ReviewArtifactTool.js' +export { CronCreateTool } from './tools/ScheduleCronTool/CronCreateTool.js' +export { CronDeleteTool } from './tools/ScheduleCronTool/CronDeleteTool.js' +export { CronListTool } from './tools/ScheduleCronTool/CronListTool.js' +export { SendMessageTool } from './tools/SendMessageTool/SendMessageTool.js' +export { SendUserFileTool } from './tools/SendUserFileTool/SendUserFileTool.js' +export { SleepTool } from './tools/SleepTool/SleepTool.js' +export { SnipTool } from './tools/SnipTool/SnipTool.js' +export { SubscribePRTool } from './tools/SubscribePRTool/SubscribePRTool.js' +export { SuggestBackgroundPRTool } from './tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.js' +export { TeamCreateTool } from './tools/TeamCreateTool/TeamCreateTool.js' +export { TeamDeleteTool } from './tools/TeamDeleteTool/TeamDeleteTool.js' +export { TerminalCaptureTool } from './tools/TerminalCaptureTool/TerminalCaptureTool.js' +export { VerifyPlanExecutionTool } from './tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.js' +export { WebBrowserTool } from './tools/WebBrowserTool/WebBrowserTool.js' +export { WorkflowTool } from './tools/WorkflowTool/WorkflowTool.js' +export { initBundledWorkflows } from './tools/WorkflowTool/bundled/index.js' +export { getWorkflowCommands } from './tools/WorkflowTool/createWorkflowCommand.js' + +// Constants +export { SYNTHETIC_OUTPUT_TOOL_NAME, createSyntheticOutputTool } from './tools/SyntheticOutputTool/SyntheticOutputTool.js' + +// Shared utilities +export { tagMessagesWithToolUseID, getToolUseIDFromParentMessage } from './tools/utils.js' diff --git a/src/tools/AgentTool/AgentTool.tsx b/packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx similarity index 96% rename from src/tools/AgentTool/AgentTool.tsx rename to packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx index 8e4ac12d3..82b729386 100644 --- a/src/tools/AgentTool/AgentTool.tsx +++ b/packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx @@ -11,19 +11,19 @@ import { z } from 'zod/v4' import { clearInvokedSkillsForAgent, getSdkAgentProgressSummariesEnabled, -} from '../../bootstrap/state.js' +} from 'src/bootstrap/state.js' import { enhanceSystemPromptWithEnvDetails, getSystemPrompt, -} from '../../constants/prompts.js' -import { isCoordinatorMode } from '../../coordinator/coordinatorMode.js' -import { startAgentSummarization } from '../../services/AgentSummary/agentSummary.js' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' +} from 'src/constants/prompts.js' +import { isCoordinatorMode } from 'src/coordinator/coordinatorMode.js' +import { startAgentSummarization } from 'src/services/AgentSummary/agentSummary.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, -} from '../../services/analytics/index.js' -import { clearDumpState } from '../../services/api/dumpPrompts.js' +} from 'src/services/analytics/index.js' +import { clearDumpState } from 'src/services/api/dumpPrompts.js' import { completeAgentTask as completeAsyncAgent, createActivityDescriptionResolver, @@ -39,53 +39,53 @@ import { unregisterAgentForeground, updateAgentProgress as updateAsyncAgentProgress, updateProgressFromMessage, -} from '../../tasks/LocalAgentTask/LocalAgentTask.js' +} from 'src/tasks/LocalAgentTask/LocalAgentTask.js' import { checkRemoteAgentEligibility, formatPreconditionError, getRemoteTaskSessionUrl, registerRemoteAgentTask, type BackgroundRemoteSessionPrecondition, -} from '../../tasks/RemoteAgentTask/RemoteAgentTask.js' -import { assembleToolPool } from '../../tools.js' -import { asAgentId } from '../../types/ids.js' -import { runWithAgentContext, type SubagentContext } from '../../utils/agentContext.js' -import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js' -import { getCwd, runWithCwdOverride } from '../../utils/cwd.js' -import { logForDebugging } from '../../utils/debug.js' -import { isEnvTruthy } from '../../utils/envUtils.js' -import { AbortError, errorMessage, toError } from '../../utils/errors.js' -import type { CacheSafeParams } from '../../utils/forkedAgent.js' -import { lazySchema } from '../../utils/lazySchema.js' +} from 'src/tasks/RemoteAgentTask/RemoteAgentTask.js' +import { assembleToolPool } from 'src/tools.js' +import { asAgentId } from 'src/types/ids.js' +import { runWithAgentContext, type SubagentContext } from 'src/utils/agentContext.js' +import { isAgentSwarmsEnabled } from 'src/utils/agentSwarmsEnabled.js' +import { getCwd, runWithCwdOverride } from 'src/utils/cwd.js' +import { logForDebugging } from 'src/utils/debug.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' +import { AbortError, errorMessage, toError } from 'src/utils/errors.js' +import type { CacheSafeParams } from 'src/utils/forkedAgent.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { createUserMessage, extractTextContent, isSyntheticMessage, normalizeMessages, -} from '../../utils/messages.js' -import { getAgentModel } from '../../utils/model/agent.js' -import { permissionModeSchema } from '../../utils/permissions/PermissionMode.js' -import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' +} from 'src/utils/messages.js' +import { getAgentModel } from 'src/utils/model/agent.js' +import { permissionModeSchema } from 'src/utils/permissions/PermissionMode.js' +import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' import { filterDeniedAgents, getDenyRuleForAgent, -} from '../../utils/permissions/permissions.js' -import { enqueueSdkEvent } from '../../utils/sdkEventQueue.js' -import { writeAgentMetadata } from '../../utils/sessionStorage.js' -import { sleep } from '../../utils/sleep.js' -import { buildEffectiveSystemPrompt } from '../../utils/systemPrompt.js' -import { asSystemPrompt } from '../../utils/systemPromptType.js' -import { getTaskOutputPath } from '../../utils/task/diskOutput.js' -import { getParentSessionId, isTeammate } from '../../utils/teammate.js' -import { isInProcessTeammate } from '../../utils/teammateContext.js' -import { teleportToRemote } from '../../utils/teleport.js' -import { getAssistantMessageContentLength } from '../../utils/tokens.js' -import { createAgentId } from '../../utils/uuid.js' +} from 'src/utils/permissions/permissions.js' +import { enqueueSdkEvent } from 'src/utils/sdkEventQueue.js' +import { writeAgentMetadata } from 'src/utils/sessionStorage.js' +import { sleep } from 'src/utils/sleep.js' +import { buildEffectiveSystemPrompt } from 'src/utils/systemPrompt.js' +import { asSystemPrompt } from 'src/utils/systemPromptType.js' +import { getTaskOutputPath } from 'src/utils/task/diskOutput.js' +import { getParentSessionId, isTeammate } from 'src/utils/teammate.js' +import { isInProcessTeammate } from 'src/utils/teammateContext.js' +import { teleportToRemote } from 'src/utils/teleport.js' +import { getAssistantMessageContentLength } from 'src/utils/tokens.js' +import { createAgentId } from 'src/utils/uuid.js' import { createAgentWorktree, hasWorktreeChanges, removeAgentWorktree, -} from '../../utils/worktree.js' +} from 'src/utils/worktree.js' import { BASH_TOOL_NAME } from '../BashTool/toolName.js' import { BackgroundHint } from '../BashTool/UI.js' import { FILE_READ_TOOL_NAME } from '../FileReadTool/prompt.js' @@ -136,7 +136,7 @@ import { /* eslint-disable @typescript-eslint/no-require-imports */ const proactiveModule = feature('PROACTIVE') || feature('KAIROS') - ? (require('../../proactive/index.js') as typeof import('../../proactive/index.js')) + ? (require('src/proactive/index.js') as typeof import('src/proactive/index.js')) : null /* eslint-enable @typescript-eslint/no-require-imports */ @@ -332,7 +332,7 @@ export type RemoteLaunchedOutput = { type InternalOutput = Output | TeammateSpawnedOutput | RemoteLaunchedOutput -import type { AgentToolProgress, ShellProgress } from '../../types/tools.js' +import type { AgentToolProgress, ShellProgress } from 'src/types/tools.js' // AgentTool forwards both its own progress events and shell progress // events from the sub-agent so the SDK receives tool_progress updates during bash/powershell runs. export type Progress = AgentToolProgress | ShellProgress diff --git a/src/tools/AgentTool/UI.tsx b/packages/builtin-tools/src/tools/AgentTool/UI.tsx similarity index 96% rename from src/tools/AgentTool/UI.tsx rename to packages/builtin-tools/src/tools/AgentTool/UI.tsx index e52e09ca8..4ba99149a 100644 --- a/src/tools/AgentTool/UI.tsx +++ b/packages/builtin-tools/src/tools/AgentTool/UI.tsx @@ -12,37 +12,37 @@ import { } from 'src/components/CtrlOToExpand.js' import { Byline, KeyboardShortcutHint } from '@anthropic/ink' import type { z } from 'zod/v4' -import { AgentProgressLine } from '../../components/AgentProgressLine.js' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' -import { FallbackToolUseRejectedMessage } from '../../components/FallbackToolUseRejectedMessage.js' -import { Markdown } from '../../components/Markdown.js' -import { Message as MessageComponent } from '../../components/Message.js' -import { MessageResponse } from '../../components/MessageResponse.js' -import { ToolUseLoader } from '../../components/ToolUseLoader.js' +import { AgentProgressLine } from 'src/components/AgentProgressLine.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' +import { FallbackToolUseRejectedMessage } from 'src/components/FallbackToolUseRejectedMessage.js' +import { Markdown } from 'src/components/Markdown.js' +import { Message as MessageComponent } from 'src/components/Message.js' +import { MessageResponse } from 'src/components/MessageResponse.js' +import { ToolUseLoader } from 'src/components/ToolUseLoader.js' import { Box, Text } from '@anthropic/ink' -import { getDumpPromptsPath } from '../../services/api/dumpPrompts.js' -import { findToolByName, type Tools } from '../../Tool.js' -import type { Message, ProgressMessage } from '../../types/message.js' -import type { AgentToolProgress } from '../../types/tools.js' -import { count } from '../../utils/array.js' +import { getDumpPromptsPath } from 'src/services/api/dumpPrompts.js' +import { findToolByName, type Tools } from 'src/Tool.js' +import type { Message, ProgressMessage } from 'src/types/message.js' +import type { AgentToolProgress } from 'src/types/tools.js' +import { count } from 'src/utils/array.js' import { getSearchOrReadFromContent, getSearchReadSummaryText, -} from '../../utils/collapseReadSearch.js' -import { getDisplayPath } from '../../utils/file.js' -import { formatDuration, formatNumber } from '../../utils/format.js' +} from 'src/utils/collapseReadSearch.js' +import { getDisplayPath } from 'src/utils/file.js' +import { formatDuration, formatNumber } from 'src/utils/format.js' import { buildSubagentLookups, createAssistantMessage, EMPTY_LOOKUPS, -} from '../../utils/messages.js' -import type { ModelAlias } from '../../utils/model/aliases.js' +} from 'src/utils/messages.js' +import type { ModelAlias } from 'src/utils/model/aliases.js' import { getMainLoopModel, parseUserSpecifiedModel, renderModelName, -} from '../../utils/model/model.js' -import type { Theme, ThemeName } from '../../utils/theme.js' +} from 'src/utils/model/model.js' +import type { Theme, ThemeName } from 'src/utils/theme.js' import type { outputSchema, Progress, diff --git a/src/tools/AgentTool/__tests__/agentDisplay.test.ts b/packages/builtin-tools/src/tools/AgentTool/__tests__/agentDisplay.test.ts similarity index 97% rename from src/tools/AgentTool/__tests__/agentDisplay.test.ts rename to packages/builtin-tools/src/tools/AgentTool/__tests__/agentDisplay.test.ts index 0ce55c497..072b48c26 100644 --- a/src/tools/AgentTool/__tests__/agentDisplay.test.ts +++ b/packages/builtin-tools/src/tools/AgentTool/__tests__/agentDisplay.test.ts @@ -1,11 +1,11 @@ import { mock, describe, expect, test } from "bun:test"; // Mock heavy deps -mock.module("../../utils/model/agent.js", () => ({ +mock.module("src/utils/model/agent.js", () => ({ getDefaultSubagentModel: () => undefined, })); -mock.module("../../utils/settings/constants.js", () => ({ +mock.module("src/utils/settings/constants.js", () => ({ getSourceDisplayName: (source: string) => source, })); diff --git a/src/tools/AgentTool/__tests__/agentToolUtils.test.ts b/packages/builtin-tools/src/tools/AgentTool/__tests__/agentToolUtils.test.ts similarity index 100% rename from src/tools/AgentTool/__tests__/agentToolUtils.test.ts rename to packages/builtin-tools/src/tools/AgentTool/__tests__/agentToolUtils.test.ts diff --git a/src/tools/AgentTool/agentColorManager.ts b/packages/builtin-tools/src/tools/AgentTool/agentColorManager.ts similarity index 92% rename from src/tools/AgentTool/agentColorManager.ts rename to packages/builtin-tools/src/tools/AgentTool/agentColorManager.ts index 3f3f7774a..ba6da1ddc 100644 --- a/src/tools/AgentTool/agentColorManager.ts +++ b/packages/builtin-tools/src/tools/AgentTool/agentColorManager.ts @@ -1,5 +1,5 @@ -import { getAgentColorMap } from '../../bootstrap/state.js' -import type { Theme } from '../../utils/theme.js' +import { getAgentColorMap } from 'src/bootstrap/state.js' +import type { Theme } from 'src/utils/theme.js' export type AgentColorName = | 'red' diff --git a/src/tools/AgentTool/agentDisplay.ts b/packages/builtin-tools/src/tools/AgentTool/agentDisplay.ts similarity index 96% rename from src/tools/AgentTool/agentDisplay.ts rename to packages/builtin-tools/src/tools/AgentTool/agentDisplay.ts index 2090ae999..1da7b7a4f 100644 --- a/src/tools/AgentTool/agentDisplay.ts +++ b/packages/builtin-tools/src/tools/AgentTool/agentDisplay.ts @@ -3,11 +3,11 @@ * Used by both the CLI `claude agents` handler and the interactive `/agents` command. */ -import { getDefaultSubagentModel } from '../../utils/model/agent.js' +import { getDefaultSubagentModel } from 'src/utils/model/agent.js' import { getSourceDisplayName, type SettingSource, -} from '../../utils/settings/constants.js' +} from 'src/utils/settings/constants.js' import type { AgentDefinition } from './loadAgentsDir.js' type AgentSource = SettingSource | 'built-in' | 'plugin' diff --git a/src/tools/AgentTool/agentMemory.ts b/packages/builtin-tools/src/tools/AgentTool/agentMemory.ts similarity index 94% rename from src/tools/AgentTool/agentMemory.ts rename to packages/builtin-tools/src/tools/AgentTool/agentMemory.ts index 2d2650cd7..d1b16f1e2 100644 --- a/src/tools/AgentTool/agentMemory.ts +++ b/packages/builtin-tools/src/tools/AgentTool/agentMemory.ts @@ -1,13 +1,13 @@ import { join, normalize, sep } from 'path' -import { getProjectRoot } from '../../bootstrap/state.js' +import { getProjectRoot } from 'src/bootstrap/state.js' import { buildMemoryPrompt, ensureMemoryDirExists, -} from '../../memdir/memdir.js' -import { getMemoryBaseDir } from '../../memdir/paths.js' -import { getCwd } from '../../utils/cwd.js' -import { findCanonicalGitRoot } from '../../utils/git.js' -import { sanitizePath } from '../../utils/path.js' +} from 'src/memdir/memdir.js' +import { getMemoryBaseDir } from 'src/memdir/paths.js' +import { getCwd } from 'src/utils/cwd.js' +import { findCanonicalGitRoot } from 'src/utils/git.js' +import { sanitizePath } from 'src/utils/path.js' // Persistent agent memory scope: 'user' (~/.claude/agent-memory/), 'project' (.claude/agent-memory/), or 'local' (.claude/agent-memory-local/) export type AgentMemoryScope = 'user' | 'project' | 'local' diff --git a/src/tools/AgentTool/agentMemorySnapshot.ts b/packages/builtin-tools/src/tools/AgentTool/agentMemorySnapshot.ts similarity index 95% rename from src/tools/AgentTool/agentMemorySnapshot.ts rename to packages/builtin-tools/src/tools/AgentTool/agentMemorySnapshot.ts index 44352925f..b08fea5cf 100644 --- a/src/tools/AgentTool/agentMemorySnapshot.ts +++ b/packages/builtin-tools/src/tools/AgentTool/agentMemorySnapshot.ts @@ -1,10 +1,10 @@ import { mkdir, readdir, readFile, unlink, writeFile } from 'fs/promises' import { join } from 'path' import { z } from 'zod/v4' -import { getCwd } from '../../utils/cwd.js' -import { logForDebugging } from '../../utils/debug.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { jsonParse, jsonStringify } from '../../utils/slowOperations.js' +import { getCwd } from 'src/utils/cwd.js' +import { logForDebugging } from 'src/utils/debug.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { jsonParse, jsonStringify } from 'src/utils/slowOperations.js' import { type AgentMemoryScope, getAgentMemoryDir } from './agentMemory.js' const SNAPSHOT_BASE = 'agent-memory-snapshots' diff --git a/src/tools/AgentTool/agentToolUtils.ts b/packages/builtin-tools/src/tools/AgentTool/agentToolUtils.ts similarity index 93% rename from src/tools/AgentTool/agentToolUtils.ts rename to packages/builtin-tools/src/tools/AgentTool/agentToolUtils.ts index 084ac6a85..e8cf493f8 100644 --- a/src/tools/AgentTool/agentToolUtils.ts +++ b/packages/builtin-tools/src/tools/AgentTool/agentToolUtils.ts @@ -1,26 +1,26 @@ import { feature } from 'bun:bundle' import { z } from 'zod/v4' -import { clearInvokedSkillsForAgent } from '../../bootstrap/state.js' +import { clearInvokedSkillsForAgent } from 'src/bootstrap/state.js' import { ALL_AGENT_DISALLOWED_TOOLS, ASYNC_AGENT_ALLOWED_TOOLS, CUSTOM_AGENT_DISALLOWED_TOOLS, IN_PROCESS_TEAMMATE_ALLOWED_TOOLS, -} from '../../constants/tools.js' -import { startAgentSummarization } from '../../services/AgentSummary/agentSummary.js' +} from 'src/constants/tools.js' +import { startAgentSummarization } from 'src/services/AgentSummary/agentSummary.js' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, -} from '../../services/analytics/index.js' -import { clearDumpState } from '../../services/api/dumpPrompts.js' -import type { AppState } from '../../state/AppState.js' +} from 'src/services/analytics/index.js' +import { clearDumpState } from 'src/services/api/dumpPrompts.js' +import type { AppState } from 'src/state/AppState.js' import type { Tool, ToolPermissionContext, Tools, ToolUseContext, -} from '../../Tool.js' -import { toolMatchesName } from '../../Tool.js' +} from 'src/Tool.js' +import { toolMatchesName } from 'src/Tool.js' import { completeAgentTask as completeAsyncAgent, createActivityDescriptionResolver, @@ -34,28 +34,28 @@ import { type ProgressTracker, updateAgentProgress as updateAsyncAgentProgress, updateProgressFromMessage, -} from '../../tasks/LocalAgentTask/LocalAgentTask.js' -import { asAgentId } from '../../types/ids.js' -import type { Message as MessageType, ContentItem } from '../../types/message.js' -import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js' -import { logForDebugging } from '../../utils/debug.js' -import { isInProtectedNamespace } from '../../utils/envUtils.js' -import { AbortError, errorMessage } from '../../utils/errors.js' -import type { CacheSafeParams } from '../../utils/forkedAgent.js' -import { lazySchema } from '../../utils/lazySchema.js' +} from 'src/tasks/LocalAgentTask/LocalAgentTask.js' +import { asAgentId } from 'src/types/ids.js' +import type { Message as MessageType, ContentItem } from 'src/types/message.js' +import { isAgentSwarmsEnabled } from 'src/utils/agentSwarmsEnabled.js' +import { logForDebugging } from 'src/utils/debug.js' +import { isInProtectedNamespace } from 'src/utils/envUtils.js' +import { AbortError, errorMessage } from 'src/utils/errors.js' +import type { CacheSafeParams } from 'src/utils/forkedAgent.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { extractTextContent, getLastAssistantMessage, -} from '../../utils/messages.js' -import type { PermissionMode } from '../../utils/permissions/PermissionMode.js' -import { permissionRuleValueFromString } from '../../utils/permissions/permissionRuleParser.js' +} from 'src/utils/messages.js' +import type { PermissionMode } from 'src/utils/permissions/PermissionMode.js' +import { permissionRuleValueFromString } from 'src/utils/permissions/permissionRuleParser.js' import { buildTranscriptForClassifier, classifyYoloAction, -} from '../../utils/permissions/yoloClassifier.js' -import { emitTaskProgress as emitTaskProgressEvent } from '../../utils/task/sdkProgress.js' -import { isInProcessTeammate } from '../../utils/teammateContext.js' -import { getTokenCountFromUsage } from '../../utils/tokens.js' +} from 'src/utils/permissions/yoloClassifier.js' +import { emitTaskProgress as emitTaskProgressEvent } from 'src/utils/task/sdkProgress.js' +import { isInProcessTeammate } from 'src/utils/teammateContext.js' +import { getTokenCountFromUsage } from 'src/utils/tokens.js' import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '../ExitPlanModeTool/constants.js' import { AGENT_TOOL_NAME, LEGACY_AGENT_TOOL_NAME } from './constants.js' import type { AgentDefinition } from './loadAgentsDir.js' diff --git a/src/tools/AgentTool/built-in/claudeCodeGuideAgent.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/claudeCodeGuideAgent.ts similarity index 91% rename from src/tools/AgentTool/built-in/claudeCodeGuideAgent.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/claudeCodeGuideAgent.ts index 30b446dc1..2ffb577d5 100644 --- a/src/tools/AgentTool/built-in/claudeCodeGuideAgent.ts +++ b/packages/builtin-tools/src/tools/AgentTool/built-in/claudeCodeGuideAgent.ts @@ -1,14 +1,14 @@ -import { BASH_TOOL_NAME } from 'src/tools/BashTool/toolName.js' -import { FILE_READ_TOOL_NAME } from 'src/tools/FileReadTool/prompt.js' -import { GLOB_TOOL_NAME } from 'src/tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from 'src/tools/GrepTool/prompt.js' -import { SEND_MESSAGE_TOOL_NAME } from 'src/tools/SendMessageTool/constants.js' -import { WEB_FETCH_TOOL_NAME } from 'src/tools/WebFetchTool/prompt.js' -import { WEB_SEARCH_TOOL_NAME } from 'src/tools/WebSearchTool/prompt.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { SEND_MESSAGE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SendMessageTool/constants.js' +import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js' +import { WEB_SEARCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebSearchTool/prompt.js' import { isUsing3PServices } from 'src/utils/auth.js' import { hasEmbeddedSearchTools } from 'src/utils/embeddedTools.js' import { getSettings_DEPRECATED } from 'src/utils/settings/settings.js' -import { jsonStringify } from '../../../utils/slowOperations.js' +import { jsonStringify } from 'src/utils/slowOperations.js' import type { AgentDefinition, BuiltInAgentDefinition, diff --git a/src/tools/AgentTool/built-in/exploreAgent.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/exploreAgent.ts similarity index 83% rename from src/tools/AgentTool/built-in/exploreAgent.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/exploreAgent.ts index f508dc62f..bf4b20ca6 100644 --- a/src/tools/AgentTool/built-in/exploreAgent.ts +++ b/packages/builtin-tools/src/tools/AgentTool/built-in/exploreAgent.ts @@ -1,11 +1,11 @@ -import { BASH_TOOL_NAME } from 'src/tools/BashTool/toolName.js' -import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' -import { FILE_EDIT_TOOL_NAME } from 'src/tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from 'src/tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from 'src/tools/FileWriteTool/prompt.js' -import { GLOB_TOOL_NAME } from 'src/tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from 'src/tools/GrepTool/prompt.js' -import { NOTEBOOK_EDIT_TOOL_NAME } from 'src/tools/NotebookEditTool/constants.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js' import { hasEmbeddedSearchTools } from 'src/utils/embeddedTools.js' import { AGENT_TOOL_NAME } from '../constants.js' import type { BuiltInAgentDefinition } from '../loadAgentsDir.js' diff --git a/src/tools/AgentTool/built-in/generalPurposeAgent.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/generalPurposeAgent.ts similarity index 100% rename from src/tools/AgentTool/built-in/generalPurposeAgent.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/generalPurposeAgent.ts diff --git a/src/tools/AgentTool/built-in/planAgent.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/planAgent.ts similarity index 82% rename from src/tools/AgentTool/built-in/planAgent.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/planAgent.ts index 71c7a78c9..d12676fb3 100644 --- a/src/tools/AgentTool/built-in/planAgent.ts +++ b/packages/builtin-tools/src/tools/AgentTool/built-in/planAgent.ts @@ -1,11 +1,11 @@ -import { BASH_TOOL_NAME } from 'src/tools/BashTool/toolName.js' -import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' -import { FILE_EDIT_TOOL_NAME } from 'src/tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from 'src/tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from 'src/tools/FileWriteTool/prompt.js' -import { GLOB_TOOL_NAME } from 'src/tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from 'src/tools/GrepTool/prompt.js' -import { NOTEBOOK_EDIT_TOOL_NAME } from 'src/tools/NotebookEditTool/constants.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js' import { hasEmbeddedSearchTools } from 'src/utils/embeddedTools.js' import { AGENT_TOOL_NAME } from '../constants.js' import type { BuiltInAgentDefinition } from '../loadAgentsDir.js' diff --git a/src/tools/AgentTool/built-in/src/tools/BashTool/toolName.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/BashTool/toolName.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/BashTool/toolName.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/BashTool/toolName.ts diff --git a/src/tools/AgentTool/built-in/src/tools/ExitPlanModeTool/constants.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/ExitPlanModeTool/constants.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/ExitPlanModeTool/constants.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/ExitPlanModeTool/constants.ts diff --git a/src/tools/AgentTool/built-in/src/tools/FileEditTool/constants.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/FileEditTool/constants.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/FileEditTool/constants.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/FileEditTool/constants.ts diff --git a/src/tools/AgentTool/built-in/src/tools/FileReadTool/prompt.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/FileReadTool/prompt.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/FileReadTool/prompt.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/FileReadTool/prompt.ts diff --git a/src/tools/AgentTool/built-in/src/tools/FileWriteTool/prompt.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/FileWriteTool/prompt.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/FileWriteTool/prompt.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/FileWriteTool/prompt.ts diff --git a/src/tools/AgentTool/built-in/src/tools/GlobTool/prompt.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/GlobTool/prompt.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/GlobTool/prompt.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/GlobTool/prompt.ts diff --git a/src/tools/AgentTool/built-in/src/tools/GrepTool/prompt.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/GrepTool/prompt.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/GrepTool/prompt.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/GrepTool/prompt.ts diff --git a/src/tools/AgentTool/built-in/src/tools/NotebookEditTool/constants.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/NotebookEditTool/constants.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/NotebookEditTool/constants.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/NotebookEditTool/constants.ts diff --git a/src/tools/AgentTool/built-in/src/tools/SendMessageTool/constants.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/SendMessageTool/constants.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/SendMessageTool/constants.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/SendMessageTool/constants.ts diff --git a/src/tools/AgentTool/built-in/src/tools/WebFetchTool/prompt.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/WebFetchTool/prompt.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/WebFetchTool/prompt.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/WebFetchTool/prompt.ts diff --git a/src/tools/AgentTool/built-in/src/tools/WebSearchTool/prompt.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/WebSearchTool/prompt.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/tools/WebSearchTool/prompt.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/tools/WebSearchTool/prompt.ts diff --git a/src/tools/AgentTool/built-in/src/utils/auth.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/utils/auth.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/utils/auth.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/utils/auth.ts diff --git a/src/tools/AgentTool/built-in/src/utils/embeddedTools.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/utils/embeddedTools.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/utils/embeddedTools.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/utils/embeddedTools.ts diff --git a/src/tools/AgentTool/built-in/src/utils/settings/settings.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/src/utils/settings/settings.ts similarity index 100% rename from src/tools/AgentTool/built-in/src/utils/settings/settings.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/src/utils/settings/settings.ts diff --git a/src/tools/AgentTool/built-in/statuslineSetup.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/statuslineSetup.ts similarity index 100% rename from src/tools/AgentTool/built-in/statuslineSetup.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/statuslineSetup.ts diff --git a/src/tools/AgentTool/built-in/verificationAgent.ts b/packages/builtin-tools/src/tools/AgentTool/built-in/verificationAgent.ts similarity index 94% rename from src/tools/AgentTool/built-in/verificationAgent.ts rename to packages/builtin-tools/src/tools/AgentTool/built-in/verificationAgent.ts index 3609f97e5..c6f62785c 100644 --- a/src/tools/AgentTool/built-in/verificationAgent.ts +++ b/packages/builtin-tools/src/tools/AgentTool/built-in/verificationAgent.ts @@ -1,9 +1,9 @@ -import { BASH_TOOL_NAME } from 'src/tools/BashTool/toolName.js' -import { EXIT_PLAN_MODE_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' -import { FILE_EDIT_TOOL_NAME } from 'src/tools/FileEditTool/constants.js' -import { FILE_WRITE_TOOL_NAME } from 'src/tools/FileWriteTool/prompt.js' -import { NOTEBOOK_EDIT_TOOL_NAME } from 'src/tools/NotebookEditTool/constants.js' -import { WEB_FETCH_TOOL_NAME } from 'src/tools/WebFetchTool/prompt.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js' +import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js' import { AGENT_TOOL_NAME } from '../constants.js' import type { BuiltInAgentDefinition } from '../loadAgentsDir.js' diff --git a/src/tools/AgentTool/builtInAgents.ts b/packages/builtin-tools/src/tools/AgentTool/builtInAgents.ts similarity index 88% rename from src/tools/AgentTool/builtInAgents.ts rename to packages/builtin-tools/src/tools/AgentTool/builtInAgents.ts index 721dff96c..5735a4692 100644 --- a/src/tools/AgentTool/builtInAgents.ts +++ b/packages/builtin-tools/src/tools/AgentTool/builtInAgents.ts @@ -1,7 +1,7 @@ import { feature } from 'bun:bundle' -import { getIsNonInteractiveSession } from '../../bootstrap/state.js' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' -import { isEnvTruthy } from '../../utils/envUtils.js' +import { getIsNonInteractiveSession } from 'src/bootstrap/state.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' import { CLAUDE_CODE_GUIDE_AGENT } from './built-in/claudeCodeGuideAgent.js' import { EXPLORE_AGENT } from './built-in/exploreAgent.js' import { GENERAL_PURPOSE_AGENT } from './built-in/generalPurposeAgent.js' @@ -36,7 +36,7 @@ export function getBuiltInAgents(): AgentDefinition[] { if (isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)) { /* eslint-disable @typescript-eslint/no-require-imports */ const { getCoordinatorAgents } = - require('../../coordinator/workerAgent.js') as typeof import('../../coordinator/workerAgent.js') + require('src/coordinator/workerAgent.js') as typeof import('src/coordinator/workerAgent.js') /* eslint-enable @typescript-eslint/no-require-imports */ return getCoordinatorAgents() } diff --git a/src/tools/AgentTool/constants.ts b/packages/builtin-tools/src/tools/AgentTool/constants.ts similarity index 100% rename from src/tools/AgentTool/constants.ts rename to packages/builtin-tools/src/tools/AgentTool/constants.ts diff --git a/src/tools/AgentTool/forkSubagent.ts b/packages/builtin-tools/src/tools/AgentTool/forkSubagent.ts similarity index 96% rename from src/tools/AgentTool/forkSubagent.ts rename to packages/builtin-tools/src/tools/AgentTool/forkSubagent.ts index 553d455de..4ab95e66a 100644 --- a/src/tools/AgentTool/forkSubagent.ts +++ b/packages/builtin-tools/src/tools/AgentTool/forkSubagent.ts @@ -1,18 +1,18 @@ import { feature } from 'bun:bundle' import type { BetaToolUseBlock } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs' import { randomUUID } from 'crypto' -import { getIsNonInteractiveSession } from '../../bootstrap/state.js' +import { getIsNonInteractiveSession } from 'src/bootstrap/state.js' import { FORK_BOILERPLATE_TAG, FORK_DIRECTIVE_PREFIX, -} from '../../constants/xml.js' -import { isCoordinatorMode } from '../../coordinator/coordinatorMode.js' +} from 'src/constants/xml.js' +import { isCoordinatorMode } from 'src/coordinator/coordinatorMode.js' import type { AssistantMessage, Message as MessageType, -} from '../../types/message.js' -import { logForDebugging } from '../../utils/debug.js' -import { createUserMessage } from '../../utils/messages.js' +} from 'src/types/message.js' +import { logForDebugging } from 'src/utils/debug.js' +import { createUserMessage } from 'src/utils/messages.js' import type { BuiltInAgentDefinition } from './loadAgentsDir.js' /** diff --git a/src/tools/AgentTool/loadAgentsDir.ts b/packages/builtin-tools/src/tools/AgentTool/loadAgentsDir.ts similarity index 96% rename from src/tools/AgentTool/loadAgentsDir.ts rename to packages/builtin-tools/src/tools/AgentTool/loadAgentsDir.ts index cb4dc35e2..30cf8bb91 100644 --- a/src/tools/AgentTool/loadAgentsDir.ts +++ b/packages/builtin-tools/src/tools/AgentTool/loadAgentsDir.ts @@ -3,41 +3,41 @@ import memoize from 'lodash-es/memoize.js' import { basename } from 'path' import type { SettingSource } from 'src/utils/settings/constants.js' import { z } from 'zod/v4' -import { isAutoMemoryEnabled } from '../../memdir/paths.js' +import { isAutoMemoryEnabled } from 'src/memdir/paths.js' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, -} from '../../services/analytics/index.js' +} from 'src/services/analytics/index.js' import { type McpServerConfig, McpServerConfigSchema, -} from '../../services/mcp/types.js' -import type { ToolUseContext } from '../../Tool.js' -import { logForDebugging } from '../../utils/debug.js' +} from 'src/services/mcp/types.js' +import type { ToolUseContext } from 'src/Tool.js' +import { logForDebugging } from 'src/utils/debug.js' import { EFFORT_LEVELS, type EffortValue, parseEffortValue, -} from '../../utils/effort.js' -import { isEnvTruthy } from '../../utils/envUtils.js' -import { parsePositiveIntFromFrontmatter } from '../../utils/frontmatterParser.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { logError } from '../../utils/log.js' +} from 'src/utils/effort.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' +import { parsePositiveIntFromFrontmatter } from 'src/utils/frontmatterParser.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { logError } from 'src/utils/log.js' import { loadMarkdownFilesForSubdir, parseAgentToolsFromFrontmatter, parseSlashCommandToolsFromFrontmatter, -} from '../../utils/markdownConfigLoader.js' +} from 'src/utils/markdownConfigLoader.js' import { PERMISSION_MODES, type PermissionMode, -} from '../../utils/permissions/PermissionMode.js' +} from 'src/utils/permissions/PermissionMode.js' import { clearPluginAgentCache, loadPluginAgents, -} from '../../utils/plugins/loadPluginAgents.js' -import { HooksSchema, type HooksSettings } from '../../utils/settings/types.js' -import { jsonStringify } from '../../utils/slowOperations.js' +} from 'src/utils/plugins/loadPluginAgents.js' +import { HooksSchema, type HooksSettings } from 'src/utils/settings/types.js' +import { jsonStringify } from 'src/utils/slowOperations.js' import { FILE_EDIT_TOOL_NAME } from '../FileEditTool/constants.js' import { FILE_READ_TOOL_NAME } from '../FileReadTool/prompt.js' import { FILE_WRITE_TOOL_NAME } from '../FileWriteTool/prompt.js' diff --git a/src/tools/AgentTool/prompt.ts b/packages/builtin-tools/src/tools/AgentTool/prompt.ts similarity index 97% rename from src/tools/AgentTool/prompt.ts rename to packages/builtin-tools/src/tools/AgentTool/prompt.ts index 2a0517685..4198859a4 100644 --- a/src/tools/AgentTool/prompt.ts +++ b/packages/builtin-tools/src/tools/AgentTool/prompt.ts @@ -1,9 +1,9 @@ -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' -import { getSubscriptionType } from '../../utils/auth.js' -import { hasEmbeddedSearchTools } from '../../utils/embeddedTools.js' -import { isEnvDefinedFalsy, isEnvTruthy } from '../../utils/envUtils.js' -import { isTeammate } from '../../utils/teammate.js' -import { isInProcessTeammate } from '../../utils/teammateContext.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import { getSubscriptionType } from 'src/utils/auth.js' +import { hasEmbeddedSearchTools } from 'src/utils/embeddedTools.js' +import { isEnvDefinedFalsy, isEnvTruthy } from 'src/utils/envUtils.js' +import { isTeammate } from 'src/utils/teammate.js' +import { isInProcessTeammate } from 'src/utils/teammateContext.js' import { FILE_READ_TOOL_NAME } from '../FileReadTool/prompt.js' import { FILE_WRITE_TOOL_NAME } from '../FileWriteTool/prompt.js' import { GLOB_TOOL_NAME } from '../GlobTool/prompt.js' diff --git a/src/tools/AgentTool/resumeAgent.ts b/packages/builtin-tools/src/tools/AgentTool/resumeAgent.ts similarity index 86% rename from src/tools/AgentTool/resumeAgent.ts rename to packages/builtin-tools/src/tools/AgentTool/resumeAgent.ts index a688bca0c..de6591e90 100644 --- a/src/tools/AgentTool/resumeAgent.ts +++ b/packages/builtin-tools/src/tools/AgentTool/resumeAgent.ts @@ -1,32 +1,32 @@ import { promises as fsp } from 'fs' -import { getSdkAgentProgressSummariesEnabled } from '../../bootstrap/state.js' -import { getSystemPrompt } from '../../constants/prompts.js' -import { isCoordinatorMode } from '../../coordinator/coordinatorMode.js' -import type { CanUseToolFn } from '../../hooks/useCanUseTool.js' -import type { ToolUseContext } from '../../Tool.js' -import { registerAsyncAgent } from '../../tasks/LocalAgentTask/LocalAgentTask.js' -import { assembleToolPool } from '../../tools.js' -import { asAgentId } from '../../types/ids.js' -import { runWithAgentContext } from '../../utils/agentContext.js' -import { runWithCwdOverride } from '../../utils/cwd.js' -import { logForDebugging } from '../../utils/debug.js' +import { getSdkAgentProgressSummariesEnabled } from 'src/bootstrap/state.js' +import { getSystemPrompt } from 'src/constants/prompts.js' +import { isCoordinatorMode } from 'src/coordinator/coordinatorMode.js' +import type { CanUseToolFn } from 'src/hooks/useCanUseTool.js' +import type { ToolUseContext } from 'src/Tool.js' +import { registerAsyncAgent } from 'src/tasks/LocalAgentTask/LocalAgentTask.js' +import { assembleToolPool } from 'src/tools.js' +import { asAgentId } from 'src/types/ids.js' +import { runWithAgentContext } from 'src/utils/agentContext.js' +import { runWithCwdOverride } from 'src/utils/cwd.js' +import { logForDebugging } from 'src/utils/debug.js' import { createUserMessage, filterOrphanedThinkingOnlyMessages, filterUnresolvedToolUses, filterWhitespaceOnlyAssistantMessages, -} from '../../utils/messages.js' -import { getAgentModel } from '../../utils/model/agent.js' -import { getQuerySourceForAgent } from '../../utils/promptCategory.js' +} from 'src/utils/messages.js' +import { getAgentModel } from 'src/utils/model/agent.js' +import { getQuerySourceForAgent } from 'src/utils/promptCategory.js' import { getAgentTranscript, readAgentMetadata, -} from '../../utils/sessionStorage.js' -import { buildEffectiveSystemPrompt } from '../../utils/systemPrompt.js' -import type { SystemPrompt } from '../../utils/systemPromptType.js' -import { getTaskOutputPath } from '../../utils/task/diskOutput.js' -import { getParentSessionId } from '../../utils/teammate.js' -import { reconstructForSubagentResume } from '../../utils/toolResultStorage.js' +} from 'src/utils/sessionStorage.js' +import { buildEffectiveSystemPrompt } from 'src/utils/systemPrompt.js' +import type { SystemPrompt } from 'src/utils/systemPromptType.js' +import { getTaskOutputPath } from 'src/utils/task/diskOutput.js' +import { getParentSessionId } from 'src/utils/teammate.js' +import { reconstructForSubagentResume } from 'src/utils/toolResultStorage.js' import { runAsyncAgentLifecycle } from './agentToolUtils.js' import { GENERAL_PURPOSE_AGENT } from './built-in/generalPurposeAgent.js' import { FORK_AGENT, isForkSubagentEnabled } from './forkSubagent.js' diff --git a/src/tools/AgentTool/runAgent.ts b/packages/builtin-tools/src/tools/AgentTool/runAgent.ts similarity index 93% rename from src/tools/AgentTool/runAgent.ts rename to packages/builtin-tools/src/tools/AgentTool/runAgent.ts index 3672ba577..baeed9022 100644 --- a/src/tools/AgentTool/runAgent.ts +++ b/packages/builtin-tools/src/tools/AgentTool/runAgent.ts @@ -3,32 +3,32 @@ import type { UUID } from 'crypto' import { randomUUID } from 'crypto' import uniqBy from 'lodash-es/uniqBy.js' import { logForDebugging } from 'src/utils/debug.js' -import { getProjectRoot, getSessionId } from '../../bootstrap/state.js' -import { getCommand, getSkillToolCommands, hasCommand } from '../../commands.js' +import { getProjectRoot, getSessionId } from 'src/bootstrap/state.js' +import { getCommand, getSkillToolCommands, hasCommand } from 'src/commands.js' import { DEFAULT_AGENT_PROMPT, enhanceSystemPromptWithEnvDetails, -} from '../../constants/prompts.js' -import type { QuerySource } from '../../constants/querySource.js' -import { getSystemContext, getUserContext } from '../../context.js' -import type { CanUseToolFn } from '../../hooks/useCanUseTool.js' -import { query } from '../../query.js' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' -import { getDumpPromptsPath } from '../../services/api/dumpPrompts.js' -import { cleanupAgentTracking } from '../../services/api/promptCacheBreakDetection.js' +} from 'src/constants/prompts.js' +import type { QuerySource } from 'src/constants/querySource.js' +import { getSystemContext, getUserContext } from 'src/context.js' +import type { CanUseToolFn } from 'src/hooks/useCanUseTool.js' +import { query } from 'src/query.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import { getDumpPromptsPath } from 'src/services/api/dumpPrompts.js' +import { cleanupAgentTracking } from 'src/services/api/promptCacheBreakDetection.js' import { connectToServer, fetchToolsForClient, -} from '../../services/mcp/client.js' -import { getMcpConfigByName } from '../../services/mcp/config.js' +} from 'src/services/mcp/client.js' +import { getMcpConfigByName } from 'src/services/mcp/config.js' import type { MCPServerConnection, ScopedMcpServerConfig, -} from '../../services/mcp/types.js' -import type { Tool, Tools, ToolUseContext } from '../../Tool.js' -import { killShellTasksForAgent } from '../../tasks/LocalShellTask/killShellTasks.js' -import type { Command } from '../../types/command.js' -import type { AgentId } from '../../types/ids.js' +} from 'src/services/mcp/types.js' +import type { Tool, Tools, ToolUseContext } from 'src/Tool.js' +import { killShellTasksForAgent } from 'src/tasks/LocalShellTask/killShellTasks.js' +import type { Command } from 'src/types/command.js' +import type { AgentId } from 'src/types/ids.js' import type { AssistantMessage, Message, @@ -39,52 +39,52 @@ import type { TombstoneMessage, ToolUseSummaryMessage, UserMessage, -} from '../../types/message.js' -import { createAttachmentMessage } from '../../utils/attachments.js' -import { AbortError } from '../../utils/errors.js' -import { getDisplayPath } from '../../utils/file.js' +} from 'src/types/message.js' +import { createAttachmentMessage } from 'src/utils/attachments.js' +import { AbortError } from 'src/utils/errors.js' +import { getDisplayPath } from 'src/utils/file.js' import { cloneFileStateCache, createFileStateCacheWithSizeLimit, READ_FILE_STATE_CACHE_SIZE, -} from '../../utils/fileStateCache.js' +} from 'src/utils/fileStateCache.js' import { type CacheSafeParams, createSubagentContext, -} from '../../utils/forkedAgent.js' -import { registerFrontmatterHooks } from '../../utils/hooks/registerFrontmatterHooks.js' -import { clearSessionHooks } from '../../utils/hooks/sessionHooks.js' -import { executeSubagentStartHooks } from '../../utils/hooks.js' -import { createUserMessage } from '../../utils/messages.js' -import { getAgentModel } from '../../utils/model/agent.js' -import { getAPIProvider } from '../../utils/model/providers.js' +} from 'src/utils/forkedAgent.js' +import { registerFrontmatterHooks } from 'src/utils/hooks/registerFrontmatterHooks.js' +import { clearSessionHooks } from 'src/utils/hooks/sessionHooks.js' +import { executeSubagentStartHooks } from 'src/utils/hooks.js' +import { createUserMessage } from 'src/utils/messages.js' +import { getAgentModel } from 'src/utils/model/agent.js' +import { getAPIProvider } from 'src/utils/model/providers.js' import { createSubagentTrace, endTrace, isLangfuseEnabled, -} from '../../services/langfuse/index.js' -import type { ModelAlias } from '../../utils/model/aliases.js' +} from 'src/services/langfuse/index.js' +import type { ModelAlias } from 'src/utils/model/aliases.js' import { clearAgentTranscriptSubdir, recordSidechainTranscript, setAgentTranscriptSubdir, writeAgentMetadata, -} from '../../utils/sessionStorage.js' +} from 'src/utils/sessionStorage.js' import { isRestrictedToPluginOnly, isSourceAdminTrusted, -} from '../../utils/settings/pluginOnlyPolicy.js' +} from 'src/utils/settings/pluginOnlyPolicy.js' import { asSystemPrompt, type SystemPrompt, -} from '../../utils/systemPromptType.js' +} from 'src/utils/systemPromptType.js' import { isPerfettoTracingEnabled, registerAgent as registerPerfettoAgent, unregisterAgent as unregisterPerfettoAgent, -} from '../../utils/telemetry/perfettoTracing.js' -import type { ContentReplacementState } from '../../utils/toolResultStorage.js' -import { createAgentId } from '../../utils/uuid.js' +} from 'src/utils/telemetry/perfettoTracing.js' +import type { ContentReplacementState } from 'src/utils/toolResultStorage.js' +import { createAgentId } from 'src/utils/uuid.js' import { resolveAgentTools } from './agentToolUtils.js' import { type AgentDefinition, isBuiltInAgent } from './loadAgentsDir.js' @@ -622,7 +622,7 @@ export async function* runAgent({ // Load all skill contents concurrently and add to initial messages const { formatSkillLoadingMetadata } = await import( - '../../utils/processUserInput/processSlashCommand.js' + 'src/utils/processUserInput/processSlashCommand.js' ) const loaded = await Promise.all( validSkills.map(async ({ skillName, skill }) => ({ @@ -875,7 +875,7 @@ export async function* runAgent({ /* eslint-disable @typescript-eslint/no-require-imports */ if (feature('MONITOR_TOOL')) { const mcpMod = - require('../../tasks/MonitorMcpTask/MonitorMcpTask.js') as typeof import('../../tasks/MonitorMcpTask/MonitorMcpTask.js') + require('src/tasks/MonitorMcpTask/MonitorMcpTask.js') as typeof import('src/tasks/MonitorMcpTask/MonitorMcpTask.js') mcpMod.killMonitorMcpTasksForAgent( agentId, toolUseContext.getAppState, diff --git a/src/tools/AgentTool/src/Tool.ts b/packages/builtin-tools/src/tools/AgentTool/src/Tool.ts similarity index 100% rename from src/tools/AgentTool/src/Tool.ts rename to packages/builtin-tools/src/tools/AgentTool/src/Tool.ts diff --git a/src/tools/AgentTool/src/components/ConfigurableShortcutHint.ts b/packages/builtin-tools/src/tools/AgentTool/src/components/ConfigurableShortcutHint.ts similarity index 100% rename from src/tools/AgentTool/src/components/ConfigurableShortcutHint.ts rename to packages/builtin-tools/src/tools/AgentTool/src/components/ConfigurableShortcutHint.ts diff --git a/src/tools/AgentTool/src/components/CtrlOToExpand.ts b/packages/builtin-tools/src/tools/AgentTool/src/components/CtrlOToExpand.ts similarity index 100% rename from src/tools/AgentTool/src/components/CtrlOToExpand.ts rename to packages/builtin-tools/src/tools/AgentTool/src/components/CtrlOToExpand.ts diff --git a/src/tools/AgentTool/src/components/design-system/Byline.ts b/packages/builtin-tools/src/tools/AgentTool/src/components/design-system/Byline.ts similarity index 100% rename from src/tools/AgentTool/src/components/design-system/Byline.ts rename to packages/builtin-tools/src/tools/AgentTool/src/components/design-system/Byline.ts diff --git a/src/tools/AgentTool/src/components/design-system/KeyboardShortcutHint.ts b/packages/builtin-tools/src/tools/AgentTool/src/components/design-system/KeyboardShortcutHint.ts similarity index 100% rename from src/tools/AgentTool/src/components/design-system/KeyboardShortcutHint.ts rename to packages/builtin-tools/src/tools/AgentTool/src/components/design-system/KeyboardShortcutHint.ts diff --git a/src/tools/AgentTool/src/types/message.ts b/packages/builtin-tools/src/tools/AgentTool/src/types/message.ts similarity index 100% rename from src/tools/AgentTool/src/types/message.ts rename to packages/builtin-tools/src/tools/AgentTool/src/types/message.ts diff --git a/src/tools/AgentTool/src/utils/debug.ts b/packages/builtin-tools/src/tools/AgentTool/src/utils/debug.ts similarity index 100% rename from src/tools/AgentTool/src/utils/debug.ts rename to packages/builtin-tools/src/tools/AgentTool/src/utils/debug.ts diff --git a/src/tools/AgentTool/src/utils/promptCategory.ts b/packages/builtin-tools/src/tools/AgentTool/src/utils/promptCategory.ts similarity index 100% rename from src/tools/AgentTool/src/utils/promptCategory.ts rename to packages/builtin-tools/src/tools/AgentTool/src/utils/promptCategory.ts diff --git a/src/tools/AgentTool/src/utils/settings/constants.ts b/packages/builtin-tools/src/tools/AgentTool/src/utils/settings/constants.ts similarity index 100% rename from src/tools/AgentTool/src/utils/settings/constants.ts rename to packages/builtin-tools/src/tools/AgentTool/src/utils/settings/constants.ts diff --git a/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx b/packages/builtin-tools/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx similarity index 98% rename from src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx rename to packages/builtin-tools/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx index 4c77e7da6..c2c964d97 100644 --- a/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +++ b/packages/builtin-tools/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx @@ -9,9 +9,9 @@ import { BLACK_CIRCLE } from 'src/constants/figures.js' import { getModeColor } from 'src/utils/permissions/PermissionMode.js' import { z } from 'zod/v4' import { Box, Text } from '@anthropic/ink' -import type { Tool } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { Tool } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { ASK_USER_QUESTION_TOOL_CHIP_WIDTH, ASK_USER_QUESTION_TOOL_NAME, diff --git a/src/tools/AskUserQuestionTool/prompt.ts b/packages/builtin-tools/src/tools/AskUserQuestionTool/prompt.ts similarity index 100% rename from src/tools/AskUserQuestionTool/prompt.ts rename to packages/builtin-tools/src/tools/AskUserQuestionTool/prompt.ts diff --git a/src/tools/AskUserQuestionTool/src/bootstrap/state.ts b/packages/builtin-tools/src/tools/AskUserQuestionTool/src/bootstrap/state.ts similarity index 100% rename from src/tools/AskUserQuestionTool/src/bootstrap/state.ts rename to packages/builtin-tools/src/tools/AskUserQuestionTool/src/bootstrap/state.ts diff --git a/src/tools/AskUserQuestionTool/src/components/MessageResponse.ts b/packages/builtin-tools/src/tools/AskUserQuestionTool/src/components/MessageResponse.ts similarity index 100% rename from src/tools/AskUserQuestionTool/src/components/MessageResponse.ts rename to packages/builtin-tools/src/tools/AskUserQuestionTool/src/components/MessageResponse.ts diff --git a/src/tools/AskUserQuestionTool/src/constants/figures.ts b/packages/builtin-tools/src/tools/AskUserQuestionTool/src/constants/figures.ts similarity index 100% rename from src/tools/AskUserQuestionTool/src/constants/figures.ts rename to packages/builtin-tools/src/tools/AskUserQuestionTool/src/constants/figures.ts diff --git a/src/tools/AskUserQuestionTool/src/utils/permissions/PermissionMode.ts b/packages/builtin-tools/src/tools/AskUserQuestionTool/src/utils/permissions/PermissionMode.ts similarity index 100% rename from src/tools/AskUserQuestionTool/src/utils/permissions/PermissionMode.ts rename to packages/builtin-tools/src/tools/AskUserQuestionTool/src/utils/permissions/PermissionMode.ts diff --git a/src/tools/BashTool/BashTool.tsx b/packages/builtin-tools/src/tools/BashTool/BashTool.tsx similarity index 95% rename from src/tools/BashTool/BashTool.tsx rename to packages/builtin-tools/src/tools/BashTool/BashTool.tsx index 24499566e..5966ba418 100644 --- a/src/tools/BashTool/BashTool.tsx +++ b/packages/builtin-tools/src/tools/BashTool/BashTool.tsx @@ -10,70 +10,70 @@ import * as React from 'react' import type { CanUseToolFn } from 'src/hooks/useCanUseTool.js' import type { AppState } from 'src/state/AppState.js' import { z } from 'zod/v4' -import { getKairosActive } from '../../bootstrap/state.js' -import { TOOL_SUMMARY_MAX_LENGTH } from '../../constants/toolLimits.js' +import { getKairosActive } from 'src/bootstrap/state.js' +import { TOOL_SUMMARY_MAX_LENGTH } from 'src/constants/toolLimits.js' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, -} from '../../services/analytics/index.js' -import { notifyVscodeFileUpdated } from '../../services/mcp/vscodeSdkMcp.js' +} from 'src/services/analytics/index.js' +import { notifyVscodeFileUpdated } from 'src/services/mcp/vscodeSdkMcp.js' import type { SetToolJSXFn, ToolCallProgress, ToolUseContext, ValidationResult, -} from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' +} from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' import { backgroundExistingForegroundTask, markTaskNotified, registerForeground, spawnShellTask, unregisterForeground, -} from '../../tasks/LocalShellTask/LocalShellTask.js' -import type { AgentId } from '../../types/ids.js' -import type { AssistantMessage } from '../../types/message.js' -import { parseForSecurity } from '../../utils/bash/ast.js' +} from 'src/tasks/LocalShellTask/LocalShellTask.js' +import type { AgentId } from 'src/types/ids.js' +import type { AssistantMessage } from 'src/types/message.js' +import { parseForSecurity } from 'src/utils/bash/ast.js' import { splitCommand_DEPRECATED, splitCommandWithOperators, -} from '../../utils/bash/commands.js' -import { extractClaudeCodeHints } from '../../utils/claudeCodeHints.js' -import { detectCodeIndexingFromCommand } from '../../utils/codeIndexing.js' -import { isEnvTruthy } from '../../utils/envUtils.js' -import { isENOENT, ShellError } from '../../utils/errors.js' +} from 'src/utils/bash/commands.js' +import { extractClaudeCodeHints } from 'src/utils/claudeCodeHints.js' +import { detectCodeIndexingFromCommand } from 'src/utils/codeIndexing.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' +import { isENOENT, ShellError } from 'src/utils/errors.js' import { detectFileEncoding, detectLineEndings, getFileModificationTime, writeTextContent, -} from '../../utils/file.js' +} from 'src/utils/file.js' import { fileHistoryEnabled, fileHistoryTrackEdit, -} from '../../utils/fileHistory.js' -import { truncate } from '../../utils/format.js' -import { getFsImplementation } from '../../utils/fsOperations.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { expandPath } from '../../utils/path.js' -import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' -import { maybeRecordPluginHint } from '../../utils/plugins/hintRecommendation.js' -import { exec } from '../../utils/Shell.js' -import type { ExecResult } from '../../utils/ShellCommand.js' -import { SandboxManager } from '../../utils/sandbox/sandbox-adapter.js' -import { semanticBoolean } from '../../utils/semanticBoolean.js' -import { semanticNumber } from '../../utils/semanticNumber.js' -import { EndTruncatingAccumulator } from '../../utils/stringUtils.js' -import { getTaskOutputPath } from '../../utils/task/diskOutput.js' -import { TaskOutput } from '../../utils/task/TaskOutput.js' -import { isOutputLineTruncated } from '../../utils/terminal.js' +} from 'src/utils/fileHistory.js' +import { truncate } from 'src/utils/format.js' +import { getFsImplementation } from 'src/utils/fsOperations.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { expandPath } from 'src/utils/path.js' +import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' +import { maybeRecordPluginHint } from 'src/utils/plugins/hintRecommendation.js' +import { exec } from 'src/utils/Shell.js' +import type { ExecResult } from 'src/utils/ShellCommand.js' +import { SandboxManager } from 'src/utils/sandbox/sandbox-adapter.js' +import { semanticBoolean } from 'src/utils/semanticBoolean.js' +import { semanticNumber } from 'src/utils/semanticNumber.js' +import { EndTruncatingAccumulator } from 'src/utils/stringUtils.js' +import { getTaskOutputPath } from 'src/utils/task/diskOutput.js' +import { TaskOutput } from 'src/utils/task/TaskOutput.js' +import { isOutputLineTruncated } from 'src/utils/terminal.js' import { buildLargeToolResultMessage, ensureToolResultsDir, generatePreview, getToolResultPath, PREVIEW_SIZE_BYTES, -} from '../../utils/toolResultStorage.js' +} from 'src/utils/toolResultStorage.js' import { userFacingName as fileEditUserFacingName } from '../FileEditTool/UI.js' import { trackGitOperations } from '../shared/gitOperationTracking.js' import { @@ -506,9 +506,9 @@ type OutputSchema = ReturnType export type Out = z.infer // Re-export BashProgress from centralized types to break import cycles -export type { BashProgress } from '../../types/tools.js' +export type { BashProgress } from 'src/types/tools.js' -import type { BashProgress } from '../../types/tools.js' +import type { BashProgress } from 'src/types/tools.js' /** * Checks if a command is allowed to be automatically backgrounded diff --git a/src/tools/BashTool/BashToolResultMessage.tsx b/packages/builtin-tools/src/tools/BashTool/BashToolResultMessage.tsx similarity index 94% rename from src/tools/BashTool/BashToolResultMessage.tsx rename to packages/builtin-tools/src/tools/BashTool/BashToolResultMessage.tsx index 6b1534bfb..640cac468 100644 --- a/src/tools/BashTool/BashToolResultMessage.tsx +++ b/packages/builtin-tools/src/tools/BashTool/BashToolResultMessage.tsx @@ -1,9 +1,9 @@ import React from 'react' import { removeSandboxViolationTags } from 'src/utils/sandbox/sandbox-ui-utils.js' import { KeyboardShortcutHint } from '@anthropic/ink' -import { MessageResponse } from '../../components/MessageResponse.js' -import { OutputLine } from '../../components/shell/OutputLine.js' -import { ShellTimeDisplay } from '../../components/shell/ShellTimeDisplay.js' +import { MessageResponse } from 'src/components/MessageResponse.js' +import { OutputLine } from 'src/components/shell/OutputLine.js' +import { ShellTimeDisplay } from 'src/components/shell/ShellTimeDisplay.js' import { Box, Text } from '@anthropic/ink' import type { Out as BashOut } from './BashTool.js' diff --git a/src/tools/BashTool/UI.tsx b/packages/builtin-tools/src/tools/BashTool/UI.tsx similarity index 85% rename from src/tools/BashTool/UI.tsx rename to packages/builtin-tools/src/tools/BashTool/UI.tsx index 2b0b3bfd3..35437ad09 100644 --- a/src/tools/BashTool/UI.tsx +++ b/packages/builtin-tools/src/tools/BashTool/UI.tsx @@ -1,21 +1,21 @@ import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs' import * as React from 'react' import { KeyboardShortcutHint } from '@anthropic/ink' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' -import { MessageResponse } from '../../components/MessageResponse.js' -import { ShellProgressMessage } from '../../components/shell/ShellProgressMessage.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' +import { MessageResponse } from 'src/components/MessageResponse.js' +import { ShellProgressMessage } from 'src/components/shell/ShellProgressMessage.js' import { Box, Text } from '@anthropic/ink' -import { useKeybinding } from '../../keybindings/useKeybinding.js' -import { useShortcutDisplay } from '../../keybindings/useShortcutDisplay.js' -import { useAppStateStore, useSetAppState } from '../../state/AppState.js' -import type { Tool } from '../../Tool.js' -import { backgroundAll } from '../../tasks/LocalShellTask/LocalShellTask.js' -import type { ProgressMessage } from '../../types/message.js' -import { env } from '../../utils/env.js' -import { isEnvTruthy } from '../../utils/envUtils.js' -import { getDisplayPath } from '../../utils/file.js' -import { isFullscreenEnvEnabled } from '../../utils/fullscreen.js' -import type { ThemeName } from '../../utils/theme.js' +import { useKeybinding } from 'src/keybindings/useKeybinding.js' +import { useShortcutDisplay } from 'src/keybindings/useShortcutDisplay.js' +import { useAppStateStore, useSetAppState } from 'src/state/AppState.js' +import type { Tool } from 'src/Tool.js' +import { backgroundAll } from 'src/tasks/LocalShellTask/LocalShellTask.js' +import type { ProgressMessage } from 'src/types/message.js' +import { env } from 'src/utils/env.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' +import { getDisplayPath } from 'src/utils/file.js' +import { isFullscreenEnvEnabled } from 'src/utils/fullscreen.js' +import type { ThemeName } from 'src/utils/theme.js' import type { BashProgress, BashToolInput, Out } from './BashTool.js' import BashToolResultMessage from './BashToolResultMessage.js' import { extractBashCommentLabel } from './commentLabel.js' diff --git a/src/tools/BashTool/__tests__/commandSemantics.test.ts b/packages/builtin-tools/src/tools/BashTool/__tests__/commandSemantics.test.ts similarity index 100% rename from src/tools/BashTool/__tests__/commandSemantics.test.ts rename to packages/builtin-tools/src/tools/BashTool/__tests__/commandSemantics.test.ts diff --git a/src/tools/BashTool/__tests__/destructiveCommandWarning.test.ts b/packages/builtin-tools/src/tools/BashTool/__tests__/destructiveCommandWarning.test.ts similarity index 100% rename from src/tools/BashTool/__tests__/destructiveCommandWarning.test.ts rename to packages/builtin-tools/src/tools/BashTool/__tests__/destructiveCommandWarning.test.ts diff --git a/src/tools/BashTool/bashCommandHelpers.ts b/packages/builtin-tools/src/tools/BashTool/bashCommandHelpers.ts similarity index 95% rename from src/tools/BashTool/bashCommandHelpers.ts rename to packages/builtin-tools/src/tools/BashTool/bashCommandHelpers.ts index 17eee5689..48f405ac6 100644 --- a/src/tools/BashTool/bashCommandHelpers.ts +++ b/packages/builtin-tools/src/tools/BashTool/bashCommandHelpers.ts @@ -2,16 +2,16 @@ import type { z } from 'zod/v4' import { isUnsafeCompoundCommand_DEPRECATED, splitCommand_DEPRECATED, -} from '../../utils/bash/commands.js' +} from 'src/utils/bash/commands.js' import { buildParsedCommandFromRoot, type IParsedCommand, ParsedCommand, -} from '../../utils/bash/ParsedCommand.js' -import { type Node, PARSE_ABORTED } from '../../utils/bash/parser.js' -import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' -import type { PermissionUpdate } from '../../utils/permissions/PermissionUpdateSchema.js' -import { createPermissionRequestMessage } from '../../utils/permissions/permissions.js' +} from 'src/utils/bash/ParsedCommand.js' +import { type Node, PARSE_ABORTED } from 'src/utils/bash/parser.js' +import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' +import type { PermissionUpdate } from 'src/utils/permissions/PermissionUpdateSchema.js' +import { createPermissionRequestMessage } from 'src/utils/permissions/permissions.js' import { BashTool } from './BashTool.js' import { bashCommandIsSafeAsync_DEPRECATED } from './bashSecurity.js' diff --git a/src/tools/BashTool/bashPermissions.ts b/packages/builtin-tools/src/tools/BashTool/bashPermissions.ts similarity index 98% rename from src/tools/BashTool/bashPermissions.ts rename to packages/builtin-tools/src/tools/BashTool/bashPermissions.ts index a8997f09f..598ece5d2 100644 --- a/src/tools/BashTool/bashPermissions.ts +++ b/packages/builtin-tools/src/tools/BashTool/bashPermissions.ts @@ -1,14 +1,14 @@ import { feature } from 'bun:bundle' import { APIUserAbortError } from '@anthropic-ai/sdk' import type { z } from 'zod/v4' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, -} from '../../services/analytics/index.js' -import type { ToolPermissionContext, ToolUseContext } from '../../Tool.js' -import type { PendingClassifierCheck } from '../../types/permissions.js' -import { count } from '../../utils/array.js' +} from 'src/services/analytics/index.js' +import type { ToolPermissionContext, ToolUseContext } from 'src/Tool.js' +import type { PendingClassifierCheck } from 'src/types/permissions.js' +import { count } from 'src/utils/array.js' import { checkSemantics, nodeTypeId, @@ -16,45 +16,45 @@ import { parseForSecurityFromAst, type Redirect, type SimpleCommand, -} from '../../utils/bash/ast.js' +} from 'src/utils/bash/ast.js' import { type CommandPrefixResult, extractOutputRedirections, getCommandSubcommandPrefix, splitCommand_DEPRECATED, -} from '../../utils/bash/commands.js' -import { parseCommandRaw } from '../../utils/bash/parser.js' -import { tryParseShellCommand } from '../../utils/bash/shellQuote.js' -import { getCwd } from '../../utils/cwd.js' -import { logForDebugging } from '../../utils/debug.js' -import { isEnvTruthy } from '../../utils/envUtils.js' -import { AbortError } from '../../utils/errors.js' +} from 'src/utils/bash/commands.js' +import { parseCommandRaw } from 'src/utils/bash/parser.js' +import { tryParseShellCommand } from 'src/utils/bash/shellQuote.js' +import { getCwd } from 'src/utils/cwd.js' +import { logForDebugging } from 'src/utils/debug.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' +import { AbortError } from 'src/utils/errors.js' import type { ClassifierBehavior, ClassifierResult, -} from '../../utils/permissions/bashClassifier.js' +} from 'src/utils/permissions/bashClassifier.js' import { classifyBashCommand, getBashPromptAllowDescriptions, getBashPromptAskDescriptions, getBashPromptDenyDescriptions, isClassifierPermissionsEnabled, -} from '../../utils/permissions/bashClassifier.js' +} from 'src/utils/permissions/bashClassifier.js' import type { PermissionDecisionReason, PermissionResult, -} from '../../utils/permissions/PermissionResult.js' +} from 'src/utils/permissions/PermissionResult.js' import type { PermissionRule, PermissionRuleValue, -} from '../../utils/permissions/PermissionRule.js' -import { extractRules } from '../../utils/permissions/PermissionUpdate.js' -import type { PermissionUpdate } from '../../utils/permissions/PermissionUpdateSchema.js' -import { permissionRuleValueToString } from '../../utils/permissions/permissionRuleParser.js' +} from 'src/utils/permissions/PermissionRule.js' +import { extractRules } from 'src/utils/permissions/PermissionUpdate.js' +import type { PermissionUpdate } from 'src/utils/permissions/PermissionUpdateSchema.js' +import { permissionRuleValueToString } from 'src/utils/permissions/permissionRuleParser.js' import { createPermissionRequestMessage, getRuleByContentsForTool, -} from '../../utils/permissions/permissions.js' +} from 'src/utils/permissions/permissions.js' import { parsePermissionRule, type ShellPermissionRule, @@ -62,11 +62,11 @@ import { permissionRuleExtractPrefix as sharedPermissionRuleExtractPrefix, suggestionForExactCommand as sharedSuggestionForExactCommand, suggestionForPrefix as sharedSuggestionForPrefix, -} from '../../utils/permissions/shellRuleMatching.js' -import { getPlatform } from '../../utils/platform.js' -import { SandboxManager } from '../../utils/sandbox/sandbox-adapter.js' -import { jsonStringify } from '../../utils/slowOperations.js' -import { windowsPathToPosixPath } from '../../utils/windowsPaths.js' +} from 'src/utils/permissions/shellRuleMatching.js' +import { getPlatform } from 'src/utils/platform.js' +import { SandboxManager } from 'src/utils/sandbox/sandbox-adapter.js' +import { jsonStringify } from 'src/utils/slowOperations.js' +import { windowsPathToPosixPath } from 'src/utils/windowsPaths.js' import { BashTool } from './BashTool.js' import { checkCommandOperatorPermissions } from './bashCommandHelpers.js' import { diff --git a/src/tools/BashTool/bashSecurity.ts b/packages/builtin-tools/src/tools/BashTool/bashSecurity.ts similarity index 99% rename from src/tools/BashTool/bashSecurity.ts rename to packages/builtin-tools/src/tools/BashTool/bashSecurity.ts index a72131110..e274037f1 100644 --- a/src/tools/BashTool/bashSecurity.ts +++ b/packages/builtin-tools/src/tools/BashTool/bashSecurity.ts @@ -1,13 +1,13 @@ import { logEvent } from 'src/services/analytics/index.js' -import { extractHeredocs } from '../../utils/bash/heredoc.js' -import { ParsedCommand } from '../../utils/bash/ParsedCommand.js' +import { extractHeredocs } from 'src/utils/bash/heredoc.js' +import { ParsedCommand } from 'src/utils/bash/ParsedCommand.js' import { hasMalformedTokens, hasShellQuoteSingleQuoteBug, tryParseShellCommand, -} from '../../utils/bash/shellQuote.js' -import type { TreeSitterAnalysis } from '../../utils/bash/treeSitterAnalysis.js' -import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' +} from 'src/utils/bash/shellQuote.js' +import type { TreeSitterAnalysis } from 'src/utils/bash/treeSitterAnalysis.js' +import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' const HEREDOC_IN_SUBSTITUTION = /\$\(.*<): React.ReactNode { diff --git a/src/tools/ConfigTool/constants.ts b/packages/builtin-tools/src/tools/ConfigTool/constants.ts similarity index 100% rename from src/tools/ConfigTool/constants.ts rename to packages/builtin-tools/src/tools/ConfigTool/constants.ts diff --git a/src/tools/ConfigTool/prompt.ts b/packages/builtin-tools/src/tools/ConfigTool/prompt.ts similarity index 95% rename from src/tools/ConfigTool/prompt.ts rename to packages/builtin-tools/src/tools/ConfigTool/prompt.ts index 2441b9567..45e7ddf36 100644 --- a/src/tools/ConfigTool/prompt.ts +++ b/packages/builtin-tools/src/tools/ConfigTool/prompt.ts @@ -1,6 +1,6 @@ import { feature } from 'bun:bundle' -import { getModelOptions } from '../../utils/model/modelOptions.js' -import { isVoiceGrowthBookEnabled } from '../../voice/voiceModeEnabled.js' +import { getModelOptions } from 'src/utils/model/modelOptions.js' +import { isVoiceGrowthBookEnabled } from 'src/voice/voiceModeEnabled.js' import { getOptionsForSetting, SUPPORTED_SETTINGS, diff --git a/src/tools/ConfigTool/supportedSettings.ts b/packages/builtin-tools/src/tools/ConfigTool/supportedSettings.ts similarity index 95% rename from src/tools/ConfigTool/supportedSettings.ts rename to packages/builtin-tools/src/tools/ConfigTool/supportedSettings.ts index 86d7d2d8e..683cfe4d6 100644 --- a/src/tools/ConfigTool/supportedSettings.ts +++ b/packages/builtin-tools/src/tools/ConfigTool/supportedSettings.ts @@ -1,13 +1,13 @@ import { feature } from 'bun:bundle' -import { getRemoteControlAtStartup } from '../../utils/config.js' +import { getRemoteControlAtStartup } from 'src/utils/config.js' import { EDITOR_MODES, NOTIFICATION_CHANNELS, TEAMMATE_MODES, -} from '../../utils/configConstants.js' -import { getModelOptions } from '../../utils/model/modelOptions.js' -import { validateModel } from '../../utils/model/validateModel.js' -import { THEME_NAMES, THEME_SETTINGS } from '../../utils/theme.js' +} from 'src/utils/configConstants.js' +import { getModelOptions } from 'src/utils/model/modelOptions.js' +import { validateModel } from 'src/utils/model/validateModel.js' +import { THEME_NAMES, THEME_SETTINGS } from 'src/utils/theme.js' /** AppState keys that can be synced for immediate UI effect */ type SyncableAppStateKey = 'verbose' | 'mainLoopModel' | 'thinkingEnabled' diff --git a/src/tools/CtxInspectTool/CtxInspectTool.ts b/packages/builtin-tools/src/tools/CtxInspectTool/CtxInspectTool.ts similarity index 92% rename from src/tools/CtxInspectTool/CtxInspectTool.ts rename to packages/builtin-tools/src/tools/CtxInspectTool/CtxInspectTool.ts index 32218ef74..c49933cd2 100644 --- a/src/tools/CtxInspectTool/CtxInspectTool.ts +++ b/packages/builtin-tools/src/tools/CtxInspectTool/CtxInspectTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' const CTX_INSPECT_TOOL_NAME = 'CtxInspect' diff --git a/src/tools/DiscoverSkillsTool/prompt.ts b/packages/builtin-tools/src/tools/DiscoverSkillsTool/prompt.ts similarity index 100% rename from src/tools/DiscoverSkillsTool/prompt.ts rename to packages/builtin-tools/src/tools/DiscoverSkillsTool/prompt.ts diff --git a/src/tools/EnterPlanModeTool/EnterPlanModeTool.ts b/packages/builtin-tools/src/tools/EnterPlanModeTool/EnterPlanModeTool.ts similarity index 89% rename from src/tools/EnterPlanModeTool/EnterPlanModeTool.ts rename to packages/builtin-tools/src/tools/EnterPlanModeTool/EnterPlanModeTool.ts index bd6deb372..47a3f0cc3 100644 --- a/src/tools/EnterPlanModeTool/EnterPlanModeTool.ts +++ b/packages/builtin-tools/src/tools/EnterPlanModeTool/EnterPlanModeTool.ts @@ -3,13 +3,13 @@ import { z } from 'zod/v4' import { getAllowedChannels, handlePlanModeTransition, -} from '../../bootstrap/state.js' -import type { Tool } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { applyPermissionUpdate } from '../../utils/permissions/PermissionUpdate.js' -import { prepareContextForPlanMode } from '../../utils/permissions/permissionSetup.js' -import { isPlanModeInterviewPhaseEnabled } from '../../utils/planModeV2.js' +} from 'src/bootstrap/state.js' +import type { Tool } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { applyPermissionUpdate } from 'src/utils/permissions/PermissionUpdate.js' +import { prepareContextForPlanMode } from 'src/utils/permissions/permissionSetup.js' +import { isPlanModeInterviewPhaseEnabled } from 'src/utils/planModeV2.js' import { ENTER_PLAN_MODE_TOOL_NAME } from './constants.js' import { getEnterPlanModeToolPrompt } from './prompt.js' import { diff --git a/src/tools/EnterPlanModeTool/UI.tsx b/packages/builtin-tools/src/tools/EnterPlanModeTool/UI.tsx similarity index 87% rename from src/tools/EnterPlanModeTool/UI.tsx rename to packages/builtin-tools/src/tools/EnterPlanModeTool/UI.tsx index a1bc5d6c8..2ef22e732 100644 --- a/src/tools/EnterPlanModeTool/UI.tsx +++ b/packages/builtin-tools/src/tools/EnterPlanModeTool/UI.tsx @@ -2,9 +2,9 @@ import * as React from 'react' import { BLACK_CIRCLE } from 'src/constants/figures.js' import { getModeColor } from 'src/utils/permissions/PermissionMode.js' import { Box, Text } from '@anthropic/ink' -import type { ToolProgressData } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import type { ThemeName } from '../../utils/theme.js' +import type { ToolProgressData } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import type { ThemeName } from 'src/utils/theme.js' import type { Output } from './EnterPlanModeTool.js' export function renderToolUseMessage(): React.ReactNode { diff --git a/src/tools/EnterPlanModeTool/constants.ts b/packages/builtin-tools/src/tools/EnterPlanModeTool/constants.ts similarity index 100% rename from src/tools/EnterPlanModeTool/constants.ts rename to packages/builtin-tools/src/tools/EnterPlanModeTool/constants.ts diff --git a/src/tools/EnterPlanModeTool/prompt.ts b/packages/builtin-tools/src/tools/EnterPlanModeTool/prompt.ts similarity index 99% rename from src/tools/EnterPlanModeTool/prompt.ts rename to packages/builtin-tools/src/tools/EnterPlanModeTool/prompt.ts index ab20fd1ef..71126cb67 100644 --- a/src/tools/EnterPlanModeTool/prompt.ts +++ b/packages/builtin-tools/src/tools/EnterPlanModeTool/prompt.ts @@ -1,4 +1,4 @@ -import { isPlanModeInterviewPhaseEnabled } from '../../utils/planModeV2.js' +import { isPlanModeInterviewPhaseEnabled } from 'src/utils/planModeV2.js' import { ASK_USER_QUESTION_TOOL_NAME } from '../AskUserQuestionTool/prompt.js' const WHAT_HAPPENS_SECTION = `## What Happens in Plan Mode diff --git a/src/tools/EnterPlanModeTool/src/constants/figures.ts b/packages/builtin-tools/src/tools/EnterPlanModeTool/src/constants/figures.ts similarity index 100% rename from src/tools/EnterPlanModeTool/src/constants/figures.ts rename to packages/builtin-tools/src/tools/EnterPlanModeTool/src/constants/figures.ts diff --git a/src/tools/EnterPlanModeTool/src/utils/permissions/PermissionMode.ts b/packages/builtin-tools/src/tools/EnterPlanModeTool/src/utils/permissions/PermissionMode.ts similarity index 100% rename from src/tools/EnterPlanModeTool/src/utils/permissions/PermissionMode.ts rename to packages/builtin-tools/src/tools/EnterPlanModeTool/src/utils/permissions/PermissionMode.ts diff --git a/src/tools/EnterWorktreeTool/EnterWorktreeTool.ts b/packages/builtin-tools/src/tools/EnterWorktreeTool/EnterWorktreeTool.ts similarity index 82% rename from src/tools/EnterWorktreeTool/EnterWorktreeTool.ts rename to packages/builtin-tools/src/tools/EnterWorktreeTool/EnterWorktreeTool.ts index eb2e6dbf7..05cfe87ba 100644 --- a/src/tools/EnterWorktreeTool/EnterWorktreeTool.ts +++ b/packages/builtin-tools/src/tools/EnterWorktreeTool/EnterWorktreeTool.ts @@ -1,21 +1,21 @@ import { z } from 'zod/v4' -import { getSessionId, setOriginalCwd } from '../../bootstrap/state.js' -import { clearSystemPromptSections } from '../../constants/systemPromptSections.js' -import { logEvent } from '../../services/analytics/index.js' -import type { Tool } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { clearMemoryFileCaches } from '../../utils/claudemd.js' -import { getCwd } from '../../utils/cwd.js' -import { findCanonicalGitRoot } from '../../utils/git.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { getPlanSlug, getPlansDirectory } from '../../utils/plans.js' -import { setCwd } from '../../utils/Shell.js' -import { saveWorktreeState } from '../../utils/sessionStorage.js' +import { getSessionId, setOriginalCwd } from 'src/bootstrap/state.js' +import { clearSystemPromptSections } from 'src/constants/systemPromptSections.js' +import { logEvent } from 'src/services/analytics/index.js' +import type { Tool } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { clearMemoryFileCaches } from 'src/utils/claudemd.js' +import { getCwd } from 'src/utils/cwd.js' +import { findCanonicalGitRoot } from 'src/utils/git.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { getPlanSlug, getPlansDirectory } from 'src/utils/plans.js' +import { setCwd } from 'src/utils/Shell.js' +import { saveWorktreeState } from 'src/utils/sessionStorage.js' import { createWorktreeForSession, getCurrentWorktreeSession, validateWorktreeSlug, -} from '../../utils/worktree.js' +} from 'src/utils/worktree.js' import { ENTER_WORKTREE_TOOL_NAME } from './constants.js' import { getEnterWorktreeToolPrompt } from './prompt.js' import { renderToolResultMessage, renderToolUseMessage } from './UI.js' diff --git a/src/tools/EnterWorktreeTool/UI.tsx b/packages/builtin-tools/src/tools/EnterWorktreeTool/UI.tsx similarity index 78% rename from src/tools/EnterWorktreeTool/UI.tsx rename to packages/builtin-tools/src/tools/EnterWorktreeTool/UI.tsx index 985186d34..8eeb1510e 100644 --- a/src/tools/EnterWorktreeTool/UI.tsx +++ b/packages/builtin-tools/src/tools/EnterWorktreeTool/UI.tsx @@ -1,8 +1,8 @@ import * as React from 'react' import { Box, Text } from '@anthropic/ink' -import type { ToolProgressData } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import type { ThemeName } from '../../utils/theme.js' +import type { ToolProgressData } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import type { ThemeName } from 'src/utils/theme.js' import type { Output } from './EnterWorktreeTool.js' export function renderToolUseMessage(): React.ReactNode { diff --git a/src/tools/EnterWorktreeTool/constants.ts b/packages/builtin-tools/src/tools/EnterWorktreeTool/constants.ts similarity index 100% rename from src/tools/EnterWorktreeTool/constants.ts rename to packages/builtin-tools/src/tools/EnterWorktreeTool/constants.ts diff --git a/src/tools/EnterWorktreeTool/prompt.ts b/packages/builtin-tools/src/tools/EnterWorktreeTool/prompt.ts similarity index 100% rename from src/tools/EnterWorktreeTool/prompt.ts rename to packages/builtin-tools/src/tools/EnterWorktreeTool/prompt.ts diff --git a/src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts b/packages/builtin-tools/src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts similarity index 94% rename from src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts rename to packages/builtin-tools/src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts index 5aa83c125..80717d169 100644 --- a/src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts +++ b/packages/builtin-tools/src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts @@ -7,37 +7,37 @@ import { setHasExitedPlanMode, setNeedsAutoModeExitAttachment, setNeedsPlanModeExitAttachment, -} from '../../bootstrap/state.js' -import { logEvent } from '../../services/analytics/index.js' -import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from '../../services/analytics/metadata.js' +} from 'src/bootstrap/state.js' +import { logEvent } from 'src/services/analytics/index.js' +import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from 'src/services/analytics/metadata.js' import { buildTool, type Tool, type ToolDef, toolMatchesName, -} from '../../Tool.js' -import { formatAgentId, generateRequestId } from '../../utils/agentId.js' -import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js' -import { logForDebugging } from '../../utils/debug.js' +} from 'src/Tool.js' +import { formatAgentId, generateRequestId } from 'src/utils/agentId.js' +import { isAgentSwarmsEnabled } from 'src/utils/agentSwarmsEnabled.js' +import { logForDebugging } from 'src/utils/debug.js' import { findInProcessTeammateTaskId, setAwaitingPlanApproval, -} from '../../utils/inProcessTeammateHelpers.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { logError } from '../../utils/log.js' +} from 'src/utils/inProcessTeammateHelpers.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { logError } from 'src/utils/log.js' import { getPlan, getPlanFilePath, persistFileSnapshotIfRemote, -} from '../../utils/plans.js' -import { jsonStringify } from '../../utils/slowOperations.js' +} from 'src/utils/plans.js' +import { jsonStringify } from 'src/utils/slowOperations.js' import { getAgentName, getTeamName, isPlanModeRequired, isTeammate, -} from '../../utils/teammate.js' -import { writeToMailbox } from '../../utils/teammateMailbox.js' +} from 'src/utils/teammate.js' +import { writeToMailbox } from 'src/utils/teammateMailbox.js' import { AGENT_TOOL_NAME } from '../AgentTool/constants.js' import { TEAM_CREATE_TOOL_NAME } from '../TeamCreateTool/constants.js' import { EXIT_PLAN_MODE_V2_TOOL_NAME } from './constants.js' @@ -50,10 +50,10 @@ import { /* eslint-disable @typescript-eslint/no-require-imports */ const autoModeStateModule = feature('TRANSCRIPT_CLASSIFIER') - ? (require('../../utils/permissions/autoModeState.js') as typeof import('../../utils/permissions/autoModeState.js')) + ? (require('src/utils/permissions/autoModeState.js') as typeof import('src/utils/permissions/autoModeState.js')) : null const permissionSetupModule = feature('TRANSCRIPT_CLASSIFIER') - ? (require('../../utils/permissions/permissionSetup.js') as typeof import('../../utils/permissions/permissionSetup.js')) + ? (require('src/utils/permissions/permissionSetup.js') as typeof import('src/utils/permissions/permissionSetup.js')) : null /* eslint-enable @typescript-eslint/no-require-imports */ diff --git a/src/tools/ExitPlanModeTool/UI.tsx b/packages/builtin-tools/src/tools/ExitPlanModeTool/UI.tsx similarity index 90% rename from src/tools/ExitPlanModeTool/UI.tsx rename to packages/builtin-tools/src/tools/ExitPlanModeTool/UI.tsx index 789ea4ccf..2976a1391 100644 --- a/src/tools/ExitPlanModeTool/UI.tsx +++ b/packages/builtin-tools/src/tools/ExitPlanModeTool/UI.tsx @@ -5,11 +5,11 @@ import { RejectedPlanMessage } from 'src/components/messages/UserToolResultMessa import { BLACK_CIRCLE } from 'src/constants/figures.js' import { getModeColor } from 'src/utils/permissions/PermissionMode.js' import { Box, Text } from '@anthropic/ink' -import type { ToolProgressData } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import { getDisplayPath } from '../../utils/file.js' -import { getPlan } from '../../utils/plans.js' -import type { ThemeName } from '../../utils/theme.js' +import type { ToolProgressData } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import { getDisplayPath } from 'src/utils/file.js' +import { getPlan } from 'src/utils/plans.js' +import type { ThemeName } from 'src/utils/theme.js' import type { Output } from './ExitPlanModeV2Tool.js' export function renderToolUseMessage(): React.ReactNode { diff --git a/src/tools/ExitPlanModeTool/constants.ts b/packages/builtin-tools/src/tools/ExitPlanModeTool/constants.ts similarity index 100% rename from src/tools/ExitPlanModeTool/constants.ts rename to packages/builtin-tools/src/tools/ExitPlanModeTool/constants.ts diff --git a/src/tools/ExitPlanModeTool/prompt.ts b/packages/builtin-tools/src/tools/ExitPlanModeTool/prompt.ts similarity index 100% rename from src/tools/ExitPlanModeTool/prompt.ts rename to packages/builtin-tools/src/tools/ExitPlanModeTool/prompt.ts diff --git a/src/tools/ExitPlanModeTool/src/components/Markdown.ts b/packages/builtin-tools/src/tools/ExitPlanModeTool/src/components/Markdown.ts similarity index 100% rename from src/tools/ExitPlanModeTool/src/components/Markdown.ts rename to packages/builtin-tools/src/tools/ExitPlanModeTool/src/components/Markdown.ts diff --git a/src/tools/ExitPlanModeTool/src/components/MessageResponse.ts b/packages/builtin-tools/src/tools/ExitPlanModeTool/src/components/MessageResponse.ts similarity index 100% rename from src/tools/ExitPlanModeTool/src/components/MessageResponse.ts rename to packages/builtin-tools/src/tools/ExitPlanModeTool/src/components/MessageResponse.ts diff --git a/src/tools/ExitPlanModeTool/src/components/messages/UserToolResultMessage/RejectedPlanMessage.ts b/packages/builtin-tools/src/tools/ExitPlanModeTool/src/components/messages/UserToolResultMessage/RejectedPlanMessage.ts similarity index 100% rename from src/tools/ExitPlanModeTool/src/components/messages/UserToolResultMessage/RejectedPlanMessage.ts rename to packages/builtin-tools/src/tools/ExitPlanModeTool/src/components/messages/UserToolResultMessage/RejectedPlanMessage.ts diff --git a/src/tools/ExitPlanModeTool/src/constants/figures.ts b/packages/builtin-tools/src/tools/ExitPlanModeTool/src/constants/figures.ts similarity index 100% rename from src/tools/ExitPlanModeTool/src/constants/figures.ts rename to packages/builtin-tools/src/tools/ExitPlanModeTool/src/constants/figures.ts diff --git a/src/tools/ExitPlanModeTool/src/utils/permissions/PermissionMode.ts b/packages/builtin-tools/src/tools/ExitPlanModeTool/src/utils/permissions/PermissionMode.ts similarity index 100% rename from src/tools/ExitPlanModeTool/src/utils/permissions/PermissionMode.ts rename to packages/builtin-tools/src/tools/ExitPlanModeTool/src/utils/permissions/PermissionMode.ts diff --git a/src/tools/ExitWorktreeTool/ExitWorktreeTool.ts b/packages/builtin-tools/src/tools/ExitWorktreeTool/ExitWorktreeTool.ts similarity index 93% rename from src/tools/ExitWorktreeTool/ExitWorktreeTool.ts rename to packages/builtin-tools/src/tools/ExitWorktreeTool/ExitWorktreeTool.ts index 2d735c071..2f40f25c3 100644 --- a/src/tools/ExitWorktreeTool/ExitWorktreeTool.ts +++ b/packages/builtin-tools/src/tools/ExitWorktreeTool/ExitWorktreeTool.ts @@ -4,25 +4,25 @@ import { getProjectRoot, setOriginalCwd, setProjectRoot, -} from '../../bootstrap/state.js' -import { clearSystemPromptSections } from '../../constants/systemPromptSections.js' -import { logEvent } from '../../services/analytics/index.js' -import type { Tool } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { count } from '../../utils/array.js' -import { clearMemoryFileCaches } from '../../utils/claudemd.js' -import { execFileNoThrow } from '../../utils/execFileNoThrow.js' -import { updateHooksConfigSnapshot } from '../../utils/hooks/hooksConfigSnapshot.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { getPlansDirectory } from '../../utils/plans.js' -import { setCwd } from '../../utils/Shell.js' -import { saveWorktreeState } from '../../utils/sessionStorage.js' +} from 'src/bootstrap/state.js' +import { clearSystemPromptSections } from 'src/constants/systemPromptSections.js' +import { logEvent } from 'src/services/analytics/index.js' +import type { Tool } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { count } from 'src/utils/array.js' +import { clearMemoryFileCaches } from 'src/utils/claudemd.js' +import { execFileNoThrow } from 'src/utils/execFileNoThrow.js' +import { updateHooksConfigSnapshot } from 'src/utils/hooks/hooksConfigSnapshot.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { getPlansDirectory } from 'src/utils/plans.js' +import { setCwd } from 'src/utils/Shell.js' +import { saveWorktreeState } from 'src/utils/sessionStorage.js' import { cleanupWorktree, getCurrentWorktreeSession, keepWorktree, killTmuxSession, -} from '../../utils/worktree.js' +} from 'src/utils/worktree.js' import { EXIT_WORKTREE_TOOL_NAME } from './constants.js' import { getExitWorktreeToolPrompt } from './prompt.js' import { renderToolResultMessage, renderToolUseMessage } from './UI.js' diff --git a/src/tools/ExitWorktreeTool/UI.tsx b/packages/builtin-tools/src/tools/ExitWorktreeTool/UI.tsx similarity index 82% rename from src/tools/ExitWorktreeTool/UI.tsx rename to packages/builtin-tools/src/tools/ExitWorktreeTool/UI.tsx index a3eccf4ba..0e79a10fc 100644 --- a/src/tools/ExitWorktreeTool/UI.tsx +++ b/packages/builtin-tools/src/tools/ExitWorktreeTool/UI.tsx @@ -1,8 +1,8 @@ import * as React from 'react' import { Box, Text } from '@anthropic/ink' -import type { ToolProgressData } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import type { ThemeName } from '../../utils/theme.js' +import type { ToolProgressData } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import type { ThemeName } from 'src/utils/theme.js' import type { Output } from './ExitWorktreeTool.js' export function renderToolUseMessage(): React.ReactNode { diff --git a/src/tools/ExitWorktreeTool/constants.ts b/packages/builtin-tools/src/tools/ExitWorktreeTool/constants.ts similarity index 100% rename from src/tools/ExitWorktreeTool/constants.ts rename to packages/builtin-tools/src/tools/ExitWorktreeTool/constants.ts diff --git a/src/tools/ExitWorktreeTool/prompt.ts b/packages/builtin-tools/src/tools/ExitWorktreeTool/prompt.ts similarity index 100% rename from src/tools/ExitWorktreeTool/prompt.ts rename to packages/builtin-tools/src/tools/ExitWorktreeTool/prompt.ts diff --git a/src/tools/FileEditTool/FileEditTool.ts b/packages/builtin-tools/src/tools/FileEditTool/FileEditTool.ts similarity index 92% rename from src/tools/FileEditTool/FileEditTool.ts rename to packages/builtin-tools/src/tools/FileEditTool/FileEditTool.ts index 85399420f..42b00676b 100644 --- a/src/tools/FileEditTool/FileEditTool.ts +++ b/packages/builtin-tools/src/tools/FileEditTool/FileEditTool.ts @@ -1,54 +1,54 @@ import { dirname, isAbsolute, sep } from 'path' import { logEvent } from 'src/services/analytics/index.js' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' -import { diagnosticTracker } from '../../services/diagnosticTracking.js' -import { clearDeliveredDiagnosticsForFile } from '../../services/lsp/LSPDiagnosticRegistry.js' -import { getLspServerManager } from '../../services/lsp/manager.js' -import { notifyVscodeFileUpdated } from '../../services/mcp/vscodeSdkMcp.js' -import { checkTeamMemSecrets } from '../../services/teamMemorySync/teamMemSecretGuard.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import { diagnosticTracker } from 'src/services/diagnosticTracking.js' +import { clearDeliveredDiagnosticsForFile } from 'src/services/lsp/LSPDiagnosticRegistry.js' +import { getLspServerManager } from 'src/services/lsp/manager.js' +import { notifyVscodeFileUpdated } from 'src/services/mcp/vscodeSdkMcp.js' +import { checkTeamMemSecrets } from 'src/services/teamMemorySync/teamMemSecretGuard.js' import { activateConditionalSkillsForPaths, addSkillDirectories, discoverSkillDirsForPaths, -} from '../../skills/loadSkillsDir.js' -import type { ToolUseContext } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { getCwd } from '../../utils/cwd.js' -import { logForDebugging } from '../../utils/debug.js' -import { countLinesChanged } from '../../utils/diff.js' -import { isEnvTruthy } from '../../utils/envUtils.js' -import { isENOENT } from '../../utils/errors.js' +} from 'src/skills/loadSkillsDir.js' +import type { ToolUseContext } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { getCwd } from 'src/utils/cwd.js' +import { logForDebugging } from 'src/utils/debug.js' +import { countLinesChanged } from 'src/utils/diff.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' +import { isENOENT } from 'src/utils/errors.js' import { FILE_NOT_FOUND_CWD_NOTE, findSimilarFile, getFileModificationTime, suggestPathUnderCwd, writeTextContent, -} from '../../utils/file.js' +} from 'src/utils/file.js' import { fileHistoryEnabled, fileHistoryTrackEdit, -} from '../../utils/fileHistory.js' -import { logFileOperation } from '../../utils/fileOperationAnalytics.js' +} from 'src/utils/fileHistory.js' +import { logFileOperation } from 'src/utils/fileOperationAnalytics.js' import { type LineEndingType, readFileSyncWithMetadata, -} from '../../utils/fileRead.js' -import { formatFileSize } from '../../utils/format.js' -import { getFsImplementation } from '../../utils/fsOperations.js' +} from 'src/utils/fileRead.js' +import { formatFileSize } from 'src/utils/format.js' +import { getFsImplementation } from 'src/utils/fsOperations.js' import { fetchSingleFileGitDiff, type ToolUseDiff, -} from '../../utils/gitDiff.js' -import { logError } from '../../utils/log.js' -import { expandPath } from '../../utils/path.js' +} from 'src/utils/gitDiff.js' +import { logError } from 'src/utils/log.js' +import { expandPath } from 'src/utils/path.js' import { checkWritePermissionForTool, matchingRuleForInput, -} from '../../utils/permissions/filesystem.js' -import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js' -import { matchWildcardPattern } from '../../utils/permissions/shellRuleMatching.js' -import { validateInputForSettingsFileEdit } from '../../utils/settings/validateEditTool.js' +} from 'src/utils/permissions/filesystem.js' +import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js' +import { matchWildcardPattern } from 'src/utils/permissions/shellRuleMatching.js' +import { validateInputForSettingsFileEdit } from 'src/utils/settings/validateEditTool.js' import { NOTEBOOK_EDIT_TOOL_NAME } from '../NotebookEditTool/constants.js' import { FILE_EDIT_TOOL_NAME, diff --git a/src/tools/FileEditTool/UI.tsx b/packages/builtin-tools/src/tools/FileEditTool/UI.tsx similarity index 90% rename from src/tools/FileEditTool/UI.tsx rename to packages/builtin-tools/src/tools/FileEditTool/UI.tsx index 57223d000..3fbd9a34b 100644 --- a/src/tools/FileEditTool/UI.tsx +++ b/packages/builtin-tools/src/tools/FileEditTool/UI.tsx @@ -5,20 +5,20 @@ import { Suspense, use, useState } from 'react' import { FileEditToolUseRejectedMessage } from 'src/components/FileEditToolUseRejectedMessage.js' import { MessageResponse } from 'src/components/MessageResponse.js' import { extractTag } from 'src/utils/messages.js' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' -import { FileEditToolUpdatedMessage } from '../../components/FileEditToolUpdatedMessage.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' +import { FileEditToolUpdatedMessage } from 'src/components/FileEditToolUpdatedMessage.js' import { Text } from '@anthropic/ink' -import { FilePathLink } from '../../components/FilePathLink.js' -import type { Tools } from '../../Tool.js' -import type { Message, ProgressMessage } from '../../types/message.js' -import { adjustHunkLineNumbers, CONTEXT_LINES } from '../../utils/diff.js' -import { FILE_NOT_FOUND_CWD_NOTE, getDisplayPath } from '../../utils/file.js' -import { logError } from '../../utils/log.js' -import { getPlansDirectory } from '../../utils/plans.js' -import { readEditContext } from '../../utils/readEditContext.js' -import { firstLineOf } from '../../utils/stringUtils.js' -import type { ThemeName } from '../../utils/theme.js' +import { FilePathLink } from 'src/components/FilePathLink.js' +import type { Tools } from 'src/Tool.js' +import type { Message, ProgressMessage } from 'src/types/message.js' +import { adjustHunkLineNumbers, CONTEXT_LINES } from 'src/utils/diff.js' +import { FILE_NOT_FOUND_CWD_NOTE, getDisplayPath } from 'src/utils/file.js' +import { logError } from 'src/utils/log.js' +import { getPlansDirectory } from 'src/utils/plans.js' +import { readEditContext } from 'src/utils/readEditContext.js' +import { firstLineOf } from 'src/utils/stringUtils.js' +import type { ThemeName } from 'src/utils/theme.js' import type { FileEditOutput } from './types.js' import { findActualString, diff --git a/src/tools/FileEditTool/__tests__/utils.test.ts b/packages/builtin-tools/src/tools/FileEditTool/__tests__/utils.test.ts similarity index 100% rename from src/tools/FileEditTool/__tests__/utils.test.ts rename to packages/builtin-tools/src/tools/FileEditTool/__tests__/utils.test.ts diff --git a/src/tools/FileEditTool/constants.ts b/packages/builtin-tools/src/tools/FileEditTool/constants.ts similarity index 100% rename from src/tools/FileEditTool/constants.ts rename to packages/builtin-tools/src/tools/FileEditTool/constants.ts diff --git a/src/tools/FileEditTool/prompt.ts b/packages/builtin-tools/src/tools/FileEditTool/prompt.ts similarity index 96% rename from src/tools/FileEditTool/prompt.ts rename to packages/builtin-tools/src/tools/FileEditTool/prompt.ts index 5a4d93add..5b6031fc9 100644 --- a/src/tools/FileEditTool/prompt.ts +++ b/packages/builtin-tools/src/tools/FileEditTool/prompt.ts @@ -1,4 +1,4 @@ -import { isCompactLinePrefixEnabled } from '../../utils/file.js' +import { isCompactLinePrefixEnabled } from 'src/utils/file.js' import { FILE_READ_TOOL_NAME } from '../FileReadTool/prompt.js' function getPreReadInstruction(): string { diff --git a/src/tools/FileEditTool/src/components/FileEditToolUseRejectedMessage.ts b/packages/builtin-tools/src/tools/FileEditTool/src/components/FileEditToolUseRejectedMessage.ts similarity index 100% rename from src/tools/FileEditTool/src/components/FileEditToolUseRejectedMessage.ts rename to packages/builtin-tools/src/tools/FileEditTool/src/components/FileEditToolUseRejectedMessage.ts diff --git a/src/tools/FileEditTool/src/components/MessageResponse.ts b/packages/builtin-tools/src/tools/FileEditTool/src/components/MessageResponse.ts similarity index 100% rename from src/tools/FileEditTool/src/components/MessageResponse.ts rename to packages/builtin-tools/src/tools/FileEditTool/src/components/MessageResponse.ts diff --git a/src/tools/FileEditTool/src/services/analytics/index.ts b/packages/builtin-tools/src/tools/FileEditTool/src/services/analytics/index.ts similarity index 100% rename from src/tools/FileEditTool/src/services/analytics/index.ts rename to packages/builtin-tools/src/tools/FileEditTool/src/services/analytics/index.ts diff --git a/src/tools/FileEditTool/src/utils/log.ts b/packages/builtin-tools/src/tools/FileEditTool/src/utils/log.ts similarity index 100% rename from src/tools/FileEditTool/src/utils/log.ts rename to packages/builtin-tools/src/tools/FileEditTool/src/utils/log.ts diff --git a/src/tools/FileEditTool/src/utils/messages.ts b/packages/builtin-tools/src/tools/FileEditTool/src/utils/messages.ts similarity index 100% rename from src/tools/FileEditTool/src/utils/messages.ts rename to packages/builtin-tools/src/tools/FileEditTool/src/utils/messages.ts diff --git a/src/tools/FileEditTool/src/utils/path.ts b/packages/builtin-tools/src/tools/FileEditTool/src/utils/path.ts similarity index 100% rename from src/tools/FileEditTool/src/utils/path.ts rename to packages/builtin-tools/src/tools/FileEditTool/src/utils/path.ts diff --git a/src/tools/FileEditTool/src/utils/stringUtils.ts b/packages/builtin-tools/src/tools/FileEditTool/src/utils/stringUtils.ts similarity index 100% rename from src/tools/FileEditTool/src/utils/stringUtils.ts rename to packages/builtin-tools/src/tools/FileEditTool/src/utils/stringUtils.ts diff --git a/src/tools/FileEditTool/types.ts b/packages/builtin-tools/src/tools/FileEditTool/types.ts similarity index 95% rename from src/tools/FileEditTool/types.ts rename to packages/builtin-tools/src/tools/FileEditTool/types.ts index 86be2683e..6517eaa94 100644 --- a/src/tools/FileEditTool/types.ts +++ b/packages/builtin-tools/src/tools/FileEditTool/types.ts @@ -1,6 +1,6 @@ import { z } from 'zod/v4' -import { lazySchema } from '../../utils/lazySchema.js' -import { semanticBoolean } from '../../utils/semanticBoolean.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { semanticBoolean } from 'src/utils/semanticBoolean.js' // The input schema with optional replace_all const inputSchema = lazySchema(() => diff --git a/src/tools/FileEditTool/utils.ts b/packages/builtin-tools/src/tools/FileEditTool/utils.ts similarity index 99% rename from src/tools/FileEditTool/utils.ts rename to packages/builtin-tools/src/tools/FileEditTool/utils.ts index 2520ed553..6de429b34 100644 --- a/src/tools/FileEditTool/utils.ts +++ b/packages/builtin-tools/src/tools/FileEditTool/utils.ts @@ -6,13 +6,13 @@ import { DIFF_TIMEOUT_MS, getPatchForDisplay, getPatchFromContents, -} from '../../utils/diff.js' -import { errorMessage, isENOENT } from '../../utils/errors.js' +} from 'src/utils/diff.js' +import { errorMessage, isENOENT } from 'src/utils/errors.js' import { addLineNumbers, convertLeadingTabsToSpaces, readFileSyncCached, -} from '../../utils/file.js' +} from 'src/utils/file.js' import type { EditInput, FileEdit } from './types.js' // Claude can't output curly quotes, so we define them as constants here for Claude to use diff --git a/src/tools/FileReadTool/FileReadTool.ts b/packages/builtin-tools/src/tools/FileReadTool/FileReadTool.ts similarity index 95% rename from src/tools/FileReadTool/FileReadTool.ts rename to packages/builtin-tools/src/tools/FileReadTool/FileReadTool.ts index 45c676e90..3dc9a21cc 100644 --- a/src/tools/FileReadTool/FileReadTool.ts +++ b/packages/builtin-tools/src/tools/FileReadTool/FileReadTool.ts @@ -7,39 +7,39 @@ import { PDF_AT_MENTION_INLINE_THRESHOLD, PDF_EXTRACT_SIZE_THRESHOLD, PDF_MAX_PAGES_PER_READ, -} from '../../constants/apiLimits.js' -import { hasBinaryExtension } from '../../constants/files.js' -import { memoryFreshnessNote } from '../../memdir/memoryAge.js' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' -import { logEvent } from '../../services/analytics/index.js' +} from 'src/constants/apiLimits.js' +import { hasBinaryExtension } from 'src/constants/files.js' +import { memoryFreshnessNote } from 'src/memdir/memoryAge.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import { logEvent } from 'src/services/analytics/index.js' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, getFileExtensionForAnalytics, -} from '../../services/analytics/metadata.js' +} from 'src/services/analytics/metadata.js' import { countTokensWithAPI, roughTokenCountEstimationForFileType, -} from '../../services/tokenEstimation.js' +} from 'src/services/tokenEstimation.js' import { activateConditionalSkillsForPaths, addSkillDirectories, discoverSkillDirsForPaths, -} from '../../skills/loadSkillsDir.js' -import type { ToolUseContext } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { getCwd } from '../../utils/cwd.js' -import { getClaudeConfigHomeDir, isEnvTruthy } from '../../utils/envUtils.js' -import { getErrnoCode, isENOENT } from '../../utils/errors.js' +} from 'src/skills/loadSkillsDir.js' +import type { ToolUseContext } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { getCwd } from 'src/utils/cwd.js' +import { getClaudeConfigHomeDir, isEnvTruthy } from 'src/utils/envUtils.js' +import { getErrnoCode, isENOENT } from 'src/utils/errors.js' import { addLineNumbers, FILE_NOT_FOUND_CWD_NOTE, findSimilarFile, getFileModificationTimeAsync, suggestPathUnderCwd, -} from '../../utils/file.js' -import { logFileOperation } from '../../utils/fileOperationAnalytics.js' -import { formatFileSize } from '../../utils/format.js' -import { getFsImplementation } from '../../utils/fsOperations.js' +} from 'src/utils/file.js' +import { logFileOperation } from 'src/utils/fileOperationAnalytics.js' +import { formatFileSize } from 'src/utils/format.js' +import { getFsImplementation } from 'src/utils/fsOperations.js' import { compressImageBufferWithTokenLimit, createImageMetadataText, @@ -47,32 +47,32 @@ import { type ImageDimensions, ImageResizeError, maybeResizeAndDownsampleImageBuffer, -} from '../../utils/imageResizer.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { logError } from '../../utils/log.js' -import { isAutoMemFile } from '../../utils/memoryFileDetection.js' -import { createUserMessage } from '../../utils/messages.js' -import { getCanonicalName, getMainLoopModel } from '../../utils/model/model.js' +} from 'src/utils/imageResizer.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { logError } from 'src/utils/log.js' +import { isAutoMemFile } from 'src/utils/memoryFileDetection.js' +import { createUserMessage } from 'src/utils/messages.js' +import { getCanonicalName, getMainLoopModel } from 'src/utils/model/model.js' import { mapNotebookCellsToToolResult, readNotebook, -} from '../../utils/notebook.js' -import { expandPath } from '../../utils/path.js' -import { extractPDFPages, getPDFPageCount, readPDF } from '../../utils/pdf.js' +} from 'src/utils/notebook.js' +import { expandPath } from 'src/utils/path.js' +import { extractPDFPages, getPDFPageCount, readPDF } from 'src/utils/pdf.js' import { isPDFExtension, isPDFSupported, parsePDFPageRange, -} from '../../utils/pdfUtils.js' +} from 'src/utils/pdfUtils.js' import { checkReadPermissionForTool, matchingRuleForInput, -} from '../../utils/permissions/filesystem.js' -import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js' -import { matchWildcardPattern } from '../../utils/permissions/shellRuleMatching.js' -import { readFileInRange } from '../../utils/readFileInRange.js' -import { semanticNumber } from '../../utils/semanticNumber.js' -import { jsonStringify } from '../../utils/slowOperations.js' +} from 'src/utils/permissions/filesystem.js' +import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js' +import { matchWildcardPattern } from 'src/utils/permissions/shellRuleMatching.js' +import { readFileInRange } from 'src/utils/readFileInRange.js' +import { semanticNumber } from 'src/utils/semanticNumber.js' +import { jsonStringify } from 'src/utils/slowOperations.js' import { BASH_TOOL_NAME } from '../BashTool/toolName.js' import { getDefaultFileReadingLimits } from './limits.js' import { diff --git a/src/tools/FileReadTool/UI.tsx b/packages/builtin-tools/src/tools/FileReadTool/UI.tsx similarity index 91% rename from src/tools/FileReadTool/UI.tsx rename to packages/builtin-tools/src/tools/FileReadTool/UI.tsx index 017d55e86..8e7430351 100644 --- a/src/tools/FileReadTool/UI.tsx +++ b/packages/builtin-tools/src/tools/FileReadTool/UI.tsx @@ -1,15 +1,15 @@ import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs' import * as React from 'react' import { extractTag } from 'src/utils/messages.js' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' -import { MessageResponse } from '../../components/MessageResponse.js' +import { MessageResponse } from 'src/components/MessageResponse.js' import { Text } from '@anthropic/ink' -import { FilePathLink } from '../../components/FilePathLink.js' -import { FILE_NOT_FOUND_CWD_NOTE, getDisplayPath } from '../../utils/file.js' -import { formatFileSize } from '../../utils/format.js' -import { getPlansDirectory } from '../../utils/plans.js' -import { getTaskOutputDir } from '../../utils/task/diskOutput.js' +import { FilePathLink } from 'src/components/FilePathLink.js' +import { FILE_NOT_FOUND_CWD_NOTE, getDisplayPath } from 'src/utils/file.js' +import { formatFileSize } from 'src/utils/format.js' +import { getPlansDirectory } from 'src/utils/plans.js' +import { getTaskOutputDir } from 'src/utils/task/diskOutput.js' import type { Input, Output } from './FileReadTool.js' /** diff --git a/src/tools/FileReadTool/imageProcessor.ts b/packages/builtin-tools/src/tools/FileReadTool/imageProcessor.ts similarity index 97% rename from src/tools/FileReadTool/imageProcessor.ts rename to packages/builtin-tools/src/tools/FileReadTool/imageProcessor.ts index e563b7315..de7ea4905 100644 --- a/src/tools/FileReadTool/imageProcessor.ts +++ b/packages/builtin-tools/src/tools/FileReadTool/imageProcessor.ts @@ -1,5 +1,5 @@ import type { Buffer } from 'buffer' -import { isInBundledMode } from '../../utils/bundledMode.js' +import { isInBundledMode } from 'src/utils/bundledMode.js' export type SharpInstance = { metadata(): Promise<{ width: number; height: number; format: string }> diff --git a/src/tools/FileReadTool/limits.ts b/packages/builtin-tools/src/tools/FileReadTool/limits.ts similarity index 100% rename from src/tools/FileReadTool/limits.ts rename to packages/builtin-tools/src/tools/FileReadTool/limits.ts diff --git a/src/tools/FileReadTool/prompt.ts b/packages/builtin-tools/src/tools/FileReadTool/prompt.ts similarity index 98% rename from src/tools/FileReadTool/prompt.ts rename to packages/builtin-tools/src/tools/FileReadTool/prompt.ts index 47be51991..8a6f2d16a 100644 --- a/src/tools/FileReadTool/prompt.ts +++ b/packages/builtin-tools/src/tools/FileReadTool/prompt.ts @@ -1,4 +1,4 @@ -import { isPDFSupported } from '../../utils/pdfUtils.js' +import { isPDFSupported } from 'src/utils/pdfUtils.js' import { BASH_TOOL_NAME } from '../BashTool/toolName.js' // Use a string constant for tool names to avoid circular dependencies diff --git a/src/tools/FileReadTool/src/services/analytics/growthbook.ts b/packages/builtin-tools/src/tools/FileReadTool/src/services/analytics/growthbook.ts similarity index 100% rename from src/tools/FileReadTool/src/services/analytics/growthbook.ts rename to packages/builtin-tools/src/tools/FileReadTool/src/services/analytics/growthbook.ts diff --git a/src/tools/FileReadTool/src/utils/file.ts b/packages/builtin-tools/src/tools/FileReadTool/src/utils/file.ts similarity index 100% rename from src/tools/FileReadTool/src/utils/file.ts rename to packages/builtin-tools/src/tools/FileReadTool/src/utils/file.ts diff --git a/src/tools/FileReadTool/src/utils/messages.ts b/packages/builtin-tools/src/tools/FileReadTool/src/utils/messages.ts similarity index 100% rename from src/tools/FileReadTool/src/utils/messages.ts rename to packages/builtin-tools/src/tools/FileReadTool/src/utils/messages.ts diff --git a/src/tools/FileWriteTool/FileWriteTool.ts b/packages/builtin-tools/src/tools/FileWriteTool/FileWriteTool.ts similarity index 89% rename from src/tools/FileWriteTool/FileWriteTool.ts rename to packages/builtin-tools/src/tools/FileWriteTool/FileWriteTool.ts index 6da0afc85..399bab62e 100644 --- a/src/tools/FileWriteTool/FileWriteTool.ts +++ b/packages/builtin-tools/src/tools/FileWriteTool/FileWriteTool.ts @@ -1,45 +1,45 @@ import { dirname, sep } from 'path' import { logEvent } from 'src/services/analytics/index.js' import { z } from 'zod/v4' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' -import { diagnosticTracker } from '../../services/diagnosticTracking.js' -import { clearDeliveredDiagnosticsForFile } from '../../services/lsp/LSPDiagnosticRegistry.js' -import { getLspServerManager } from '../../services/lsp/manager.js' -import { notifyVscodeFileUpdated } from '../../services/mcp/vscodeSdkMcp.js' -import { checkTeamMemSecrets } from '../../services/teamMemorySync/teamMemSecretGuard.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import { diagnosticTracker } from 'src/services/diagnosticTracking.js' +import { clearDeliveredDiagnosticsForFile } from 'src/services/lsp/LSPDiagnosticRegistry.js' +import { getLspServerManager } from 'src/services/lsp/manager.js' +import { notifyVscodeFileUpdated } from 'src/services/mcp/vscodeSdkMcp.js' +import { checkTeamMemSecrets } from 'src/services/teamMemorySync/teamMemSecretGuard.js' import { activateConditionalSkillsForPaths, addSkillDirectories, discoverSkillDirsForPaths, -} from '../../skills/loadSkillsDir.js' -import type { ToolUseContext } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { getCwd } from '../../utils/cwd.js' -import { logForDebugging } from '../../utils/debug.js' -import { countLinesChanged, getPatchForDisplay } from '../../utils/diff.js' -import { isEnvTruthy } from '../../utils/envUtils.js' -import { isENOENT } from '../../utils/errors.js' -import { getFileModificationTime, writeTextContent } from '../../utils/file.js' +} from 'src/skills/loadSkillsDir.js' +import type { ToolUseContext } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { getCwd } from 'src/utils/cwd.js' +import { logForDebugging } from 'src/utils/debug.js' +import { countLinesChanged, getPatchForDisplay } from 'src/utils/diff.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' +import { isENOENT } from 'src/utils/errors.js' +import { getFileModificationTime, writeTextContent } from 'src/utils/file.js' import { fileHistoryEnabled, fileHistoryTrackEdit, -} from '../../utils/fileHistory.js' -import { logFileOperation } from '../../utils/fileOperationAnalytics.js' -import { readFileSyncWithMetadata } from '../../utils/fileRead.js' -import { getFsImplementation } from '../../utils/fsOperations.js' +} from 'src/utils/fileHistory.js' +import { logFileOperation } from 'src/utils/fileOperationAnalytics.js' +import { readFileSyncWithMetadata } from 'src/utils/fileRead.js' +import { getFsImplementation } from 'src/utils/fsOperations.js' import { fetchSingleFileGitDiff, type ToolUseDiff, -} from '../../utils/gitDiff.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { logError } from '../../utils/log.js' -import { expandPath } from '../../utils/path.js' +} from 'src/utils/gitDiff.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { logError } from 'src/utils/log.js' +import { expandPath } from 'src/utils/path.js' import { checkWritePermissionForTool, matchingRuleForInput, -} from '../../utils/permissions/filesystem.js' -import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js' -import { matchWildcardPattern } from '../../utils/permissions/shellRuleMatching.js' +} from 'src/utils/permissions/filesystem.js' +import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js' +import { matchWildcardPattern } from 'src/utils/permissions/shellRuleMatching.js' import { FILE_UNEXPECTEDLY_MODIFIED_ERROR } from '../FileEditTool/constants.js' import { gitDiffSchema, hunkSchema } from '../FileEditTool/types.js' import { FILE_WRITE_TOOL_NAME, getWriteToolDescription } from './prompt.js' diff --git a/src/tools/FileWriteTool/UI.tsx b/packages/builtin-tools/src/tools/FileWriteTool/UI.tsx similarity index 90% rename from src/tools/FileWriteTool/UI.tsx rename to packages/builtin-tools/src/tools/FileWriteTool/UI.tsx index 8ea218fb7..5b96cf4f8 100644 --- a/src/tools/FileWriteTool/UI.tsx +++ b/packages/builtin-tools/src/tools/FileWriteTool/UI.tsx @@ -5,23 +5,23 @@ import * as React from 'react' import { Suspense, use, useState } from 'react' import { MessageResponse } from 'src/components/MessageResponse.js' import { extractTag } from 'src/utils/messages.js' -import { CtrlOToExpand } from '../../components/CtrlOToExpand.js' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' -import { FileEditToolUpdatedMessage } from '../../components/FileEditToolUpdatedMessage.js' -import { FileEditToolUseRejectedMessage } from '../../components/FileEditToolUseRejectedMessage.js' +import { CtrlOToExpand } from 'src/components/CtrlOToExpand.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' +import { FileEditToolUpdatedMessage } from 'src/components/FileEditToolUpdatedMessage.js' +import { FileEditToolUseRejectedMessage } from 'src/components/FileEditToolUseRejectedMessage.js' -import { HighlightedCode } from '../../components/HighlightedCode.js' -import { useTerminalSize } from '../../hooks/useTerminalSize.js' +import { HighlightedCode } from 'src/components/HighlightedCode.js' +import { useTerminalSize } from 'src/hooks/useTerminalSize.js' import { Box, Text } from '@anthropic/ink' -import { FilePathLink } from '../../components/FilePathLink.js' -import type { ToolProgressData } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import { getCwd } from '../../utils/cwd.js' -import { getPatchForDisplay } from '../../utils/diff.js' -import { getDisplayPath } from '../../utils/file.js' -import { logError } from '../../utils/log.js' -import { getPlansDirectory } from '../../utils/plans.js' -import { openForScan, readCapped } from '../../utils/readEditContext.js' +import { FilePathLink } from 'src/components/FilePathLink.js' +import type { ToolProgressData } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import { getCwd } from 'src/utils/cwd.js' +import { getPatchForDisplay } from 'src/utils/diff.js' +import { getDisplayPath } from 'src/utils/file.js' +import { logError } from 'src/utils/log.js' +import { getPlansDirectory } from 'src/utils/plans.js' +import { openForScan, readCapped } from 'src/utils/readEditContext.js' import type { Output } from './FileWriteTool.js' const MAX_LINES_TO_RENDER = 10 diff --git a/src/tools/FileWriteTool/prompt.ts b/packages/builtin-tools/src/tools/FileWriteTool/prompt.ts similarity index 100% rename from src/tools/FileWriteTool/prompt.ts rename to packages/builtin-tools/src/tools/FileWriteTool/prompt.ts diff --git a/src/tools/FileWriteTool/src/components/MessageResponse.ts b/packages/builtin-tools/src/tools/FileWriteTool/src/components/MessageResponse.ts similarity index 100% rename from src/tools/FileWriteTool/src/components/MessageResponse.ts rename to packages/builtin-tools/src/tools/FileWriteTool/src/components/MessageResponse.ts diff --git a/src/tools/FileWriteTool/src/services/analytics/index.ts b/packages/builtin-tools/src/tools/FileWriteTool/src/services/analytics/index.ts similarity index 100% rename from src/tools/FileWriteTool/src/services/analytics/index.ts rename to packages/builtin-tools/src/tools/FileWriteTool/src/services/analytics/index.ts diff --git a/src/tools/FileWriteTool/src/utils/messages.ts b/packages/builtin-tools/src/tools/FileWriteTool/src/utils/messages.ts similarity index 100% rename from src/tools/FileWriteTool/src/utils/messages.ts rename to packages/builtin-tools/src/tools/FileWriteTool/src/utils/messages.ts diff --git a/src/tools/GlobTool/GlobTool.ts b/packages/builtin-tools/src/tools/GlobTool/GlobTool.ts similarity index 88% rename from src/tools/GlobTool/GlobTool.ts rename to packages/builtin-tools/src/tools/GlobTool/GlobTool.ts index 7b24554d0..b328495e3 100644 --- a/src/tools/GlobTool/GlobTool.ts +++ b/packages/builtin-tools/src/tools/GlobTool/GlobTool.ts @@ -1,19 +1,19 @@ import { z } from 'zod/v4' -import type { ValidationResult } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { getCwd } from '../../utils/cwd.js' -import { isENOENT } from '../../utils/errors.js' +import type { ValidationResult } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { getCwd } from 'src/utils/cwd.js' +import { isENOENT } from 'src/utils/errors.js' import { FILE_NOT_FOUND_CWD_NOTE, suggestPathUnderCwd, -} from '../../utils/file.js' -import { getFsImplementation } from '../../utils/fsOperations.js' -import { glob } from '../../utils/glob.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { expandPath, toRelativePath } from '../../utils/path.js' -import { checkReadPermissionForTool } from '../../utils/permissions/filesystem.js' -import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js' -import { matchWildcardPattern } from '../../utils/permissions/shellRuleMatching.js' +} from 'src/utils/file.js' +import { getFsImplementation } from 'src/utils/fsOperations.js' +import { glob } from 'src/utils/glob.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { expandPath, toRelativePath } from 'src/utils/path.js' +import { checkReadPermissionForTool } from 'src/utils/permissions/filesystem.js' +import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js' +import { matchWildcardPattern } from 'src/utils/permissions/shellRuleMatching.js' import { DESCRIPTION, GLOB_TOOL_NAME } from './prompt.js' import { getToolUseSummary, diff --git a/src/tools/GlobTool/UI.tsx b/packages/builtin-tools/src/tools/GlobTool/UI.tsx similarity index 85% rename from src/tools/GlobTool/UI.tsx rename to packages/builtin-tools/src/tools/GlobTool/UI.tsx index b70934fa4..295497dc5 100644 --- a/src/tools/GlobTool/UI.tsx +++ b/packages/builtin-tools/src/tools/GlobTool/UI.tsx @@ -2,11 +2,11 @@ import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs import React from 'react' import { MessageResponse } from 'src/components/MessageResponse.js' import { extractTag } from 'src/utils/messages.js' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' -import { TOOL_SUMMARY_MAX_LENGTH } from '../../constants/toolLimits.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' +import { TOOL_SUMMARY_MAX_LENGTH } from 'src/constants/toolLimits.js' import { Text } from '@anthropic/ink' -import { FILE_NOT_FOUND_CWD_NOTE, getDisplayPath } from '../../utils/file.js' -import { truncate } from '../../utils/format.js' +import { FILE_NOT_FOUND_CWD_NOTE, getDisplayPath } from 'src/utils/file.js' +import { truncate } from 'src/utils/format.js' import { GrepTool } from '../GrepTool/GrepTool.js' export function userFacingName(): string { diff --git a/src/tools/GlobTool/prompt.ts b/packages/builtin-tools/src/tools/GlobTool/prompt.ts similarity index 100% rename from src/tools/GlobTool/prompt.ts rename to packages/builtin-tools/src/tools/GlobTool/prompt.ts diff --git a/src/tools/GlobTool/src/components/MessageResponse.ts b/packages/builtin-tools/src/tools/GlobTool/src/components/MessageResponse.ts similarity index 100% rename from src/tools/GlobTool/src/components/MessageResponse.ts rename to packages/builtin-tools/src/tools/GlobTool/src/components/MessageResponse.ts diff --git a/src/tools/GlobTool/src/utils/messages.ts b/packages/builtin-tools/src/tools/GlobTool/src/utils/messages.ts similarity index 100% rename from src/tools/GlobTool/src/utils/messages.ts rename to packages/builtin-tools/src/tools/GlobTool/src/utils/messages.ts diff --git a/src/tools/GrepTool/GrepTool.ts b/packages/builtin-tools/src/tools/GrepTool/GrepTool.ts similarity index 95% rename from src/tools/GrepTool/GrepTool.ts rename to packages/builtin-tools/src/tools/GrepTool/GrepTool.ts index 9bdd024ab..75a51406b 100644 --- a/src/tools/GrepTool/GrepTool.ts +++ b/packages/builtin-tools/src/tools/GrepTool/GrepTool.ts @@ -1,27 +1,27 @@ import { z } from 'zod/v4' -import type { ValidationResult } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { getCwd } from '../../utils/cwd.js' -import { isENOENT } from '../../utils/errors.js' +import type { ValidationResult } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { getCwd } from 'src/utils/cwd.js' +import { isENOENT } from 'src/utils/errors.js' import { FILE_NOT_FOUND_CWD_NOTE, suggestPathUnderCwd, -} from '../../utils/file.js' -import { getFsImplementation } from '../../utils/fsOperations.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { expandPath, toRelativePath } from '../../utils/path.js' +} from 'src/utils/file.js' +import { getFsImplementation } from 'src/utils/fsOperations.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { expandPath, toRelativePath } from 'src/utils/path.js' import { checkReadPermissionForTool, getFileReadIgnorePatterns, normalizePatternsToPath, -} from '../../utils/permissions/filesystem.js' -import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js' -import { matchWildcardPattern } from '../../utils/permissions/shellRuleMatching.js' -import { getGlobExclusionsForPluginCache } from '../../utils/plugins/orphanedPluginFilter.js' -import { ripGrep } from '../../utils/ripgrep.js' -import { semanticBoolean } from '../../utils/semanticBoolean.js' -import { semanticNumber } from '../../utils/semanticNumber.js' -import { plural } from '../../utils/stringUtils.js' +} from 'src/utils/permissions/filesystem.js' +import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js' +import { matchWildcardPattern } from 'src/utils/permissions/shellRuleMatching.js' +import { getGlobExclusionsForPluginCache } from 'src/utils/plugins/orphanedPluginFilter.js' +import { ripGrep } from 'src/utils/ripgrep.js' +import { semanticBoolean } from 'src/utils/semanticBoolean.js' +import { semanticNumber } from 'src/utils/semanticNumber.js' +import { plural } from 'src/utils/stringUtils.js' import { GREP_TOOL_NAME, getDescription } from './prompt.js' import { getToolUseSummary, diff --git a/src/tools/GrepTool/UI.tsx b/packages/builtin-tools/src/tools/GrepTool/UI.tsx similarity index 87% rename from src/tools/GrepTool/UI.tsx rename to packages/builtin-tools/src/tools/GrepTool/UI.tsx index 4bc319175..0cde1d7ca 100644 --- a/src/tools/GrepTool/UI.tsx +++ b/packages/builtin-tools/src/tools/GrepTool/UI.tsx @@ -1,15 +1,15 @@ import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs' import React from 'react' -import { CtrlOToExpand } from '../../components/CtrlOToExpand.js' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' -import { MessageResponse } from '../../components/MessageResponse.js' -import { TOOL_SUMMARY_MAX_LENGTH } from '../../constants/toolLimits.js' +import { CtrlOToExpand } from 'src/components/CtrlOToExpand.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' +import { MessageResponse } from 'src/components/MessageResponse.js' +import { TOOL_SUMMARY_MAX_LENGTH } from 'src/constants/toolLimits.js' import { Box, Text } from '@anthropic/ink' -import type { ToolProgressData } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import { FILE_NOT_FOUND_CWD_NOTE, getDisplayPath } from '../../utils/file.js' -import { truncate } from '../../utils/format.js' -import { extractTag } from '../../utils/messages.js' +import type { ToolProgressData } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import { FILE_NOT_FOUND_CWD_NOTE, getDisplayPath } from 'src/utils/file.js' +import { truncate } from 'src/utils/format.js' +import { extractTag } from 'src/utils/messages.js' // Reusable component for search result summaries function SearchResultSummary({ diff --git a/src/tools/GrepTool/prompt.ts b/packages/builtin-tools/src/tools/GrepTool/prompt.ts similarity index 100% rename from src/tools/GrepTool/prompt.ts rename to packages/builtin-tools/src/tools/GrepTool/prompt.ts diff --git a/src/tools/LSPTool/LSPTool.ts b/packages/builtin-tools/src/tools/LSPTool/LSPTool.ts similarity index 96% rename from src/tools/LSPTool/LSPTool.ts rename to packages/builtin-tools/src/tools/LSPTool/LSPTool.ts index 04c4ca7c6..621a59933 100644 --- a/src/tools/LSPTool/LSPTool.ts +++ b/packages/builtin-tools/src/tools/LSPTool/LSPTool.ts @@ -17,20 +17,20 @@ import { getLspServerManager, isLspConnected, waitForInitialization, -} from '../../services/lsp/manager.js' -import type { ValidationResult } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { uniq } from '../../utils/array.js' -import { getCwd } from '../../utils/cwd.js' -import { logForDebugging } from '../../utils/debug.js' -import { isENOENT, toError } from '../../utils/errors.js' -import { execFileNoThrowWithCwd } from '../../utils/execFileNoThrow.js' -import { getFsImplementation } from '../../utils/fsOperations.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { logError } from '../../utils/log.js' -import { expandPath } from '../../utils/path.js' -import { checkReadPermissionForTool } from '../../utils/permissions/filesystem.js' -import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js' +} from 'src/services/lsp/manager.js' +import type { ValidationResult } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { uniq } from 'src/utils/array.js' +import { getCwd } from 'src/utils/cwd.js' +import { logForDebugging } from 'src/utils/debug.js' +import { isENOENT, toError } from 'src/utils/errors.js' +import { execFileNoThrowWithCwd } from 'src/utils/execFileNoThrow.js' +import { getFsImplementation } from 'src/utils/fsOperations.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { logError } from 'src/utils/log.js' +import { expandPath } from 'src/utils/path.js' +import { checkReadPermissionForTool } from 'src/utils/permissions/filesystem.js' +import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js' import { formatDocumentSymbolResult, formatFindReferencesResult, diff --git a/src/tools/LSPTool/UI.tsx b/packages/builtin-tools/src/tools/LSPTool/UI.tsx similarity index 94% rename from src/tools/LSPTool/UI.tsx rename to packages/builtin-tools/src/tools/LSPTool/UI.tsx index 2a5403b12..cbbcb1835 100644 --- a/src/tools/LSPTool/UI.tsx +++ b/packages/builtin-tools/src/tools/LSPTool/UI.tsx @@ -1,11 +1,11 @@ import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs' import React from 'react' -import { CtrlOToExpand } from '../../components/CtrlOToExpand.js' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' -import { MessageResponse } from '../../components/MessageResponse.js' +import { CtrlOToExpand } from 'src/components/CtrlOToExpand.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' +import { MessageResponse } from 'src/components/MessageResponse.js' import { Box, Text } from '@anthropic/ink' -import { getDisplayPath } from '../../utils/file.js' -import { extractTag } from '../../utils/messages.js' +import { getDisplayPath } from 'src/utils/file.js' +import { extractTag } from 'src/utils/messages.js' import type { Input, Output } from './LSPTool.js' import { getSymbolAtPosition } from './symbolContext.js' diff --git a/src/tools/LSPTool/__tests__/formatters.test.ts b/packages/builtin-tools/src/tools/LSPTool/__tests__/formatters.test.ts similarity index 100% rename from src/tools/LSPTool/__tests__/formatters.test.ts rename to packages/builtin-tools/src/tools/LSPTool/__tests__/formatters.test.ts diff --git a/src/tools/LSPTool/__tests__/schemas.test.ts b/packages/builtin-tools/src/tools/LSPTool/__tests__/schemas.test.ts similarity index 100% rename from src/tools/LSPTool/__tests__/schemas.test.ts rename to packages/builtin-tools/src/tools/LSPTool/__tests__/schemas.test.ts diff --git a/src/tools/LSPTool/formatters.ts b/packages/builtin-tools/src/tools/LSPTool/formatters.ts similarity index 99% rename from src/tools/LSPTool/formatters.ts rename to packages/builtin-tools/src/tools/LSPTool/formatters.ts index 3c9bbbd99..26e6d51b0 100644 --- a/src/tools/LSPTool/formatters.ts +++ b/packages/builtin-tools/src/tools/LSPTool/formatters.ts @@ -12,9 +12,9 @@ import type { SymbolInformation, SymbolKind, } from 'vscode-languageserver-types' -import { logForDebugging } from '../../utils/debug.js' -import { errorMessage } from '../../utils/errors.js' -import { plural } from '../../utils/stringUtils.js' +import { logForDebugging } from 'src/utils/debug.js' +import { errorMessage } from 'src/utils/errors.js' +import { plural } from 'src/utils/stringUtils.js' /** * Formats a URI by converting it to a relative path if possible. diff --git a/src/tools/LSPTool/prompt.ts b/packages/builtin-tools/src/tools/LSPTool/prompt.ts similarity index 100% rename from src/tools/LSPTool/prompt.ts rename to packages/builtin-tools/src/tools/LSPTool/prompt.ts diff --git a/src/tools/LSPTool/schemas.ts b/packages/builtin-tools/src/tools/LSPTool/schemas.ts similarity index 99% rename from src/tools/LSPTool/schemas.ts rename to packages/builtin-tools/src/tools/LSPTool/schemas.ts index 63d5bef31..655ba371e 100644 --- a/src/tools/LSPTool/schemas.ts +++ b/packages/builtin-tools/src/tools/LSPTool/schemas.ts @@ -1,5 +1,5 @@ import { z } from 'zod/v4' -import { lazySchema } from '../../utils/lazySchema.js' +import { lazySchema } from 'src/utils/lazySchema.js' /** * Discriminated union of all LSP operations diff --git a/src/tools/LSPTool/symbolContext.ts b/packages/builtin-tools/src/tools/LSPTool/symbolContext.ts similarity index 93% rename from src/tools/LSPTool/symbolContext.ts rename to packages/builtin-tools/src/tools/LSPTool/symbolContext.ts index d621f7698..fc0216d79 100644 --- a/src/tools/LSPTool/symbolContext.ts +++ b/packages/builtin-tools/src/tools/LSPTool/symbolContext.ts @@ -1,7 +1,7 @@ -import { logForDebugging } from '../../utils/debug.js' -import { truncate } from '../../utils/format.js' -import { getFsImplementation } from '../../utils/fsOperations.js' -import { expandPath } from '../../utils/path.js' +import { logForDebugging } from 'src/utils/debug.js' +import { truncate } from 'src/utils/format.js' +import { getFsImplementation } from 'src/utils/fsOperations.js' +import { expandPath } from 'src/utils/path.js' const MAX_READ_BYTES = 64 * 1024 diff --git a/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts b/packages/builtin-tools/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts similarity index 90% rename from src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts rename to packages/builtin-tools/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts index 6f3f087af..72e776ed8 100644 --- a/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +++ b/packages/builtin-tools/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts @@ -2,13 +2,13 @@ import { z } from 'zod/v4' import { ensureConnectedClient, fetchResourcesForClient, -} from '../../services/mcp/client.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { errorMessage } from '../../utils/errors.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { logMCPError } from '../../utils/log.js' -import { jsonStringify } from '../../utils/slowOperations.js' -import { isOutputLineTruncated } from '../../utils/terminal.js' +} from 'src/services/mcp/client.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { errorMessage } from 'src/utils/errors.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { logMCPError } from 'src/utils/log.js' +import { jsonStringify } from 'src/utils/slowOperations.js' +import { isOutputLineTruncated } from 'src/utils/terminal.js' import { DESCRIPTION, LIST_MCP_RESOURCES_TOOL_NAME, PROMPT } from './prompt.js' import { renderToolResultMessage, renderToolUseMessage } from './UI.js' diff --git a/src/tools/ListMcpResourcesTool/UI.tsx b/packages/builtin-tools/src/tools/ListMcpResourcesTool/UI.tsx similarity index 74% rename from src/tools/ListMcpResourcesTool/UI.tsx rename to packages/builtin-tools/src/tools/ListMcpResourcesTool/UI.tsx index 6f9b18559..9926cb658 100644 --- a/src/tools/ListMcpResourcesTool/UI.tsx +++ b/packages/builtin-tools/src/tools/ListMcpResourcesTool/UI.tsx @@ -1,10 +1,10 @@ import * as React from 'react' -import { MessageResponse } from '../../components/MessageResponse.js' -import { OutputLine } from '../../components/shell/OutputLine.js' +import { MessageResponse } from 'src/components/MessageResponse.js' +import { OutputLine } from 'src/components/shell/OutputLine.js' import { Text } from '@anthropic/ink' -import type { ToolProgressData } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import { jsonStringify } from '../../utils/slowOperations.js' +import type { ToolProgressData } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import { jsonStringify } from 'src/utils/slowOperations.js' import type { Output } from './ListMcpResourcesTool.js' export function renderToolUseMessage( diff --git a/src/tools/ListMcpResourcesTool/prompt.ts b/packages/builtin-tools/src/tools/ListMcpResourcesTool/prompt.ts similarity index 100% rename from src/tools/ListMcpResourcesTool/prompt.ts rename to packages/builtin-tools/src/tools/ListMcpResourcesTool/prompt.ts diff --git a/src/tools/ListPeersTool/ListPeersTool.ts b/packages/builtin-tools/src/tools/ListPeersTool/ListPeersTool.ts similarity index 94% rename from src/tools/ListPeersTool/ListPeersTool.ts rename to packages/builtin-tools/src/tools/ListPeersTool/ListPeersTool.ts index 7ff3a88a3..e520243a5 100644 --- a/src/tools/ListPeersTool/ListPeersTool.ts +++ b/packages/builtin-tools/src/tools/ListPeersTool/ListPeersTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' const LIST_PEERS_TOOL_NAME = 'ListPeers' diff --git a/src/tools/MCPTool/MCPTool.ts b/packages/builtin-tools/src/tools/MCPTool/MCPTool.ts similarity index 85% rename from src/tools/MCPTool/MCPTool.ts rename to packages/builtin-tools/src/tools/MCPTool/MCPTool.ts index 3896868b3..88ad94e5f 100644 --- a/src/tools/MCPTool/MCPTool.ts +++ b/packages/builtin-tools/src/tools/MCPTool/MCPTool.ts @@ -1,8 +1,8 @@ import { z } from 'zod/v4' -import { buildTool, type ToolDef } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' -import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' -import { isOutputLineTruncated } from '../../utils/terminal.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' +import { isOutputLineTruncated } from 'src/utils/terminal.js' import { DESCRIPTION, PROMPT } from './prompt.js' import { renderToolResultMessage, @@ -22,7 +22,7 @@ type OutputSchema = ReturnType export type Output = z.infer // Re-export MCPProgress from centralized types to break import cycles -export type { MCPProgress } from '../../types/tools.js' +export type { MCPProgress } from 'src/types/tools.js' export const MCPTool = buildTool({ isMcp: true, diff --git a/src/tools/MCPTool/UI.tsx b/packages/builtin-tools/src/tools/MCPTool/UI.tsx similarity index 95% rename from src/tools/MCPTool/UI.tsx rename to packages/builtin-tools/src/tools/MCPTool/UI.tsx index 5fa55c7a2..56db3fd98 100644 --- a/src/tools/MCPTool/UI.tsx +++ b/packages/builtin-tools/src/tools/MCPTool/UI.tsx @@ -3,23 +3,23 @@ import figures from 'figures' import * as React from 'react' import type { z } from 'zod/v4' import { ProgressBar } from '@anthropic/ink' -import { MessageResponse } from '../../components/MessageResponse.js' +import { MessageResponse } from 'src/components/MessageResponse.js' import { linkifyUrlsInText, OutputLine, -} from '../../components/shell/OutputLine.js' +} from 'src/components/shell/OutputLine.js' import { Ansi, Box, Text, stringWidth } from '@anthropic/ink' -import { createHyperlink } from '../../utils/hyperlink.js' -import type { ToolProgressData } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import type { MCPProgress } from '../../types/tools.js' -import { formatNumber } from '../../utils/format.js' +import { createHyperlink } from 'src/utils/hyperlink.js' +import type { ToolProgressData } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import type { MCPProgress } from 'src/types/tools.js' +import { formatNumber } from 'src/utils/format.js' import { getContentSizeEstimate, type MCPToolResult, -} from '../../utils/mcpValidation.js' -import { jsonParse, jsonStringify } from '../../utils/slowOperations.js' +} from 'src/utils/mcpValidation.js' +import { jsonParse, jsonStringify } from 'src/utils/slowOperations.js' import type { inputSchema } from './MCPTool.js' // Threshold for displaying warning about large MCP responses diff --git a/src/tools/MCPTool/__tests__/classifyForCollapse.test.ts b/packages/builtin-tools/src/tools/MCPTool/__tests__/classifyForCollapse.test.ts similarity index 100% rename from src/tools/MCPTool/__tests__/classifyForCollapse.test.ts rename to packages/builtin-tools/src/tools/MCPTool/__tests__/classifyForCollapse.test.ts diff --git a/src/tools/MCPTool/classifyForCollapse.ts b/packages/builtin-tools/src/tools/MCPTool/classifyForCollapse.ts similarity index 100% rename from src/tools/MCPTool/classifyForCollapse.ts rename to packages/builtin-tools/src/tools/MCPTool/classifyForCollapse.ts diff --git a/src/tools/MCPTool/prompt.ts b/packages/builtin-tools/src/tools/MCPTool/prompt.ts similarity index 100% rename from src/tools/MCPTool/prompt.ts rename to packages/builtin-tools/src/tools/MCPTool/prompt.ts diff --git a/src/tools/McpAuthTool/McpAuthTool.ts b/packages/builtin-tools/src/tools/McpAuthTool/McpAuthTool.ts similarity index 93% rename from src/tools/McpAuthTool/McpAuthTool.ts rename to packages/builtin-tools/src/tools/McpAuthTool/McpAuthTool.ts index 7ea96795f..4321e8e20 100644 --- a/src/tools/McpAuthTool/McpAuthTool.ts +++ b/packages/builtin-tools/src/tools/McpAuthTool/McpAuthTool.ts @@ -1,24 +1,24 @@ import reject from 'lodash-es/reject.js' import { z } from 'zod/v4' -import { performMCPOAuthFlow } from '../../services/mcp/auth.js' +import { performMCPOAuthFlow } from 'src/services/mcp/auth.js' import { clearMcpAuthCache, reconnectMcpServerImpl, -} from '../../services/mcp/client.js' +} from 'src/services/mcp/client.js' import { buildMcpToolName, getMcpPrefix, -} from '../../services/mcp/mcpStringUtils.js' +} from 'src/services/mcp/mcpStringUtils.js' import type { McpHTTPServerConfig, McpSSEServerConfig, ScopedMcpServerConfig, -} from '../../services/mcp/types.js' -import type { Tool } from '../../Tool.js' -import { errorMessage } from '../../utils/errors.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { logMCPDebug, logMCPError } from '../../utils/log.js' -import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js' +} from 'src/services/mcp/types.js' +import type { Tool } from 'src/Tool.js' +import { errorMessage } from 'src/utils/errors.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { logMCPDebug, logMCPError } from 'src/utils/log.js' +import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js' const inputSchema = lazySchema(() => z.object({})) type InputSchema = ReturnType diff --git a/src/tools/MonitorTool/MonitorTool.tsx b/packages/builtin-tools/src/tools/MonitorTool/MonitorTool.tsx similarity index 90% rename from src/tools/MonitorTool/MonitorTool.tsx rename to packages/builtin-tools/src/tools/MonitorTool/MonitorTool.tsx index 2a378e64f..0d659ae2a 100644 --- a/src/tools/MonitorTool/MonitorTool.tsx +++ b/packages/builtin-tools/src/tools/MonitorTool/MonitorTool.tsx @@ -1,17 +1,17 @@ import React from 'react' import { Text } from '@anthropic/ink' import { z } from 'zod/v4' -import { TOOL_SUMMARY_MAX_LENGTH } from '../../constants/toolLimits.js' -import type { ToolResultBlockParam, ToolUseContext, ValidationResult } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { spawnShellTask } from '../../tasks/LocalShellTask/LocalShellTask.js' +import { TOOL_SUMMARY_MAX_LENGTH } from 'src/constants/toolLimits.js' +import type { ToolResultBlockParam, ToolUseContext, ValidationResult } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { spawnShellTask } from 'src/tasks/LocalShellTask/LocalShellTask.js' import { bashToolHasPermission } from '../BashTool/bashPermissions.js' -import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { truncate } from '../../utils/format.js' -import { exec } from '../../utils/Shell.js' -import { getTaskOutputPath } from '../../utils/task/diskOutput.js' -import { logEvent } from '../../services/analytics/index.js' +import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { truncate } from 'src/utils/format.js' +import { exec } from 'src/utils/Shell.js' +import { getTaskOutputPath } from 'src/utils/task/diskOutput.js' +import { logEvent } from 'src/services/analytics/index.js' const MONITOR_TOOL_NAME = 'Monitor' diff --git a/src/tools/NotebookEditTool/NotebookEditTool.ts b/packages/builtin-tools/src/tools/NotebookEditTool/NotebookEditTool.ts similarity index 94% rename from src/tools/NotebookEditTool/NotebookEditTool.ts rename to packages/builtin-tools/src/tools/NotebookEditTool/NotebookEditTool.ts index 828fb6848..ac828efc8 100644 --- a/src/tools/NotebookEditTool/NotebookEditTool.ts +++ b/packages/builtin-tools/src/tools/NotebookEditTool/NotebookEditTool.ts @@ -5,18 +5,18 @@ import { fileHistoryTrackEdit, } from 'src/utils/fileHistory.js' import { z } from 'zod/v4' -import { buildTool, type ToolDef, type ToolUseContext } from '../../Tool.js' -import type { NotebookCell, NotebookContent } from '../../types/notebook.js' -import { getCwd } from '../../utils/cwd.js' -import { isENOENT } from '../../utils/errors.js' -import { getFileModificationTime, writeTextContent } from '../../utils/file.js' -import { readFileSyncWithMetadata } from '../../utils/fileRead.js' -import { safeParseJSON } from '../../utils/json.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { parseCellId } from '../../utils/notebook.js' -import { checkWritePermissionForTool } from '../../utils/permissions/filesystem.js' -import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js' -import { jsonParse, jsonStringify } from '../../utils/slowOperations.js' +import { buildTool, type ToolDef, type ToolUseContext } from 'src/Tool.js' +import type { NotebookCell, NotebookContent } from 'src/types/notebook.js' +import { getCwd } from 'src/utils/cwd.js' +import { isENOENT } from 'src/utils/errors.js' +import { getFileModificationTime, writeTextContent } from 'src/utils/file.js' +import { readFileSyncWithMetadata } from 'src/utils/fileRead.js' +import { safeParseJSON } from 'src/utils/json.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { parseCellId } from 'src/utils/notebook.js' +import { checkWritePermissionForTool } from 'src/utils/permissions/filesystem.js' +import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js' +import { jsonParse, jsonStringify } from 'src/utils/slowOperations.js' import { NOTEBOOK_EDIT_TOOL_NAME } from './constants.js' import { DESCRIPTION, PROMPT } from './prompt.js' import { diff --git a/src/tools/NotebookEditTool/UI.tsx b/packages/builtin-tools/src/tools/NotebookEditTool/UI.tsx similarity index 85% rename from src/tools/NotebookEditTool/UI.tsx rename to packages/builtin-tools/src/tools/NotebookEditTool/UI.tsx index e209aaba7..236c4f506 100644 --- a/src/tools/NotebookEditTool/UI.tsx +++ b/packages/builtin-tools/src/tools/NotebookEditTool/UI.tsx @@ -4,15 +4,15 @@ import type { Message, ProgressMessage } from 'src/types/message.js' import { extractTag } from 'src/utils/messages.js' import type { ThemeName } from 'src/utils/theme.js' import type { z } from 'zod/v4' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' -import { HighlightedCode } from '../../components/HighlightedCode.js' -import { MessageResponse } from '../../components/MessageResponse.js' -import { NotebookEditToolUseRejectedMessage } from '../../components/NotebookEditToolUseRejectedMessage.js' +import { HighlightedCode } from 'src/components/HighlightedCode.js' +import { MessageResponse } from 'src/components/MessageResponse.js' +import { NotebookEditToolUseRejectedMessage } from 'src/components/NotebookEditToolUseRejectedMessage.js' import { Box, Text } from '@anthropic/ink' -import { FilePathLink } from '../../components/FilePathLink.js' -import type { Tools } from '../../Tool.js' -import { getDisplayPath } from '../../utils/file.js' +import { FilePathLink } from 'src/components/FilePathLink.js' +import type { Tools } from 'src/Tool.js' +import { getDisplayPath } from 'src/utils/file.js' import type { inputSchema, Output } from './NotebookEditTool.js' export function getToolUseSummary( diff --git a/src/tools/NotebookEditTool/constants.ts b/packages/builtin-tools/src/tools/NotebookEditTool/constants.ts similarity index 100% rename from src/tools/NotebookEditTool/constants.ts rename to packages/builtin-tools/src/tools/NotebookEditTool/constants.ts diff --git a/src/tools/NotebookEditTool/prompt.ts b/packages/builtin-tools/src/tools/NotebookEditTool/prompt.ts similarity index 100% rename from src/tools/NotebookEditTool/prompt.ts rename to packages/builtin-tools/src/tools/NotebookEditTool/prompt.ts diff --git a/src/tools/NotebookEditTool/src/types/message.ts b/packages/builtin-tools/src/tools/NotebookEditTool/src/types/message.ts similarity index 100% rename from src/tools/NotebookEditTool/src/types/message.ts rename to packages/builtin-tools/src/tools/NotebookEditTool/src/types/message.ts diff --git a/src/tools/NotebookEditTool/src/utils/fileHistory.ts b/packages/builtin-tools/src/tools/NotebookEditTool/src/utils/fileHistory.ts similarity index 100% rename from src/tools/NotebookEditTool/src/utils/fileHistory.ts rename to packages/builtin-tools/src/tools/NotebookEditTool/src/utils/fileHistory.ts diff --git a/src/tools/NotebookEditTool/src/utils/messages.ts b/packages/builtin-tools/src/tools/NotebookEditTool/src/utils/messages.ts similarity index 100% rename from src/tools/NotebookEditTool/src/utils/messages.ts rename to packages/builtin-tools/src/tools/NotebookEditTool/src/utils/messages.ts diff --git a/src/tools/NotebookEditTool/src/utils/theme.ts b/packages/builtin-tools/src/tools/NotebookEditTool/src/utils/theme.ts similarity index 100% rename from src/tools/NotebookEditTool/src/utils/theme.ts rename to packages/builtin-tools/src/tools/NotebookEditTool/src/utils/theme.ts diff --git a/src/tools/OverflowTestTool/OverflowTestTool.ts b/packages/builtin-tools/src/tools/OverflowTestTool/OverflowTestTool.ts similarity index 100% rename from src/tools/OverflowTestTool/OverflowTestTool.ts rename to packages/builtin-tools/src/tools/OverflowTestTool/OverflowTestTool.ts diff --git a/src/tools/PowerShellTool/PowerShellTool.tsx b/packages/builtin-tools/src/tools/PowerShellTool/PowerShellTool.tsx similarity index 96% rename from src/tools/PowerShellTool/PowerShellTool.tsx rename to packages/builtin-tools/src/tools/PowerShellTool/PowerShellTool.tsx index d5d49614f..2b5d7f7fb 100644 --- a/src/tools/PowerShellTool/PowerShellTool.tsx +++ b/packages/builtin-tools/src/tools/PowerShellTool/PowerShellTool.tsx @@ -10,57 +10,57 @@ import * as React from 'react' import type { CanUseToolFn } from 'src/hooks/useCanUseTool.js' import type { AppState } from 'src/state/AppState.js' import { z } from 'zod/v4' -import { getKairosActive } from '../../bootstrap/state.js' -import { TOOL_SUMMARY_MAX_LENGTH } from '../../constants/toolLimits.js' +import { getKairosActive } from 'src/bootstrap/state.js' +import { TOOL_SUMMARY_MAX_LENGTH } from 'src/constants/toolLimits.js' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, -} from '../../services/analytics/index.js' +} from 'src/services/analytics/index.js' import type { SetToolJSXFn, Tool, ToolCallProgress, ValidationResult, -} from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' +} from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' import { backgroundExistingForegroundTask, markTaskNotified, registerForeground, spawnShellTask, unregisterForeground, -} from '../../tasks/LocalShellTask/LocalShellTask.js' -import type { AgentId } from '../../types/ids.js' -import type { AssistantMessage } from '../../types/message.js' -import { extractClaudeCodeHints } from '../../utils/claudeCodeHints.js' -import { isEnvTruthy } from '../../utils/envUtils.js' +} from 'src/tasks/LocalShellTask/LocalShellTask.js' +import type { AgentId } from 'src/types/ids.js' +import type { AssistantMessage } from 'src/types/message.js' +import { extractClaudeCodeHints } from 'src/utils/claudeCodeHints.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' import { errorMessage as getErrorMessage, ShellError, -} from '../../utils/errors.js' -import { truncate } from '../../utils/format.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { logError } from '../../utils/log.js' -import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' -import { getPlatform } from '../../utils/platform.js' -import { maybeRecordPluginHint } from '../../utils/plugins/hintRecommendation.js' -import { exec } from '../../utils/Shell.js' -import type { ExecResult } from '../../utils/ShellCommand.js' -import { SandboxManager } from '../../utils/sandbox/sandbox-adapter.js' -import { semanticBoolean } from '../../utils/semanticBoolean.js' -import { semanticNumber } from '../../utils/semanticNumber.js' -import { getCachedPowerShellPath } from '../../utils/shell/powershellDetection.js' -import { EndTruncatingAccumulator } from '../../utils/stringUtils.js' -import { getTaskOutputPath } from '../../utils/task/diskOutput.js' -import { TaskOutput } from '../../utils/task/TaskOutput.js' -import { isOutputLineTruncated } from '../../utils/terminal.js' +} from 'src/utils/errors.js' +import { truncate } from 'src/utils/format.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { logError } from 'src/utils/log.js' +import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' +import { getPlatform } from 'src/utils/platform.js' +import { maybeRecordPluginHint } from 'src/utils/plugins/hintRecommendation.js' +import { exec } from 'src/utils/Shell.js' +import type { ExecResult } from 'src/utils/ShellCommand.js' +import { SandboxManager } from 'src/utils/sandbox/sandbox-adapter.js' +import { semanticBoolean } from 'src/utils/semanticBoolean.js' +import { semanticNumber } from 'src/utils/semanticNumber.js' +import { getCachedPowerShellPath } from 'src/utils/shell/powershellDetection.js' +import { EndTruncatingAccumulator } from 'src/utils/stringUtils.js' +import { getTaskOutputPath } from 'src/utils/task/diskOutput.js' +import { TaskOutput } from 'src/utils/task/TaskOutput.js' +import { isOutputLineTruncated } from 'src/utils/terminal.js' import { buildLargeToolResultMessage, ensureToolResultsDir, generatePreview, getToolResultPath, PREVIEW_SIZE_BYTES, -} from '../../utils/toolResultStorage.js' +} from 'src/utils/toolResultStorage.js' import { shouldUseSandbox } from '../BashTool/shouldUseSandbox.js' import { BackgroundHint } from '../BashTool/UI.js' import { @@ -353,9 +353,9 @@ const outputSchema = lazySchema(() => type OutputSchema = ReturnType export type Out = z.infer -import type { PowerShellProgress } from '../../types/tools.js' +import type { PowerShellProgress } from 'src/types/tools.js' -export type { PowerShellProgress } from '../../types/tools.js' +export type { PowerShellProgress } from 'src/types/tools.js' const COMMON_BACKGROUND_COMMANDS = [ 'npm', diff --git a/src/tools/PowerShellTool/UI.tsx b/packages/builtin-tools/src/tools/PowerShellTool/UI.tsx similarity index 88% rename from src/tools/PowerShellTool/UI.tsx rename to packages/builtin-tools/src/tools/PowerShellTool/UI.tsx index 8b27bfa12..33730985b 100644 --- a/src/tools/PowerShellTool/UI.tsx +++ b/packages/builtin-tools/src/tools/PowerShellTool/UI.tsx @@ -1,16 +1,16 @@ import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs' import * as React from 'react' import { KeyboardShortcutHint } from '@anthropic/ink' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' -import { MessageResponse } from '../../components/MessageResponse.js' -import { OutputLine } from '../../components/shell/OutputLine.js' -import { ShellProgressMessage } from '../../components/shell/ShellProgressMessage.js' -import { ShellTimeDisplay } from '../../components/shell/ShellTimeDisplay.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' +import { MessageResponse } from 'src/components/MessageResponse.js' +import { OutputLine } from 'src/components/shell/OutputLine.js' +import { ShellProgressMessage } from 'src/components/shell/ShellProgressMessage.js' +import { ShellTimeDisplay } from 'src/components/shell/ShellTimeDisplay.js' import { Box, Text } from '@anthropic/ink' -import type { Tool } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import type { PowerShellProgress } from '../../types/tools.js' -import type { ThemeName } from '../../utils/theme.js' +import type { Tool } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import type { PowerShellProgress } from 'src/types/tools.js' +import type { ThemeName } from 'src/utils/theme.js' import type { Out, PowerShellToolInput } from './PowerShellTool.js' // Constants for command display diff --git a/src/tools/PowerShellTool/__tests__/commandSemantics.test.ts b/packages/builtin-tools/src/tools/PowerShellTool/__tests__/commandSemantics.test.ts similarity index 100% rename from src/tools/PowerShellTool/__tests__/commandSemantics.test.ts rename to packages/builtin-tools/src/tools/PowerShellTool/__tests__/commandSemantics.test.ts diff --git a/src/tools/PowerShellTool/__tests__/destructiveCommandWarning.test.ts b/packages/builtin-tools/src/tools/PowerShellTool/__tests__/destructiveCommandWarning.test.ts similarity index 100% rename from src/tools/PowerShellTool/__tests__/destructiveCommandWarning.test.ts rename to packages/builtin-tools/src/tools/PowerShellTool/__tests__/destructiveCommandWarning.test.ts diff --git a/src/tools/PowerShellTool/__tests__/gitSafety.test.ts b/packages/builtin-tools/src/tools/PowerShellTool/__tests__/gitSafety.test.ts similarity index 100% rename from src/tools/PowerShellTool/__tests__/gitSafety.test.ts rename to packages/builtin-tools/src/tools/PowerShellTool/__tests__/gitSafety.test.ts diff --git a/src/tools/PowerShellTool/__tests__/powershellSecurity.test.ts b/packages/builtin-tools/src/tools/PowerShellTool/__tests__/powershellSecurity.test.ts similarity index 99% rename from src/tools/PowerShellTool/__tests__/powershellSecurity.test.ts rename to packages/builtin-tools/src/tools/PowerShellTool/__tests__/powershellSecurity.test.ts index 0cabd53ef..c0b79a784 100644 --- a/src/tools/PowerShellTool/__tests__/powershellSecurity.test.ts +++ b/packages/builtin-tools/src/tools/PowerShellTool/__tests__/powershellSecurity.test.ts @@ -1,8 +1,8 @@ import { mock, describe, expect, test } from "bun:test"; -import type { ParsedCommandElement, ParsedPowerShellCommand } from "../../../utils/powershell/parser.js"; +import type { ParsedCommandElement, ParsedPowerShellCommand } from "src/utils/powershell/parser.js"; // Mock clmTypes to avoid heavy dependency chain -mock.module("../../../utils/powershell/dangerousCmdlets.js", () => ({ +mock.module("src/utils/powershell/dangerousCmdlets.js", () => ({ DANGEROUS_SCRIPT_BLOCK_CMDLETS: new Set([ "invoke-command", "icm", diff --git a/src/tools/PowerShellTool/clmTypes.ts b/packages/builtin-tools/src/tools/PowerShellTool/clmTypes.ts similarity index 100% rename from src/tools/PowerShellTool/clmTypes.ts rename to packages/builtin-tools/src/tools/PowerShellTool/clmTypes.ts diff --git a/src/tools/PowerShellTool/commandSemantics.ts b/packages/builtin-tools/src/tools/PowerShellTool/commandSemantics.ts similarity index 100% rename from src/tools/PowerShellTool/commandSemantics.ts rename to packages/builtin-tools/src/tools/PowerShellTool/commandSemantics.ts diff --git a/src/tools/PowerShellTool/commonParameters.ts b/packages/builtin-tools/src/tools/PowerShellTool/commonParameters.ts similarity index 100% rename from src/tools/PowerShellTool/commonParameters.ts rename to packages/builtin-tools/src/tools/PowerShellTool/commonParameters.ts diff --git a/src/tools/PowerShellTool/destructiveCommandWarning.ts b/packages/builtin-tools/src/tools/PowerShellTool/destructiveCommandWarning.ts similarity index 100% rename from src/tools/PowerShellTool/destructiveCommandWarning.ts rename to packages/builtin-tools/src/tools/PowerShellTool/destructiveCommandWarning.ts diff --git a/src/tools/PowerShellTool/gitSafety.ts b/packages/builtin-tools/src/tools/PowerShellTool/gitSafety.ts similarity index 98% rename from src/tools/PowerShellTool/gitSafety.ts rename to packages/builtin-tools/src/tools/PowerShellTool/gitSafety.ts index 44c62cec4..6ce767452 100644 --- a/src/tools/PowerShellTool/gitSafety.ts +++ b/packages/builtin-tools/src/tools/PowerShellTool/gitSafety.ts @@ -8,8 +8,8 @@ */ import { basename, posix, resolve, sep } from 'path' -import { getCwd } from '../../utils/cwd.js' -import { PS_TOKENIZER_DASH_CHARS } from '../../utils/powershell/parser.js' +import { getCwd } from 'src/utils/cwd.js' +import { PS_TOKENIZER_DASH_CHARS } from 'src/utils/powershell/parser.js' /** * If a normalized path starts with `..//`, it re-enters cwd diff --git a/src/tools/PowerShellTool/modeValidation.ts b/packages/builtin-tools/src/tools/PowerShellTool/modeValidation.ts similarity index 98% rename from src/tools/PowerShellTool/modeValidation.ts rename to packages/builtin-tools/src/tools/PowerShellTool/modeValidation.ts index 82b404319..5f395bb16 100644 --- a/src/tools/PowerShellTool/modeValidation.ts +++ b/packages/builtin-tools/src/tools/PowerShellTool/modeValidation.ts @@ -6,14 +6,14 @@ * Follows the same patterns as BashTool/modeValidation.ts. */ -import type { ToolPermissionContext } from '../../Tool.js' -import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' -import type { ParsedPowerShellCommand } from '../../utils/powershell/parser.js' +import type { ToolPermissionContext } from 'src/Tool.js' +import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' +import type { ParsedPowerShellCommand } from 'src/utils/powershell/parser.js' import { deriveSecurityFlags, getPipelineSegments, PS_TOKENIZER_DASH_CHARS, -} from '../../utils/powershell/parser.js' +} from 'src/utils/powershell/parser.js' import { argLeaksValue, isAllowlistedPipelineTail, diff --git a/src/tools/PowerShellTool/pathValidation.ts b/packages/builtin-tools/src/tools/PowerShellTool/pathValidation.ts similarity index 98% rename from src/tools/PowerShellTool/pathValidation.ts rename to packages/builtin-tools/src/tools/PowerShellTool/pathValidation.ts index 79813f197..9ccaaaf67 100644 --- a/src/tools/PowerShellTool/pathValidation.ts +++ b/packages/builtin-tools/src/tools/PowerShellTool/pathValidation.ts @@ -8,14 +8,14 @@ import { homedir } from 'os' import { isAbsolute, resolve } from 'path' -import type { ToolPermissionContext } from '../../Tool.js' -import type { PermissionRule } from '../../types/permissions.js' -import { getCwd } from '../../utils/cwd.js' +import type { ToolPermissionContext } from 'src/Tool.js' +import type { PermissionRule } from 'src/types/permissions.js' +import { getCwd } from 'src/utils/cwd.js' import { getFsImplementation, safeResolvePath, -} from '../../utils/fsOperations.js' -import { containsPathTraversal, getDirectoryForPath } from '../../utils/path.js' +} from 'src/utils/fsOperations.js' +import { containsPathTraversal, getDirectoryForPath } from 'src/utils/path.js' import { allWorkingDirectories, checkEditableInternalPath, @@ -23,23 +23,23 @@ import { checkReadableInternalPath, matchingRuleForInput, pathInAllowedWorkingPath, -} from '../../utils/permissions/filesystem.js' -import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' -import { createReadRuleSuggestion } from '../../utils/permissions/PermissionUpdate.js' -import type { PermissionUpdate } from '../../utils/permissions/PermissionUpdateSchema.js' +} from 'src/utils/permissions/filesystem.js' +import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' +import { createReadRuleSuggestion } from 'src/utils/permissions/PermissionUpdate.js' +import type { PermissionUpdate } from 'src/utils/permissions/PermissionUpdateSchema.js' import { isDangerousRemovalPath, isPathInSandboxWriteAllowlist, -} from '../../utils/permissions/pathValidation.js' -import { getPlatform } from '../../utils/platform.js' +} from 'src/utils/permissions/pathValidation.js' +import { getPlatform } from 'src/utils/platform.js' import type { ParsedCommandElement, ParsedPowerShellCommand, -} from '../../utils/powershell/parser.js' +} from 'src/utils/powershell/parser.js' import { isNullRedirectionTarget, isPowerShellParameter, -} from '../../utils/powershell/parser.js' +} from 'src/utils/powershell/parser.js' import { COMMON_SWITCHES, COMMON_VALUE_PARAMS } from './commonParameters.js' import { resolveToCanonical } from './readOnlyValidation.js' @@ -53,7 +53,7 @@ type FileOperationType = 'read' | 'write' | 'create' type PathCheckResult = { allowed: boolean - decisionReason?: import('../../utils/permissions/PermissionResult.js').PermissionDecisionReason + decisionReason?: import('src/utils/permissions/PermissionResult.js').PermissionDecisionReason } type ResolvedPathCheckResult = PathCheckResult & { diff --git a/src/tools/PowerShellTool/powershellPermissions.ts b/packages/builtin-tools/src/tools/PowerShellTool/powershellPermissions.ts similarity index 99% rename from src/tools/PowerShellTool/powershellPermissions.ts rename to packages/builtin-tools/src/tools/PowerShellTool/powershellPermissions.ts index 942991e7c..b05f347ef 100644 --- a/src/tools/PowerShellTool/powershellPermissions.ts +++ b/packages/builtin-tools/src/tools/PowerShellTool/powershellPermissions.ts @@ -4,25 +4,25 @@ */ import { resolve } from 'path' -import type { ToolPermissionContext, ToolUseContext } from '../../Tool.js' +import type { ToolPermissionContext, ToolUseContext } from 'src/Tool.js' import type { PermissionDecisionReason, PermissionResult, -} from '../../types/permissions.js' -import { getCwd } from '../../utils/cwd.js' -import { isCurrentDirectoryBareGitRepo } from '../../utils/git.js' -import type { PermissionRule } from '../../utils/permissions/PermissionRule.js' -import type { PermissionUpdate } from '../../utils/permissions/PermissionUpdateSchema.js' +} from 'src/types/permissions.js' +import { getCwd } from 'src/utils/cwd.js' +import { isCurrentDirectoryBareGitRepo } from 'src/utils/git.js' +import type { PermissionRule } from 'src/utils/permissions/PermissionRule.js' +import type { PermissionUpdate } from 'src/utils/permissions/PermissionUpdateSchema.js' import { createPermissionRequestMessage, getRuleByContentsForToolName, -} from '../../utils/permissions/permissions.js' +} from 'src/utils/permissions/permissions.js' import { matchWildcardPattern, parsePermissionRule, type ShellPermissionRule, suggestionForExactCommand as sharedSuggestionForExactCommand, -} from '../../utils/permissions/shellRuleMatching.js' +} from 'src/utils/permissions/shellRuleMatching.js' import { classifyCommandName, deriveSecurityFlags, @@ -33,8 +33,8 @@ import { PS_TOKENIZER_DASH_CHARS, parsePowerShellCommand, stripModulePrefix, -} from '../../utils/powershell/parser.js' -import { containsVulnerableUncPath } from '../../utils/shell/readOnlyCommandValidation.js' +} from 'src/utils/powershell/parser.js' +import { containsVulnerableUncPath } from 'src/utils/shell/readOnlyCommandValidation.js' import { isDotGitPathPS, isGitInternalPathPS } from './gitSafety.js' import { checkPermissionMode, diff --git a/src/tools/PowerShellTool/powershellSecurity.ts b/packages/builtin-tools/src/tools/PowerShellTool/powershellSecurity.ts similarity index 99% rename from src/tools/PowerShellTool/powershellSecurity.ts rename to packages/builtin-tools/src/tools/PowerShellTool/powershellSecurity.ts index 8439f86f1..f0c6a5f47 100644 --- a/src/tools/PowerShellTool/powershellSecurity.ts +++ b/packages/builtin-tools/src/tools/PowerShellTool/powershellSecurity.ts @@ -12,11 +12,11 @@ import { DANGEROUS_SCRIPT_BLOCK_CMDLETS, FILEPATH_EXECUTION_CMDLETS, MODULE_LOADING_CMDLETS, -} from '../../utils/powershell/dangerousCmdlets.js' +} from 'src/utils/powershell/dangerousCmdlets.js' import type { ParsedCommandElement, ParsedPowerShellCommand, -} from '../../utils/powershell/parser.js' +} from 'src/utils/powershell/parser.js' import { COMMON_ALIASES, commandHasArgAbbreviation, @@ -24,7 +24,7 @@ import { getAllCommands, getVariablesByScope, hasCommandNamed, -} from '../../utils/powershell/parser.js' +} from 'src/utils/powershell/parser.js' import { isClmAllowedType } from './clmTypes.js' type PowerShellSecurityResult = { diff --git a/src/tools/PowerShellTool/prompt.ts b/packages/builtin-tools/src/tools/PowerShellTool/prompt.ts similarity index 97% rename from src/tools/PowerShellTool/prompt.ts rename to packages/builtin-tools/src/tools/PowerShellTool/prompt.ts index 5cd23b3e4..6e812aeee 100644 --- a/src/tools/PowerShellTool/prompt.ts +++ b/packages/builtin-tools/src/tools/PowerShellTool/prompt.ts @@ -1,13 +1,13 @@ -import { isEnvTruthy } from '../../utils/envUtils.js' -import { getMaxOutputLength } from '../../utils/shell/outputLimits.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' +import { getMaxOutputLength } from 'src/utils/shell/outputLimits.js' import { getPowerShellEdition, type PowerShellEdition, -} from '../../utils/shell/powershellDetection.js' +} from 'src/utils/shell/powershellDetection.js' import { getDefaultBashTimeoutMs, getMaxBashTimeoutMs, -} from '../../utils/timeouts.js' +} from 'src/utils/timeouts.js' import { FILE_EDIT_TOOL_NAME } from '../FileEditTool/constants.js' import { FILE_READ_TOOL_NAME } from '../FileReadTool/prompt.js' import { FILE_WRITE_TOOL_NAME } from '../FileWriteTool/prompt.js' diff --git a/src/tools/PowerShellTool/readOnlyValidation.ts b/packages/builtin-tools/src/tools/PowerShellTool/readOnlyValidation.ts similarity index 99% rename from src/tools/PowerShellTool/readOnlyValidation.ts rename to packages/builtin-tools/src/tools/PowerShellTool/readOnlyValidation.ts index e0894fa56..d28541d23 100644 --- a/src/tools/PowerShellTool/readOnlyValidation.ts +++ b/packages/builtin-tools/src/tools/PowerShellTool/readOnlyValidation.ts @@ -7,26 +7,26 @@ import type { ParsedCommandElement, ParsedPowerShellCommand, -} from '../../utils/powershell/parser.js' +} from 'src/utils/powershell/parser.js' type ParsedStatement = ParsedPowerShellCommand['statements'][number] -import { getPlatform } from '../../utils/platform.js' +import { getPlatform } from 'src/utils/platform.js' import { COMMON_ALIASES, deriveSecurityFlags, getPipelineSegments, isNullRedirectionTarget, isPowerShellParameter, -} from '../../utils/powershell/parser.js' -import type { ExternalCommandConfig } from '../../utils/shell/readOnlyCommandValidation.js' +} from 'src/utils/powershell/parser.js' +import type { ExternalCommandConfig } from 'src/utils/shell/readOnlyCommandValidation.js' import { DOCKER_READ_ONLY_COMMANDS, EXTERNAL_READONLY_COMMANDS, GH_READ_ONLY_COMMANDS, GIT_READ_ONLY_COMMANDS, validateFlags, -} from '../../utils/shell/readOnlyCommandValidation.js' +} from 'src/utils/shell/readOnlyCommandValidation.js' import { COMMON_PARAMETERS } from './commonParameters.js' const DOTNET_READ_ONLY_FLAGS = new Set([ diff --git a/src/tools/PowerShellTool/src/hooks/useCanUseTool.ts b/packages/builtin-tools/src/tools/PowerShellTool/src/hooks/useCanUseTool.ts similarity index 100% rename from src/tools/PowerShellTool/src/hooks/useCanUseTool.ts rename to packages/builtin-tools/src/tools/PowerShellTool/src/hooks/useCanUseTool.ts diff --git a/src/tools/PowerShellTool/src/state/AppState.ts b/packages/builtin-tools/src/tools/PowerShellTool/src/state/AppState.ts similarity index 100% rename from src/tools/PowerShellTool/src/state/AppState.ts rename to packages/builtin-tools/src/tools/PowerShellTool/src/state/AppState.ts diff --git a/src/tools/PowerShellTool/toolName.ts b/packages/builtin-tools/src/tools/PowerShellTool/toolName.ts similarity index 100% rename from src/tools/PowerShellTool/toolName.ts rename to packages/builtin-tools/src/tools/PowerShellTool/toolName.ts diff --git a/src/tools/PushNotificationTool/PushNotificationTool.ts b/packages/builtin-tools/src/tools/PushNotificationTool/PushNotificationTool.ts similarity index 93% rename from src/tools/PushNotificationTool/PushNotificationTool.ts rename to packages/builtin-tools/src/tools/PushNotificationTool/PushNotificationTool.ts index bc730594b..be2d0702c 100644 --- a/src/tools/PushNotificationTool/PushNotificationTool.ts +++ b/packages/builtin-tools/src/tools/PushNotificationTool/PushNotificationTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' const PUSH_NOTIFICATION_TOOL_NAME = 'PushNotification' diff --git a/src/tools/REPLTool/REPLTool.ts b/packages/builtin-tools/src/tools/REPLTool/REPLTool.ts similarity index 94% rename from src/tools/REPLTool/REPLTool.ts rename to packages/builtin-tools/src/tools/REPLTool/REPLTool.ts index cc9bb80b7..f1ce33309 100644 --- a/src/tools/REPLTool/REPLTool.ts +++ b/packages/builtin-tools/src/tools/REPLTool/REPLTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { REPL_TOOL_NAME } from './constants.js' const inputSchema = lazySchema(() => diff --git a/src/tools/REPLTool/constants.ts b/packages/builtin-tools/src/tools/REPLTool/constants.ts similarity index 95% rename from src/tools/REPLTool/constants.ts rename to packages/builtin-tools/src/tools/REPLTool/constants.ts index 87bfe18d9..935e89c8f 100644 --- a/src/tools/REPLTool/constants.ts +++ b/packages/builtin-tools/src/tools/REPLTool/constants.ts @@ -1,4 +1,4 @@ -import { isEnvDefinedFalsy, isEnvTruthy } from '../../utils/envUtils.js' +import { isEnvDefinedFalsy, isEnvTruthy } from 'src/utils/envUtils.js' import { AGENT_TOOL_NAME } from '../AgentTool/constants.js' import { BASH_TOOL_NAME } from '../BashTool/toolName.js' import { FILE_EDIT_TOOL_NAME } from '../FileEditTool/constants.js' diff --git a/src/tools/REPLTool/primitiveTools.ts b/packages/builtin-tools/src/tools/REPLTool/primitiveTools.ts similarity index 97% rename from src/tools/REPLTool/primitiveTools.ts rename to packages/builtin-tools/src/tools/REPLTool/primitiveTools.ts index 4ea53e465..9a21dac3d 100644 --- a/src/tools/REPLTool/primitiveTools.ts +++ b/packages/builtin-tools/src/tools/REPLTool/primitiveTools.ts @@ -1,4 +1,4 @@ -import type { Tool } from '../../Tool.js' +import type { Tool } from 'src/Tool.js' import { AgentTool } from '../AgentTool/AgentTool.js' import { BashTool } from '../BashTool/BashTool.js' import { FileEditTool } from '../FileEditTool/FileEditTool.js' diff --git a/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts b/packages/builtin-tools/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts similarity index 92% rename from src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts rename to packages/builtin-tools/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts index 593131e74..dd7001ba6 100644 --- a/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +++ b/packages/builtin-tools/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts @@ -3,15 +3,15 @@ import { ReadResourceResultSchema, } from '@modelcontextprotocol/sdk/types.js' import { z } from 'zod/v4' -import { ensureConnectedClient } from '../../services/mcp/client.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import { ensureConnectedClient } from 'src/services/mcp/client.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { getBinaryBlobSavedMessage, persistBinaryContent, -} from '../../utils/mcpOutputStorage.js' -import { jsonStringify } from '../../utils/slowOperations.js' -import { isOutputLineTruncated } from '../../utils/terminal.js' +} from 'src/utils/mcpOutputStorage.js' +import { jsonStringify } from 'src/utils/slowOperations.js' +import { isOutputLineTruncated } from 'src/utils/terminal.js' import { DESCRIPTION, PROMPT } from './prompt.js' import { renderToolResultMessage, diff --git a/src/tools/ReadMcpResourceTool/UI.tsx b/packages/builtin-tools/src/tools/ReadMcpResourceTool/UI.tsx similarity index 79% rename from src/tools/ReadMcpResourceTool/UI.tsx rename to packages/builtin-tools/src/tools/ReadMcpResourceTool/UI.tsx index d2641adc2..4bb430d93 100644 --- a/src/tools/ReadMcpResourceTool/UI.tsx +++ b/packages/builtin-tools/src/tools/ReadMcpResourceTool/UI.tsx @@ -1,11 +1,11 @@ import * as React from 'react' import type { z } from 'zod/v4' -import { MessageResponse } from '../../components/MessageResponse.js' -import { OutputLine } from '../../components/shell/OutputLine.js' +import { MessageResponse } from 'src/components/MessageResponse.js' +import { OutputLine } from 'src/components/shell/OutputLine.js' import { Box, Text } from '@anthropic/ink' -import type { ToolProgressData } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import { jsonStringify } from '../../utils/slowOperations.js' +import type { ToolProgressData } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import { jsonStringify } from 'src/utils/slowOperations.js' import type { inputSchema, Output } from './ReadMcpResourceTool.js' export function renderToolUseMessage( diff --git a/src/tools/ReadMcpResourceTool/prompt.ts b/packages/builtin-tools/src/tools/ReadMcpResourceTool/prompt.ts similarity index 100% rename from src/tools/ReadMcpResourceTool/prompt.ts rename to packages/builtin-tools/src/tools/ReadMcpResourceTool/prompt.ts diff --git a/src/tools/RemoteTriggerTool/RemoteTriggerTool.ts b/packages/builtin-tools/src/tools/RemoteTriggerTool/RemoteTriggerTool.ts similarity index 88% rename from src/tools/RemoteTriggerTool/RemoteTriggerTool.ts rename to packages/builtin-tools/src/tools/RemoteTriggerTool/RemoteTriggerTool.ts index 8e623a15e..6d0412fa6 100644 --- a/src/tools/RemoteTriggerTool/RemoteTriggerTool.ts +++ b/packages/builtin-tools/src/tools/RemoteTriggerTool/RemoteTriggerTool.ts @@ -1,17 +1,17 @@ import axios from 'axios' import { z } from 'zod/v4' -import { getOauthConfig } from '../../constants/oauth.js' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' -import { getOrganizationUUID } from '../../services/oauth/client.js' -import { isPolicyAllowed } from '../../services/policyLimits/index.js' -import type { ToolUseContext } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' +import { getOauthConfig } from 'src/constants/oauth.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import { getOrganizationUUID } from 'src/services/oauth/client.js' +import { isPolicyAllowed } from 'src/services/policyLimits/index.js' +import type { ToolUseContext } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' import { checkAndRefreshOAuthTokenIfNeeded, getClaudeAIOAuthTokens, -} from '../../utils/auth.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { jsonStringify } from '../../utils/slowOperations.js' +} from 'src/utils/auth.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { jsonStringify } from 'src/utils/slowOperations.js' import { DESCRIPTION, PROMPT, REMOTE_TRIGGER_TOOL_NAME } from './prompt.js' import { renderToolResultMessage, renderToolUseMessage } from './UI.js' diff --git a/src/tools/RemoteTriggerTool/UI.tsx b/packages/builtin-tools/src/tools/RemoteTriggerTool/UI.tsx similarity index 81% rename from src/tools/RemoteTriggerTool/UI.tsx rename to packages/builtin-tools/src/tools/RemoteTriggerTool/UI.tsx index 5aae25157..45e389dc3 100644 --- a/src/tools/RemoteTriggerTool/UI.tsx +++ b/packages/builtin-tools/src/tools/RemoteTriggerTool/UI.tsx @@ -1,7 +1,7 @@ import React from 'react' -import { MessageResponse } from '../../components/MessageResponse.js' +import { MessageResponse } from 'src/components/MessageResponse.js' import { Text } from '@anthropic/ink' -import { countCharInString } from '../../utils/stringUtils.js' +import { countCharInString } from 'src/utils/stringUtils.js' import type { Input, Output } from './RemoteTriggerTool.js' export function renderToolUseMessage(input: Partial): React.ReactNode { diff --git a/src/tools/RemoteTriggerTool/prompt.ts b/packages/builtin-tools/src/tools/RemoteTriggerTool/prompt.ts similarity index 100% rename from src/tools/RemoteTriggerTool/prompt.ts rename to packages/builtin-tools/src/tools/RemoteTriggerTool/prompt.ts diff --git a/src/tools/ReviewArtifactTool/ReviewArtifactTool.ts b/packages/builtin-tools/src/tools/ReviewArtifactTool/ReviewArtifactTool.ts similarity index 97% rename from src/tools/ReviewArtifactTool/ReviewArtifactTool.ts rename to packages/builtin-tools/src/tools/ReviewArtifactTool/ReviewArtifactTool.ts index 26429f50e..94965efa8 100644 --- a/src/tools/ReviewArtifactTool/ReviewArtifactTool.ts +++ b/packages/builtin-tools/src/tools/ReviewArtifactTool/ReviewArtifactTool.ts @@ -1,6 +1,6 @@ import { z } from 'zod/v4' -import { buildTool, type ToolDef } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import React from 'react' import { Box, Text } from '@anthropic/ink' diff --git a/src/tools/ScheduleCronTool/CronCreateTool.ts b/packages/builtin-tools/src/tools/ScheduleCronTool/CronCreateTool.ts similarity index 91% rename from src/tools/ScheduleCronTool/CronCreateTool.ts rename to packages/builtin-tools/src/tools/ScheduleCronTool/CronCreateTool.ts index 85e6f0611..57f384e96 100644 --- a/src/tools/ScheduleCronTool/CronCreateTool.ts +++ b/packages/builtin-tools/src/tools/ScheduleCronTool/CronCreateTool.ts @@ -1,17 +1,17 @@ import { z } from 'zod/v4' -import { setScheduledTasksEnabled } from '../../bootstrap/state.js' -import type { ValidationResult } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { cronToHuman, parseCronExpression } from '../../utils/cron.js' +import { setScheduledTasksEnabled } from 'src/bootstrap/state.js' +import type { ValidationResult } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { cronToHuman, parseCronExpression } from 'src/utils/cron.js' import { addCronTask, getCronFilePath, listAllCronTasks, nextCronRunMs, -} from '../../utils/cronTasks.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { semanticBoolean } from '../../utils/semanticBoolean.js' -import { getTeammateContext } from '../../utils/teammateContext.js' +} from 'src/utils/cronTasks.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { semanticBoolean } from 'src/utils/semanticBoolean.js' +import { getTeammateContext } from 'src/utils/teammateContext.js' import { buildCronCreateDescription, buildCronCreatePrompt, diff --git a/src/tools/ScheduleCronTool/CronDeleteTool.ts b/packages/builtin-tools/src/tools/ScheduleCronTool/CronDeleteTool.ts similarity index 89% rename from src/tools/ScheduleCronTool/CronDeleteTool.ts rename to packages/builtin-tools/src/tools/ScheduleCronTool/CronDeleteTool.ts index 3dff3b34a..34fd8fca8 100644 --- a/src/tools/ScheduleCronTool/CronDeleteTool.ts +++ b/packages/builtin-tools/src/tools/ScheduleCronTool/CronDeleteTool.ts @@ -1,13 +1,13 @@ import { z } from 'zod/v4' -import type { ValidationResult } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' +import type { ValidationResult } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' import { getCronFilePath, listAllCronTasks, removeCronTasks, -} from '../../utils/cronTasks.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { getTeammateContext } from '../../utils/teammateContext.js' +} from 'src/utils/cronTasks.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { getTeammateContext } from 'src/utils/teammateContext.js' import { buildCronDeletePrompt, CRON_DELETE_DESCRIPTION, diff --git a/src/tools/ScheduleCronTool/CronListTool.ts b/packages/builtin-tools/src/tools/ScheduleCronTool/CronListTool.ts similarity index 88% rename from src/tools/ScheduleCronTool/CronListTool.ts rename to packages/builtin-tools/src/tools/ScheduleCronTool/CronListTool.ts index 4a08a740b..caeb7336f 100644 --- a/src/tools/ScheduleCronTool/CronListTool.ts +++ b/packages/builtin-tools/src/tools/ScheduleCronTool/CronListTool.ts @@ -1,10 +1,10 @@ import { z } from 'zod/v4' -import { buildTool, type ToolDef } from '../../Tool.js' -import { cronToHuman } from '../../utils/cron.js' -import { listAllCronTasks } from '../../utils/cronTasks.js' -import { truncate } from '../../utils/format.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { getTeammateContext } from '../../utils/teammateContext.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { cronToHuman } from 'src/utils/cron.js' +import { listAllCronTasks } from 'src/utils/cronTasks.js' +import { truncate } from 'src/utils/format.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { getTeammateContext } from 'src/utils/teammateContext.js' import { buildCronListPrompt, CRON_LIST_DESCRIPTION, diff --git a/src/tools/ScheduleCronTool/UI.tsx b/packages/builtin-tools/src/tools/ScheduleCronTool/UI.tsx similarity index 94% rename from src/tools/ScheduleCronTool/UI.tsx rename to packages/builtin-tools/src/tools/ScheduleCronTool/UI.tsx index 7e4928a81..6eaca4abd 100644 --- a/src/tools/ScheduleCronTool/UI.tsx +++ b/packages/builtin-tools/src/tools/ScheduleCronTool/UI.tsx @@ -1,7 +1,7 @@ import React from 'react' -import { MessageResponse } from '../../components/MessageResponse.js' +import { MessageResponse } from 'src/components/MessageResponse.js' import { Text } from '@anthropic/ink' -import { truncate } from '../../utils/format.js' +import { truncate } from 'src/utils/format.js' import type { CreateOutput } from './CronCreateTool.js' import type { DeleteOutput } from './CronDeleteTool.js' import type { ListOutput } from './CronListTool.js' diff --git a/src/tools/ScheduleCronTool/prompt.ts b/packages/builtin-tools/src/tools/ScheduleCronTool/prompt.ts similarity index 97% rename from src/tools/ScheduleCronTool/prompt.ts rename to packages/builtin-tools/src/tools/ScheduleCronTool/prompt.ts index e82da47b6..c41019687 100644 --- a/src/tools/ScheduleCronTool/prompt.ts +++ b/packages/builtin-tools/src/tools/ScheduleCronTool/prompt.ts @@ -1,7 +1,7 @@ import { feature } from 'bun:bundle' -import { getFeatureValue_CACHED_WITH_REFRESH } from '../../services/analytics/growthbook.js' -import { DEFAULT_CRON_JITTER_CONFIG } from '../../utils/cronTasks.js' -import { isEnvTruthy } from '../../utils/envUtils.js' +import { getFeatureValue_CACHED_WITH_REFRESH } from 'src/services/analytics/growthbook.js' +import { DEFAULT_CRON_JITTER_CONFIG } from 'src/utils/cronTasks.js' +import { isEnvTruthy } from 'src/utils/envUtils.js' const KAIROS_CRON_REFRESH_MS = 5 * 60 * 1000 diff --git a/src/tools/SendMessageTool/SendMessageTool.ts b/packages/builtin-tools/src/tools/SendMessageTool/SendMessageTool.ts similarity index 93% rename from src/tools/SendMessageTool/SendMessageTool.ts rename to packages/builtin-tools/src/tools/SendMessageTool/SendMessageTool.ts index fbb602d38..4e9737051 100644 --- a/src/tools/SendMessageTool/SendMessageTool.ts +++ b/packages/builtin-tools/src/tools/SendMessageTool/SendMessageTool.ts @@ -1,29 +1,29 @@ import { feature } from 'bun:bundle' import { z } from 'zod/v4' -import { isReplBridgeActive } from '../../bootstrap/state.js' -import { getReplBridgeHandle } from '../../bridge/replBridgeHandle.js' -import type { Tool, ToolUseContext } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { findTeammateTaskByAgentId } from '../../tasks/InProcessTeammateTask/InProcessTeammateTask.js' +import { isReplBridgeActive } from 'src/bootstrap/state.js' +import { getReplBridgeHandle } from 'src/bridge/replBridgeHandle.js' +import type { Tool, ToolUseContext } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { findTeammateTaskByAgentId } from 'src/tasks/InProcessTeammateTask/InProcessTeammateTask.js' import { isLocalAgentTask, queuePendingMessage, -} from '../../tasks/LocalAgentTask/LocalAgentTask.js' -import { isMainSessionTask } from '../../tasks/LocalMainSessionTask.js' -import { toAgentId } from '../../types/ids.js' -import { generateRequestId } from '../../utils/agentId.js' -import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js' -import { logForDebugging } from '../../utils/debug.js' -import { errorMessage } from '../../utils/errors.js' -import { truncate } from '../../utils/format.js' -import { gracefulShutdown } from '../../utils/gracefulShutdown.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { parseAddress } from '../../utils/peerAddress.js' -import { semanticBoolean } from '../../utils/semanticBoolean.js' -import { jsonStringify } from '../../utils/slowOperations.js' -import type { BackendType } from '../../utils/swarm/backends/types.js' -import { TEAM_LEAD_NAME } from '../../utils/swarm/constants.js' -import { readTeamFileAsync } from '../../utils/swarm/teamHelpers.js' +} from 'src/tasks/LocalAgentTask/LocalAgentTask.js' +import { isMainSessionTask } from 'src/tasks/LocalMainSessionTask.js' +import { toAgentId } from 'src/types/ids.js' +import { generateRequestId } from 'src/utils/agentId.js' +import { isAgentSwarmsEnabled } from 'src/utils/agentSwarmsEnabled.js' +import { logForDebugging } from 'src/utils/debug.js' +import { errorMessage } from 'src/utils/errors.js' +import { truncate } from 'src/utils/format.js' +import { gracefulShutdown } from 'src/utils/gracefulShutdown.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { parseAddress } from 'src/utils/peerAddress.js' +import { semanticBoolean } from 'src/utils/semanticBoolean.js' +import { jsonStringify } from 'src/utils/slowOperations.js' +import type { BackendType } from 'src/utils/swarm/backends/types.js' +import { TEAM_LEAD_NAME } from 'src/utils/swarm/constants.js' +import { readTeamFileAsync } from 'src/utils/swarm/teamHelpers.js' import { getAgentId, getAgentName, @@ -31,13 +31,13 @@ import { getTeamName, isTeamLead, isTeammate, -} from '../../utils/teammate.js' +} from 'src/utils/teammate.js' import { createShutdownApprovedMessage, createShutdownRejectedMessage, createShutdownRequestMessage, writeToMailbox, -} from '../../utils/teammateMailbox.js' +} from 'src/utils/teammateMailbox.js' import { resumeAgentBackground } from '../AgentTool/resumeAgent.js' import { SEND_MESSAGE_TOOL_NAME } from './constants.js' import { DESCRIPTION, getPrompt } from './prompt.js' @@ -770,7 +770,7 @@ export const SendMessageTool: Tool = } /* eslint-disable @typescript-eslint/no-require-imports */ const { postInterClaudeMessage } = - require('../../bridge/peerSessions.js') as typeof import('../../bridge/peerSessions.js') + require('src/bridge/peerSessions.js') as typeof import('src/bridge/peerSessions.js') /* eslint-enable @typescript-eslint/no-require-imports */ const result = await postInterClaudeMessage( addr.target, @@ -789,7 +789,7 @@ export const SendMessageTool: Tool = if (addr.scheme === 'uds') { /* eslint-disable @typescript-eslint/no-require-imports */ const { sendToUdsSocket } = - require('../../utils/udsClient.js') as typeof import('../../utils/udsClient.js') + require('src/utils/udsClient.js') as typeof import('src/utils/udsClient.js') /* eslint-enable @typescript-eslint/no-require-imports */ try { await sendToUdsSocket(addr.target, input.message) @@ -811,9 +811,9 @@ export const SendMessageTool: Tool = } if (addr.scheme === 'tcp' && feature('LAN_PIPES')) { const { parseTcpTarget } = - require('../../utils/peerAddress.js') as typeof import('../../utils/peerAddress.js') + require('src/utils/peerAddress.js') as typeof import('src/utils/peerAddress.js') const { PipeClient } = - require('../../utils/pipeTransport.js') as typeof import('../../utils/pipeTransport.js') + require('src/utils/pipeTransport.js') as typeof import('src/utils/pipeTransport.js') const ep = parseTcpTarget(addr.target) if (!ep) { return { diff --git a/src/tools/SendMessageTool/UI.tsx b/packages/builtin-tools/src/tools/SendMessageTool/UI.tsx similarity index 88% rename from src/tools/SendMessageTool/UI.tsx rename to packages/builtin-tools/src/tools/SendMessageTool/UI.tsx index 38d17a8d4..babdc98f7 100644 --- a/src/tools/SendMessageTool/UI.tsx +++ b/packages/builtin-tools/src/tools/SendMessageTool/UI.tsx @@ -1,7 +1,7 @@ import React from 'react' -import { MessageResponse } from '../../components/MessageResponse.js' +import { MessageResponse } from 'src/components/MessageResponse.js' import { Text } from '@anthropic/ink' -import { jsonParse } from '../../utils/slowOperations.js' +import { jsonParse } from 'src/utils/slowOperations.js' import type { Input, SendMessageToolOutput } from './SendMessageTool.js' export function renderToolUseMessage(input: Partial): React.ReactNode { diff --git a/src/tools/SendMessageTool/constants.ts b/packages/builtin-tools/src/tools/SendMessageTool/constants.ts similarity index 100% rename from src/tools/SendMessageTool/constants.ts rename to packages/builtin-tools/src/tools/SendMessageTool/constants.ts diff --git a/src/tools/SendMessageTool/prompt.ts b/packages/builtin-tools/src/tools/SendMessageTool/prompt.ts similarity index 100% rename from src/tools/SendMessageTool/prompt.ts rename to packages/builtin-tools/src/tools/SendMessageTool/prompt.ts diff --git a/src/tools/SendUserFileTool/SendUserFileTool.ts b/packages/builtin-tools/src/tools/SendUserFileTool/SendUserFileTool.ts similarity index 93% rename from src/tools/SendUserFileTool/SendUserFileTool.ts rename to packages/builtin-tools/src/tools/SendUserFileTool/SendUserFileTool.ts index 584872c8c..9f8b98f7f 100644 --- a/src/tools/SendUserFileTool/SendUserFileTool.ts +++ b/packages/builtin-tools/src/tools/SendUserFileTool/SendUserFileTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { SEND_USER_FILE_TOOL_NAME } from './prompt.js' const inputSchema = lazySchema(() => diff --git a/src/tools/SendUserFileTool/prompt.ts b/packages/builtin-tools/src/tools/SendUserFileTool/prompt.ts similarity index 100% rename from src/tools/SendUserFileTool/prompt.ts rename to packages/builtin-tools/src/tools/SendUserFileTool/prompt.ts diff --git a/src/tools/SkillTool/SkillTool.ts b/packages/builtin-tools/src/tools/SkillTool/SkillTool.ts similarity index 96% rename from src/tools/SkillTool/SkillTool.ts rename to packages/builtin-tools/src/tools/SkillTool/SkillTool.ts index c7149141d..bc18e2447 100644 --- a/src/tools/SkillTool/SkillTool.ts +++ b/packages/builtin-tools/src/tools/SkillTool/SkillTool.ts @@ -38,27 +38,27 @@ import { addInvokedSkill, clearInvokedSkillsForAgent, getSessionId, -} from '../../bootstrap/state.js' -import { COMMAND_MESSAGE_TAG } from '../../constants/xml.js' -import type { CanUseToolFn } from '../../hooks/useCanUseTool.js' +} from 'src/bootstrap/state.js' +import { COMMAND_MESSAGE_TAG } from 'src/constants/xml.js' +import type { CanUseToolFn } from 'src/hooks/useCanUseTool.js' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, type AnalyticsMetadata_I_VERIFIED_THIS_IS_PII_TAGGED, logEvent, -} from '../../services/analytics/index.js' -import { getAgentContext } from '../../utils/agentContext.js' -import { errorMessage } from '../../utils/errors.js' +} from 'src/services/analytics/index.js' +import { getAgentContext } from 'src/utils/agentContext.js' +import { errorMessage } from 'src/utils/errors.js' import { extractResultText, prepareForkedCommandContext, -} from '../../utils/forkedAgent.js' -import { parseFrontmatter } from '../../utils/frontmatterParser.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { createUserMessage, normalizeMessages } from '../../utils/messages.js' -import type { ModelAlias } from '../../utils/model/aliases.js' -import { resolveSkillModelOverride } from '../../utils/model/model.js' -import { recordSkillUsage } from '../../utils/suggestions/skillUsageTracking.js' -import { createAgentId } from '../../utils/uuid.js' +} from 'src/utils/forkedAgent.js' +import { parseFrontmatter } from 'src/utils/frontmatterParser.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { createUserMessage, normalizeMessages } from 'src/utils/messages.js' +import type { ModelAlias } from 'src/utils/model/aliases.js' +import { resolveSkillModelOverride } from 'src/utils/model/model.js' +import { recordSkillUsage } from 'src/utils/suggestions/skillUsageTracking.js' +import { createAgentId } from 'src/utils/uuid.js' import { runAgent } from '../AgentTool/runAgent.js' import { getToolUseIDFromParentMessage, @@ -94,9 +94,9 @@ async function getAllCommands(context: ToolUseContext): Promise { } // Re-export Progress from centralized types to break import cycles -export type { SkillToolProgress as Progress } from '../../types/tools.js' +export type { SkillToolProgress as Progress } from 'src/types/tools.js' -import type { SkillToolProgress as Progress } from '../../types/tools.js' +import type { SkillToolProgress as Progress } from 'src/types/tools.js' // Conditional require for remote skill modules — static imports here would // pull in akiBackend.ts (via remoteSkillLoader → akiBackend), which has @@ -107,10 +107,10 @@ import type { SkillToolProgress as Progress } from '../../types/tools.js' /* eslint-disable @typescript-eslint/no-require-imports */ const remoteSkillModules = feature('EXPERIMENTAL_SKILL_SEARCH') ? { - ...(require('../../services/skillSearch/remoteSkillState.js') as typeof import('../../services/skillSearch/remoteSkillState.js')), - ...(require('../../services/skillSearch/remoteSkillLoader.js') as typeof import('../../services/skillSearch/remoteSkillLoader.js')), - ...(require('../../services/skillSearch/telemetry.js') as typeof import('../../services/skillSearch/telemetry.js')), - ...(require('../../services/skillSearch/featureCheck.js') as typeof import('../../services/skillSearch/featureCheck.js')), + ...(require('src/services/skillSearch/remoteSkillState.js') as typeof import('src/services/skillSearch/remoteSkillState.js')), + ...(require('src/services/skillSearch/remoteSkillLoader.js') as typeof import('src/services/skillSearch/remoteSkillLoader.js')), + ...(require('src/services/skillSearch/telemetry.js') as typeof import('src/services/skillSearch/telemetry.js')), + ...(require('src/services/skillSearch/featureCheck.js') as typeof import('src/services/skillSearch/featureCheck.js')), } : null /* eslint-enable @typescript-eslint/no-require-imports */ diff --git a/src/tools/SkillTool/UI.tsx b/packages/builtin-tools/src/tools/SkillTool/UI.tsx similarity index 91% rename from src/tools/SkillTool/UI.tsx rename to packages/builtin-tools/src/tools/SkillTool/UI.tsx index 7898ee348..e61b398b7 100644 --- a/src/tools/SkillTool/UI.tsx +++ b/packages/builtin-tools/src/tools/SkillTool/UI.tsx @@ -4,15 +4,15 @@ import { SubAgentProvider } from 'src/components/CtrlOToExpand.js' import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' import { FallbackToolUseRejectedMessage } from 'src/components/FallbackToolUseRejectedMessage.js' import type { z } from 'zod/v4' -import type { Command } from '../../commands.js' +import type { Command } from 'src/commands.js' import { Byline } from '@anthropic/ink' -import { Message as MessageComponent } from '../../components/Message.js' -import { MessageResponse } from '../../components/MessageResponse.js' +import { Message as MessageComponent } from 'src/components/Message.js' +import { MessageResponse } from 'src/components/MessageResponse.js' import { Box, Text } from '@anthropic/ink' -import type { Tools } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import { buildSubagentLookups, EMPTY_LOOKUPS } from '../../utils/messages.js' -import { plural } from '../../utils/stringUtils.js' +import type { Tools } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import { buildSubagentLookups, EMPTY_LOOKUPS } from 'src/utils/messages.js' +import { plural } from 'src/utils/stringUtils.js' import type { inputSchema, Output, Progress } from './SkillTool.js' type Input = z.infer> diff --git a/src/tools/SkillTool/constants.ts b/packages/builtin-tools/src/tools/SkillTool/constants.ts similarity index 100% rename from src/tools/SkillTool/constants.ts rename to packages/builtin-tools/src/tools/SkillTool/constants.ts diff --git a/src/tools/SkillTool/prompt.ts b/packages/builtin-tools/src/tools/SkillTool/prompt.ts similarity index 95% rename from src/tools/SkillTool/prompt.ts rename to packages/builtin-tools/src/tools/SkillTool/prompt.ts index ef8267a78..d7b177400 100644 --- a/src/tools/SkillTool/prompt.ts +++ b/packages/builtin-tools/src/tools/SkillTool/prompt.ts @@ -5,17 +5,17 @@ import { getSkillToolCommands, getSlashCommandToolSkills, } from 'src/commands.js' -import { COMMAND_NAME_TAG } from '../../constants/xml.js' +import { COMMAND_NAME_TAG } from 'src/constants/xml.js' import { stringWidth } from '@anthropic/ink' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, -} from '../../services/analytics/index.js' -import { count } from '../../utils/array.js' -import { logForDebugging } from '../../utils/debug.js' -import { toError } from '../../utils/errors.js' -import { truncate } from '../../utils/format.js' -import { logError } from '../../utils/log.js' +} from 'src/services/analytics/index.js' +import { count } from 'src/utils/array.js' +import { logForDebugging } from 'src/utils/debug.js' +import { toError } from 'src/utils/errors.js' +import { truncate } from 'src/utils/format.js' +import { logError } from 'src/utils/log.js' // Skill listing gets 1% of the context window (in characters) export const SKILL_BUDGET_CONTEXT_PERCENT = 0.01 diff --git a/src/tools/SkillTool/src/Tool.ts b/packages/builtin-tools/src/tools/SkillTool/src/Tool.ts similarity index 100% rename from src/tools/SkillTool/src/Tool.ts rename to packages/builtin-tools/src/tools/SkillTool/src/Tool.ts diff --git a/src/tools/SkillTool/src/bootstrap/state.ts b/packages/builtin-tools/src/tools/SkillTool/src/bootstrap/state.ts similarity index 100% rename from src/tools/SkillTool/src/bootstrap/state.ts rename to packages/builtin-tools/src/tools/SkillTool/src/bootstrap/state.ts diff --git a/src/tools/SkillTool/src/commands.ts b/packages/builtin-tools/src/tools/SkillTool/src/commands.ts similarity index 100% rename from src/tools/SkillTool/src/commands.ts rename to packages/builtin-tools/src/tools/SkillTool/src/commands.ts diff --git a/src/tools/SkillTool/src/components/CtrlOToExpand.ts b/packages/builtin-tools/src/tools/SkillTool/src/components/CtrlOToExpand.ts similarity index 100% rename from src/tools/SkillTool/src/components/CtrlOToExpand.ts rename to packages/builtin-tools/src/tools/SkillTool/src/components/CtrlOToExpand.ts diff --git a/src/tools/SkillTool/src/components/FallbackToolUseErrorMessage.ts b/packages/builtin-tools/src/tools/SkillTool/src/components/FallbackToolUseErrorMessage.ts similarity index 100% rename from src/tools/SkillTool/src/components/FallbackToolUseErrorMessage.ts rename to packages/builtin-tools/src/tools/SkillTool/src/components/FallbackToolUseErrorMessage.ts diff --git a/src/tools/SkillTool/src/components/FallbackToolUseRejectedMessage.ts b/packages/builtin-tools/src/tools/SkillTool/src/components/FallbackToolUseRejectedMessage.ts similarity index 100% rename from src/tools/SkillTool/src/components/FallbackToolUseRejectedMessage.ts rename to packages/builtin-tools/src/tools/SkillTool/src/components/FallbackToolUseRejectedMessage.ts diff --git a/src/tools/SkillTool/src/types/command.ts b/packages/builtin-tools/src/tools/SkillTool/src/types/command.ts similarity index 100% rename from src/tools/SkillTool/src/types/command.ts rename to packages/builtin-tools/src/tools/SkillTool/src/types/command.ts diff --git a/src/tools/SkillTool/src/types/message.ts b/packages/builtin-tools/src/tools/SkillTool/src/types/message.ts similarity index 100% rename from src/tools/SkillTool/src/types/message.ts rename to packages/builtin-tools/src/tools/SkillTool/src/types/message.ts diff --git a/src/tools/SkillTool/src/utils/debug.ts b/packages/builtin-tools/src/tools/SkillTool/src/utils/debug.ts similarity index 100% rename from src/tools/SkillTool/src/utils/debug.ts rename to packages/builtin-tools/src/tools/SkillTool/src/utils/debug.ts diff --git a/src/tools/SkillTool/src/utils/permissions/PermissionResult.ts b/packages/builtin-tools/src/tools/SkillTool/src/utils/permissions/PermissionResult.ts similarity index 100% rename from src/tools/SkillTool/src/utils/permissions/PermissionResult.ts rename to packages/builtin-tools/src/tools/SkillTool/src/utils/permissions/PermissionResult.ts diff --git a/src/tools/SkillTool/src/utils/permissions/permissions.ts b/packages/builtin-tools/src/tools/SkillTool/src/utils/permissions/permissions.ts similarity index 100% rename from src/tools/SkillTool/src/utils/permissions/permissions.ts rename to packages/builtin-tools/src/tools/SkillTool/src/utils/permissions/permissions.ts diff --git a/src/tools/SkillTool/src/utils/plugins/pluginIdentifier.ts b/packages/builtin-tools/src/tools/SkillTool/src/utils/plugins/pluginIdentifier.ts similarity index 100% rename from src/tools/SkillTool/src/utils/plugins/pluginIdentifier.ts rename to packages/builtin-tools/src/tools/SkillTool/src/utils/plugins/pluginIdentifier.ts diff --git a/src/tools/SkillTool/src/utils/telemetry/pluginTelemetry.ts b/packages/builtin-tools/src/tools/SkillTool/src/utils/telemetry/pluginTelemetry.ts similarity index 100% rename from src/tools/SkillTool/src/utils/telemetry/pluginTelemetry.ts rename to packages/builtin-tools/src/tools/SkillTool/src/utils/telemetry/pluginTelemetry.ts diff --git a/src/tools/SleepTool/SleepTool.ts b/packages/builtin-tools/src/tools/SleepTool/SleepTool.ts similarity index 90% rename from src/tools/SleepTool/SleepTool.ts rename to packages/builtin-tools/src/tools/SleepTool/SleepTool.ts index 3807a30bc..32c491c57 100644 --- a/src/tools/SleepTool/SleepTool.ts +++ b/packages/builtin-tools/src/tools/SleepTool/SleepTool.ts @@ -1,8 +1,8 @@ import { feature } from 'bun:bundle' import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { SLEEP_TOOL_NAME, DESCRIPTION, SLEEP_TOOL_PROMPT } from './prompt.js' const inputSchema = lazySchema(() => @@ -71,7 +71,7 @@ export const SleepTool = buildTool({ // re-issuing Sleep after an interruption caused by /proactive disable. if (feature('PROACTIVE') || feature('KAIROS')) { const mod = - require('../../proactive/index.js') as typeof import('../../proactive/index.js') + require('src/proactive/index.js') as typeof import('src/proactive/index.js') if (!mod.isProactiveActive()) { return { data: { @@ -106,7 +106,7 @@ export const SleepTool = buildTool({ feature('PROACTIVE') || feature('KAIROS') ? setInterval(() => { const mod = - require('../../proactive/index.js') as typeof import('../../proactive/index.js') + require('src/proactive/index.js') as typeof import('src/proactive/index.js') if (!mod.isProactiveActive()) { clearTimeout(timer) clearInterval(proactiveCheck) diff --git a/src/tools/SleepTool/prompt.ts b/packages/builtin-tools/src/tools/SleepTool/prompt.ts similarity index 93% rename from src/tools/SleepTool/prompt.ts rename to packages/builtin-tools/src/tools/SleepTool/prompt.ts index 3bf817438..b880184d5 100644 --- a/src/tools/SleepTool/prompt.ts +++ b/packages/builtin-tools/src/tools/SleepTool/prompt.ts @@ -1,4 +1,4 @@ -import { TICK_TAG } from '../../constants/xml.js' +import { TICK_TAG } from 'src/constants/xml.js' export const SLEEP_TOOL_NAME = 'Sleep' diff --git a/src/tools/SnipTool/SnipTool.ts b/packages/builtin-tools/src/tools/SnipTool/SnipTool.ts similarity index 94% rename from src/tools/SnipTool/SnipTool.ts rename to packages/builtin-tools/src/tools/SnipTool/SnipTool.ts index 773d40300..39629f2b6 100644 --- a/src/tools/SnipTool/SnipTool.ts +++ b/packages/builtin-tools/src/tools/SnipTool/SnipTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { SNIP_TOOL_NAME } from './prompt.js' const inputSchema = lazySchema(() => diff --git a/src/tools/SnipTool/prompt.ts b/packages/builtin-tools/src/tools/SnipTool/prompt.ts similarity index 100% rename from src/tools/SnipTool/prompt.ts rename to packages/builtin-tools/src/tools/SnipTool/prompt.ts diff --git a/src/tools/SubscribePRTool/SubscribePRTool.ts b/packages/builtin-tools/src/tools/SubscribePRTool/SubscribePRTool.ts similarity index 93% rename from src/tools/SubscribePRTool/SubscribePRTool.ts rename to packages/builtin-tools/src/tools/SubscribePRTool/SubscribePRTool.ts index adb4d71bc..9e051fd94 100644 --- a/src/tools/SubscribePRTool/SubscribePRTool.ts +++ b/packages/builtin-tools/src/tools/SubscribePRTool/SubscribePRTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' const SUBSCRIBE_PR_TOOL_NAME = 'SubscribePR' diff --git a/src/tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.ts b/packages/builtin-tools/src/tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.ts similarity index 93% rename from src/tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.ts rename to packages/builtin-tools/src/tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.ts index d97ba094f..d05452f89 100644 --- a/src/tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.ts +++ b/packages/builtin-tools/src/tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' const SUGGEST_BACKGROUND_PR_TOOL_NAME = 'SuggestBackgroundPR' diff --git a/src/tools/SyntheticOutputTool/SyntheticOutputTool.ts b/packages/builtin-tools/src/tools/SyntheticOutputTool/SyntheticOutputTool.ts similarity index 93% rename from src/tools/SyntheticOutputTool/SyntheticOutputTool.ts rename to packages/builtin-tools/src/tools/SyntheticOutputTool/SyntheticOutputTool.ts index f58438a03..4cbcbb07d 100644 --- a/src/tools/SyntheticOutputTool/SyntheticOutputTool.ts +++ b/packages/builtin-tools/src/tools/SyntheticOutputTool/SyntheticOutputTool.ts @@ -1,11 +1,11 @@ import { Ajv } from 'ajv' import { z } from 'zod/v4' -import type { Tool, ToolInputJSONSchema } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from '../../utils/errors.js' -import { lazySchema } from '../../utils/lazySchema.js' -import type { PermissionResult } from '../../utils/permissions/PermissionResult.js' -import { jsonStringify } from '../../utils/slowOperations.js' +import type { Tool, ToolInputJSONSchema } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from 'src/utils/errors.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' +import { jsonStringify } from 'src/utils/slowOperations.js' // Allow any input object since the schema is provided dynamically const inputSchema = lazySchema(() => z.object({}).passthrough()) diff --git a/src/tools/TaskCreateTool/TaskCreateTool.ts b/packages/builtin-tools/src/tools/TaskCreateTool/TaskCreateTool.ts similarity index 93% rename from src/tools/TaskCreateTool/TaskCreateTool.ts rename to packages/builtin-tools/src/tools/TaskCreateTool/TaskCreateTool.ts index 2d82c8b77..f607c821d 100644 --- a/src/tools/TaskCreateTool/TaskCreateTool.ts +++ b/packages/builtin-tools/src/tools/TaskCreateTool/TaskCreateTool.ts @@ -1,17 +1,17 @@ import { z } from 'zod/v4' -import { buildTool, type ToolDef } from '../../Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' import { executeTaskCreatedHooks, getTaskCreatedHookMessage, -} from '../../utils/hooks.js' -import { lazySchema } from '../../utils/lazySchema.js' +} from 'src/utils/hooks.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { createTask, deleteTask, getTaskListId, isTodoV2Enabled, -} from '../../utils/tasks.js' -import { getAgentName, getTeamName } from '../../utils/teammate.js' +} from 'src/utils/tasks.js' +import { getAgentName, getTeamName } from 'src/utils/teammate.js' import { TASK_CREATE_TOOL_NAME } from './constants.js' import { DESCRIPTION, getPrompt } from './prompt.js' diff --git a/src/tools/TaskCreateTool/constants.ts b/packages/builtin-tools/src/tools/TaskCreateTool/constants.ts similarity index 100% rename from src/tools/TaskCreateTool/constants.ts rename to packages/builtin-tools/src/tools/TaskCreateTool/constants.ts diff --git a/src/tools/TaskCreateTool/prompt.ts b/packages/builtin-tools/src/tools/TaskCreateTool/prompt.ts similarity index 97% rename from src/tools/TaskCreateTool/prompt.ts rename to packages/builtin-tools/src/tools/TaskCreateTool/prompt.ts index 74db4135f..3ddcd886c 100644 --- a/src/tools/TaskCreateTool/prompt.ts +++ b/packages/builtin-tools/src/tools/TaskCreateTool/prompt.ts @@ -1,4 +1,4 @@ -import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js' +import { isAgentSwarmsEnabled } from 'src/utils/agentSwarmsEnabled.js' export const DESCRIPTION = 'Create a new task in the task list' diff --git a/src/tools/TaskGetTool/TaskGetTool.ts b/packages/builtin-tools/src/tools/TaskGetTool/TaskGetTool.ts similarity index 95% rename from src/tools/TaskGetTool/TaskGetTool.ts rename to packages/builtin-tools/src/tools/TaskGetTool/TaskGetTool.ts index ffcbfaff0..f23f6ffbf 100644 --- a/src/tools/TaskGetTool/TaskGetTool.ts +++ b/packages/builtin-tools/src/tools/TaskGetTool/TaskGetTool.ts @@ -1,12 +1,12 @@ import { z } from 'zod/v4' -import { buildTool, type ToolDef } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { getTask, getTaskListId, isTodoV2Enabled, TaskStatusSchema, -} from '../../utils/tasks.js' +} from 'src/utils/tasks.js' import { TASK_GET_TOOL_NAME } from './constants.js' import { DESCRIPTION, PROMPT } from './prompt.js' diff --git a/src/tools/TaskGetTool/constants.ts b/packages/builtin-tools/src/tools/TaskGetTool/constants.ts similarity index 100% rename from src/tools/TaskGetTool/constants.ts rename to packages/builtin-tools/src/tools/TaskGetTool/constants.ts diff --git a/src/tools/TaskGetTool/prompt.ts b/packages/builtin-tools/src/tools/TaskGetTool/prompt.ts similarity index 100% rename from src/tools/TaskGetTool/prompt.ts rename to packages/builtin-tools/src/tools/TaskGetTool/prompt.ts diff --git a/src/tools/TaskListTool/TaskListTool.ts b/packages/builtin-tools/src/tools/TaskListTool/TaskListTool.ts similarity index 94% rename from src/tools/TaskListTool/TaskListTool.ts rename to packages/builtin-tools/src/tools/TaskListTool/TaskListTool.ts index 61e455897..128f73143 100644 --- a/src/tools/TaskListTool/TaskListTool.ts +++ b/packages/builtin-tools/src/tools/TaskListTool/TaskListTool.ts @@ -1,12 +1,12 @@ import { z } from 'zod/v4' -import { buildTool, type ToolDef } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { getTaskListId, isTodoV2Enabled, listTasks, TaskStatusSchema, -} from '../../utils/tasks.js' +} from 'src/utils/tasks.js' import { TASK_LIST_TOOL_NAME } from './constants.js' import { DESCRIPTION, getPrompt } from './prompt.js' diff --git a/src/tools/TaskListTool/constants.ts b/packages/builtin-tools/src/tools/TaskListTool/constants.ts similarity index 100% rename from src/tools/TaskListTool/constants.ts rename to packages/builtin-tools/src/tools/TaskListTool/constants.ts diff --git a/src/tools/TaskListTool/prompt.ts b/packages/builtin-tools/src/tools/TaskListTool/prompt.ts similarity index 96% rename from src/tools/TaskListTool/prompt.ts rename to packages/builtin-tools/src/tools/TaskListTool/prompt.ts index 8a2933be8..981fdd044 100644 --- a/src/tools/TaskListTool/prompt.ts +++ b/packages/builtin-tools/src/tools/TaskListTool/prompt.ts @@ -1,4 +1,4 @@ -import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js' +import { isAgentSwarmsEnabled } from 'src/utils/agentSwarmsEnabled.js' export const DESCRIPTION = 'List all tasks in the task list' diff --git a/src/tools/TaskOutputTool/TaskOutputTool.tsx b/packages/builtin-tools/src/tools/TaskOutputTool/TaskOutputTool.tsx similarity index 90% rename from src/tools/TaskOutputTool/TaskOutputTool.tsx rename to packages/builtin-tools/src/tools/TaskOutputTool/TaskOutputTool.tsx index d093f9267..644935e54 100644 --- a/src/tools/TaskOutputTool/TaskOutputTool.tsx +++ b/packages/builtin-tools/src/tools/TaskOutputTool/TaskOutputTool.tsx @@ -1,28 +1,28 @@ import React from 'react' import { z } from 'zod/v4' -import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js' -import { FallbackToolUseRejectedMessage } from '../../components/FallbackToolUseRejectedMessage.js' -import { MessageResponse } from '../../components/MessageResponse.js' +import { FallbackToolUseErrorMessage } from 'src/components/FallbackToolUseErrorMessage.js' +import { FallbackToolUseRejectedMessage } from 'src/components/FallbackToolUseRejectedMessage.js' +import { MessageResponse } from 'src/components/MessageResponse.js' import { Box, Text } from '@anthropic/ink' -import { useShortcutDisplay } from '../../keybindings/useShortcutDisplay.js' -import type { TaskType } from '../../Task.js' -import type { Tool } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import type { LocalAgentTaskState } from '../../tasks/LocalAgentTask/LocalAgentTask.js' -import type { LocalShellTaskState } from '../../tasks/LocalShellTask/guards.js' -import type { RemoteAgentTaskState } from '../../tasks/RemoteAgentTask/RemoteAgentTask.js' -import type { TaskState } from '../../tasks/types.js' -import { AbortError } from '../../utils/errors.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { extractTextContent } from '../../utils/messages.js' -import { semanticBoolean } from '../../utils/semanticBoolean.js' -import { sleep } from '../../utils/sleep.js' -import { jsonParse } from '../../utils/slowOperations.js' -import { countCharInString } from '../../utils/stringUtils.js' -import { getTaskOutput } from '../../utils/task/diskOutput.js' -import { updateTaskState } from '../../utils/task/framework.js' -import { formatTaskOutput } from '../../utils/task/outputFormatting.js' -import type { ThemeName } from '../../utils/theme.js' +import { useShortcutDisplay } from 'src/keybindings/useShortcutDisplay.js' +import type { TaskType } from 'src/Task.js' +import type { Tool } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import type { LocalAgentTaskState } from 'src/tasks/LocalAgentTask/LocalAgentTask.js' +import type { LocalShellTaskState } from 'src/tasks/LocalShellTask/guards.js' +import type { RemoteAgentTaskState } from 'src/tasks/RemoteAgentTask/RemoteAgentTask.js' +import type { TaskState } from 'src/tasks/types.js' +import { AbortError } from 'src/utils/errors.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { extractTextContent } from 'src/utils/messages.js' +import { semanticBoolean } from 'src/utils/semanticBoolean.js' +import { sleep } from 'src/utils/sleep.js' +import { jsonParse } from 'src/utils/slowOperations.js' +import { countCharInString } from 'src/utils/stringUtils.js' +import { getTaskOutput } from 'src/utils/task/diskOutput.js' +import { updateTaskState } from 'src/utils/task/framework.js' +import { formatTaskOutput } from 'src/utils/task/outputFormatting.js' +import type { ThemeName } from 'src/utils/theme.js' import { AgentPromptDisplay, AgentResponseDisplay } from '../AgentTool/UI.js' import BashToolResultMessage from '../BashTool/BashToolResultMessage.js' import { TASK_OUTPUT_TOOL_NAME } from './constants.js' @@ -65,7 +65,7 @@ type TaskOutputToolOutput = { } // Re-export Progress from centralized types to break import cycles -export type { TaskOutputProgress as Progress } from '../../types/tools.js' +export type { TaskOutputProgress as Progress } from 'src/types/tools.js' // Get output for any task type async function getTaskOutputData(task: TaskState): Promise { diff --git a/src/tools/TaskOutputTool/constants.ts b/packages/builtin-tools/src/tools/TaskOutputTool/constants.ts similarity index 100% rename from src/tools/TaskOutputTool/constants.ts rename to packages/builtin-tools/src/tools/TaskOutputTool/constants.ts diff --git a/src/tools/TaskStopTool/TaskStopTool.ts b/packages/builtin-tools/src/tools/TaskStopTool/TaskStopTool.ts similarity index 93% rename from src/tools/TaskStopTool/TaskStopTool.ts rename to packages/builtin-tools/src/tools/TaskStopTool/TaskStopTool.ts index 3a1acc008..5d7ce0283 100644 --- a/src/tools/TaskStopTool/TaskStopTool.ts +++ b/packages/builtin-tools/src/tools/TaskStopTool/TaskStopTool.ts @@ -1,9 +1,9 @@ import { z } from 'zod/v4' -import type { TaskStateBase } from '../../Task.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { stopTask } from '../../tasks/stopTask.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { jsonStringify } from '../../utils/slowOperations.js' +import type { TaskStateBase } from 'src/Task.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { stopTask } from 'src/tasks/stopTask.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { jsonStringify } from 'src/utils/slowOperations.js' import { DESCRIPTION, TASK_STOP_TOOL_NAME } from './prompt.js' import { renderToolResultMessage, renderToolUseMessage } from './UI.js' diff --git a/src/tools/TaskStopTool/UI.tsx b/packages/builtin-tools/src/tools/TaskStopTool/UI.tsx similarity index 89% rename from src/tools/TaskStopTool/UI.tsx rename to packages/builtin-tools/src/tools/TaskStopTool/UI.tsx index e4b2e8501..beb54da5a 100644 --- a/src/tools/TaskStopTool/UI.tsx +++ b/packages/builtin-tools/src/tools/TaskStopTool/UI.tsx @@ -1,7 +1,7 @@ import React from 'react' -import { MessageResponse } from '../../components/MessageResponse.js' +import { MessageResponse } from 'src/components/MessageResponse.js' import { Text, stringWidth } from '@anthropic/ink' -import { truncateToWidthNoEllipsis } from '../../utils/format.js' +import { truncateToWidthNoEllipsis } from 'src/utils/format.js' import type { Output } from './TaskStopTool.js' export function renderToolUseMessage(): React.ReactNode { diff --git a/src/tools/TaskStopTool/prompt.ts b/packages/builtin-tools/src/tools/TaskStopTool/prompt.ts similarity index 100% rename from src/tools/TaskStopTool/prompt.ts rename to packages/builtin-tools/src/tools/TaskStopTool/prompt.ts diff --git a/src/tools/TaskUpdateTool/TaskUpdateTool.ts b/packages/builtin-tools/src/tools/TaskUpdateTool/TaskUpdateTool.ts similarity index 96% rename from src/tools/TaskUpdateTool/TaskUpdateTool.ts rename to packages/builtin-tools/src/tools/TaskUpdateTool/TaskUpdateTool.ts index 427831bfb..1477facdd 100644 --- a/src/tools/TaskUpdateTool/TaskUpdateTool.ts +++ b/packages/builtin-tools/src/tools/TaskUpdateTool/TaskUpdateTool.ts @@ -1,13 +1,13 @@ import { feature } from 'bun:bundle' import { z } from 'zod/v4' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { isAgentSwarmsEnabled } from 'src/utils/agentSwarmsEnabled.js' import { executeTaskCompletedHooks, getTaskCompletedHookMessage, -} from '../../utils/hooks.js' -import { lazySchema } from '../../utils/lazySchema.js' +} from 'src/utils/hooks.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { blockTask, deleteTask, @@ -18,14 +18,14 @@ import { type TaskStatus, TaskStatusSchema, updateTask, -} from '../../utils/tasks.js' +} from 'src/utils/tasks.js' import { getAgentId, getAgentName, getTeammateColor, getTeamName, -} from '../../utils/teammate.js' -import { writeToMailbox } from '../../utils/teammateMailbox.js' +} from 'src/utils/teammate.js' +import { writeToMailbox } from 'src/utils/teammateMailbox.js' import { VERIFICATION_AGENT_TYPE } from '../AgentTool/constants.js' import { TASK_UPDATE_TOOL_NAME } from './constants.js' import { DESCRIPTION, PROMPT } from './prompt.js' diff --git a/src/tools/TaskUpdateTool/constants.ts b/packages/builtin-tools/src/tools/TaskUpdateTool/constants.ts similarity index 100% rename from src/tools/TaskUpdateTool/constants.ts rename to packages/builtin-tools/src/tools/TaskUpdateTool/constants.ts diff --git a/src/tools/TaskUpdateTool/prompt.ts b/packages/builtin-tools/src/tools/TaskUpdateTool/prompt.ts similarity index 100% rename from src/tools/TaskUpdateTool/prompt.ts rename to packages/builtin-tools/src/tools/TaskUpdateTool/prompt.ts diff --git a/src/tools/TeamCreateTool/TeamCreateTool.ts b/packages/builtin-tools/src/tools/TeamCreateTool/TeamCreateTool.ts similarity index 86% rename from src/tools/TeamCreateTool/TeamCreateTool.ts rename to packages/builtin-tools/src/tools/TeamCreateTool/TeamCreateTool.ts index 64a801860..a769325a6 100644 --- a/src/tools/TeamCreateTool/TeamCreateTool.ts +++ b/packages/builtin-tools/src/tools/TeamCreateTool/TeamCreateTool.ts @@ -1,35 +1,35 @@ import { z } from 'zod/v4' -import { getSessionId } from '../../bootstrap/state.js' -import { logEvent } from '../../services/analytics/index.js' -import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from '../../services/analytics/metadata.js' -import type { Tool } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { formatAgentId } from '../../utils/agentId.js' -import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js' -import { getCwd } from '../../utils/cwd.js' -import { lazySchema } from '../../utils/lazySchema.js' +import { getSessionId } from 'src/bootstrap/state.js' +import { logEvent } from 'src/services/analytics/index.js' +import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from 'src/services/analytics/metadata.js' +import type { Tool } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { formatAgentId } from 'src/utils/agentId.js' +import { isAgentSwarmsEnabled } from 'src/utils/agentSwarmsEnabled.js' +import { getCwd } from 'src/utils/cwd.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { getDefaultMainLoopModel, parseUserSpecifiedModel, -} from '../../utils/model/model.js' -import { jsonStringify } from '../../utils/slowOperations.js' -import { getResolvedTeammateMode } from '../../utils/swarm/backends/registry.js' -import { TEAM_LEAD_NAME } from '../../utils/swarm/constants.js' -import type { TeamFile } from '../../utils/swarm/teamHelpers.js' +} from 'src/utils/model/model.js' +import { jsonStringify } from 'src/utils/slowOperations.js' +import { getResolvedTeammateMode } from 'src/utils/swarm/backends/registry.js' +import { TEAM_LEAD_NAME } from 'src/utils/swarm/constants.js' +import type { TeamFile } from 'src/utils/swarm/teamHelpers.js' import { getTeamFilePath, readTeamFile, registerTeamForSessionCleanup, sanitizeName, writeTeamFileAsync, -} from '../../utils/swarm/teamHelpers.js' -import { assignTeammateColor } from '../../utils/swarm/teammateLayoutManager.js' +} from 'src/utils/swarm/teamHelpers.js' +import { assignTeammateColor } from 'src/utils/swarm/teammateLayoutManager.js' import { ensureTasksDir, resetTaskList, setLeaderTeamName, -} from '../../utils/tasks.js' -import { generateWordSlug } from '../../utils/words.js' +} from 'src/utils/tasks.js' +import { generateWordSlug } from 'src/utils/words.js' import { TEAM_CREATE_TOOL_NAME } from './constants.js' import { getPrompt } from './prompt.js' import { renderToolUseMessage } from './UI.js' diff --git a/src/tools/TeamCreateTool/UI.tsx b/packages/builtin-tools/src/tools/TeamCreateTool/UI.tsx similarity index 100% rename from src/tools/TeamCreateTool/UI.tsx rename to packages/builtin-tools/src/tools/TeamCreateTool/UI.tsx diff --git a/src/tools/TeamCreateTool/constants.ts b/packages/builtin-tools/src/tools/TeamCreateTool/constants.ts similarity index 100% rename from src/tools/TeamCreateTool/constants.ts rename to packages/builtin-tools/src/tools/TeamCreateTool/constants.ts diff --git a/src/tools/TeamCreateTool/prompt.ts b/packages/builtin-tools/src/tools/TeamCreateTool/prompt.ts similarity index 100% rename from src/tools/TeamCreateTool/prompt.ts rename to packages/builtin-tools/src/tools/TeamCreateTool/prompt.ts diff --git a/src/tools/TeamDeleteTool/TeamDeleteTool.ts b/packages/builtin-tools/src/tools/TeamDeleteTool/TeamDeleteTool.ts similarity index 84% rename from src/tools/TeamDeleteTool/TeamDeleteTool.ts rename to packages/builtin-tools/src/tools/TeamDeleteTool/TeamDeleteTool.ts index f09f78c30..7c80df676 100644 --- a/src/tools/TeamDeleteTool/TeamDeleteTool.ts +++ b/packages/builtin-tools/src/tools/TeamDeleteTool/TeamDeleteTool.ts @@ -1,19 +1,19 @@ import { z } from 'zod/v4' -import { logEvent } from '../../services/analytics/index.js' -import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from '../../services/analytics/metadata.js' -import type { Tool } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { jsonStringify } from '../../utils/slowOperations.js' -import { TEAM_LEAD_NAME } from '../../utils/swarm/constants.js' +import { logEvent } from 'src/services/analytics/index.js' +import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from 'src/services/analytics/metadata.js' +import type { Tool } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { isAgentSwarmsEnabled } from 'src/utils/agentSwarmsEnabled.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { jsonStringify } from 'src/utils/slowOperations.js' +import { TEAM_LEAD_NAME } from 'src/utils/swarm/constants.js' import { cleanupTeamDirectories, readTeamFile, unregisterTeamForSessionCleanup, -} from '../../utils/swarm/teamHelpers.js' -import { clearTeammateColors } from '../../utils/swarm/teammateLayoutManager.js' -import { clearLeaderTeamName } from '../../utils/tasks.js' +} from 'src/utils/swarm/teamHelpers.js' +import { clearTeammateColors } from 'src/utils/swarm/teammateLayoutManager.js' +import { clearLeaderTeamName } from 'src/utils/tasks.js' import { TEAM_DELETE_TOOL_NAME } from './constants.js' import { getPrompt } from './prompt.js' import { renderToolResultMessage, renderToolUseMessage } from './UI.js' diff --git a/src/tools/TeamDeleteTool/UI.tsx b/packages/builtin-tools/src/tools/TeamDeleteTool/UI.tsx similarity index 91% rename from src/tools/TeamDeleteTool/UI.tsx rename to packages/builtin-tools/src/tools/TeamDeleteTool/UI.tsx index 32b435b6c..228957439 100644 --- a/src/tools/TeamDeleteTool/UI.tsx +++ b/packages/builtin-tools/src/tools/TeamDeleteTool/UI.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { jsonParse } from '../../utils/slowOperations.js' +import { jsonParse } from 'src/utils/slowOperations.js' import type { Output } from './TeamDeleteTool.js' export function renderToolUseMessage( diff --git a/src/tools/TeamDeleteTool/constants.ts b/packages/builtin-tools/src/tools/TeamDeleteTool/constants.ts similarity index 100% rename from src/tools/TeamDeleteTool/constants.ts rename to packages/builtin-tools/src/tools/TeamDeleteTool/constants.ts diff --git a/src/tools/TeamDeleteTool/prompt.ts b/packages/builtin-tools/src/tools/TeamDeleteTool/prompt.ts similarity index 100% rename from src/tools/TeamDeleteTool/prompt.ts rename to packages/builtin-tools/src/tools/TeamDeleteTool/prompt.ts diff --git a/src/tools/TerminalCaptureTool/TerminalCaptureTool.ts b/packages/builtin-tools/src/tools/TerminalCaptureTool/TerminalCaptureTool.ts similarity index 92% rename from src/tools/TerminalCaptureTool/TerminalCaptureTool.ts rename to packages/builtin-tools/src/tools/TerminalCaptureTool/TerminalCaptureTool.ts index 9f953a1c3..8f54aa597 100644 --- a/src/tools/TerminalCaptureTool/TerminalCaptureTool.ts +++ b/packages/builtin-tools/src/tools/TerminalCaptureTool/TerminalCaptureTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { TERMINAL_CAPTURE_TOOL_NAME } from './prompt.js' const inputSchema = lazySchema(() => diff --git a/src/tools/TerminalCaptureTool/prompt.ts b/packages/builtin-tools/src/tools/TerminalCaptureTool/prompt.ts similarity index 100% rename from src/tools/TerminalCaptureTool/prompt.ts rename to packages/builtin-tools/src/tools/TerminalCaptureTool/prompt.ts diff --git a/src/tools/TodoWriteTool/TodoWriteTool.ts b/packages/builtin-tools/src/tools/TodoWriteTool/TodoWriteTool.ts similarity index 90% rename from src/tools/TodoWriteTool/TodoWriteTool.ts rename to packages/builtin-tools/src/tools/TodoWriteTool/TodoWriteTool.ts index f0eafbad2..d36d2f833 100644 --- a/src/tools/TodoWriteTool/TodoWriteTool.ts +++ b/packages/builtin-tools/src/tools/TodoWriteTool/TodoWriteTool.ts @@ -1,11 +1,11 @@ import { feature } from 'bun:bundle' import { z } from 'zod/v4' -import { getSessionId } from '../../bootstrap/state.js' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { isTodoV2Enabled } from '../../utils/tasks.js' -import { TodoListSchema } from '../../utils/todo/types.js' +import { getSessionId } from 'src/bootstrap/state.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { isTodoV2Enabled } from 'src/utils/tasks.js' +import { TodoListSchema } from 'src/utils/todo/types.js' import { VERIFICATION_AGENT_TYPE } from '../AgentTool/constants.js' import { TODO_WRITE_TOOL_NAME } from './constants.js' import { DESCRIPTION, PROMPT } from './prompt.js' diff --git a/src/tools/TodoWriteTool/constants.ts b/packages/builtin-tools/src/tools/TodoWriteTool/constants.ts similarity index 100% rename from src/tools/TodoWriteTool/constants.ts rename to packages/builtin-tools/src/tools/TodoWriteTool/constants.ts diff --git a/src/tools/TodoWriteTool/prompt.ts b/packages/builtin-tools/src/tools/TodoWriteTool/prompt.ts similarity index 100% rename from src/tools/TodoWriteTool/prompt.ts rename to packages/builtin-tools/src/tools/TodoWriteTool/prompt.ts diff --git a/src/tools/ToolSearchTool/ToolSearchTool.ts b/packages/builtin-tools/src/tools/ToolSearchTool/ToolSearchTool.ts similarity index 97% rename from src/tools/ToolSearchTool/ToolSearchTool.ts rename to packages/builtin-tools/src/tools/ToolSearchTool/ToolSearchTool.ts index ee43b6683..25e20ba91 100644 --- a/src/tools/ToolSearchTool/ToolSearchTool.ts +++ b/packages/builtin-tools/src/tools/ToolSearchTool/ToolSearchTool.ts @@ -4,18 +4,18 @@ import { z } from 'zod/v4' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, -} from '../../services/analytics/index.js' +} from 'src/services/analytics/index.js' import { buildTool, findToolByName, type Tool, type ToolDef, type Tools, -} from '../../Tool.js' -import { logForDebugging } from '../../utils/debug.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { escapeRegExp } from '../../utils/stringUtils.js' -import { isToolSearchEnabledOptimistic } from '../../utils/toolSearch.js' +} from 'src/Tool.js' +import { logForDebugging } from 'src/utils/debug.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { escapeRegExp } from 'src/utils/stringUtils.js' +import { isToolSearchEnabledOptimistic } from 'src/utils/toolSearch.js' import { getPrompt, isDeferredTool, TOOL_SEARCH_TOOL_NAME } from './prompt.js' export const inputSchema = lazySchema(() => diff --git a/src/tools/ToolSearchTool/constants.ts b/packages/builtin-tools/src/tools/ToolSearchTool/constants.ts similarity index 100% rename from src/tools/ToolSearchTool/constants.ts rename to packages/builtin-tools/src/tools/ToolSearchTool/constants.ts diff --git a/src/tools/ToolSearchTool/prompt.ts b/packages/builtin-tools/src/tools/ToolSearchTool/prompt.ts similarity index 96% rename from src/tools/ToolSearchTool/prompt.ts rename to packages/builtin-tools/src/tools/ToolSearchTool/prompt.ts index ca3e6b07b..4e205f8b6 100644 --- a/src/tools/ToolSearchTool/prompt.ts +++ b/packages/builtin-tools/src/tools/ToolSearchTool/prompt.ts @@ -1,7 +1,7 @@ import { feature } from 'bun:bundle' -import { isReplBridgeActive } from '../../bootstrap/state.js' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' -import type { Tool } from '../../Tool.js' +import { isReplBridgeActive } from 'src/bootstrap/state.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import type { Tool } from 'src/Tool.js' import { AGENT_TOOL_NAME } from '../AgentTool/constants.js' // Dead code elimination: Brief tool name only needed when KAIROS or KAIROS_BRIEF is on diff --git a/src/tools/TungstenTool/TungstenLiveMonitor.ts b/packages/builtin-tools/src/tools/TungstenTool/TungstenLiveMonitor.ts similarity index 100% rename from src/tools/TungstenTool/TungstenLiveMonitor.ts rename to packages/builtin-tools/src/tools/TungstenTool/TungstenLiveMonitor.ts diff --git a/src/tools/TungstenTool/TungstenTool.js b/packages/builtin-tools/src/tools/TungstenTool/TungstenTool.js similarity index 100% rename from src/tools/TungstenTool/TungstenTool.js rename to packages/builtin-tools/src/tools/TungstenTool/TungstenTool.js diff --git a/src/tools/TungstenTool/TungstenTool.ts b/packages/builtin-tools/src/tools/TungstenTool/TungstenTool.ts similarity index 86% rename from src/tools/TungstenTool/TungstenTool.ts rename to packages/builtin-tools/src/tools/TungstenTool/TungstenTool.ts index 3542a05f1..5f4cc6317 100644 --- a/src/tools/TungstenTool/TungstenTool.ts +++ b/packages/builtin-tools/src/tools/TungstenTool/TungstenTool.ts @@ -1,5 +1,5 @@ // Auto-generated stub — replace with real implementation -import type { Tool } from '../../Tool.js' +import type { Tool } from 'src/Tool.js' export const TungstenTool: Tool = (() => {}) as unknown as Tool; export const clearSessionsWithTungstenUsage: () => void = (() => {}); diff --git a/src/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.ts b/packages/builtin-tools/src/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.ts similarity index 93% rename from src/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.ts rename to packages/builtin-tools/src/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.ts index 65131d639..2d5eb1786 100644 --- a/src/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.ts +++ b/packages/builtin-tools/src/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' import { VERIFY_PLAN_EXECUTION_TOOL_NAME } from './constants.js' const inputSchema = lazySchema(() => diff --git a/src/tools/VerifyPlanExecutionTool/constants.ts b/packages/builtin-tools/src/tools/VerifyPlanExecutionTool/constants.ts similarity index 100% rename from src/tools/VerifyPlanExecutionTool/constants.ts rename to packages/builtin-tools/src/tools/VerifyPlanExecutionTool/constants.ts diff --git a/src/tools/WebBrowserTool/WebBrowserPanel.ts b/packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserPanel.ts similarity index 100% rename from src/tools/WebBrowserTool/WebBrowserPanel.ts rename to packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserPanel.ts diff --git a/src/tools/WebBrowserTool/WebBrowserTool.ts b/packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserTool.ts similarity index 93% rename from src/tools/WebBrowserTool/WebBrowserTool.ts rename to packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserTool.ts index 99110caa6..5041bd778 100644 --- a/src/tools/WebBrowserTool/WebBrowserTool.ts +++ b/packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' const WEB_BROWSER_TOOL_NAME = 'WebBrowser' diff --git a/src/tools/WebFetchTool/UI.tsx b/packages/builtin-tools/src/tools/WebFetchTool/UI.tsx similarity index 83% rename from src/tools/WebFetchTool/UI.tsx rename to packages/builtin-tools/src/tools/WebFetchTool/UI.tsx index 546bf727e..7ae4fcfbb 100644 --- a/src/tools/WebFetchTool/UI.tsx +++ b/packages/builtin-tools/src/tools/WebFetchTool/UI.tsx @@ -1,10 +1,10 @@ import React from 'react' -import { MessageResponse } from '../../components/MessageResponse.js' -import { TOOL_SUMMARY_MAX_LENGTH } from '../../constants/toolLimits.js' +import { MessageResponse } from 'src/components/MessageResponse.js' +import { TOOL_SUMMARY_MAX_LENGTH } from 'src/constants/toolLimits.js' import { Box, Text } from '@anthropic/ink' -import type { ToolProgressData } from '../../Tool.js' -import type { ProgressMessage } from '../../types/message.js' -import { formatFileSize, truncate } from '../../utils/format.js' +import type { ToolProgressData } from 'src/Tool.js' +import type { ProgressMessage } from 'src/types/message.js' +import { formatFileSize, truncate } from 'src/utils/format.js' import type { Output } from './WebFetchTool.js' export function renderToolUseMessage( diff --git a/src/tools/WebFetchTool/WebFetchTool.ts b/packages/builtin-tools/src/tools/WebFetchTool/WebFetchTool.ts similarity index 95% rename from src/tools/WebFetchTool/WebFetchTool.ts rename to packages/builtin-tools/src/tools/WebFetchTool/WebFetchTool.ts index b439f4468..0993e7959 100644 --- a/src/tools/WebFetchTool/WebFetchTool.ts +++ b/packages/builtin-tools/src/tools/WebFetchTool/WebFetchTool.ts @@ -1,10 +1,10 @@ import { z } from 'zod/v4' -import { buildTool, type ToolDef } from '../../Tool.js' -import type { PermissionUpdate } from '../../types/permissions.js' -import { formatFileSize } from '../../utils/format.js' -import { lazySchema } from '../../utils/lazySchema.js' -import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js' -import { getRuleByContentsForTool } from '../../utils/permissions/permissions.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import type { PermissionUpdate } from 'src/types/permissions.js' +import { formatFileSize } from 'src/utils/format.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import type { PermissionDecision } from 'src/utils/permissions/PermissionResult.js' +import { getRuleByContentsForTool } from 'src/utils/permissions/permissions.js' import { isPreapprovedHost } from './preapproved.js' import { DESCRIPTION, WEB_FETCH_TOOL_NAME } from './prompt.js' import { diff --git a/src/tools/WebFetchTool/__tests__/preapproved.test.ts b/packages/builtin-tools/src/tools/WebFetchTool/__tests__/preapproved.test.ts similarity index 100% rename from src/tools/WebFetchTool/__tests__/preapproved.test.ts rename to packages/builtin-tools/src/tools/WebFetchTool/__tests__/preapproved.test.ts diff --git a/src/tools/WebFetchTool/__tests__/urlValidation.test.ts b/packages/builtin-tools/src/tools/WebFetchTool/__tests__/urlValidation.test.ts similarity index 100% rename from src/tools/WebFetchTool/__tests__/urlValidation.test.ts rename to packages/builtin-tools/src/tools/WebFetchTool/__tests__/urlValidation.test.ts diff --git a/src/tools/WebFetchTool/preapproved.ts b/packages/builtin-tools/src/tools/WebFetchTool/preapproved.ts similarity index 100% rename from src/tools/WebFetchTool/preapproved.ts rename to packages/builtin-tools/src/tools/WebFetchTool/preapproved.ts diff --git a/src/tools/WebFetchTool/prompt.ts b/packages/builtin-tools/src/tools/WebFetchTool/prompt.ts similarity index 100% rename from src/tools/WebFetchTool/prompt.ts rename to packages/builtin-tools/src/tools/WebFetchTool/prompt.ts diff --git a/src/tools/WebFetchTool/utils.ts b/packages/builtin-tools/src/tools/WebFetchTool/utils.ts similarity index 97% rename from src/tools/WebFetchTool/utils.ts rename to packages/builtin-tools/src/tools/WebFetchTool/utils.ts index 912d51f09..0d8576ece 100644 --- a/src/tools/WebFetchTool/utils.ts +++ b/packages/builtin-tools/src/tools/WebFetchTool/utils.ts @@ -3,17 +3,17 @@ import { LRUCache } from 'lru-cache' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, -} from '../../services/analytics/index.js' -import { queryHaiku } from '../../services/api/claude.js' -import { AbortError } from '../../utils/errors.js' -import { getWebFetchUserAgent } from '../../utils/http.js' -import { logError } from '../../utils/log.js' +} from 'src/services/analytics/index.js' +import { queryHaiku } from 'src/services/api/claude.js' +import { AbortError } from 'src/utils/errors.js' +import { getWebFetchUserAgent } from 'src/utils/http.js' +import { logError } from 'src/utils/log.js' import { isBinaryContentType, persistBinaryContent, -} from '../../utils/mcpOutputStorage.js' -import { getSettings_DEPRECATED } from '../../utils/settings/settings.js' -import { asSystemPrompt } from '../../utils/systemPromptType.js' +} from 'src/utils/mcpOutputStorage.js' +import { getSettings_DEPRECATED } from 'src/utils/settings/settings.js' +import { asSystemPrompt } from 'src/utils/systemPromptType.js' import { isPreapprovedHost } from './preapproved.js' import { makeSecondaryModelPrompt } from './prompt.js' diff --git a/src/tools/WebSearchTool/UI.tsx b/packages/builtin-tools/src/tools/WebSearchTool/UI.tsx similarity index 91% rename from src/tools/WebSearchTool/UI.tsx rename to packages/builtin-tools/src/tools/WebSearchTool/UI.tsx index 005f95db9..9c08bbe8e 100644 --- a/src/tools/WebSearchTool/UI.tsx +++ b/packages/builtin-tools/src/tools/WebSearchTool/UI.tsx @@ -1,9 +1,9 @@ import React from 'react' -import { MessageResponse } from '../../components/MessageResponse.js' -import { TOOL_SUMMARY_MAX_LENGTH } from '../../constants/toolLimits.js' +import { MessageResponse } from 'src/components/MessageResponse.js' +import { TOOL_SUMMARY_MAX_LENGTH } from 'src/constants/toolLimits.js' import { Box, Text } from '@anthropic/ink' -import type { ProgressMessage } from '../../types/message.js' -import { truncate } from '../../utils/format.js' +import type { ProgressMessage } from 'src/types/message.js' +import { truncate } from 'src/utils/format.js' import type { Output, SearchResult, diff --git a/src/tools/WebSearchTool/WebSearchTool.ts b/packages/builtin-tools/src/tools/WebSearchTool/WebSearchTool.ts similarity index 95% rename from src/tools/WebSearchTool/WebSearchTool.ts rename to packages/builtin-tools/src/tools/WebSearchTool/WebSearchTool.ts index 77fba39f5..43a032585 100644 --- a/src/tools/WebSearchTool/WebSearchTool.ts +++ b/packages/builtin-tools/src/tools/WebSearchTool/WebSearchTool.ts @@ -1,8 +1,8 @@ import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js' import { z } from 'zod/v4' -import { buildTool, type ToolDef } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' -import { jsonStringify } from '../../utils/slowOperations.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' +import { jsonStringify } from 'src/utils/slowOperations.js' import { createAdapter } from './adapters/index.js' import { getWebSearchPrompt, WEB_SEARCH_TOOL_NAME } from './prompt.js' import { @@ -58,9 +58,9 @@ type OutputSchema = ReturnType export type Output = z.infer // Re-export WebSearchProgress from centralized types to break import cycles -export type { WebSearchProgress } from '../../types/tools.js' +export type { WebSearchProgress } from 'src/types/tools.js' -import type { WebSearchProgress } from '../../types/tools.js' +import type { WebSearchProgress } from 'src/types/tools.js' export const WebSearchTool = buildTool({ name: WEB_SEARCH_TOOL_NAME, diff --git a/src/tools/WebSearchTool/__tests__/adapterFactory.test.ts b/packages/builtin-tools/src/tools/WebSearchTool/__tests__/adapterFactory.test.ts similarity index 81% rename from src/tools/WebSearchTool/__tests__/adapterFactory.test.ts rename to packages/builtin-tools/src/tools/WebSearchTool/__tests__/adapterFactory.test.ts index d93b255b4..be2ab2cb6 100644 --- a/src/tools/WebSearchTool/__tests__/adapterFactory.test.ts +++ b/packages/builtin-tools/src/tools/WebSearchTool/__tests__/adapterFactory.test.ts @@ -2,19 +2,8 @@ import { afterEach, describe, expect, mock, test } from 'bun:test' let isFirstPartyBaseUrl = true -mock.module('../adapters/apiAdapter.js', () => ({ - ApiSearchAdapter: class ApiSearchAdapter {}, -})) - -mock.module('../adapters/bingAdapter.js', () => ({ - BingSearchAdapter: class BingSearchAdapter {}, -})) - -mock.module('../adapters/braveAdapter.js', () => ({ - BraveSearchAdapter: class BraveSearchAdapter {}, -})) - -mock.module('../../../utils/model/providers.js', () => ({ +// Only mock the external dependency that controls adapter selection +mock.module('src/utils/model/providers.js', () => ({ isFirstPartyAnthropicBaseUrl: () => isFirstPartyBaseUrl, })) diff --git a/src/tools/WebSearchTool/__tests__/bingAdapter.integration.ts b/packages/builtin-tools/src/tools/WebSearchTool/__tests__/bingAdapter.integration.ts similarity index 100% rename from src/tools/WebSearchTool/__tests__/bingAdapter.integration.ts rename to packages/builtin-tools/src/tools/WebSearchTool/__tests__/bingAdapter.integration.ts diff --git a/src/tools/WebSearchTool/__tests__/bingAdapter.test.ts b/packages/builtin-tools/src/tools/WebSearchTool/__tests__/bingAdapter.test.ts similarity index 97% rename from src/tools/WebSearchTool/__tests__/bingAdapter.test.ts rename to packages/builtin-tools/src/tools/WebSearchTool/__tests__/bingAdapter.test.ts index 5331a5dea..f1903551d 100644 --- a/src/tools/WebSearchTool/__tests__/bingAdapter.test.ts +++ b/packages/builtin-tools/src/tools/WebSearchTool/__tests__/bingAdapter.test.ts @@ -312,7 +312,7 @@ describe('BingSearchAdapter.search', () => { isCancel: () => false, }, })) - mock.module('../../../utils/http', () => ({ + mock.module('src/utils/http', () => ({ getWebFetchUserAgent: () => 'TestAgent/1.0', })) @@ -330,7 +330,7 @@ describe('BingSearchAdapter.search', () => { isCancel: () => false, }, })) - mock.module('../../../utils/http', () => ({ + mock.module('src/utils/http', () => ({ getWebFetchUserAgent: () => 'TestAgent/1.0', })) @@ -364,7 +364,7 @@ describe('BingSearchAdapter.search', () => { isCancel: () => false, }, })) - mock.module('../../../utils/http', () => ({ + mock.module('src/utils/http', () => ({ getWebFetchUserAgent: () => 'TestAgent/1.0', })) @@ -393,7 +393,7 @@ describe('BingSearchAdapter.search', () => { isCancel: () => false, }, })) - mock.module('../../../utils/http', () => ({ + mock.module('src/utils/http', () => ({ getWebFetchUserAgent: () => 'TestAgent/1.0', })) @@ -422,7 +422,7 @@ describe('BingSearchAdapter.search', () => { isCancel: () => false, }, })) - mock.module('../../../utils/http', () => ({ + mock.module('src/utils/http', () => ({ getWebFetchUserAgent: () => 'TestAgent/1.0', })) @@ -448,7 +448,7 @@ describe('BingSearchAdapter.search', () => { isCancel: (e: any) => e?.__CANCEL__ === true, }, })) - mock.module('../../../utils/http', () => ({ + mock.module('src/utils/http', () => ({ getWebFetchUserAgent: () => 'TestAgent/1.0', })) @@ -456,7 +456,7 @@ describe('BingSearchAdapter.search', () => { const controller = new AbortController() controller.abort() - const { AbortError } = await import('../../../utils/errors') + const { AbortError } = await import('src/utils/errors') await expect( adapter.search('test', { signal: controller.signal }), ).rejects.toThrow(AbortError) @@ -470,7 +470,7 @@ describe('BingSearchAdapter.search', () => { isCancel: () => false, }, })) - mock.module('../../../utils/http', () => ({ + mock.module('src/utils/http', () => ({ getWebFetchUserAgent: () => 'TestAgent/1.0', })) @@ -486,7 +486,7 @@ describe('BingSearchAdapter.search', () => { isCancel: () => false, }, })) - mock.module('../../../utils/http', () => ({ + mock.module('src/utils/http', () => ({ getWebFetchUserAgent: () => 'TestAgent/1.0', })) diff --git a/src/tools/WebSearchTool/__tests__/braveAdapter.extract.test.ts b/packages/builtin-tools/src/tools/WebSearchTool/__tests__/braveAdapter.extract.test.ts similarity index 100% rename from src/tools/WebSearchTool/__tests__/braveAdapter.extract.test.ts rename to packages/builtin-tools/src/tools/WebSearchTool/__tests__/braveAdapter.extract.test.ts diff --git a/src/tools/WebSearchTool/__tests__/braveAdapter.integration.ts b/packages/builtin-tools/src/tools/WebSearchTool/__tests__/braveAdapter.integration.ts similarity index 100% rename from src/tools/WebSearchTool/__tests__/braveAdapter.integration.ts rename to packages/builtin-tools/src/tools/WebSearchTool/__tests__/braveAdapter.integration.ts diff --git a/src/tools/WebSearchTool/__tests__/braveAdapter.test.ts b/packages/builtin-tools/src/tools/WebSearchTool/__tests__/braveAdapter.test.ts similarity index 99% rename from src/tools/WebSearchTool/__tests__/braveAdapter.test.ts rename to packages/builtin-tools/src/tools/WebSearchTool/__tests__/braveAdapter.test.ts index 8158e6dde..bc0481087 100644 --- a/src/tools/WebSearchTool/__tests__/braveAdapter.test.ts +++ b/packages/builtin-tools/src/tools/WebSearchTool/__tests__/braveAdapter.test.ts @@ -190,7 +190,7 @@ describe('BraveSearchAdapter.search', () => { const controller = new AbortController() controller.abort() - const { AbortError } = await import('../../../utils/errors') + const { AbortError } = await import('src/utils/errors') await expect( adapter.search('test', { signal: controller.signal }), ).rejects.toThrow(AbortError) diff --git a/src/tools/WebSearchTool/adapters/apiAdapter.ts b/packages/builtin-tools/src/tools/WebSearchTool/adapters/apiAdapter.ts similarity index 92% rename from src/tools/WebSearchTool/adapters/apiAdapter.ts rename to packages/builtin-tools/src/tools/WebSearchTool/adapters/apiAdapter.ts index ab78c4b21..0f61a5764 100644 --- a/src/tools/WebSearchTool/adapters/apiAdapter.ts +++ b/packages/builtin-tools/src/tools/WebSearchTool/adapters/apiAdapter.ts @@ -7,12 +7,12 @@ import type { BetaContentBlock, BetaWebSearchTool20250305, } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs' -import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../../services/analytics/growthbook.js' -import { queryModelWithStreaming } from '../../../services/api/claude.js' -import { createUserMessage } from '../../../utils/messages.js' -import { getMainLoopModel, getSmallFastModel } from '../../../utils/model/model.js' -import { jsonParse } from '../../../utils/slowOperations.js' -import { asSystemPrompt } from '../../../utils/systemPromptType.js' +import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' +import { queryModelWithStreaming } from 'src/services/api/claude.js' +import { createUserMessage } from 'src/utils/messages.js' +import { getMainLoopModel, getSmallFastModel } from 'src/utils/model/model.js' +import { jsonParse } from 'src/utils/slowOperations.js' +import { asSystemPrompt } from 'src/utils/systemPromptType.js' import type { SearchResult, SearchOptions, WebSearchAdapter } from './types.js' function makeToolSchema(input: { allowedDomains?: string[]; blockedDomains?: string[] }): BetaWebSearchTool20250305 { diff --git a/src/tools/WebSearchTool/adapters/bingAdapter.ts b/packages/builtin-tools/src/tools/WebSearchTool/adapters/bingAdapter.ts similarity index 99% rename from src/tools/WebSearchTool/adapters/bingAdapter.ts rename to packages/builtin-tools/src/tools/WebSearchTool/adapters/bingAdapter.ts index da9fefa4d..8f944a770 100644 --- a/src/tools/WebSearchTool/adapters/bingAdapter.ts +++ b/packages/builtin-tools/src/tools/WebSearchTool/adapters/bingAdapter.ts @@ -5,7 +5,7 @@ import axios from 'axios' import he from 'he' -import { AbortError } from '../../../utils/errors.js' +import { AbortError } from 'src/utils/errors.js' import type { SearchResult, SearchOptions, WebSearchAdapter } from './types.js' const FETCH_TIMEOUT_MS = 30_000 diff --git a/src/tools/WebSearchTool/adapters/braveAdapter.ts b/packages/builtin-tools/src/tools/WebSearchTool/adapters/braveAdapter.ts similarity index 98% rename from src/tools/WebSearchTool/adapters/braveAdapter.ts rename to packages/builtin-tools/src/tools/WebSearchTool/adapters/braveAdapter.ts index fbfc6e7da..58204131b 100644 --- a/src/tools/WebSearchTool/adapters/braveAdapter.ts +++ b/packages/builtin-tools/src/tools/WebSearchTool/adapters/braveAdapter.ts @@ -4,7 +4,7 @@ */ import axios from 'axios' -import { AbortError } from '../../../utils/errors.js' +import { AbortError } from 'src/utils/errors.js' import type { SearchResult, SearchOptions, WebSearchAdapter } from './types.js' const FETCH_TIMEOUT_MS = 30_000 diff --git a/src/tools/WebSearchTool/adapters/index.ts b/packages/builtin-tools/src/tools/WebSearchTool/adapters/index.ts similarity index 94% rename from src/tools/WebSearchTool/adapters/index.ts rename to packages/builtin-tools/src/tools/WebSearchTool/adapters/index.ts index 2a42aac42..6500e8be6 100644 --- a/src/tools/WebSearchTool/adapters/index.ts +++ b/packages/builtin-tools/src/tools/WebSearchTool/adapters/index.ts @@ -3,7 +3,7 @@ * whether the API base URL points to Anthropic's official endpoint. */ -import { isFirstPartyAnthropicBaseUrl } from '../../../utils/model/providers.js' +import { isFirstPartyAnthropicBaseUrl } from 'src/utils/model/providers.js' import { ApiSearchAdapter } from './apiAdapter.js' import { BingSearchAdapter } from './bingAdapter.js' import { BraveSearchAdapter } from './braveAdapter.js' diff --git a/src/tools/WebSearchTool/adapters/types.ts b/packages/builtin-tools/src/tools/WebSearchTool/adapters/types.ts similarity index 100% rename from src/tools/WebSearchTool/adapters/types.ts rename to packages/builtin-tools/src/tools/WebSearchTool/adapters/types.ts diff --git a/src/tools/WebSearchTool/prompt.ts b/packages/builtin-tools/src/tools/WebSearchTool/prompt.ts similarity index 100% rename from src/tools/WebSearchTool/prompt.ts rename to packages/builtin-tools/src/tools/WebSearchTool/prompt.ts diff --git a/src/tools/WebSearchTool/src/constants/common.ts b/packages/builtin-tools/src/tools/WebSearchTool/src/constants/common.ts similarity index 100% rename from src/tools/WebSearchTool/src/constants/common.ts rename to packages/builtin-tools/src/tools/WebSearchTool/src/constants/common.ts diff --git a/src/tools/WebSearchTool/src/utils/model/providers.ts b/packages/builtin-tools/src/tools/WebSearchTool/src/utils/model/providers.ts similarity index 100% rename from src/tools/WebSearchTool/src/utils/model/providers.ts rename to packages/builtin-tools/src/tools/WebSearchTool/src/utils/model/providers.ts diff --git a/src/tools/WebSearchTool/src/utils/permissions/PermissionResult.ts b/packages/builtin-tools/src/tools/WebSearchTool/src/utils/permissions/PermissionResult.ts similarity index 100% rename from src/tools/WebSearchTool/src/utils/permissions/PermissionResult.ts rename to packages/builtin-tools/src/tools/WebSearchTool/src/utils/permissions/PermissionResult.ts diff --git a/src/tools/WorkflowTool/WorkflowPermissionRequest.tsx b/packages/builtin-tools/src/tools/WorkflowTool/WorkflowPermissionRequest.tsx similarity index 88% rename from src/tools/WorkflowTool/WorkflowPermissionRequest.tsx rename to packages/builtin-tools/src/tools/WorkflowTool/WorkflowPermissionRequest.tsx index 0d3ce048a..638aec132 100644 --- a/src/tools/WorkflowTool/WorkflowPermissionRequest.tsx +++ b/packages/builtin-tools/src/tools/WorkflowTool/WorkflowPermissionRequest.tsx @@ -1,16 +1,16 @@ import React, { useCallback, useMemo } from 'react' import { Box, Text, useTheme } from '@anthropic/ink' -import { getTheme } from '../../utils/theme.js' -import { env } from '../../utils/env.js' -import { shouldShowAlwaysAllowOptions } from '../../utils/permissions/permissionsLoader.js' -import { logUnaryEvent } from '../../utils/unaryLogging.js' -import { PermissionDialog } from '../../components/permissions/PermissionDialog.js' +import { getTheme } from 'src/utils/theme.js' +import { env } from 'src/utils/env.js' +import { shouldShowAlwaysAllowOptions } from 'src/utils/permissions/permissionsLoader.js' +import { logUnaryEvent } from 'src/utils/unaryLogging.js' +import { PermissionDialog } from 'src/components/permissions/PermissionDialog.js' import { PermissionPrompt, type PermissionPromptOption, -} from '../../components/permissions/PermissionPrompt.js' -import type { PermissionRequestProps } from '../../components/permissions/PermissionRequest.js' -import { PermissionRuleExplanation } from '../../components/permissions/PermissionRuleExplanation.js' +} from 'src/components/permissions/PermissionPrompt.js' +import type { PermissionRequestProps } from 'src/components/permissions/PermissionRequest.js' +import { PermissionRuleExplanation } from 'src/components/permissions/PermissionRuleExplanation.js' type OptionValue = 'yes' | 'yes-dont-ask-again' | 'no' diff --git a/src/tools/WorkflowTool/WorkflowTool.ts b/packages/builtin-tools/src/tools/WorkflowTool/WorkflowTool.ts similarity index 93% rename from src/tools/WorkflowTool/WorkflowTool.ts rename to packages/builtin-tools/src/tools/WorkflowTool/WorkflowTool.ts index 735fc7821..4c6bfc767 100644 --- a/src/tools/WorkflowTool/WorkflowTool.ts +++ b/packages/builtin-tools/src/tools/WorkflowTool/WorkflowTool.ts @@ -1,7 +1,7 @@ import { z } from 'zod/v4' -import type { ToolResultBlockParam } from '../../Tool.js' -import { buildTool } from '../../Tool.js' -import { truncate } from '../../utils/format.js' +import type { ToolResultBlockParam } from 'src/Tool.js' +import { buildTool } from 'src/Tool.js' +import { truncate } from 'src/utils/format.js' import { WORKFLOW_TOOL_NAME } from './constants.js' const inputSchema = z.object({ diff --git a/src/tools/WorkflowTool/bundled/index.ts b/packages/builtin-tools/src/tools/WorkflowTool/bundled/index.ts similarity index 100% rename from src/tools/WorkflowTool/bundled/index.ts rename to packages/builtin-tools/src/tools/WorkflowTool/bundled/index.ts diff --git a/src/tools/WorkflowTool/constants.ts b/packages/builtin-tools/src/tools/WorkflowTool/constants.ts similarity index 100% rename from src/tools/WorkflowTool/constants.ts rename to packages/builtin-tools/src/tools/WorkflowTool/constants.ts diff --git a/src/tools/WorkflowTool/createWorkflowCommand.ts b/packages/builtin-tools/src/tools/WorkflowTool/createWorkflowCommand.ts similarity index 96% rename from src/tools/WorkflowTool/createWorkflowCommand.ts rename to packages/builtin-tools/src/tools/WorkflowTool/createWorkflowCommand.ts index a6369f565..4fbc236f9 100644 --- a/src/tools/WorkflowTool/createWorkflowCommand.ts +++ b/packages/builtin-tools/src/tools/WorkflowTool/createWorkflowCommand.ts @@ -1,6 +1,6 @@ import { readdir } from 'fs/promises' import { join, parse } from 'path' -import type { Command } from '../../types/command.js' +import type { Command } from 'src/types/command.js' import { WORKFLOW_DIR_NAME, WORKFLOW_FILE_EXTENSIONS } from './constants.js' /** diff --git a/src/tools/shared/__tests__/gitOperationTracking.test.ts b/packages/builtin-tools/src/tools/shared/__tests__/gitOperationTracking.test.ts similarity index 100% rename from src/tools/shared/__tests__/gitOperationTracking.test.ts rename to packages/builtin-tools/src/tools/shared/__tests__/gitOperationTracking.test.ts diff --git a/src/tools/shared/gitOperationTracking.ts b/packages/builtin-tools/src/tools/shared/gitOperationTracking.ts similarity index 97% rename from src/tools/shared/gitOperationTracking.ts rename to packages/builtin-tools/src/tools/shared/gitOperationTracking.ts index 970a53f89..ea6abc4e8 100644 --- a/src/tools/shared/gitOperationTracking.ts +++ b/packages/builtin-tools/src/tools/shared/gitOperationTracking.ts @@ -8,11 +8,11 @@ * external binaries with the same argv syntax). */ -import { getCommitCounter, getPrCounter } from '../../bootstrap/state.js' +import { getCommitCounter, getPrCounter } from 'src/bootstrap/state.js' import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, -} from '../../services/analytics/index.js' +} from 'src/services/analytics/index.js' /** * Build a regex that matches `git ` while tolerating git's global @@ -229,9 +229,9 @@ export function trackGitOperations( const prInfo = findPrInStdout(stdout) if (prInfo) { // Import is done dynamically to avoid circular dependency - void import('../../utils/sessionStorage.js').then( + void import('src/utils/sessionStorage.js').then( ({ linkSessionToPR }) => { - void import('../../bootstrap/state.js').then(({ getSessionId }) => { + void import('src/bootstrap/state.js').then(({ getSessionId }) => { const sessionId = getSessionId() if (sessionId) { void linkSessionToPR( diff --git a/src/tools/shared/spawnMultiAgent.ts b/packages/builtin-tools/src/tools/shared/spawnMultiAgent.ts similarity index 94% rename from src/tools/shared/spawnMultiAgent.ts rename to packages/builtin-tools/src/tools/shared/spawnMultiAgent.ts index dc7c8dd02..5eaf338f6 100644 --- a/src/tools/shared/spawnMultiAgent.ts +++ b/packages/builtin-tools/src/tools/shared/spawnMultiAgent.ts @@ -11,61 +11,61 @@ import { getMainLoopModelOverride, getSessionBypassPermissionsMode, getSessionId, -} from '../../bootstrap/state.js' -import type { AppState } from '../../state/AppState.js' -import { createTaskStateBase, generateTaskId } from '../../Task.js' -import type { ToolUseContext } from '../../Tool.js' -import type { InProcessTeammateTaskState } from '../../tasks/InProcessTeammateTask/types.js' -import { formatAgentId } from '../../utils/agentId.js' -import { quote } from '../../utils/bash/shellQuote.js' -import { isInBundledMode } from '../../utils/bundledMode.js' -import { getGlobalConfig } from '../../utils/config.js' -import { getCwd } from '../../utils/cwd.js' -import { logForDebugging } from '../../utils/debug.js' -import { errorMessage } from '../../utils/errors.js' -import { execFileNoThrow } from '../../utils/execFileNoThrow.js' -import { parseUserSpecifiedModel } from '../../utils/model/model.js' -import type { PermissionMode } from '../../utils/permissions/PermissionMode.js' -import { isTmuxAvailable } from '../../utils/swarm/backends/detection.js' +} from 'src/bootstrap/state.js' +import type { AppState } from 'src/state/AppState.js' +import { createTaskStateBase, generateTaskId } from 'src/Task.js' +import type { ToolUseContext } from 'src/Tool.js' +import type { InProcessTeammateTaskState } from 'src/tasks/InProcessTeammateTask/types.js' +import { formatAgentId } from 'src/utils/agentId.js' +import { quote } from 'src/utils/bash/shellQuote.js' +import { isInBundledMode } from 'src/utils/bundledMode.js' +import { getGlobalConfig } from 'src/utils/config.js' +import { getCwd } from 'src/utils/cwd.js' +import { logForDebugging } from 'src/utils/debug.js' +import { errorMessage } from 'src/utils/errors.js' +import { execFileNoThrow } from 'src/utils/execFileNoThrow.js' +import { parseUserSpecifiedModel } from 'src/utils/model/model.js' +import type { PermissionMode } from 'src/utils/permissions/PermissionMode.js' +import { isTmuxAvailable } from 'src/utils/swarm/backends/detection.js' import { detectAndGetBackend, getBackendByType, isInProcessEnabled, markInProcessFallback, resetBackendDetection, -} from '../../utils/swarm/backends/registry.js' -import { getTeammateModeFromSnapshot } from '../../utils/swarm/backends/teammateModeSnapshot.js' -import type { BackendType } from '../../utils/swarm/backends/types.js' -import { isPaneBackend } from '../../utils/swarm/backends/types.js' +} from 'src/utils/swarm/backends/registry.js' +import { getTeammateModeFromSnapshot } from 'src/utils/swarm/backends/teammateModeSnapshot.js' +import type { BackendType } from 'src/utils/swarm/backends/types.js' +import { isPaneBackend } from 'src/utils/swarm/backends/types.js' import { SWARM_SESSION_NAME, TEAM_LEAD_NAME, TEAMMATE_COMMAND_ENV_VAR, TMUX_COMMAND, -} from '../../utils/swarm/constants.js' -import { It2SetupPrompt } from '../../utils/swarm/It2SetupPrompt.js' -import { startInProcessTeammate } from '../../utils/swarm/inProcessRunner.js' +} from 'src/utils/swarm/constants.js' +import { It2SetupPrompt } from 'src/utils/swarm/It2SetupPrompt.js' +import { startInProcessTeammate } from 'src/utils/swarm/inProcessRunner.js' import { type InProcessSpawnConfig, spawnInProcessTeammate, -} from '../../utils/swarm/spawnInProcess.js' -import { buildInheritedEnvVars } from '../../utils/swarm/spawnUtils.js' +} from 'src/utils/swarm/spawnInProcess.js' +import { buildInheritedEnvVars } from 'src/utils/swarm/spawnUtils.js' import { readTeamFileAsync, sanitizeAgentName, sanitizeName, writeTeamFileAsync, -} from '../../utils/swarm/teamHelpers.js' +} from 'src/utils/swarm/teamHelpers.js' import { assignTeammateColor, createTeammatePaneInSwarmView, enablePaneBorderStatus, isInsideTmux, sendCommandToPane, -} from '../../utils/swarm/teammateLayoutManager.js' -import { getHardcodedTeammateModelFallback } from '../../utils/swarm/teammateModel.js' -import { registerTask } from '../../utils/task/framework.js' -import { writeToMailbox } from '../../utils/teammateMailbox.js' +} from 'src/utils/swarm/teammateLayoutManager.js' +import { getHardcodedTeammateModelFallback } from 'src/utils/swarm/teammateModel.js' +import { registerTask } from 'src/utils/task/framework.js' +import { writeToMailbox } from 'src/utils/teammateMailbox.js' import type { CustomAgentDefinition } from '../AgentTool/loadAgentsDir.js' import { isCustomAgent } from '../AgentTool/loadAgentsDir.js' diff --git a/src/tools/src/types/message.ts b/packages/builtin-tools/src/tools/src/types/message.ts similarity index 100% rename from src/tools/src/types/message.ts rename to packages/builtin-tools/src/tools/src/types/message.ts diff --git a/src/tools/testing/TestingPermissionTool.tsx b/packages/builtin-tools/src/tools/testing/TestingPermissionTool.tsx similarity index 91% rename from src/tools/testing/TestingPermissionTool.tsx rename to packages/builtin-tools/src/tools/testing/TestingPermissionTool.tsx index ffcdc330c..1e530d670 100644 --- a/src/tools/testing/TestingPermissionTool.tsx +++ b/packages/builtin-tools/src/tools/testing/TestingPermissionTool.tsx @@ -3,9 +3,9 @@ * the model. */ import { z } from 'zod/v4' -import type { Tool } from '../../Tool.js' -import { buildTool, type ToolDef } from '../../Tool.js' -import { lazySchema } from '../../utils/lazySchema.js' +import type { Tool } from 'src/Tool.js' +import { buildTool, type ToolDef } from 'src/Tool.js' +import { lazySchema } from 'src/utils/lazySchema.js' const NAME = 'TestingPermission' diff --git a/src/tools/utils.ts b/packages/builtin-tools/src/tools/utils.ts similarity index 100% rename from src/tools/utils.ts rename to packages/builtin-tools/src/tools/utils.ts diff --git a/packages/mcp-client/package.json b/packages/mcp-client/package.json new file mode 100644 index 000000000..e3a16c649 --- /dev/null +++ b/packages/mcp-client/package.json @@ -0,0 +1,16 @@ +{ + "name": "@claude-code-best/mcp-client", + "version": "1.0.0", + "private": true, + "type": "module", + "main": "./src/index.ts", + "types": "./src/index.ts", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "@claude-code-best/agent-tools": "workspace:*", + "lru-cache": "^10.0.0", + "lodash-es": "^4.17.21", + "p-map": "^4.0.0", + "zod": "^3.25.0" + } +} diff --git a/packages/mcp-client/src/__tests__/InProcessTransport.test.ts b/packages/mcp-client/src/__tests__/InProcessTransport.test.ts new file mode 100644 index 000000000..f9ee89a4e --- /dev/null +++ b/packages/mcp-client/src/__tests__/InProcessTransport.test.ts @@ -0,0 +1,80 @@ +import { describe, expect, test } from 'bun:test' +import { createLinkedTransportPair } from '../transport/InProcessTransport.js' +import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js' + +describe('InProcessTransport', () => { + test('creates linked pair', () => { + const [client, server] = createLinkedTransportPair() + expect(client).toBeDefined() + expect(server).toBeDefined() + }) + + test('delivers messages from client to server', async () => { + const [client, server] = createLinkedTransportPair() + + let received: JSONRPCMessage | null = null + server.onmessage = (msg) => { received = msg } + + const message: JSONRPCMessage = { + jsonrpc: '2.0', + method: 'test', + params: {}, + id: 1, + } + + await client.send(message) + + // Wait for queueMicrotask to deliver + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(received).not.toBeNull() + expect(received!.jsonrpc).toBe('2.0') + expect((received as any).method).toBe('test') + }) + + test('delivers messages from server to client', async () => { + const [client, server] = createLinkedTransportPair() + + let received: JSONRPCMessage | null = null + client.onmessage = (msg) => { received = msg } + + await server.send({ jsonrpc: '2.0', result: 42, id: 1 }) + + await new Promise(resolve => setTimeout(resolve, 10)) + + expect(received).not.toBeNull() + }) + + test('close triggers onclose on both sides', async () => { + const [client, server] = createLinkedTransportPair() + + let clientClosed = false + let serverClosed = false + client.onclose = () => { clientClosed = true } + server.onclose = () => { serverClosed = true } + + await client.close() + + expect(clientClosed).toBe(true) + expect(serverClosed).toBe(true) + }) + + test('close is idempotent', async () => { + const [client] = createLinkedTransportPair() + + let closeCount = 0 + client.onclose = () => { closeCount++ } + + await client.close() + await client.close() + + expect(closeCount).toBe(1) + }) + + test('send after close throws', async () => { + const [client] = createLinkedTransportPair() + await client.close() + + expect(client.send({ jsonrpc: '2.0', method: 'test' } as any)).rejects.toThrow('Transport is closed') + }) +}) diff --git a/packages/mcp-client/src/__tests__/cache.test.ts b/packages/mcp-client/src/__tests__/cache.test.ts new file mode 100644 index 000000000..b5e6fe049 --- /dev/null +++ b/packages/mcp-client/src/__tests__/cache.test.ts @@ -0,0 +1,80 @@ +import { describe, expect, test } from 'bun:test' +import { memoizeWithLRU } from '../cache.js' + +describe('memoizeWithLRU', () => { + test('caches results', () => { + let callCount = 0 + const fn = memoizeWithLRU( + (x: number) => { callCount++; return x * 2 }, + (x) => `key-${x}`, + 10, + ) + + expect(fn(5)).toBe(10) + expect(callCount).toBe(1) + expect(fn(5)).toBe(10) + expect(callCount).toBe(1) // cached, no new call + }) + + test('evicts least recently used entries', () => { + const fn = memoizeWithLRU( + (x: number) => x, + (x) => `key-${x}`, + 2, + ) + + fn(1) + fn(2) + fn(3) // should evict key-1 + + expect(fn.cache.size()).toBe(2) + expect(fn.cache.has('key-1')).toBe(false) + expect(fn.cache.has('key-2')).toBe(true) + expect(fn.cache.has('key-3')).toBe(true) + }) + + test('cache.clear removes all entries', () => { + const fn = memoizeWithLRU( + (x: number) => x, + (x) => `key-${x}`, + 10, + ) + + fn(1) + fn(2) + expect(fn.cache.size()).toBe(2) + + fn.cache.clear() + expect(fn.cache.size()).toBe(0) + }) + + test('cache.delete removes specific entry', () => { + const fn = memoizeWithLRU( + (x: number) => x, + (x) => `key-${x}`, + 10, + ) + + fn(1) + fn(2) + expect(fn.cache.delete('key-1')).toBe(true) + expect(fn.cache.has('key-1')).toBe(false) + expect(fn.cache.has('key-2')).toBe(true) + }) + + test('cache.get returns value without promoting', () => { + const fn = memoizeWithLRU( + (x: number) => x * 10, + (x) => `key-${x}`, + 2, + ) + + fn(1) + fn(2) + // key-1 is LRU, but get() should not promote it + expect(fn.cache.get('key-1')).toBe(10) + // Adding key-3 should still evict key-1 (not promoted by get) + fn(3) + expect(fn.cache.has('key-1')).toBe(false) + }) +}) diff --git a/packages/mcp-client/src/__tests__/connection.test.ts b/packages/mcp-client/src/__tests__/connection.test.ts new file mode 100644 index 000000000..7f8f78c62 --- /dev/null +++ b/packages/mcp-client/src/__tests__/connection.test.ts @@ -0,0 +1,84 @@ +import { describe, expect, test } from 'bun:test' +import { + DEFAULT_CONNECTION_TIMEOUT_MS, + MAX_MCP_DESCRIPTION_LENGTH, + MAX_ERRORS_BEFORE_RECONNECT, + isTerminalConnectionError, + isMcpSessionExpiredError, +} from '../connection.js' + +describe('connection constants', () => { + test('has reasonable defaults', () => { + expect(DEFAULT_CONNECTION_TIMEOUT_MS).toBe(30_000) + expect(MAX_MCP_DESCRIPTION_LENGTH).toBe(2048) + expect(MAX_ERRORS_BEFORE_RECONNECT).toBe(3) + }) +}) + +describe('isTerminalConnectionError', () => { + test('detects ECONNRESET', () => { + expect(isTerminalConnectionError('Connection reset: ECONNRESET')).toBe(true) + }) + + test('detects ETIMEDOUT', () => { + expect(isTerminalConnectionError('Connection timed out: ETIMEDOUT')).toBe(true) + }) + + test('detects EPIPE', () => { + expect(isTerminalConnectionError('Broken pipe: EPIPE')).toBe(true) + }) + + test('detects EHOSTUNREACH', () => { + expect(isTerminalConnectionError('Host unreachable: EHOSTUNREACH')).toBe(true) + }) + + test('detects ECONNREFUSED', () => { + expect(isTerminalConnectionError('Connection refused: ECONNREFUSED')).toBe(true) + }) + + test('detects SSE disconnection messages', () => { + expect(isTerminalConnectionError('SSE stream disconnected')).toBe(true) + expect(isTerminalConnectionError('Failed to reconnect SSE stream')).toBe(true) + }) + + test('detects terminated', () => { + expect(isTerminalConnectionError('Process terminated')).toBe(true) + }) + + test('rejects non-terminal errors', () => { + expect(isTerminalConnectionError('some random error')).toBe(false) + expect(isTerminalConnectionError('')).toBe(false) + expect(isTerminalConnectionError('timeout waiting for response')).toBe(false) + }) +}) + +describe('isMcpSessionExpiredError', () => { + test('detects 404 with JSON-RPC session-not-found code', () => { + const error = new Error('Not found: {"code":-32001,"message":"Session not found"}') + Object.assign(error, { code: 404 }) + expect(isMcpSessionExpiredError(error)).toBe(true) + }) + + test('detects 404 with spaced JSON-RPC code', () => { + const error = new Error('Not found: {"code": -32001}') + Object.assign(error, { code: 404 }) + expect(isMcpSessionExpiredError(error)).toBe(true) + }) + + test('rejects non-404 errors', () => { + const error = new Error('{"code":-32001}') + Object.assign(error, { code: 500 }) + expect(isMcpSessionExpiredError(error)).toBe(false) + }) + + test('rejects 404 without session code', () => { + const error = new Error('Not found') + Object.assign(error, { code: 404 }) + expect(isMcpSessionExpiredError(error)).toBe(false) + }) + + test('rejects errors without code property', () => { + const error = new Error('Session not found') + expect(isMcpSessionExpiredError(error)).toBe(false) + }) +}) diff --git a/packages/mcp-client/src/__tests__/discovery.test.ts b/packages/mcp-client/src/__tests__/discovery.test.ts new file mode 100644 index 000000000..a43d3472f --- /dev/null +++ b/packages/mcp-client/src/__tests__/discovery.test.ts @@ -0,0 +1,162 @@ +import { describe, expect, test, mock } from 'bun:test' +import { discoverTools, createCachedToolDiscovery } from '../discovery.js' +import type { DiscoveryOptions } from '../discovery.js' +import type { ConnectedMCPServer } from '../types.js' +import type { McpClientDependencies } from '../interfaces.js' + +function createMockDeps(): McpClientDependencies { + return { + logger: { + debug: mock(() => {}), + info: mock(() => {}), + warn: mock(() => {}), + error: mock(() => {}), + }, + httpConfig: { + getUserAgent: () => 'test-agent/1.0', + }, + } +} + +describe('discoverTools', () => { + test('returns empty array when capabilities.tools is missing', async () => { + const result = await discoverTools({ + serverName: 'test', + client: {} as any, + capabilities: {}, + deps: createMockDeps(), + }) + expect(result).toEqual([]) + }) + + test('fetches and transforms tools from server', async () => { + const mockClient = { + request: mock(() => + Promise.resolve({ + tools: [ + { + name: 'search', + description: 'Search for items', + inputSchema: { type: 'object' }, + annotations: { readOnlyHint: true, title: 'Search Items' }, + }, + ], + }), + ), + } + + const result = await discoverTools({ + serverName: 'my-server', + client: mockClient as any, + capabilities: { tools: {} }, + deps: createMockDeps(), + }) + + expect(result).toHaveLength(1) + const tool = result[0] + expect(tool.name).toBe('mcp__my-server__search') + expect(tool.mcpInfo).toEqual({ serverName: 'my-server', toolName: 'search' }) + expect(tool.isMcp).toBe(true) + expect(tool.isReadOnly()).toBe(true) + expect(tool.userFacingName()).toBe('Search Items') + expect(await tool.description()).toBe('Search for items') + }) + + test('respects skipPrefix option', async () => { + const mockClient = { + request: mock(() => + Promise.resolve({ + tools: [{ name: 'search', description: 'Search' }], + }), + ), + } + + const result = await discoverTools({ + serverName: 'my-server', + client: mockClient as any, + capabilities: { tools: {} }, + skipPrefix: true, + deps: createMockDeps(), + }) + + expect(result[0].name).toBe('search') + }) + + test('returns empty array on fetch error', async () => { + const mockClient = { + request: mock(() => Promise.reject(new Error('Connection lost'))), + } + const deps = createMockDeps() + + const result = await discoverTools({ + serverName: 'failing-server', + client: mockClient as any, + capabilities: { tools: {} }, + deps, + }) + + expect(result).toEqual([]) + expect(deps.logger.warn).toHaveBeenCalled() + }) + + test('sanitizes tool data', async () => { + const mockClient = { + request: mock(() => + Promise.resolve({ + tools: [ + { + name: 'tool\x00with\x07control', + description: 'desc', + }, + ], + }), + ), + } + + const result = await discoverTools({ + serverName: 'test', + client: mockClient as any, + capabilities: { tools: {} }, + deps: createMockDeps(), + }) + + expect(result[0].name).not.toContain('\x00') + }) +}) + +describe('createCachedToolDiscovery', () => { + test('caches results by server name', async () => { + const deps = createMockDeps() + const { discover, cache } = createCachedToolDiscovery(deps) + + const mockConn = { + type: 'connected' as const, + name: 'cached-server', + client: { + request: mock(() => + Promise.resolve({ + tools: [{ name: 'tool1', description: 'Tool 1' }], + }), + ), + }, + capabilities: { tools: {} }, + } as unknown as ConnectedMCPServer + + // First call — should fetch + const result1 = await discover(mockConn) + expect(result1).toHaveLength(1) + + // Second call — should use cache + const result2 = await discover(mockConn) + expect(result2).toHaveLength(1) + + // Request was called only once + expect(mockConn.client.request).toHaveBeenCalledTimes(1) + + // Cache delete works + cache.delete('cached-server') + const result3 = await discover(mockConn) + expect(result3).toHaveLength(1) + expect(mockConn.client.request).toHaveBeenCalledTimes(2) + }) +}) diff --git a/packages/mcp-client/src/__tests__/errors.test.ts b/packages/mcp-client/src/__tests__/errors.test.ts new file mode 100644 index 000000000..9201794a8 --- /dev/null +++ b/packages/mcp-client/src/__tests__/errors.test.ts @@ -0,0 +1,69 @@ +import { describe, expect, test } from 'bun:test' +import { + McpError, + McpConnectionError, + McpAuthError, + McpTimeoutError, + McpToolCallError, + McpSessionExpiredError, +} from '../errors.js' + +describe('McpError', () => { + test('has correct properties', () => { + const err = new McpError('test message', 'my-server', 'TEST_CODE') + expect(err.message).toBe('test message') + expect(err.serverName).toBe('my-server') + expect(err.code).toBe('TEST_CODE') + expect(err.name).toBe('McpError') + expect(err).toBeInstanceOf(Error) + }) +}) + +describe('McpConnectionError', () => { + test('inherits from McpError', () => { + const cause = new Error('ECONNREFUSED') + const err = new McpConnectionError('my-server', 'Connection failed', cause) + expect(err).toBeInstanceOf(McpError) + expect(err).toBeInstanceOf(Error) + expect(err.code).toBe('CONNECTION_FAILED') + expect(err.serverName).toBe('my-server') + expect(err.cause).toBe(cause) + }) + + test('works without cause', () => { + const err = new McpConnectionError('my-server', 'Failed') + expect(err.cause).toBeUndefined() + }) +}) + +describe('McpAuthError', () => { + test('has AUTH_REQUIRED code', () => { + const err = new McpAuthError('my-server', 'Auth needed') + expect(err.code).toBe('AUTH_REQUIRED') + expect(err).toBeInstanceOf(McpError) + }) +}) + +describe('McpTimeoutError', () => { + test('has timeout info in message', () => { + const err = new McpTimeoutError('my-server', 5000) + expect(err.code).toBe('TIMEOUT') + expect(err.timeoutMs).toBe(5000) + expect(err.message).toContain('5000') + }) +}) + +describe('McpToolCallError', () => { + test('has tool name', () => { + const err = new McpToolCallError('my-server', 'query', 'Tool failed') + expect(err.code).toBe('TOOL_CALL_FAILED') + expect(err.toolName).toBe('query') + }) +}) + +describe('McpSessionExpiredError', () => { + test('has SESSION_EXPIRED code', () => { + const err = new McpSessionExpiredError('my-server') + expect(err.code).toBe('SESSION_EXPIRED') + }) +}) diff --git a/packages/mcp-client/src/__tests__/execution.test.ts b/packages/mcp-client/src/__tests__/execution.test.ts new file mode 100644 index 000000000..c70053c89 --- /dev/null +++ b/packages/mcp-client/src/__tests__/execution.test.ts @@ -0,0 +1,144 @@ +import { describe, expect, test, mock } from 'bun:test' +import { callMcpTool } from '../execution.js' +import type { ConnectedMCPServer } from '../types.js' +import type { McpClientDependencies } from '../interfaces.js' +import { McpAuthError, McpToolCallError } from '../errors.js' + +function createMockDeps(): McpClientDependencies { + return { + logger: { + debug: mock(() => {}), + info: mock(() => {}), + warn: mock(() => {}), + error: mock(() => {}), + }, + httpConfig: { + getUserAgent: () => 'test-agent/1.0', + }, + } +} + +describe('callMcpTool', () => { + test('calls tool and returns result', async () => { + const mockResult = { + content: [{ type: 'text', text: 'result data' }], + _meta: { requestId: '123' }, + } + + const mockConn = { + name: 'test-server', + client: { + callTool: mock(() => Promise.resolve(mockResult)), + }, + type: 'connected' as const, + } as unknown as ConnectedMCPServer + + const result = await callMcpTool( + { + client: mockConn, + tool: 'search', + args: { query: 'test' }, + signal: new AbortController().signal, + }, + createMockDeps(), + ) + + expect(result.content).toBeDefined() + }) + + test('throws McpToolCallError when result has isError=true', async () => { + const mockResult = { + isError: true, + content: [{ type: 'text', text: 'Something went wrong' }], + } + + const mockConn = { + name: 'test-server', + client: { + callTool: mock(() => Promise.resolve(mockResult)), + }, + type: 'connected' as const, + } as unknown as ConnectedMCPServer + + await expect( + callMcpTool( + { + client: mockConn, + tool: 'fail-tool', + args: {}, + signal: new AbortController().signal, + }, + createMockDeps(), + ), + ).rejects.toThrow() + + try { + await callMcpTool( + { + client: mockConn, + tool: 'fail-tool', + args: {}, + signal: new AbortController().signal, + }, + createMockDeps(), + ) + } catch (e) { + expect(e).toBeInstanceOf(McpToolCallError) + expect((e as McpToolCallError).serverName).toBe('test-server') + expect((e as McpToolCallError).toolName).toBe('fail-tool') + } + }) + + test('throws McpAuthError on 401 response', async () => { + const error = new Error('Unauthorized') + Object.assign(error, { code: 401 }) + + const mockConn = { + name: 'auth-server', + client: { + callTool: mock(() => Promise.reject(error)), + }, + type: 'connected' as const, + } as unknown as ConnectedMCPServer + + await expect( + callMcpTool( + { + client: mockConn, + tool: 'protected-tool', + args: {}, + signal: new AbortController().signal, + }, + createMockDeps(), + ), + ).rejects.toThrow(McpAuthError) + }) + + test('passes metadata to the client', async () => { + const mockResult = { content: [{ type: 'text', text: 'ok' }] } + const callToolMock = mock(() => Promise.resolve(mockResult)) + + const mockConn = { + name: 'test-server', + client: { + callTool: callToolMock, + }, + type: 'connected' as const, + } as unknown as ConnectedMCPServer + + await callMcpTool( + { + client: mockConn, + tool: 'my-tool', + args: { key: 'value' }, + meta: { 'custom-key': 'custom-value' }, + signal: new AbortController().signal, + }, + createMockDeps(), + ) + + expect(callToolMock).toHaveBeenCalled() + const callArgs = callToolMock.mock.calls[0] as any[] + expect(callArgs[0]._meta).toEqual({ 'custom-key': 'custom-value' }) + }) +}) diff --git a/packages/mcp-client/src/__tests__/manager.test.ts b/packages/mcp-client/src/__tests__/manager.test.ts new file mode 100644 index 000000000..f067ffa2e --- /dev/null +++ b/packages/mcp-client/src/__tests__/manager.test.ts @@ -0,0 +1,113 @@ +import { describe, expect, test, mock } from 'bun:test' +import { createMcpManager } from '../manager.js' +import type { McpManager } from '../manager.js' +import type { McpClientDependencies } from '../interfaces.js' +import type { ScopedMcpServerConfig, MCPServerConnection, ConnectedMCPServer } from '../types.js' +import type { Client } from '@modelcontextprotocol/sdk/client/index.js' + +function createMockDeps(): McpClientDependencies { + return { + logger: { + debug: mock(() => {}), + info: mock(() => {}), + warn: mock(() => {}), + error: mock(() => {}), + }, + httpConfig: { + getUserAgent: () => 'test-agent/1.0', + getSessionId: () => 'test-session', + }, + } +} + +describe('createMcpManager', () => { + test('creates a manager instance', () => { + const manager = createMcpManager(createMockDeps()) + expect(manager).toBeDefined() + expect(manager.getConnections).toBeTypeOf('function') + expect(manager.connect).toBeTypeOf('function') + expect(manager.disconnect).toBeTypeOf('function') + expect(manager.getTools).toBeTypeOf('function') + expect(manager.getAllTools).toBeTypeOf('function') + expect(manager.callTool).toBeTypeOf('function') + expect(manager.on).toBeTypeOf('function') + expect(manager.off).toBeTypeOf('function') + }) + + test('connect throws if connectFn not set', async () => { + const manager = createMcpManager(createMockDeps()) + await expect(manager.connect('test', { command: 'npx', args: [] })) + .rejects.toThrow('connectFn not set') + }) + + test('connect calls connectFn and emits connected event', async () => { + const manager = createMcpManager(createMockDeps()) as any + let connectedEvent: string | null = null + manager.on('connected', (name: string) => { connectedEvent = name }) + + const mockConnection: ConnectedMCPServer = { + type: 'connected', + name: 'test-server', + client: { + request: mock(() => Promise.resolve({ tools: [] })), + onclose: null, + } as unknown as Client, + capabilities: {}, + config: { command: 'npx', args: [], scope: 'dynamic' } as ScopedMcpServerConfig, + cleanup: mock(() => Promise.resolve()), + } + + manager.setConnectFn(async (name: string, config: ScopedMcpServerConfig) => { + expect(name).toBe('test-server') + expect(config.scope).toBe('dynamic') + return mockConnection + }) + + const result = await manager.connect('test-server', { command: 'npx', args: [] }) + expect(result.type).toBe('connected') + expect(connectedEvent).toBe('test-server') + }) + + test('disconnect calls cleanup and emits disconnected', async () => { + const manager = createMcpManager(createMockDeps()) as any + let disconnected = false + manager.on('disconnected', () => { disconnected = true }) + + const mockCleanup = mock(() => Promise.resolve()) + const mockConnection: ConnectedMCPServer = { + type: 'connected', + name: 'test-server', + client: { request: mock(() => Promise.resolve({ tools: [] })) } as unknown as Client, + capabilities: {}, + config: { command: 'npx', args: [], scope: 'dynamic' } as ScopedMcpServerConfig, + cleanup: mockCleanup, + } + + manager.setConnectFn(async () => mockConnection) + await manager.connect('test-server', { command: 'npx', args: [] }) + + await manager.disconnect('test-server') + expect(mockCleanup).toHaveBeenCalled() + expect(disconnected).toBe(true) + expect(manager.getConnections().size).toBe(0) + }) + + test('on/off event handling', () => { + const manager = createMcpManager(createMockDeps()) as any + const handler = mock(() => {}) + manager.on('error', handler) + manager.off('error', handler) + // No crash — just verifying it works + expect(true).toBe(true) + }) + + test('getTools returns empty array for unknown server', () => { + const manager = createMcpManager(createMockDeps()) + expect(manager.getTools('unknown')).toEqual([]) + }) + + test('getAllTools returns empty array initially', () => { + const manager = createMcpManager(createMockDeps()) + expect(manager.getAllTools()).toEqual([]) + }) +}) diff --git a/packages/mcp-client/src/__tests__/sanitization.test.ts b/packages/mcp-client/src/__tests__/sanitization.test.ts new file mode 100644 index 000000000..b254a638f --- /dev/null +++ b/packages/mcp-client/src/__tests__/sanitization.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, test } from 'bun:test' +import { recursivelySanitizeUnicode } from '../sanitization.js' + +describe('recursivelySanitizeUnicode', () => { + test('passes through clean strings', () => { + expect(recursivelySanitizeUnicode('hello world')).toBe('hello world') + expect(recursivelySanitizeUnicode('')).toBe('') + }) + + test('removes control characters', () => { + expect(recursivelySanitizeUnicode('hello\x00world')).toBe('helloworld') + expect(recursivelySanitizeUnicode('test\x07bell')).toBe('testbell') + }) + + test('preserves allowed whitespace', () => { + expect(recursivelySanitizeUnicode('hello\tworld')).toBe('hello\tworld') + expect(recursivelySanitizeUnicode('hello\nworld')).toBe('hello\nworld') + expect(recursivelySanitizeUnicode('hello\rworld')).toBe('hello\rworld') + }) + + test('removes replacement character', () => { + expect(recursivelySanitizeUnicode('hello\uFFFDworld')).toBe('helloworld') + }) + + test('normalizes to NFC', () => { + // é can be composed (U+00E9) or decomposed (U+0065 + U+0301) + const decomposed = 'e\u0301' + const result = recursivelySanitizeUnicode(decomposed) + expect(result).toBe('é') + }) + + test('sanitizes arrays recursively', () => { + const input = ['hello\x00world', 'clean'] + expect(recursivelySanitizeUnicode(input)).toEqual(['helloworld', 'clean']) + }) + + test('sanitizes objects recursively', () => { + const input = { name: 'test\x07', nested: { value: 'a\x00b' } } + expect(recursivelySanitizeUnicode(input)).toEqual({ + name: 'test', + nested: { value: 'ab' }, + }) + }) + + test('handles null and non-string primitives', () => { + expect(recursivelySanitizeUnicode(null)).toBe(null) + expect(recursivelySanitizeUnicode(42)).toBe(42) + expect(recursivelySanitizeUnicode(true)).toBe(true) + expect(recursivelySanitizeUnicode(undefined)).toBe(undefined) + }) +}) diff --git a/packages/mcp-client/src/__tests__/strings.test.ts b/packages/mcp-client/src/__tests__/strings.test.ts new file mode 100644 index 000000000..9a8e031e8 --- /dev/null +++ b/packages/mcp-client/src/__tests__/strings.test.ts @@ -0,0 +1,101 @@ +import { describe, expect, test } from 'bun:test' +import { + buildMcpToolName, + normalizeNameForMCP, + mcpInfoFromString, + getMcpPrefix, + getToolNameForPermissionCheck, + getMcpDisplayName, + extractMcpToolDisplayName, +} from '../strings.js' + +describe('normalizeNameForMCP', () => { + test('keeps valid names unchanged', () => { + expect(normalizeNameForMCP('my-server')).toBe('my-server') + expect(normalizeNameForMCP('my_server')).toBe('my_server') + expect(normalizeNameForMCP('server123')).toBe('server123') + }) + + test('replaces dots and spaces with underscores', () => { + expect(normalizeNameForMCP('test.server')).toBe('test_server') + expect(normalizeNameForMCP('test server')).toBe('test_server') + }) + + test('collapses underscores for claude.ai prefix', () => { + expect(normalizeNameForMCP('claude.ai Slack')).toBe('claude_ai_Slack') + expect(normalizeNameForMCP('claude.ai My Server')).toBe('claude_ai_My_Server') + }) +}) + +describe('buildMcpToolName', () => { + test('builds fully qualified name', () => { + expect(buildMcpToolName('my-server', 'query')).toBe('mcp__my-server__query') + }) + + test('normalizes server name with dots', () => { + expect(buildMcpToolName('test.server', 'tool')).toBe('mcp__test_server__tool') + }) +}) + +describe('mcpInfoFromString', () => { + test('parses valid MCP tool name', () => { + const info = mcpInfoFromString('mcp__my-server__query') + expect(info).toEqual({ serverName: 'my-server', toolName: 'query' }) + }) + + test('returns null for non-MCP names', () => { + expect(mcpInfoFromString('bash')).toBeNull() + expect(mcpInfoFromString('mcp__')).toBeNull() + expect(mcpInfoFromString('')).toBeNull() + }) + + test('handles tool names with double underscores', () => { + const info = mcpInfoFromString('mcp__server__tool__part') + expect(info).toEqual({ serverName: 'server', toolName: 'tool__part' }) + }) + + test('handles server-only (no tool name)', () => { + const info = mcpInfoFromString('mcp__server') + expect(info).toEqual({ serverName: 'server', toolName: undefined }) + }) +}) + +describe('getMcpPrefix', () => { + test('returns correct prefix', () => { + expect(getMcpPrefix('my-server')).toBe('mcp__my-server__') + }) +}) + +describe('getToolNameForPermissionCheck', () => { + test('uses mcp prefix for MCP tools', () => { + expect(getToolNameForPermissionCheck({ + name: 'query', + mcpInfo: { serverName: 'my-server', toolName: 'query' }, + })).toBe('mcp__my-server__query') + }) + + test('uses raw name for non-MCP tools', () => { + expect(getToolNameForPermissionCheck({ name: 'bash' })).toBe('bash') + }) +}) + +describe('getMcpDisplayName', () => { + test('strips MCP prefix', () => { + // getMcpDisplayName normalizes server name before building prefix + expect(getMcpDisplayName('mcp__my_server__query', 'my.server')).toBe('query') + }) +}) + +describe('extractMcpToolDisplayName', () => { + test('removes MCP suffix', () => { + expect(extractMcpToolDisplayName('github - Add comment (MCP)')).toBe('Add comment') + }) + + test('handles no dash', () => { + expect(extractMcpToolDisplayName('Add comment (MCP)')).toBe('Add comment') + }) + + test('handles no suffix', () => { + expect(extractMcpToolDisplayName('github - Add comment')).toBe('Add comment') + }) +}) diff --git a/packages/mcp-client/src/cache.ts b/packages/mcp-client/src/cache.ts new file mode 100644 index 000000000..b434cb506 --- /dev/null +++ b/packages/mcp-client/src/cache.ts @@ -0,0 +1,58 @@ +// LRU memoization cache for MCP tool discovery +// Adapted from src/utils/memoize.ts — only memoizeWithLRU needed + +import { LRUCache } from 'lru-cache' + +type LRUMemoizedFunction = { + (...args: Args): Result + cache: { + clear: () => void + size: () => number + delete: (key: string) => boolean + get: (key: string) => Result | undefined + has: (key: string) => boolean + } +} + +/** + * Creates a memoized function with LRU eviction policy. + * Prevents unbounded memory growth by evicting least recently used entries. + * + * @param f The function to memoize + * @param cacheFn Key generation function + * @param maxCacheSize Maximum cache entries (default 100) + */ +export function memoizeWithLRU< + Args extends unknown[], + Result extends NonNullable, +>( + f: (...args: Args) => Result, + cacheFn: (...args: Args) => string, + maxCacheSize: number = 100, +): LRUMemoizedFunction { + const cache = new LRUCache({ + max: maxCacheSize, + }) + + const memoized = (...args: Args): Result => { + const key = cacheFn(...args) + const cached = cache.get(key) + if (cached !== undefined) { + return cached + } + + const result = f(...args) + cache.set(key, result) + return result + } + + memoized.cache = { + clear: () => cache.clear(), + size: () => cache.size, + delete: (key: string) => cache.delete(key), + get: (key: string) => cache.peek(key), + has: (key: string) => cache.has(key), + } + + return memoized +} diff --git a/packages/mcp-client/src/connection.ts b/packages/mcp-client/src/connection.ts new file mode 100644 index 000000000..30f3b18d6 --- /dev/null +++ b/packages/mcp-client/src/connection.ts @@ -0,0 +1,519 @@ +// MCP connection utilities — protocol-level helpers for establishing and managing connections +// These are building blocks used by the host's connectToServer implementation. + +import { Client } from '@modelcontextprotocol/sdk/client/index.js' +import { ListRootsRequestSchema } from '@modelcontextprotocol/sdk/types.js' +import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js' +import type { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js' +import type { McpClientDependencies } from './interfaces.js' +import type { ConnectedMCPServer, ScopedMcpServerConfig } from './types.js' + +// ============================================================================ +// Constants +// ============================================================================ + +/** Default connection timeout in milliseconds */ +export const DEFAULT_CONNECTION_TIMEOUT_MS = 30_000 + +/** Maximum length for MCP descriptions/instructions */ +export const MAX_MCP_DESCRIPTION_LENGTH = 2048 + +/** Maximum consecutive terminal errors before triggering reconnection */ +export const MAX_ERRORS_BEFORE_RECONNECT = 3 + +// ============================================================================ +// Client creation +// ============================================================================ + +export interface CreateClientOptions { + /** Client name (e.g., "claude-code") */ + name: string + /** Client title */ + title?: string + /** Client version */ + version: string + /** Client description */ + description?: string + /** Client website URL */ + websiteUrl?: string + /** Root URI for ListRoots requests (defaults to current working directory) */ + rootUri?: string +} + +/** + * Creates a configured MCP Client instance with standard capabilities and handlers. + * The host can further customize the client before connecting. + */ +export function createMcpClient(options: CreateClientOptions): Client { + const client = new Client( + { + name: options.name, + title: options.title ?? options.name, + version: options.version, + description: options.description, + websiteUrl: options.websiteUrl, + }, + { + capabilities: { + roots: {}, + elicitation: {}, + }, + }, + ) + + // Register default ListRoots handler + client.setRequestHandler(ListRootsRequestSchema, async () => ({ + roots: [ + { + uri: options.rootUri ?? `file://${process.cwd()}`, + }, + ], + })) + + return client +} + +// ============================================================================ +// Connection timeout +// ============================================================================ + +/** + * Wraps a connection promise with a timeout. + * Returns the result of connectPromise or rejects with a timeout error. + */ +export async function withConnectionTimeout( + connectPromise: Promise, + timeoutMs: number, + onTimeout: () => Promise | void, +): Promise { + const startTime = Date.now() + + const timeoutPromise = new Promise((_, reject) => { + const timeoutId = setTimeout(async () => { + await onTimeout() + reject( + new Error( + `MCP connection timed out after ${timeoutMs}ms`, + ), + ) + }, timeoutMs) + + // Clean up timeout if connect resolves or rejects + connectPromise.then( + () => clearTimeout(timeoutId), + () => clearTimeout(timeoutId), + ) + }) + + return Promise.race([connectPromise, timeoutPromise]) +} + +// ============================================================================ +// Stderr capture +// ============================================================================ + +/** + * Sets up stderr capture for stdio transports. + * Returns the stderr output accumulator and cleanup function. + */ +export function captureStderr( + transport: StdioClientTransport, + maxSize = 64 * 1024 * 1024, +): { getOutput: () => string; clearOutput: () => void; removeHandler: () => void } { + let stderrOutput = '' + + const handler = (data: Buffer) => { + if (stderrOutput.length < maxSize) { + try { + stderrOutput += data.toString() + } catch { + // Ignore errors from exceeding max string length + } + } + } + + transport.stderr?.on('data', handler) + + return { + getOutput: () => stderrOutput, + clearOutput: () => { stderrOutput = '' }, + removeHandler: () => { transport.stderr?.off('data', handler) }, + } +} + +// ============================================================================ +// Error/close handlers +// ============================================================================ + +/** + * Terminal connection error patterns that indicate the connection is broken. + */ +export function isTerminalConnectionError(msg: string): boolean { + return ( + msg.includes('ECONNRESET') || + msg.includes('ETIMEDOUT') || + msg.includes('EPIPE') || + msg.includes('EHOSTUNREACH') || + msg.includes('ECONNREFUSED') || + msg.includes('Body Timeout Error') || + msg.includes('terminated') || + msg.includes('SSE stream disconnected') || + msg.includes('Failed to reconnect SSE stream') + ) +} + +/** + * Detects MCP "Session not found" errors (HTTP 404 + JSON-RPC code -32001). + */ +export function isMcpSessionExpiredError(error: Error): boolean { + const httpStatus = + 'code' in error ? (error as Error & { code?: number }).code : undefined + if (httpStatus !== 404) { + return false + } + return ( + error.message.includes('"code":-32001') || + error.message.includes('"code": -32001') + ) +} + +export interface ConnectionMonitorOptions { + serverName: string + transportType: string + logger: McpClientDependencies['logger'] + /** Called when the transport should be closed to trigger reconnection */ + closeTransport: () => void + /** Called to clear connection caches on close */ + onConnectionClosed?: () => void +} + +/** + * Installs enhanced error and close handlers on an MCP Client for + * connection drop detection and automatic reconnection. + * + * Returns the cleanup function to remove handlers. + */ +export function installConnectionMonitor( + client: Client, + options: ConnectionMonitorOptions, +): () => void { + const { serverName, transportType, logger, closeTransport, onConnectionClosed } = options + const connectionStartTime = Date.now() + let hasErrorOccurred = false + let consecutiveConnectionErrors = 0 + let hasTriggeredClose = false + + const originalOnerror = client.onerror + const originalOnclose = client.onclose + + const safeClose = (reason: string) => { + if (hasTriggeredClose) return + hasTriggeredClose = true + logger.debug(`[${serverName}] Closing transport (${reason})`) + void client.close().catch(e => { + logger.debug(`[${serverName}] Error during close: ${e}`) + }) + } + + // Error handler + client.onerror = (error: Error) => { + const uptime = Date.now() - connectionStartTime + hasErrorOccurred = true + + logger.debug( + `[${serverName}] ${transportType.toUpperCase()} connection dropped after ${Math.floor(uptime / 1000)}s uptime`, + ) + + // Session expiry for HTTP transports + if ( + (transportType === 'http' || transportType === 'claudeai-proxy') && + isMcpSessionExpiredError(error) + ) { + logger.debug( + `[${serverName}] MCP session expired, triggering reconnection`, + ) + safeClose('session expired') + originalOnerror?.(error) + return + } + + // Terminal error tracking for remote transports + if ( + transportType === 'sse' || + transportType === 'http' || + transportType === 'claudeai-proxy' + ) { + if (error.message.includes('Maximum reconnection attempts')) { + safeClose('SSE reconnection exhausted') + originalOnerror?.(error) + return + } + + if (isTerminalConnectionError(error.message)) { + consecutiveConnectionErrors++ + logger.debug( + `[${serverName}] Terminal connection error ${consecutiveConnectionErrors}/${MAX_ERRORS_BEFORE_RECONNECT}`, + ) + + if (consecutiveConnectionErrors >= MAX_ERRORS_BEFORE_RECONNECT) { + consecutiveConnectionErrors = 0 + safeClose('max consecutive terminal errors') + } + } else { + consecutiveConnectionErrors = 0 + } + } + + originalOnerror?.(error) + } + + // Close handler + client.onclose = () => { + const uptime = Date.now() - connectionStartTime + logger.debug( + `[${serverName}] ${transportType.toUpperCase()} connection closed after ${Math.floor(uptime / 1000)}s (${hasErrorOccurred ? 'with errors' : 'cleanly'})`, + ) + + onConnectionClosed?.() + originalOnclose?.() + } + + // Return cleanup function + return () => { + client.onerror = originalOnerror + client.onclose = originalOnclose + } +} + +// ============================================================================ +// Signal escalation for stdio cleanup +// ============================================================================ + +/** + * Terminates a stdio child process with escalating signals: + * SIGINT (100ms) → SIGTERM (400ms) → SIGKILL + * + * Total maximum cleanup time: ~500ms + */ +export async function terminateWithSignalEscalation( + childPid: number, + logger: McpClientDependencies['logger'], + serverName: string, +): Promise { + try { + logger.debug(`[${serverName}] Sending SIGINT to MCP server process`) + + try { + process.kill(childPid, 'SIGINT') + } catch (error) { + logger.debug(`[${serverName}] Error sending SIGINT: ${error}`) + return + } + + await new Promise(async resolve => { + let resolved = false + + const checkInterval = setInterval(() => { + try { + process.kill(childPid, 0) + } catch { + if (!resolved) { + resolved = true + clearInterval(checkInterval) + clearTimeout(failsafeTimeout) + logger.debug(`[${serverName}] MCP server process exited cleanly`) + resolve() + } + } + }, 50) + + const failsafeTimeout = setTimeout(() => { + if (!resolved) { + resolved = true + clearInterval(checkInterval) + logger.debug(`[${serverName}] Cleanup timeout reached, stopping process monitoring`) + resolve() + } + }, 600) + + try { + // Wait 100ms for SIGINT to work + await sleep(100) + + if (!resolved) { + try { + process.kill(childPid, 0) + // Process still exists, try SIGTERM + logger.debug(`[${serverName}] SIGINT failed, sending SIGTERM`) + try { + process.kill(childPid, 'SIGTERM') + } catch (termError) { + logger.debug(`[${serverName}] Error sending SIGTERM: ${termError}`) + resolved = true + clearInterval(checkInterval) + clearTimeout(failsafeTimeout) + resolve() + return + } + } catch { + resolved = true + clearInterval(checkInterval) + clearTimeout(failsafeTimeout) + resolve() + return + } + + // Wait 400ms for SIGTERM + await sleep(400) + + if (!resolved) { + try { + process.kill(childPid, 0) + logger.debug(`[${serverName}] SIGTERM failed, sending SIGKILL`) + try { + process.kill(childPid, 'SIGKILL') + } catch (killError) { + logger.debug(`[${serverName}] Error sending SIGKILL: ${killError}`) + } + } catch { + resolved = true + clearInterval(checkInterval) + clearTimeout(failsafeTimeout) + resolve() + } + } + } + + if (!resolved) { + resolved = true + clearInterval(checkInterval) + clearTimeout(failsafeTimeout) + resolve() + } + } catch { + if (!resolved) { + resolved = true + clearInterval(checkInterval) + clearTimeout(failsafeTimeout) + resolve() + } + } + }) + } catch (processError) { + logger.debug(`[${serverName}] Error terminating process: ${processError}`) + } +} + +/** Simple sleep utility (avoids importing from host) */ +function sleep(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +// ============================================================================ +// Cleanup factory +// ============================================================================ + +export interface CleanupOptions { + client: Client + transport: Transport + transportType: string + childPid?: number + inProcessServer?: { close(): Promise } + stderrCleanup?: { removeHandler: () => void } + logger: McpClientDependencies['logger'] + serverName: string +} + +/** + * Creates a cleanup function for an MCP connection. + * Handles in-process servers, stderr listener removal, signal escalation, and client close. + */ +export function createCleanup(options: CleanupOptions): () => Promise { + const { + client, + transport, + transportType, + childPid, + inProcessServer, + stderrCleanup, + logger, + serverName, + } = options + + return async () => { + // In-process servers + if (inProcessServer) { + try { + await inProcessServer.close() + } catch (error) { + logger.debug(`[${serverName}] Error closing in-process server: ${error}`) + } + try { + await client.close() + } catch (error) { + logger.debug(`[${serverName}] Error closing client: ${error}`) + } + return + } + + // Remove stderr listener + stderrCleanup?.removeHandler() + + // Signal escalation for stdio + if (transportType === 'stdio' && childPid) { + await terminateWithSignalEscalation(childPid, logger, serverName) + } + + // Close the client connection (which also closes the transport) + try { + await client.close() + } catch (error) { + logger.debug(`[${serverName}] Error closing client: ${error}`) + } + } +} + +// ============================================================================ +// Connected server result builder +// ============================================================================ + +export interface BuildConnectedServerOptions { + name: string + client: Client + config: ScopedMcpServerConfig + cleanup: () => Promise +} + +/** + * Builds a ConnectedMCPServer result from a connected client. + * Truncates server instructions if they exceed MAX_MCP_DESCRIPTION_LENGTH. + */ +export function buildConnectedServer( + options: BuildConnectedServerOptions, + logger: McpClientDependencies['logger'], +): ConnectedMCPServer { + const { name, client, config, cleanup } = options + + const capabilities = client.getServerCapabilities() ?? {} + const serverVersion = client.getServerVersion() + const rawInstructions = client.getInstructions() + + let instructions = rawInstructions + if (rawInstructions && rawInstructions.length > MAX_MCP_DESCRIPTION_LENGTH) { + instructions = rawInstructions.slice(0, MAX_MCP_DESCRIPTION_LENGTH) + '… [truncated]' + logger.debug( + `[${name}] Server instructions truncated from ${rawInstructions.length} to ${MAX_MCP_DESCRIPTION_LENGTH} chars`, + ) + } + + return { + name, + client, + type: 'connected' as const, + capabilities, + serverInfo: serverVersion, + instructions, + config, + cleanup, + } +} diff --git a/packages/mcp-client/src/discovery.ts b/packages/mcp-client/src/discovery.ts new file mode 100644 index 000000000..aaec7fc28 --- /dev/null +++ b/packages/mcp-client/src/discovery.ts @@ -0,0 +1,143 @@ +// MCP tool discovery — fetch and process tools from connected MCP servers +// Extracted from src/services/mcp/client.ts (fetchToolsForClient) + +import type { Client } from '@modelcontextprotocol/sdk/client/index.js' +import { + ListToolsResultSchema, + type ListToolsResult, +} from '@modelcontextprotocol/sdk/types.js' +import type { CoreTool } from '@claude-code-best/agent-tools' +import type { ConnectedMCPServer } from './types.js' +import type { McpClientDependencies } from './interfaces.js' +import { buildMcpToolName } from './strings.js' +import { memoizeWithLRU } from './cache.js' +import { recursivelySanitizeUnicode } from './sanitization.js' + +// ============================================================================ +// Constants +// ============================================================================ + +/** Default max cache size for tool discovery (keyed by server name) */ +export const MCP_FETCH_CACHE_SIZE = 20 + +/** Maximum description length before truncation */ +const MAX_MCP_DESCRIPTION_LENGTH = 2048 + +// ============================================================================ +// Tool discovery +// ============================================================================ + +export interface DiscoveryOptions { + /** Server name for logging and tool naming */ + serverName: string + /** Connected MCP server client */ + client: Client + /** Server capabilities (checked before fetching) */ + capabilities: Record + /** Whether to skip the mcp__ prefix for tool names */ + skipPrefix?: boolean + /** Host dependencies for logging */ + deps: McpClientDependencies +} + +/** + * Fetches tools from a connected MCP server and converts them to CoreTool format. + * Returns empty array if the server doesn't support tools or if fetching fails. + */ +export async function discoverTools(options: DiscoveryOptions): Promise { + const { serverName, client, capabilities, skipPrefix, deps } = options + + if (!capabilities?.tools) { + return [] + } + + try { + const result = (await client.request( + { method: 'tools/list' }, + ListToolsResultSchema, + )) as ListToolsResult + + // Sanitize tool data from MCP server + const toolsToProcess = recursivelySanitizeUnicode(result.tools) + + return toolsToProcess.map((tool): CoreTool => { + const fullyQualifiedName = buildMcpToolName(serverName, tool.name) + const effectiveName = skipPrefix ? tool.name : fullyQualifiedName + + return { + name: effectiveName, + mcpInfo: { serverName, toolName: tool.name }, + isMcp: true, + inputJSONSchema: tool.inputSchema as CoreTool['inputJSONSchema'], + async description() { + return tool.description ?? '' + }, + async prompt() { + const desc = tool.description ?? '' + return desc.length > MAX_MCP_DESCRIPTION_LENGTH + ? desc.slice(0, MAX_MCP_DESCRIPTION_LENGTH) + '… [truncated]' + : desc + }, + isConcurrencySafe: () => tool.annotations?.readOnlyHint ?? false, + isReadOnly: () => tool.annotations?.readOnlyHint ?? false, + isDestructive: () => tool.annotations?.destructiveHint ?? false, + isOpenWorld: () => tool.annotations?.openWorldHint ?? false, + isEnabled: () => true, + async checkPermissions() { + return { behavior: 'passthrough' as const } + }, + toAutoClassifierInput: () => '', + userFacingName: () => tool.annotations?.title ?? tool.name, + maxResultSizeChars: 100_000, + mapToolResultToToolResultBlockParam: (content: unknown, id: string) => ({ + type: 'tool_result' as const, + tool_use_id: id, + content, + }), + async call() { + throw new Error('Use manager.callTool() instead') + }, + inputSchema: {} as CoreTool['inputSchema'], + } satisfies CoreTool + }) + } catch (error) { + deps.logger.warn(`Failed to fetch tools for ${serverName}:`, error) + return [] + } +} + +// ============================================================================ +// Cached tool discovery (LRU by server name) +// ============================================================================ + +/** + * Creates a memoized tool discovery function with LRU caching. + * Cache is keyed by server name (stable across reconnects). + */ +export function createCachedToolDiscovery( + deps: McpClientDependencies, + cacheSize: number = MCP_FETCH_CACHE_SIZE, +): { + discover: (server: ConnectedMCPServer, skipPrefix?: boolean) => Promise + cache: { delete(key: string): void; clear(): void } +} { + const discover = memoizeWithLRU( + async (server: ConnectedMCPServer, skipPrefix?: boolean): Promise => { + if (server.type !== 'connected') return [] + return discoverTools({ + serverName: server.name, + client: server.client, + capabilities: server.capabilities ?? {}, + skipPrefix, + deps, + }) + }, + (server: ConnectedMCPServer) => server.name, + cacheSize, + ) + + return { + discover, + cache: discover.cache, + } +} diff --git a/packages/mcp-client/src/errors.ts b/packages/mcp-client/src/errors.ts new file mode 100644 index 000000000..f917c8cd6 --- /dev/null +++ b/packages/mcp-client/src/errors.ts @@ -0,0 +1,80 @@ +// MCP typed error hierarchy + +/** + * Base error class for all MCP-related errors. + */ +export class McpError extends Error { + constructor( + message: string, + public readonly serverName: string, + public readonly code: string, + ) { + super(message) + this.name = 'McpError' + } +} + +/** + * Error thrown when connection to an MCP server fails. + */ +export class McpConnectionError extends McpError { + constructor( + serverName: string, + message: string, + public readonly cause?: Error, + ) { + super(message, serverName, 'CONNECTION_FAILED') + this.name = 'McpConnectionError' + } +} + +/** + * Error thrown when authentication is required but not available. + */ +export class McpAuthError extends McpError { + constructor(serverName: string, message: string) { + super(message, serverName, 'AUTH_REQUIRED') + this.name = 'McpAuthError' + } +} + +/** + * Error thrown when a connection or request times out. + */ +export class McpTimeoutError extends McpError { + constructor( + serverName: string, + public readonly timeoutMs: number, + ) { + super( + `Connection to ${serverName} timed out after ${timeoutMs}ms`, + serverName, + 'TIMEOUT', + ) + this.name = 'McpTimeoutError' + } +} + +/** + * Error thrown when an MCP tool call fails. + */ +export class McpToolCallError extends McpError { + constructor( + serverName: string, + public readonly toolName: string, + message: string, + ) { + super(message, serverName, 'TOOL_CALL_FAILED') + this.name = 'McpToolCallError' + } +} + +/** + * Error thrown when an MCP session has expired. + */ +export class McpSessionExpiredError extends McpError { + constructor(serverName: string) { + super(`Session expired for ${serverName}`, serverName, 'SESSION_EXPIRED') + this.name = 'McpSessionExpiredError' + } +} diff --git a/packages/mcp-client/src/execution.ts b/packages/mcp-client/src/execution.ts new file mode 100644 index 000000000..381818840 --- /dev/null +++ b/packages/mcp-client/src/execution.ts @@ -0,0 +1,182 @@ +// MCP tool execution — call tools on connected MCP servers +// Extracted from src/services/mcp/client.ts (callMCPTool) + +import { + CallToolResultSchema, +} from '@modelcontextprotocol/sdk/types.js' +import type { ConnectedMCPServer } from './types.js' +import type { McpClientDependencies } from './interfaces.js' +import { + McpToolCallError, + McpAuthError, +} from './errors.js' + +// ============================================================================ +// Constants +// ============================================================================ + +/** Default timeout for MCP tool calls (~27.8 hours — effectively infinite) */ +const DEFAULT_MCP_TOOL_TIMEOUT_MS = 100_000_000 + +// ============================================================================ +// Tool execution +// ============================================================================ + +export interface CallToolOptions { + /** The connected MCP server to call */ + client: ConnectedMCPServer + /** Tool name (as registered on the server, not the fully qualified name) */ + tool: string + /** Tool arguments */ + args: Record + /** Optional metadata to send with the call */ + meta?: Record + /** Abort signal for cancellation */ + signal: AbortSignal + /** Progress callback */ + onProgress?: (data: { progress?: number; total?: number; message?: string }) => void + /** Tool call timeout in ms (defaults to ~27.8 hours) */ + timeoutMs?: number +} + +export interface CallToolResult { + content: unknown + _meta?: Record + structuredContent?: Record + isError?: boolean +} + +/** + * Call a tool on a connected MCP server with timeout and progress handling. + * + * This is the protocol-level tool execution function. The host is responsible for: + * - Session management (reconnection on expiry) + * - Result transformation (content processing, truncation, persistence) + * - Error wrapping for telemetry + */ +export async function callMcpTool( + options: CallToolOptions, + deps: McpClientDependencies, +): Promise { + const { client, tool, args, meta, signal, onProgress, timeoutMs } = options + const { name: serverName, client: mcpClient } = client + const effectiveTimeout = timeoutMs ?? getMcpToolTimeoutMs() + + let progressInterval: ReturnType | undefined + + try { + deps.logger.debug(`[${serverName}] Calling MCP tool: ${tool}`) + + // Progress logging for long-running tools (every 30 seconds) + progressInterval = setInterval( + () => { + deps.logger.debug(`[${serverName}] Tool '${tool}' still running`) + }, + 30_000, + ) + + const result = await Promise.race([ + mcpClient.callTool( + { + name: tool, + arguments: args, + _meta: meta, + }, + CallToolResultSchema, + { + signal, + timeout: effectiveTimeout, + onprogress: onProgress, + }, + ), + createTimeoutPromise(serverName, tool, effectiveTimeout), + ]) + + // Handle isError in result + if ('isError' in result && result.isError) { + let errorDetails = 'Unknown error' + if ( + 'content' in result && + Array.isArray(result.content) && + result.content.length > 0 + ) { + const firstContent = result.content[0] + if ( + firstContent && + typeof firstContent === 'object' && + 'text' in firstContent + ) { + errorDetails = (firstContent as { text: string }).text + } + } + + throw new McpToolCallError(serverName, tool, errorDetails) + } + + return { + content: result, + _meta: result._meta as Record | undefined, + structuredContent: result.structuredContent as + | Record + | undefined, + } + } catch (e) { + if (progressInterval !== undefined) { + clearInterval(progressInterval) + } + + if (e instanceof Error && e.name !== 'AbortError') { + deps.logger.debug( + `[${serverName}] Tool '${tool}' failed: ${e.message}`, + ) + } + + // Check for 401 errors + if (e instanceof Error) { + const errorCode = 'code' in e ? (e.code as number | undefined) : undefined + if (errorCode === 401) { + throw new McpAuthError( + serverName, + `MCP server "${serverName}" requires re-authorization (token expired)`, + ) + } + } + + throw e + } finally { + if (progressInterval !== undefined) { + clearInterval(progressInterval) + } + } +} + +// ============================================================================ +// Helpers +// ============================================================================ + +function getMcpToolTimeoutMs(): number { + return ( + parseInt(process.env.MCP_TOOL_TIMEOUT || '', 10) || + DEFAULT_MCP_TOOL_TIMEOUT_MS + ) +} + +function createTimeoutPromise( + serverName: string, + tool: string, + timeoutMs: number, +): Promise { + return new Promise((_, reject) => { + const timeoutId = setTimeout( + () => { + reject( + new Error( + `MCP server "${serverName}" tool "${tool}" timed out after ${Math.floor(timeoutMs / 1000)}s`, + ), + ) + }, + timeoutMs, + ) + timeoutId.unref?.() + }) +} diff --git a/packages/mcp-client/src/index.ts b/packages/mcp-client/src/index.ts new file mode 100644 index 000000000..f165d40f3 --- /dev/null +++ b/packages/mcp-client/src/index.ts @@ -0,0 +1,124 @@ +// mcp-client — MCP protocol client +// Strict protocol layer: connection, transport, tool discovery, execution + +// Types & schemas +export { + ConfigScope, + TransportType, + McpStdioServerConfigSchema, + McpSSEServerConfigSchema, + McpHTTPServerConfigSchema, + McpWebSocketServerConfigSchema, + McpSdkServerConfigSchema, + McpClaudeAIProxyServerConfigSchema, + McpServerConfigSchema, + McpJsonConfigSchema, +} from './types.js' + +export type { + ConfigScope as ConfigScopeType, + Transport, + McpStdioServerConfig, + McpSSEServerConfig, + McpSSEIDEServerConfig, + McpWebSocketIDEServerConfig, + McpHTTPServerConfig, + McpWebSocketServerConfig, + McpSdkServerConfig, + McpClaudeAIProxyServerConfig, + McpServerConfig, + ScopedMcpServerConfig, + McpJsonConfig, + MCPServerConnection, + ConnectedMCPServer, + FailedMCPServer, + NeedsAuthMCPServer, + PendingMCPServer, + DisabledMCPServer, + ServerResource, + SerializedTool, + SerializedClient, + MCPCliState, +} from './types.js' + +// Errors +export { + McpError, + McpConnectionError, + McpAuthError, + McpTimeoutError, + McpToolCallError, + McpSessionExpiredError, +} from './errors.js' + +// Interfaces (host dependency injection) +export type { + Logger, + AnalyticsSink, + FeatureGate, + AuthProvider, + ProxyConfig, + ContentStorage, + ImageProcessor, + HttpConfig, + SubprocessEnvProvider, + McpClientDependencies, +} from './interfaces.js' + +// Transport +export { createLinkedTransportPair } from './transport/InProcessTransport.js' + +// String utilities +export { + buildMcpToolName, + normalizeNameForMCP, + mcpInfoFromString, + getMcpPrefix, + getToolNameForPermissionCheck, + getMcpDisplayName, + extractMcpToolDisplayName, +} from './strings.js' + +// Cache +export { memoizeWithLRU } from './cache.js' + +// Sanitization +export { recursivelySanitizeUnicode } from './sanitization.js' + +// Connection utilities +export { + DEFAULT_CONNECTION_TIMEOUT_MS, + MAX_MCP_DESCRIPTION_LENGTH, + MAX_ERRORS_BEFORE_RECONNECT, + createMcpClient, + withConnectionTimeout, + captureStderr, + isTerminalConnectionError, + isMcpSessionExpiredError, + installConnectionMonitor, + terminateWithSignalEscalation, + createCleanup, + buildConnectedServer, +} from './connection.js' +export type { + CreateClientOptions, + ConnectionMonitorOptions, + CleanupOptions, + BuildConnectedServerOptions, +} from './connection.js' + +// Tool discovery +export { + MCP_FETCH_CACHE_SIZE, + discoverTools, + createCachedToolDiscovery, +} from './discovery.js' +export type { DiscoveryOptions } from './discovery.js' + +// Tool execution +export { callMcpTool } from './execution.js' +export type { CallToolOptions, CallToolResult } from './execution.js' + +// Manager (main API) +export { createMcpManager } from './manager.js' +export type { McpManager } from './manager.js' diff --git a/packages/mcp-client/src/interfaces.ts b/packages/mcp-client/src/interfaces.ts new file mode 100644 index 000000000..9e4fdb753 --- /dev/null +++ b/packages/mcp-client/src/interfaces.ts @@ -0,0 +1,74 @@ +// Host dependency injection interfaces +// The MCP client package uses these interfaces to decouple from host infrastructure. + +/** Logging interface */ +export interface Logger { + debug(message: string, ...args: unknown[]): void + info(message: string, ...args: unknown[]): void + warn(message: string, ...args: unknown[]): void + error(message: string, ...args: unknown[]): void +} + +/** Analytics/telemetry callback */ +export interface AnalyticsSink { + trackEvent(event: string, metadata: Record): void +} + +/** Feature flag check */ +export interface FeatureGate { + isEnabled(flag: string): boolean +} + +/** OAuth token provider */ +export interface AuthProvider { + getTokens(): Promise<{ accessToken: string } | null> + refreshTokens(): Promise + handleOAuthError?(error: unknown): Promise +} + +/** HTTP/WebSocket proxy configuration */ +export interface ProxyConfig { + getFetchOptions?(): Record + getWebSocketAgent?(url: string): unknown + getWebSocketUrl?(url: string): string | undefined + getTLSOptions?(): Record | undefined +} + +/** Binary/image content persistence */ +export interface ContentStorage { + persistBinaryContent(data: Buffer, ext: string): Promise + persistToolResult?(toolUseId: string, content: unknown): Promise +} + +/** Image processing (resize, downsample) */ +export interface ImageProcessor { + resizeAndDownsample?(buffer: Buffer): Promise +} + +/** HTTP configuration (user agent, session ID) */ +export interface HttpConfig { + getUserAgent(): string + getSessionId?(): string +} + +/** Subprocess environment variable provider */ +export interface SubprocessEnvProvider { + getEnv(additional?: Record): Record +} + +/** + * Complete set of host dependencies required by the MCP client. + * All fields except `logger` and `httpConfig` are optional — + * the client degrades gracefully when they're not provided. + */ +export interface McpClientDependencies { + logger: Logger + analytics?: AnalyticsSink + featureGate?: FeatureGate + auth?: AuthProvider + proxy?: ProxyConfig + storage?: ContentStorage + imageProcessor?: ImageProcessor + httpConfig: HttpConfig + subprocessEnv?: SubprocessEnvProvider +} diff --git a/packages/mcp-client/src/manager.ts b/packages/mcp-client/src/manager.ts new file mode 100644 index 000000000..0f7062ed9 --- /dev/null +++ b/packages/mcp-client/src/manager.ts @@ -0,0 +1,241 @@ +// McpManager — imperative API for MCP protocol client +// Factory function that creates a manager instance with event-based notifications + +import type { Client } from '@modelcontextprotocol/sdk/client/index.js' +import type { + ListToolsResult, +} from '@modelcontextprotocol/sdk/types.js' +import memoize from 'lodash-es/memoize.js' +import { buildMcpToolName } from './strings.js' +import type { CoreTool } from '@claude-code-best/agent-tools' +import type { + McpServerConfig, + ScopedMcpServerConfig, + MCPServerConnection, + ConnectedMCPServer, + FailedMCPServer, + NeedsAuthMCPServer, +} from './types.js' +import type { McpClientDependencies } from './interfaces.js' +import { + McpConnectionError, + McpAuthError, + McpTimeoutError, +} from './errors.js' +import { memoizeWithLRU } from './cache.js' +import { discoverTools } from './discovery.js' +import { callMcpTool } from './execution.js' + +// ============================================================================ +// Event types +// ============================================================================ + +export type McpManagerEvents = { + connected: (name: string) => void + disconnected: (name: string, error?: Error) => void + toolsChanged: (serverName: string, tools: CoreTool[]) => void + error: (name: string, error: Error) => void + authRequired: (name: string) => void +} + +type EventHandler = (...args: any[]) => void + +// ============================================================================ +// Manager interface +// ============================================================================ + +export interface McpManager { + connect(name: string, config: McpServerConfig): Promise + disconnect(name: string): Promise + disconnectAll(): Promise + getConnections(): Map + getTools(serverName: string): CoreTool[] + getAllTools(): CoreTool[] + callTool(serverName: string, toolName: string, args: unknown): Promise + on(event: E, handler: McpManagerEvents[E]): void + off(event: string, handler: EventHandler): void +} + +// ============================================================================ +// Default timeout +// ============================================================================ + +const MCP_TIMEOUT_MS = 30_000 +const MCP_REQUEST_TIMEOUT_MS = 60_000 + +// ============================================================================ +// Manager implementation +// ============================================================================ + +class McpManagerImpl implements McpManager { + private connections = new Map() + private toolsCache = new Map() + private listeners = new Map>() + private deps: McpClientDependencies + private connectFn: ((name: string, config: ScopedMcpServerConfig) => Promise) | null = null + + constructor(deps: McpClientDependencies) { + this.deps = deps + } + + /** Set the connect function — the host provides this with all transport logic */ + setConnectFn(fn: (name: string, config: ScopedMcpServerConfig) => Promise): void { + this.connectFn = fn + } + + async connect(name: string, config: McpServerConfig): Promise { + if (!this.connectFn) { + throw new Error('McpManager: connectFn not set. Call setConnectFn() first.') + } + + const scopedConfig: ScopedMcpServerConfig = { ...config, scope: 'dynamic' } + + try { + const connection = await this.connectFn(name, scopedConfig) + this.connections.set(name, connection) + + if (connection.type === 'connected') { + this.emit('connected', name) + // Fetch tools for this server + await this.refreshTools(name, connection) + } else if (connection.type === 'needs-auth') { + this.emit('authRequired', name) + } + + return connection + } catch (err) { + const error = err instanceof Error ? err : new Error(String(err)) + this.emit('error', name, error) + throw err + } + } + + async disconnect(name: string): Promise { + const conn = this.connections.get(name) + if (!conn) return + + if (conn.type === 'connected') { + try { + await conn.cleanup() + } catch (err) { + this.deps.logger.warn(`Error disconnecting ${name}:`, err) + } + } + + this.connections.delete(name) + this.toolsCache.delete(name) + this.emit('disconnected', name) + } + + async disconnectAll(): Promise { + const names = [...this.connections.keys()] + await Promise.all(names.map(name => this.disconnect(name))) + } + + getConnections(): Map { + return new Map(this.connections) + } + + getTools(serverName: string): CoreTool[] { + return this.toolsCache.get(serverName) ?? [] + } + + getAllTools(): CoreTool[] { + const all: CoreTool[] = [] + for (const tools of this.toolsCache.values()) { + all.push(...tools) + } + return all + } + + async callTool(serverName: string, toolName: string, args: unknown): Promise { + const conn = this.connections.get(serverName) + if (!conn || conn.type !== 'connected') { + throw new McpConnectionError(serverName, `Server ${serverName} is not connected`) + } + + return callMcpTool( + { + client: conn, + tool: toolName, + args: args as Record, + signal: new AbortController().signal, + }, + this.deps, + ) + } + + on(event: E, handler: McpManagerEvents[E]): void { + if (!this.listeners.has(event)) { + this.listeners.set(event, new Set()) + } + this.listeners.get(event)!.add(handler) + } + + off(event: string, handler: EventHandler): void { + this.listeners.get(event)?.delete(handler) + } + + // ── Private ── + + private emit(event: string, ...args: unknown[]): void { + this.listeners.get(event)?.forEach(handler => { + try { + handler(...args) + } catch (err) { + this.deps.logger.error(`Error in ${event} handler:`, err) + } + }) + } + + private async refreshTools(name: string, conn: ConnectedMCPServer): Promise { + try { + const tools = await discoverTools({ + serverName: name, + client: conn.client, + capabilities: conn.capabilities ?? {}, + deps: this.deps, + }) + + this.toolsCache.set(name, tools) + this.emit('toolsChanged', name, tools) + } catch (err) { + this.deps.logger.warn(`Failed to fetch tools for ${name}:`, err) + } + } +} + +// ============================================================================ +// Factory function +// ============================================================================ + +/** + * Creates a new MCP manager instance. + * + * The manager handles connection lifecycle, tool discovery, and event notification. + * The host must call `setConnectFn()` to provide the transport-level connection logic. + * + * @param deps Host dependency injections (logger, auth, proxy, etc.) + * @returns McpManager instance + * + * @example + * ```typescript + * const manager = createMcpManager({ + * logger: console, + * httpConfig: { getUserAgent: () => 'my-app/1.0' }, + * }) + * + * manager.setConnectFn(async (name, config) => { + * // Transport-level connection logic here + * }) + * + * manager.on('connected', (name) => console.log(`Connected to ${name}`)) + * manager.on('toolsChanged', (name, tools) => console.log(`${name}: ${tools.length} tools`)) + * + * await manager.connect('my-server', { command: 'npx', args: ['my-mcp-server'] }) + * const tools = manager.getAllTools() + * ``` + */ +export function createMcpManager(deps: McpClientDependencies): McpManager { + return new McpManagerImpl(deps) +} diff --git a/packages/mcp-client/src/sanitization.ts b/packages/mcp-client/src/sanitization.ts new file mode 100644 index 000000000..91713fc73 --- /dev/null +++ b/packages/mcp-client/src/sanitization.ts @@ -0,0 +1,31 @@ +// Unicode sanitization for MCP data +// Extracted from src/utils/sanitization.ts + +/** + * Recursively sanitizes Unicode characters in MCP server responses. + * Removes or replaces problematic Unicode that could cause display or parsing issues. + */ +export function recursivelySanitizeUnicode(data: T): T { + if (typeof data === 'string') { + // Remove control characters except \t, \n, \r + // Replace null bytes and other C0 controls + return data + .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '') + .replace(/\uFFFD/g, '') // replacement character + .normalize('NFC') as unknown as T + } + + if (Array.isArray(data)) { + return data.map(item => recursivelySanitizeUnicode(item)) as unknown as T + } + + if (data !== null && typeof data === 'object') { + const result = {} as Record + for (const [key, value] of Object.entries(data as Record)) { + result[key] = recursivelySanitizeUnicode(value) + } + return result as T + } + + return data +} diff --git a/packages/mcp-client/src/strings.ts b/packages/mcp-client/src/strings.ts new file mode 100644 index 000000000..c1b9a760e --- /dev/null +++ b/packages/mcp-client/src/strings.ts @@ -0,0 +1,86 @@ +// MCP string utility functions — pure, no dependencies +// Extracted from src/services/mcp/mcpStringUtils.ts and normalization.ts + +// Claude.ai server names are prefixed with this string +const CLAUDEAI_SERVER_PREFIX = 'claude.ai ' + +/** + * Normalize server names to be compatible with the API pattern ^[a-zA-Z0-9_-]{1,64}$ + * Replaces any invalid characters (including dots and spaces) with underscores. + */ +export function normalizeNameForMCP(name: string): string { + let normalized = name.replace(/[^a-zA-Z0-9_-]/g, '_') + if (name.startsWith(CLAUDEAI_SERVER_PREFIX)) { + normalized = normalized.replace(/_+/g, '_').replace(/^_|_$/g, '') + } + return normalized +} + +/** + * Generates the MCP tool/command name prefix for a given server + */ +export function getMcpPrefix(serverName: string): string { + return `mcp__${normalizeNameForMCP(serverName)}__` +} + +/** + * Builds a fully qualified MCP tool name from server and tool names. + * Inverse of mcpInfoFromString(). + */ +export function buildMcpToolName(serverName: string, toolName: string): string { + return `${getMcpPrefix(serverName)}${normalizeNameForMCP(toolName)}` +} + +/** + * Extracts MCP server information from a tool name string. + * @param toolString Expected format: "mcp__serverName__toolName" + */ +export function mcpInfoFromString(toolString: string): { + serverName: string + toolName: string | undefined +} | null { + const parts = toolString.split('__') + const [mcpPart, serverName, ...toolNameParts] = parts + if (mcpPart !== 'mcp' || !serverName) { + return null + } + const toolName = + toolNameParts.length > 0 ? toolNameParts.join('__') : undefined + return { serverName, toolName } +} + +/** + * Returns the name to use for permission rule matching. + */ +export function getToolNameForPermissionCheck(tool: { + name: string + mcpInfo?: { serverName: string; toolName: string } +}): string { + return tool.mcpInfo + ? buildMcpToolName(tool.mcpInfo.serverName, tool.mcpInfo.toolName) + : tool.name +} + +/** + * Extracts the display name from an MCP tool/command name + */ +export function getMcpDisplayName( + fullName: string, + serverName: string, +): string { + const prefix = `mcp__${normalizeNameForMCP(serverName)}__` + return fullName.replace(prefix, '') +} + +/** + * Extracts just the tool/command display name from a userFacingName + */ +export function extractMcpToolDisplayName(userFacingName: string): string { + let withoutSuffix = userFacingName.replace(/\s*\(MCP\)\s*$/, '') + withoutSuffix = withoutSuffix.trim() + const dashIndex = withoutSuffix.indexOf(' - ') + if (dashIndex !== -1) { + return withoutSuffix.substring(dashIndex + 3).trim() + } + return withoutSuffix +} diff --git a/packages/mcp-client/src/transport/InProcessTransport.ts b/packages/mcp-client/src/transport/InProcessTransport.ts new file mode 100644 index 000000000..61a198d44 --- /dev/null +++ b/packages/mcp-client/src/transport/InProcessTransport.ts @@ -0,0 +1,63 @@ +import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js' +import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js' + +/** + * In-process linked transport pair for running an MCP server and client + * in the same process without spawning a subprocess. + * + * `send()` on one side delivers to `onmessage` on the other. + * `close()` on either side calls `onclose` on both. + */ +class InProcessTransport implements Transport { + private peer: InProcessTransport | undefined + private closed = false + + onclose?: () => void + onerror?: (error: Error) => void + onmessage?: (message: JSONRPCMessage) => void + + /** @internal */ + _setPeer(peer: InProcessTransport): void { + this.peer = peer + } + + async start(): Promise {} + + async send(message: JSONRPCMessage): Promise { + if (this.closed) { + throw new Error('Transport is closed') + } + // Deliver to the other side asynchronously to avoid stack depth issues + // with synchronous request/response cycles + queueMicrotask(() => { + this.peer?.onmessage?.(message) + }) + } + + async close(): Promise { + if (this.closed) { + return + } + this.closed = true + this.onclose?.() + // Close the peer if it hasn't already closed + if (this.peer && !this.peer.closed) { + this.peer.closed = true + this.peer.onclose?.() + } + } +} + +/** + * Creates a pair of linked transports for in-process MCP communication. + * Messages sent on one transport are delivered to the other's `onmessage`. + * + * @returns [clientTransport, serverTransport] + */ +export function createLinkedTransportPair(): [Transport, Transport] { + const a = new InProcessTransport() + const b = new InProcessTransport() + a._setPeer(b) + b._setPeer(a) + return [a, b] +} diff --git a/packages/mcp-client/src/types.ts b/packages/mcp-client/src/types.ts new file mode 100644 index 000000000..5204a654a --- /dev/null +++ b/packages/mcp-client/src/types.ts @@ -0,0 +1,240 @@ +// MCP configuration types, schemas, and connection state types +// Adapted from src/services/mcp/types.ts — uses zod directly instead of lazySchema + +import type { Client } from '@modelcontextprotocol/sdk/client/index.js' +import type { + Resource, + ServerCapabilities, +} from '@modelcontextprotocol/sdk/types.js' +import { z } from 'zod/v4' + +// ============================================================================ +// Configuration scope +// ============================================================================ + +export const ConfigScope = z.enum([ + 'local', + 'user', + 'project', + 'dynamic', + 'enterprise', + 'claudeai', + 'managed', +]) +export type ConfigScope = z.infer + +// ============================================================================ +// Transport type +// ============================================================================ + +export const TransportType = z.enum([ + 'stdio', + 'sse', + 'sse-ide', + 'http', + 'ws', + 'sdk', + 'claudeai-proxy', +]) +export type Transport = z.infer + +// ============================================================================ +// Server configuration schemas +// ============================================================================ + +export const McpStdioServerConfigSchema = z.object({ + type: z.literal('stdio').optional(), + command: z.string().min(1, 'Command cannot be empty'), + args: z.array(z.string()).default([]), + env: z.record(z.string(), z.string()).optional(), +}) + +const McpOAuthConfigSchema = z.object({ + clientId: z.string().optional(), + callbackPort: z.number().int().positive().optional(), + authServerMetadataUrl: z + .string() + .url() + .startsWith('https://', { + message: 'authServerMetadataUrl must use https://', + }) + .optional(), + xaa: z.boolean().optional(), +}) + +export const McpSSEServerConfigSchema = z.object({ + type: z.literal('sse'), + url: z.string(), + headers: z.record(z.string(), z.string()).optional(), + headersHelper: z.string().optional(), + oauth: McpOAuthConfigSchema.optional(), +}) + +export const McpSSEIDEServerConfigSchema = z.object({ + type: z.literal('sse-ide'), + url: z.string(), + ideName: z.string(), + ideRunningInWindows: z.boolean().optional(), +}) + +export const McpWebSocketIDEServerConfigSchema = z.object({ + type: z.literal('ws-ide'), + url: z.string(), + ideName: z.string(), + authToken: z.string().optional(), + ideRunningInWindows: z.boolean().optional(), +}) + +export const McpHTTPServerConfigSchema = z.object({ + type: z.literal('http'), + url: z.string(), + headers: z.record(z.string(), z.string()).optional(), + headersHelper: z.string().optional(), + oauth: McpOAuthConfigSchema.optional(), +}) + +export const McpWebSocketServerConfigSchema = z.object({ + type: z.literal('ws'), + url: z.string(), + headers: z.record(z.string(), z.string()).optional(), + headersHelper: z.string().optional(), +}) + +export const McpSdkServerConfigSchema = z.object({ + type: z.literal('sdk'), + name: z.string(), +}) + +export const McpClaudeAIProxyServerConfigSchema = z.object({ + type: z.literal('claudeai-proxy'), + url: z.string(), + id: z.string(), +}) + +export const McpServerConfigSchema = z.union([ + McpStdioServerConfigSchema, + McpSSEServerConfigSchema, + McpSSEIDEServerConfigSchema, + McpWebSocketIDEServerConfigSchema, + McpHTTPServerConfigSchema, + McpWebSocketServerConfigSchema, + McpSdkServerConfigSchema, + McpClaudeAIProxyServerConfigSchema, +]) + +// ============================================================================ +// Inferred config types +// ============================================================================ + +export type McpStdioServerConfig = z.infer +export type McpSSEServerConfig = z.infer +export type McpSSEIDEServerConfig = z.infer +export type McpWebSocketIDEServerConfig = z.infer< + typeof McpWebSocketIDEServerConfigSchema +> +export type McpHTTPServerConfig = z.infer +export type McpWebSocketServerConfig = z.infer< + typeof McpWebSocketServerConfigSchema +> +export type McpSdkServerConfig = z.infer +export type McpClaudeAIProxyServerConfig = z.infer< + typeof McpClaudeAIProxyServerConfigSchema +> +export type McpServerConfig = z.infer + +export type ScopedMcpServerConfig = McpServerConfig & { + scope: ConfigScope + pluginSource?: string +} + +export const McpJsonConfigSchema = z.object({ + mcpServers: z.record(z.string(), McpServerConfigSchema), +}) + +export type McpJsonConfig = z.infer + +// ============================================================================ +// Server connection state types +// ============================================================================ + +export type ConnectedMCPServer = { + client: Client + name: string + type: 'connected' + capabilities: ServerCapabilities + serverInfo?: { + name: string + version: string + } + instructions?: string + config: ScopedMcpServerConfig + cleanup: () => Promise +} + +export type FailedMCPServer = { + name: string + type: 'failed' + config: ScopedMcpServerConfig + error?: string +} + +export type NeedsAuthMCPServer = { + name: string + type: 'needs-auth' + config: ScopedMcpServerConfig +} + +export type PendingMCPServer = { + name: string + type: 'pending' + config: ScopedMcpServerConfig + reconnectAttempt?: number + maxReconnectAttempts?: number +} + +export type DisabledMCPServer = { + name: string + type: 'disabled' + config: ScopedMcpServerConfig +} + +export type MCPServerConnection = + | ConnectedMCPServer + | FailedMCPServer + | NeedsAuthMCPServer + | PendingMCPServer + | DisabledMCPServer + +// ============================================================================ +// Resource and serialization types +// ============================================================================ + +export type ServerResource = Resource & { server: string } + +export interface SerializedTool { + name: string + description: string + inputJSONSchema?: { + [x: string]: unknown + type: 'object' + properties?: { + [x: string]: unknown + } + } + isMcp?: boolean + originalToolName?: string +} + +export interface SerializedClient { + name: string + type: 'connected' | 'failed' | 'needs-auth' | 'pending' | 'disabled' + capabilities?: ServerCapabilities +} + +export interface MCPCliState { + clients: SerializedClient[] + configs: Record + tools: SerializedTool[] + resources: Record + normalizedNames?: Record +} diff --git a/src/QueryEngine.ts b/src/QueryEngine.ts index 467a8de89..c9d67d382 100644 --- a/src/QueryEngine.ts +++ b/src/QueryEngine.ts @@ -38,8 +38,8 @@ import { categorizeRetryableAPIError } from './services/api/errors.js' import type { MCPServerConnection } from './services/mcp/types.js' import type { AppState } from './state/AppState.js' import { type Tools, type ToolUseContext, toolMatchesName } from './Tool.js' -import type { AgentDefinition } from './tools/AgentTool/loadAgentsDir.js' -import { SYNTHETIC_OUTPUT_TOOL_NAME } from './tools/SyntheticOutputTool/SyntheticOutputTool.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { SYNTHETIC_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SyntheticOutputTool/SyntheticOutputTool.js' import type { APIError } from '@anthropic-ai/sdk' import type { CompactMetadata, Message, SystemCompactBoundaryMessage } from './types/message.js' import type { OrphanedPermission } from './types/textInputTypes.js' diff --git a/src/Tool.ts b/src/Tool.ts index 335d9bb7c..8c27885d9 100644 --- a/src/Tool.ts +++ b/src/Tool.ts @@ -29,7 +29,7 @@ import type { import type { AgentDefinition, AgentDefinitionsResult, -} from './tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import type { AssistantMessage, AttachmentMessage, diff --git a/src/bootstrap/state.ts b/src/bootstrap/state.ts index c30f3ab66..66702cadf 100644 --- a/src/bootstrap/state.ts +++ b/src/bootstrap/state.ts @@ -8,7 +8,7 @@ import { realpathSync } from 'fs' import sumBy from 'lodash-es/sumBy.js' import { cwd } from 'process' import type { HookEvent, ModelUsage } from 'src/entrypoints/agentSdkTypes.js' -import type { AgentColorName } from 'src/tools/AgentTool/agentColorManager.js' +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import type { HookCallbackMatcher } from 'src/types/hooks.js' // Indirection for browser-sdk build (package.json "browser" field swaps // crypto.ts for crypto.browser.ts). Pure leaf re-export of node:crypto — diff --git a/src/cli/handlers/agents.ts b/src/cli/handlers/agents.ts index c94723b00..f02ce8e1d 100644 --- a/src/cli/handlers/agents.ts +++ b/src/cli/handlers/agents.ts @@ -10,11 +10,11 @@ import { type ResolvedAgent, resolveAgentModelDisplay, resolveAgentOverrides, -} from '../../tools/AgentTool/agentDisplay.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentDisplay.js' import { getActiveAgentsFromList, getAgentDefinitionsWithOverrides, -} from '../../tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { getCwd } from '../../utils/cwd.js' function formatAgent(agent: ResolvedAgent): string { diff --git a/src/cli/print.ts b/src/cli/print.ts index affe37e60..5f2cb308c 100644 --- a/src/cli/print.ts +++ b/src/cli/print.ts @@ -37,7 +37,7 @@ import { type AgentDefinition, isBuiltInAgent, parseAgentsFromJson, -} from 'src/tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import type { Message, NormalizedUserMessage } from 'src/types/message.js' import type { QueuedCommand } from 'src/types/textInputTypes.js' import { @@ -200,7 +200,7 @@ import { getInitJsonSchema, setSdkAgentProgressSummariesEnabled, } from 'src/bootstrap/state.js' -import { createSyntheticOutputTool } from 'src/tools/SyntheticOutputTool/SyntheticOutputTool.js' +import { createSyntheticOutputTool } from '@claude-code-best/builtin-tools/tools/SyntheticOutputTool/SyntheticOutputTool.js' import { parseSessionIdentifier } from 'src/utils/sessionUrl.js' import { hydrateRemoteSession, @@ -364,7 +364,7 @@ const proactiveModule = : null const cronSchedulerModule = require('../utils/cronScheduler.js') as typeof import('../utils/cronScheduler.js') const cronJitterConfigModule = require('../utils/cronJitterConfig.js') as typeof import('../utils/cronJitterConfig.js') -const cronGate = require('../tools/ScheduleCronTool/prompt.js') as typeof import('../tools/ScheduleCronTool/prompt.js') +const cronGate = require('@claude-code-best/builtin-tools/tools/ScheduleCronTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/ScheduleCronTool/prompt.js') const extractMemoriesModule = feature('EXTRACT_MEMORIES') ? (require('../services/extractMemories/extractMemories.js') as typeof import('../services/extractMemories/extractMemories.js')) : null @@ -4940,7 +4940,7 @@ async function loadInitialMessages( getActiveAgentsFromList, } = // eslint-disable-next-line @typescript-eslint/no-require-imports - require('../tools/AgentTool/loadAgentsDir.js') as typeof import('../tools/AgentTool/loadAgentsDir.js') + require('@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js') as typeof import('@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js') getAgentDefinitionsWithOverrides.cache.clear?.() const freshAgentDefs = await getAgentDefinitionsWithOverrides( getCwd(), @@ -5142,7 +5142,7 @@ async function loadInitialMessages( // Refresh agent definitions to reflect the mode switch const { getAgentDefinitionsWithOverrides, getActiveAgentsFromList } = // eslint-disable-next-line @typescript-eslint/no-require-imports - require('../tools/AgentTool/loadAgentsDir.js') as typeof import('../tools/AgentTool/loadAgentsDir.js') + require('@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js') as typeof import('@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js') getAgentDefinitionsWithOverrides.cache.clear?.() const freshAgentDefs = await getAgentDefinitionsWithOverrides( getCwd(), diff --git a/src/commands.ts b/src/commands.ts index f411746a5..3d5847eb4 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -444,7 +444,7 @@ async function getSkills(cwd: string): Promise<{ /* eslint-disable @typescript-eslint/no-require-imports */ const getWorkflowCommands = feature('WORKFLOW_SCRIPTS') ? ( - require('./tools/WorkflowTool/createWorkflowCommand.js') as typeof import('./tools/WorkflowTool/createWorkflowCommand.js') + require('@claude-code-best/builtin-tools/tools/WorkflowTool/createWorkflowCommand.js') as typeof import('@claude-code-best/builtin-tools/tools/WorkflowTool/createWorkflowCommand.js') ).getWorkflowCommands : null /* eslint-enable @typescript-eslint/no-require-imports */ diff --git a/src/commands/brief.ts b/src/commands/brief.ts index d37ffd0ab..cb798bf52 100644 --- a/src/commands/brief.ts +++ b/src/commands/brief.ts @@ -7,8 +7,8 @@ import { logEvent, } from '../services/analytics/index.js' import type { ToolUseContext } from '../Tool.js' -import { isBriefEntitled } from '../tools/BriefTool/BriefTool.js' -import { BRIEF_TOOL_NAME } from '../tools/BriefTool/prompt.js' +import { isBriefEntitled } from '@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js' +import { BRIEF_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BriefTool/prompt.js' import type { Command, LocalJSXCommandContext, diff --git a/src/commands/clear/caches.ts b/src/commands/clear/caches.ts index 146ebe584..8eacc0d6f 100644 --- a/src/commands/clear/caches.ts +++ b/src/commands/clear/caches.ts @@ -93,7 +93,7 @@ export function clearSessionCaches( // Clear tungsten session usage tracking if (process.env.USER_TYPE === 'ant') { - void import('../../tools/TungstenTool/TungstenTool.js').then( + void import('@claude-code-best/builtin-tools/tools/TungstenTool/TungstenTool.js').then( ({ clearSessionsWithTungstenUsage, resetInitializationState }) => { clearSessionsWithTungstenUsage() resetInitializationState() @@ -126,19 +126,19 @@ export function clearSessionCaches( // Clear session environment variables clearSessionEnvVars() // Clear WebFetch URL cache (up to 50MB of cached page content) - void import('../../tools/WebFetchTool/utils.js').then( + void import('@claude-code-best/builtin-tools/tools/WebFetchTool/utils.js').then( ({ clearWebFetchCache }) => clearWebFetchCache(), ) // Clear ToolSearch description cache (full tool prompts, ~500KB for 50 MCP tools) - void import('../../tools/ToolSearchTool/ToolSearchTool.js').then( + void import('@claude-code-best/builtin-tools/tools/ToolSearchTool/ToolSearchTool.js').then( ({ clearToolSearchDescriptionCache }) => clearToolSearchDescriptionCache(), ) // Clear agent definitions cache (accumulates per-cwd via EnterWorktreeTool) - void import('../../tools/AgentTool/loadAgentsDir.js').then( + void import('@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js').then( ({ clearAgentDefinitionsCache }) => clearAgentDefinitionsCache(), ) // Clear SkillTool prompt cache (accumulates per project root) - void import('../../tools/SkillTool/prompt.js').then(({ clearPromptCache }) => + void import('@claude-code-best/builtin-tools/tools/SkillTool/prompt.js').then(({ clearPromptCache }) => clearPromptCache(), ) } diff --git a/src/commands/color/color.ts b/src/commands/color/color.ts index e4420b7f9..94347faef 100644 --- a/src/commands/color/color.ts +++ b/src/commands/color/color.ts @@ -4,7 +4,7 @@ import type { ToolUseContext } from '../../Tool.js' import { AGENT_COLORS, type AgentColorName, -} from '../../tools/AgentTool/agentColorManager.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import type { LocalJSXCommandContext, LocalJSXCommandOnDone, diff --git a/src/commands/context/context-noninteractive.ts b/src/commands/context/context-noninteractive.ts index 6a366d5fb..710c6d36a 100644 --- a/src/commands/context/context-noninteractive.ts +++ b/src/commands/context/context-noninteractive.ts @@ -2,7 +2,7 @@ import { feature } from 'bun:bundle' import { microcompactMessages } from '../../services/compact/microCompact.js' import type { AppState } from '../../state/AppStateStore.js' import type { Tools, ToolUseContext } from '../../Tool.js' -import type { AgentDefinitionsResult } from '../../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinitionsResult } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import type { Message } from '../../types/message.js' import { analyzeContextUsage, diff --git a/src/commands/fork/fork.tsx b/src/commands/fork/fork.tsx index d1053dc15..b9e416a01 100644 --- a/src/commands/fork/fork.tsx +++ b/src/commands/fork/fork.tsx @@ -1,7 +1,7 @@ import { feature } from 'bun:bundle' import React from 'react' -import { AgentTool } from '../../tools/AgentTool/AgentTool.js' -import { isInForkChild } from '../../tools/AgentTool/forkSubagent.js' +import { AgentTool } from '@claude-code-best/builtin-tools/tools/AgentTool/AgentTool.js' +import { isInForkChild } from '@claude-code-best/builtin-tools/tools/AgentTool/forkSubagent.js' import { logForDebugging } from '../../utils/debug.js' import type { LocalJSXCommandOnDone, LocalJSXCommandContext } from '../../types/command.js' diff --git a/src/commands/insights.ts b/src/commands/insights.ts index 3e9acbe41..1e5e40dd5 100644 --- a/src/commands/insights.ts +++ b/src/commands/insights.ts @@ -18,7 +18,7 @@ import { queryWithModel } from '../services/api/claude.js' import { AGENT_TOOL_NAME, LEGACY_AGENT_TOOL_NAME, -} from '../tools/AgentTool/constants.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' import type { LogOption } from '../types/logs.js' import { getClaudeConfigHomeDir } from '../utils/envUtils.js' import { toError } from '../utils/errors.js' diff --git a/src/commands/statusline.tsx b/src/commands/statusline.tsx index d12f4ad2d..46d2e7d57 100644 --- a/src/commands/statusline.tsx +++ b/src/commands/statusline.tsx @@ -1,6 +1,6 @@ import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/index.mjs' import type { Command } from '../commands.js' -import { AGENT_TOOL_NAME } from '../tools/AgentTool/constants.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' const statusline = { type: 'prompt', diff --git a/src/commands/workflows/index.ts b/src/commands/workflows/index.ts index d7d64472c..aba9ca07a 100644 --- a/src/commands/workflows/index.ts +++ b/src/commands/workflows/index.ts @@ -1,5 +1,5 @@ import type { Command, LocalCommandCall } from '../../types/command.js' -import { getWorkflowCommands } from '../../tools/WorkflowTool/createWorkflowCommand.js' +import { getWorkflowCommands } from '@claude-code-best/builtin-tools/tools/WorkflowTool/createWorkflowCommand.js' import { getCwd } from '../../utils/cwd.js' const call: LocalCommandCall = async (_args, _context) => { diff --git a/src/components/BashModeProgress.tsx b/src/components/BashModeProgress.tsx index c36dd1b32..817320220 100644 --- a/src/components/BashModeProgress.tsx +++ b/src/components/BashModeProgress.tsx @@ -1,6 +1,6 @@ import React from 'react' import { Box } from '@anthropic/ink' -import { BashTool } from '../tools/BashTool/BashTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' import type { ShellProgress } from '../types/tools.js' import { UserBashInputMessage } from './messages/UserBashInputMessage.js' import { ShellProgressMessage } from './shell/ShellProgressMessage.js' diff --git a/src/components/FeedbackSurvey/useMemorySurvey.tsx b/src/components/FeedbackSurvey/useMemorySurvey.tsx index 8ed385f3e..81767eac8 100644 --- a/src/components/FeedbackSurvey/useMemorySurvey.tsx +++ b/src/components/FeedbackSurvey/useMemorySurvey.tsx @@ -7,7 +7,7 @@ import { } from 'src/services/analytics/index.js' import { isAutoMemoryEnabled } from '../../memdir/paths.js' import { isPolicyAllowed } from '../../services/policyLimits/index.js' -import { FILE_READ_TOOL_NAME } from '../../tools/FileReadTool/prompt.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' import type { Message } from '../../types/message.js' import { getGlobalConfig, saveGlobalConfig } from '../../utils/config.js' import { isEnvTruthy } from '../../utils/envUtils.js' diff --git a/src/components/FileEditToolDiff.tsx b/src/components/FileEditToolDiff.tsx index 75efda0f5..4b9f6f66b 100644 --- a/src/components/FileEditToolDiff.tsx +++ b/src/components/FileEditToolDiff.tsx @@ -3,11 +3,11 @@ import * as React from 'react' import { Suspense, use, useState } from 'react' import { useTerminalSize } from '../hooks/useTerminalSize.js' import { Box, Text } from '@anthropic/ink' -import type { FileEdit } from '../tools/FileEditTool/types.js' +import type { FileEdit } from '@claude-code-best/builtin-tools/tools/FileEditTool/types.js' import { findActualString, preserveQuoteStyle, -} from '../tools/FileEditTool/utils.js' +} from '@claude-code-best/builtin-tools/tools/FileEditTool/utils.js' import { adjustHunkLineNumbers, CONTEXT_LINES, diff --git a/src/components/MessageSelector.tsx b/src/components/MessageSelector.tsx index d41cf36f9..caca52aa7 100644 --- a/src/components/MessageSelector.tsx +++ b/src/components/MessageSelector.tsx @@ -43,8 +43,8 @@ function isTextBlock(block: ContentBlockParam): block is TextBlockParam { import * as path from 'path' import { useTerminalSize } from 'src/hooks/useTerminalSize.js' -import type { FileEditOutput } from 'src/tools/FileEditTool/types.js' -import type { Output as FileWriteToolOutput } from 'src/tools/FileWriteTool/FileWriteTool.js' +import type { FileEditOutput } from '@claude-code-best/builtin-tools/tools/FileEditTool/types.js' +import type { Output as FileWriteToolOutput } from '@claude-code-best/builtin-tools/tools/FileWriteTool/FileWriteTool.js' import { BASH_STDERR_TAG, BASH_STDOUT_TAG, diff --git a/src/components/Messages.tsx b/src/components/Messages.tsx index 82caacd38..7bcbe96a5 100644 --- a/src/components/Messages.tsx +++ b/src/components/Messages.tsx @@ -16,7 +16,7 @@ import { useShortcutDisplay } from '../keybindings/useShortcutDisplay.js' import type { Screen } from '../screens/REPL.js' import type { Tools } from '../Tool.js' import { findToolByName } from '../Tool.js' -import type { AgentDefinitionsResult } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinitionsResult } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import type { Message as MessageType, NormalizedMessage, @@ -104,12 +104,12 @@ const proactiveModule = const BRIEF_TOOL_NAME: string | null = feature('KAIROS') || feature('KAIROS_BRIEF') ? ( - require('../tools/BriefTool/prompt.js') as typeof import('../tools/BriefTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') ).BRIEF_TOOL_NAME : null const SEND_USER_FILE_TOOL_NAME: string | null = feature('KAIROS') ? ( - require('../tools/SendUserFileTool/prompt.js') as typeof import('../tools/SendUserFileTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/SendUserFileTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/SendUserFileTool/prompt.js') ).SEND_USER_FILE_TOOL_NAME : null diff --git a/src/components/PromptInput/PromptInput.tsx b/src/components/PromptInput/PromptInput.tsx index 418ce82e1..3d43a1fae 100644 --- a/src/components/PromptInput/PromptInput.tsx +++ b/src/components/PromptInput/PromptInput.tsx @@ -100,8 +100,8 @@ import { AGENT_COLOR_TO_THEME_COLOR, AGENT_COLORS, type AgentColorName, -} from '../../tools/AgentTool/agentColorManager.js' -import type { AgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import type { Message } from '../../types/message.js' import type { PermissionMode } from '../../types/permissions.js' import type { diff --git a/src/components/PromptInput/PromptInputModeIndicator.tsx b/src/components/PromptInput/PromptInputModeIndicator.tsx index e493dba2d..b52828ba6 100644 --- a/src/components/PromptInput/PromptInputModeIndicator.tsx +++ b/src/components/PromptInput/PromptInputModeIndicator.tsx @@ -5,7 +5,7 @@ import { AGENT_COLOR_TO_THEME_COLOR, AGENT_COLORS, type AgentColorName, -} from 'src/tools/AgentTool/agentColorManager.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import type { PromptInputMode } from 'src/types/textInputTypes.js' import { getTeammateColor } from 'src/utils/teammate.js' import type { Theme } from 'src/utils/theme.js' diff --git a/src/components/PromptInput/useSwarmBanner.ts b/src/components/PromptInput/useSwarmBanner.ts index 2ce6ba9f6..18feb0503 100644 --- a/src/components/PromptInput/useSwarmBanner.ts +++ b/src/components/PromptInput/useSwarmBanner.ts @@ -9,7 +9,7 @@ import { AGENT_COLORS, type AgentColorName, getAgentColor, -} from '../../tools/AgentTool/agentColorManager.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { getStandaloneAgentName } from '../../utils/standaloneAgent.js' import { isInsideTmux } from '../../utils/swarm/backends/detection.js' import { diff --git a/src/components/Settings/Config.tsx b/src/components/Settings/Config.tsx index 3461b556d..4499fa056 100644 --- a/src/components/Settings/Config.tsx +++ b/src/components/Settings/Config.tsx @@ -215,7 +215,7 @@ export function Config({ const showDefaultViewPicker = feature('KAIROS') || feature('KAIROS_BRIEF') ? ( - require('../../tools/BriefTool/BriefTool.js') as typeof import('../../tools/BriefTool/BriefTool.js') + require('@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js') as typeof import('@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js') ).isBriefEntitled() : false /* eslint-enable @typescript-eslint/no-require-imports */ diff --git a/src/components/StatusNotices.tsx b/src/components/StatusNotices.tsx index ae25c5d9f..c8e629885 100644 --- a/src/components/StatusNotices.tsx +++ b/src/components/StatusNotices.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { use } from 'react' import { Box } from '@anthropic/ink' -import type { AgentDefinitionsResult } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinitionsResult } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { getMemoryFiles } from '../utils/claudemd.js' import { getGlobalConfig } from '../utils/config.js' import { diff --git a/src/components/TaskListV2.tsx b/src/components/TaskListV2.tsx index 6ab77ccbb..d96126dec 100644 --- a/src/components/TaskListV2.tsx +++ b/src/components/TaskListV2.tsx @@ -7,7 +7,7 @@ import { isInProcessTeammateTask } from '../tasks/InProcessTeammateTask/types.js import { AGENT_COLOR_TO_THEME_COLOR, type AgentColorName, -} from '../tools/AgentTool/agentColorManager.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { isAgentSwarmsEnabled } from '../utils/agentSwarmsEnabled.js' import { count } from '../utils/array.js' import { summarizeRecentActivities } from '../utils/collapseReadSearch.js' diff --git a/src/components/TrustDialog/TrustDialog.tsx b/src/components/TrustDialog/TrustDialog.tsx index 88a0c897f..e16384b53 100644 --- a/src/components/TrustDialog/TrustDialog.tsx +++ b/src/components/TrustDialog/TrustDialog.tsx @@ -7,7 +7,7 @@ import { useExitOnCtrlCDWithKeybindings } from '../../hooks/useExitOnCtrlCDWithK import { Box, Link, Text } from '@anthropic/ink' import { useKeybinding } from '../../keybindings/useKeybinding.js' import { getMcpConfigsByScope } from '../../services/mcp/config.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' import { checkHasTrustDialogAccepted, saveCurrentProjectConfig, diff --git a/src/components/TrustDialog/utils.ts b/src/components/TrustDialog/utils.ts index 0be335a97..4e8db9f97 100644 --- a/src/components/TrustDialog/utils.ts +++ b/src/components/TrustDialog/utils.ts @@ -1,7 +1,7 @@ import type { PermissionRule } from 'src/utils/permissions/PermissionRule.js' import { getSettingsForSource } from 'src/utils/settings/settings.js' import type { SettingsJson } from 'src/utils/settings/types.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' import { SAFE_ENV_VARS } from '../../utils/managedEnvConstants.js' import { getPermissionRulesForSource } from '../../utils/permissions/permissionsLoader.js' diff --git a/src/components/agents/AgentDetail.tsx b/src/components/agents/AgentDetail.tsx index 88f368dc6..f27fe6360 100644 --- a/src/components/agents/AgentDetail.tsx +++ b/src/components/agents/AgentDetail.tsx @@ -3,13 +3,13 @@ import * as React from 'react' import { type KeyboardEvent, Box, Text } from '@anthropic/ink' import { useKeybinding } from '../../keybindings/useKeybinding.js' import type { Tools } from '../../Tool.js' -import { getAgentColor } from '../../tools/AgentTool/agentColorManager.js' -import { getMemoryScopeDisplay } from '../../tools/AgentTool/agentMemory.js' -import { resolveAgentTools } from '../../tools/AgentTool/agentToolUtils.js' +import { getAgentColor } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' +import { getMemoryScopeDisplay } from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js' +import { resolveAgentTools } from '@claude-code-best/builtin-tools/tools/AgentTool/agentToolUtils.js' import { type AgentDefinition, isBuiltInAgent, -} from '../../tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { getAgentModelDisplay } from '../../utils/model/agent.js' import { Markdown } from '../Markdown.js' import { getActualRelativeAgentFilePath } from './agentFileUtils.js' diff --git a/src/components/agents/AgentEditor.tsx b/src/components/agents/AgentEditor.tsx index 7cbd52b96..6bdbb7ec3 100644 --- a/src/components/agents/AgentEditor.tsx +++ b/src/components/agents/AgentEditor.tsx @@ -9,13 +9,13 @@ import type { Tools } from '../../Tool.js' import { type AgentColorName, setAgentColor, -} from '../../tools/AgentTool/agentColorManager.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { type AgentDefinition, getActiveAgentsFromList, isCustomAgent, isPluginAgent, -} from '../../tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { editFileInEditor } from '../../utils/promptEditor.js' import { getActualAgentFilePath, updateAgentFile } from './agentFileUtils.js' import { ColorPicker } from './ColorPicker.js' diff --git a/src/components/agents/AgentsList.tsx b/src/components/agents/AgentsList.tsx index 4be51e11b..11b632daf 100644 --- a/src/components/agents/AgentsList.tsx +++ b/src/components/agents/AgentsList.tsx @@ -2,14 +2,14 @@ import figures from 'figures' import * as React from 'react' import type { SettingSource } from 'src/utils/settings/constants.js' import { type KeyboardEvent, Box, Text } from '@anthropic/ink' -import type { ResolvedAgent } from '../../tools/AgentTool/agentDisplay.js' +import type { ResolvedAgent } from '@claude-code-best/builtin-tools/tools/AgentTool/agentDisplay.js' import { AGENT_SOURCE_GROUPS, compareAgentsByName, getOverrideSourceLabel, resolveAgentModelDisplay, -} from '../../tools/AgentTool/agentDisplay.js' -import type { AgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentDisplay.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { count } from '../../utils/array.js' import { Dialog, Divider } from '@anthropic/ink' import { getAgentSourceDisplayName } from './utils.js' diff --git a/src/components/agents/AgentsMenu.tsx b/src/components/agents/AgentsMenu.tsx index 00c3a9ce3..ce2e789ca 100644 --- a/src/components/agents/AgentsMenu.tsx +++ b/src/components/agents/AgentsMenu.tsx @@ -11,11 +11,11 @@ import type { Tools } from '../../Tool.js' import { type ResolvedAgent, resolveAgentOverrides, -} from '../../tools/AgentTool/agentDisplay.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentDisplay.js' import { type AgentDefinition, getActiveAgentsFromList, -} from '../../tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { toError } from '../../utils/errors.js' import { logError } from '../../utils/log.js' import { Select } from '../CustomSelect/select.js' diff --git a/src/components/agents/ColorPicker.tsx b/src/components/agents/ColorPicker.tsx index 7db5ea288..3e74ea8ca 100644 --- a/src/components/agents/ColorPicker.tsx +++ b/src/components/agents/ColorPicker.tsx @@ -6,7 +6,7 @@ import { AGENT_COLOR_TO_THEME_COLOR, AGENT_COLORS, type AgentColorName, -} from '../../tools/AgentTool/agentColorManager.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { capitalize } from '../../utils/stringUtils.js' type ColorOption = AgentColorName | 'automatic' diff --git a/src/components/agents/SnapshotUpdateDialog.ts b/src/components/agents/SnapshotUpdateDialog.ts index 3ef073321..a23511b4d 100644 --- a/src/components/agents/SnapshotUpdateDialog.ts +++ b/src/components/agents/SnapshotUpdateDialog.ts @@ -1,6 +1,6 @@ // Auto-generated stub — replace with real implementation import type React from 'react'; -import type { AgentMemoryScope } from '../../tools/AgentTool/agentMemory.js'; +import type { AgentMemoryScope } from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js'; export {}; export const SnapshotUpdateDialog: React.FC<{ diff --git a/src/components/agents/ToolSelector.tsx b/src/components/agents/ToolSelector.tsx index 96b9f4b68..8fc4b4730 100644 --- a/src/components/agents/ToolSelector.tsx +++ b/src/components/agents/ToolSelector.tsx @@ -3,24 +3,24 @@ import React, { useCallback, useMemo, useState } from 'react' import { mcpInfoFromString } from 'src/services/mcp/mcpStringUtils.js' import { isMcpTool } from 'src/services/mcp/utils.js' import type { Tool, Tools } from 'src/Tool.js' -import { filterToolsForAgent } from 'src/tools/AgentTool/agentToolUtils.js' -import { AGENT_TOOL_NAME } from 'src/tools/AgentTool/constants.js' -import { BashTool } from 'src/tools/BashTool/BashTool.js' -import { ExitPlanModeV2Tool } from 'src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' -import { FileEditTool } from 'src/tools/FileEditTool/FileEditTool.js' -import { FileReadTool } from 'src/tools/FileReadTool/FileReadTool.js' -import { FileWriteTool } from 'src/tools/FileWriteTool/FileWriteTool.js' -import { GlobTool } from 'src/tools/GlobTool/GlobTool.js' -import { GrepTool } from 'src/tools/GrepTool/GrepTool.js' -import { ListMcpResourcesTool } from 'src/tools/ListMcpResourcesTool/ListMcpResourcesTool.js' -import { NotebookEditTool } from 'src/tools/NotebookEditTool/NotebookEditTool.js' -import { ReadMcpResourceTool } from 'src/tools/ReadMcpResourceTool/ReadMcpResourceTool.js' -import { TaskOutputTool } from 'src/tools/TaskOutputTool/TaskOutputTool.js' -import { TaskStopTool } from 'src/tools/TaskStopTool/TaskStopTool.js' -import { TodoWriteTool } from 'src/tools/TodoWriteTool/TodoWriteTool.js' -import { TungstenTool } from 'src/tools/TungstenTool/TungstenTool.js' -import { WebFetchTool } from 'src/tools/WebFetchTool/WebFetchTool.js' -import { WebSearchTool } from 'src/tools/WebSearchTool/WebSearchTool.js' +import { filterToolsForAgent } from '@claude-code-best/builtin-tools/tools/AgentTool/agentToolUtils.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' +import { ExitPlanModeV2Tool } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' +import { FileEditTool } from '@claude-code-best/builtin-tools/tools/FileEditTool/FileEditTool.js' +import { FileReadTool } from '@claude-code-best/builtin-tools/tools/FileReadTool/FileReadTool.js' +import { FileWriteTool } from '@claude-code-best/builtin-tools/tools/FileWriteTool/FileWriteTool.js' +import { GlobTool } from '@claude-code-best/builtin-tools/tools/GlobTool/GlobTool.js' +import { GrepTool } from '@claude-code-best/builtin-tools/tools/GrepTool/GrepTool.js' +import { ListMcpResourcesTool } from '@claude-code-best/builtin-tools/tools/ListMcpResourcesTool/ListMcpResourcesTool.js' +import { NotebookEditTool } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/NotebookEditTool.js' +import { ReadMcpResourceTool } from '@claude-code-best/builtin-tools/tools/ReadMcpResourceTool/ReadMcpResourceTool.js' +import { TaskOutputTool } from '@claude-code-best/builtin-tools/tools/TaskOutputTool/TaskOutputTool.js' +import { TaskStopTool } from '@claude-code-best/builtin-tools/tools/TaskStopTool/TaskStopTool.js' +import { TodoWriteTool } from '@claude-code-best/builtin-tools/tools/TodoWriteTool/TodoWriteTool.js' +import { TungstenTool } from '@claude-code-best/builtin-tools/tools/TungstenTool/TungstenTool.js' +import { WebFetchTool } from '@claude-code-best/builtin-tools/tools/WebFetchTool/WebFetchTool.js' +import { WebSearchTool } from '@claude-code-best/builtin-tools/tools/WebSearchTool/WebSearchTool.js' import { type KeyboardEvent, Box, Text } from '@anthropic/ink' import { useKeybinding } from '../../keybindings/useKeybinding.js' import { count } from '../../utils/array.js' diff --git a/src/components/agents/agentFileUtils.ts b/src/components/agents/agentFileUtils.ts index 87e4e4b0f..822f13412 100644 --- a/src/components/agents/agentFileUtils.ts +++ b/src/components/agents/agentFileUtils.ts @@ -2,12 +2,12 @@ import { mkdir, open, unlink } from 'fs/promises' import { join } from 'path' import type { SettingSource } from 'src/utils/settings/constants.js' import { getManagedFilePath } from 'src/utils/settings/managedPath.js' -import type { AgentMemoryScope } from '../../tools/AgentTool/agentMemory.js' +import type { AgentMemoryScope } from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js' import { type AgentDefinition, isBuiltInAgent, isPluginAgent, -} from '../../tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { getCwd } from '../../utils/cwd.js' import type { EffortValue } from '../../utils/effort.js' import { getClaudeConfigHomeDir } from '../../utils/envUtils.js' diff --git a/src/components/agents/generateAgent.ts b/src/components/agents/generateAgent.ts index 062786677..801601d4b 100644 --- a/src/components/agents/generateAgent.ts +++ b/src/components/agents/generateAgent.ts @@ -2,7 +2,7 @@ import type { ContentBlock } from '@anthropic-ai/sdk/resources/index.mjs' import { getUserContext } from 'src/context.js' import { queryModelWithoutStreaming } from 'src/services/api/claude.js' import { getEmptyToolPermissionContext } from 'src/Tool.js' -import { AGENT_TOOL_NAME } from 'src/tools/AgentTool/constants.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' import { prependUserContext } from 'src/utils/api.js' import { createUserMessage, diff --git a/src/components/agents/new-agent-creation/CreateAgentWizard.tsx b/src/components/agents/new-agent-creation/CreateAgentWizard.tsx index 33c282fa6..fa6ed6816 100644 --- a/src/components/agents/new-agent-creation/CreateAgentWizard.tsx +++ b/src/components/agents/new-agent-creation/CreateAgentWizard.tsx @@ -1,7 +1,7 @@ import React, { type ReactNode } from 'react' import { isAutoMemoryEnabled } from '../../../memdir/paths.js' import type { Tools } from '../../../Tool.js' -import type { AgentDefinition } from '../../../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { WizardProvider } from '../../wizard/index.js' import type { WizardStepComponent } from '../../wizard/types.js' import type { AgentWizardData } from './types.js' diff --git a/src/components/agents/new-agent-creation/wizard-steps/ColorStep.tsx b/src/components/agents/new-agent-creation/wizard-steps/ColorStep.tsx index 7763daac6..e28133a38 100644 --- a/src/components/agents/new-agent-creation/wizard-steps/ColorStep.tsx +++ b/src/components/agents/new-agent-creation/wizard-steps/ColorStep.tsx @@ -1,7 +1,7 @@ import React, { type ReactNode } from 'react' import { Box, Byline, KeyboardShortcutHint } from '@anthropic/ink' import { useKeybinding } from '../../../../keybindings/useKeybinding.js' -import type { AgentColorName } from '../../../../tools/AgentTool/agentColorManager.js' +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { ConfigurableShortcutHint } from '../../../ConfigurableShortcutHint.js' import { useWizard } from '../../../wizard/index.js' import { WizardDialogLayout } from '../../../wizard/WizardDialogLayout.js' diff --git a/src/components/agents/new-agent-creation/wizard-steps/ConfirmStep.tsx b/src/components/agents/new-agent-creation/wizard-steps/ConfirmStep.tsx index ef02cbefe..cbe284991 100644 --- a/src/components/agents/new-agent-creation/wizard-steps/ConfirmStep.tsx +++ b/src/components/agents/new-agent-creation/wizard-steps/ConfirmStep.tsx @@ -3,8 +3,8 @@ import { type KeyboardEvent, Box, Byline, KeyboardShortcutHint, Text } from '@an import { useKeybinding } from '../../../../keybindings/useKeybinding.js' import { isAutoMemoryEnabled } from '../../../../memdir/paths.js' import type { Tools } from '../../../../Tool.js' -import { getMemoryScopeDisplay } from '../../../../tools/AgentTool/agentMemory.js' -import type { AgentDefinition } from '../../../../tools/AgentTool/loadAgentsDir.js' +import { getMemoryScopeDisplay } from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { truncateToWidth } from '../../../../utils/format.js' import { getAgentModelDisplay } from '../../../../utils/model/agent.js' import { ConfigurableShortcutHint } from '../../../ConfigurableShortcutHint.js' diff --git a/src/components/agents/new-agent-creation/wizard-steps/ConfirmStepWrapper.tsx b/src/components/agents/new-agent-creation/wizard-steps/ConfirmStepWrapper.tsx index 013de633a..b1e391e7f 100644 --- a/src/components/agents/new-agent-creation/wizard-steps/ConfirmStepWrapper.tsx +++ b/src/components/agents/new-agent-creation/wizard-steps/ConfirmStepWrapper.tsx @@ -6,8 +6,8 @@ import { } from 'src/services/analytics/index.js' import { useSetAppState } from 'src/state/AppState.js' import type { Tools } from '../../../../Tool.js' -import type { AgentDefinition } from '../../../../tools/AgentTool/loadAgentsDir.js' -import { getActiveAgentsFromList } from '../../../../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { getActiveAgentsFromList } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { editFileInEditor } from '../../../../utils/promptEditor.js' import { useWizard } from '../../../wizard/index.js' import { getNewAgentFilePath, saveAgentToFile } from '../../agentFileUtils.js' diff --git a/src/components/agents/new-agent-creation/wizard-steps/MemoryStep.tsx b/src/components/agents/new-agent-creation/wizard-steps/MemoryStep.tsx index d9fb92ed5..317e304d0 100644 --- a/src/components/agents/new-agent-creation/wizard-steps/MemoryStep.tsx +++ b/src/components/agents/new-agent-creation/wizard-steps/MemoryStep.tsx @@ -5,7 +5,7 @@ import { isAutoMemoryEnabled } from '../../../../memdir/paths.js' import { type AgentMemoryScope, loadAgentMemoryPrompt, -} from '../../../../tools/AgentTool/agentMemory.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js' import { ConfigurableShortcutHint } from '../../../ConfigurableShortcutHint.js' import { Select } from '../../../CustomSelect/select.js' import { useWizard } from '../../../wizard/index.js' diff --git a/src/components/agents/new-agent-creation/wizard-steps/TypeStep.tsx b/src/components/agents/new-agent-creation/wizard-steps/TypeStep.tsx index 6c57440c8..59f8fb8da 100644 --- a/src/components/agents/new-agent-creation/wizard-steps/TypeStep.tsx +++ b/src/components/agents/new-agent-creation/wizard-steps/TypeStep.tsx @@ -1,7 +1,7 @@ import React, { type ReactNode, useState } from 'react' import { Box, Byline, KeyboardShortcutHint, Text } from '@anthropic/ink' import { useKeybinding } from '../../../../keybindings/useKeybinding.js' -import type { AgentDefinition } from '../../../../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { ConfigurableShortcutHint } from '../../../ConfigurableShortcutHint.js' import TextInput from '../../../TextInput.js' import { useWizard } from '../../../wizard/index.js' diff --git a/src/components/agents/types.ts b/src/components/agents/types.ts index e8cf05343..8e186f16a 100644 --- a/src/components/agents/types.ts +++ b/src/components/agents/types.ts @@ -1,5 +1,5 @@ import type { SettingSource } from 'src/utils/settings/constants.js' -import type { AgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' export const AGENT_PATHS = { FOLDER_NAME: '.claude', diff --git a/src/components/agents/validateAgent.ts b/src/components/agents/validateAgent.ts index 5e29d0b2a..0958919af 100644 --- a/src/components/agents/validateAgent.ts +++ b/src/components/agents/validateAgent.ts @@ -1,9 +1,9 @@ import type { Tools } from '../../Tool.js' -import { resolveAgentTools } from '../../tools/AgentTool/agentToolUtils.js' +import { resolveAgentTools } from '@claude-code-best/builtin-tools/tools/AgentTool/agentToolUtils.js' import type { AgentDefinition, CustomAgentDefinition, -} from '../../tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { getAgentSourceDisplayName } from './utils.js' export type AgentValidationResult = { diff --git a/src/components/memory/MemoryFileSelector.tsx b/src/components/memory/MemoryFileSelector.tsx index 2d7105917..62d1f0d5b 100644 --- a/src/components/memory/MemoryFileSelector.tsx +++ b/src/components/memory/MemoryFileSelector.tsx @@ -13,7 +13,7 @@ import { logEvent } from '../../services/analytics/index.js' import { isAutoDreamEnabled } from '../../services/autoDream/config.js' import { readLastConsolidatedAt } from '../../services/autoDream/consolidationLock.js' import { useAppState } from '../../state/AppState.js' -import { getAgentMemoryDir } from '../../tools/AgentTool/agentMemory.js' +import { getAgentMemoryDir } from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js' import { openPath } from '../../utils/browser.js' import { getMemoryFiles, type MemoryFileInfo } from '../../utils/claudemd.js' import { getClaudeConfigHomeDir } from '../../utils/envUtils.js' diff --git a/src/components/messages/CollapsedReadSearchContent.tsx b/src/components/messages/CollapsedReadSearchContent.tsx index 57aef23bc..1176eafbb 100644 --- a/src/components/messages/CollapsedReadSearchContent.tsx +++ b/src/components/messages/CollapsedReadSearchContent.tsx @@ -4,7 +4,7 @@ import React, { useRef } from 'react' import { useMinDisplayTime } from '../../hooks/useMinDisplayTime.js' import { Ansi, Box, Text, useTheme } from '@anthropic/ink' import { findToolByName, type Tools } from '../../Tool.js' -import { getReplPrimitiveTools } from '../../tools/REPLTool/primitiveTools.js' +import { getReplPrimitiveTools } from '@claude-code-best/builtin-tools/tools/REPLTool/primitiveTools.js' import type { CollapsedReadSearchGroup, NormalizedAssistantMessage, diff --git a/src/components/messages/UserBashOutputMessage.tsx b/src/components/messages/UserBashOutputMessage.tsx index 99ec8ea7e..1e9afc537 100644 --- a/src/components/messages/UserBashOutputMessage.tsx +++ b/src/components/messages/UserBashOutputMessage.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import BashToolResultMessage from '../../tools/BashTool/BashToolResultMessage.js' +import BashToolResultMessage from '@claude-code-best/builtin-tools/tools/BashTool/BashToolResultMessage.js' import { extractTag } from '../../utils/messages.js' export function UserBashOutputMessage({ diff --git a/src/components/permissions/AskUserQuestionPermissionRequest/AskUserQuestionPermissionRequest.tsx b/src/components/permissions/AskUserQuestionPermissionRequest/AskUserQuestionPermissionRequest.tsx index 562c6653c..c19bce214 100644 --- a/src/components/permissions/AskUserQuestionPermissionRequest/AskUserQuestionPermissionRequest.tsx +++ b/src/components/permissions/AskUserQuestionPermissionRequest/AskUserQuestionPermissionRequest.tsx @@ -19,8 +19,8 @@ import { logEvent, } from '../../../services/analytics/index.js' import { useAppState } from '../../../state/AppState.js' -import type { Question } from '../../../tools/AskUserQuestionTool/AskUserQuestionTool.js' -import { AskUserQuestionTool } from '../../../tools/AskUserQuestionTool/AskUserQuestionTool.js' +import type { Question } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/AskUserQuestionTool.js' +import { AskUserQuestionTool } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/AskUserQuestionTool.js' import { type CliHighlight, getCliHighlightPromise, diff --git a/src/components/permissions/AskUserQuestionPermissionRequest/PreviewQuestionView.tsx b/src/components/permissions/AskUserQuestionPermissionRequest/PreviewQuestionView.tsx index 6e80ce25f..bea9bb103 100644 --- a/src/components/permissions/AskUserQuestionPermissionRequest/PreviewQuestionView.tsx +++ b/src/components/permissions/AskUserQuestionPermissionRequest/PreviewQuestionView.tsx @@ -7,7 +7,7 @@ import { useKeybindings, } from '../../../keybindings/useKeybinding.js' import { useAppState } from '../../../state/AppState.js' -import type { Question } from '../../../tools/AskUserQuestionTool/AskUserQuestionTool.js' +import type { Question } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/AskUserQuestionTool.js' import { getExternalEditor } from '../../../utils/editor.js' import { toIDEDisplayName } from '../../../utils/ide.js' import { editPromptInEditor } from '../../../utils/promptEditor.js' diff --git a/src/components/permissions/AskUserQuestionPermissionRequest/QuestionNavigationBar.tsx b/src/components/permissions/AskUserQuestionPermissionRequest/QuestionNavigationBar.tsx index 082ba086c..c30b584f9 100644 --- a/src/components/permissions/AskUserQuestionPermissionRequest/QuestionNavigationBar.tsx +++ b/src/components/permissions/AskUserQuestionPermissionRequest/QuestionNavigationBar.tsx @@ -2,7 +2,7 @@ import figures from 'figures' import React, { useMemo } from 'react' import { useTerminalSize } from '../../../hooks/useTerminalSize.js' import { Box, Text, stringWidth } from '@anthropic/ink' -import type { Question } from '../../../tools/AskUserQuestionTool/AskUserQuestionTool.js' +import type { Question } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/AskUserQuestionTool.js' import { truncateToWidth } from '../../../utils/format.js' type Props = { diff --git a/src/components/permissions/AskUserQuestionPermissionRequest/QuestionView.tsx b/src/components/permissions/AskUserQuestionPermissionRequest/QuestionView.tsx index ec4aa3ad7..7fc9e6a6f 100644 --- a/src/components/permissions/AskUserQuestionPermissionRequest/QuestionView.tsx +++ b/src/components/permissions/AskUserQuestionPermissionRequest/QuestionView.tsx @@ -5,7 +5,7 @@ import { useAppState } from '../../../state/AppState.js' import type { Question, QuestionOption, -} from '../../../tools/AskUserQuestionTool/AskUserQuestionTool.js' +} from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/AskUserQuestionTool.js' import type { PastedContent } from '../../../utils/config.js' import { getExternalEditor } from '../../../utils/editor.js' import { toIDEDisplayName } from '../../../utils/ide.js' diff --git a/src/components/permissions/AskUserQuestionPermissionRequest/SubmitQuestionsView.tsx b/src/components/permissions/AskUserQuestionPermissionRequest/SubmitQuestionsView.tsx index 37e7e832c..8bb6757b8 100644 --- a/src/components/permissions/AskUserQuestionPermissionRequest/SubmitQuestionsView.tsx +++ b/src/components/permissions/AskUserQuestionPermissionRequest/SubmitQuestionsView.tsx @@ -1,7 +1,7 @@ import figures from 'figures' import React from 'react' import { Box, Text } from '@anthropic/ink' -import type { Question } from '../../../tools/AskUserQuestionTool/AskUserQuestionTool.js' +import type { Question } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/AskUserQuestionTool.js' import type { PermissionDecision } from '../../../utils/permissions/PermissionResult.js' import { Select } from '../../CustomSelect/index.js' import { Divider } from '@anthropic/ink' diff --git a/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx b/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx index fb2c06da9..e37dba10c 100644 --- a/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +++ b/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx @@ -10,14 +10,14 @@ import { } from '../../../services/analytics/index.js' import { sanitizeToolNameForAnalytics } from '../../../services/analytics/metadata.js' import { useAppState } from '../../../state/AppState.js' -import { BashTool } from '../../../tools/BashTool/BashTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' import { getFirstWordPrefix, getSimpleCommandPrefix, -} from '../../../tools/BashTool/bashPermissions.js' -import { getDestructiveCommandWarning } from '../../../tools/BashTool/destructiveCommandWarning.js' -import { parseSedEditCommand } from '../../../tools/BashTool/sedEditParser.js' -import { shouldUseSandbox } from '../../../tools/BashTool/shouldUseSandbox.js' +} from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js' +import { getDestructiveCommandWarning } from '@claude-code-best/builtin-tools/tools/BashTool/destructiveCommandWarning.js' +import { parseSedEditCommand } from '@claude-code-best/builtin-tools/tools/BashTool/sedEditParser.js' +import { shouldUseSandbox } from '@claude-code-best/builtin-tools/tools/BashTool/shouldUseSandbox.js' import { getCompoundCommandPrefixesStatic } from '../../../utils/bash/prefix.js' import { createPromptRuleContent, diff --git a/src/components/permissions/BashPermissionRequest/bashToolUseOptions.tsx b/src/components/permissions/BashPermissionRequest/bashToolUseOptions.tsx index 18d35d062..b6a073ad0 100644 --- a/src/components/permissions/BashPermissionRequest/bashToolUseOptions.tsx +++ b/src/components/permissions/BashPermissionRequest/bashToolUseOptions.tsx @@ -1,4 +1,4 @@ -import { BASH_TOOL_NAME } from '../../../tools/BashTool/toolName.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' import { extractOutputRedirections } from '../../../utils/bash/commands.js' import { isClassifierPermissionsEnabled } from '../../../utils/permissions/bashClassifier.js' import type { PermissionDecisionReason } from '../../../utils/permissions/PermissionResult.js' diff --git a/src/components/permissions/ExitPlanModePermissionRequest/ExitPlanModePermissionRequest.tsx b/src/components/permissions/ExitPlanModePermissionRequest/ExitPlanModePermissionRequest.tsx index 657acf1e3..796ffeeec 100644 --- a/src/components/permissions/ExitPlanModePermissionRequest/ExitPlanModePermissionRequest.tsx +++ b/src/components/permissions/ExitPlanModePermissionRequest/ExitPlanModePermissionRequest.tsx @@ -31,10 +31,10 @@ import { generateSessionName } from '../../../commands/rename/generateSessionNam import { launchUltraplan } from '../../../commands/ultraplan.js' import { type KeyboardEvent, Box, Text } from '@anthropic/ink' import type { AppState } from '../../../state/AppStateStore.js' -import { AGENT_TOOL_NAME } from '../../../tools/AgentTool/constants.js' -import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '../../../tools/ExitPlanModeTool/constants.js' -import type { AllowedPrompt } from '../../../tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' -import { TEAM_CREATE_TOOL_NAME } from '../../../tools/TeamCreateTool/constants.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' +import type { AllowedPrompt } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' +import { TEAM_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamCreateTool/constants.js' import { isAgentSwarmsEnabled } from '../../../utils/agentSwarmsEnabled.js' import { calculateContextPercentages, diff --git a/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx b/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx index 9f8683017..42d558664 100644 --- a/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +++ b/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx @@ -4,7 +4,7 @@ import { FileEditToolDiff } from 'src/components/FileEditToolDiff.js' import { getCwd } from 'src/utils/cwd.js' import type { z } from 'zod/v4' import { Text } from '@anthropic/ink' -import { FileEditTool } from '../../../tools/FileEditTool/FileEditTool.js' +import { FileEditTool } from '@claude-code-best/builtin-tools/tools/FileEditTool/FileEditTool.js' import { FilePermissionDialog } from '../FilePermissionDialog/FilePermissionDialog.js' import { createSingleEditDiffConfig, diff --git a/src/components/permissions/FilePermissionDialog/usePermissionHandler.ts b/src/components/permissions/FilePermissionDialog/usePermissionHandler.ts index 85821cbca..fa7ea5432 100644 --- a/src/components/permissions/FilePermissionDialog/usePermissionHandler.ts +++ b/src/components/permissions/FilePermissionDialog/usePermissionHandler.ts @@ -8,7 +8,7 @@ import { CLAUDE_FOLDER_PERMISSION_PATTERN, FILE_EDIT_TOOL_NAME, GLOBAL_CLAUDE_FOLDER_PERMISSION_PATTERN, -} from '../../../tools/FileEditTool/constants.js' +} from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' import { env } from '../../../utils/env.js' import { generateSuggestions } from '../../../utils/permissions/filesystem.js' import type { PermissionUpdate } from '../../../utils/permissions/PermissionUpdateSchema.js' diff --git a/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx b/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx index 744673193..f6146f705 100644 --- a/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +++ b/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx @@ -2,7 +2,7 @@ import { basename, relative } from 'path' import React, { useMemo } from 'react' import type { z } from 'zod/v4' import { Text } from '@anthropic/ink' -import { FileWriteTool } from '../../../tools/FileWriteTool/FileWriteTool.js' +import { FileWriteTool } from '@claude-code-best/builtin-tools/tools/FileWriteTool/FileWriteTool.js' import { getCwd } from '../../../utils/cwd.js' import { isENOENT } from '../../../utils/errors.js' import { readFileSync } from '../../../utils/fileRead.js' diff --git a/src/components/permissions/NotebookEditPermissionRequest/NotebookEditPermissionRequest.tsx b/src/components/permissions/NotebookEditPermissionRequest/NotebookEditPermissionRequest.tsx index 9ebc09642..ab2c94393 100644 --- a/src/components/permissions/NotebookEditPermissionRequest/NotebookEditPermissionRequest.tsx +++ b/src/components/permissions/NotebookEditPermissionRequest/NotebookEditPermissionRequest.tsx @@ -2,7 +2,7 @@ import { basename } from 'path' import React from 'react' import type { z } from 'zod/v4' import { Text } from '@anthropic/ink' -import { NotebookEditTool } from '../../../tools/NotebookEditTool/NotebookEditTool.js' +import { NotebookEditTool } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/NotebookEditTool.js' import { logError } from '../../../utils/log.js' import { FilePermissionDialog } from '../FilePermissionDialog/FilePermissionDialog.js' import type { PermissionRequestProps } from '../PermissionRequest.js' diff --git a/src/components/permissions/PermissionRequest.tsx b/src/components/permissions/PermissionRequest.tsx index 53dba4032..a08f78519 100644 --- a/src/components/permissions/PermissionRequest.tsx +++ b/src/components/permissions/PermissionRequest.tsx @@ -1,21 +1,21 @@ import { feature } from 'bun:bundle' import * as React from 'react' -import { EnterPlanModeTool } from 'src/tools/EnterPlanModeTool/EnterPlanModeTool.js' -import { ExitPlanModeV2Tool } from 'src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' +import { EnterPlanModeTool } from '@claude-code-best/builtin-tools/tools/EnterPlanModeTool/EnterPlanModeTool.js' +import { ExitPlanModeV2Tool } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' import { useNotifyAfterTimeout } from '../../hooks/useNotifyAfterTimeout.js' import { useKeybinding } from '../../keybindings/useKeybinding.js' import type { AnyObject, Tool, ToolUseContext } from '../../Tool.js' -import { AskUserQuestionTool } from '../../tools/AskUserQuestionTool/AskUserQuestionTool.js' -import { BashTool } from '../../tools/BashTool/BashTool.js' -import { FileEditTool } from '../../tools/FileEditTool/FileEditTool.js' -import { FileReadTool } from '../../tools/FileReadTool/FileReadTool.js' -import { FileWriteTool } from '../../tools/FileWriteTool/FileWriteTool.js' -import { GlobTool } from '../../tools/GlobTool/GlobTool.js' -import { GrepTool } from '../../tools/GrepTool/GrepTool.js' -import { NotebookEditTool } from '../../tools/NotebookEditTool/NotebookEditTool.js' -import { PowerShellTool } from '../../tools/PowerShellTool/PowerShellTool.js' -import { SkillTool } from '../../tools/SkillTool/SkillTool.js' -import { WebFetchTool } from '../../tools/WebFetchTool/WebFetchTool.js' +import { AskUserQuestionTool } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/AskUserQuestionTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' +import { FileEditTool } from '@claude-code-best/builtin-tools/tools/FileEditTool/FileEditTool.js' +import { FileReadTool } from '@claude-code-best/builtin-tools/tools/FileReadTool/FileReadTool.js' +import { FileWriteTool } from '@claude-code-best/builtin-tools/tools/FileWriteTool/FileWriteTool.js' +import { GlobTool } from '@claude-code-best/builtin-tools/tools/GlobTool/GlobTool.js' +import { GrepTool } from '@claude-code-best/builtin-tools/tools/GrepTool/GrepTool.js' +import { NotebookEditTool } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/NotebookEditTool.js' +import { PowerShellTool } from '@claude-code-best/builtin-tools/tools/PowerShellTool/PowerShellTool.js' +import { SkillTool } from '@claude-code-best/builtin-tools/tools/SkillTool/SkillTool.js' +import { WebFetchTool } from '@claude-code-best/builtin-tools/tools/WebFetchTool/WebFetchTool.js' import type { AssistantMessage } from '../../types/message.js' import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js' import { AskUserQuestionPermissionRequest } from './AskUserQuestionPermissionRequest/AskUserQuestionPermissionRequest.js' @@ -34,7 +34,7 @@ import { WebFetchPermissionRequest } from './WebFetchPermissionRequest/WebFetchP /* eslint-disable @typescript-eslint/no-require-imports */ const ReviewArtifactTool = feature('REVIEW_ARTIFACT') ? ( - require('../../tools/ReviewArtifactTool/ReviewArtifactTool.js') as typeof import('../../tools/ReviewArtifactTool/ReviewArtifactTool.js') + require('@claude-code-best/builtin-tools/tools/ReviewArtifactTool/ReviewArtifactTool.js') as typeof import('@claude-code-best/builtin-tools/tools/ReviewArtifactTool/ReviewArtifactTool.js') ).ReviewArtifactTool : null @@ -46,19 +46,19 @@ const ReviewArtifactPermissionRequest = feature('REVIEW_ARTIFACT') const WorkflowTool = feature('WORKFLOW_SCRIPTS') ? ( - require('../../tools/WorkflowTool/WorkflowTool.js') as typeof import('../../tools/WorkflowTool/WorkflowTool.js') + require('@claude-code-best/builtin-tools/tools/WorkflowTool/WorkflowTool.js') as typeof import('@claude-code-best/builtin-tools/tools/WorkflowTool/WorkflowTool.js') ).WorkflowTool : null const WorkflowPermissionRequest = feature('WORKFLOW_SCRIPTS') ? ( - require('../../tools/WorkflowTool/WorkflowPermissionRequest.js') as typeof import('../../tools/WorkflowTool/WorkflowPermissionRequest.js') + require('@claude-code-best/builtin-tools/tools/WorkflowTool/WorkflowPermissionRequest.js') as typeof import('@claude-code-best/builtin-tools/tools/WorkflowTool/WorkflowPermissionRequest.js') ).WorkflowPermissionRequest : null const MonitorTool = feature('MONITOR_TOOL') ? ( - require('../../tools/MonitorTool/MonitorTool.js') as typeof import('../../tools/MonitorTool/MonitorTool.js') + require('@claude-code-best/builtin-tools/tools/MonitorTool/MonitorTool.js') as typeof import('@claude-code-best/builtin-tools/tools/MonitorTool/MonitorTool.js') ).MonitorTool : null diff --git a/src/components/permissions/PowerShellPermissionRequest/PowerShellPermissionRequest.tsx b/src/components/permissions/PowerShellPermissionRequest/PowerShellPermissionRequest.tsx index 16183ec79..3aec521d5 100644 --- a/src/components/permissions/PowerShellPermissionRequest/PowerShellPermissionRequest.tsx +++ b/src/components/permissions/PowerShellPermissionRequest/PowerShellPermissionRequest.tsx @@ -7,9 +7,9 @@ import { logEvent, } from '../../../services/analytics/index.js' import { sanitizeToolNameForAnalytics } from '../../../services/analytics/metadata.js' -import { getDestructiveCommandWarning } from '../../../tools/PowerShellTool/destructiveCommandWarning.js' -import { PowerShellTool } from '../../../tools/PowerShellTool/PowerShellTool.js' -import { isAllowlistedCommand } from '../../../tools/PowerShellTool/readOnlyValidation.js' +import { getDestructiveCommandWarning } from '@claude-code-best/builtin-tools/tools/PowerShellTool/destructiveCommandWarning.js' +import { PowerShellTool } from '@claude-code-best/builtin-tools/tools/PowerShellTool/PowerShellTool.js' +import { isAllowlistedCommand } from '@claude-code-best/builtin-tools/tools/PowerShellTool/readOnlyValidation.js' import type { PermissionUpdate } from '../../../utils/permissions/PermissionUpdateSchema.js' import { getCompoundCommandPrefixesStatic } from '../../../utils/powershell/staticPrefix.js' import { Select } from '../../CustomSelect/select.js' diff --git a/src/components/permissions/PowerShellPermissionRequest/powershellToolUseOptions.tsx b/src/components/permissions/PowerShellPermissionRequest/powershellToolUseOptions.tsx index 2ad089efe..f09caf185 100644 --- a/src/components/permissions/PowerShellPermissionRequest/powershellToolUseOptions.tsx +++ b/src/components/permissions/PowerShellPermissionRequest/powershellToolUseOptions.tsx @@ -1,4 +1,4 @@ -import { POWERSHELL_TOOL_NAME } from '../../../tools/PowerShellTool/toolName.js' +import { POWERSHELL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/PowerShellTool/toolName.js' import type { PermissionUpdate } from '../../../utils/permissions/PermissionUpdateSchema.js' import { shouldShowAlwaysAllowOptions } from '../../../utils/permissions/permissionsLoader.js' import type { OptionWithDescription } from '../../CustomSelect/select.js' diff --git a/src/components/permissions/SedEditPermissionRequest/SedEditPermissionRequest.tsx b/src/components/permissions/SedEditPermissionRequest/SedEditPermissionRequest.tsx index 2135b5e22..4ccd2da67 100644 --- a/src/components/permissions/SedEditPermissionRequest/SedEditPermissionRequest.tsx +++ b/src/components/permissions/SedEditPermissionRequest/SedEditPermissionRequest.tsx @@ -6,11 +6,11 @@ import { isENOENT } from 'src/utils/errors.js' import { detectEncodingForResolvedPath } from 'src/utils/fileRead.js' import { getFsImplementation } from 'src/utils/fsOperations.js' import { Text } from '@anthropic/ink' -import { BashTool } from '../../../tools/BashTool/BashTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' import { applySedSubstitution, type SedEditInfo, -} from '../../../tools/BashTool/sedEditParser.js' +} from '@claude-code-best/builtin-tools/tools/BashTool/sedEditParser.js' import { FilePermissionDialog } from '../FilePermissionDialog/FilePermissionDialog.js' import type { PermissionRequestProps } from '../PermissionRequest.js' diff --git a/src/components/permissions/SkillPermissionRequest/SkillPermissionRequest.tsx b/src/components/permissions/SkillPermissionRequest/SkillPermissionRequest.tsx index bd73023dd..234f7d970 100644 --- a/src/components/permissions/SkillPermissionRequest/SkillPermissionRequest.tsx +++ b/src/components/permissions/SkillPermissionRequest/SkillPermissionRequest.tsx @@ -3,8 +3,8 @@ import { logError } from 'src/utils/log.js' import { getOriginalCwd } from '../../../bootstrap/state.js' import { Box, Text } from '@anthropic/ink' import { sanitizeToolNameForAnalytics } from '../../../services/analytics/metadata.js' -import { SKILL_TOOL_NAME } from '../../../tools/SkillTool/constants.js' -import { SkillTool } from '../../../tools/SkillTool/SkillTool.js' +import { SKILL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SkillTool/constants.js' +import { SkillTool } from '@claude-code-best/builtin-tools/tools/SkillTool/SkillTool.js' import { env } from '../../../utils/env.js' import { shouldShowAlwaysAllowOptions } from '../../../utils/permissions/permissionsLoader.js' import { logUnaryEvent } from '../../../utils/unaryLogging.js' diff --git a/src/components/permissions/WebFetchPermissionRequest/WebFetchPermissionRequest.tsx b/src/components/permissions/WebFetchPermissionRequest/WebFetchPermissionRequest.tsx index 5e0625498..f91f3431b 100644 --- a/src/components/permissions/WebFetchPermissionRequest/WebFetchPermissionRequest.tsx +++ b/src/components/permissions/WebFetchPermissionRequest/WebFetchPermissionRequest.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from 'react' import { Box, Text, useTheme } from '@anthropic/ink' -import { WebFetchTool } from '../../../tools/WebFetchTool/WebFetchTool.js' +import { WebFetchTool } from '@claude-code-best/builtin-tools/tools/WebFetchTool/WebFetchTool.js' import { shouldShowAlwaysAllowOptions } from '../../../utils/permissions/permissionsLoader.js' import { type OptionWithDescription, diff --git a/src/components/permissions/hooks.ts b/src/components/permissions/hooks.ts index e037083db..16dee0a64 100644 --- a/src/components/permissions/hooks.ts +++ b/src/components/permissions/hooks.ts @@ -5,7 +5,7 @@ import { logEvent, } from 'src/services/analytics/index.js' import { sanitizeToolNameForAnalytics } from 'src/services/analytics/metadata.js' -import { BashTool } from 'src/tools/BashTool/BashTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' import { splitCommand_DEPRECATED } from 'src/utils/bash/commands.js' import type { PermissionDecisionReason, diff --git a/src/components/permissions/rules/PermissionRuleDescription.tsx b/src/components/permissions/rules/PermissionRuleDescription.tsx index d4591b8d9..597fc4b09 100644 --- a/src/components/permissions/rules/PermissionRuleDescription.tsx +++ b/src/components/permissions/rules/PermissionRuleDescription.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { Text } from '@anthropic/ink' -import { BashTool } from '../../../tools/BashTool/BashTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' import type { PermissionRuleValue } from '../../../utils/permissions/PermissionRule.js' type RuleSubtitleProps = { diff --git a/src/components/permissions/rules/PermissionRuleInput.tsx b/src/components/permissions/rules/PermissionRuleInput.tsx index fae8553d9..599263197 100644 --- a/src/components/permissions/rules/PermissionRuleInput.tsx +++ b/src/components/permissions/rules/PermissionRuleInput.tsx @@ -6,8 +6,8 @@ import { useExitOnCtrlCDWithKeybindings } from '../../../hooks/useExitOnCtrlCDWi import { useTerminalSize } from '../../../hooks/useTerminalSize.js' import { Box, Newline, Text } from '@anthropic/ink' import { useKeybinding } from '../../../keybindings/useKeybinding.js' -import { BashTool } from '../../../tools/BashTool/BashTool.js' -import { WebFetchTool } from '../../../tools/WebFetchTool/WebFetchTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' +import { WebFetchTool } from '@claude-code-best/builtin-tools/tools/WebFetchTool/WebFetchTool.js' import type { PermissionBehavior, PermissionRuleValue, diff --git a/src/components/tasks/BackgroundTaskStatus.tsx b/src/components/tasks/BackgroundTaskStatus.tsx index c315bfa90..4813c86eb 100644 --- a/src/components/tasks/BackgroundTaskStatus.tsx +++ b/src/components/tasks/BackgroundTaskStatus.tsx @@ -21,7 +21,7 @@ import { AGENT_COLOR_TO_THEME_COLOR, AGENT_COLORS, type AgentColorName, -} from '../../tools/AgentTool/agentColorManager.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import type { Theme } from '../../utils/theme.js' import { KeyboardShortcutHint } from '@anthropic/ink' import { shouldHideTasksFooter } from './taskStatusUtils.js' diff --git a/src/components/tasks/RemoteSessionDetailDialog.tsx b/src/components/tasks/RemoteSessionDetailDialog.tsx index f21291b5e..5e45dfbb5 100644 --- a/src/components/tasks/RemoteSessionDetailDialog.tsx +++ b/src/components/tasks/RemoteSessionDetailDialog.tsx @@ -12,9 +12,9 @@ import { getRemoteTaskSessionUrl } from '../../tasks/RemoteAgentTask/RemoteAgent import { AGENT_TOOL_NAME, LEGACY_AGENT_TOOL_NAME, -} from '../../tools/AgentTool/constants.js' -import { ASK_USER_QUESTION_TOOL_NAME } from '../../tools/AskUserQuestionTool/prompt.js' -import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '../../tools/ExitPlanModeTool/constants.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { ASK_USER_QUESTION_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/prompt.js' +import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' import { openBrowser } from '../../utils/browser.js' import { errorMessage } from '../../utils/errors.js' import { formatDuration, truncateToWidth } from '../../utils/format.js' diff --git a/src/components/teams/TeamsDialog.tsx b/src/components/teams/TeamsDialog.tsx index a21caaebe..48019d6e0 100644 --- a/src/components/teams/TeamsDialog.tsx +++ b/src/components/teams/TeamsDialog.tsx @@ -14,7 +14,7 @@ import { useSetAppState, } from '../../state/AppState.js' import { getEmptyToolPermissionContext } from '../../Tool.js' -import { AGENT_COLOR_TO_THEME_COLOR } from '../../tools/AgentTool/agentColorManager.js' +import { AGENT_COLOR_TO_THEME_COLOR } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { logForDebugging } from '../../utils/debug.js' import { execFileNoThrow } from '../../utils/execFileNoThrow.js' import { truncateToWidth } from '../../utils/format.js' diff --git a/src/constants/prompts.ts b/src/constants/prompts.ts index 02b6a2289..1145207c4 100644 --- a/src/constants/prompts.ts +++ b/src/constants/prompts.ts @@ -10,51 +10,51 @@ import { getInitialSettings } from '../utils/settings/settings.js' import { AGENT_TOOL_NAME, VERIFICATION_AGENT_TYPE, -} from '../tools/AgentTool/constants.js' -import { FILE_WRITE_TOOL_NAME } from '../tools/FileWriteTool/prompt.js' -import { FILE_READ_TOOL_NAME } from '../tools/FileReadTool/prompt.js' -import { FILE_EDIT_TOOL_NAME } from '../tools/FileEditTool/constants.js' -import { TODO_WRITE_TOOL_NAME } from '../tools/TodoWriteTool/constants.js' -import { TASK_CREATE_TOOL_NAME } from '../tools/TaskCreateTool/constants.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { TODO_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TodoWriteTool/constants.js' +import { TASK_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskCreateTool/constants.js' import type { Tools } from '../Tool.js' import type { Command } from '../types/command.js' -import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' import { getCanonicalName, getMarketingNameForModel, } from '../utils/model/model.js' import { getSkillToolCommands } from 'src/commands.js' -import { SKILL_TOOL_NAME } from '../tools/SkillTool/constants.js' +import { SKILL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SkillTool/constants.js' import { getOutputStyleConfig } from './outputStyles.js' import type { MCPServerConnection, ConnectedMCPServer, } from '../services/mcp/types.js' -import { GLOB_TOOL_NAME } from 'src/tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from 'src/tools/GrepTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' import { hasEmbeddedSearchTools } from 'src/utils/embeddedTools.js' -import { ASK_USER_QUESTION_TOOL_NAME } from '../tools/AskUserQuestionTool/prompt.js' +import { ASK_USER_QUESTION_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/prompt.js' import { EXPLORE_AGENT, EXPLORE_AGENT_MIN_QUERIES, -} from 'src/tools/AgentTool/built-in/exploreAgent.js' -import { areExplorePlanAgentsEnabled } from 'src/tools/AgentTool/builtInAgents.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/built-in/exploreAgent.js' +import { areExplorePlanAgentsEnabled } from '@claude-code-best/builtin-tools/tools/AgentTool/builtInAgents.js' import { isScratchpadEnabled, getScratchpadDir, } from '../utils/permissions/filesystem.js' import { isEnvTruthy } from '../utils/envUtils.js' -import { isReplModeEnabled } from '../tools/REPLTool/constants.js' +import { isReplModeEnabled } from '@claude-code-best/builtin-tools/tools/REPLTool/constants.js' import { feature } from 'bun:bundle' import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' import { shouldUseGlobalCacheScope } from '../utils/betas.js' -import { isForkSubagentEnabled } from '../tools/AgentTool/forkSubagent.js' +import { isForkSubagentEnabled } from '@claude-code-best/builtin-tools/tools/AgentTool/forkSubagent.js' import { systemPromptSection, DANGEROUS_uncachedSystemPromptSection, resolveSystemPromptSections, } from './systemPromptSections.js' -import { SLEEP_TOOL_NAME } from '../tools/SleepTool/prompt.js' +import { SLEEP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SleepTool/prompt.js' import { TICK_TAG } from './xml.js' import { logForDebugging } from '../utils/debug.js' import { loadMemoryPrompt } from '../memdir/memdir.js' @@ -77,18 +77,18 @@ const proactiveModule = const BRIEF_PROACTIVE_SECTION: string | null = feature('KAIROS') || feature('KAIROS_BRIEF') ? ( - require('../tools/BriefTool/prompt.js') as typeof import('../tools/BriefTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') ).BRIEF_PROACTIVE_SECTION : null const briefToolModule = feature('KAIROS') || feature('KAIROS_BRIEF') - ? (require('../tools/BriefTool/BriefTool.js') as typeof import('../tools/BriefTool/BriefTool.js')) + ? (require('@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js') as typeof import('@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js')) : null const DISCOVER_SKILLS_TOOL_NAME: string | null = feature( 'EXPERIMENTAL_SKILL_SEARCH', ) ? ( - require('../tools/DiscoverSkillsTool/prompt.js') as typeof import('../tools/DiscoverSkillsTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/DiscoverSkillsTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/DiscoverSkillsTool/prompt.js') ).DISCOVER_SKILLS_TOOL_NAME : null // Capture the module (not .isSkillSearchEnabled directly) so spyOn() in tests diff --git a/src/constants/tools.ts b/src/constants/tools.ts index 114f7e909..063558802 100644 --- a/src/constants/tools.ts +++ b/src/constants/tools.ts @@ -1,37 +1,37 @@ // biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered import { feature } from 'bun:bundle' -import { TASK_OUTPUT_TOOL_NAME } from '../tools/TaskOutputTool/constants.js' -import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '../tools/ExitPlanModeTool/constants.js' -import { ENTER_PLAN_MODE_TOOL_NAME } from '../tools/EnterPlanModeTool/constants.js' -import { AGENT_TOOL_NAME } from '../tools/AgentTool/constants.js' -import { ASK_USER_QUESTION_TOOL_NAME } from '../tools/AskUserQuestionTool/prompt.js' -import { TASK_STOP_TOOL_NAME } from '../tools/TaskStopTool/prompt.js' -import { FILE_READ_TOOL_NAME } from '../tools/FileReadTool/prompt.js' -import { WEB_SEARCH_TOOL_NAME } from '../tools/WebSearchTool/prompt.js' -import { TODO_WRITE_TOOL_NAME } from '../tools/TodoWriteTool/constants.js' -import { GREP_TOOL_NAME } from '../tools/GrepTool/prompt.js' -import { WEB_FETCH_TOOL_NAME } from '../tools/WebFetchTool/prompt.js' -import { GLOB_TOOL_NAME } from '../tools/GlobTool/prompt.js' +import { TASK_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskOutputTool/constants.js' +import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' +import { ENTER_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/EnterPlanModeTool/constants.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { ASK_USER_QUESTION_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/prompt.js' +import { TASK_STOP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskStopTool/prompt.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { WEB_SEARCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebSearchTool/prompt.js' +import { TODO_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TodoWriteTool/constants.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' import { SHELL_TOOL_NAMES } from '../utils/shell/shellToolUtils.js' -import { FILE_EDIT_TOOL_NAME } from '../tools/FileEditTool/constants.js' -import { FILE_WRITE_TOOL_NAME } from '../tools/FileWriteTool/prompt.js' -import { NOTEBOOK_EDIT_TOOL_NAME } from '../tools/NotebookEditTool/constants.js' -import { SKILL_TOOL_NAME } from '../tools/SkillTool/constants.js' -import { SEND_MESSAGE_TOOL_NAME } from '../tools/SendMessageTool/constants.js' -import { TASK_CREATE_TOOL_NAME } from '../tools/TaskCreateTool/constants.js' -import { TASK_GET_TOOL_NAME } from '../tools/TaskGetTool/constants.js' -import { TASK_LIST_TOOL_NAME } from '../tools/TaskListTool/constants.js' -import { TASK_UPDATE_TOOL_NAME } from '../tools/TaskUpdateTool/constants.js' -import { TOOL_SEARCH_TOOL_NAME } from '../tools/ToolSearchTool/prompt.js' -import { SYNTHETIC_OUTPUT_TOOL_NAME } from '../tools/SyntheticOutputTool/SyntheticOutputTool.js' -import { ENTER_WORKTREE_TOOL_NAME } from '../tools/EnterWorktreeTool/constants.js' -import { EXIT_WORKTREE_TOOL_NAME } from '../tools/ExitWorktreeTool/constants.js' -import { WORKFLOW_TOOL_NAME } from '../tools/WorkflowTool/constants.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js' +import { SKILL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SkillTool/constants.js' +import { SEND_MESSAGE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SendMessageTool/constants.js' +import { TASK_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskCreateTool/constants.js' +import { TASK_GET_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskGetTool/constants.js' +import { TASK_LIST_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskListTool/constants.js' +import { TASK_UPDATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskUpdateTool/constants.js' +import { TOOL_SEARCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ToolSearchTool/prompt.js' +import { SYNTHETIC_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SyntheticOutputTool/SyntheticOutputTool.js' +import { ENTER_WORKTREE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/EnterWorktreeTool/constants.js' +import { EXIT_WORKTREE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitWorktreeTool/constants.js' +import { WORKFLOW_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WorkflowTool/constants.js' import { CRON_CREATE_TOOL_NAME, CRON_DELETE_TOOL_NAME, CRON_LIST_TOOL_NAME, -} from '../tools/ScheduleCronTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/ScheduleCronTool/prompt.js' export const ALL_AGENT_DISALLOWED_TOOLS = new Set([ TASK_OUTPUT_TOOL_NAME, diff --git a/src/coordinator/coordinatorMode.ts b/src/coordinator/coordinatorMode.ts index fc5dc4eb1..a1a99f928 100644 --- a/src/coordinator/coordinatorMode.ts +++ b/src/coordinator/coordinatorMode.ts @@ -5,15 +5,15 @@ import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, } from '../services/analytics/index.js' -import { AGENT_TOOL_NAME } from '../tools/AgentTool/constants.js' -import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js' -import { FILE_EDIT_TOOL_NAME } from '../tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from '../tools/FileReadTool/prompt.js' -import { SEND_MESSAGE_TOOL_NAME } from '../tools/SendMessageTool/constants.js' -import { SYNTHETIC_OUTPUT_TOOL_NAME } from '../tools/SyntheticOutputTool/SyntheticOutputTool.js' -import { TASK_STOP_TOOL_NAME } from '../tools/TaskStopTool/prompt.js' -import { TEAM_CREATE_TOOL_NAME } from '../tools/TeamCreateTool/constants.js' -import { TEAM_DELETE_TOOL_NAME } from '../tools/TeamDeleteTool/constants.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { SEND_MESSAGE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SendMessageTool/constants.js' +import { SYNTHETIC_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SyntheticOutputTool/SyntheticOutputTool.js' +import { TASK_STOP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskStopTool/prompt.js' +import { TEAM_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamCreateTool/constants.js' +import { TEAM_DELETE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamDeleteTool/constants.js' import { isEnvTruthy } from '../utils/envUtils.js' // Checks the same gate as isScratchpadEnabled() in diff --git a/src/coordinator/workerAgent.ts b/src/coordinator/workerAgent.ts index b39ee8b98..699daedbf 100644 --- a/src/coordinator/workerAgent.ts +++ b/src/coordinator/workerAgent.ts @@ -11,11 +11,11 @@ * and verify autonomously. */ import { ASYNC_AGENT_ALLOWED_TOOLS } from '../constants/tools.js' -import { SEND_MESSAGE_TOOL_NAME } from '../tools/SendMessageTool/constants.js' -import { SYNTHETIC_OUTPUT_TOOL_NAME } from '../tools/SyntheticOutputTool/SyntheticOutputTool.js' -import { TEAM_CREATE_TOOL_NAME } from '../tools/TeamCreateTool/constants.js' -import { TEAM_DELETE_TOOL_NAME } from '../tools/TeamDeleteTool/constants.js' -import type { BuiltInAgentDefinition } from '../tools/AgentTool/loadAgentsDir.js' +import { SEND_MESSAGE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SendMessageTool/constants.js' +import { SYNTHETIC_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SyntheticOutputTool/SyntheticOutputTool.js' +import { TEAM_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamCreateTool/constants.js' +import { TEAM_DELETE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamDeleteTool/constants.js' +import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' /** * Tools that workers must NOT have — these are coordinator-only diff --git a/src/dialogLaunchers.tsx b/src/dialogLaunchers.tsx index e39c42119..ace8548a3 100644 --- a/src/dialogLaunchers.tsx +++ b/src/dialogLaunchers.tsx @@ -13,7 +13,7 @@ import type { Root } from '@anthropic/ink' import { renderAndRun, showSetupDialog } from './interactiveHelpers.js' import { KeybindingSetup } from './keybindings/KeybindingProviderSetup.js' import type { AppState } from './state/AppStateStore.js' -import type { AgentMemoryScope } from './tools/AgentTool/agentMemory.js' +import type { AgentMemoryScope } from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js' import type { TeleportRemoteResponse } from './utils/conversationRecovery.js' import type { FpsMetrics } from './utils/fpsTracker.js' import type { ValidationError } from './utils/settings/validation.js' diff --git a/src/hooks/toolPermission/PermissionContext.ts b/src/hooks/toolPermission/PermissionContext.ts index 21d6020a1..c799db1ee 100644 --- a/src/hooks/toolPermission/PermissionContext.ts +++ b/src/hooks/toolPermission/PermissionContext.ts @@ -11,8 +11,8 @@ import type { Tool as ToolType, ToolUseContext, } from '../../Tool.js' -import { awaitClassifierAutoApproval } from '../../tools/BashTool/bashPermissions.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' +import { awaitClassifierAutoApproval } from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' import type { AssistantMessage } from '../../types/message.js' import type { PendingClassifierCheck, diff --git a/src/hooks/toolPermission/handlers/interactiveHandler.ts b/src/hooks/toolPermission/handlers/interactiveHandler.ts index f504c6bed..8255d5d87 100644 --- a/src/hooks/toolPermission/handlers/interactiveHandler.ts +++ b/src/hooks/toolPermission/handlers/interactiveHandler.ts @@ -17,8 +17,8 @@ import { shortRequestId, truncateForPreview, } from '../../../services/mcp/channelPermissions.js' -import { executeAsyncClassifierCheck } from '../../../tools/BashTool/bashPermissions.js' -import { BASH_TOOL_NAME } from '../../../tools/BashTool/toolName.js' +import { executeAsyncClassifierCheck } from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' import { clearClassifierChecking, setClassifierApproval, diff --git a/src/hooks/unifiedSuggestions.ts b/src/hooks/unifiedSuggestions.ts index 9fdd5a44e..f6b822c7d 100644 --- a/src/hooks/unifiedSuggestions.ts +++ b/src/hooks/unifiedSuggestions.ts @@ -3,8 +3,8 @@ import { basename } from 'path' import type { SuggestionItem } from 'src/components/PromptInput/PromptInputFooterSuggestions.js' import { generateFileSuggestions } from 'src/hooks/fileSuggestions.js' import type { ServerResource } from 'src/services/mcp/types.js' -import { getAgentColor } from 'src/tools/AgentTool/agentColorManager.js' -import type { AgentDefinition } from 'src/tools/AgentTool/loadAgentsDir.js' +import { getAgentColor } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { truncateToWidth } from 'src/utils/format.js' import { logError } from 'src/utils/log.js' import type { Theme } from 'src/utils/theme.js' diff --git a/src/hooks/useCanUseTool.tsx b/src/hooks/useCanUseTool.tsx index 8f76743b7..7a3df0ab0 100644 --- a/src/hooks/useCanUseTool.tsx +++ b/src/hooks/useCanUseTool.tsx @@ -17,8 +17,8 @@ import type { import { consumeSpeculativeClassifierCheck, peekSpeculativeClassifierCheck, -} from '../tools/BashTool/bashPermissions.js' -import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js' +} from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' import type { AssistantMessage } from '../types/message.js' import { recordAutoModeDenial } from '../utils/autoModeDenials.js' import { diff --git a/src/hooks/useDiffInIDE.ts b/src/hooks/useDiffInIDE.ts index 8fb0d106f..ba7fe8b9f 100644 --- a/src/hooks/useDiffInIDE.ts +++ b/src/hooks/useDiffInIDE.ts @@ -11,11 +11,11 @@ import type { McpWebSocketIDEServerConfig, } from '../services/mcp/types.js' import type { ToolUseContext } from '../Tool.js' -import type { FileEdit } from '../tools/FileEditTool/types.js' +import type { FileEdit } from '@claude-code-best/builtin-tools/tools/FileEditTool/types.js' import { getEditsForPatch, getPatchForEdits, -} from '../tools/FileEditTool/utils.js' +} from '@claude-code-best/builtin-tools/tools/FileEditTool/utils.js' import { getGlobalConfig } from '../utils/config.js' import { getPatchFromContents } from '../utils/diff.js' import { isENOENT } from '../utils/errors.js' diff --git a/src/hooks/useGlobalKeybindings.tsx b/src/hooks/useGlobalKeybindings.tsx index 1dd171cb8..5668748fc 100644 --- a/src/hooks/useGlobalKeybindings.tsx +++ b/src/hooks/useGlobalKeybindings.tsx @@ -104,7 +104,7 @@ export function GlobalKeybindingHandlers({ // isBriefOnly (Messages.tsx filter is gated on !isTranscriptMode). /* eslint-disable @typescript-eslint/no-require-imports */ const { isBriefEnabled } = - require('../tools/BriefTool/BriefTool.js') as typeof import('../tools/BriefTool/BriefTool.js') + require('@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js') as typeof import('@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js') /* eslint-enable @typescript-eslint/no-require-imports */ if (!isBriefEnabled() && isBriefOnly && screen !== 'transcript') { setAppState(prev => { @@ -177,7 +177,7 @@ export function GlobalKeybindingHandlers({ if (feature('KAIROS') || feature('KAIROS_BRIEF')) { /* eslint-disable @typescript-eslint/no-require-imports */ const { isBriefEnabled } = - require('../tools/BriefTool/BriefTool.js') as typeof import('../tools/BriefTool/BriefTool.js') + require('@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js') as typeof import('@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js') /* eslint-enable @typescript-eslint/no-require-imports */ if (!isBriefEnabled() && !isBriefOnly) return const next = !isBriefOnly diff --git a/src/hooks/useIssueFlagBanner.ts b/src/hooks/useIssueFlagBanner.ts index da4f07527..c21789cec 100644 --- a/src/hooks/useIssueFlagBanner.ts +++ b/src/hooks/useIssueFlagBanner.ts @@ -1,5 +1,5 @@ import { useMemo, useRef } from 'react' -import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' import type { Message } from '../types/message.js' import { getUserMessageText } from '../utils/messages.js' diff --git a/src/hooks/useManagePlugins.ts b/src/hooks/useManagePlugins.ts index 5029f45c1..6e230b252 100644 --- a/src/hooks/useManagePlugins.ts +++ b/src/hooks/useManagePlugins.ts @@ -7,7 +7,7 @@ import { } from '../services/analytics/index.js' import { reinitializeLspServerManager } from '../services/lsp/manager.js' import { useAppState, useSetAppState } from '../state/AppState.js' -import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { count } from '../utils/array.js' import { logForDebugging } from '../utils/debug.js' import { logForDiagnosticsNoPII } from '../utils/diagLogs.js' diff --git a/src/hooks/useScheduledTasks.ts b/src/hooks/useScheduledTasks.ts index eaf47e24d..1bdff1223 100644 --- a/src/hooks/useScheduledTasks.ts +++ b/src/hooks/useScheduledTasks.ts @@ -5,7 +5,7 @@ import { findTeammateTaskByAgentId, injectUserMessageToTeammate, } from '../tasks/InProcessTeammateTask/InProcessTeammateTask.js' -import { isKairosCronEnabled } from '../tools/ScheduleCronTool/prompt.js' +import { isKairosCronEnabled } from '@claude-code-best/builtin-tools/tools/ScheduleCronTool/prompt.js' import type { Message } from '../types/message.js' import { getCronJitterConfig } from '../utils/cronJitterConfig.js' import { createCronScheduler } from '../utils/cronScheduler.js' diff --git a/src/hooks/useTurnDiffs.ts b/src/hooks/useTurnDiffs.ts index c78ff59af..5913d5471 100644 --- a/src/hooks/useTurnDiffs.ts +++ b/src/hooks/useTurnDiffs.ts @@ -1,7 +1,7 @@ import type { StructuredPatchHunk } from 'diff' import { useMemo, useRef } from 'react' -import type { FileEditOutput } from '../tools/FileEditTool/types.js' -import type { Output as FileWriteOutput } from '../tools/FileWriteTool/FileWriteTool.js' +import type { FileEditOutput } from '@claude-code-best/builtin-tools/tools/FileEditTool/types.js' +import type { Output as FileWriteOutput } from '@claude-code-best/builtin-tools/tools/FileWriteTool/FileWriteTool.js' import type { Message } from '../types/message.js' export type TurnFileDiff = { diff --git a/src/hooks/useTypeahead.tsx b/src/hooks/useTypeahead.tsx index 62834c4d8..6625586d3 100644 --- a/src/hooks/useTypeahead.tsx +++ b/src/hooks/useTypeahead.tsx @@ -14,7 +14,7 @@ import { useOptionalKeybindingContext, useRegisterKeybindingContext } from '../k import { useKeybindings } from '../keybindings/useKeybinding.js'; import { useShortcutDisplay } from '../keybindings/useShortcutDisplay.js'; import { useAppState, useAppStateStore } from '../state/AppState.js'; -import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js'; +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'; import type { InlineGhostText, PromptInputMode } from '../types/textInputTypes.js'; import { isAgentSwarmsEnabled } from '../utils/agentSwarmsEnabled.js'; import { generateProgressiveArgumentHint, parseArguments } from '../utils/argumentSubstitution.js'; diff --git a/src/main.tsx b/src/main.tsx index fe1fe65ce..58f278b01 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -75,7 +75,7 @@ import type { ToolInputJSONSchema } from "./Tool.js"; import { createSyntheticOutputTool, isSyntheticOutputToolEnabled, -} from "./tools/SyntheticOutputTool/SyntheticOutputTool.js"; +} from "@claude-code-best/builtin-tools/tools/SyntheticOutputTool/SyntheticOutputTool.js"; import { getTools } from "./tools.js"; import { canUserConfigureAdvisor, @@ -192,14 +192,14 @@ import { VALID_UPDATE_SCOPES, } from "./services/plugins/pluginCliCommands.js"; import { initBundledSkills } from "./skills/bundled/index.js"; -import type { AgentColorName } from "./tools/AgentTool/agentColorManager.js"; +import type { AgentColorName } from "@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js"; import { getActiveAgentsFromList, getAgentDefinitionsWithOverrides, isBuiltInAgent, isCustomAgent, parseAgentsFromJson, -} from "./tools/AgentTool/loadAgentsDir.js"; +} from "@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js"; import type { LogOption } from "./types/logs.js"; import type { Message as MessageType } from "./types/message.js"; import { @@ -2674,9 +2674,9 @@ async function run(): Promise { ) { /* eslint-disable @typescript-eslint/no-require-imports */ const { BRIEF_TOOL_NAME, LEGACY_BRIEF_TOOL_NAME } = - require("./tools/BriefTool/prompt.js") as typeof import("./tools/BriefTool/prompt.js"); + require("@claude-code-best/builtin-tools/tools/BriefTool/prompt.js") as typeof import("@claude-code-best/builtin-tools/tools/BriefTool/prompt.js"); const { isBriefEntitled } = - require("./tools/BriefTool/BriefTool.js") as typeof import("./tools/BriefTool/BriefTool.js"); + require("@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js") as typeof import("@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js"); /* eslint-enable @typescript-eslint/no-require-imports */ const parsed = parseToolListFromCLI(baseTools); if ( @@ -3320,7 +3320,7 @@ async function run(): Promise { ) { /* eslint-disable @typescript-eslint/no-require-imports */ const { isBriefEntitled } = - require("./tools/BriefTool/BriefTool.js") as typeof import("./tools/BriefTool/BriefTool.js"); + require("@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js") as typeof import("@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js"); /* eslint-enable @typescript-eslint/no-require-imports */ if (isBriefEntitled()) { setUserMsgOptIn(true); @@ -3339,7 +3339,7 @@ async function run(): Promise { const briefVisibility = feature("KAIROS") || feature("KAIROS_BRIEF") ? ( - require("./tools/BriefTool/BriefTool.js") as typeof import("./tools/BriefTool/BriefTool.js") + require("@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js") as typeof import("@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js") ).isBriefEnabled() ? "Call SendUserMessage at checkpoints to mark where things stand." : "The user will see any text you output." @@ -6909,7 +6909,7 @@ function maybeActivateBrief(options: unknown): void { // into external builds via BriefTool.ts → prompt.ts. /* eslint-disable @typescript-eslint/no-require-imports */ const { isBriefEntitled } = - require("./tools/BriefTool/BriefTool.js") as typeof import("./tools/BriefTool/BriefTool.js"); + require("@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js") as typeof import("@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js"); /* eslint-enable @typescript-eslint/no-require-imports */ const entitled = isBriefEntitled(); if (entitled) { diff --git a/src/memdir/memdir.ts b/src/memdir/memdir.ts index 1e7e68b55..d8d3edfbe 100644 --- a/src/memdir/memdir.ts +++ b/src/memdir/memdir.ts @@ -15,8 +15,8 @@ import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, } from '../services/analytics/index.js' -import { GREP_TOOL_NAME } from '../tools/GrepTool/prompt.js' -import { isReplModeEnabled } from '../tools/REPLTool/constants.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { isReplModeEnabled } from '@claude-code-best/builtin-tools/tools/REPLTool/constants.js' import { logForDebugging } from '../utils/debug.js' import { hasEmbeddedSearchTools } from '../utils/embeddedTools.js' import { isEnvTruthy } from '../utils/envUtils.js' diff --git a/src/query.ts b/src/query.ts index f8a7eb7b4..026f0d74e 100644 --- a/src/query.ts +++ b/src/query.ts @@ -88,7 +88,7 @@ import { } from './utils/tokens.js' import { ESCALATED_MAX_TOKENS } from './utils/context.js' import { getFeatureValue_CACHED_MAY_BE_STALE } from './services/analytics/growthbook.js' -import { SLEEP_TOOL_NAME } from './tools/SleepTool/prompt.js' +import { SLEEP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SleepTool/prompt.js' import { executePostSamplingHooks } from './utils/hooks/postSamplingHooks.js' import { executeStopFailureHooks } from './utils/hooks.js' import type { QuerySource } from './constants/querySource.js' diff --git a/src/screens/REPL.tsx b/src/screens/REPL.tsx index 9dab48b97..4af35add2 100644 --- a/src/screens/REPL.tsx +++ b/src/screens/REPL.tsx @@ -203,9 +203,9 @@ import { import { buildPermissionUpdates } from '../components/permissions/ExitPlanModePermissionRequest/ExitPlanModePermissionRequest.js'; import { stripDangerousPermissionsForAutoMode } from '../utils/permissions/permissionSetup.js'; import { getScratchpadDir, isScratchpadEnabled } from '../utils/permissions/filesystem.js'; -import { WEB_FETCH_TOOL_NAME } from '../tools/WebFetchTool/prompt.js'; -import { SLEEP_TOOL_NAME } from '../tools/SleepTool/prompt.js'; -import { clearSpeculativeChecks } from '../tools/BashTool/bashPermissions.js'; +import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js'; +import { SLEEP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SleepTool/prompt.js'; +import { clearSpeculativeChecks } from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js'; import type { AutoUpdaterResult } from '../utils/autoUpdater.js'; import { getGlobalConfig, saveGlobalConfig, getGlobalConfigWriteCount } from '../utils/config.js'; import { hasConsoleBillingAccess } from '../utils/billing.js'; @@ -268,9 +268,9 @@ import { processSessionStartHooks } from '../utils/sessionStart.js'; import { executeSessionEndHooks, getSessionEndHookTimeoutMs } from '../utils/hooks.js'; import { type IDESelection, useIdeSelection } from '../hooks/useIdeSelection.js'; import { getTools, assembleToolPool } from '../tools.js'; -import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js'; -import { resolveAgentTools } from '../tools/AgentTool/agentToolUtils.js'; -import { resumeAgentBackground } from '../tools/AgentTool/resumeAgent.js'; +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'; +import { resolveAgentTools } from '@claude-code-best/builtin-tools/tools/AgentTool/agentToolUtils.js'; +import { resumeAgentBackground } from '@claude-code-best/builtin-tools/tools/AgentTool/resumeAgent.js'; import { useMainLoopModel } from '../hooks/useMainLoopModel.js'; import { useAppState, useSetAppState, useAppStateStore } from '../state/AppState.js'; import type { ContentBlockParam, ContentBlock, ImageBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs'; @@ -301,7 +301,7 @@ import { } from '../utils/toolResultStorage.js'; import { partialCompactConversation } from '../services/compact/compact.js'; import type { LogOption } from '../types/logs.js'; -import type { AgentColorName } from '../tools/AgentTool/agentColorManager.js'; +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js'; import { fileHistoryMakeSnapshot, type FileHistoryState, @@ -451,10 +451,10 @@ import { type AutoRunIssueReason, } from '../utils/autoRunIssue.js'; import type { HookProgress } from '../types/hooks.js'; -import { TungstenLiveMonitor } from '../tools/TungstenTool/TungstenLiveMonitor.js'; +import { TungstenLiveMonitor } from '@claude-code-best/builtin-tools/tools/TungstenTool/TungstenLiveMonitor.js'; /* eslint-disable @typescript-eslint/no-require-imports */ const WebBrowserPanelModule = feature('WEB_BROWSER_TOOL') - ? (require('../tools/WebBrowserTool/WebBrowserPanel.js') as typeof import('../tools/WebBrowserTool/WebBrowserPanel.js')) + ? (require('@claude-code-best/builtin-tools/tools/WebBrowserTool/WebBrowserPanel.js') as typeof import('@claude-code-best/builtin-tools/tools/WebBrowserTool/WebBrowserPanel.js')) : null; /* eslint-enable @typescript-eslint/no-require-imports */ import { IssueFlagBanner } from '../components/PromptInput/IssueFlagBanner.js'; @@ -2079,7 +2079,7 @@ export function REPL({ // reflect the new coordinator/normal mode /* eslint-disable @typescript-eslint/no-require-imports */ const { getAgentDefinitionsWithOverrides, getActiveAgentsFromList } = - require('../tools/AgentTool/loadAgentsDir.js') as typeof import('../tools/AgentTool/loadAgentsDir.js'); + require('@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js') as typeof import('@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'); /* eslint-enable @typescript-eslint/no-require-imports */ getAgentDefinitionsWithOverrides.cache.clear?.(); const freshAgentDefs = await getAgentDefinitionsWithOverrides(getOriginalCwd()); diff --git a/src/screens/ResumeConversation.tsx b/src/screens/ResumeConversation.tsx index 2e5024a9b..f1a5ea83e 100644 --- a/src/screens/ResumeConversation.tsx +++ b/src/screens/ResumeConversation.tsx @@ -20,8 +20,8 @@ import type { } from '../services/mcp/types.js' import { useAppState, useSetAppState } from '../state/AppState.js' import type { Tool } from '../Tool.js' -import type { AgentColorName } from '../tools/AgentTool/agentColorManager.js' -import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { asSessionId } from '../types/ids.js' import type { LogOption } from '../types/logs.js' import type { Message } from '../types/message.js' @@ -249,7 +249,7 @@ export function ResumeConversation({ if (warning) { /* eslint-disable @typescript-eslint/no-require-imports */ const { getAgentDefinitionsWithOverrides, getActiveAgentsFromList } = - require('../tools/AgentTool/loadAgentsDir.js') as typeof import('../tools/AgentTool/loadAgentsDir.js') + require('@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js') as typeof import('@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js') /* eslint-enable @typescript-eslint/no-require-imports */ getAgentDefinitionsWithOverrides.cache.clear?.() const freshAgentDefs = await getAgentDefinitionsWithOverrides( diff --git a/src/services/AgentSummary/agentSummary.ts b/src/services/AgentSummary/agentSummary.ts index 26a9ece65..50146b3c7 100644 --- a/src/services/AgentSummary/agentSummary.ts +++ b/src/services/AgentSummary/agentSummary.ts @@ -11,8 +11,9 @@ */ import type { TaskContext } from '../../Task.js' +import { isPoorModeActive } from '../../commands/poor/poorMode.js' import { updateAgentSummary } from '../../tasks/LocalAgentTask/LocalAgentTask.js' -import { filterIncompleteToolCalls } from '../../tools/AgentTool/runAgent.js' +import { filterIncompleteToolCalls } from '@claude-code-best/builtin-tools/tools/AgentTool/runAgent.js' import type { AgentId } from '../../types/ids.js' import { logForDebugging } from '../../utils/debug.js' import { @@ -60,6 +61,11 @@ export function startAgentSummarization( async function runSummary(): Promise { if (stopped) return + if (isPoorModeActive()) { + logForDebugging('[AgentSummary] Skipping summary — poor mode active') + scheduleNext() + return + } logForDebugging(`[AgentSummary] Timer fired for agent ${agentId}`) diff --git a/src/services/MagicDocs/magicDocs.ts b/src/services/MagicDocs/magicDocs.ts index a756d427d..06fa69df3 100644 --- a/src/services/MagicDocs/magicDocs.ts +++ b/src/services/MagicDocs/magicDocs.ts @@ -7,14 +7,14 @@ */ import type { Tool, ToolUseContext } from '../../Tool.js' -import type { BuiltInAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' -import { runAgent } from '../../tools/AgentTool/runAgent.js' -import { FILE_EDIT_TOOL_NAME } from '../../tools/FileEditTool/constants.js' +import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { runAgent } from '@claude-code-best/builtin-tools/tools/AgentTool/runAgent.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' import { FileReadTool, type Output as FileReadToolOutput, registerFileReadListener, -} from '../../tools/FileReadTool/FileReadTool.js' +} from '@claude-code-best/builtin-tools/tools/FileReadTool/FileReadTool.js' import { isFsInaccessible } from '../../utils/errors.js' import { cloneFileStateCache } from '../../utils/fileStateCache.js' import { diff --git a/src/services/PromptSuggestion/speculation.ts b/src/services/PromptSuggestion/speculation.ts index de0b523a6..9835d4d86 100644 --- a/src/services/PromptSuggestion/speculation.ts +++ b/src/services/PromptSuggestion/speculation.ts @@ -10,8 +10,8 @@ import { type SpeculationResult, type SpeculationState, } from '../../state/AppStateStore.js' -import { commandHasAnyCd } from '../../tools/BashTool/bashPermissions.js' -import { checkReadOnlyConstraints } from '../../tools/BashTool/readOnlyValidation.js' +import { commandHasAnyCd } from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js' +import { checkReadOnlyConstraints } from '@claude-code-best/builtin-tools/tools/BashTool/readOnlyValidation.js' import type { SpeculationAcceptMessage } from '../../types/logs.js' import type { Message } from '../../types/message.js' import { createChildAbortController } from '../../utils/abortController.js' diff --git a/src/services/SessionMemory/sessionMemory.ts b/src/services/SessionMemory/sessionMemory.ts index 7be2da4b6..2df75aa0d 100644 --- a/src/services/SessionMemory/sessionMemory.ts +++ b/src/services/SessionMemory/sessionMemory.ts @@ -12,11 +12,11 @@ import { getSystemPrompt } from '../../constants/prompts.js' import { getSystemContext, getUserContext } from '../../context.js' import type { CanUseToolFn } from '../../hooks/useCanUseTool.js' import type { Tool, ToolUseContext } from '../../Tool.js' -import { FILE_EDIT_TOOL_NAME } from '../../tools/FileEditTool/constants.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' import { FileReadTool, type Output as FileReadToolOutput, -} from '../../tools/FileReadTool/FileReadTool.js' +} from '@claude-code-best/builtin-tools/tools/FileReadTool/FileReadTool.js' import type { Message } from '../../types/message.js' import { count } from '../../utils/array.js' import { diff --git a/src/services/api/claude.ts b/src/services/api/claude.ts index 8a726886f..e811fd74e 100644 --- a/src/services/api/claude.ts +++ b/src/services/api/claude.ts @@ -36,7 +36,7 @@ import { type Tools, toolMatchesName, } from '../../Tool.js' -import type { AgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { type ConnectorTextBlock, type ConnectorTextDelta, @@ -195,7 +195,7 @@ import { formatDeferredToolLine, isDeferredTool, TOOL_SEARCH_TOOL_NAME, -} from '../../tools/ToolSearchTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/ToolSearchTool/prompt.js' import { count } from '../../utils/array.js' import { insertBlockAfterToolResults } from '../../utils/contentArray.js' import { validateBoundedIntEnvVar } from '../../utils/envValidation.js' diff --git a/src/services/api/openai/index.ts b/src/services/api/openai/index.ts index 74b112193..040907006 100644 --- a/src/services/api/openai/index.ts +++ b/src/services/api/openai/index.ts @@ -46,7 +46,7 @@ import { import { isDeferredTool, TOOL_SEARCH_TOOL_NAME, -} from '../../../tools/ToolSearchTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/ToolSearchTool/prompt.js' /** * Detect whether DeepSeek-style thinking mode should be enabled. diff --git a/src/services/autoDream/autoDream.ts b/src/services/autoDream/autoDream.ts index 12a8d4a75..d87b34f31 100644 --- a/src/services/autoDream/autoDream.ts +++ b/src/services/autoDream/autoDream.ts @@ -49,8 +49,8 @@ import { failDreamTask, isDreamTask, } from '../../tasks/DreamTask/DreamTask.js' -import { FILE_EDIT_TOOL_NAME } from '../../tools/FileEditTool/constants.js' -import { FILE_WRITE_TOOL_NAME } from '../../tools/FileWriteTool/prompt.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' // Scan throttle: when time-gate passes but session-gate doesn't, the lock // mtime doesn't advance, so the time-gate keeps passing every turn. diff --git a/src/services/compact/apiMicrocompact.ts b/src/services/compact/apiMicrocompact.ts index 4a6b84b1b..44b292dac 100644 --- a/src/services/compact/apiMicrocompact.ts +++ b/src/services/compact/apiMicrocompact.ts @@ -1,11 +1,11 @@ -import { FILE_EDIT_TOOL_NAME } from 'src/tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from 'src/tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from 'src/tools/FileWriteTool/prompt.js' -import { GLOB_TOOL_NAME } from 'src/tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from 'src/tools/GrepTool/prompt.js' -import { NOTEBOOK_EDIT_TOOL_NAME } from 'src/tools/NotebookEditTool/constants.js' -import { WEB_FETCH_TOOL_NAME } from 'src/tools/WebFetchTool/prompt.js' -import { WEB_SEARCH_TOOL_NAME } from 'src/tools/WebSearchTool/prompt.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js' +import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js' +import { WEB_SEARCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebSearchTool/prompt.js' import { SHELL_TOOL_NAMES } from 'src/utils/shell/shellToolUtils.js' import { isEnvTruthy } from '../../utils/envUtils.js' diff --git a/src/services/compact/compact.ts b/src/services/compact/compact.ts index 8e3e0560d..f46194ffb 100644 --- a/src/services/compact/compact.ts +++ b/src/services/compact/compact.ts @@ -14,12 +14,12 @@ import type { QuerySource } from '../../constants/querySource.js' import type { CanUseToolFn } from '../../hooks/useCanUseTool.js' import type { Tool, ToolUseContext } from '../../Tool.js' import type { LocalAgentTaskState } from '../../tasks/LocalAgentTask/LocalAgentTask.js' -import { FileReadTool } from '../../tools/FileReadTool/FileReadTool.js' +import { FileReadTool } from '@claude-code-best/builtin-tools/tools/FileReadTool/FileReadTool.js' import { FILE_READ_TOOL_NAME, FILE_UNCHANGED_STUB, -} from '../../tools/FileReadTool/prompt.js' -import { ToolSearchTool } from '../../tools/ToolSearchTool/ToolSearchTool.js' +} from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { ToolSearchTool } from '@claude-code-best/builtin-tools/tools/ToolSearchTool/ToolSearchTool.js' import type { AgentId } from '../../types/ids.js' import type { AssistantMessage, diff --git a/src/services/compact/microCompact.ts b/src/services/compact/microCompact.ts index 417e25926..015991a4c 100644 --- a/src/services/compact/microCompact.ts +++ b/src/services/compact/microCompact.ts @@ -2,13 +2,13 @@ import { feature } from 'bun:bundle' import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs' import type { QuerySource } from '../../constants/querySource.js' import type { ToolUseContext } from '../../Tool.js' -import { FILE_EDIT_TOOL_NAME } from '../../tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from '../../tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from '../../tools/FileWriteTool/prompt.js' -import { GLOB_TOOL_NAME } from '../../tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from '../../tools/GrepTool/prompt.js' -import { WEB_FETCH_TOOL_NAME } from '../../tools/WebFetchTool/prompt.js' -import { WEB_SEARCH_TOOL_NAME } from '../../tools/WebSearchTool/prompt.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js' +import { WEB_SEARCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebSearchTool/prompt.js' import type { Message } from '../../types/message.js' import { logForDebugging } from '../../utils/debug.js' import { getMainLoopModel } from '../../utils/model/model.js' diff --git a/src/services/compact/postCompactCleanup.ts b/src/services/compact/postCompactCleanup.ts index 2b214728e..aa789f05b 100644 --- a/src/services/compact/postCompactCleanup.ts +++ b/src/services/compact/postCompactCleanup.ts @@ -2,7 +2,7 @@ import { feature } from 'bun:bundle' import type { QuerySource } from '../../constants/querySource.js' import { clearSystemPromptSections } from '../../constants/systemPromptSections.js' import { getUserContext } from '../../context.js' -import { clearSpeculativeChecks } from '../../tools/BashTool/bashPermissions.js' +import { clearSpeculativeChecks } from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js' import { clearClassifierApprovals } from '../../utils/classifierApprovals.js' import { resetGetMemoryFilesCache } from '../../utils/claudemd.js' import { clearSessionMessagesCache } from '../../utils/sessionStorage.js' diff --git a/src/services/extractMemories/extractMemories.ts b/src/services/extractMemories/extractMemories.ts index ad6d5742b..bb2ae1103 100644 --- a/src/services/extractMemories/extractMemories.ts +++ b/src/services/extractMemories/extractMemories.ts @@ -28,13 +28,13 @@ import { isAutoMemPath, } from '../../memdir/paths.js' import type { Tool } from '../../Tool.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' -import { FILE_EDIT_TOOL_NAME } from '../../tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from '../../tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from '../../tools/FileWriteTool/prompt.js' -import { GLOB_TOOL_NAME } from '../../tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from '../../tools/GrepTool/prompt.js' -import { REPL_TOOL_NAME } from '../../tools/REPLTool/constants.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { REPL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/REPLTool/constants.js' import type { AssistantMessage, Message, diff --git a/src/services/extractMemories/prompts.ts b/src/services/extractMemories/prompts.ts index 804adb3e1..9411d6808 100644 --- a/src/services/extractMemories/prompts.ts +++ b/src/services/extractMemories/prompts.ts @@ -16,12 +16,12 @@ import { TYPES_SECTION_INDIVIDUAL, WHAT_NOT_TO_SAVE_SECTION, } from '../../memdir/memoryTypes.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' -import { FILE_EDIT_TOOL_NAME } from '../../tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from '../../tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from '../../tools/FileWriteTool/prompt.js' -import { GLOB_TOOL_NAME } from '../../tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from '../../tools/GrepTool/prompt.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' /** * Shared opener for both extract-prompt variants. diff --git a/src/services/mcp/adapter/analytics.ts b/src/services/mcp/adapter/analytics.ts new file mode 100644 index 000000000..6b3bf46c1 --- /dev/null +++ b/src/services/mcp/adapter/analytics.ts @@ -0,0 +1,18 @@ +// Host analytics adapter — bridges logEvent to mcp-client's AnalyticsSink interface + +import type { AnalyticsSink } from '@claude-code-best/mcp-client' +import { + type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, + logEvent, +} from '../../analytics/index.js' + +/** + * Creates an AnalyticsSink implementation that delegates to the host's logEvent. + */ +export function createMcpAnalytics(): AnalyticsSink { + return { + trackEvent(event: string, metadata: Record) { + logEvent(event, metadata as Record) + }, + } +} diff --git a/src/services/mcp/adapter/auth.ts b/src/services/mcp/adapter/auth.ts new file mode 100644 index 000000000..e10f86a2e --- /dev/null +++ b/src/services/mcp/adapter/auth.ts @@ -0,0 +1,28 @@ +// Host auth provider adapter — bridges OAuth token management to mcp-client's AuthProvider interface + +import type { AuthProvider } from '@claude-code-best/mcp-client' +import { + getClaudeAIOAuthTokens, + checkAndRefreshOAuthTokenIfNeeded, + handleOAuth401Error, +} from '../../../utils/auth.js' + +/** + * Creates an AuthProvider implementation using the host's OAuth token management. + */ +export function createMcpAuth(): AuthProvider { + return { + async getTokens() { + const tokens = getClaudeAIOAuthTokens() + if (!tokens) return null + return { accessToken: tokens.accessToken } + }, + async refreshTokens() { + await checkAndRefreshOAuthTokenIfNeeded() + }, + async handleOAuthError(error: unknown) { + const currentToken = getClaudeAIOAuthTokens()?.accessToken ?? '' + await handleOAuth401Error(currentToken) + }, + } +} diff --git a/src/services/mcp/adapter/featureGate.ts b/src/services/mcp/adapter/featureGate.ts new file mode 100644 index 000000000..2afddd747 --- /dev/null +++ b/src/services/mcp/adapter/featureGate.ts @@ -0,0 +1,15 @@ +// Host feature gate adapter — bridges feature() to mcp-client's FeatureGate interface + +import type { FeatureGate } from '@claude-code-best/mcp-client' +import { feature } from 'bun:bundle' + +/** + * Creates a FeatureGate implementation using the host's feature flag system. + */ +export function createMcpFeatureGate(): FeatureGate { + return { + isEnabled(flag: string) { + return feature(flag) + }, + } +} diff --git a/src/services/mcp/adapter/httpConfig.ts b/src/services/mcp/adapter/httpConfig.ts new file mode 100644 index 000000000..cebf3d60f --- /dev/null +++ b/src/services/mcp/adapter/httpConfig.ts @@ -0,0 +1,15 @@ +// Host HTTP config adapter — bridges getUserAgent/getSessionId to mcp-client's HttpConfig interface + +import type { HttpConfig } from '@claude-code-best/mcp-client' +import { getMCPUserAgent } from '../../../utils/http.js' +import { getSessionId } from '../../../bootstrap/state.js' + +/** + * Creates an HttpConfig implementation using the host's user agent and session ID. + */ +export function createMcpHttpConfig(): HttpConfig { + return { + getUserAgent: () => getMCPUserAgent(), + getSessionId: () => getSessionId(), + } +} diff --git a/src/services/mcp/adapter/imageProcessor.ts b/src/services/mcp/adapter/imageProcessor.ts new file mode 100644 index 000000000..f8670d64a --- /dev/null +++ b/src/services/mcp/adapter/imageProcessor.ts @@ -0,0 +1,16 @@ +// Host image processor adapter — bridges maybeResizeAndDownsampleImageBuffer to mcp-client's ImageProcessor interface + +import type { ImageProcessor } from '@claude-code-best/mcp-client' +import { maybeResizeAndDownsampleImageBuffer } from '../../../utils/imageResizer.js' + +/** + * Creates an ImageProcessor implementation using the host's image resizing. + */ +export function createMcpImageProcessor(): ImageProcessor { + return { + async resizeAndDownsample(buffer: Buffer) { + const result = await maybeResizeAndDownsampleImageBuffer(buffer, buffer.length, 'png') + return result.buffer + }, + } +} diff --git a/src/services/mcp/adapter/index.ts b/src/services/mcp/adapter/index.ts new file mode 100644 index 000000000..5fd0f7881 --- /dev/null +++ b/src/services/mcp/adapter/index.ts @@ -0,0 +1,32 @@ +// Host dependency injection — assembles McpClientDependencies from host infrastructure +// This is the single entry point for creating the dependencies object used by createMcpManager() + +import type { McpClientDependencies } from '@claude-code-best/mcp-client' +import { createMcpLogger } from './logger.js' +import { createMcpHttpConfig } from './httpConfig.js' +import { createMcpProxyConfig } from './proxy.js' +import { createMcpAnalytics } from './analytics.js' +import { createMcpSubprocessEnv } from './subprocessEnv.js' +import { createMcpStorage } from './storage.js' +import { createMcpImageProcessor } from './imageProcessor.js' +import { createMcpAuth } from './auth.js' +/** + * Creates the full set of MCP client dependencies using host infrastructure. + * All adapters are lazy — they only call into host modules when invoked. + * + * Note: featureGate is omitted because Bun's feature() requires string-literal + * arguments at compile time and cannot accept runtime variables. The interface + * field is optional and the mcp-client package does not use it currently. + */ +export function createMcpDependencies(): McpClientDependencies { + return { + logger: createMcpLogger(), + httpConfig: createMcpHttpConfig(), + proxy: createMcpProxyConfig(), + analytics: createMcpAnalytics(), + subprocessEnv: createMcpSubprocessEnv(), + storage: createMcpStorage(), + imageProcessor: createMcpImageProcessor(), + auth: createMcpAuth(), + } +} diff --git a/src/services/mcp/adapter/logger.ts b/src/services/mcp/adapter/logger.ts new file mode 100644 index 000000000..473fa8421 --- /dev/null +++ b/src/services/mcp/adapter/logger.ts @@ -0,0 +1,38 @@ +// Host logger adapter — bridges logMCPDebug/logMCPError to mcp-client's Logger interface + +import type { Logger } from '@claude-code-best/mcp-client' +import { logMCPDebug, logMCPError } from '../../../utils/log.js' + +/** + * Creates a Logger implementation that delegates to the host's MCP logging system. + */ +export function createMcpLogger(): Logger { + return { + debug(message: string, ...args: unknown[]) { + // Extract server name from bracketed prefix if present: [serverName] message + const match = message.match(/^\[([^\]]+)\]\s*(.*)/) + if (match) { + logMCPDebug(match[1], match[2]) + } + // Silently ignore messages without server name prefix + }, + info(message: string, ...args: unknown[]) { + const match = message.match(/^\[([^\]]+)\]\s*(.*)/) + if (match) { + logMCPDebug(match[1], match[2]) + } + }, + warn(message: string, ...args: unknown[]) { + const match = message.match(/^\[([^\]]+)\]\s*(.*)/) + if (match) { + logMCPError(match[1], message) + } + }, + error(message: string, ...args: unknown[]) { + const match = message.match(/^\[([^\]]+)\]\s*(.*)/) + if (match) { + logMCPError(match[1], args[0] ?? message) + } + }, + } +} diff --git a/src/services/mcp/adapter/proxy.ts b/src/services/mcp/adapter/proxy.ts new file mode 100644 index 000000000..5fe74dc24 --- /dev/null +++ b/src/services/mcp/adapter/proxy.ts @@ -0,0 +1,30 @@ +// Host proxy config adapter — bridges proxy/MTLS to mcp-client's ProxyConfig interface + +import type { ProxyConfig } from '@claude-code-best/mcp-client' +import { + getProxyFetchOptions, + getWebSocketProxyAgent, + getWebSocketProxyUrl, +} from '../../../utils/proxy.js' +import { getWebSocketTLSOptions } from '../../../utils/mtls.js' + +/** + * Creates a ProxyConfig implementation using the host's proxy and TLS settings. + */ +export function createMcpProxyConfig(): ProxyConfig { + return { + getFetchOptions() { + return getProxyFetchOptions() as Record + }, + getWebSocketAgent(url: string) { + return getWebSocketProxyAgent(url) + }, + getWebSocketUrl(url: string) { + return getWebSocketProxyUrl(url) + }, + getTLSOptions() { + const opts = getWebSocketTLSOptions() + return opts as Record | undefined + }, + } +} diff --git a/src/services/mcp/adapter/storage.ts b/src/services/mcp/adapter/storage.ts new file mode 100644 index 000000000..8ba2f2526 --- /dev/null +++ b/src/services/mcp/adapter/storage.ts @@ -0,0 +1,20 @@ +// Host content storage adapter — bridges persistBinaryContent to mcp-client's ContentStorage interface + +import type { ContentStorage } from '@claude-code-best/mcp-client' +import { persistBinaryContent } from '../../../utils/mcpOutputStorage.js' +import { persistToolResult, isPersistError } from '../../../utils/toolResultStorage.js' + +/** + * Creates a ContentStorage implementation using the host's binary persistence. + */ +export function createMcpStorage(): ContentStorage { + return { + async persistBinaryContent(data: Buffer, ext: string) { + const result = await persistBinaryContent(data, ext, `mcp-adapter-${Date.now()}`) + if ('error' in result) { + throw new Error(result.error) + } + return result.filepath + }, + } +} diff --git a/src/services/mcp/adapter/subprocessEnv.ts b/src/services/mcp/adapter/subprocessEnv.ts new file mode 100644 index 000000000..9e049a672 --- /dev/null +++ b/src/services/mcp/adapter/subprocessEnv.ts @@ -0,0 +1,15 @@ +// Host subprocess environment adapter + +import type { SubprocessEnvProvider } from '@claude-code-best/mcp-client' +import { subprocessEnv } from '../../../utils/subprocessEnv.js' + +/** + * Creates a SubprocessEnvProvider using the host's subprocess environment logic. + */ +export function createMcpSubprocessEnv(): SubprocessEnvProvider { + return { + getEnv(additional?: Record) { + return { ...subprocessEnv(), ...additional } as Record + }, + } +} diff --git a/src/services/mcp/client.ts b/src/services/mcp/client.ts index d6db09b38..00576954d 100644 --- a/src/services/mcp/client.ts +++ b/src/services/mcp/client.ts @@ -50,10 +50,10 @@ import { type ToolCallProgress, toolMatchesName, } from '../../Tool.js' -import { ListMcpResourcesTool } from '../../tools/ListMcpResourcesTool/ListMcpResourcesTool.js' -import { type MCPProgress, MCPTool } from '../../tools/MCPTool/MCPTool.js' -import { createMcpAuthTool } from '../../tools/McpAuthTool/McpAuthTool.js' -import { ReadMcpResourceTool } from '../../tools/ReadMcpResourceTool/ReadMcpResourceTool.js' +import { ListMcpResourcesTool } from '@claude-code-best/builtin-tools/tools/ListMcpResourcesTool/ListMcpResourcesTool.js' +import { type MCPProgress, MCPTool } from '@claude-code-best/builtin-tools/tools/MCPTool/MCPTool.js' +import { createMcpAuthTool } from '@claude-code-best/builtin-tools/tools/McpAuthTool/McpAuthTool.js' +import { ReadMcpResourceTool } from '@claude-code-best/builtin-tools/tools/ReadMcpResourceTool/ReadMcpResourceTool.js' import { createAbortController } from '../../utils/abortController.js' import { count } from '../../utils/array.js' import { @@ -93,7 +93,6 @@ import { getWebSocketProxyAgent, getWebSocketProxyUrl, } from '../../utils/proxy.js' -import { recursivelySanitizeUnicode } from '../../utils/sanitization.js' import { getSessionIngressAuthToken } from '../../utils/sessionIngressAuth.js' import { subprocessEnv } from '../../utils/subprocessEnv.js' import { @@ -113,6 +112,19 @@ import { buildMcpToolName } from './mcpStringUtils.js' import { normalizeNameForMCP } from './normalization.js' import { getLoggingSafeMcpBaseUrl } from './utils.js' +// Package imports — delegate to mcp-client package utilities where applicable +import { + createMcpClient as createMcpClientFromPackage, + captureStderr, + isMcpSessionExpiredError as isMcpSessionExpiredErrorFromPackage, + installConnectionMonitor, + createCleanup as createCleanupFromPackage, + buildConnectedServer, + DEFAULT_CONNECTION_TIMEOUT_MS, + MAX_MCP_DESCRIPTION_LENGTH as PKG_MAX_MCP_DESCRIPTION_LENGTH, +} from '@claude-code-best/mcp-client' +import { recursivelySanitizeUnicode } from '@claude-code-best/mcp-client' + /* eslint-disable @typescript-eslint/no-require-imports */ const fetchMcpSkillsForClient = feature('MCP_SKILLS') ? ( @@ -123,7 +135,7 @@ const fetchMcpSkillsForClient = feature('MCP_SKILLS') import { UnauthorizedError } from '@modelcontextprotocol/sdk/client/auth.js' import type { AssistantMessage } from 'src/types/message.js' /* eslint-enable @typescript-eslint/no-require-imports */ -import { classifyMcpToolForCollapse } from '../../tools/MCPTool/classifyForCollapse.js' +import { classifyMcpToolForCollapse } from '@claude-code-best/builtin-tools/tools/MCPTool/classifyForCollapse.js' import { clearKeychainCache } from '../../utils/secureStorage/macOsKeychainHelpers.js' import { sleep } from '../../utils/sleep.js' import { @@ -191,20 +203,7 @@ export class McpToolCallError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS extends T * Per the MCP spec, servers return 404 when a session ID is no longer valid. * We check both signals to avoid false positives from generic 404s (wrong URL, server gone, etc.). */ -export function isMcpSessionExpiredError(error: Error): boolean { - const httpStatus = - 'code' in error ? (error as Error & { code?: number }).code : undefined - if (httpStatus !== 404) { - return false - } - // The SDK embeds the response body text in the error message. - // MCP servers return: {"error":{"code":-32001,"message":"Session not found"},...} - // Check for the JSON-RPC error code to distinguish from generic web server 404s. - return ( - error.message.includes('"code":-32001') || - error.message.includes('"code": -32001') - ) -} +export const isMcpSessionExpiredError = isMcpSessionExpiredErrorFromPackage /** * Default timeout for MCP tool calls (effectively infinite - ~27.8 hours). @@ -216,7 +215,7 @@ const DEFAULT_MCP_TOOL_TIMEOUT_MS = 100_000_000 * OpenAPI-generated MCP servers have been observed dumping 15-60KB of endpoint * docs into tool.description; this caps the p95 tail without losing the intent. */ -const MAX_MCP_DESCRIPTION_LENGTH = 2048 +const MAX_MCP_DESCRIPTION_LENGTH = PKG_MAX_MCP_DESCRIPTION_LENGTH /** * Gets the timeout for MCP tool calls in milliseconds. diff --git a/src/services/mcp/types.ts b/src/services/mcp/types.ts index b98821dee..9f64d5666 100644 --- a/src/services/mcp/types.ts +++ b/src/services/mcp/types.ts @@ -21,7 +21,7 @@ export const ConfigScopeSchema = lazySchema(() => export type ConfigScope = z.infer> export const TransportSchema = lazySchema(() => - z.enum(['stdio', 'sse', 'sse-ide', 'http', 'ws', 'sdk']), + z.enum(['stdio', 'sse', 'sse-ide', 'http', 'ws', 'sdk', 'claudeai-proxy']), ) export type Transport = z.infer> diff --git a/src/services/mcp/utils.ts b/src/services/mcp/utils.ts index 55ca0005c..fb3bd2d38 100644 --- a/src/services/mcp/utils.ts +++ b/src/services/mcp/utils.ts @@ -4,7 +4,7 @@ import { getIsNonInteractiveSession } from '../../bootstrap/state.js' import type { Command } from '../../commands.js' import type { AgentMcpServerInfo } from '../../components/mcp/types.js' import type { Tool } from '../../Tool.js' -import type { AgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { getCwd } from '../../utils/cwd.js' import { getGlobalClaudeFile } from '../../utils/env.js' import { isSettingSourceEnabled } from '../../utils/settings/constants.js' diff --git a/src/services/tips/tipRegistry.ts b/src/services/tips/tipRegistry.ts index e802e8903..37bf27cad 100644 --- a/src/services/tips/tipRegistry.ts +++ b/src/services/tips/tipRegistry.ts @@ -11,7 +11,7 @@ import { getDesktopUpsellConfig } from '../../components/DesktopUpsell/DesktopUp import { color } from '@anthropic/ink' import { shouldShowOverageCreditUpsell } from '../../components/LogoV2/OverageCreditUpsell.js' import { getShortcutDisplay } from '../../keybindings/shortcutFormat.js' -import { isKairosCronEnabled } from '../../tools/ScheduleCronTool/prompt.js' +import { isKairosCronEnabled } from '@claude-code-best/builtin-tools/tools/ScheduleCronTool/prompt.js' import { is1PApiCustomer } from '../../utils/auth.js' import { countConcurrentSessions } from '../../utils/concurrentSessions.js' import { getGlobalConfig } from '../../utils/config.js' diff --git a/src/services/tools/StreamingToolExecutor.ts b/src/services/tools/StreamingToolExecutor.ts index 40c3dff3d..ce7911c4b 100644 --- a/src/services/tools/StreamingToolExecutor.ts +++ b/src/services/tools/StreamingToolExecutor.ts @@ -6,7 +6,7 @@ import { } from 'src/utils/messages.js' import type { CanUseToolFn } from '../../hooks/useCanUseTool.js' import { findToolByName, type Tools, type ToolUseContext } from '../../Tool.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' import type { AssistantMessage, Message } from '../../types/message.js' import { createChildAbortController } from '../../utils/abortController.js' import { runToolUse } from './toolExecution.js' diff --git a/src/services/tools/toolExecution.ts b/src/services/tools/toolExecution.ts index e67ede8fb..89a4180cb 100644 --- a/src/services/tools/toolExecution.ts +++ b/src/services/tools/toolExecution.ts @@ -35,19 +35,19 @@ import { type ToolProgressData, type ToolUseContext, } from '../../Tool.js' -import type { BashToolInput } from '../../tools/BashTool/BashTool.js' -import { startSpeculativeClassifierCheck } from '../../tools/BashTool/bashPermissions.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' -import { FILE_EDIT_TOOL_NAME } from '../../tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from '../../tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from '../../tools/FileWriteTool/prompt.js' -import { NOTEBOOK_EDIT_TOOL_NAME } from '../../tools/NotebookEditTool/constants.js' -import { POWERSHELL_TOOL_NAME } from '../../tools/PowerShellTool/toolName.js' -import { parseGitCommitId } from '../../tools/shared/gitOperationTracking.js' +import type { BashToolInput } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' +import { startSpeculativeClassifierCheck } from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js' +import { POWERSHELL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/PowerShellTool/toolName.js' +import { parseGitCommitId } from '@claude-code-best/builtin-tools/tools/shared/gitOperationTracking.js' import { isDeferredTool, TOOL_SEARCH_TOOL_NAME, -} from '../../tools/ToolSearchTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/ToolSearchTool/prompt.js' import { getAllBaseTools } from '../../tools.js' import type { HookProgress } from '../../types/hooks.js' import { recordToolObservation } from '../langfuse/index.js' diff --git a/src/skills/bundled/batch.ts b/src/skills/bundled/batch.ts index 90b4845ad..cb7660f80 100644 --- a/src/skills/bundled/batch.ts +++ b/src/skills/bundled/batch.ts @@ -1,8 +1,8 @@ -import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' -import { ASK_USER_QUESTION_TOOL_NAME } from '../../tools/AskUserQuestionTool/prompt.js' -import { ENTER_PLAN_MODE_TOOL_NAME } from '../../tools/EnterPlanModeTool/constants.js' -import { EXIT_PLAN_MODE_TOOL_NAME } from '../../tools/ExitPlanModeTool/constants.js' -import { SKILL_TOOL_NAME } from '../../tools/SkillTool/constants.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { ASK_USER_QUESTION_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/prompt.js' +import { ENTER_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/EnterPlanModeTool/constants.js' +import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' +import { SKILL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SkillTool/constants.js' import { getIsGit } from '../../utils/git.js' import { registerBundledSkill } from '../bundledSkills.js' diff --git a/src/skills/bundled/cronManage.ts b/src/skills/bundled/cronManage.ts index c3b93d37d..2169b0303 100644 --- a/src/skills/bundled/cronManage.ts +++ b/src/skills/bundled/cronManage.ts @@ -2,7 +2,7 @@ import { CRON_DELETE_TOOL_NAME, CRON_LIST_TOOL_NAME, isKairosCronEnabled, -} from '../../tools/ScheduleCronTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/ScheduleCronTool/prompt.js' import { registerBundledSkill } from '../bundledSkills.js' export function registerCronListSkill(): void { diff --git a/src/skills/bundled/debug.ts b/src/skills/bundled/debug.ts index 94c70435d..4529002ea 100644 --- a/src/skills/bundled/debug.ts +++ b/src/skills/bundled/debug.ts @@ -1,5 +1,5 @@ import { open, stat } from 'fs/promises' -import { CLAUDE_CODE_GUIDE_AGENT_TYPE } from 'src/tools/AgentTool/built-in/claudeCodeGuideAgent.js' +import { CLAUDE_CODE_GUIDE_AGENT_TYPE } from '@claude-code-best/builtin-tools/tools/AgentTool/built-in/claudeCodeGuideAgent.js' import { getSettingsFilePathForSource } from 'src/utils/settings/settings.js' import { enableDebugLogging, getDebugLogPath } from '../../utils/debug.js' import { errorMessage, isENOENT } from '../../utils/errors.js' diff --git a/src/skills/bundled/loop.ts b/src/skills/bundled/loop.ts index ccc472daa..b74ff0290 100644 --- a/src/skills/bundled/loop.ts +++ b/src/skills/bundled/loop.ts @@ -3,7 +3,7 @@ import { CRON_DELETE_TOOL_NAME, DEFAULT_MAX_AGE_DAYS, isKairosCronEnabled, -} from '../../tools/ScheduleCronTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/ScheduleCronTool/prompt.js' import { registerBundledSkill } from '../bundledSkills.js' const DEFAULT_INTERVAL = '10m' diff --git a/src/skills/bundled/scheduleRemoteAgents.ts b/src/skills/bundled/scheduleRemoteAgents.ts index 21b2ac694..acbf950cd 100644 --- a/src/skills/bundled/scheduleRemoteAgents.ts +++ b/src/skills/bundled/scheduleRemoteAgents.ts @@ -2,8 +2,8 @@ import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/gr import type { MCPServerConnection } from '../../services/mcp/types.js' import { isPolicyAllowed } from '../../services/policyLimits/index.js' import type { ToolUseContext } from '../../Tool.js' -import { ASK_USER_QUESTION_TOOL_NAME } from '../../tools/AskUserQuestionTool/prompt.js' -import { REMOTE_TRIGGER_TOOL_NAME } from '../../tools/RemoteTriggerTool/prompt.js' +import { ASK_USER_QUESTION_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/prompt.js' +import { REMOTE_TRIGGER_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/RemoteTriggerTool/prompt.js' import { getClaudeAIOAuthTokens } from '../../utils/auth.js' import { checkRepoForRemoteAccess } from '../../utils/background/remote/preconditions.js' import { logForDebugging } from '../../utils/debug.js' diff --git a/src/skills/bundled/simplify.ts b/src/skills/bundled/simplify.ts index efdfde216..f33441b0f 100644 --- a/src/skills/bundled/simplify.ts +++ b/src/skills/bundled/simplify.ts @@ -1,4 +1,4 @@ -import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' import { registerBundledSkill } from '../bundledSkills.js' const SIMPLIFY_PROMPT = `# Simplify: Code Review and Cleanup diff --git a/src/state/AppStateStore.ts b/src/state/AppStateStore.ts index 14fc84506..e5f20efda 100644 --- a/src/state/AppStateStore.ts +++ b/src/state/AppStateStore.ts @@ -15,9 +15,9 @@ import { type ToolPermissionContext, } from '../Tool.js' import type { TaskState } from '../tasks/types.js' -import type { AgentColorName } from '../tools/AgentTool/agentColorManager.js' -import type { AgentDefinitionsResult } from '../tools/AgentTool/loadAgentsDir.js' -import type { AllowedPrompt } from '../tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' +import type { AgentDefinitionsResult } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import type { AllowedPrompt } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' import type { AgentId } from '../types/ids.js' import type { Message, UserMessage } from '../types/message.js' import type { LoadedPlugin, PluginError } from '../types/plugin.js' diff --git a/src/tasks/InProcessTeammateTask/types.ts b/src/tasks/InProcessTeammateTask/types.ts index d6e6d39af..df8b7fc2c 100644 --- a/src/tasks/InProcessTeammateTask/types.ts +++ b/src/tasks/InProcessTeammateTask/types.ts @@ -1,6 +1,6 @@ import type { TaskStateBase } from '../../Task.js' -import type { AgentToolResult } from '../../tools/AgentTool/agentToolUtils.js' -import type { AgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' +import type { AgentToolResult } from '@claude-code-best/builtin-tools/tools/AgentTool/agentToolUtils.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import type { Message } from '../../types/message.js' import type { PermissionMode } from '../../utils/permissions/PermissionMode.js' import type { AgentProgress } from '../LocalAgentTask/LocalAgentTask.js' diff --git a/src/tasks/LocalAgentTask/LocalAgentTask.tsx b/src/tasks/LocalAgentTask/LocalAgentTask.tsx index 0f7eb3740..3b65cfb82 100644 --- a/src/tasks/LocalAgentTask/LocalAgentTask.tsx +++ b/src/tasks/LocalAgentTask/LocalAgentTask.tsx @@ -17,9 +17,9 @@ import type { SetAppState, Task, TaskStateBase } from '../../Task.js' import { createTaskStateBase } from '../../Task.js' import type { Tools } from '../../Tool.js' import { findToolByName } from '../../Tool.js' -import type { AgentToolResult } from '../../tools/AgentTool/agentToolUtils.js' -import type { AgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' -import { SYNTHETIC_OUTPUT_TOOL_NAME } from '../../tools/SyntheticOutputTool/SyntheticOutputTool.js' +import type { AgentToolResult } from '@claude-code-best/builtin-tools/tools/AgentTool/agentToolUtils.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { SYNTHETIC_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SyntheticOutputTool/SyntheticOutputTool.js' import { asAgentId } from '../../types/ids.js' import type { Message } from '../../types/message.js' import { diff --git a/src/tasks/LocalMainSessionTask.ts b/src/tasks/LocalMainSessionTask.ts index e0d4bf90d..27398d515 100644 --- a/src/tasks/LocalMainSessionTask.ts +++ b/src/tasks/LocalMainSessionTask.ts @@ -26,7 +26,7 @@ import { createTaskStateBase } from '../Task.js' import type { AgentDefinition, CustomAgentDefinition, -} from '../tools/AgentTool/loadAgentsDir.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { asAgentId } from '../types/ids.js' import type { Message } from '../types/message.js' import { createAbortController } from '../utils/abortController.js' diff --git a/src/tasks/RemoteAgentTask/RemoteAgentTask.tsx b/src/tasks/RemoteAgentTask/RemoteAgentTask.tsx index 75e096014..0d9fc1057 100644 --- a/src/tasks/RemoteAgentTask/RemoteAgentTask.tsx +++ b/src/tasks/RemoteAgentTask/RemoteAgentTask.tsx @@ -24,7 +24,7 @@ import type { TaskStateBase, } from '../../Task.js' import { createTaskStateBase, generateTaskId } from '../../Task.js' -import { TodoWriteTool } from '../../tools/TodoWriteTool/TodoWriteTool.js' +import { TodoWriteTool } from '@claude-code-best/builtin-tools/tools/TodoWriteTool/TodoWriteTool.js' import { type BackgroundRemoteSessionPrecondition, checkBackgroundRemoteSessionEligibility, diff --git a/src/tools.ts b/src/tools.ts index 9725d7ed9..9c956ff65 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -1,86 +1,86 @@ // biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered import { toolMatchesName, type Tool, type Tools } from './Tool.js' -import { AgentTool } from './tools/AgentTool/AgentTool.js' -import { SkillTool } from './tools/SkillTool/SkillTool.js' -import { BashTool } from './tools/BashTool/BashTool.js' -import { FileEditTool } from './tools/FileEditTool/FileEditTool.js' -import { FileReadTool } from './tools/FileReadTool/FileReadTool.js' -import { FileWriteTool } from './tools/FileWriteTool/FileWriteTool.js' -import { GlobTool } from './tools/GlobTool/GlobTool.js' -import { NotebookEditTool } from './tools/NotebookEditTool/NotebookEditTool.js' -import { WebFetchTool } from './tools/WebFetchTool/WebFetchTool.js' -import { TaskStopTool } from './tools/TaskStopTool/TaskStopTool.js' -import { BriefTool } from './tools/BriefTool/BriefTool.js' +import { AgentTool } from '@claude-code-best/builtin-tools/tools/AgentTool/AgentTool.js' +import { SkillTool } from '@claude-code-best/builtin-tools/tools/SkillTool/SkillTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' +import { FileEditTool } from '@claude-code-best/builtin-tools/tools/FileEditTool/FileEditTool.js' +import { FileReadTool } from '@claude-code-best/builtin-tools/tools/FileReadTool/FileReadTool.js' +import { FileWriteTool } from '@claude-code-best/builtin-tools/tools/FileWriteTool/FileWriteTool.js' +import { GlobTool } from '@claude-code-best/builtin-tools/tools/GlobTool/GlobTool.js' +import { NotebookEditTool } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/NotebookEditTool.js' +import { WebFetchTool } from '@claude-code-best/builtin-tools/tools/WebFetchTool/WebFetchTool.js' +import { TaskStopTool } from '@claude-code-best/builtin-tools/tools/TaskStopTool/TaskStopTool.js' +import { BriefTool } from '@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js' // Dead code elimination: conditional import for ant-only tools /* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */ const REPLTool = process.env.USER_TYPE === 'ant' - ? require('./tools/REPLTool/REPLTool.js').REPLTool + ? require('@claude-code-best/builtin-tools/tools/REPLTool/REPLTool.js').REPLTool : null const SuggestBackgroundPRTool = process.env.USER_TYPE === 'ant' - ? require('./tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.js') + ? require('@claude-code-best/builtin-tools/tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.js') .SuggestBackgroundPRTool : null const SleepTool = feature('PROACTIVE') || feature('KAIROS') - ? require('./tools/SleepTool/SleepTool.js').SleepTool + ? require('@claude-code-best/builtin-tools/tools/SleepTool/SleepTool.js').SleepTool : null const cronTools = [ - require('./tools/ScheduleCronTool/CronCreateTool.js').CronCreateTool, - require('./tools/ScheduleCronTool/CronDeleteTool.js').CronDeleteTool, - require('./tools/ScheduleCronTool/CronListTool.js').CronListTool, + require('@claude-code-best/builtin-tools/tools/ScheduleCronTool/CronCreateTool.js').CronCreateTool, + require('@claude-code-best/builtin-tools/tools/ScheduleCronTool/CronDeleteTool.js').CronDeleteTool, + require('@claude-code-best/builtin-tools/tools/ScheduleCronTool/CronListTool.js').CronListTool, ] const RemoteTriggerTool = feature('AGENT_TRIGGERS_REMOTE') - ? require('./tools/RemoteTriggerTool/RemoteTriggerTool.js').RemoteTriggerTool + ? require('@claude-code-best/builtin-tools/tools/RemoteTriggerTool/RemoteTriggerTool.js').RemoteTriggerTool : null const MonitorTool = feature('MONITOR_TOOL') - ? require('./tools/MonitorTool/MonitorTool.js').MonitorTool + ? require('@claude-code-best/builtin-tools/tools/MonitorTool/MonitorTool.js').MonitorTool : null const SendUserFileTool = feature('KAIROS') - ? require('./tools/SendUserFileTool/SendUserFileTool.js').SendUserFileTool + ? require('@claude-code-best/builtin-tools/tools/SendUserFileTool/SendUserFileTool.js').SendUserFileTool : null const PushNotificationTool = feature('KAIROS') || feature('KAIROS_PUSH_NOTIFICATION') - ? require('./tools/PushNotificationTool/PushNotificationTool.js') + ? require('@claude-code-best/builtin-tools/tools/PushNotificationTool/PushNotificationTool.js') .PushNotificationTool : null const SubscribePRTool = feature('KAIROS_GITHUB_WEBHOOKS') - ? require('./tools/SubscribePRTool/SubscribePRTool.js').SubscribePRTool + ? require('@claude-code-best/builtin-tools/tools/SubscribePRTool/SubscribePRTool.js').SubscribePRTool : null /* eslint-enable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */ -import { TaskOutputTool } from './tools/TaskOutputTool/TaskOutputTool.js' -import { WebSearchTool } from './tools/WebSearchTool/WebSearchTool.js' -import { TodoWriteTool } from './tools/TodoWriteTool/TodoWriteTool.js' -import { ExitPlanModeV2Tool } from './tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' -import { TestingPermissionTool } from './tools/testing/TestingPermissionTool.js' -import { GrepTool } from './tools/GrepTool/GrepTool.js' -import { TungstenTool } from './tools/TungstenTool/TungstenTool.js' +import { TaskOutputTool } from '@claude-code-best/builtin-tools/tools/TaskOutputTool/TaskOutputTool.js' +import { WebSearchTool } from '@claude-code-best/builtin-tools/tools/WebSearchTool/WebSearchTool.js' +import { TodoWriteTool } from '@claude-code-best/builtin-tools/tools/TodoWriteTool/TodoWriteTool.js' +import { ExitPlanModeV2Tool } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' +import { TestingPermissionTool } from '@claude-code-best/builtin-tools/tools/testing/TestingPermissionTool.js' +import { GrepTool } from '@claude-code-best/builtin-tools/tools/GrepTool/GrepTool.js' +import { TungstenTool } from '@claude-code-best/builtin-tools/tools/TungstenTool/TungstenTool.js' // Lazy require to break circular dependency: tools.ts -> TeamCreateTool/TeamDeleteTool -> ... -> tools.ts /* eslint-disable @typescript-eslint/no-require-imports */ const getTeamCreateTool = () => - require('./tools/TeamCreateTool/TeamCreateTool.js') - .TeamCreateTool as typeof import('./tools/TeamCreateTool/TeamCreateTool.js').TeamCreateTool + require('@claude-code-best/builtin-tools/tools/TeamCreateTool/TeamCreateTool.js') + .TeamCreateTool as typeof import('@claude-code-best/builtin-tools/tools/TeamCreateTool/TeamCreateTool.js').TeamCreateTool const getTeamDeleteTool = () => - require('./tools/TeamDeleteTool/TeamDeleteTool.js') - .TeamDeleteTool as typeof import('./tools/TeamDeleteTool/TeamDeleteTool.js').TeamDeleteTool + require('@claude-code-best/builtin-tools/tools/TeamDeleteTool/TeamDeleteTool.js') + .TeamDeleteTool as typeof import('@claude-code-best/builtin-tools/tools/TeamDeleteTool/TeamDeleteTool.js').TeamDeleteTool const getSendMessageTool = () => - require('./tools/SendMessageTool/SendMessageTool.js') - .SendMessageTool as typeof import('./tools/SendMessageTool/SendMessageTool.js').SendMessageTool + require('@claude-code-best/builtin-tools/tools/SendMessageTool/SendMessageTool.js') + .SendMessageTool as typeof import('@claude-code-best/builtin-tools/tools/SendMessageTool/SendMessageTool.js').SendMessageTool /* eslint-enable @typescript-eslint/no-require-imports */ -import { AskUserQuestionTool } from './tools/AskUserQuestionTool/AskUserQuestionTool.js' -import { LSPTool } from './tools/LSPTool/LSPTool.js' -import { ListMcpResourcesTool } from './tools/ListMcpResourcesTool/ListMcpResourcesTool.js' -import { ReadMcpResourceTool } from './tools/ReadMcpResourceTool/ReadMcpResourceTool.js' -import { ToolSearchTool } from './tools/ToolSearchTool/ToolSearchTool.js' -import { EnterPlanModeTool } from './tools/EnterPlanModeTool/EnterPlanModeTool.js' -import { EnterWorktreeTool } from './tools/EnterWorktreeTool/EnterWorktreeTool.js' -import { ExitWorktreeTool } from './tools/ExitWorktreeTool/ExitWorktreeTool.js' -import { ConfigTool } from './tools/ConfigTool/ConfigTool.js' -import { TaskCreateTool } from './tools/TaskCreateTool/TaskCreateTool.js' -import { TaskGetTool } from './tools/TaskGetTool/TaskGetTool.js' -import { TaskUpdateTool } from './tools/TaskUpdateTool/TaskUpdateTool.js' -import { TaskListTool } from './tools/TaskListTool/TaskListTool.js' +import { AskUserQuestionTool } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/AskUserQuestionTool.js' +import { LSPTool } from '@claude-code-best/builtin-tools/tools/LSPTool/LSPTool.js' +import { ListMcpResourcesTool } from '@claude-code-best/builtin-tools/tools/ListMcpResourcesTool/ListMcpResourcesTool.js' +import { ReadMcpResourceTool } from '@claude-code-best/builtin-tools/tools/ReadMcpResourceTool/ReadMcpResourceTool.js' +import { ToolSearchTool } from '@claude-code-best/builtin-tools/tools/ToolSearchTool/ToolSearchTool.js' +import { EnterPlanModeTool } from '@claude-code-best/builtin-tools/tools/EnterPlanModeTool/EnterPlanModeTool.js' +import { EnterWorktreeTool } from '@claude-code-best/builtin-tools/tools/EnterWorktreeTool/EnterWorktreeTool.js' +import { ExitWorktreeTool } from '@claude-code-best/builtin-tools/tools/ExitWorktreeTool/ExitWorktreeTool.js' +import { ConfigTool } from '@claude-code-best/builtin-tools/tools/ConfigTool/ConfigTool.js' +import { TaskCreateTool } from '@claude-code-best/builtin-tools/tools/TaskCreateTool/TaskCreateTool.js' +import { TaskGetTool } from '@claude-code-best/builtin-tools/tools/TaskGetTool/TaskGetTool.js' +import { TaskUpdateTool } from '@claude-code-best/builtin-tools/tools/TaskUpdateTool/TaskUpdateTool.js' +import { TaskListTool } from '@claude-code-best/builtin-tools/tools/TaskListTool/TaskListTool.js' import uniqBy from 'lodash-es/uniqBy.js' import { isToolSearchEnabledOptimistic } from './utils/toolSearch.js' import { isTodoV2Enabled } from './utils/tasks.js' @@ -88,11 +88,11 @@ import { isTodoV2Enabled } from './utils/tasks.js' /* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */ const VerifyPlanExecutionTool = process.env.CLAUDE_CODE_VERIFY_PLAN === 'true' - ? require('./tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.js') + ? require('@claude-code-best/builtin-tools/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.js') .VerifyPlanExecutionTool : null /* eslint-enable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */ -import { SYNTHETIC_OUTPUT_TOOL_NAME } from './tools/SyntheticOutputTool/SyntheticOutputTool.js' +import { SYNTHETIC_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SyntheticOutputTool/SyntheticOutputTool.js' export { ALL_AGENT_DISALLOWED_TOOLS, CUSTOM_AGENT_DISALLOWED_TOOLS, @@ -103,35 +103,35 @@ import { feature } from 'bun:bundle' // Dead code elimination: conditional import for OVERFLOW_TEST_TOOL /* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */ const OverflowTestTool = feature('OVERFLOW_TEST_TOOL') - ? require('./tools/OverflowTestTool/OverflowTestTool.js').OverflowTestTool + ? require('@claude-code-best/builtin-tools/tools/OverflowTestTool/OverflowTestTool.js').OverflowTestTool : null const CtxInspectTool = feature('CONTEXT_COLLAPSE') - ? require('./tools/CtxInspectTool/CtxInspectTool.js').CtxInspectTool + ? require('@claude-code-best/builtin-tools/tools/CtxInspectTool/CtxInspectTool.js').CtxInspectTool : null const TerminalCaptureTool = feature('TERMINAL_PANEL') - ? require('./tools/TerminalCaptureTool/TerminalCaptureTool.js') + ? require('@claude-code-best/builtin-tools/tools/TerminalCaptureTool/TerminalCaptureTool.js') .TerminalCaptureTool : null const WebBrowserTool = feature('WEB_BROWSER_TOOL') - ? require('./tools/WebBrowserTool/WebBrowserTool.js').WebBrowserTool + ? require('@claude-code-best/builtin-tools/tools/WebBrowserTool/WebBrowserTool.js').WebBrowserTool : null const coordinatorModeModule = feature('COORDINATOR_MODE') ? (require('./coordinator/coordinatorMode.js') as typeof import('./coordinator/coordinatorMode.js')) : null const SnipTool = feature('HISTORY_SNIP') - ? require('./tools/SnipTool/SnipTool.js').SnipTool + ? require('@claude-code-best/builtin-tools/tools/SnipTool/SnipTool.js').SnipTool : null const ReviewArtifactTool = feature('REVIEW_ARTIFACT') - ? require('./tools/ReviewArtifactTool/ReviewArtifactTool.js') + ? require('@claude-code-best/builtin-tools/tools/ReviewArtifactTool/ReviewArtifactTool.js') .ReviewArtifactTool : null const ListPeersTool = feature('UDS_INBOX') - ? require('./tools/ListPeersTool/ListPeersTool.js').ListPeersTool + ? require('@claude-code-best/builtin-tools/tools/ListPeersTool/ListPeersTool.js').ListPeersTool : null const WorkflowTool = feature('WORKFLOW_SCRIPTS') ? (() => { - require('./tools/WorkflowTool/bundled/index.js').initBundledWorkflows() - return require('./tools/WorkflowTool/WorkflowTool.js').WorkflowTool + require('@claude-code-best/builtin-tools/tools/WorkflowTool/bundled/index.js').initBundledWorkflows() + return require('@claude-code-best/builtin-tools/tools/WorkflowTool/WorkflowTool.js').WorkflowTool })() : null /* eslint-enable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */ @@ -146,13 +146,13 @@ import { REPL_TOOL_NAME, REPL_ONLY_TOOLS, isReplModeEnabled, -} from './tools/REPLTool/constants.js' +} from '@claude-code-best/builtin-tools/tools/REPLTool/constants.js' export { REPL_ONLY_TOOLS } /* eslint-disable @typescript-eslint/no-require-imports */ const getPowerShellTool = () => { if (!isPowerShellToolEnabled()) return null return ( - require('./tools/PowerShellTool/PowerShellTool.js') as typeof import('./tools/PowerShellTool/PowerShellTool.js') + require('@claude-code-best/builtin-tools/tools/PowerShellTool/PowerShellTool.js') as typeof import('@claude-code-best/builtin-tools/tools/PowerShellTool/PowerShellTool.js') ).PowerShellTool } /* eslint-enable @typescript-eslint/no-require-imports */ diff --git a/src/types/message.ts b/src/types/message.ts index fce9b433e..567bae475 100644 --- a/src/types/message.ts +++ b/src/types/message.ts @@ -9,7 +9,7 @@ import type { BranchAction, CommitKind, PrAction, -} from '../tools/shared/gitOperationTracking.js' +} from '@claude-code-best/builtin-tools/tools/shared/gitOperationTracking.js' /** * Base message type with discriminant `type` field and common properties. diff --git a/src/utils/analyzeContext.ts b/src/utils/analyzeContext.ts index 4af0f8f73..329ba6508 100644 --- a/src/utils/analyzeContext.ts +++ b/src/utils/analyzeContext.ts @@ -32,12 +32,12 @@ import { import type { AgentDefinition, AgentDefinitionsResult, -} from '../tools/AgentTool/loadAgentsDir.js' -import { SKILL_TOOL_NAME } from '../tools/SkillTool/constants.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { SKILL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SkillTool/constants.js' import { getLimitedSkillToolCommands, getSkillToolInfo as getSlashCommandInfo, -} from '../tools/SkillTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/SkillTool/prompt.js' import type { AssistantMessage, AttachmentMessage, @@ -384,7 +384,7 @@ async function countBuiltInToolTokens( // Check if tool search is enabled const { isToolSearchEnabled } = await import('./toolSearch.js') - const { isDeferredTool } = await import('../tools/ToolSearchTool/prompt.js') + const { isDeferredTool } = await import('@claude-code-best/builtin-tools/tools/ToolSearchTool/prompt.js') const isDeferred = await isToolSearchEnabled( model ?? '', tools, @@ -668,7 +668,7 @@ export async function countMcpToolTokens( // Check if tool search is enabled - if so, MCP tools are deferred // isToolSearchEnabled handles threshold calculation internally for TstAuto mode const { isToolSearchEnabled } = await import('./toolSearch.js') - const { isDeferredTool } = await import('../tools/ToolSearchTool/prompt.js') + const { isDeferredTool } = await import('@claude-code-best/builtin-tools/tools/ToolSearchTool/prompt.js') const isDeferred = await isToolSearchEnabled( model, diff --git a/src/utils/api.ts b/src/utils/api.ts index 9b66fd798..8cc347457 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -17,23 +17,23 @@ import { } from 'src/services/analytics/index.js' import { prefetchAllMcpResources } from 'src/services/mcp/client.js' import type { ScopedMcpServerConfig } from 'src/services/mcp/types.js' -import { BashTool } from 'src/tools/BashTool/BashTool.js' -import { FileEditTool } from 'src/tools/FileEditTool/FileEditTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' +import { FileEditTool } from '@claude-code-best/builtin-tools/tools/FileEditTool/FileEditTool.js' import { normalizeFileEditInput, stripTrailingWhitespace, -} from 'src/tools/FileEditTool/utils.js' -import { FileWriteTool } from 'src/tools/FileWriteTool/FileWriteTool.js' +} from '@claude-code-best/builtin-tools/tools/FileEditTool/utils.js' +import { FileWriteTool } from '@claude-code-best/builtin-tools/tools/FileWriteTool/FileWriteTool.js' import { getTools } from 'src/tools.js' import type { AgentId } from 'src/types/ids.js' import type { z } from 'zod/v4' import { CLI_SYSPROMPT_PREFIXES } from '../constants/system.js' import { roughTokenCountEstimation } from '../services/tokenEstimation.js' import type { Tool, ToolPermissionContext, Tools } from '../Tool.js' -import { AGENT_TOOL_NAME } from '../tools/AgentTool/constants.js' -import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js' -import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '../tools/ExitPlanModeTool/constants.js' -import { TASK_OUTPUT_TOOL_NAME } from '../tools/TaskOutputTool/constants.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' +import { TASK_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskOutputTool/constants.js' import type { Message } from '../types/message.js' import { isAgentSwarmsEnabled } from './agentSwarmsEnabled.js' import { diff --git a/src/utils/attachments.ts b/src/utils/attachments.ts index e92b712d9..eccd59ebd 100644 --- a/src/utils/attachments.ts +++ b/src/utils/attachments.ts @@ -14,7 +14,7 @@ import { MaxFileReadTokenExceededError, type Output as FileReadToolOutput, readImageWithTokenBudget, -} from '../tools/FileReadTool/FileReadTool.js' +} from '@claude-code-best/builtin-tools/tools/FileReadTool/FileReadTool.js' import { FileTooLargeError, readFileInRange } from './readFileInRange.js' import { expandPath } from './path.js' import { countCharInString } from './stringUtils.js' @@ -22,11 +22,11 @@ import { count, uniq } from './array.js' import { getFsImplementation } from './fsOperations.js' import { readdir, stat } from 'fs/promises' import type { IDESelection } from '../hooks/useIdeSelection.js' -import { TODO_WRITE_TOOL_NAME } from '../tools/TodoWriteTool/constants.js' -import { TASK_CREATE_TOOL_NAME } from '../tools/TaskCreateTool/constants.js' -import { TASK_UPDATE_TOOL_NAME } from '../tools/TaskUpdateTool/constants.js' -import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js' -import { SKILL_TOOL_NAME } from '../tools/SkillTool/constants.js' +import { TODO_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TodoWriteTool/constants.js' +import { TASK_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskCreateTool/constants.js' +import { TASK_UPDATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskUpdateTool/constants.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { SKILL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SkillTool/constants.js' import type { TodoList } from './todo/types.js' import { type Task, @@ -64,7 +64,7 @@ import { } from 'src/types/textInputTypes.js' import { randomUUID, type UUID } from 'crypto' import { getSettings_DEPRECATED } from './settings/settings.js' -import { getSnippetForTwoFileDiff } from 'src/tools/FileEditTool/utils.js' +import { getSnippetForTwoFileDiff } from '@claude-code-best/builtin-tools/tools/FileEditTool/utils.js' import type { ContentBlockParam, ImageBlockParam, @@ -83,7 +83,7 @@ import { getSkillToolCommands, getMcpSkillCommands } from '../commands.js' import type { Command } from '../types/command.js' import uniqBy from 'lodash-es/uniqBy.js' import { getProjectRoot } from '../bootstrap/state.js' -import { formatCommandsWithinBudget } from '../tools/SkillTool/prompt.js' +import { formatCommandsWithinBudget } from '@claude-code-best/builtin-tools/tools/SkillTool/prompt.js' import { getContextWindowForModel } from './context.js' import type { DiscoverySignal } from '../services/skillSearch/signals.js' // Conditional require for DCE. All skill-search string literals that would @@ -107,8 +107,8 @@ const autoModeStateModule = feature('TRANSCRIPT_CLASSIFIER') import { MAX_LINES_TO_READ, FILE_READ_TOOL_NAME, -} from 'src/tools/FileReadTool/prompt.js' -import { getDefaultFileReadingLimits } from 'src/tools/FileReadTool/limits.js' +} from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { getDefaultFileReadingLimits } from '@claude-code-best/builtin-tools/tools/FileReadTool/limits.js' import { cacheKeys, type FileStateCache } from './fileStateCache.js' import { createAbortController, @@ -119,13 +119,13 @@ import { getFileModificationTimeAsync, isFileWithinReadSizeLimit, } from './file.js' -import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js' -import { filterAgentsByMcpRequirements } from '../tools/AgentTool/loadAgentsDir.js' -import { AGENT_TOOL_NAME } from '../tools/AgentTool/constants.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { filterAgentsByMcpRequirements } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' import { formatAgentLine, shouldInjectAgentListInMessages, -} from '../tools/AgentTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/prompt.js' import { filterDeniedAgents } from './permissions/permissions.js' import { getSubscriptionType } from './auth.js' import { mcpInfoFromString } from '../services/mcp/mcpStringUtils.js' @@ -200,7 +200,7 @@ import { feature } from 'bun:bundle' const BRIEF_TOOL_NAME: string | null = feature('KAIROS') || feature('KAIROS_BRIEF') ? ( - require('../tools/BriefTool/prompt.js') as typeof import('../tools/BriefTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') ).BRIEF_TOOL_NAME : null const sessionTranscriptModule = feature('KAIROS') @@ -232,7 +232,7 @@ import { isAgentSwarmsEnabled } from './agentSwarmsEnabled.js' import { findRelevantMemories } from '../memdir/findRelevantMemories.js' import { memoryAge, memoryFreshnessText } from '../memdir/memoryAge.js' import { getAutoMemPath, isAutoMemoryEnabled } from '../memdir/paths.js' -import { getAgentMemoryDir } from '../tools/AgentTool/agentMemory.js' +import { getAgentMemoryDir } from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js' import { readUnreadMessages, markMessagesAsReadByPredicate, diff --git a/src/utils/attribution.ts b/src/utils/attribution.ts index fbce4237f..d76291637 100644 --- a/src/utils/attribution.ts +++ b/src/utils/attribution.ts @@ -8,11 +8,11 @@ import { } from '../constants/product.js' import { TERMINAL_OUTPUT_TAGS } from '../constants/xml.js' import type { AppState } from '../state/AppState.js' -import { FILE_EDIT_TOOL_NAME } from '../tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from '../tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from '../tools/FileWriteTool/prompt.js' -import { GLOB_TOOL_NAME } from '../tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from '../tools/GrepTool/prompt.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' import type { Entry } from '../types/logs.js' import { type AttributionData, diff --git a/src/utils/claudeInChrome/toolRendering.tsx b/src/utils/claudeInChrome/toolRendering.tsx index 6f77bcf0b..362cb3dcd 100644 --- a/src/utils/claudeInChrome/toolRendering.tsx +++ b/src/utils/claudeInChrome/toolRendering.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { MessageResponse } from '../../components/MessageResponse.js' import { supportsHyperlinks } from '@anthropic/ink' import { Link, Text } from '@anthropic/ink' -import { renderToolResultMessage as renderDefaultMCPToolResultMessage } from '../../tools/MCPTool/UI.js' +import { renderToolResultMessage as renderDefaultMCPToolResultMessage } from '@claude-code-best/builtin-tools/tools/MCPTool/UI.js' import type { MCPToolResult } from '../../utils/mcpValidation.js' import { truncateToWidth } from '../format.js' import { trackClaudeInChromeTabId } from './common.js' diff --git a/src/utils/collapseReadSearch.ts b/src/utils/collapseReadSearch.ts index ad905008e..6f80a36fa 100644 --- a/src/utils/collapseReadSearch.ts +++ b/src/utils/collapseReadSearch.ts @@ -1,19 +1,19 @@ import { feature } from 'bun:bundle' import type { UUID } from 'crypto' import { findToolByName, type Tools } from '../Tool.js' -import { extractBashCommentLabel } from '../tools/BashTool/commentLabel.js' -import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js' -import { FILE_EDIT_TOOL_NAME } from '../tools/FileEditTool/constants.js' -import { FILE_WRITE_TOOL_NAME } from '../tools/FileWriteTool/prompt.js' -import { REPL_TOOL_NAME } from '../tools/REPLTool/constants.js' -import { getReplPrimitiveTools } from '../tools/REPLTool/primitiveTools.js' +import { extractBashCommentLabel } from '@claude-code-best/builtin-tools/tools/BashTool/commentLabel.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { REPL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/REPLTool/constants.js' +import { getReplPrimitiveTools } from '@claude-code-best/builtin-tools/tools/REPLTool/primitiveTools.js' import { type BranchAction, type CommitKind, detectGitOperation, type PrAction, -} from '../tools/shared/gitOperationTracking.js' -import { TOOL_SEARCH_TOOL_NAME } from '../tools/ToolSearchTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/shared/gitOperationTracking.js' +import { TOOL_SEARCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ToolSearchTool/prompt.js' import type { CollapsedReadSearchGroup, CollapsibleMessage, @@ -56,7 +56,7 @@ const teamMemOps = feature('TEAMMEM') : null const SNIP_TOOL_NAME = feature('HISTORY_SNIP') ? ( - require('../tools/SnipTool/prompt.js') as typeof import('../tools/SnipTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/SnipTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/SnipTool/prompt.js') ).SNIP_TOOL_NAME : null /* eslint-enable @typescript-eslint/no-require-imports */ diff --git a/src/utils/contextSuggestions.ts b/src/utils/contextSuggestions.ts index 6959e128b..33852da2e 100644 --- a/src/utils/contextSuggestions.ts +++ b/src/utils/contextSuggestions.ts @@ -1,7 +1,7 @@ -import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js' -import { FILE_READ_TOOL_NAME } from '../tools/FileReadTool/prompt.js' -import { GREP_TOOL_NAME } from '../tools/GrepTool/prompt.js' -import { WEB_FETCH_TOOL_NAME } from '../tools/WebFetchTool/prompt.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js' import type { ContextData } from './analyzeContext.js' import { getDisplayPath } from './file.js' import { formatTokens } from './format.js' diff --git a/src/utils/conversationRecovery.ts b/src/utils/conversationRecovery.ts index 4afbd2862..51c36520c 100644 --- a/src/utils/conversationRecovery.ts +++ b/src/utils/conversationRecovery.ts @@ -55,18 +55,18 @@ import type { ContentReplacementRecord } from './toolResultStorage.js' const BRIEF_TOOL_NAME: string | null = feature('KAIROS') || feature('KAIROS_BRIEF') ? ( - require('../tools/BriefTool/prompt.js') as typeof import('../tools/BriefTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') ).BRIEF_TOOL_NAME : null const LEGACY_BRIEF_TOOL_NAME: string | null = feature('KAIROS') || feature('KAIROS_BRIEF') ? ( - require('../tools/BriefTool/prompt.js') as typeof import('../tools/BriefTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') ).LEGACY_BRIEF_TOOL_NAME : null const SEND_USER_FILE_TOOL_NAME: string | null = feature('KAIROS') ? ( - require('../tools/SendUserFileTool/prompt.js') as typeof import('../tools/SendUserFileTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/SendUserFileTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/SendUserFileTool/prompt.js') ).SEND_USER_FILE_TOOL_NAME : null /* eslint-enable @typescript-eslint/no-require-imports */ diff --git a/src/utils/diff.ts b/src/utils/diff.ts index 38e7c1bf6..630a00d7d 100644 --- a/src/utils/diff.ts +++ b/src/utils/diff.ts @@ -2,7 +2,7 @@ import { type StructuredPatchHunk, structuredPatch } from 'diff' import { logEvent } from 'src/services/analytics/index.js' import { getLocCounter } from '../bootstrap/state.js' import { addToTotalLinesChanged } from '../cost-tracker.js' -import type { FileEdit } from '../tools/FileEditTool/types.js' +import type { FileEdit } from '@claude-code-best/builtin-tools/tools/FileEditTool/types.js' import { count } from './array.js' import { convertLeadingTabsToSpaces } from './file.js' diff --git a/src/utils/doctorContextWarnings.ts b/src/utils/doctorContextWarnings.ts index fb77a34ba..c2684e1d0 100644 --- a/src/utils/doctorContextWarnings.ts +++ b/src/utils/doctorContextWarnings.ts @@ -1,6 +1,6 @@ import { roughTokenCountEstimation } from '../services/tokenEstimation.js' import type { Tool, ToolPermissionContext } from '../Tool.js' -import type { AgentDefinitionsResult } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinitionsResult } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { countMcpToolTokens } from './analyzeContext.js' import { getLargeMemoryFiles, diff --git a/src/utils/forkedAgent.ts b/src/utils/forkedAgent.ts index 94c95b122..c6717b1ff 100644 --- a/src/utils/forkedAgent.ts +++ b/src/utils/forkedAgent.ts @@ -21,7 +21,7 @@ import { import { accumulateUsage, updateUsage } from '../services/api/claude.js' import { EMPTY_USAGE, type NonNullableUsage } from '../services/api/logging.js' import type { ToolUseContext } from '../Tool.js' -import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import type { AgentId } from '../types/ids.js' import type { Message } from '../types/message.js' import { createChildAbortController } from './abortController.js' diff --git a/src/utils/hooks/execAgentHook.ts b/src/utils/hooks/execAgentHook.ts index be133fb40..290e68ed4 100644 --- a/src/utils/hooks/execAgentHook.ts +++ b/src/utils/hooks/execAgentHook.ts @@ -5,7 +5,7 @@ import { logEvent } from '../../services/analytics/index.js' import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from '../../services/analytics/metadata.js' import type { ToolUseContext } from '../../Tool.js' import { type Tool, toolMatchesName } from '../../Tool.js' -import { SYNTHETIC_OUTPUT_TOOL_NAME } from '../../tools/SyntheticOutputTool/SyntheticOutputTool.js' +import { SYNTHETIC_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SyntheticOutputTool/SyntheticOutputTool.js' import { ALL_AGENT_DISALLOWED_TOOLS } from '../../tools.js' import { asAgentId } from '../../types/ids.js' import type { Message } from '../../types/message.js' diff --git a/src/utils/hooks/hookHelpers.ts b/src/utils/hooks/hookHelpers.ts index c6bed459a..f4231d03d 100644 --- a/src/utils/hooks/hookHelpers.ts +++ b/src/utils/hooks/hookHelpers.ts @@ -3,7 +3,7 @@ import type { Tool } from '../../Tool.js' import { SYNTHETIC_OUTPUT_TOOL_NAME, SyntheticOutputTool, -} from '../../tools/SyntheticOutputTool/SyntheticOutputTool.js' +} from '@claude-code-best/builtin-tools/tools/SyntheticOutputTool/SyntheticOutputTool.js' import { substituteArguments } from '../argumentSubstitution.js' import { lazySchema } from '../lazySchema.js' import type { SetAppState } from '../messageQueueManager.js' diff --git a/src/utils/imagePaste.ts b/src/utils/imagePaste.ts index ee1696a44..4f6005d3b 100644 --- a/src/utils/imagePaste.ts +++ b/src/utils/imagePaste.ts @@ -8,7 +8,7 @@ import { IMAGE_TARGET_RAW_SIZE, } from '../constants/apiLimits.js' import { getFeatureValue_CACHED_MAY_BE_STALE } from '../services/analytics/growthbook.js' -import { getImageProcessor } from '../tools/FileReadTool/imageProcessor.js' +import { getImageProcessor } from '@claude-code-best/builtin-tools/tools/FileReadTool/imageProcessor.js' import { logForDebugging } from './debug.js' import { execFileNoThrowWithCwd } from './execFileNoThrow.js' import { getFsImplementation } from './fsOperations.js' diff --git a/src/utils/imageResizer.ts b/src/utils/imageResizer.ts index 149b4087e..f7c7347d1 100644 --- a/src/utils/imageResizer.ts +++ b/src/utils/imageResizer.ts @@ -13,7 +13,7 @@ import { getImageProcessor, type SharpFunction, type SharpInstance, -} from '../tools/FileReadTool/imageProcessor.js' +} from '@claude-code-best/builtin-tools/tools/FileReadTool/imageProcessor.js' import { logForDebugging } from './debug.js' import { errorMessage } from './errors.js' import { formatFileSize } from './format.js' diff --git a/src/utils/ink.ts b/src/utils/ink.ts index 915837bc9..b6849b37b 100644 --- a/src/utils/ink.ts +++ b/src/utils/ink.ts @@ -2,7 +2,7 @@ import type { TextProps } from '@anthropic/ink' import { AGENT_COLOR_TO_THEME_COLOR, type AgentColorName, -} from '../tools/AgentTool/agentColorManager.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' const DEFAULT_AGENT_THEME_COLOR = 'cyan_FOR_SUBAGENTS_ONLY' diff --git a/src/utils/memoryFileDetection.ts b/src/utils/memoryFileDetection.ts index 528bbad41..e60398e2b 100644 --- a/src/utils/memoryFileDetection.ts +++ b/src/utils/memoryFileDetection.ts @@ -6,7 +6,7 @@ import { isAutoMemoryEnabled, isAutoMemPath, } from '../memdir/paths.js' -import { isAgentMemoryPath } from '../tools/AgentTool/agentMemory.js' +import { isAgentMemoryPath } from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js' import { getClaudeConfigHomeDir } from './envUtils.js' import { posixPathToWindowsPath, diff --git a/src/utils/messages.ts b/src/utils/messages.ts index 0d58b9b33..ab1bd122a 100644 --- a/src/utils/messages.ts +++ b/src/utils/messages.ts @@ -104,21 +104,21 @@ import type { HookEvent, SDKAssistantMessageError, } from 'src/entrypoints/agentSdkTypes.js' -import { EXPLORE_AGENT } from 'src/tools/AgentTool/built-in/exploreAgent.js' -import { PLAN_AGENT } from 'src/tools/AgentTool/built-in/planAgent.js' -import { areExplorePlanAgentsEnabled } from 'src/tools/AgentTool/builtInAgents.js' -import { AGENT_TOOL_NAME } from 'src/tools/AgentTool/constants.js' -import { ASK_USER_QUESTION_TOOL_NAME } from 'src/tools/AskUserQuestionTool/prompt.js' -import { BashTool } from 'src/tools/BashTool/BashTool.js' -import { ExitPlanModeV2Tool } from 'src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' -import { FileEditTool } from 'src/tools/FileEditTool/FileEditTool.js' +import { EXPLORE_AGENT } from '@claude-code-best/builtin-tools/tools/AgentTool/built-in/exploreAgent.js' +import { PLAN_AGENT } from '@claude-code-best/builtin-tools/tools/AgentTool/built-in/planAgent.js' +import { areExplorePlanAgentsEnabled } from '@claude-code-best/builtin-tools/tools/AgentTool/builtInAgents.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { ASK_USER_QUESTION_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/prompt.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' +import { ExitPlanModeV2Tool } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js' +import { FileEditTool } from '@claude-code-best/builtin-tools/tools/FileEditTool/FileEditTool.js' import { FILE_READ_TOOL_NAME, MAX_LINES_TO_READ, -} from 'src/tools/FileReadTool/prompt.js' -import { FileWriteTool } from 'src/tools/FileWriteTool/FileWriteTool.js' -import { GLOB_TOOL_NAME } from 'src/tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from 'src/tools/GrepTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FileWriteTool } from '@claude-code-best/builtin-tools/tools/FileWriteTool/FileWriteTool.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' import type { DeepImmutable } from 'src/types/utils.js' import { getStrictToolResultPairing } from '../bootstrap/state.js' import type { SpinnerMode } from '../components/Spinner.js' @@ -139,11 +139,11 @@ import { import { FileReadTool, type Output as FileReadToolOutput, -} from '../tools/FileReadTool/FileReadTool.js' -import { SEND_MESSAGE_TOOL_NAME } from '../tools/SendMessageTool/constants.js' -import { TASK_CREATE_TOOL_NAME } from '../tools/TaskCreateTool/constants.js' -import { TASK_OUTPUT_TOOL_NAME } from '../tools/TaskOutputTool/constants.js' -import { TASK_UPDATE_TOOL_NAME } from '../tools/TaskUpdateTool/constants.js' +} from '@claude-code-best/builtin-tools/tools/FileReadTool/FileReadTool.js' +import { SEND_MESSAGE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SendMessageTool/constants.js' +import { TASK_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskCreateTool/constants.js' +import { TASK_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskOutputTool/constants.js' +import { TASK_UPDATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskUpdateTool/constants.js' import type { PermissionMode } from '../types/permissions.js' import { normalizeToolInput, normalizeToolInputForAPI } from './api.js' import { getCurrentProjectConfig } from './config.js' diff --git a/src/utils/messages/mappers.ts b/src/utils/messages/mappers.ts index d04a4235e..c8d4e1046 100644 --- a/src/utils/messages/mappers.ts +++ b/src/utils/messages/mappers.ts @@ -13,7 +13,7 @@ import type { SDKRateLimitInfo, } from 'src/entrypoints/agentSdkTypes.js' import type { ClaudeAILimits } from 'src/services/claudeAiLimits.js' -import { EXIT_PLAN_MODE_V2_TOOL_NAME } from 'src/tools/ExitPlanModeTool/constants.js' +import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' import type { AssistantMessage, CompactMetadata, diff --git a/src/utils/messages/systemInit.ts b/src/utils/messages/systemInit.ts index 0530b8709..fcb9e74d1 100644 --- a/src/utils/messages/systemInit.ts +++ b/src/utils/messages/systemInit.ts @@ -10,7 +10,7 @@ import type { import { AGENT_TOOL_NAME, LEGACY_AGENT_TOOL_NAME, -} from 'src/tools/AgentTool/constants.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' import { getAnthropicApiKeyWithSource } from '../auth.js' import { getCwd } from '../cwd.js' import { getFastModeState } from '../fastMode.js' diff --git a/src/utils/notebook.ts b/src/utils/notebook.ts index 8640e2685..59067eaac 100644 --- a/src/utils/notebook.ts +++ b/src/utils/notebook.ts @@ -3,8 +3,8 @@ import type { TextBlockParam, ToolResultBlockParam, } from '@anthropic-ai/sdk/resources/index.mjs' -import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js' -import { formatOutput } from '../tools/BashTool/utils.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { formatOutput } from '@claude-code-best/builtin-tools/tools/BashTool/utils.js' import type { NotebookCell, NotebookCellOutput, diff --git a/src/utils/permissions/classifierDecision.ts b/src/utils/permissions/classifierDecision.ts index d329ebafd..0e3938744 100644 --- a/src/utils/permissions/classifierDecision.ts +++ b/src/utils/permissions/classifierDecision.ts @@ -1,24 +1,24 @@ import { feature } from 'bun:bundle' -import { ASK_USER_QUESTION_TOOL_NAME } from '../../tools/AskUserQuestionTool/prompt.js' -import { ENTER_PLAN_MODE_TOOL_NAME } from '../../tools/EnterPlanModeTool/constants.js' -import { EXIT_PLAN_MODE_TOOL_NAME } from '../../tools/ExitPlanModeTool/constants.js' -import { FILE_READ_TOOL_NAME } from '../../tools/FileReadTool/prompt.js' -import { GLOB_TOOL_NAME } from '../../tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from '../../tools/GrepTool/prompt.js' -import { LIST_MCP_RESOURCES_TOOL_NAME } from '../../tools/ListMcpResourcesTool/prompt.js' -import { LSP_TOOL_NAME } from '../../tools/LSPTool/prompt.js' -import { SEND_MESSAGE_TOOL_NAME } from '../../tools/SendMessageTool/constants.js' -import { SLEEP_TOOL_NAME } from '../../tools/SleepTool/prompt.js' -import { TASK_CREATE_TOOL_NAME } from '../../tools/TaskCreateTool/constants.js' -import { TASK_GET_TOOL_NAME } from '../../tools/TaskGetTool/constants.js' -import { TASK_LIST_TOOL_NAME } from '../../tools/TaskListTool/constants.js' -import { TASK_OUTPUT_TOOL_NAME } from '../../tools/TaskOutputTool/constants.js' -import { TASK_STOP_TOOL_NAME } from '../../tools/TaskStopTool/prompt.js' -import { TASK_UPDATE_TOOL_NAME } from '../../tools/TaskUpdateTool/constants.js' -import { TEAM_CREATE_TOOL_NAME } from '../../tools/TeamCreateTool/constants.js' -import { TEAM_DELETE_TOOL_NAME } from '../../tools/TeamDeleteTool/constants.js' -import { TODO_WRITE_TOOL_NAME } from '../../tools/TodoWriteTool/constants.js' -import { TOOL_SEARCH_TOOL_NAME } from '../../tools/ToolSearchTool/prompt.js' +import { ASK_USER_QUESTION_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AskUserQuestionTool/prompt.js' +import { ENTER_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/EnterPlanModeTool/constants.js' +import { EXIT_PLAN_MODE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { LIST_MCP_RESOURCES_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ListMcpResourcesTool/prompt.js' +import { LSP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/LSPTool/prompt.js' +import { SEND_MESSAGE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SendMessageTool/constants.js' +import { SLEEP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SleepTool/prompt.js' +import { TASK_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskCreateTool/constants.js' +import { TASK_GET_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskGetTool/constants.js' +import { TASK_LIST_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskListTool/constants.js' +import { TASK_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskOutputTool/constants.js' +import { TASK_STOP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskStopTool/prompt.js' +import { TASK_UPDATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskUpdateTool/constants.js' +import { TEAM_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamCreateTool/constants.js' +import { TEAM_DELETE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamDeleteTool/constants.js' +import { TODO_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TodoWriteTool/constants.js' +import { TOOL_SEARCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ToolSearchTool/prompt.js' import { YOLO_CLASSIFIER_TOOL_NAME } from './yoloClassifier.js' // Ant-only tool names: conditional require so Bun can DCE these in external builds. @@ -26,23 +26,23 @@ import { YOLO_CLASSIFIER_TOOL_NAME } from './yoloClassifier.js' /* eslint-disable @typescript-eslint/no-require-imports */ const TERMINAL_CAPTURE_TOOL_NAME = feature('TERMINAL_PANEL') ? ( - require('../../tools/TerminalCaptureTool/prompt.js') as typeof import('../../tools/TerminalCaptureTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/TerminalCaptureTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/TerminalCaptureTool/prompt.js') ).TERMINAL_CAPTURE_TOOL_NAME : null const OVERFLOW_TEST_TOOL_NAME = feature('OVERFLOW_TEST_TOOL') ? ( - require('../../tools/OverflowTestTool/OverflowTestTool.js') as typeof import('../../tools/OverflowTestTool/OverflowTestTool.js') + require('@claude-code-best/builtin-tools/tools/OverflowTestTool/OverflowTestTool.js') as typeof import('@claude-code-best/builtin-tools/tools/OverflowTestTool/OverflowTestTool.js') ).OVERFLOW_TEST_TOOL_NAME : null const VERIFY_PLAN_EXECUTION_TOOL_NAME = process.env.USER_TYPE === 'ant' ? ( - require('../../tools/VerifyPlanExecutionTool/constants.js') as typeof import('../../tools/VerifyPlanExecutionTool/constants.js') + require('@claude-code-best/builtin-tools/tools/VerifyPlanExecutionTool/constants.js') as typeof import('@claude-code-best/builtin-tools/tools/VerifyPlanExecutionTool/constants.js') ).VERIFY_PLAN_EXECUTION_TOOL_NAME : null const WORKFLOW_TOOL_NAME = feature('WORKFLOW_SCRIPTS') ? ( - require('../../tools/WorkflowTool/constants.js') as typeof import('../../tools/WorkflowTool/constants.js') + require('@claude-code-best/builtin-tools/tools/WorkflowTool/constants.js') as typeof import('@claude-code-best/builtin-tools/tools/WorkflowTool/constants.js') ).WORKFLOW_TOOL_NAME : null /* eslint-enable @typescript-eslint/no-require-imports */ diff --git a/src/utils/permissions/filesystem.ts b/src/utils/permissions/filesystem.ts index 9fd709e7c..2340492cd 100644 --- a/src/utils/permissions/filesystem.ts +++ b/src/utils/permissions/filesystem.ts @@ -5,17 +5,17 @@ import memoize from 'lodash-es/memoize.js' import { homedir, tmpdir } from 'os' import { join, normalize, posix, sep } from 'path' import { hasAutoMemPathOverride, isAutoMemPath } from 'src/memdir/paths.js' -import { isAgentMemoryPath } from 'src/tools/AgentTool/agentMemory.js' +import { isAgentMemoryPath } from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js' import { CLAUDE_FOLDER_PERMISSION_PATTERN, FILE_EDIT_TOOL_NAME, GLOBAL_CLAUDE_FOLDER_PERMISSION_PATTERN, -} from 'src/tools/FileEditTool/constants.js' +} from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' import type { z } from 'zod/v4' import { getOriginalCwd, getSessionId } from '../../bootstrap/state.js' import { checkStatsigFeatureGate_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js' import type { AnyObject, Tool, ToolPermissionContext } from '../../Tool.js' -import { FILE_READ_TOOL_NAME } from '../../tools/FileReadTool/prompt.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' import { getCwd } from '../cwd.js' import { getClaudeConfigHomeDir } from '../envUtils.js' import { diff --git a/src/utils/permissions/permissionRuleParser.ts b/src/utils/permissions/permissionRuleParser.ts index 77ff0681f..233a63a75 100644 --- a/src/utils/permissions/permissionRuleParser.ts +++ b/src/utils/permissions/permissionRuleParser.ts @@ -1,7 +1,7 @@ import { feature } from 'bun:bundle' -import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' -import { TASK_OUTPUT_TOOL_NAME } from '../../tools/TaskOutputTool/constants.js' -import { TASK_STOP_TOOL_NAME } from '../../tools/TaskStopTool/prompt.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { TASK_OUTPUT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskOutputTool/constants.js' +import { TASK_STOP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskStopTool/prompt.js' import type { PermissionRuleValue } from './PermissionRule.js' // Dead code elimination: ant-only tool names are conditionally required so @@ -10,7 +10,7 @@ import type { PermissionRuleValue } from './PermissionRule.js' const BRIEF_TOOL_NAME: string | null = feature('KAIROS') || feature('KAIROS_BRIEF') ? ( - require('../../tools/BriefTool/prompt.js') as typeof import('../../tools/BriefTool/prompt.js') + require('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') as typeof import('@claude-code-best/builtin-tools/tools/BriefTool/prompt.js') ).BRIEF_TOOL_NAME : null /* eslint-enable @typescript-eslint/no-require-imports */ diff --git a/src/utils/permissions/permissionSetup.ts b/src/utils/permissions/permissionSetup.ts index 700d198d7..7275307f9 100644 --- a/src/utils/permissions/permissionSetup.ts +++ b/src/utils/permissions/permissionSetup.ts @@ -48,10 +48,10 @@ import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, } from '../../services/analytics/index.js' -import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' /* eslint-enable @typescript-eslint/no-require-imports */ -import { POWERSHELL_TOOL_NAME } from '../../tools/PowerShellTool/toolName.js' +import { POWERSHELL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/PowerShellTool/toolName.js' import { getToolsForDefaultPreset, parseToolPreset } from '../../tools.js' import { getFsImplementation, diff --git a/src/utils/permissions/permissions.ts b/src/utils/permissions/permissions.ts index e7dbc5c59..e023a4eb7 100644 --- a/src/utils/permissions/permissions.ts +++ b/src/utils/permissions/permissions.ts @@ -6,11 +6,11 @@ import { mcpInfoFromString, } from '../../services/mcp/mcpStringUtils.js' import type { Tool, ToolPermissionContext, ToolUseContext } from '../../Tool.js' -import { AGENT_TOOL_NAME } from '../../tools/AgentTool/constants.js' -import { shouldUseSandbox } from '../../tools/BashTool/shouldUseSandbox.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' -import { POWERSHELL_TOOL_NAME } from '../../tools/PowerShellTool/toolName.js' -import { REPL_TOOL_NAME } from '../../tools/REPLTool/constants.js' +import { AGENT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/AgentTool/constants.js' +import { shouldUseSandbox } from '@claude-code-best/builtin-tools/tools/BashTool/shouldUseSandbox.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { POWERSHELL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/PowerShellTool/toolName.js' +import { REPL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/REPLTool/constants.js' import type { AssistantMessage } from '../../types/message.js' import { extractOutputRedirections } from '../bash/commands.js' import { logForDebugging } from '../debug.js' diff --git a/src/utils/permissions/shadowedRuleDetection.ts b/src/utils/permissions/shadowedRuleDetection.ts index c54ce9417..35b9d48d8 100644 --- a/src/utils/permissions/shadowedRuleDetection.ts +++ b/src/utils/permissions/shadowedRuleDetection.ts @@ -1,5 +1,5 @@ import type { ToolPermissionContext } from '../../Tool.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' import type { PermissionRule, PermissionRuleSource } from './PermissionRule.js' import { getAllowRules, diff --git a/src/utils/plans.ts b/src/utils/plans.ts index 1842ab488..22ca6906f 100644 --- a/src/utils/plans.ts +++ b/src/utils/plans.ts @@ -11,7 +11,7 @@ import type { UserMessage, } from 'src/types/message.js' import { getPlanSlugCache, getSessionId } from '../bootstrap/state.js' -import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '../tools/ExitPlanModeTool/constants.js' +import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' import { getCwd } from './cwd.js' import { logForDebugging } from './debug.js' import { getClaudeConfigHomeDir } from './envUtils.js' diff --git a/src/utils/plugins/cacheUtils.ts b/src/utils/plugins/cacheUtils.ts index 969898eac..bd1013252 100644 --- a/src/utils/plugins/cacheUtils.ts +++ b/src/utils/plugins/cacheUtils.ts @@ -2,8 +2,8 @@ import { readdir, rm, stat, unlink, writeFile } from 'fs/promises' import { join } from 'path' import { clearCommandsCache } from '../../commands.js' import { clearAllOutputStylesCache } from '../../constants/outputStyles.js' -import { clearAgentDefinitionsCache } from '../../tools/AgentTool/loadAgentsDir.js' -import { clearPromptCache } from '../../tools/SkillTool/prompt.js' +import { clearAgentDefinitionsCache } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { clearPromptCache } from '@claude-code-best/builtin-tools/tools/SkillTool/prompt.js' import { resetSentSkillNames } from '../attachments.js' import { logForDebugging } from '../debug.js' import { getErrnoCode } from '../errors.js' diff --git a/src/utils/plugins/loadPluginAgents.ts b/src/utils/plugins/loadPluginAgents.ts index d335a1234..7dc9c31f7 100644 --- a/src/utils/plugins/loadPluginAgents.ts +++ b/src/utils/plugins/loadPluginAgents.ts @@ -1,15 +1,15 @@ import memoize from 'lodash-es/memoize.js' import { basename } from 'path' import { isAutoMemoryEnabled } from '../../memdir/paths.js' -import type { AgentColorName } from '../../tools/AgentTool/agentColorManager.js' +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { type AgentMemoryScope, loadAgentMemoryPrompt, -} from '../../tools/AgentTool/agentMemory.js' -import type { AgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' -import { FILE_EDIT_TOOL_NAME } from '../../tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from '../../tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from '../../tools/FileWriteTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/agentMemory.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' import { getPluginErrorMessage } from '../../types/plugin.js' import { logForDebugging } from '../debug.js' import { EFFORT_LEVELS, parseEffortValue } from '../effort.js' diff --git a/src/utils/plugins/refresh.ts b/src/utils/plugins/refresh.ts index fafbee676..b3a24fbe2 100644 --- a/src/utils/plugins/refresh.ts +++ b/src/utils/plugins/refresh.ts @@ -21,8 +21,8 @@ import { getOriginalCwd } from '../../bootstrap/state.js' import type { Command } from '../../commands.js' import { reinitializeLspServerManager } from '../../services/lsp/manager.js' import type { AppState } from '../../state/AppState.js' -import type { AgentDefinitionsResult } from '../../tools/AgentTool/loadAgentsDir.js' -import { getAgentDefinitionsWithOverrides } from '../../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinitionsResult } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { getAgentDefinitionsWithOverrides } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import type { PluginError } from '../../types/plugin.js' import { logForDebugging } from '../debug.js' import { errorMessage } from '../errors.js' diff --git a/src/utils/processUserInput/processBashCommand.tsx b/src/utils/processUserInput/processBashCommand.tsx index a8460d4d0..3c30ba4b4 100644 --- a/src/utils/processUserInput/processBashCommand.tsx +++ b/src/utils/processUserInput/processBashCommand.tsx @@ -3,7 +3,7 @@ import { randomUUID } from 'crypto' import * as React from 'react' import { BashModeProgress } from 'src/components/BashModeProgress.js' import type { SetToolJSXFn } from 'src/Tool.js' -import { BashTool } from 'src/tools/BashTool/BashTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' import type { AttachmentMessage, SystemMessage, @@ -99,12 +99,12 @@ export async function processBashCommand( // native, shouldUseSandbox() returns false regardless (unsupported platform). // Lazy-require PowerShellTool so its ~300KB chunk only loads when the // user has actually selected the powershell default shell. - type PSMod = typeof import('src/tools/PowerShellTool/PowerShellTool.js') + type PSMod = typeof import('@claude-code-best/builtin-tools/tools/PowerShellTool/PowerShellTool.js') let PowerShellTool: PSMod['PowerShellTool'] | null = null if (usePowerShell) { /* eslint-disable @typescript-eslint/no-require-imports */ PowerShellTool = ( - require('src/tools/PowerShellTool/PowerShellTool.js') as PSMod + require('@claude-code-best/builtin-tools/tools/PowerShellTool/PowerShellTool.js') as PSMod ).PowerShellTool /* eslint-enable @typescript-eslint/no-require-imports */ } diff --git a/src/utils/processUserInput/processSlashCommand.tsx b/src/utils/processUserInput/processSlashCommand.tsx index 9b16fe950..6ee4bfe93 100644 --- a/src/utils/processUserInput/processSlashCommand.tsx +++ b/src/utils/processUserInput/processSlashCommand.tsx @@ -36,9 +36,9 @@ import { import { getDumpPromptsPath } from '../../services/api/dumpPrompts.js' import { buildPostCompactMessages } from '../../services/compact/compact.js' import { resetMicrocompactState } from '../../services/compact/microCompact.js' -import type { Progress as AgentProgress } from '../../tools/AgentTool/AgentTool.js' -import { runAgent } from '../../tools/AgentTool/runAgent.js' -import { renderToolUseProgressMessage } from '../../tools/AgentTool/UI.js' +import type { Progress as AgentProgress } from '@claude-code-best/builtin-tools/tools/AgentTool/AgentTool.js' +import { runAgent } from '@claude-code-best/builtin-tools/tools/AgentTool/runAgent.js' +import { renderToolUseProgressMessage } from '@claude-code-best/builtin-tools/tools/AgentTool/UI.js' import type { CommandResultDisplay } from '../../types/command.js' import { createAbortController } from '../abortController.js' import { getAgentContext } from '../agentContext.js' diff --git a/src/utils/promptShellExecution.ts b/src/utils/promptShellExecution.ts index 942699461..2eb1bcbf3 100644 --- a/src/utils/promptShellExecution.ts +++ b/src/utils/promptShellExecution.ts @@ -1,6 +1,6 @@ import { randomUUID } from 'crypto' import type { Tool, ToolUseContext } from '../Tool.js' -import { BashTool } from '../tools/BashTool/BashTool.js' +import { BashTool } from '@claude-code-best/builtin-tools/tools/BashTool/BashTool.js' import { logForDebugging } from './debug.js' import { errorMessage, MalformedCommandError, ShellError } from './errors.js' import type { FrontmatterShell } from './frontmatterParser.js' @@ -37,7 +37,7 @@ const getPowerShellTool = (() => { return (): PromptShellTool => { if (!cached) { cached = ( - require('../tools/PowerShellTool/PowerShellTool.js') as typeof import('../tools/PowerShellTool/PowerShellTool.js') + require('@claude-code-best/builtin-tools/tools/PowerShellTool/PowerShellTool.js') as typeof import('@claude-code-best/builtin-tools/tools/PowerShellTool/PowerShellTool.js') ).PowerShellTool } return cached diff --git a/src/utils/queryContext.ts b/src/utils/queryContext.ts index 0312111cd..a95e56deb 100644 --- a/src/utils/queryContext.ts +++ b/src/utils/queryContext.ts @@ -15,7 +15,7 @@ import { getSystemContext, getUserContext } from '../context.js' import type { MCPServerConnection } from '../services/mcp/types.js' import type { AppState } from '../state/AppStateStore.js' import type { Tools, ToolUseContext } from '../Tool.js' -import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import type { Message } from '../types/message.js' import { createAbortController } from './abortController.js' import type { FileStateCache } from './fileStateCache.js' diff --git a/src/utils/queryHelpers.ts b/src/utils/queryHelpers.ts index c08428d69..a2d26ec38 100644 --- a/src/utils/queryHelpers.ts +++ b/src/utils/queryHelpers.ts @@ -8,14 +8,14 @@ import type { SDKMessage } from 'src/entrypoints/agentSdkTypes.js' import type { CanUseToolFn } from '../hooks/useCanUseTool.js' import { runTools } from '../services/tools/toolOrchestration.js' import { findToolByName, type Tool, type Tools } from '../Tool.js' -import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js' -import { FILE_EDIT_TOOL_NAME } from '../tools/FileEditTool/constants.js' -import type { Input as FileReadInput } from '../tools/FileReadTool/FileReadTool.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import type { Input as FileReadInput } from '@claude-code-best/builtin-tools/tools/FileReadTool/FileReadTool.js' import { FILE_READ_TOOL_NAME, FILE_UNCHANGED_STUB, -} from '../tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from '../tools/FileWriteTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' import type { Message } from '../types/message.js' import type { OrphanedPermission } from '../types/textInputTypes.js' import { logForDebugging } from './debug.js' diff --git a/src/utils/sandbox/sandbox-adapter.ts b/src/utils/sandbox/sandbox-adapter.ts index 170ecac78..4f20ca7e0 100644 --- a/src/utils/sandbox/sandbox-adapter.ts +++ b/src/utils/sandbox/sandbox-adapter.ts @@ -49,10 +49,10 @@ import type { SettingsJson } from '../settings/types.js' // Settings Converter // ============================================================================ -import { BASH_TOOL_NAME } from 'src/tools/BashTool/toolName.js' -import { FILE_EDIT_TOOL_NAME } from 'src/tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from 'src/tools/FileReadTool/prompt.js' -import { WEB_FETCH_TOOL_NAME } from 'src/tools/WebFetchTool/prompt.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { WEB_FETCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebFetchTool/prompt.js' import { errorMessage } from '../errors.js' import { getClaudeTempDir } from '../permissions/filesystem.js' import type { PermissionRuleValue } from '../permissions/PermissionRule.js' diff --git a/src/utils/sessionFileAccessHooks.ts b/src/utils/sessionFileAccessHooks.ts index d4b401d34..4ddcae3b4 100644 --- a/src/utils/sessionFileAccessHooks.ts +++ b/src/utils/sessionFileAccessHooks.ts @@ -10,16 +10,16 @@ import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent, } from '../services/analytics/index.js' -import { FILE_EDIT_TOOL_NAME } from '../tools/FileEditTool/constants.js' -import { inputSchema as editInputSchema } from '../tools/FileEditTool/types.js' -import { FileReadTool } from '../tools/FileReadTool/FileReadTool.js' -import { FILE_READ_TOOL_NAME } from '../tools/FileReadTool/prompt.js' -import { FileWriteTool } from '../tools/FileWriteTool/FileWriteTool.js' -import { FILE_WRITE_TOOL_NAME } from '../tools/FileWriteTool/prompt.js' -import { GlobTool } from '../tools/GlobTool/GlobTool.js' -import { GLOB_TOOL_NAME } from '../tools/GlobTool/prompt.js' -import { GrepTool } from '../tools/GrepTool/GrepTool.js' -import { GREP_TOOL_NAME } from '../tools/GrepTool/prompt.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { inputSchema as editInputSchema } from '@claude-code-best/builtin-tools/tools/FileEditTool/types.js' +import { FileReadTool } from '@claude-code-best/builtin-tools/tools/FileReadTool/FileReadTool.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FileWriteTool } from '@claude-code-best/builtin-tools/tools/FileWriteTool/FileWriteTool.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { GlobTool } from '@claude-code-best/builtin-tools/tools/GlobTool/GlobTool.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GrepTool } from '@claude-code-best/builtin-tools/tools/GrepTool/GrepTool.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' import type { HookCallback } from '../types/hooks.js' import { detectSessionFileType, diff --git a/src/utils/sessionRestore.ts b/src/utils/sessionRestore.ts index 9f77841c7..93cded34b 100644 --- a/src/utils/sessionRestore.ts +++ b/src/utils/sessionRestore.ts @@ -12,14 +12,14 @@ import { import { clearSystemPromptSections } from '../constants/systemPromptSections.js' import { restoreCostStateForSession } from '../cost-tracker.js' import type { AppState } from '../state/AppState.js' -import type { AgentColorName } from '../tools/AgentTool/agentColorManager.js' +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { type AgentDefinition, type AgentDefinitionsResult, getActiveAgentsFromList, getAgentDefinitionsWithOverrides, -} from '../tools/AgentTool/loadAgentsDir.js' -import { TODO_WRITE_TOOL_NAME } from '../tools/TodoWriteTool/constants.js' +} from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { TODO_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TodoWriteTool/constants.js' import { asSessionId } from '../types/ids.js' import type { AttributionSnapshotMessage, diff --git a/src/utils/sessionStorage.ts b/src/utils/sessionStorage.ts index 579e1b7b7..994cdd42d 100644 --- a/src/utils/sessionStorage.ts +++ b/src/utils/sessionStorage.ts @@ -34,7 +34,7 @@ import { builtInCommandNames } from '../commands.js' import { COMMAND_NAME_TAG, TICK_TAG } from '../constants/xml.js' import { getFeatureValue_CACHED_MAY_BE_STALE } from '../services/analytics/growthbook.js' import * as sessionIngress from '../services/api/sessionIngress.js' -import { REPL_TOOL_NAME } from '../tools/REPLTool/constants.js' +import { REPL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/REPLTool/constants.js' import { type AgentId, asAgentId, diff --git a/src/utils/shell/shellToolUtils.ts b/src/utils/shell/shellToolUtils.ts index 0de75034b..b11cb4055 100644 --- a/src/utils/shell/shellToolUtils.ts +++ b/src/utils/shell/shellToolUtils.ts @@ -1,5 +1,5 @@ -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' -import { POWERSHELL_TOOL_NAME } from '../../tools/PowerShellTool/toolName.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { POWERSHELL_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/PowerShellTool/toolName.js' import { isEnvDefinedFalsy, isEnvTruthy } from '../envUtils.js' import { getPlatform } from '../platform.js' diff --git a/src/utils/statusNoticeDefinitions.tsx b/src/utils/statusNoticeDefinitions.tsx index 9ad173fd0..af480c882 100644 --- a/src/utils/statusNoticeDefinitions.tsx +++ b/src/utils/statusNoticeDefinitions.tsx @@ -17,7 +17,7 @@ import { getAuthTokenSource, isClaudeAISubscriber, } from './auth.js' -import type { AgentDefinitionsResult } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinitionsResult } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { getAgentDescriptionsTotalTokens, AGENT_DESCRIPTIONS_THRESHOLD, diff --git a/src/utils/statusNoticeHelpers.ts b/src/utils/statusNoticeHelpers.ts index e445ccfc3..c5c668e00 100644 --- a/src/utils/statusNoticeHelpers.ts +++ b/src/utils/statusNoticeHelpers.ts @@ -1,5 +1,5 @@ import { roughTokenCountEstimation } from '../services/tokenEstimation.js' -import type { AgentDefinitionsResult } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinitionsResult } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' export const AGENT_DESCRIPTIONS_THRESHOLD = 15_000 diff --git a/src/utils/streamlinedTransform.ts b/src/utils/streamlinedTransform.ts index abe3ccdf6..06dcd9b5b 100644 --- a/src/utils/streamlinedTransform.ts +++ b/src/utils/streamlinedTransform.ts @@ -10,16 +10,16 @@ import type { SDKAssistantMessage } from 'src/entrypoints/agentSdkTypes.js' import type { StdoutMessage } from 'src/entrypoints/sdk/controlTypes.js' -import { FILE_EDIT_TOOL_NAME } from 'src/tools/FileEditTool/constants.js' -import { FILE_READ_TOOL_NAME } from 'src/tools/FileReadTool/prompt.js' -import { FILE_WRITE_TOOL_NAME } from 'src/tools/FileWriteTool/prompt.js' -import { GLOB_TOOL_NAME } from 'src/tools/GlobTool/prompt.js' -import { GREP_TOOL_NAME } from 'src/tools/GrepTool/prompt.js' -import { LIST_MCP_RESOURCES_TOOL_NAME } from 'src/tools/ListMcpResourcesTool/prompt.js' -import { LSP_TOOL_NAME } from 'src/tools/LSPTool/prompt.js' -import { NOTEBOOK_EDIT_TOOL_NAME } from 'src/tools/NotebookEditTool/constants.js' -import { TASK_STOP_TOOL_NAME } from 'src/tools/TaskStopTool/prompt.js' -import { WEB_SEARCH_TOOL_NAME } from 'src/tools/WebSearchTool/prompt.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_READ_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileReadTool/prompt.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' +import { GLOB_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GlobTool/prompt.js' +import { GREP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/GrepTool/prompt.js' +import { LIST_MCP_RESOURCES_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ListMcpResourcesTool/prompt.js' +import { LSP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/LSPTool/prompt.js' +import { NOTEBOOK_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/NotebookEditTool/constants.js' +import { TASK_STOP_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskStopTool/prompt.js' +import { WEB_SEARCH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/WebSearchTool/prompt.js' import { extractTextContent } from 'src/utils/messages.js' import { SHELL_TOOL_NAMES } from 'src/utils/shell/shellToolUtils.js' import { capitalize } from 'src/utils/stringUtils.js' diff --git a/src/utils/swarm/backends/ITermBackend.ts b/src/utils/swarm/backends/ITermBackend.ts index 47a6d925f..dc1f0b210 100644 --- a/src/utils/swarm/backends/ITermBackend.ts +++ b/src/utils/swarm/backends/ITermBackend.ts @@ -1,4 +1,4 @@ -import type { AgentColorName } from '../../../tools/AgentTool/agentColorManager.js' +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { logForDebugging } from '../../../utils/debug.js' import { execFileNoThrow } from '../../../utils/execFileNoThrow.js' import { IT2_COMMAND, isInITerm2, isIt2CliAvailable } from './detection.js' diff --git a/src/utils/swarm/backends/TmuxBackend.ts b/src/utils/swarm/backends/TmuxBackend.ts index 402afd8dc..321958c7b 100644 --- a/src/utils/swarm/backends/TmuxBackend.ts +++ b/src/utils/swarm/backends/TmuxBackend.ts @@ -1,4 +1,4 @@ -import type { AgentColorName } from '../../../tools/AgentTool/agentColorManager.js' +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { logForDebugging } from '../../../utils/debug.js' import { execFileNoThrow } from '../../../utils/execFileNoThrow.js' import { logError } from '../../../utils/log.js' diff --git a/src/utils/swarm/backends/types.ts b/src/utils/swarm/backends/types.ts index b57964c15..185253ad5 100644 --- a/src/utils/swarm/backends/types.ts +++ b/src/utils/swarm/backends/types.ts @@ -1,4 +1,4 @@ -import type { AgentColorName } from '../../../tools/AgentTool/agentColorManager.js' +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' /** * Types of backends available for teammate execution. diff --git a/src/utils/swarm/inProcessRunner.ts b/src/utils/swarm/inProcessRunner.ts index 245acf19f..3faf2598b 100644 --- a/src/utils/swarm/inProcessRunner.ts +++ b/src/utils/swarm/inProcessRunner.ts @@ -44,17 +44,17 @@ import { getProgressUpdate, updateProgressFromMessage, } from '../../tasks/LocalAgentTask/LocalAgentTask.js' -import type { CustomAgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js' -import { runAgent } from '../../tools/AgentTool/runAgent.js' -import { awaitClassifierAutoApproval } from '../../tools/BashTool/bashPermissions.js' -import { BASH_TOOL_NAME } from '../../tools/BashTool/toolName.js' -import { SEND_MESSAGE_TOOL_NAME } from '../../tools/SendMessageTool/constants.js' -import { TASK_CREATE_TOOL_NAME } from '../../tools/TaskCreateTool/constants.js' -import { TASK_GET_TOOL_NAME } from '../../tools/TaskGetTool/constants.js' -import { TASK_LIST_TOOL_NAME } from '../../tools/TaskListTool/constants.js' -import { TASK_UPDATE_TOOL_NAME } from '../../tools/TaskUpdateTool/constants.js' -import { TEAM_CREATE_TOOL_NAME } from '../../tools/TeamCreateTool/constants.js' -import { TEAM_DELETE_TOOL_NAME } from '../../tools/TeamDeleteTool/constants.js' +import type { CustomAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { runAgent } from '@claude-code-best/builtin-tools/tools/AgentTool/runAgent.js' +import { awaitClassifierAutoApproval } from '@claude-code-best/builtin-tools/tools/BashTool/bashPermissions.js' +import { BASH_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BashTool/toolName.js' +import { SEND_MESSAGE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SendMessageTool/constants.js' +import { TASK_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskCreateTool/constants.js' +import { TASK_GET_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskGetTool/constants.js' +import { TASK_LIST_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskListTool/constants.js' +import { TASK_UPDATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TaskUpdateTool/constants.js' +import { TEAM_CREATE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamCreateTool/constants.js' +import { TEAM_DELETE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/TeamDeleteTool/constants.js' import type { Message } from '../../types/message.js' import type { PermissionDecision } from '../../types/permissions.js' import { diff --git a/src/utils/swarm/teammateLayoutManager.ts b/src/utils/swarm/teammateLayoutManager.ts index 2b26a3e17..d1785fb29 100644 --- a/src/utils/swarm/teammateLayoutManager.ts +++ b/src/utils/swarm/teammateLayoutManager.ts @@ -1,5 +1,5 @@ -import type { AgentColorName } from '../../tools/AgentTool/agentColorManager.js' -import { AGENT_COLORS } from '../../tools/AgentTool/agentColorManager.js' +import type { AgentColorName } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' +import { AGENT_COLORS } from '@claude-code-best/builtin-tools/tools/AgentTool/agentColorManager.js' import { detectAndGetBackend } from './backends/registry.js' import type { PaneBackend } from './backends/types.js' diff --git a/src/utils/systemPrompt.ts b/src/utils/systemPrompt.ts index 2059c81bd..7667686e1 100644 --- a/src/utils/systemPrompt.ts +++ b/src/utils/systemPrompt.ts @@ -4,8 +4,8 @@ import { logEvent, } from '../services/analytics/index.js' import type { ToolUseContext } from '../Tool.js' -import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js' -import { isBuiltInAgent } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' +import { isBuiltInAgent } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { isEnvTruthy } from './envUtils.js' import { asSystemPrompt, type SystemPrompt } from './systemPromptType.js' diff --git a/src/utils/teamMemoryOps.ts b/src/utils/teamMemoryOps.ts index 30810f01b..e6f6ec255 100644 --- a/src/utils/teamMemoryOps.ts +++ b/src/utils/teamMemoryOps.ts @@ -1,6 +1,6 @@ import { isTeamMemFile } from '../memdir/teamMemPaths.js' -import { FILE_EDIT_TOOL_NAME } from '../tools/FileEditTool/constants.js' -import { FILE_WRITE_TOOL_NAME } from '../tools/FileWriteTool/prompt.js' +import { FILE_EDIT_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileEditTool/constants.js' +import { FILE_WRITE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/FileWriteTool/prompt.js' export { isTeamMemFile } diff --git a/src/utils/teammateMailbox.ts b/src/utils/teammateMailbox.ts index d2841766a..eb72fcc21 100644 --- a/src/utils/teammateMailbox.ts +++ b/src/utils/teammateMailbox.ts @@ -12,7 +12,7 @@ import { join } from 'path' import { z } from 'zod/v4' import { TEAMMATE_MESSAGE_TAG } from '../constants/xml.js' import { PermissionModeSchema } from '../entrypoints/sdk/coreSchemas.js' -import { SEND_MESSAGE_TOOL_NAME } from '../tools/SendMessageTool/constants.js' +import { SEND_MESSAGE_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/SendMessageTool/constants.js' import type { Message } from '../types/message.js' import { generateRequestId } from './agentId.js' import { count } from './array.js' diff --git a/src/utils/telemetry/skillLoadedEvent.ts b/src/utils/telemetry/skillLoadedEvent.ts index a84a58bb6..6d0307605 100644 --- a/src/utils/telemetry/skillLoadedEvent.ts +++ b/src/utils/telemetry/skillLoadedEvent.ts @@ -4,7 +4,7 @@ import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_PII_TAGGED, logEvent, } from '../../services/analytics/index.js' -import { getCharBudget } from '../../tools/SkillTool/prompt.js' +import { getCharBudget } from '@claude-code-best/builtin-tools/tools/SkillTool/prompt.js' /** * Logs a tengu_skill_loaded event for each skill available at session startup. diff --git a/src/utils/toolSearch.ts b/src/utils/toolSearch.ts index a860c2b36..29f3148a1 100644 --- a/src/utils/toolSearch.ts +++ b/src/utils/toolSearch.ts @@ -18,12 +18,12 @@ import { type Tools, toolMatchesName, } from '../Tool.js' -import type { AgentDefinition } from '../tools/AgentTool/loadAgentsDir.js' +import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' import { formatDeferredToolLine, isDeferredTool, TOOL_SEARCH_TOOL_NAME, -} from '../tools/ToolSearchTool/prompt.js' +} from '@claude-code-best/builtin-tools/tools/ToolSearchTool/prompt.js' import type { Message } from '../types/message.js' import { countToolDefinitionTokens, diff --git a/src/utils/ultraplan/ccrSession.ts b/src/utils/ultraplan/ccrSession.ts index 2aca9aa66..7c45465ca 100644 --- a/src/utils/ultraplan/ccrSession.ts +++ b/src/utils/ultraplan/ccrSession.ts @@ -9,7 +9,7 @@ import type { ToolUseBlock, } from '@anthropic-ai/sdk/resources' import type { SDKMessage } from '../../entrypoints/agentSdkTypes.js' -import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '../../tools/ExitPlanModeTool/constants.js' +import { EXIT_PLAN_MODE_V2_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/ExitPlanModeTool/constants.js' import { logForDebugging } from '../debug.js' import { sleep } from '../sleep.js' import { isTransientNetworkError } from '../teleport/api.js' diff --git a/tsconfig.json b/tsconfig.json index 79e1c17fa..65f7e4c81 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,9 +12,11 @@ "resolveJsonModule": true, "types": ["bun"], "paths": { - "src/*": ["./src/*"] + "src/*": ["./src/*"], + "@claude-code-best/builtin-tools/*": ["./packages/builtin-tools/src/*"], + "@claude-code-best/builtin-tools": ["./packages/builtin-tools/src/index.ts"] } }, - "include": ["src/**/*.ts", "src/**/*.tsx"], + "include": ["src/**/*.ts", "src/**/*.tsx", "packages/builtin-tools/src/**/*.ts", "packages/builtin-tools/src/**/*.tsx"], "exclude": ["node_modules"] }