首页 / 资讯中心 / 文章详情

ponytail:CLI驱动的轻量级AI Agent开发框架

ponytail:CLI驱动的轻量级AI Agent开发框架 ★ FEATURED ARTICLE
1. “ponytail”不是发型是新一代CLI驱动型AI Agent开发框架的代号你可能在GitHub趋势榜、Hugging Face社区或某次技术分享会上偶然瞥见这个词——ponytail。它没有出现在任何主流编程语言文档里搜索引擎结果稀疏且零散连官方仓库都尚未公开。但就在最近三个月一批早期测试者在Discord私密频道、Obsidian插件讨论组和FastAPI开发者小群中反复提及“用ponytail搭了个本地Agent工作流比写三个FastAPI路由还快”“CLI初始化后直接跑通了Ollama调用文件记忆Canvas渲染三件套”。这不是某个新玩具的营销话术而是一套正在悄然成型的、面向轻量级AI Agent快速验证与本地化部署的工程实践范式。核心关键词早已浮出水面CLI、agent、JavaScript、FastAPI。这四个词组合在一起本身就构成了一条极具张力的技术路径——它拒绝把Agent塞进臃肿的Web UI壳子里也不依赖云端大模型API的持续扣费而是选择用命令行作为第一交互界面用JavaScript处理前端逻辑与数据流转用FastAPI构建可调试、可监控、可打包的后端服务层。ponytail正是这条路径上最新出现的“连接器”它不替代任何一项技术却让它们之间不再需要手写胶水代码。我第一次接触ponytail是在帮一位独立开发者排查一个“FastAPI日志丢失”的问题时。他没用uvicorn的标准启动方式而是执行了一行看似普通的命令ponytail dev --model llama3:8b --port 8001。几秒后终端里跳出的不是传统FastAPI的ASGI启动日志而是一段带颜色标记的结构化输出[✓] Runtime: Python 3.11.9 (venv) [✓] Model backend: Ollama (llama3:8b, loaded in 2.4s) [✓] Memory layer: SQLite file watcher active [→] Serving at http://localhost:8001/docs [] Try: curl -X POST http://localhost:8001/v1/chat -d {message:Hello}更关键的是他随后打开的不是一个Swagger UI页面而是一个极简的本地HTML文件——由ponytail自动生成内嵌了用JavaScript写的实时消息流组件能直接调用/v1/chat接口并渲染Markdown响应。整个过程没有Webpack、没有Vite、没有npm run dev只有ponytail dev一条命令。这背后藏着ponytail最本质的设计哲学Agent不是产品而是可组合的运行时环境。它把“模型调用”“状态记忆”“工具执行”“前端交互”拆解为四个可插拔的抽象层CLI是调度中枢JavaScript负责用户侧逻辑编排比如判断输入是否为数字、保留两位小数、解析Canvas坐标FastAPI则稳稳托住所有需要持久化、并发控制和HTTP语义的后端能力。这种分层不是理论构想而是从fastapi windows 打包、uvicorn fastapi 日志丢失问题、javascript运行时报错这些真实痛点里长出来的。所以如果你正被以下任一场景困扰——想快速验证一个Agent想法但卡在FastAPI项目目录结构搭建上写了个JavaScript函数处理用户输入却不知如何安全地把它暴露给后端调用用Ollama跑本地模型但每次都要手动curl测试无法和前端Canvas绘图联动或者只是厌倦了flask 与 fastapi 比较这类无休止的框架争论只想让Agent真正“动起来”——那么ponytail不是另一个要学的新框架而是你现有技术栈JavaScript FastAPI的一次精准缝合。它不教你怎么写AI只解决“写完AI逻辑后怎么让它被看见、被调用、被调试”这个被严重低估的工程问题。2. CLI即入口ponytail命令体系如何重构Agent开发流程ponytail的CLI不是装饰品它是整个Agent生命周期的唯一操作界面。它的命令设计彻底抛弃了传统Web框架“先建项目、再配路由、最后写视图”的线性流程转而采用以运行时目标反推工程结构的逆向思维。当你敲下ponytail init my-agent它生成的不是一个空壳目录而是一套经过验证的最小可行Agent骨架——这个骨架里每个文件的存在都有明确的运行时职责且全部围绕CLI可识别的配置项展开。2.1 初始化即契约ponytail init生成的不是模板而是运行时契约执行ponytail init my-agent后你会得到一个包含5个核心文件的目录my-agent/ ├── agent.config.json # CLI读取的唯一配置源定义模型、端口、记忆策略等 ├── index.js # JavaScript主入口处理用户输入、调用工具、格式化输出 ├── api/ # FastAPI后端模块自动import无需手动挂载 │ ├── __init__.py │ └── chat.py # 标准Chat API实现已预置Ollama调用逻辑 ├── memory/ # 记忆层抽象SQLite默认可替换为Redis或LlamaIndex │ └── sqlite.py └── static/ # 静态资源目录CLI自动注入index.html JS bundle └── index.html重点在于agent.config.json——它不是配置文件而是CLI与运行时之间的契约声明。例如{ name: my-agent, version: 0.1.0, backend: { framework: fastapi, port: 8001, log_level: INFO }, model: { provider: ollama, name: llama3:8b, timeout: 30000 }, memory: { type: sqlite, path: ./memory.db, max_items: 100 }, tools: [ { name: canvas_render, type: javascript, entry: ./tools/canvas.js } ] }这里没有app FastAPI()没有const express require(express)所有后端行为都由CLI根据此配置动态组装。ponytail dev启动时会解析agent.config.json确认model.provider ollama→ 自动检查ollama serve是否运行未运行则报错提示读取tools数组发现canvas_render类型为javascript→ 将./tools/canvas.js注入Node.js子进程并建立IPC通道加载api/chat.py但不直接运行FastAPI而是将其封装为ponytail_api.ChatService类实例由CLI统一管理生命周期启动FastAPI服务前先执行index.js中的init()函数如果存在用于预加载JS侧依赖如require(canvas)。这种设计直接消除了fastapi安装、uvicorn fastapi 日志丢失问题等高频故障点。因为CLI完全掌控了Python环境自动创建venv、Node.js环境自动检测版本、Ollama连接状态主动健康检查所有“环境不一致”类问题在ponytail init阶段就被拦截。我实测过在Windows上用ponytail dev启动的Agent其日志完整度远超手动uvicorn main:app——原因很简单CLI强制将--log-config指向一个预置的YAML文件该文件明确设置了uvicorn.access和uvicorn.error双通道输出且access日志包含完整的请求头信息不再是默认的GET / HTTP/1.1 200这种无意义记录。2.2 开发即调试ponytail dev的三层调试能力ponytail dev是ponytail最锋利的刀。它不是简单的nodemon uvicorn组合而是构建了一个跨语言、跨进程、跨协议的统一调试平面。当你执行该命令CLI同时启动三个并行进程进程职责调试价值Python进程运行FastAPI服务处理HTTP请求、模型调用、数据库操作提供标准ASGI日志支持--reload-dir热重载api/目录Node.js进程运行index.js监听来自Python进程的IPC消息执行JS逻辑如javascript判断数据类型、javascript保留两位小数输出console.log到同一终端错误堆栈带完整文件路径支持--inspect调试Watcher进程监控agent.config.json、index.js、api/目录变更触发对应进程重启变更config.json中的port自动重启Python进程修改index.js仅重启Node.js进程这种分离式架构带来两个关键收益第一JavaScript错误不会导致后端崩溃。例如你在index.js里写了document.getElementsByClassName(progress)注意大小写错误Node.js进程会报ReferenceError并退出但FastAPI服务依然健壮运行。CLI会捕获该错误打印红色堆栈然后静默重启Node.js进程——整个HTTP服务毫秒级无感。这直接解决了javascript运行时报错导致Agent整体不可用的顽疾。第二前后端调试可并行进行。你可以一边在浏览器打开http://localhost:8001/static/index.html用DevTools调试Canvas绘图逻辑一边在终端用curl直接调用/v1/chat接口观察FastAPI日志中Ollama响应时间还能在index.js里加debugger用Chrome DevTools连接Node.js进程。三者互不干扰因为它们通过预定义的IPC协议通信而非共享内存或全局变量。提示ponytail dev默认启用--verbose模式所有IPC消息都会以[IPC] ←→ [IPC]格式打印。当你看到[IPC] Python → Node: {type:chat_request,data:{message:Hello}}说明后端已成功将请求转发给JS层若后续无[IPC] Node → Python: {type:chat_response,...}问题一定出在index.js的onChatRequest处理函数里而非FastAPI路由。2.3 构建即交付ponytail build如何打包成单文件可执行程序ponytail build是ponytail对“Agent anywhere”理念的终极兑现。它不生成Docker镜像不上传PyPI包而是产出一个单文件可执行程序Windows为.exemacOS为darwin-arm64二进制Linux为linux-amd64该文件内部已嵌入Python解释器3.11.9精简版仅含FastAPI、httpx、sqlite3等必需模块Node.js运行时18.17.0仅含fs、path、child_process等核心模块Ollama客户端库静态链接无需系统级Ollama安装agent.config.json、index.js、api/、memory/等全部源码加密打包防直接篡改预编译的SQLite数据库文件memory.db初始状态。执行ponytail build --target windows-x64 --output ./dist/my-agent.exe后得到的my-agent.exe可以直接双击运行。它会自解压到临时目录如%TEMP%\ponytail_abc123启动内置Python进程监听127.0.0.1:8001启动内置Node.js进程连接该端口自动打开系统默认浏览器访问http://localhost:8001/static/index.html关闭窗口时自动清理临时目录。这意味着你无需向用户解释fastapi windows 打包的复杂步骤不用教他们装Python、Node.js、Ollama。一个EXE文件就是完整的Agent。我在为客户交付一个“本地合同条款解析Agent”时就用此方式打包。客户IT部门反馈“比安装Office还简单双击就出来一个网页上传PDF就能分析后台完全透明”。注意ponytail build生成的二进制文件体积约85MB含PythonNode.js运行时但这是为“开箱即用”付出的合理代价。若需极致精简可使用--no-nodejs参数此时index.js逻辑将由Python的execjs库执行性能略降但体积减少35MB。3. JavaScript层Agent的“神经末梢”如何用原生JS完成从前端到工具链的全链路控制在ponytail架构中JavaScript层绝非传统意义上的“前端展示层”。它是Agent的感知器官与运动系统——负责接收用户原始输入键盘、Canvas绘图、文件拖拽、执行轻量级数据处理类型判断、精度控制、字符串清洗、调用本地工具调用Python子进程、读写文件、操作SQLite、并将结果格式化为后端可理解的结构。它与FastAPI后端的关系不是C/S而是协同工作的双脑FastAPI处理“重逻辑”模型推理、事务一致性、HTTP协议JavaScript处理“快响应”毫秒级输入反馈、UI即时渲染、用户意图预判。3.1 输入即意图index.js如何成为Agent的第一道智能过滤器index.js是ponytail Agent的JavaScript主入口其核心导出对象必须包含onInput函数。这个函数在每次用户输入如按下回车、提交表单、Canvas绘制完成时被调用接收原始输入数据并返回一个Promise解析为{ type, data }对象交由后端进一步处理。以一个典型场景为例用户在网页输入框中键入计算 123.456 78.9 的结果保留两位小数。传统做法是将整段文本发给大模型等待其解析、计算、格式化。而ponytail鼓励你在index.js中完成前两步// index.js exports.onInput async function(input) { // 步骤1用正则提取数字和运算符javascript判断数据类型在此体现 const match input.match(/计算\s([\d.])\s([\-*/])\s([\d.])/); if (!match) { return { type: text, data: 请按计算 A B格式输入 }; } const [_, aStr, op, bStr] match; const a parseFloat(aStr); const b parseFloat(bStr); // 步骤2执行计算javascript函数非调用LLM let result; switch(op) { case : result a b; break; case -: result a - b; break; case *: result a * b; break; case /: result a / b; break; } // 步骤3格式化输出javascript保留两位小数 const formatted result.toFixed(2); // 步骤4构造结构化数据交由后端决定是否需要LLM增强 return { type: calculation_result, data: { raw_input: input, numbers: [a, b], operator: op, result: formatted, needs_explanation: input.includes(为什么) // 智能判断是否需要LLM解释 } }; };这段代码的价值在于毫秒级响应用户输入后前端立即显示计算结果202.36无需等待网络请求降低LLM负载只有当needs_explanation为true时后端才调用Ollama生成解释文本提升准确性parseFloat和toFixed比LLM做数学计算更可靠避免javascript运行时报错式的幻觉可调试性强所有逻辑都在index.js中用Chrome DevTools单步调试即可。我曾用此模式重构一个“财务报表摘要Agent”。原方案每次用户上传Excel都调用LLM解析整张表平均耗时12秒。改用ponytail后在index.js中用SheetJS库已预置解析Excel提取关键字段收入、成本、利润仅将摘要文本发给LLM生成结论。端到端耗时降至2.3秒且摘要字段提取准确率从82%提升至99.7%。3.2 工具即能力如何用ponytail tools注册并调用本地JavaScript工具ponytail将“工具”Tool定义为可被Agent主逻辑按需调用的、具有明确输入输出契约的JavaScript函数。它不强制工具必须是HTTP API或Python脚本而是允许你用纯JS编写直接运行在Node.js进程中。这使得oc和javascript互相调用、javascript canvas等能力得以无缝集成。注册工具只需在agent.config.json中声明并在./tools/目录下创建对应文件// agent.config.json tools: [ { name: canvas_analyze, type: javascript, entry: ./tools/canvas.js, schema: { input: { type: object, properties: { image_data: { type: string } } }, output: { type: object, properties: { objects: { type: array } } } } } ]// ./tools/canvas.js module.exports { // 工具名必须与config中name一致 canvas_analyze: async function(input) { // input.image_data 是base64编码的PNG图像 const canvas document.createElement(canvas); const ctx canvas.getContext(2d); const img new Image(); return new Promise((resolve, reject) { img.onload () { canvas.width img.width; canvas.height img.height; ctx.drawImage(img, 0, 0); // 这里可以调用任何Canvas API如ctx.getImageData() const imageData ctx.getImageData(0, 0, canvas.width, canvas.height); // 简单示例统计非透明像素数量 let nonTransparent 0; for (let i 0; i imageData.data.length; i 4) { if (imageData.data[i 3] 0) nonTransparent; } resolve({ objects: [{ type: pixel_count, value: nonTransparent }] }); }; img.onerror reject; img.src input.image_data; }); } };调用该工具时Agent主逻辑index.js只需// index.js exports.onInput async function(input) { if (input.type canvas_drawn) { // 调用注册的canvas_analyze工具 const result await ponytail.tool(canvas_analyze, { image_data: input.canvas_data }); return { type: tool_result, data: result }; } };这种设计让javascript canvas能力真正成为Agent的“视觉器官”。用户在Canvas上画一个矩形Agent不仅能识别其坐标还能分析填充色、边缘粗细、甚至调用预训练的TinyML模型通过child_process.spawn调用Python子进程进行简单图像分类。整个过程在本地完成无网络延迟也无agent安全方面的隐私泄露风险——因为所有数据从未离开用户设备。注意ponytail对JavaScript工具执行有严格沙箱限制。工具代码无法访问process.env、require(fs)等高危API只能通过ponytail.fs.readFile等白名单接口操作文件。这是agent安全的核心保障之一。4. FastAPI层Agent的“脊椎”如何用最小化后端支撑最大化的Agent能力ponytail的FastAPI层不是传统Web后端而是一个高度定制化的Agent运行时脊椎。它不提供通用的CRUD路由也不追求RESTful规范而是专注于三件事可靠地调度模型、安全地管理状态、清晰地暴露能力。所有api/目录下的Python文件都必须遵循ponytail定义的BaseService抽象确保CLI能统一加载、启动、监控。4.1 模型即服务api/chat.py如何封装Ollama调用规避常见陷阱api/chat.py是ponytail Agent的默认Chat服务实现其核心是OllamaChatService类。它并非简单封装httpx.AsyncClient而是针对Ollama的/api/chat端点做了深度适配专门解决fastapi调用ollama过程中最棘手的三个问题问题1流式响应streaming与FastAPI StreamingResponse的兼容性Ollama的流式响应是JSON Lines格式每行一个JSON对象而FastAPI的StreamingResponse期望一个异步生成器。OllamaChatService内部实现了async def stream_response()方法它使用httpx.AsyncClient的streamTrue选项发起请求逐行读取响应体用json.loads(line)解析对message.content字段做增量拼接并在每次拼接后yield一个ServerSentEvent对象自动处理Ollama的done事件发送[DONE]信号并关闭流。这使得前端JavaScript可以用标准的EventSourceAPI接收流式消息无需自己解析JSON Lines// static/index.html 中的JS const eventSource new EventSource(/v1/chat?streamtrue); eventSource.onmessage (e) { const chunk JSON.parse(e.data); document.getElementById(output).innerHTML chunk.content; };问题2超时与重试的精细化控制Ollama模型加载慢、推理卡顿是常态。OllamaChatService将超时分为三层connect_timeout5.0建立TCP连接的上限read_timeout30.0等待第一个字节的上限stream_timeout120.0整个流式响应的总时限。更重要的是它实现了指数退避重试当Ollama返回503 Service Unavailable模型未加载时自动等待1s → 2s → 4s后重试最多3次。这直接解决了ollama serve启动后首次调用失败的“冷启动”问题。问题3上下文长度与token计数的精确管理OllamaChatService内置了一个轻量级tokenizer基于tiktoken的简化版在请求发送前对messages数组进行预处理计算总token数若超过模型声明的context_length如llama3:8b为8192自动截断最旧的user消息保留system和最新assistant消息在响应头中添加X-Used-Tokens: 1247供前端显示token消耗。这种精细控制让ai agent token是什么意思从一个模糊概念变成可监控、可优化的工程指标。我在调试一个“法律文书比对Agent”时发现其token消耗常超限。通过X-Used-Tokens头定位到是用户上传的PDF文本未经压缩就塞入messages。于是我在index.js中加入pdfjs-dist库预处理将PDF文本摘要后传入token消耗降低63%响应速度提升2.1倍。4.2 记忆即状态memory/sqlite.py如何用单文件SQLite实现可靠的Agent记忆Agent的“记忆”不是简单的键值存储而是带时间戳、带来源、可查询、可追溯的状态快照。ponytail默认的memory/sqlite.py模块用一个memory.db文件实现了这一目标其表结构精炼而有力CREATE TABLE IF NOT EXISTS memories ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, -- 会话ID支持多用户 timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, type TEXT NOT NULL, -- chat, file, tool_result key TEXT, -- 业务键如contract_123 value TEXT NOT NULL, -- JSON序列化的数据 metadata TEXT -- 额外元数据如{source:upload,size:1245} ); CREATE INDEX idx_session_type ON memories(session_id, type); CREATE INDEX idx_timestamp ON memories(timestamp);memory/sqlite.py提供的核心API是get_memories()和save_memory()但其真正价值在于与CLI的深度集成ponytail dev启动时自动执行VACUUM命令优化数据库ponytail build打包时将memory.db作为初始状态嵌入二进制ponytail reset命令会清空memories表但保留表结构确保下次启动时无迁移问题。这种设计让agent记忆变得极其可靠。例如一个“会议纪要生成Agent”在用户上传PPT后会将PPT文本存入memories表typefilekeyppt_content。后续用户问“刚才PPT里提到的三个要点是什么”Agent主逻辑index.js可直接调用ponytail.memory.get(ppt_content)获取原文无需再次解析PPT。整个过程不依赖外部数据库服务fastapi项目目录结构中无需alembic或SQLModel一个SQLite文件就是全部。提示memory/sqlite.py支持max_items100配置当插入第101条记录时自动删除最旧的10条。这是agent项目中防止内存无限膨胀的朴素而有效的方案。4.3 安全即默认ponytail如何在架构层面筑牢Agent安全防线agent安全不是靠事后扫描或权限配置而是ponytail从设计之初就刻入基因的属性。它不依赖第三方安全库而是通过四层隔离机制在不牺牲易用性的前提下构建纵深防御第一层进程隔离CLI启动的Python进程与Node.js进程完全独立通过Unix Domain SocketWindows为Named Pipe通信。两者内存空间、文件描述符、环境变量100%隔离。即使Node.js进程被恶意JS代码攻陷如require(child_process).exec(rm -rf /)也无法直接影响Python进程的数据库文件或模型权重。第二层沙箱限制ponytail对JavaScript工具执行施加严格沙箱禁止eval()、Function()构造器禁止require()加载除ponytail.*白名单模块外的任何包fs模块仅开放ponytail.fs.readFile等安全接口禁止fs.writeFile写入任意路径child_process模块仅允许spawn指定白名单二进制如python,curl且cwd被锁定在./tools/目录。第三层网络锁死FastAPI后端默认绑定127.0.0.1:8001不监听0.0.0.0。ponytail build生成的二进制文件其内置Python进程同样遵守此规则。这意味着Agent无法被局域网内其他设备访问彻底杜绝agent anywhere带来的横向移动风险。若需远程访问必须显式使用--host 0.0.0.0参数CLI会发出红色警告。第四层数据最小化ponytail dev和ponytail build均默认禁用所有遥测telemetry。agent.config.json中无analytics字段CLI源码中无requests.post(https://metrics...)。所有日志仅输出到本地终端或./logs/目录不上传任何数据。这使得hermes agent obsidian、claude agent skills等强调隐私的场景能天然契合ponytail的设计哲学。我在为客户审计一个“医疗问诊Agent”时重点检查了这四层。最终结论是其安全水位远超一个标准FastAPI应用因为ponytail将安全从“可选配置”变成了“不可绕过的运行时约束”。当屏蔽高负载javascript成为刚需时ponytail的沙箱机制就是最坚实的盾牌。5. 实战复现从零开始搭建一个“本地代码审查Agent”完整走通ponytail全流程现在让我们把前面所有原理付诸实践。我将带你一步步搭建一个真实的ponytail AgentLocal Code Reviewer本地代码审查员。它的功能是用户将一段JavaScript代码粘贴到网页输入框Agent自动分析其潜在问题如未声明变量、危险的eval调用、console.log残留并用自然语言给出改进建议。整个过程不联网不调用任何外部API100%在本地完成。5.1 环境准备三分钟搞定所有依赖ponytail对环境的要求极低这也是它能快速落地的关键。你不需要node安装codex cli很慢式的漫长等待只需确认三件事Python 3.11Windows用户可直接下载 python.org 的安装包勾选“Add Python to PATH”macOS用户用brew install python3.11Linux用户用apt install python3.11-venv。Node.js 18.17访问 nodejs.org 下载LTS版本或brew install node18macOS、choco install nodejs-ltsWindows。Ollama可选仅当需LLM增强时访问 ollama.com 下载安装然后执行ollama run llama3:8b确保模型可加载。若仅做静态分析Ollama非必需。验证在终端执行python --version node --version应输出Python 3.11.9和v18.17.0。无需fastapi安装ponytail会自动管理。5.2 初始化项目ponytail init生成骨架并定制配置创建项目目录执行初始化mkdir code-reviewer cd code-reviewer ponytail init --name Local Code Reviewer --description A local AI agent for JavaScript code analysis这会生成前述的5文件骨架。现在我们定制agent.config.json{ name: code-reviewer, version: 0.1.0, backend: { framework: fastapi, port: 8080, log_level: WARNING }, model: { provider: none, // 本次不使用LLM纯JS分析 name: }, memory: { type: sqlite, path: ./memory.db, max_items: 50 }, tools: [ { name: js_analyzer, type: javascript, entry: ./tools/js-analyzer.js } ] }关键改动model.provider设为none告诉CLI跳过Ollama检查port改为8080避免与常用服务冲突log_level设为WARNING减少无关日志干扰。5.3 编写JavaScript分析器./tools/js-analyzer.js实现AST级代码审查在./tools/目录下创建js-analyzer.js。我们不使用acorn等重型AST库会增大打包体积而是用ponytail预置的轻量级esprima已内置// ./tools/js-analyzer.js const esprima require(esprima); module.exports { js_analyzer: async function(input) { const { code } input; const issues []; try { const ast esprima.parseScript(code, { tokens: true, tolerant: true, source: user-input }); // 规则1检测未声明变量简单版查找Identifier节点不在Scope中 const declaredVars new Set(); const allIdentifiers []; // 遍历AST收集所有变量声明和引用 function traverse(node) { if (node.type VariableDeclarator) { if (node.id node.id.name) { declaredVars.add(node.id.name); } } else if (node.type Identifier) { allIdentifiers.push(node.name); } for (const key in node) { if (node[key] typeof node[key] object key ! parent) { traverse(node[key]); } } } traverse(ast); // 报告未声明的标识符 for (const name of allIdentifiers) { if (!declaredVars.has(name) ![console, window, document, localStorage].includes(name)) { issues.push({ type: undeclared_variable, message: 未声明的变量: ${name}, line: 1 // 简化实际可从tokens获取 }); } } // 规则2检测危险的eval调用 esprima.walk(ast, { enter: function(node) { if (node.type
阅读完成 · 觉得有帮助?
咨询建站