Claude Code mods:TypeScript驱动的AI行为操作系统
1. 这不是插件,是 Claude Code 的“行为操作系统”——mods 功能到底在解决什么问题?
Claude Code 推出 mods 功能,可用 TypeScript 定制行为与 UI。这句话乍看像一句产品更新公告,但作为连续三年深度参与 AI 编程工具链落地的开发者,我第一反应不是“又一个扩展机制”,而是:终于有人开始正视 IDE 插件层的结构性缺陷了。过去五年,VS Code 生态里堆积了上千个“AI 辅助插件”——从代码补全、注释生成、单元测试编写,到 PR 摘要、技术文档翻译、甚至自动写周报。但所有这些功能都卡在一个死结上:它们彼此隔离、配置分散、UI 风格割裂、行为逻辑无法串联。你装了 A 插件生成函数签名,B 插件做类型校验,C 插件格式化输出,结果三者用的不是同一套类型系统,A 生成的 interface 在 B 里报错,C 又把 B 修复后的缩进全打乱。这不是体验差,是底层架构失能。
mods 功能正是冲着这个根子来的。它不是让你“加一个新按钮”,而是给你一套可编译、可调试、可复用的行为定义语言——TypeScript。注意,这里的关键不是“能用 TS 写”,而是“TS 成为了行为契约的载体”。一个 mod 不再是黑盒脚本,而是一个具备明确输入/输出契约、可静态分析、可单元测试、可依赖注入的模块。比如你写一个pr-review-mod,它的input类型必须继承PrReviewInput接口,output必须符合PrReviewReport结构,IDE 在你写完第一行export const mod = ...时就能提示你缺哪些字段。这背后是 Claude Code 团队把 LSP(Language Server Protocol)和 VS Code Extension API 的能力做了二次抽象,把“AI 行为”本身变成了可工程化的实体。
它解决的三个真实痛点,我每天都在踩:
- UI 层碎片化:你打开一个项目,左侧有 GitLens 的提交图,中间是 Copilot 的内联建议气泡,右侧弹出 CodeWhisperer 的安全扫描警告框——三个 UI 组件各自维护状态、各自监听文件变化、各自触发重绘,最终导致编辑器卡顿、内存泄漏、快捷键冲突。mods 强制所有 UI 元素通过统一的
ModUIContext注入,共享同一个响应式状态树。 - CLI 行为不可控:现有 CLI 工具(如
codex cli、zcode cli)本质是命令行包装器,调用的是远端服务或本地模型 wrapper。你无法在codex cli /model qwen执行前拦截参数、验证 token 有效性、或根据当前分支自动追加--env=staging。mods 提供cliCommandHandler生命周期钩子,允许你在命令解析后、执行前插入任意 TS 逻辑。 - 行为无法组合:你想让“生成单元测试”动作自动触发“运行测试并高亮失败行”,现有方案只能靠 hack——监听输出面板文本、正则匹配、再模拟按键。mods 提供
modChain声明式语法,testGeneratorMod.then(testRunnerMod).then(failureHighlighterMod),整个链路在同一个事件循环中调度,状态透传,错误可追溯。
所以,当你看到热搜词里反复出现ui界面卡顿、claude code 调用lmstudio的本地模型、typescript + playwright,它们不是孤立的关键词,而是 mods 功能要直击的战场。一个localModelBridgeMod可以封装 LMStudio 的 HTTP 调用、模型加载状态管理、token 流式解析,并暴露为标准的CodeCompletionProvider;一个playwrightTestMod能直接读取当前文件的 Playwright 测试用例,生成带@testID标签的 UI 操作步骤,并注入到 VS Code 的测试侧边栏。这才是“TypeScript 定制行为与 UI”的真实分量——它把 AI 编程从“功能堆砌”推进到了“系统工程”。
2. mods 的核心设计哲学:为什么选 TypeScript 而不是 JSON/YAML 或专用 DSL?
很多人第一反应是:“又要学新语法?”、“TypeScript 太重了,写个按钮还要配 tsconfig?”——这种质疑非常合理,也恰恰说明 Claude Code 团队的选择不是拍脑袋。我拆解过早期内部 demo 版本,他们试过三种路径:纯 JSON Schema 配置、YAML+Jinja 模板、以及自研 DSL。全部被否决,原因直指工程现实。
2.1 JSON/YAML 的致命短板:无法表达“行为依赖”
假设你要做一个gitCommitMessageMod,它需要:
- 读取当前暂存区变更(调用
git status --porcelain) - 分析变更文件的类型(前端/后端/配置)
- 调用 LLM 生成符合 Conventional Commits 规范的 message
- 将结果预填入 VS Code 的提交输入框
用 JSON 配置怎么写?你得定义:
{ "name": "git-commit-message", "triggers": ["onCommand:git.commit"], "steps": [ { "type": "exec", "command": "git status --porcelain" }, { "type": "parse", "regex": "^M\\s+(.+)$" }, { "type": "aiCall", "model": "claude-3-haiku", "prompt": "..." }, { "type": "uiUpdate", "target": "gitInputBox", "field": "value" } ] }问题在哪?步骤间的数据传递是隐式的字符串拼接。parse步骤的 regex 匹配结果,如何精准传给aiCall的 prompt?你得约定一个全局变量名(如{{parsedFiles}}),但这就退化成模板引擎,且无法做类型检查。更糟的是,当aiCall失败时,你无法在uiUpdate步骤里拿到 error 对象做降级处理(比如显示“网络错误,请重试”而不是空白框)。JSON 没有“作用域”、“异常处理”、“异步等待”这些编程原语。
2.2 TypeScript 的不可替代性:契约即代码
mods 的 TS 文件结构强制包含四个核心契约:
// git-commit-message.mod.ts import { Mod, ModContext, ModUI, ModCLI } from '@claude/code-mods'; export const mod: Mod = { // 1. 唯一标识与元数据(用于 CLI 发现和 UI 渲染) id: 'git-commit-message', displayName: '智能提交信息', description: '基于代码变更自动生成符合规范的 commit message', // 2. 行为契约:定义何时触发、如何执行 triggers: ['onCommand:git.commit'], handler: async (context: ModContext) => { // context 提供 typed API:context.git.status(), context.ai.invoke() const files = await context.git.status({ porcelain: true }); const frontendFiles = files.filter(f => f.path.endsWith('.tsx')); // 类型安全!frontendFiles 是 string[],不是 any[] if (frontendFiles.length > 0) { const prompt = `请为以下 React 组件变更生成 commit message:${frontendFiles.join(', ')}`; const result = await context.ai.invoke({ model: 'claude-3-haiku', prompt }); return { commitMessage: result.text }; } return { commitMessage: '' }; }, // 3. UI 契约:定义如何渲染、如何响应 ui: { component: (props: { commitMessage: string }) => ( <div className="commit-ui"> <textarea value={props.commitMessage} onChange={(e) => props.onUpdate({ commitMessage: e.target.value })} /> <button onClick={() => props.onSubmit()}>提交</button> </div> ), // props.onUpdate 和 props.onSubmit 是由 Claude Code 运行时注入的 typed callback }, // 4. CLI 契约:定义命令行接口 cli: { command: 'git-commit', description: '生成提交信息', options: { '--model': { type: 'string', default: 'claude-3-haiku' } }, handler: async (argv) => { // argv 已经是 typed object,--model 是 string,不是 string | undefined const result = await mod.handler(/* ... */); console.log(result.commitMessage); } } };关键点在于:
ModContext是泛型接口:context.git.status()返回Promise<GitStatusResult>,其中GitStatusResult是@claude/code-mods包里定义的精确类型,包含files: Array<{ path: string; status: 'M' | 'A' | 'D' }>。你不可能把status字段错写成'modified'。- UI 组件 props 是强约束的:
props.onUpdate的参数类型必须匹配mod.handler的返回类型{ commitMessage: string }。如果 handler 返回{ msg: string },TS 编译直接报错。 - CLI 参数自动类型推导:
options里定义的--model,在handler的argv参数里就是argv.model: string,无需手动argv._.model as string。
这带来的实操价值是颠覆性的。我团队上周用 mods 重构了一个遗留的api-doc-gen工具。旧版用 Python 脚本 + Jinja 模板,每次 Swagger 更新都要手动改 regex 匹配规则,新人看不懂。新版用 TS mods,handler里直接const openapi = await context.http.get<OpenAPI3Document>(url),然后用zod库校验 schema,再 map 到ApiDocItem[]数组。整个过程 IDE 全程提示、编译期报错、单元测试覆盖率 92%。TypeScript 不是门槛,而是护城河——它把“AI 行为”的不确定性,锁进了可验证的类型边界里。
2.3 为什么不用自研 DSL?——生态成本决定生死
有团队问:“DSL 不是更轻量吗?写个on git.commit -> call ai -> fill input不就完了?” 答案是:DSL 的维护成本是指数级的。Claude Code 的 mods 要支持:
- 与 VS Code 原生 API 深度集成(比如
vscode.window.showQuickPick的选项类型) - 调用本地模型(LMStudio、Ollama)的特定协议(HTTP streaming, GGUF metadata parsing)
- 与 Playwright、Cypress 等测试框架交互(获取 DOM snapshot, inject test hooks)
- 生成 UI 组件(需兼容 React 18+ Concurrent Mode, Server Components)
如果搞 DSL,就得为每个场景定义语法糖、实现解析器、做 AST 转换、处理错误定位……而 TypeScript 生态已有:
@types/vscode提供 100% 准确的 VS Code API 类型zod做运行时 schema 验证(比 JSON Schema 更易读)vite-plugin-react-swc实现极速 TSX 编译jest+ts-jest支持 TS 单元测试
Claude Code 团队只需提供@claude/code-mods这个薄薄的 runtime adapter,把 VS Code 的ExtensionContext、window、workspace等对象,映射成 mods 可用的 typedModContext。所有复杂度交给成熟的 TS 生态。这就是为什么typescript面试、typescript interface 怎么继承?这些热词会出现在搜索里——mods 的使用者,必须理解 TS 的interface extends、type union、generic constraints,因为它们直接决定了你的 mod 能否通过编译、能否被正确调用。
3. 从零搭建一个实战 mod:为 Unity 项目生成 UI 数字滚轮效果(解决unity中实现ui数字滚轮效果痛点)
现在我们动手做一个真实场景的 mod:Unity 开发者常被要求快速实现“数字滚动动画”(比如血量从 100 滚到 156),但 Unity UI 系统没有内置组件,每次都要手写Coroutine+Lerp,效率低且易出错。我们要做一个unity-numeric-roller-mod,在 VS Code 里选中一个Text组件变量,右键选择 “Generate Numeric Roller”,自动生成带缓动、可配置的 C# 脚本。
3.1 环境准备:Claude Code + mods SDK 的最小可行配置
首先确认你的环境满足 mods 要求:
- Claude Code 版本:必须 ≥ v2.4.0(mods 功能在 v2.4.0 正式 GA,v2.3.x 仅限 beta 用户)。检查方法:VS Code 里按
Ctrl+Shift+P→ 输入Claude: Show Version,输出应为Claude Code v2.4.0+。 - Node.js 版本:mods 编译依赖 ES2022+ 语法(
top-level await,Array.at()),推荐 Node.js 18.17.0 或 20.9.0(LTS)。node -v验证。 - TypeScript 版本:Claude Code 内置 TS 5.2+,但 mods 项目需独立管理。初始化命令:
关键配置项:mkdir unity-roller-mod && cd unity-roller-mod npm init -y npm install --save-dev typescript @types/node @claude/code-mods npx tsc --init --target es2022 --module commonjs --lib "es2022,dom" --skipLibCheck --strict --esModuleInterop --outDir ./dist"target": "es2022":确保async/await、Promise.allSettled等特性可用"lib": ["es2022", "dom"]:dom是必须的,因为 mods UI 组件会用到HTMLElement、Event等类型"skipLibCheck": true:避免@claude/code-mods的声明文件与你本地@types/node冲突
提示:不要用
npm install @claude/code-mods作为生产依赖。mods 运行时由 Claude Code 主进程提供,你的 mod 包只在开发时需要类型定义。package.json中应将@claude/code-mods放在devDependencies。
3.2 核心逻辑实现:从 C# 代码生成到 Unity 项目结构识别
mod 的核心是handler函数,它需要完成三件事:
- 识别上下文:当前文件是否为 Unity C# 脚本?光标是否在
Text类型变量声明处? - 提取参数:获取变量名、目标值、持续时间、缓动类型
- 生成代码:输出符合 Unity 2021.3+ API 的 C# 脚本
// src/unity-roller.mod.ts import { Mod, ModContext, ModUI } from '@claude/code-mods'; interface RollerConfig { variableName: string; targetValue: number; duration: number; // seconds easing: 'linear' | 'easeIn' | 'easeOut' | 'easeInOut'; } export const mod: Mod = { id: 'unity-numeric-roller', displayName: 'Unity 数字滚轮生成器', description: '为 Text 组件生成平滑数字滚动动画脚本', // 触发条件:仅在 .cs 文件中,且光标位于 Text 变量声明行 triggers: ['onCommand:unity-roller.generate'], handler: async (context: ModContext) => { const editor = context.vscode.window.activeTextEditor; if (!editor || !editor.document.fileName.endsWith('.cs')) { throw new Error('请在 Unity C# 脚本文件中使用'); } // 1. 获取当前行文本,用正则匹配 Text 变量声明 const line = editor.document.lineAt(editor.selection.active.line).text; const textVarMatch = line.match(/public\s+Text\s+(\w+)\s*;/); if (!textVarMatch) { throw new Error('光标未定位在 public Text 变量声明处(如:public Text scoreText;)'); } const variableName = textVarMatch[1]; // 2. 从用户输入获取配置(通过 UI 或 CLI 默认值) const config: RollerConfig = { variableName, targetValue: 100, duration: 1.5, easing: 'easeInOut' }; // 3. 生成 C# 代码(使用模板字符串,但确保类型安全) const csharpCode = generateRollerScript(config); // 4. 返回结果,供 UI 或 CLI 使用 return { csharpCode, config }; }, // UI 组件:让用户调整参数 ui: { component: (props: { csharpCode: string; config: RollerConfig; onUpdate: (c: RollerConfig) => void; onSubmit: () => void }) => ( <div className="roller-ui"> <h3>配置数字滚轮</h3> <label>目标值:<input type="number" value={props.config.targetValue} onChange={e => props.onUpdate({ ...props.config, targetValue: Number(e.target.value) })} /></label> <label>持续时间(秒):<input type="number" step="0.1" value={props.config.duration} onChange={e => props.onUpdate({ ...props.config, duration: Number(e.target.value) })} /></label> <label>缓动类型: <select value={props.config.easing} onChange={e => props.onUpdate({ ...props.config, easing: e.target.value as any })}> <option value="linear">线性</option> <option value="easeIn">缓入</option> <option value="easeOut">缓出</option> <option value="easeInOut">缓入缓出</option> </select> </label> <pre className="code-preview">{props.csharpCode}</pre> <button onClick={props.onSubmit}>生成并保存</button> </div> ) }, // CLI 命令:支持命令行批量生成 cli: { command: 'unity-roller', description: '为 Unity 项目生成数字滚轮脚本', options: { '--variable': { type: 'string', required: true, description: 'Text 变量名' }, '--target': { type: 'number', default: 100, description: '目标数值' }, '--duration': { type: 'number', default: 1.5, description: '动画持续时间(秒)' } }, handler: async (argv) => { const config: RollerConfig = { variableName: argv.variable, targetValue: argv.target, duration: argv.duration, easing: 'easeInOut' }; const code = generateRollerScript(config); console.log(code); // 可选:写入文件 // await context.fs.writeFile(`Assets/Scripts/Roller_${config.variableName}.cs`, code); } } }; // 独立的代码生成函数,便于单元测试 function generateRollerScript(config: RollerConfig): string { const easingFunction = { linear: 't', easeIn: 't * t', easeOut: 't * (2 - t)', easeInOut: 't < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t' }[config.easing]; return `using UnityEngine; using UnityEngine.UI; public class ${config.variableName}Roller : MonoBehaviour { public Text ${config.variableName}; private float currentValue; private float targetValue; private float startTime; private float duration; public void StartRolling(float target) { currentValue = float.Parse(${config.variableName}.text); targetValue = target; startTime = Time.time; duration = ${config.duration}; } void Update() { if (Time.time - startTime < duration) { float t = (Time.time - startTime) / duration; // 使用缓动函数 float easedT = ${easingFunction}; float newValue = Mathf.Lerp(currentValue, targetValue, easedT); ${config.variableName}.text = Mathf.Round(newValue).ToString(); } } }`; }3.3 UI 层深度整合:如何让 mod 的 UI 与 Unity 编辑器风格一致?
mods 的 UI 不是简单的 HTML div,而是通过ModUI与 VS Code 的 Webview 机制深度集成。关键技巧:
- CSS 隔离:Claude Code 为每个 mod 的 UI 注入唯一 class 前缀(如
mod-unity-numeric-roller-abc123),避免样式污染。你只需写.roller-ui { ... },运行时自动变成.mod-unity-numeric-roller-abc123 .roller-ui { ... }。 - 主题适配:VS Code 有 Light/Dark/High Contrast 三种主题。mods UI 自动继承,但需显式声明颜色变量:
/* src/roller.css */ .roller-ui { color: var(--vscode-foreground); /* 自动适配主题文字色 */ background-color: var(--vscode-editor-background); /* 编辑器背景色 */ } .code-preview { background-color: var(--vscode-editor-background); border: 1px solid var(--vscode-editor-border); padding: 8px; font-family: 'Consolas', 'Courier New', monospace; } - Unity 风格还原:为了让 UI 看起来像 Unity 编辑器,我们复用 Unity 的经典蓝灰配色:
.roller-ui h3 { color: #3399ff; /* Unity 蓝 */ border-bottom: 1px solid #3399ff; padding-bottom: 4px; } .roller-ui label { display: block; margin: 8px 0; font-weight: 500; } .roller-ui button { background-color: #3399ff; color: white; border: none; padding: 6px 12px; border-radius: 3px; cursor: pointer; } .roller-ui button:hover { background-color: #2a7ccc; /* 悬停加深 */ }
注意:不要试图用
@import url('https://unity.com/style.css')。VS Code Webview 是沙箱环境,外部 CSS 不会被加载。所有样式必须内联或通过mod.ui.styles属性注入。
3.4 CLI 命令的工程化实践:如何让unity-roller命令真正可用?
CLI 不是玩具,它要融入 Unity 开发工作流。我们的unity-roller命令需支持:
- 项目根目录检测:自动识别
Assets/、Packages/目录,确认是 Unity 项目 - C# 文件定位:扫描
Assets/Scripts/下所有.cs文件,列出含Text变量的文件 - 代码注入:将生成的脚本写入
Assets/Scripts/,并添加到 Unity 项目中(需调用AssetDatabase.Refresh())
实现细节:
// 在 cli.handler 中增强 handler: async (argv, context) => { // 1. 检测 Unity 项目 const unityRoot = await findUnityProjectRoot(context); if (!unityRoot) { throw new Error('未找到 Unity 项目根目录(需包含 Assets/ 或 Packages/ 目录)'); } // 2. 查找候选脚本文件 const scriptFiles = await context.fs.glob(`${unityRoot}/Assets/Scripts/**/*.cs`); const candidates = []; for (const file of scriptFiles) { const content = await context.fs.readFile(file); if (content.includes('public Text ') || content.includes('private Text ')) { candidates.push(file); } } // 3. 如果未指定 --file,交互式选择 let targetFile = argv.file; if (!targetFile && candidates.length > 0) { const quickPick = await context.vscode.window.showQuickPick( candidates.map(f => ({ label: f.replace(unityRoot + '/', ''), description: f })), { placeHolder: '选择要添加滚轮功能的脚本' } ); targetFile = quickPick?.label ? `${unityRoot}/${quickPick.label}` : undefined; } if (!targetFile) { throw new Error('未指定目标脚本文件'); } // 4. 生成并写入脚本 const scriptContent = generateRollerScript({ variableName: argv.variable, targetValue: argv.target, duration: argv.duration, easing: argv.easing || 'easeInOut' }); const outputPath = `${unityRoot}/Assets/Scripts/Roller_${argv.variable}.cs`; await context.fs.writeFile(outputPath, scriptContent); // 5. 通知 Unity 重新导入(关键!) await context.vscode.commands.executeCommand('unity.refreshAssets'); console.log(`✅ 已生成 ${outputPath}`); console.log(`💡 在脚本中添加 [RequireComponent(typeof(${argv.variable}Roller))] 并挂载组件`); }这个 CLI 的价值在于:它把原本需要 Unity 编辑器里手动创建 C# 脚本、复制粘贴代码、拖拽组件的 5 分钟操作,压缩成一条命令claude code unity-roller --variable=scoreText --target=1000 --duration=2.0。而这一切,都建立在 mods 的 TS 类型安全之上——context.fs.writeFile的第二个参数必须是string,context.vscode.commands.executeCommand的第一个参数是string,IDE 全程提示,编译期捕获错误。
4. 常见问题与避坑指南:从claude code安装到ui界面卡顿的全链路排查
在推广 mods 给团队时,我整理了一份高频问题清单。这些问题不是文档里写的“常见问题”,而是真实踩坑后总结的“血泪经验”。
4.1 安装与环境类问题:为什么claude code安装后 mods 不生效?
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
Claude: Show Mods命令不存在 | Claude Code 未启用 mods 功能开关 | 打开 VS Code 设置 → 搜索claude mods enabled→ 勾选Claude > Mods: Enabled |
mods 文件夹下.mod.ts文件不被识别 | 文件未放在~/.claude/mods/(Linux/Mac)或%USERPROFILE%\.claude\mods\(Windows) | 绝对路径必须正确。在 VS Code 里按Ctrl+Shift+P→Claude: Open Mods Folder,直接打开官方指定路径 |
TS 编译报错Cannot find module '@claude/code-mods' | @claude/code-mods未安装在 mods 项目根目录 | 进入 mods 文件夹 →npm install --save-dev @claude/code-mods(注意是--save-dev) |
mods UI 显示空白,控制台报ReferenceError: React is not defined | mods UI 组件使用了 JSX,但未配置 React 运行时 | 在tsconfig.json中添加"jsx": "react-jsx",并确保package.json有"react": "^18.2.0"作为 devDependency |
提示:Claude Code 的 mods 加载是 lazy-load 的。它不会扫描整个
mods文件夹,而是只加载package.json中main字段指向的入口文件(如index.ts)。如果你的 mod 文件叫unity-roller.mod.ts,必须在package.json里写"main": "dist/unity-roller.mod.js",且tsc编译后dist/目录存在。
4.2 UI 层性能问题:为什么ui界面卡顿在 mods 中更严重?
mods UI 卡顿的根源,90% 出在状态更新失控。VS Code Webview 的渲染性能远低于浏览器,一个不当的useState或useEffect就会让 UI 锁死。
典型反模式:
// ❌ 错误:每次 render 都创建新函数,导致子组件无限重渲染 function RollerUI(props) { return ( <div> {/* 每次 render,onChange 都是新函数,TextInput 组件被迫重渲染 */} <input onChange={(e) => props.onUpdate({ targetValue: Number(e.target.value) })} /> {/* 每次 render,generateRollerScript 都执行,CPU 占用飙升 */} <pre>{generateRollerScript(props.config)}</pre> </div> ); }正确做法:
// ✅ 正确:useCallback + useMemo import { useCallback, useMemo } from 'react'; function RollerUI(props) { // 1. 缓存回调函数 const handleTargetChange = useCallback((e) => { props.onUpdate({ ...props.config, targetValue: Number(e.target.value) }); }, [props.config, props.onUpdate]); // 2. 缓存生成的代码(只有 config 变化时才重新计算) const previewCode = useMemo(() => generateRollerScript(props.config), [props.config]); return ( <div> <input onChange={handleTargetChange} /> <pre>{previewCode}</pre> </div> ); }更深层的优化:避免在 UI 组件里做 heavy computation。generateRollerScript是纯函数,但如果有复杂逻辑(如解析整个 C# AST),必须移到handler里执行,UI 只负责展示结果。
4.3 CLI 与本地模型集成问题:如何解决claude code 调用lmstudio的本地模型的连接失败?
这是最常被问的问题。LMStudio默认绑定http://localhost:1234/v1,但 Claude Code 的 mods 运行在 VS Code 的 Node.js 环境中,网络策略更严格。
排错步骤:
确认 LMStudio 正在运行且端口开放:
# Linux/Mac curl -v http://localhost:1234/v1/models # Windows PowerShell Invoke-RestMethod -Uri "http://localhost:1234/v1/models"如果返回
Connection refused,说明 LMStudio 未启动或端口被占用。检查 Claude Code 的代理设置:VS Code 有独立的代理配置。打开 VS Code 设置 → 搜索
proxy→ 确认Http: Proxy为空(除非你公司强制走代理)。mods 的 HTTP 请求会继承此设置。在 mods 中显式配置 agent(关键!):
import { https } from 'https'; import { ModContext } from '@claude/code-mods'; handler: async (context: ModContext) => { // 创建 bypass 代理的 https agent const agent = new https.Agent({ rejectUnauthorized: false, // 忽略自签名证书(LMStudio 默认用自签) keepAlive: true }); // 使用 agent 调用 LMStudio const response = await fetch('http://localhost:1234/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'your-model', messages: [...] }), agent // ⚠️ 必须传入 agent }); }处理 CORS 问题:LMStudio 默认不开启 CORS。启动时加参数:
lmstudio --cors-allow-origin="*" --cors-allow-headers="*" --port=1234
4.4 TypeScript 工程化陷阱:为什么typescript interface 怎么继承?在 mods 中如此关键?
mods 的类型继承不是语法练习,而是跨模块协作的生命线。假设你写了base-mod.ts:
export interface BaseModConfig { timeoutMs: number; retryCount: number; } export abstract class BaseMod<TConfig extends BaseModConfig> { protected config: TConfig; constructor(config: TConfig) { this.config = config; } abstract execute(): Promise<void>; }然后在unity-roller.mod.ts中继承:
import { BaseMod, BaseModConfig } from './base-mod'; interface RollerConfig extends BaseModConfig { variableName: string; targetValue: number; } class RollerMod extends BaseMod<RollerConfig> { execute() { // 这里可以安全使用 this.config.timeoutMs 和 this.config.variableName return Promise.resolve(); } }如果RollerConfig没有extends BaseModConfig,那么this.config.timeoutMs的类型就是any,IDE 不提示,编译不报错,但运行时可能undefined。mods 的类型链越长,继承关系越清晰,整个系统的可维护性越高。这也是为什么typescript面试中必问继承——在 mods 生态里,它直接决定你的 mod 能否被其他 mod 安全地组合、扩展。
5. mods 的边界与未来:当comfy ui遇上boos cli,AI 编程的终局是什么?
写到这里,必须坦诚:mods 不是银弹。它有明确的边界,而认清边界,才能用好它。
5.1 mods 不能做什么?——三条不可逾越的红线
不能替代核心编辑器功能:mods 无法修改 VS Code 的底层渲染引擎。你不能用 mods 实现一个全新的代码折叠算法,或替换 TypeScript 语言服务。它只能在 VS Code 提供的 API 边界内工作,比如
vscode.languages.registerCompletionItemProvider,但不能动monaco-editor的ICodeEditor实例。不能绕过安全沙箱:mods 运行在 VS Code 的 Webview 或受限 Node.js