a-calc 3.0.0-beta.20260105 → 3.0.0-beta.20260124.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -379
- package/a-calc.versions.js +56 -52
- package/browser/index.js +4 -2
- package/calc.d.ts +163 -22
- package/cjs/index.js +4 -2
- package/es/index.js +4 -2
- package/mcp-server/README.md +204 -0
- package/mcp-server/package.json +26 -0
- package/mcp-server/src/index.js +1360 -0
- package/package.json +20 -9
|
@@ -0,0 +1,1360 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import {
|
|
6
|
+
CallToolRequestSchema,
|
|
7
|
+
ListToolsRequestSchema,
|
|
8
|
+
ListResourcesRequestSchema,
|
|
9
|
+
ReadResourceRequestSchema,
|
|
10
|
+
ListPromptsRequestSchema,
|
|
11
|
+
GetPromptRequestSchema,
|
|
12
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
calc,
|
|
16
|
+
calc_sum,
|
|
17
|
+
calc_wrap,
|
|
18
|
+
fmt,
|
|
19
|
+
add,
|
|
20
|
+
sub,
|
|
21
|
+
mul,
|
|
22
|
+
div,
|
|
23
|
+
mod,
|
|
24
|
+
pow,
|
|
25
|
+
idiv,
|
|
26
|
+
abs,
|
|
27
|
+
neg,
|
|
28
|
+
sqrt,
|
|
29
|
+
ln,
|
|
30
|
+
exp,
|
|
31
|
+
cadd,
|
|
32
|
+
csub,
|
|
33
|
+
cmul,
|
|
34
|
+
cdiv,
|
|
35
|
+
set_config,
|
|
36
|
+
get_config,
|
|
37
|
+
} from "../../es/index.js";
|
|
38
|
+
|
|
39
|
+
// ==================== Tools 定义 ====================
|
|
40
|
+
|
|
41
|
+
const TOOLS = [
|
|
42
|
+
{
|
|
43
|
+
name: "calc",
|
|
44
|
+
description: `🔢 a-calc 高精度计算工具 - 解决 JavaScript 浮点数精度问题
|
|
45
|
+
|
|
46
|
+
⚠️ 重要:当用户需要进行任何数值计算时,优先使用此工具而不是直接计算!
|
|
47
|
+
|
|
48
|
+
🚨 编码规范(必读!):
|
|
49
|
+
|
|
50
|
+
1. 变量注入方式:
|
|
51
|
+
❌ 错误:calc(\`\${a} + \${b}\`) // 不要用模板字符串拼接
|
|
52
|
+
✅ 正确:calc("a + b", {a, b}) // 使用第二参数注入变量
|
|
53
|
+
|
|
54
|
+
2. 批量计算方式:
|
|
55
|
+
❌ 错误:let total = '0'; items.forEach(item => total = calc(\`\${total} + \${item.price}\`))
|
|
56
|
+
✅ 正确:const total = calc_sum("price * qty", items) // 使用 calc_sum
|
|
57
|
+
|
|
58
|
+
3. 购物车等场景:
|
|
59
|
+
❌ 错误:cart.forEach(item => total = calc(\`\${total} + \${item.price} * \${item.quantity}\`))
|
|
60
|
+
✅ 正确:calc_sum("price * quantity | =2", cart)
|
|
61
|
+
|
|
62
|
+
4. 对象字段传递:
|
|
63
|
+
❌ 错误:calc("price * qty", {price: item.price, qty: item.qty}) // 冗余
|
|
64
|
+
✅ 正确:calc("price * qty", item) // 简洁优雅
|
|
65
|
+
|
|
66
|
+
核心优势:
|
|
67
|
+
- ✅ 解决 0.1 + 0.2 = 0.30000000000000004 的精度问题
|
|
68
|
+
- ✅ 金融计算、价格计算、统计分析等场景必用
|
|
69
|
+
- ✅ 支持复杂表达式、变量替换、条件判断
|
|
70
|
+
- ✅ 内置格式化:千分位、小数位、百分比、科学计数法
|
|
71
|
+
|
|
72
|
+
适用场景(必须使用):
|
|
73
|
+
1. 任何涉及小数的加减乘除运算
|
|
74
|
+
2. 金融计算、价格计算、折扣计算
|
|
75
|
+
3. 百分比计算、比率计算
|
|
76
|
+
4. 需要格式化输出的数值(千分位、保留小数等)
|
|
77
|
+
5. 带单位的计算(如 "100元 + 50元")
|
|
78
|
+
6. 条件判断和比较运算
|
|
79
|
+
|
|
80
|
+
快速示例:
|
|
81
|
+
- calc("0.1 + 0.2") → "0.3" (精确!)
|
|
82
|
+
- calc("price * qty | =2", {price: 99.9, qty: 3}) → "299.70"
|
|
83
|
+
- calc("1234567 | ,") → "1,234,567" (千分位)
|
|
84
|
+
- calc("score >= 60 ? '及格' : '不及格'", {score: 75}) → "及格"
|
|
85
|
+
|
|
86
|
+
变量注入最佳实践:
|
|
87
|
+
- 如果对象已有所需字段,直接传入:calc("price * qty", item)
|
|
88
|
+
- 如果需要多个独立变量,使用简写:calc("a + b", {a, b})
|
|
89
|
+
- 避免冗余:❌ calc("price * qty", {price: item.price, qty: item.qty})
|
|
90
|
+
|
|
91
|
+
支持的运算:
|
|
92
|
+
- 基础运算: + - * / % ** // (加减乘除、取模、幂、整除)
|
|
93
|
+
- 比较运算: > < >= <= == !=
|
|
94
|
+
- 逻辑运算: && || !
|
|
95
|
+
- 数学函数: sqrt, sin, cos, tan, pow, max, min, abs, floor, ceil 等
|
|
96
|
+
- 格式化: =N(小数位), ,(千分位), %(百分比), !e(科学计数), !v(交易量)`,
|
|
97
|
+
inputSchema: {
|
|
98
|
+
type: "object",
|
|
99
|
+
properties: {
|
|
100
|
+
expr: {
|
|
101
|
+
type: "string",
|
|
102
|
+
description: "计算表达式,支持变量名和格式化(用 | 分隔)",
|
|
103
|
+
},
|
|
104
|
+
options: {
|
|
105
|
+
type: "object",
|
|
106
|
+
description: "配置选项和变量数据",
|
|
107
|
+
properties: {
|
|
108
|
+
_error: {
|
|
109
|
+
type: ["string", "number", "null"],
|
|
110
|
+
description: "错误时的返回值,默认会抛出异常",
|
|
111
|
+
},
|
|
112
|
+
_unit: {
|
|
113
|
+
type: "boolean",
|
|
114
|
+
description: "是否启用单位计算,如 '100元 + 50元'",
|
|
115
|
+
},
|
|
116
|
+
_fmt: {
|
|
117
|
+
type: "string",
|
|
118
|
+
description: "默认格式化字符串",
|
|
119
|
+
},
|
|
120
|
+
_mode: {
|
|
121
|
+
type: "string",
|
|
122
|
+
enum: ["normal", "space", "space-all"],
|
|
123
|
+
description: "解析模式",
|
|
124
|
+
},
|
|
125
|
+
_debug: {
|
|
126
|
+
type: "boolean",
|
|
127
|
+
description: "是否启用调试模式",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
additionalProperties: true,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
required: ["expr"],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "fmt",
|
|
138
|
+
description: `📊 a-calc 数值格式化工具 - 专业的数字格式化,性能最优
|
|
139
|
+
|
|
140
|
+
⚠️ 使用场景:当需要格式化数字(千分位、小数位、百分比等)但不需要计算时使用
|
|
141
|
+
|
|
142
|
+
性能优势:
|
|
143
|
+
- 跳过表达式解析,比 calc 更快
|
|
144
|
+
- 适合纯格式化场景
|
|
145
|
+
|
|
146
|
+
常用格式化规则:
|
|
147
|
+
- =N: 精确N位小数 (如 =2 → "100.00")
|
|
148
|
+
- <=N: 最多N位小数 (如 <=2 → "3.14")
|
|
149
|
+
- >=N: 至少N位小数 (如 >=3 → "3.100")
|
|
150
|
+
- ~5: 四舍五入 (如 ~5=2 → "1.13")
|
|
151
|
+
- ~6: 银行家舍入
|
|
152
|
+
- ,: 千分位分隔 (如 , → "1,234,567")
|
|
153
|
+
- %: 百分比 (如 %=2 → "12.34%")
|
|
154
|
+
- !e: 科学计数法 (如 !e=2 → "1.23e+8")
|
|
155
|
+
- +: 显示正号 (如 + → "+100")
|
|
156
|
+
- !n: 返回数字类型
|
|
157
|
+
- !v: 交易量缩写 (如 !v → "1.23M")
|
|
158
|
+
- !t:us/eu/indian/cn4: 千分位预设
|
|
159
|
+
|
|
160
|
+
快速示例:
|
|
161
|
+
- fmt(100, "=2") → "100.00"
|
|
162
|
+
- fmt(1234567, ",") → "1,234,567"
|
|
163
|
+
- fmt(0.1234, "%=2") → "12.34%"
|
|
164
|
+
- fmt(123456789, "!e=2") → "1.23e+8"
|
|
165
|
+
- fmt(1234567, "!v") → "1.23M"
|
|
166
|
+
- fmt(1234567.89, "!t:eu") → "1.234.567,89"`,
|
|
167
|
+
inputSchema: {
|
|
168
|
+
type: "object",
|
|
169
|
+
properties: {
|
|
170
|
+
value: {
|
|
171
|
+
type: ["number", "string"],
|
|
172
|
+
description: "要格式化的数值",
|
|
173
|
+
},
|
|
174
|
+
format_str: {
|
|
175
|
+
type: "string",
|
|
176
|
+
description: "格式化字符串",
|
|
177
|
+
},
|
|
178
|
+
options: {
|
|
179
|
+
type: "object",
|
|
180
|
+
description: "格式化选项",
|
|
181
|
+
additionalProperties: true,
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
required: ["value"],
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: "calc_sum",
|
|
189
|
+
description: `📈 a-calc 批量聚合计算工具 - 对数组数据进行批量计算并求和
|
|
190
|
+
|
|
191
|
+
⚠️ 使用场景:处理数组数据、批量计算、统计汇总时使用
|
|
192
|
+
|
|
193
|
+
🚨 这是处理数组数据的正确方式!不要用 forEach 累加!
|
|
194
|
+
|
|
195
|
+
典型应用场景:
|
|
196
|
+
1. 计算订单总价:多个商品的 price * quantity 求和
|
|
197
|
+
2. 统计销售额:多条销售记录的金额汇总
|
|
198
|
+
3. 报表数据汇总:批量计算并求和
|
|
199
|
+
4. 购物车总价计算
|
|
200
|
+
|
|
201
|
+
编码规范对比(必读!):
|
|
202
|
+
|
|
203
|
+
❌ 错误写法(不要这样做):
|
|
204
|
+
\`\`\`javascript
|
|
205
|
+
// 购物车总价 - 错误示例
|
|
206
|
+
let total = '0'
|
|
207
|
+
cart.forEach(item => {
|
|
208
|
+
total = calc(\`\${total} + \${item.price} * \${item.quantity}\`)
|
|
209
|
+
})
|
|
210
|
+
\`\`\`
|
|
211
|
+
问题:使用模板字符串拼接、forEach 累加,代码不清晰、性能差
|
|
212
|
+
|
|
213
|
+
✅ 正确写法(推荐):
|
|
214
|
+
\`\`\`javascript
|
|
215
|
+
// 购物车总价 - 使用 calc_sum
|
|
216
|
+
const total = calc_sum("price * quantity | =2", cart)
|
|
217
|
+
|
|
218
|
+
// 单个商品小计 - 直接传入对象(最优雅)
|
|
219
|
+
const itemTotal = calc("price * quantity | =2", item)
|
|
220
|
+
\`\`\`
|
|
221
|
+
优势:代码简洁、性能好、自动处理精度
|
|
222
|
+
|
|
223
|
+
🎯 最佳实践:
|
|
224
|
+
- 对象已有所需字段 → 直接传入:calc("a + b", obj)
|
|
225
|
+
- 需要多个独立变量 → 使用简写:calc("a + b", {a, b})
|
|
226
|
+
- 避免冗余写法 → ❌ calc("a + b", {a: obj.a, b: obj.b})
|
|
227
|
+
|
|
228
|
+
快速示例:
|
|
229
|
+
- calc_sum("a + b", [{a:1,b:2}, {a:3,b:4}]) → "10"
|
|
230
|
+
- calc_sum("price * qty", [{price:99.9,qty:2}, {price:49.9,qty:3}]) → "349.50"
|
|
231
|
+
- calc_sum("price * qty * 0.9 | =2", orders) → 计算所有订单9折后总价
|
|
232
|
+
|
|
233
|
+
优势:
|
|
234
|
+
- 自动处理精度问题
|
|
235
|
+
- 支持复杂表达式
|
|
236
|
+
- 支持格式化输出
|
|
237
|
+
- 性能优于手动累加`,
|
|
238
|
+
inputSchema: {
|
|
239
|
+
type: "object",
|
|
240
|
+
properties: {
|
|
241
|
+
expr: {
|
|
242
|
+
type: "string",
|
|
243
|
+
description: "计算表达式",
|
|
244
|
+
},
|
|
245
|
+
data_array: {
|
|
246
|
+
type: "array",
|
|
247
|
+
description: "数据源数组",
|
|
248
|
+
items: {
|
|
249
|
+
type: "object",
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
required: ["expr", "data_array"],
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
name: "basic_calc",
|
|
258
|
+
description: `a-calc 基础运算函数 - 直接进行精确的数学运算,性能最优
|
|
259
|
+
|
|
260
|
+
支持的运算:
|
|
261
|
+
- add: 加法 (支持多参数)
|
|
262
|
+
- sub: 减法 (支持多参数)
|
|
263
|
+
- mul: 乘法 (支持多参数)
|
|
264
|
+
- div: 除法 (支持多参数)
|
|
265
|
+
- mod: 取模
|
|
266
|
+
- pow: 幂运算
|
|
267
|
+
- idiv: 整除
|
|
268
|
+
- abs: 绝对值
|
|
269
|
+
- neg: 取负
|
|
270
|
+
- sqrt: 平方根
|
|
271
|
+
- ln: 自然对数
|
|
272
|
+
- exp: e的幂
|
|
273
|
+
|
|
274
|
+
使用示例:
|
|
275
|
+
- add(0.1, 0.2) → "0.3"
|
|
276
|
+
- mul(0.1, 0.2, 0.3) → "0.006"
|
|
277
|
+
- div(1, 3) → "0.333..."
|
|
278
|
+
- sqrt(16) → "4"`,
|
|
279
|
+
inputSchema: {
|
|
280
|
+
type: "object",
|
|
281
|
+
properties: {
|
|
282
|
+
operation: {
|
|
283
|
+
type: "string",
|
|
284
|
+
enum: ["add", "sub", "mul", "div", "mod", "pow", "idiv", "abs", "neg", "sqrt", "ln", "exp"],
|
|
285
|
+
description: "运算类型",
|
|
286
|
+
},
|
|
287
|
+
args: {
|
|
288
|
+
type: "array",
|
|
289
|
+
description: "运算参数",
|
|
290
|
+
items: {
|
|
291
|
+
type: ["number", "string"],
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
required: ["operation", "args"],
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
name: "chain_calc",
|
|
300
|
+
description: `a-calc 链式计算函数 - 流式 API 风格的连续运算
|
|
301
|
+
|
|
302
|
+
链式函数:
|
|
303
|
+
- cadd: 加法起始
|
|
304
|
+
- csub: 减法起始
|
|
305
|
+
- cmul: 乘法起始
|
|
306
|
+
- cdiv: 除法起始
|
|
307
|
+
|
|
308
|
+
链上方法: .add() .sub() .mul() .div() .mod() .pow() .idiv()
|
|
309
|
+
最后调用 () 或 (格式化字符串) 获取结果
|
|
310
|
+
|
|
311
|
+
使用示例:
|
|
312
|
+
- cadd(100, 200).mul(0.8).sub(50)() → "190"
|
|
313
|
+
- cmul(10, 20, 30).div(100)("=2") → "60.00"
|
|
314
|
+
- cadd(99.9, 199, 49.5).mul(0.9).sub(20)("=2,") → "296.33"`,
|
|
315
|
+
inputSchema: {
|
|
316
|
+
type: "object",
|
|
317
|
+
properties: {
|
|
318
|
+
start_op: {
|
|
319
|
+
type: "string",
|
|
320
|
+
enum: ["cadd", "csub", "cmul", "cdiv"],
|
|
321
|
+
description: "起始运算类型",
|
|
322
|
+
},
|
|
323
|
+
start_args: {
|
|
324
|
+
type: "array",
|
|
325
|
+
description: "起始运算参数",
|
|
326
|
+
items: {
|
|
327
|
+
type: ["number", "string"],
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
chain_ops: {
|
|
331
|
+
type: "array",
|
|
332
|
+
description: "链式操作序列",
|
|
333
|
+
items: {
|
|
334
|
+
type: "object",
|
|
335
|
+
properties: {
|
|
336
|
+
op: {
|
|
337
|
+
type: "string",
|
|
338
|
+
enum: ["add", "sub", "mul", "div", "mod", "pow", "idiv"],
|
|
339
|
+
},
|
|
340
|
+
args: {
|
|
341
|
+
type: "array",
|
|
342
|
+
items: {
|
|
343
|
+
type: ["number", "string"],
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
required: ["op", "args"],
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
format: {
|
|
351
|
+
type: "string",
|
|
352
|
+
description: "最终格式化字符串(可选)",
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
required: ["start_op", "start_args"],
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
name: "get_acalc_guide",
|
|
360
|
+
description: `获取 a-calc 库的使用指南和最佳实践
|
|
361
|
+
|
|
362
|
+
可获取的内容:
|
|
363
|
+
- api: API 完整参考
|
|
364
|
+
- formatting: 格式化规则详解
|
|
365
|
+
- functions: 内置数学函数
|
|
366
|
+
- conditional: 条件表达式和比较运算
|
|
367
|
+
- chain: 链式计算
|
|
368
|
+
- examples: 常见使用示例
|
|
369
|
+
- all: 获取全部内容`,
|
|
370
|
+
inputSchema: {
|
|
371
|
+
type: "object",
|
|
372
|
+
properties: {
|
|
373
|
+
topic: {
|
|
374
|
+
type: "string",
|
|
375
|
+
enum: ["api", "formatting", "functions", "conditional", "chain", "examples", "all"],
|
|
376
|
+
description: "要获取的主题",
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
required: ["topic"],
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
name: "debug_info",
|
|
384
|
+
description: `🔍 调试工具 - 获取 MCP 服务器的运行环境信息
|
|
385
|
+
|
|
386
|
+
返回信息:
|
|
387
|
+
- cwd: 当前工作目录 (process.cwd())
|
|
388
|
+
- __dirname: 脚本所在目录
|
|
389
|
+
- __filename: 脚本文件路径
|
|
390
|
+
- node_version: Node.js 版本
|
|
391
|
+
- platform: 操作系统平台
|
|
392
|
+
- env: 相关环境变量
|
|
393
|
+
|
|
394
|
+
用途:调试 MCP 服务器配置问题`,
|
|
395
|
+
inputSchema: {
|
|
396
|
+
type: "object",
|
|
397
|
+
properties: {},
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
];
|
|
401
|
+
|
|
402
|
+
// ==================== Resources 定义 ====================
|
|
403
|
+
|
|
404
|
+
const RESOURCES = [
|
|
405
|
+
{
|
|
406
|
+
uri: "acalc://api/overview",
|
|
407
|
+
name: "a-calc API 概览",
|
|
408
|
+
description: "a-calc 库的完整 API 参考文档",
|
|
409
|
+
mimeType: "text/markdown",
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
uri: "acalc://guide/formatting",
|
|
413
|
+
name: "格式化规则指南",
|
|
414
|
+
description: "详细的格式化规则和选项说明",
|
|
415
|
+
mimeType: "text/markdown",
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
uri: "acalc://guide/functions",
|
|
419
|
+
name: "内置数学函数",
|
|
420
|
+
description: "支持的数学函数列表和用法",
|
|
421
|
+
mimeType: "text/markdown",
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
uri: "acalc://guide/conditional",
|
|
425
|
+
name: "条件表达式",
|
|
426
|
+
description: "条件表达式、比较运算、逻辑运算",
|
|
427
|
+
mimeType: "text/markdown",
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
uri: "acalc://examples/common",
|
|
431
|
+
name: "常见示例",
|
|
432
|
+
description: "常见使用场景的代码示例",
|
|
433
|
+
mimeType: "text/markdown",
|
|
434
|
+
},
|
|
435
|
+
];
|
|
436
|
+
|
|
437
|
+
// ==================== Resource Contents ====================
|
|
438
|
+
|
|
439
|
+
const RESOURCE_CONTENTS = {
|
|
440
|
+
"acalc://api/overview": `# a-calc API 完整参考
|
|
441
|
+
|
|
442
|
+
## 核心函数
|
|
443
|
+
|
|
444
|
+
### calc(expr, options?)
|
|
445
|
+
核心计算函数,支持表达式计算、变量填充、格式化。
|
|
446
|
+
|
|
447
|
+
**参数:**
|
|
448
|
+
- \`expr\`: string | number - 计算表达式
|
|
449
|
+
- \`options\`: object - 配置选项和变量数据
|
|
450
|
+
|
|
451
|
+
**返回:** string | number
|
|
452
|
+
|
|
453
|
+
**示例:**
|
|
454
|
+
\`\`\`javascript
|
|
455
|
+
calc("0.1 + 0.2") // "0.3"
|
|
456
|
+
calc("a + b", {a: 1, b: 2}) // "3"
|
|
457
|
+
calc("10 / 3 | =2") // "3.33"
|
|
458
|
+
\`\`\`
|
|
459
|
+
|
|
460
|
+
### fmt(value, format?, options?)
|
|
461
|
+
专用格式化函数,跳过表达式解析,性能更优。
|
|
462
|
+
|
|
463
|
+
**参数:**
|
|
464
|
+
- \`value\`: number | string - 要格式化的数值
|
|
465
|
+
- \`format\`: string - 格式化字符串
|
|
466
|
+
- \`options\`: object - 配置选项
|
|
467
|
+
|
|
468
|
+
**返回:** string | number
|
|
469
|
+
|
|
470
|
+
**示例:**
|
|
471
|
+
\`\`\`javascript
|
|
472
|
+
fmt(100, "=2") // "100.00"
|
|
473
|
+
fmt(1234567, ",") // "1,234,567"
|
|
474
|
+
\`\`\`
|
|
475
|
+
|
|
476
|
+
### calc_sum(expr, data_array)
|
|
477
|
+
聚合计算函数,对数组数据批量计算并求和。
|
|
478
|
+
|
|
479
|
+
**参数:**
|
|
480
|
+
- \`expr\`: string - 计算表达式
|
|
481
|
+
- \`data_array\`: array - 数据源数组
|
|
482
|
+
|
|
483
|
+
**返回:** string | number
|
|
484
|
+
|
|
485
|
+
**示例:**
|
|
486
|
+
\`\`\`javascript
|
|
487
|
+
calc_sum("a + b", [{a:1,b:2}, {a:3,b:4}]) // "10"
|
|
488
|
+
\`\`\`
|
|
489
|
+
|
|
490
|
+
## 基础运算函数
|
|
491
|
+
|
|
492
|
+
支持多参数运算,返回 number 类型:
|
|
493
|
+
|
|
494
|
+
- \`add(...nums)\` - 加法
|
|
495
|
+
- \`sub(...nums)\` - 减法
|
|
496
|
+
- \`mul(...nums)\` - 乘法
|
|
497
|
+
- \`div(...nums)\` - 除法
|
|
498
|
+
- \`mod(a, b)\` - 取模
|
|
499
|
+
- \`pow(base, exp)\` - 幂运算
|
|
500
|
+
- \`idiv(a, b)\` - 整除
|
|
501
|
+
- \`abs(value)\` - 绝对值
|
|
502
|
+
- \`neg(value)\` - 取负
|
|
503
|
+
- \`sqrt(value)\` - 平方根
|
|
504
|
+
- \`ln(value)\` - 自然对数
|
|
505
|
+
- \`exp(value)\` - e的幂
|
|
506
|
+
|
|
507
|
+
## 链式计算函数
|
|
508
|
+
|
|
509
|
+
流式 API 风格的连续运算:
|
|
510
|
+
|
|
511
|
+
- \`cadd(...nums)\` - 加法起始
|
|
512
|
+
- \`csub(first, ...rest)\` - 减法起始
|
|
513
|
+
- \`cmul(...nums)\` - 乘法起始
|
|
514
|
+
- \`cdiv(first, ...rest)\` - 除法起始
|
|
515
|
+
|
|
516
|
+
链上方法:\`.add()\` \`.sub()\` \`.mul()\` \`.div()\` \`.mod()\` \`.pow()\` \`.idiv()\`
|
|
517
|
+
|
|
518
|
+
**示例:**
|
|
519
|
+
\`\`\`javascript
|
|
520
|
+
cadd(100, 200).mul(0.8).sub(50)() // "190"
|
|
521
|
+
\`\`\`
|
|
522
|
+
`,
|
|
523
|
+
|
|
524
|
+
"acalc://guide/formatting": `# 格式化规则详解
|
|
525
|
+
|
|
526
|
+
## 小数位控制
|
|
527
|
+
|
|
528
|
+
- \`=N\` - 精确N位小数
|
|
529
|
+
- \`<=N\` - 最多N位小数
|
|
530
|
+
- \`>=N\` - 至少N位小数
|
|
531
|
+
- \`>=M<=N\` - M到N位小数范围
|
|
532
|
+
|
|
533
|
+
**示例:**
|
|
534
|
+
\`\`\`javascript
|
|
535
|
+
calc("10 / 3 | =2") // "3.33"
|
|
536
|
+
calc("3.14159 | <=2") // "3.14"
|
|
537
|
+
calc("3.1 | >=3") // "3.100"
|
|
538
|
+
\`\`\`
|
|
539
|
+
|
|
540
|
+
## 舍入规则
|
|
541
|
+
|
|
542
|
+
- \`~-\` - 截断(默认)
|
|
543
|
+
- \`~+\` - 进位
|
|
544
|
+
- \`~5\` - 四舍五入
|
|
545
|
+
- \`~6\` - 银行家舍入
|
|
546
|
+
|
|
547
|
+
**示例:**
|
|
548
|
+
\`\`\`javascript
|
|
549
|
+
calc("1.125 | ~5=2") // "1.13"
|
|
550
|
+
calc("1.125 | ~6=2") // "1.12"
|
|
551
|
+
calc("1.124 | ~+=2") // "1.13"
|
|
552
|
+
\`\`\`
|
|
553
|
+
|
|
554
|
+
## 千分位
|
|
555
|
+
|
|
556
|
+
- \`,\` - 千分位分隔符
|
|
557
|
+
- \`!t:us\` - 美式千分位 (1,234.56)
|
|
558
|
+
- \`!t:eu\` - 欧式千分位 (1.234,56)
|
|
559
|
+
- \`!t:indian\` - 印度式千分位 (12,34,567)
|
|
560
|
+
- \`!t:cn4\` - 中文四位分隔 (1234,5678)
|
|
561
|
+
|
|
562
|
+
**示例:**
|
|
563
|
+
\`\`\`javascript
|
|
564
|
+
calc("1234567 | ,") // "1,234,567"
|
|
565
|
+
fmt(1234567.89, "!t:eu") // "1.234.567,89"
|
|
566
|
+
\`\`\`
|
|
567
|
+
|
|
568
|
+
## 百分比
|
|
569
|
+
|
|
570
|
+
- \`%\` - 转换为百分比
|
|
571
|
+
|
|
572
|
+
**示例:**
|
|
573
|
+
\`\`\`javascript
|
|
574
|
+
calc("0.1234 | %=2") // "12.34%"
|
|
575
|
+
\`\`\`
|
|
576
|
+
|
|
577
|
+
## 科学计数法
|
|
578
|
+
|
|
579
|
+
- \`!e\` - 科学计数法输出
|
|
580
|
+
|
|
581
|
+
**示例:**
|
|
582
|
+
\`\`\`javascript
|
|
583
|
+
calc("123456789 | !e=2") // "1.23e+8"
|
|
584
|
+
\`\`\`
|
|
585
|
+
|
|
586
|
+
## 正负号
|
|
587
|
+
|
|
588
|
+
- \`+\` - 正数显示 + 号
|
|
589
|
+
|
|
590
|
+
**示例:**
|
|
591
|
+
\`\`\`javascript
|
|
592
|
+
calc("100 | +") // "+100"
|
|
593
|
+
\`\`\`
|
|
594
|
+
|
|
595
|
+
## 返回数字类型
|
|
596
|
+
|
|
597
|
+
- \`!n\` - 返回 number 类型而非 string
|
|
598
|
+
|
|
599
|
+
**示例:**
|
|
600
|
+
\`\`\`javascript
|
|
601
|
+
calc("1 + 1 | !n") // 2 (number)
|
|
602
|
+
\`\`\`
|
|
603
|
+
|
|
604
|
+
## 交易量格式化
|
|
605
|
+
|
|
606
|
+
- \`!v\` - 交易量缩写 (1.23M, 1.23B)
|
|
607
|
+
- \`!v:wan\` - 中文单位 (1.23万)
|
|
608
|
+
|
|
609
|
+
**示例:**
|
|
610
|
+
\`\`\`javascript
|
|
611
|
+
calc("1234567 | !v") // "1.23M"
|
|
612
|
+
calc("12345 | !v:wan") // "1.23万"
|
|
613
|
+
\`\`\`
|
|
614
|
+
|
|
615
|
+
## 组合使用
|
|
616
|
+
|
|
617
|
+
格式化参数可以组合使用:
|
|
618
|
+
|
|
619
|
+
\`\`\`javascript
|
|
620
|
+
calc("0.1234 | %=2+") // "+12.34%"
|
|
621
|
+
calc("1234567.89 | ,=2") // "1,234,567.89"
|
|
622
|
+
calc("price * qty | ~5=2,", {price: 99.9, qty: 3}) // "299.70"
|
|
623
|
+
\`\`\`
|
|
624
|
+
`,
|
|
625
|
+
|
|
626
|
+
"acalc://guide/functions": `# 内置数学函数
|
|
627
|
+
|
|
628
|
+
a-calc 支持在表达式中直接使用数学函数。
|
|
629
|
+
|
|
630
|
+
## 基础数学函数
|
|
631
|
+
|
|
632
|
+
- \`sqrt(x)\` - 平方根
|
|
633
|
+
- \`cbrt(x)\` - 立方根
|
|
634
|
+
- \`abs(x)\` - 绝对值
|
|
635
|
+
- \`pow(x, y)\` - x 的 y 次方
|
|
636
|
+
- \`exp(x)\` - e 的 x 次方
|
|
637
|
+
- \`ln(x)\` - 自然对数
|
|
638
|
+
- \`log(x)\` - 常用对数(以10为底)
|
|
639
|
+
- \`log2(x)\` - 以2为底的对数
|
|
640
|
+
- \`log10(x)\` - 以10为底的对数
|
|
641
|
+
|
|
642
|
+
## 三角函数
|
|
643
|
+
|
|
644
|
+
- \`sin(x)\` - 正弦
|
|
645
|
+
- \`cos(x)\` - 余弦
|
|
646
|
+
- \`tan(x)\` - 正切
|
|
647
|
+
- \`asin(x)\` - 反正弦
|
|
648
|
+
- \`acos(x)\` - 反余弦
|
|
649
|
+
- \`atan(x)\` - 反正切
|
|
650
|
+
|
|
651
|
+
## 双曲函数
|
|
652
|
+
|
|
653
|
+
- \`sinh(x)\` - 双曲正弦
|
|
654
|
+
- \`cosh(x)\` - 双曲余弦
|
|
655
|
+
- \`tanh(x)\` - 双曲正切
|
|
656
|
+
- \`asinh(x)\` - 反双曲正弦
|
|
657
|
+
- \`acosh(x)\` - 反双曲余弦
|
|
658
|
+
- \`atanh(x)\` - 反双曲正切
|
|
659
|
+
|
|
660
|
+
## 取整函数
|
|
661
|
+
|
|
662
|
+
- \`floor(x)\` - 向下取整
|
|
663
|
+
- \`ceil(x)\` - 向上取整
|
|
664
|
+
- \`trunc(x)\` - 截断小数
|
|
665
|
+
- \`round(x)\` - 四舍五入
|
|
666
|
+
|
|
667
|
+
## 比较函数
|
|
668
|
+
|
|
669
|
+
- \`max(x, y, ...)\` - 最大值
|
|
670
|
+
- \`min(x, y, ...)\` - 最小值
|
|
671
|
+
|
|
672
|
+
## 使用示例
|
|
673
|
+
|
|
674
|
+
\`\`\`javascript
|
|
675
|
+
calc("sqrt(16) + pow(2, 3)") // "12"
|
|
676
|
+
calc("sin(0) + cos(0)") // "1"
|
|
677
|
+
calc("max(10, 20, 30)") // "30"
|
|
678
|
+
calc("floor(3.7) + ceil(3.2)") // "7"
|
|
679
|
+
calc("ln(exp(1))") // "1"
|
|
680
|
+
\`\`\`
|
|
681
|
+
|
|
682
|
+
## 函数嵌套
|
|
683
|
+
|
|
684
|
+
函数可以嵌套使用:
|
|
685
|
+
|
|
686
|
+
\`\`\`javascript
|
|
687
|
+
calc("sqrt(pow(3, 2) + pow(4, 2))") // "5" (勾股定理)
|
|
688
|
+
calc("round(sqrt(2) * 100) / 100") // "1.41"
|
|
689
|
+
\`\`\`
|
|
690
|
+
`,
|
|
691
|
+
|
|
692
|
+
"acalc://guide/conditional": `# 条件表达式和运算符
|
|
693
|
+
|
|
694
|
+
## 条件表达式
|
|
695
|
+
|
|
696
|
+
a-calc 支持三元条件表达式:
|
|
697
|
+
|
|
698
|
+
\`\`\`javascript
|
|
699
|
+
calc("score >= 60 ? '及格' : '不及格'", {score: 75}) // "及格"
|
|
700
|
+
calc("age >= 18 ? 'adult' : 'minor'", {age: 20}) // "adult"
|
|
701
|
+
\`\`\`
|
|
702
|
+
|
|
703
|
+
## 比较运算符
|
|
704
|
+
|
|
705
|
+
- \`>\` - 大于
|
|
706
|
+
- \`<\` - 小于
|
|
707
|
+
- \`>=\` - 大于等于
|
|
708
|
+
- \`<=\` - 小于等于
|
|
709
|
+
- \`==\` - 等于
|
|
710
|
+
- \`!=\` - 不等于
|
|
711
|
+
|
|
712
|
+
**示例:**
|
|
713
|
+
\`\`\`javascript
|
|
714
|
+
calc("10 > 5") // "1" (true)
|
|
715
|
+
calc("10 < 5") // "0" (false)
|
|
716
|
+
calc("10 == 10") // "1"
|
|
717
|
+
calc("10 != 5") // "1"
|
|
718
|
+
\`\`\`
|
|
719
|
+
|
|
720
|
+
## 逻辑运算符
|
|
721
|
+
|
|
722
|
+
- \`&&\` - 逻辑与
|
|
723
|
+
- \`||\` - 逻辑或
|
|
724
|
+
- \`!\` - 逻辑非
|
|
725
|
+
|
|
726
|
+
**示例:**
|
|
727
|
+
\`\`\`javascript
|
|
728
|
+
calc("(10 > 5) && (20 > 10)") // "1" (true)
|
|
729
|
+
calc("(10 > 5) || (20 < 10)") // "1" (true)
|
|
730
|
+
calc("!(10 > 5)") // "0" (false)
|
|
731
|
+
\`\`\`
|
|
732
|
+
|
|
733
|
+
## 链式比较
|
|
734
|
+
|
|
735
|
+
a-calc 支持链式比较表达式:
|
|
736
|
+
|
|
737
|
+
\`\`\`javascript
|
|
738
|
+
calc("1 < x < 10", {x: 5}) // "1" (true)
|
|
739
|
+
calc("0 <= score <= 100", {score: 85}) // "1" (true)
|
|
740
|
+
\`\`\`
|
|
741
|
+
|
|
742
|
+
## 复杂条件
|
|
743
|
+
|
|
744
|
+
可以组合使用条件和逻辑运算:
|
|
745
|
+
|
|
746
|
+
\`\`\`javascript
|
|
747
|
+
calc("(score >= 90) ? 'A' : (score >= 80) ? 'B' : (score >= 60) ? 'C' : 'D'", {score: 85})
|
|
748
|
+
// "B"
|
|
749
|
+
|
|
750
|
+
calc("(age >= 18 && hasLicense) ? 'can drive' : 'cannot drive'", {
|
|
751
|
+
age: 20,
|
|
752
|
+
hasLicense: 1
|
|
753
|
+
}) // "can drive"
|
|
754
|
+
\`\`\`
|
|
755
|
+
`,
|
|
756
|
+
|
|
757
|
+
"acalc://examples/common": `# 常见使用示例
|
|
758
|
+
|
|
759
|
+
## 金融计算
|
|
760
|
+
|
|
761
|
+
### 价格计算
|
|
762
|
+
\`\`\`javascript
|
|
763
|
+
// 含税价格 - 如果有 product 对象包含 price 和 taxRate
|
|
764
|
+
const product = {price: 100, taxRate: 0.13}
|
|
765
|
+
calc("price * (1 + taxRate) | =2", product) // "113.00"
|
|
766
|
+
|
|
767
|
+
// 折扣价格 - 直接传入商品对象
|
|
768
|
+
const item = {price: 199.9, discount: 0.8}
|
|
769
|
+
calc("price * discount | =2", item) // "159.92"
|
|
770
|
+
|
|
771
|
+
// 订单总价 - 直接传入订单对象
|
|
772
|
+
const order = {price: 99.9, qty: 3, shipping: 15}
|
|
773
|
+
calc("price * qty + shipping | =2,", order) // "314.70"
|
|
774
|
+
\`\`\`
|
|
775
|
+
|
|
776
|
+
### 利率计算
|
|
777
|
+
\`\`\`javascript
|
|
778
|
+
// 单利 - 直接传入投资对象
|
|
779
|
+
const investment = {principal: 10000, rate: 0.05, time: 2}
|
|
780
|
+
calc("principal * rate * time | =2", investment) // "1000.00"
|
|
781
|
+
|
|
782
|
+
// 复利
|
|
783
|
+
calc("principal * pow(1 + rate, time) - principal | =2", investment) // "1025.00"
|
|
784
|
+
\`\`\`
|
|
785
|
+
|
|
786
|
+
## 电商场景
|
|
787
|
+
|
|
788
|
+
### 购物车计算
|
|
789
|
+
\`\`\`javascript
|
|
790
|
+
const items = [
|
|
791
|
+
{price: 99.9, qty: 2},
|
|
792
|
+
{price: 49.9, qty: 3},
|
|
793
|
+
{price: 199, qty: 1}
|
|
794
|
+
]
|
|
795
|
+
|
|
796
|
+
calc_sum("price * qty | =2", items) // "548.50"
|
|
797
|
+
\`\`\`
|
|
798
|
+
|
|
799
|
+
### 优惠券计算
|
|
800
|
+
\`\`\`javascript
|
|
801
|
+
const cart = {total: 250}
|
|
802
|
+
calc("total > 200 ? total * 0.9 : total | =2", cart) // "225.00"
|
|
803
|
+
\`\`\`
|
|
804
|
+
|
|
805
|
+
## 数据格式化
|
|
806
|
+
|
|
807
|
+
### 金额显示
|
|
808
|
+
\`\`\`javascript
|
|
809
|
+
fmt(1234567.89, ",=2") // "1,234,567.89"
|
|
810
|
+
fmt(1234567, "!v") // "1.23M"
|
|
811
|
+
\`\`\`
|
|
812
|
+
|
|
813
|
+
### 百分比显示
|
|
814
|
+
\`\`\`javascript
|
|
815
|
+
fmt(0.1234, "%=2") // "12.34%"
|
|
816
|
+
fmt(0.0523, "%=2+") // "+5.23%" (涨跌幅)
|
|
817
|
+
\`\`\`
|
|
818
|
+
|
|
819
|
+
### 科学计数法
|
|
820
|
+
\`\`\`javascript
|
|
821
|
+
fmt(123456789, "!e=2") // "1.23e+8"
|
|
822
|
+
\`\`\`
|
|
823
|
+
|
|
824
|
+
## 统计计算
|
|
825
|
+
|
|
826
|
+
### 平均值
|
|
827
|
+
\`\`\`javascript
|
|
828
|
+
const values = [10, 20, 30, 40, 50]
|
|
829
|
+
const sum = add(...values) // 150
|
|
830
|
+
const avg = div(sum, values.length) // 30
|
|
831
|
+
\`\`\`
|
|
832
|
+
|
|
833
|
+
### 标准差
|
|
834
|
+
\`\`\`javascript
|
|
835
|
+
import { add, div, sqrt, sub, mul } from 'a-calc'
|
|
836
|
+
|
|
837
|
+
const values = [10, 20, 30, 40, 50]
|
|
838
|
+
const avg = 30
|
|
839
|
+
const variance = div(
|
|
840
|
+
add(...values.map(v => mul(sub(v, avg), sub(v, avg)))),
|
|
841
|
+
values.length
|
|
842
|
+
) // 200
|
|
843
|
+
const stdDev = sqrt(variance) // 14.142...
|
|
844
|
+
\`\`\`
|
|
845
|
+
|
|
846
|
+
## 单位计算
|
|
847
|
+
|
|
848
|
+
### 带单位的计算
|
|
849
|
+
\`\`\`javascript
|
|
850
|
+
calc("100元 + 50元", {_unit: true}) // "150元"
|
|
851
|
+
calc("10% + 5%", {_unit: true}) // "15%"
|
|
852
|
+
calc("1.5kg * 2", {_unit: true}) // "3kg"
|
|
853
|
+
\`\`\`
|
|
854
|
+
|
|
855
|
+
## 链式计算
|
|
856
|
+
|
|
857
|
+
### 复杂运算
|
|
858
|
+
\`\`\`javascript
|
|
859
|
+
// (100 + 200) * 0.8 - 50
|
|
860
|
+
cadd(100, 200).mul(0.8).sub(50)("=2") // "190.00"
|
|
861
|
+
|
|
862
|
+
// 价格计算链
|
|
863
|
+
cmul(99.9, 3) // 单价 * 数量
|
|
864
|
+
.mul(0.9) // 打9折
|
|
865
|
+
.add(15) // 加运费
|
|
866
|
+
("=2,") // "284.73"
|
|
867
|
+
\`\`\`
|
|
868
|
+
`
|
|
869
|
+
};
|
|
870
|
+
|
|
871
|
+
// ==================== Prompts 定义 ====================
|
|
872
|
+
|
|
873
|
+
const PROMPTS = [
|
|
874
|
+
{
|
|
875
|
+
name: "a-calc",
|
|
876
|
+
description: "强制在所有数值计算中使用 a-calc(推荐)",
|
|
877
|
+
arguments: [],
|
|
878
|
+
},
|
|
879
|
+
];
|
|
880
|
+
|
|
881
|
+
const PROMPT_CONTENTS = {
|
|
882
|
+
"a-calc": {
|
|
883
|
+
messages: [
|
|
884
|
+
{
|
|
885
|
+
role: "user",
|
|
886
|
+
content: {
|
|
887
|
+
type: "text",
|
|
888
|
+
text: `# 数值计算强制规则
|
|
889
|
+
|
|
890
|
+
⚠️ **重要:在本次对话中,所有数值计算必须使用 a-calc MCP 工具!**
|
|
891
|
+
|
|
892
|
+
## 强制使用场景
|
|
893
|
+
|
|
894
|
+
### 1. 任何涉及小数的运算(必须使用)
|
|
895
|
+
- ✅ 使用 calc("0.1 + 0.2")
|
|
896
|
+
- ❌ 不要直接计算 0.1 + 0.2
|
|
897
|
+
|
|
898
|
+
### 2. 价格和金额计算(必须使用)
|
|
899
|
+
- ✅ 使用 calc("price * qty | =2", item) // 直接传入对象
|
|
900
|
+
- ❌ 不要使用 JavaScript 的 * 运算符
|
|
901
|
+
|
|
902
|
+
### 3. 百分比和折扣计算(必须使用)
|
|
903
|
+
- ✅ 使用 calc("price * 0.9 | =2", product) // 直接传入对象
|
|
904
|
+
- ❌ 不要直接计算
|
|
905
|
+
|
|
906
|
+
### 4. 需要格式化的数值(必须使用)
|
|
907
|
+
- ✅ 使用 fmt(1234567, ",") 或 calc("value | ,", data)
|
|
908
|
+
- ❌ 不要使用 toLocaleString()
|
|
909
|
+
|
|
910
|
+
### 5. 批量数据计算(必须使用)
|
|
911
|
+
- ✅ 使用 calc_sum("price * qty", items)
|
|
912
|
+
- ❌ 不要使用 reduce() 或 forEach() 手动累加
|
|
913
|
+
|
|
914
|
+
## 可以不使用的场景
|
|
915
|
+
|
|
916
|
+
只有以下情况可以不使用 a-calc:
|
|
917
|
+
- 简单的整数加减:1 + 1, 10 - 5
|
|
918
|
+
- 数组长度、索引等非计算场景
|
|
919
|
+
|
|
920
|
+
## 为什么必须使用 a-calc?
|
|
921
|
+
|
|
922
|
+
JavaScript 的浮点数精度问题:
|
|
923
|
+
- 0.1 + 0.2 = 0.30000000000000004 ❌
|
|
924
|
+
- 0.3 - 0.1 = 0.19999999999999998 ❌
|
|
925
|
+
- 99.9 * 3 = 299.70000000000005 ❌
|
|
926
|
+
|
|
927
|
+
使用 a-calc 后:
|
|
928
|
+
- calc("0.1 + 0.2") = "0.3" ✅
|
|
929
|
+
- calc("0.3 - 0.1") = "0.2" ✅
|
|
930
|
+
- calc("99.9 * 3") = "299.7" ✅
|
|
931
|
+
|
|
932
|
+
## 编码规范和最佳实践
|
|
933
|
+
|
|
934
|
+
### ❌ 错误写法 1:使用模板字符串拼接
|
|
935
|
+
\`\`\`javascript
|
|
936
|
+
// 不要这样写!
|
|
937
|
+
let total = '0'
|
|
938
|
+
cart.forEach(item => {
|
|
939
|
+
total = calc(\`\${total} + \${item.price} * \${item.quantity}\`)
|
|
940
|
+
})
|
|
941
|
+
\`\`\`
|
|
942
|
+
**问题**:代码不清晰、难以维护、性能差
|
|
943
|
+
|
|
944
|
+
### ❌ 错误写法 2:重复写字段名(冗余)
|
|
945
|
+
\`\`\`javascript
|
|
946
|
+
// 不要这样写!
|
|
947
|
+
const itemTotal = calc("price * qty | =2", {
|
|
948
|
+
price: item.price,
|
|
949
|
+
qty: item.qty
|
|
950
|
+
})
|
|
951
|
+
\`\`\`
|
|
952
|
+
**问题**:代码冗余、不简洁、重复劳动
|
|
953
|
+
|
|
954
|
+
### ✅ 正确写法 1:使用 calc_sum(批量计算)
|
|
955
|
+
\`\`\`javascript
|
|
956
|
+
const total = calc_sum("price * qty | =2", cart)
|
|
957
|
+
\`\`\`
|
|
958
|
+
|
|
959
|
+
### ✅ 正确写法 2:直接传入对象(最优雅)
|
|
960
|
+
\`\`\`javascript
|
|
961
|
+
// 对象已有所需字段,直接传入
|
|
962
|
+
const itemTotal = calc("price * qty | =2", item)
|
|
963
|
+
\`\`\`
|
|
964
|
+
|
|
965
|
+
### ✅ 正确写法 3:使用变量简写
|
|
966
|
+
\`\`\`javascript
|
|
967
|
+
// 多个独立变量,使用简写
|
|
968
|
+
const result = calc("a + b", {a, b})
|
|
969
|
+
\`\`\`
|
|
970
|
+
|
|
971
|
+
### ✅ 正确写法 4:数组映射
|
|
972
|
+
\`\`\`javascript
|
|
973
|
+
// 对每个对象进行计算
|
|
974
|
+
const results = items.map(item => calc("price * qty | =2", item))
|
|
975
|
+
\`\`\`
|
|
976
|
+
|
|
977
|
+
### 完整示例:购物车计算
|
|
978
|
+
|
|
979
|
+
\`\`\`javascript
|
|
980
|
+
import { calc, calc_sum, fmt } from 'a-calc'
|
|
981
|
+
|
|
982
|
+
// ❌ 错误:使用模板字符串累加
|
|
983
|
+
const wrongTotal = () => {
|
|
984
|
+
let total = '0'
|
|
985
|
+
cart.forEach(item => {
|
|
986
|
+
total = calc(\`\${total} + \${item.price} * \${item.quantity}\`)
|
|
987
|
+
})
|
|
988
|
+
return total
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
// ✅ 正确:使用 calc_sum
|
|
992
|
+
const correctTotal = () => {
|
|
993
|
+
return calc_sum("price * quantity | =2", cart)
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// ✅ 正确:单个商品小计(直接传入 item 对象)
|
|
997
|
+
const itemSubtotal = (item) => {
|
|
998
|
+
return calc("price * quantity | =2", item)
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// ✅ 正确:应用折扣(直接传入对象)
|
|
1002
|
+
const applyDiscount = (order) => {
|
|
1003
|
+
return calc("total * (1 - discountRate) | =2", order)
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// ✅ 正确:含税价格(直接传入对象)
|
|
1007
|
+
const withTax = (order) => {
|
|
1008
|
+
return calc("subtotal * (1 + taxRate) | =2", order)
|
|
1009
|
+
}
|
|
1010
|
+
\`\`\`
|
|
1011
|
+
|
|
1012
|
+
## 核心原则
|
|
1013
|
+
|
|
1014
|
+
1. **批量计算用 calc_sum** - 不要用 forEach 累加
|
|
1015
|
+
2. **变量用第二参数注入** - 不要用模板字符串拼接
|
|
1016
|
+
3. **保持表达式简洁** - 一次计算完成,不要分步累加
|
|
1017
|
+
4. **使用格式化** - 用 \`| =2\` 保留小数位
|
|
1018
|
+
|
|
1019
|
+
## 实施要求
|
|
1020
|
+
|
|
1021
|
+
在编写代码时:
|
|
1022
|
+
1. 遇到数值计算,立即考虑是否需要使用 a-calc
|
|
1023
|
+
2. 涉及小数、金额、价格的,必须使用 a-calc
|
|
1024
|
+
3. 优先使用 calc_sum 处理数组数据
|
|
1025
|
+
4. 使用第二参数注入变量,不要用模板字符串
|
|
1026
|
+
5. 在代码注释中说明为什么使用 a-calc
|
|
1027
|
+
|
|
1028
|
+
请确认你理解并将严格遵守这些规则。`,
|
|
1029
|
+
},
|
|
1030
|
+
},
|
|
1031
|
+
],
|
|
1032
|
+
},
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
// ==================== Server Setup ====================
|
|
1036
|
+
|
|
1037
|
+
const server = new Server(
|
|
1038
|
+
{
|
|
1039
|
+
name: "a-calc-mcp-server",
|
|
1040
|
+
version: "1.0.0",
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
capabilities: {
|
|
1044
|
+
tools: {},
|
|
1045
|
+
resources: {},
|
|
1046
|
+
prompts: {},
|
|
1047
|
+
},
|
|
1048
|
+
}
|
|
1049
|
+
);
|
|
1050
|
+
|
|
1051
|
+
// ==================== Tool Handlers ====================
|
|
1052
|
+
|
|
1053
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
1054
|
+
return { tools: TOOLS };
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
1058
|
+
const { name, arguments: args } = request.params;
|
|
1059
|
+
|
|
1060
|
+
try {
|
|
1061
|
+
switch (name) {
|
|
1062
|
+
case "calc": {
|
|
1063
|
+
const { expr, options = {} } = args;
|
|
1064
|
+
const result = calc(expr, options);
|
|
1065
|
+
return {
|
|
1066
|
+
content: [
|
|
1067
|
+
{
|
|
1068
|
+
type: "text",
|
|
1069
|
+
text: JSON.stringify({ result, type: typeof result }),
|
|
1070
|
+
},
|
|
1071
|
+
],
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
case "fmt": {
|
|
1076
|
+
const { value, format_str, options = {} } = args;
|
|
1077
|
+
const result = fmt(value, format_str, options);
|
|
1078
|
+
return {
|
|
1079
|
+
content: [
|
|
1080
|
+
{
|
|
1081
|
+
type: "text",
|
|
1082
|
+
text: JSON.stringify({ result, type: typeof result }),
|
|
1083
|
+
},
|
|
1084
|
+
],
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
case "calc_sum": {
|
|
1089
|
+
const { expr, data_array } = args;
|
|
1090
|
+
const result = calc_sum(expr, data_array);
|
|
1091
|
+
return {
|
|
1092
|
+
content: [
|
|
1093
|
+
{
|
|
1094
|
+
type: "text",
|
|
1095
|
+
text: JSON.stringify({ result, type: typeof result }),
|
|
1096
|
+
},
|
|
1097
|
+
],
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
case "basic_calc": {
|
|
1102
|
+
const { operation, args: calcArgs } = args;
|
|
1103
|
+
let result;
|
|
1104
|
+
|
|
1105
|
+
switch (operation) {
|
|
1106
|
+
case "add":
|
|
1107
|
+
result = add(...calcArgs);
|
|
1108
|
+
break;
|
|
1109
|
+
case "sub":
|
|
1110
|
+
result = sub(...calcArgs);
|
|
1111
|
+
break;
|
|
1112
|
+
case "mul":
|
|
1113
|
+
result = mul(...calcArgs);
|
|
1114
|
+
break;
|
|
1115
|
+
case "div":
|
|
1116
|
+
result = div(...calcArgs);
|
|
1117
|
+
break;
|
|
1118
|
+
case "mod":
|
|
1119
|
+
result = mod(...calcArgs);
|
|
1120
|
+
break;
|
|
1121
|
+
case "pow":
|
|
1122
|
+
result = pow(...calcArgs);
|
|
1123
|
+
break;
|
|
1124
|
+
case "idiv":
|
|
1125
|
+
result = idiv(...calcArgs);
|
|
1126
|
+
break;
|
|
1127
|
+
case "abs":
|
|
1128
|
+
result = abs(calcArgs[0]);
|
|
1129
|
+
break;
|
|
1130
|
+
case "neg":
|
|
1131
|
+
result = neg(calcArgs[0]);
|
|
1132
|
+
break;
|
|
1133
|
+
case "sqrt":
|
|
1134
|
+
result = sqrt(calcArgs[0]);
|
|
1135
|
+
break;
|
|
1136
|
+
case "ln":
|
|
1137
|
+
result = ln(calcArgs[0]);
|
|
1138
|
+
break;
|
|
1139
|
+
case "exp":
|
|
1140
|
+
result = exp(calcArgs[0]);
|
|
1141
|
+
break;
|
|
1142
|
+
default:
|
|
1143
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
return {
|
|
1147
|
+
content: [
|
|
1148
|
+
{
|
|
1149
|
+
type: "text",
|
|
1150
|
+
text: JSON.stringify({ result, type: typeof result }),
|
|
1151
|
+
},
|
|
1152
|
+
],
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
case "chain_calc": {
|
|
1157
|
+
const { start_op, start_args, chain_ops = [], format } = args;
|
|
1158
|
+
|
|
1159
|
+
let chainFn;
|
|
1160
|
+
switch (start_op) {
|
|
1161
|
+
case "cadd":
|
|
1162
|
+
chainFn = cadd(...start_args);
|
|
1163
|
+
break;
|
|
1164
|
+
case "csub":
|
|
1165
|
+
chainFn = csub(...start_args);
|
|
1166
|
+
break;
|
|
1167
|
+
case "cmul":
|
|
1168
|
+
chainFn = cmul(...start_args);
|
|
1169
|
+
break;
|
|
1170
|
+
case "cdiv":
|
|
1171
|
+
chainFn = cdiv(...start_args);
|
|
1172
|
+
break;
|
|
1173
|
+
default:
|
|
1174
|
+
throw new Error(`Unknown start operation: ${start_op}`);
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
for (const { op, args: opArgs } of chain_ops) {
|
|
1178
|
+
switch (op) {
|
|
1179
|
+
case "add":
|
|
1180
|
+
chainFn = chainFn.add(...opArgs);
|
|
1181
|
+
break;
|
|
1182
|
+
case "sub":
|
|
1183
|
+
chainFn = chainFn.sub(...opArgs);
|
|
1184
|
+
break;
|
|
1185
|
+
case "mul":
|
|
1186
|
+
chainFn = chainFn.mul(...opArgs);
|
|
1187
|
+
break;
|
|
1188
|
+
case "div":
|
|
1189
|
+
chainFn = chainFn.div(...opArgs);
|
|
1190
|
+
break;
|
|
1191
|
+
case "mod":
|
|
1192
|
+
chainFn = chainFn.mod(...opArgs);
|
|
1193
|
+
break;
|
|
1194
|
+
case "pow":
|
|
1195
|
+
chainFn = chainFn.pow(...opArgs);
|
|
1196
|
+
break;
|
|
1197
|
+
case "idiv":
|
|
1198
|
+
chainFn = chainFn.idiv(...opArgs);
|
|
1199
|
+
break;
|
|
1200
|
+
default:
|
|
1201
|
+
throw new Error(`Unknown chain operation: ${op}`);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
const result = format ? chainFn(format) : chainFn();
|
|
1206
|
+
return {
|
|
1207
|
+
content: [
|
|
1208
|
+
{
|
|
1209
|
+
type: "text",
|
|
1210
|
+
text: JSON.stringify({ result, type: typeof result }),
|
|
1211
|
+
},
|
|
1212
|
+
],
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
case "get_acalc_guide": {
|
|
1217
|
+
const { topic } = args;
|
|
1218
|
+
let content = "";
|
|
1219
|
+
|
|
1220
|
+
if (topic === "all") {
|
|
1221
|
+
content = Object.values(RESOURCE_CONTENTS).join("\n\n---\n\n");
|
|
1222
|
+
} else {
|
|
1223
|
+
const resourceMap = {
|
|
1224
|
+
api: "acalc://api/overview",
|
|
1225
|
+
formatting: "acalc://guide/formatting",
|
|
1226
|
+
functions: "acalc://guide/functions",
|
|
1227
|
+
conditional: "acalc://guide/conditional",
|
|
1228
|
+
chain: "acalc://api/overview",
|
|
1229
|
+
examples: "acalc://examples/common",
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
const uri = resourceMap[topic];
|
|
1233
|
+
if (uri && RESOURCE_CONTENTS[uri]) {
|
|
1234
|
+
content = RESOURCE_CONTENTS[uri];
|
|
1235
|
+
} else {
|
|
1236
|
+
throw new Error(`Unknown topic: ${topic}`);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
return {
|
|
1241
|
+
content: [
|
|
1242
|
+
{
|
|
1243
|
+
type: "text",
|
|
1244
|
+
text: content,
|
|
1245
|
+
},
|
|
1246
|
+
],
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
case "debug_info": {
|
|
1251
|
+
const debugInfo = {
|
|
1252
|
+
cwd: process.cwd(),
|
|
1253
|
+
__dirname: import.meta.url,
|
|
1254
|
+
node_version: process.version,
|
|
1255
|
+
platform: process.platform,
|
|
1256
|
+
arch: process.arch,
|
|
1257
|
+
env: {
|
|
1258
|
+
HOME: process.env.HOME,
|
|
1259
|
+
USERPROFILE: process.env.USERPROFILE,
|
|
1260
|
+
PATH: process.env.PATH?.split(process.platform === 'win32' ? ';' : ':').slice(0, 5).join('\n '),
|
|
1261
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
1262
|
+
},
|
|
1263
|
+
};
|
|
1264
|
+
|
|
1265
|
+
return {
|
|
1266
|
+
content: [
|
|
1267
|
+
{
|
|
1268
|
+
type: "text",
|
|
1269
|
+
text: JSON.stringify(debugInfo, null, 2),
|
|
1270
|
+
},
|
|
1271
|
+
],
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
default:
|
|
1276
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
1277
|
+
}
|
|
1278
|
+
} catch (error) {
|
|
1279
|
+
return {
|
|
1280
|
+
content: [
|
|
1281
|
+
{
|
|
1282
|
+
type: "text",
|
|
1283
|
+
text: JSON.stringify({
|
|
1284
|
+
error: error.message,
|
|
1285
|
+
stack: error.stack,
|
|
1286
|
+
}),
|
|
1287
|
+
},
|
|
1288
|
+
],
|
|
1289
|
+
isError: true,
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
// ==================== Resource Handlers ====================
|
|
1295
|
+
|
|
1296
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
1297
|
+
return { resources: RESOURCES };
|
|
1298
|
+
});
|
|
1299
|
+
|
|
1300
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
1301
|
+
const { uri } = request.params;
|
|
1302
|
+
|
|
1303
|
+
if (RESOURCE_CONTENTS[uri]) {
|
|
1304
|
+
return {
|
|
1305
|
+
contents: [
|
|
1306
|
+
{
|
|
1307
|
+
uri,
|
|
1308
|
+
mimeType: "text/markdown",
|
|
1309
|
+
text: RESOURCE_CONTENTS[uri],
|
|
1310
|
+
},
|
|
1311
|
+
],
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
throw new Error(`Resource not found: ${uri}`);
|
|
1316
|
+
});
|
|
1317
|
+
|
|
1318
|
+
// ==================== Prompt Handlers ====================
|
|
1319
|
+
|
|
1320
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
1321
|
+
return { prompts: PROMPTS };
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
1325
|
+
const { name } = request.params;
|
|
1326
|
+
|
|
1327
|
+
if (PROMPT_CONTENTS[name]) {
|
|
1328
|
+
return PROMPT_CONTENTS[name];
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
throw new Error(`Prompt not found: ${name}`);
|
|
1332
|
+
});
|
|
1333
|
+
|
|
1334
|
+
// ==================== Start Server ====================
|
|
1335
|
+
|
|
1336
|
+
async function main() {
|
|
1337
|
+
// 解析命令行参数
|
|
1338
|
+
const args = process.argv.slice(2);
|
|
1339
|
+
const cwdIndex = args.indexOf('--cwd');
|
|
1340
|
+
|
|
1341
|
+
if (cwdIndex !== -1 && args[cwdIndex + 1]) {
|
|
1342
|
+
const targetCwd = args[cwdIndex + 1];
|
|
1343
|
+
try {
|
|
1344
|
+
process.chdir(targetCwd);
|
|
1345
|
+
console.error(`Changed working directory to: ${process.cwd()}`);
|
|
1346
|
+
} catch (error) {
|
|
1347
|
+
console.error(`Failed to change directory to ${targetCwd}:`, error.message);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
const transport = new StdioServerTransport();
|
|
1352
|
+
await server.connect(transport);
|
|
1353
|
+
console.error("a-calc MCP Server running on stdio");
|
|
1354
|
+
console.error(`Working directory: ${process.cwd()}`);
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
main().catch((error) => {
|
|
1358
|
+
console.error("Fatal error:", error);
|
|
1359
|
+
process.exit(1);
|
|
1360
|
+
});
|