cli-blueprint 0.1.0 → 0.2.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 +34 -17
- package/install.mjs +148 -7
- package/package.json +2 -2
- package/skills/blueprint/SKILL.md +33 -25
- package/skills/blueprint/install-meta.json +7 -0
- package/skills/calctool/SKILL.md +167 -0
- package/skills/calctool/install-meta.json +7 -0
- package/skills/calctool/platform-template/README.md +74 -0
- package/skills/calctool/platform-template/index.html +12 -0
- package/skills/calctool/platform-template/package.json +26 -0
- package/skills/calctool/platform-template/src/App.tsx +233 -0
- package/skills/calctool/platform-template/src/authz.ts +103 -0
- package/skills/calctool/platform-template/src/engine/evaluate.ts +114 -0
- package/skills/calctool/platform-template/src/engine-definition.json +195 -0
- package/skills/calctool/platform-template/src/main.tsx +13 -0
- package/skills/calctool/platform-template/src/pipeline.ts +80 -0
- package/skills/calctool/platform-template/src/store.ts +53 -0
- package/skills/calctool/platform-template/tsconfig.json +15 -0
- package/skills/calctool/platform-template/vite.config.ts +7 -0
- package/skills/calctool/references/declarative-pages.md +69 -0
- package/skills/calctool/references/engine-meta-model.md +123 -0
- package/skills/calctool/references/finance-example.md +132 -0
- package/skills/calctool/references/formula-dsl.md +92 -0
- package/skills/calctool/references/import-ocr.md +72 -0
- package/skills/calctool/skill.json +10 -0
- package/skills/calctool/templates/ecommerce-ops/README.md +27 -0
- package/skills/calctool/templates/ecommerce-ops/domain-reference.yaml +172 -0
- package/sources.json +8 -1
package/README.md
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# cli-blueprint
|
|
2
2
|
|
|
3
|
-
**多
|
|
3
|
+
**多 skill 多 IDE 安装器** —— 一条命令从 cli.tax 拉取并分发到本机所有已装 IDE,可无限扩展。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
```bash
|
|
6
|
+
npx cli-blueprint@latest install
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
默认包含:
|
|
10
|
+
- `blueprint`(CLI.Tax 工程规划 skill,`https://cli.tax/wvz6zmRWmX`)
|
|
11
|
+
- `calctool`(万能计算工具生成器,`https://cli.tax/VjFfeR6wdB`)
|
|
6
12
|
|
|
7
13
|
## 这是什么机制?
|
|
8
14
|
|
|
@@ -72,34 +78,45 @@ node install.mjs uninstall # 从相同目标卸载本包安装的 skill
|
|
|
72
78
|
|
|
73
79
|
## 分发给别人
|
|
74
80
|
|
|
75
|
-
### 方式 A:
|
|
76
|
-
|
|
81
|
+
### 方式 A:npm 一条命令(推荐,最简单)
|
|
82
|
+
已发布到 npm(`cli-blueprint@0.1.0` / `cli-calctool@0.1.0`),使用者只需:
|
|
83
|
+
```bash
|
|
84
|
+
npx cli-blueprint@latest install # 装 blueprint + calctool 两个 skill
|
|
85
|
+
npx cli-calctool@latest install # 同样内容(calctool 命名入口)
|
|
86
|
+
```
|
|
87
|
+
自动完成:从 cli.tax 拉取 blueprint + calctool → 检测本机已装 IDE → 分发到每个 IDE。
|
|
88
|
+
更新:同一命令(`@latest` 自动拉新版),且每次 install 会对比 cli.tax 最新版本并提示 ⤴。
|
|
89
|
+
|
|
90
|
+
### 方式 B:Git 仓库
|
|
77
91
|
```bash
|
|
78
|
-
git clone
|
|
92
|
+
git clone https://github.com/88208555/Blueprint-clitax.git
|
|
93
|
+
cd Blueprint-clitax
|
|
94
|
+
node install.mjs install
|
|
79
95
|
```
|
|
80
|
-
更新:`git pull && node install.mjs update
|
|
96
|
+
更新:`git pull && node install.mjs update`(install/update 会对比已装版本与 cli.tax 最新版本并提示)。
|
|
81
97
|
|
|
82
|
-
###
|
|
83
|
-
|
|
98
|
+
### 更新感知(check)
|
|
99
|
+
安装器写入 `install-meta.json`(来源/版本/时间)到每个 skill 目录;SKILL.md 注入版本横幅,
|
|
100
|
+
IDE 每次读取即可见版本与更新入口。主动检查:
|
|
84
101
|
```bash
|
|
85
|
-
|
|
102
|
+
node install.mjs check # 遍历本机已装 IDE,对比 cli.tax 最新版本
|
|
103
|
+
npx cli-blueprint@latest check # 单包检查(calctool 同理)
|
|
86
104
|
```
|
|
87
|
-
更新:同一命令(`@latest` 自动拉新版)。
|
|
88
|
-
> 注意 npm 官方源对包名唯一性有要求;内部使用可部署私有 registry(如 Verdaccio)。
|
|
89
105
|
|
|
90
|
-
### 方式 C:直接用 clitaxio
|
|
106
|
+
### 方式 C:直接用 clitaxio(只装单个 IDE,作为对照)
|
|
91
107
|
```bash
|
|
92
|
-
npx clitaxio@latest install
|
|
108
|
+
npx clitaxio@latest install wvz6zmRWmX
|
|
93
109
|
```
|
|
94
|
-
|
|
110
|
+
> ⚠️ 注意:clitaxio **只把 skill 装到默认的 Codex 目录**(单一 IDE),不会自动检测/分发到
|
|
111
|
+
> 其他 IDE,也不处理 `~/.agents/skills` 共享根重复问题。需要多 IDE 分发请用方式 A/B。
|
|
95
112
|
|
|
96
113
|
## 目录结构
|
|
97
114
|
|
|
98
115
|
```
|
|
99
|
-
|
|
116
|
+
cli-blueprint/
|
|
100
117
|
├── install.mjs # 安装器(Node ≥18,零依赖):pull / install / uninstall / list / ides
|
|
101
118
|
├── sources.json # ★ cli.tax skill 源清单(code → 自动拉取),扩展就加一行
|
|
102
|
-
├── package.json # npm
|
|
119
|
+
├── package.json # npm 包元数据(cli-blueprint)
|
|
103
120
|
├── README.md
|
|
104
121
|
└── skills/ # skill 内容(pull 生成,可提交 git 离线兜底)
|
|
105
122
|
└── blueprint/
|
package/install.mjs
CHANGED
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
* 需要时用 --agents 显式开启(会打印警告);
|
|
16
16
|
* - --ide / --skip 精确控制;新增 IDE 只需在 IDES 表加一行。
|
|
17
17
|
*
|
|
18
|
+
* 更新感知:
|
|
19
|
+
* - pull 时把 cli.tax 返回的 version 写入 skills/<slug>/install-meta.json;
|
|
20
|
+
* - install / update 时对比「已安装版本」与「远端最新版本」,有新版本会提示;
|
|
21
|
+
* - check 子命令:遍历本机已装 IDE 的 skill 目录,对比远端最新版本并报告更新。
|
|
22
|
+
*
|
|
18
23
|
* 用法:
|
|
19
24
|
* node install.mjs pull # 从 sources.json(cli.tax)拉取全部 skill 到 skills/
|
|
20
25
|
* node install.mjs install # 自动匹配:只装本机已安装的 IDE(推荐)
|
|
@@ -26,6 +31,7 @@
|
|
|
26
31
|
* node install.mjs install --agents # 额外安装到共享 ~/.agents/skills(警告)
|
|
27
32
|
* node install.mjs install --target /abs/path # 仅自定义目录
|
|
28
33
|
* node install.mjs update # 同 install(幂等覆盖)
|
|
34
|
+
* node install.mjs check # 检查已安装 skill 是否有新版本(对比 cli.tax)
|
|
29
35
|
* node install.mjs uninstall # 从相同目标移除本包安装的 skills
|
|
30
36
|
* node install.mjs list # 列出本包包含的 skills
|
|
31
37
|
* node install.mjs ides # 列出已知 IDE 及本机检测结果
|
|
@@ -45,6 +51,9 @@ const SKILLS_SRC = join(__dirname, 'skills')
|
|
|
45
51
|
const HOME = homedir()
|
|
46
52
|
const CWD = process.cwd()
|
|
47
53
|
|
|
54
|
+
/** 每个 skill 安装/拉取时的版本元数据文件名(IDE 目录与 skills/ 内都会写) */
|
|
55
|
+
const INSTALL_META = 'install-meta.json'
|
|
56
|
+
|
|
48
57
|
/**
|
|
49
58
|
* 全世界已知 IDE/编码 agent 的 skills 安装位置表(官方文档核实,2026-08)。
|
|
50
59
|
* key: 命令行标识
|
|
@@ -126,14 +135,37 @@ async function syncOne(name, targetRoot, { remove = false } = {}) {
|
|
|
126
135
|
return
|
|
127
136
|
}
|
|
128
137
|
await mkdir(dest, { recursive: true })
|
|
129
|
-
|
|
130
|
-
|
|
138
|
+
const sourceDir = join(SKILLS_SRC, name)
|
|
139
|
+
const destMeta = readMeta(dest) // 覆盖前读取旧版本
|
|
140
|
+
await cp(sourceDir, dest, { recursive: true, force: true })
|
|
141
|
+
const srcMeta = readMeta(sourceDir)
|
|
142
|
+
// 安装时注入版本横幅到 SKILL.md(IDE 每次读取即见版本与更新入口)
|
|
143
|
+
if (srcMeta?.version) {
|
|
144
|
+
const installedSkillMd = readFileSync(join(dest, 'SKILL.md'), 'utf8')
|
|
145
|
+
await writeFile(join(dest, 'SKILL.md'), injectVersionBanner(installedSkillMd, srcMeta.version, name))
|
|
146
|
+
}
|
|
147
|
+
if (srcMeta) {
|
|
148
|
+
await writeMeta(dest, { ...srcMeta, installedAt: new Date().toISOString() })
|
|
149
|
+
}
|
|
150
|
+
const upgrade = destMeta && srcMeta && destMeta.version && srcMeta.version && destMeta.version !== srcMeta.version
|
|
151
|
+
if (upgrade) {
|
|
152
|
+
print(` ⤴ 已更新 ${name} ${destMeta.version} → ${srcMeta.version} → ${dest}`)
|
|
153
|
+
} else {
|
|
154
|
+
print(` ✓ 已安装 ${name} → ${dest}${srcMeta?.version ? `(${srcMeta.version})` : ''}`)
|
|
155
|
+
}
|
|
131
156
|
}
|
|
132
157
|
|
|
133
|
-
async function syncAll(targetRoot, { remove = false } = {}) {
|
|
158
|
+
async function syncAll(targetRoot, { remove = false, reportUpdated } = {}) {
|
|
134
159
|
const skills = await listSkills()
|
|
135
160
|
if (!remove) await mkdir(targetRoot, { recursive: true })
|
|
136
|
-
for (const s of skills)
|
|
161
|
+
for (const s of skills) {
|
|
162
|
+
const before = reportUpdated ? readMeta(join(targetRoot, s)) : null
|
|
163
|
+
await syncOne(s, targetRoot, { remove })
|
|
164
|
+
if (reportUpdated && before && before.version) {
|
|
165
|
+
const after = readMeta(join(targetRoot, s))
|
|
166
|
+
if (after && after.version && after.version !== before.version) reportUpdated(1)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
137
169
|
}
|
|
138
170
|
|
|
139
171
|
/** 解析目标列表:--target / --ide / --skip / 默认(全部已知 IDE) */
|
|
@@ -202,6 +234,31 @@ function parseTargets(args) {
|
|
|
202
234
|
|
|
203
235
|
const [cmd, ...rest] = process.argv.slice(2)
|
|
204
236
|
|
|
237
|
+
/** 读取 skill 目录的 install-meta.json(没有则返回 null) */
|
|
238
|
+
function readMeta(skillDir) {
|
|
239
|
+
const p = join(skillDir, INSTALL_META)
|
|
240
|
+
if (!existsSync(p)) return null
|
|
241
|
+
try { return JSON.parse(readFileSync(p, 'utf8')) } catch { return null }
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** 写入 skill 目录的 install-meta.json(来源/版本/时间/地址) */
|
|
245
|
+
async function writeMeta(skillDir, meta) {
|
|
246
|
+
await writeFile(join(skillDir, INSTALL_META), `${JSON.stringify(meta, null, 2)}\n`)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** 在 SKILL.md frontmatter 之后注入版本横幅:IDE 每次读取即见版本与更新命令 */
|
|
250
|
+
function injectVersionBanner(skillMd, version, slug) {
|
|
251
|
+
if (!skillMd || !version) return skillMd
|
|
252
|
+
const banner = `<!-- calctool-installer: version ${version} · 检查更新见 install-meta.json / npx cli-${slug}@latest check -->\n`
|
|
253
|
+
if (skillMd.startsWith('---')) {
|
|
254
|
+
const end = skillMd.indexOf('\n---', 3)
|
|
255
|
+
if (end !== -1) {
|
|
256
|
+
return `${skillMd.slice(0, end + 5)}\n\n${banner}${skillMd.slice(end + 5).replace(/^\n+/, '')}`
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return `${banner}${skillMd}`
|
|
260
|
+
}
|
|
261
|
+
|
|
205
262
|
/** 从 cli.tax 拉取一个 skill 到 skills/<slug>/(覆盖本地副本) */
|
|
206
263
|
async function pullSkill(source) {
|
|
207
264
|
const url = source.endpoint.replace('{code}', source.code)
|
|
@@ -215,10 +272,83 @@ async function pullSkill(source) {
|
|
|
215
272
|
await mkdir(dir, { recursive: true })
|
|
216
273
|
await writeFile(join(dir, 'SKILL.md'), data.skillMd)
|
|
217
274
|
await writeFile(join(dir, 'skill.json'), data.skillJson)
|
|
218
|
-
|
|
275
|
+
const previous = readMeta(dir)
|
|
276
|
+
await writeMeta(dir, {
|
|
277
|
+
source: source.code,
|
|
278
|
+
slug: data.slug || source.slug,
|
|
279
|
+
version: data.version ?? '',
|
|
280
|
+
endpoint: url,
|
|
281
|
+
installedAt: new Date().toISOString(),
|
|
282
|
+
})
|
|
283
|
+
const changed = previous && previous.version && previous.version !== data.version
|
|
284
|
+
if (changed) {
|
|
285
|
+
print(` ⤴ 已更新 ${data.displayName} ${previous.version} → ${data.version ?? ''} → skills/${data.slug}/`)
|
|
286
|
+
} else {
|
|
287
|
+
print(` ✓ 已拉取 ${data.displayName} ${data.version ?? ''} → skills/${data.slug}/`)
|
|
288
|
+
}
|
|
219
289
|
return true
|
|
220
290
|
}
|
|
221
291
|
|
|
292
|
+
/** 从 cli.tax 拉取单个 skill 的最新元数据(check 用,不写盘) */
|
|
293
|
+
async function fetchLatestMeta(source) {
|
|
294
|
+
const url = source.endpoint.replace('{code}', source.code)
|
|
295
|
+
try {
|
|
296
|
+
const resp = await fetch(url)
|
|
297
|
+
if (!resp.ok) return null
|
|
298
|
+
const data = await resp.json()
|
|
299
|
+
return {
|
|
300
|
+
source: source.code,
|
|
301
|
+
slug: data.slug || source.slug,
|
|
302
|
+
version: data.version ?? '',
|
|
303
|
+
displayName: data.displayName ?? data.slug ?? source.slug,
|
|
304
|
+
endpoint: url,
|
|
305
|
+
}
|
|
306
|
+
} catch {
|
|
307
|
+
return null
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** check:遍历已安装目标的 skill 目录,对比远端最新版本,报告更新 */
|
|
312
|
+
async function checkUpdates(targets) {
|
|
313
|
+
const sources = loadSources()
|
|
314
|
+
if (!sources.length) {
|
|
315
|
+
print('⚠ sources.json 无源,无法检查更新。')
|
|
316
|
+
return 1
|
|
317
|
+
}
|
|
318
|
+
let found = 0
|
|
319
|
+
for (const t of targets) {
|
|
320
|
+
print(`[${t.label}] ${t.path}`)
|
|
321
|
+
if (!existsSync(t.path)) { print(' · 未安装'); continue }
|
|
322
|
+
const entries = (await readdir(t.path, { withFileTypes: true }).catch(() => []))
|
|
323
|
+
.filter((e) => e.isDirectory())
|
|
324
|
+
if (!entries.length) { print(' · 无已安装 skill'); continue }
|
|
325
|
+
for (const e of entries) {
|
|
326
|
+
const skillDir = join(t.path, e.name)
|
|
327
|
+
const local = readMeta(skillDir)
|
|
328
|
+
const source = sources.find((s) => (s.slug === e.name)
|
|
329
|
+
|| (local && local.source === s.code))
|
|
330
|
+
if (!source) continue
|
|
331
|
+
const remote = await fetchLatestMeta(source)
|
|
332
|
+
if (!remote) { print(` · ${e.name}:远端查询失败,跳过`); continue }
|
|
333
|
+
if (!local || !local.version) {
|
|
334
|
+
print(` · ${e.name}:本地无版本记录(旧安装),远端最新 ${remote.version} —— 运行 install 补齐`)
|
|
335
|
+
found++
|
|
336
|
+
} else if (local.version === remote.version) {
|
|
337
|
+
print(` ✓ ${e.name} 已是最新(${remote.version})`)
|
|
338
|
+
} else {
|
|
339
|
+
print(` ⤴ ${e.name} 有新版本 ${local.version} → ${remote.version} —— 运行 install 更新`)
|
|
340
|
+
found++
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (found) {
|
|
345
|
+
print(`\n发现 ${found} 个 skill 可更新。执行: node install.mjs install`)
|
|
346
|
+
} else {
|
|
347
|
+
print('\n全部已是最新。')
|
|
348
|
+
}
|
|
349
|
+
return 0
|
|
350
|
+
}
|
|
351
|
+
|
|
222
352
|
/** 读取 sources.json 中的源列表 */
|
|
223
353
|
function loadSources() {
|
|
224
354
|
const p = join(__dirname, 'sources.json')
|
|
@@ -269,14 +399,22 @@ if (cmd === 'list') {
|
|
|
269
399
|
if (!skills.length) { print('skills/ 目录为空,无法安装'); process.exit(1) }
|
|
270
400
|
if (rest.includes('--agents') && !targets.some((t) => t.path === AGENTS.path)) targets.push(AGENTS)
|
|
271
401
|
print(`将安装 ${skills.length} 个 skills → ${targets.length} 个目标`)
|
|
402
|
+
let updated = 0
|
|
272
403
|
for (const t of targets) {
|
|
273
404
|
print(`[${t.label}] ${t.path}`)
|
|
274
|
-
await syncAll(t.path)
|
|
405
|
+
await syncAll(t.path, { reportUpdated: (n) => { updated += n } })
|
|
275
406
|
}
|
|
276
407
|
if (rest.includes('--agents')) {
|
|
277
408
|
print('⚠ 已安装到共享 ~/.agents/skills:该目录会被 Codex/Gemini/Zed/OpenCode/Cursor 等同时扫描,同一 skill 可能被重复发现。')
|
|
278
409
|
}
|
|
279
410
|
print('完成。各 IDE 会自动发现各自用户级根中的新目录(可立即在新会话中调用)。')
|
|
411
|
+
if (updated) {
|
|
412
|
+
print(`提示:${updated} 个 skill 有更新。以后可用 node install.mjs check 检查新版本。`)
|
|
413
|
+
}
|
|
414
|
+
} else if (cmd === 'check') {
|
|
415
|
+
const targets = parseTargets(rest)
|
|
416
|
+
if (rest.includes('--agents') && !targets.some((t) => t.path === AGENTS.path)) targets.push(AGENTS)
|
|
417
|
+
process.exitCode = await checkUpdates(targets)
|
|
280
418
|
} else if (cmd === 'uninstall') {
|
|
281
419
|
const targets = parseTargets(rest)
|
|
282
420
|
if (rest.includes('--agents') && !targets.some((t) => t.path === AGENTS.path)) targets.push(AGENTS)
|
|
@@ -290,8 +428,11 @@ if (cmd === 'list') {
|
|
|
290
428
|
node install.mjs install [--all|--ide <key>|--skip <key>|--project|--agents|--pull|--target <dir>]
|
|
291
429
|
node install.mjs pull
|
|
292
430
|
node install.mjs update
|
|
431
|
+
node install.mjs check
|
|
293
432
|
node install.mjs uninstall
|
|
294
433
|
node install.mjs list
|
|
295
|
-
node install.mjs ides
|
|
434
|
+
node install.mjs ides
|
|
435
|
+
|
|
436
|
+
npm 安装后(npx cli-blueprint@latest / npx cli-calctool@latest)用法相同。`)
|
|
296
437
|
process.exit(1)
|
|
297
438
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cli-blueprint",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "Blueprint
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Blueprint + calctool 多 IDE 安装器:从 cli.tax 自动拉取并分发到本机所有已装 IDE(Codex/DSH/Claude/Cursor/…)。支持 check 更新检测。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cli-blueprint": "install.mjs"
|
|
@@ -1,39 +1,47 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description:
|
|
2
|
+
name: blueprint
|
|
3
|
+
description: Compile one goal into an implementable engineering blueprint with deterministic checks. Use when the user wants to turn an idea, product, or site goal into an executable engineering plan with nodes, dependencies, acceptance criteria, and validation.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Blueprint Skill
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Endpoint: https://cli.tax/wvz6zmRWmX
|
|
9
|
+
Request schema: blueprint.skill.request/1.0
|
|
10
|
+
Response schema: blueprint.skill.response/1.0
|
|
9
11
|
|
|
10
|
-
##
|
|
12
|
+
## Request envelope
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
- Version: v0.4.0
|
|
14
|
-
- Status at generation: published
|
|
15
|
-
- Address: `https://cli.tax/wvz6zmRWmX`
|
|
16
|
-
- Method: `POST`
|
|
17
|
-
- Content type: `application/json`
|
|
18
|
-
|
|
19
|
-
Blueprint 是一个跨工具的工程规划 CLI,把明确目标编译为可执行、可追溯、可验收的全站工程蓝图,并通过确定性规则检查每个节点、分支、合同、任务与验收闭环。默认由当前 IDE 的多智能体协同推演,也可连接用户自行安装的本地 Hermes;平台不托管模型密钥。
|
|
20
|
-
|
|
21
|
-
## Invocation
|
|
22
|
-
|
|
23
|
-
Send JSON to the exact CLI address and put capability arguments inside `input`:
|
|
14
|
+
POST JSON to the endpoint with an `input` wrapper:
|
|
24
15
|
|
|
25
16
|
```json
|
|
26
17
|
{
|
|
27
|
-
"input": {
|
|
18
|
+
"input": {
|
|
19
|
+
"schemaVersion": "blueprint.skill.request/1.0",
|
|
20
|
+
"requestId": "<unique-id>",
|
|
21
|
+
"operation": "<operation>",
|
|
22
|
+
"input": {}
|
|
23
|
+
}
|
|
28
24
|
}
|
|
29
25
|
```
|
|
30
26
|
|
|
31
|
-
|
|
27
|
+
## Operations
|
|
28
|
+
|
|
29
|
+
- `capabilities`: discover the operation list, per-operation inputs, and the recommended next step.
|
|
30
|
+
- `help`: return the usage guide, operation catalog, and request examples.
|
|
31
|
+
- `intake`: return the questions the IDE must ask the user before building the Blueprint.
|
|
32
|
+
- `validate`: deterministically validate a Blueprint object conforming to `blueprint.ir/1.0`.
|
|
33
|
+
- `compile-inline`: validate and compile a Blueprint, returning the generated artifacts inline.
|
|
34
|
+
|
|
35
|
+
## Required flow
|
|
36
|
+
|
|
37
|
+
1. Call `capabilities` first and read the returned `nextStep`.
|
|
38
|
+
2. Call `intake` and ask the user the returned questions one at a time, waiting for each answer.
|
|
39
|
+
3. Do not compile a Blueprint until all required questions are answered.
|
|
40
|
+
4. Build a Blueprint conforming to `blueprint.ir/1.0`, then call `validate`.
|
|
41
|
+
5. Fix every validation finding until the report is green, then call `compile-inline` and save the artifacts.
|
|
32
42
|
|
|
33
|
-
##
|
|
43
|
+
## Safety rules
|
|
34
44
|
|
|
35
|
-
-
|
|
36
|
-
- `
|
|
37
|
-
-
|
|
38
|
-
- `429`: rate or concurrency limit reached
|
|
39
|
-
- `5xx`: execution or upstream failure
|
|
45
|
+
- Never send credentials, model keys, provider endpoints, or personal secrets inside the request envelope or `input`.
|
|
46
|
+
- The response `status` must be `succeeded`; a `failed` response is an error, not a result.
|
|
47
|
+
- Public responses never prove that code was developed, tested, or deployed.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: calctool
|
|
3
|
+
description: 按需生成「万能计算工具」:用户输入一个领域需求(如"我是财务,想要一个经营健康诊断工具"),本技能通过提问明确指标、公式、输入方式与输出形式,生成一个可执行、可验证、可发布的在线计算工具——支持自定义指标、自定义公式逻辑、用户上传内容自动识别(Excel 映射 / 图片 OCR)、报告输出。当用户想"把某套计算逻辑/指标/公式做成在线工具"时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# calctool
|
|
7
|
+
|
|
8
|
+
把「业务计算逻辑」编译为「可执行的在线计算工具」的生成器。
|
|
9
|
+
|
|
10
|
+
## 全链路总流程(老板视角 → 可运行工具)
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
老板(任何 IDE / DSH):"我要搭电商运营计算工具"
|
|
14
|
+
↓
|
|
15
|
+
1. 顾问式对话(intake-round) —— 智能体主动给方案(基于领域参考包),
|
|
16
|
+
老板逐轮确认指标/公式/口径,直到说"创建"
|
|
17
|
+
↓
|
|
18
|
+
2. 情报蜂群(research) —— 自动派情报智能体搜索行业标准/抓指定地址,
|
|
19
|
+
产出可溯源参考包(老板说"电商"等关键词时自动触发)
|
|
20
|
+
↓
|
|
21
|
+
3. 蜂群执行(brain-invoke/complete)—— 需求自动拆解为 fields/formulas/rules/
|
|
22
|
+
imports/reports/pages 任务,依赖图驱动并行,独立复核,确定性合并
|
|
23
|
+
↓
|
|
24
|
+
4. 编译工具(compile-tool) —— 引擎定义 → 可运行工程文件清单
|
|
25
|
+
(App 壳/公式引擎/存储/构建,页面自动生成:录入/指标卡/报告)
|
|
26
|
+
↓
|
|
27
|
+
5. 环境适配(probe-env/adapt-config)—— 自动探测 Node 版本/包管理器/OS/架构,
|
|
28
|
+
Node≥18 全功能、16 兼容(sql.js)、<16 零构建预览;pnpm/yarn/npm 自动适配
|
|
29
|
+
↓
|
|
30
|
+
6. 完成前门禁(final-gate) —— 审计/测试/运维三智能体协调接管检测,
|
|
31
|
+
全部符合通过(engine-valid / 基准样例全通过 / 环境就绪)才标记完成
|
|
32
|
+
↓
|
|
33
|
+
7. 交付运行 —— 按适配命令一键搭建(pnpm install → pnpm run dev)
|
|
34
|
+
→ 老板得到可交互工具;后续对话继续改指标/公式(热更新)
|
|
35
|
+
|
|
36
|
+
或直接走「全自动流水线」(auto-pipeline)——老板只需说需求 + 授权一次:
|
|
37
|
+
授权(告知消耗) → 情报蜂群 → 蜂群生成 → 测试审计 → 编译 → 自动启动弹出页面
|
|
38
|
+
→ 完成前门禁(审计/测试/运维三智能体协调接管,全部符合通过才标记完成)
|
|
39
|
+
全程无需老板参与,热更新即时生效
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**关键**:老板一句话 → 对话确认 → 情报 → 蜂群 → 编译 → 环境适配 → **可运行工具**。全程框架不变,需求变更只改配置。
|
|
43
|
+
|
|
44
|
+
## 何时使用
|
|
45
|
+
|
|
46
|
+
- 用户描述了一个领域场景(财务、运营、工程、教育、医疗……)并想要一个可交互的在线计算工具
|
|
47
|
+
- 用户已有指标、公式、评分或报告逻辑,想固化成工具
|
|
48
|
+
- 用户需要"自定义指标 + 自定义公式 + 上传识别"能力
|
|
49
|
+
|
|
50
|
+
不要用于:纯展示型页面(无计算)、与计算无关的 CRUD 后台。
|
|
51
|
+
|
|
52
|
+
## 核心原则
|
|
53
|
+
|
|
54
|
+
1. **确定性计算**:正式数字由版本化确定性引擎(公式 AST + Decimal 运行时)产生;模型/OCR/AI 只产生候选、草稿与解释,绝不直接给出不可追溯的正式结果。
|
|
55
|
+
2. **配置化而非代码化**:工具 = 一份可发布的引擎定义(字段目录 + 公式图 + 规则包 + 导入映射 + 视图 + 报告),不是散落的页面代码。
|
|
56
|
+
3. **显式除零**:所有除法必须选 `div`(除零报错)或 `safeDivide`(除零回退),不静默吞错。
|
|
57
|
+
4. **零虚构**:能力未接入时保持"未接入态"(planned/not_installed/disconnected),不虚构数据、状态或按钮。
|
|
58
|
+
|
|
59
|
+
## 五步实施流程
|
|
60
|
+
|
|
61
|
+
### 1. intake —— 收集需求(必须提问,一次一问)
|
|
62
|
+
调用运行时 intake 或按下面问题逐条问用户:
|
|
63
|
+
- 目标:这个工具帮用户完成什么?什么必须发生、什么绝不允许发生?
|
|
64
|
+
- 输入指标:用户会输入哪些字段?(如收入、成本、人数、月份)
|
|
65
|
+
- 公式逻辑:哪些指标由公式算出?(如毛利 = 收入 - 成本)
|
|
66
|
+
- 输入方式:手工录入 / Excel 上传 / 图片 OCR / 三者都要?
|
|
67
|
+
- 输出形式:指标卡、表格、诊断报告、历史记录?
|
|
68
|
+
- 约束:单位、精度、语言、离线/在线、禁止项?
|
|
69
|
+
|
|
70
|
+
### 2. 生成引擎定义(Engine Definition)
|
|
71
|
+
```yaml
|
|
72
|
+
engineId: <kebab-case-引擎名>
|
|
73
|
+
name: <显示名>
|
|
74
|
+
category: <领域,如 finance/operations/education>
|
|
75
|
+
ownerType: platform-template
|
|
76
|
+
status: draft
|
|
77
|
+
semanticVersion: 1.0.0
|
|
78
|
+
compatibilityProfile: legacy-compatible
|
|
79
|
+
decimalPolicy: decimal-string
|
|
80
|
+
defaultLocale: zh-CN
|
|
81
|
+
```
|
|
82
|
+
包含(详见 references/engine-meta-model.md):
|
|
83
|
+
- field-catalog:字段目录(类型:amount/ratio/int/enum/dimension/date)
|
|
84
|
+
- formula-graph:公式图(节点 = 字段/公式,边 = 依赖)
|
|
85
|
+
- rule-packs:规则包(阈值、评分、分级)
|
|
86
|
+
- import-profiles:导入映射(Excel 列 / OCR 字段 → 字段目录)
|
|
87
|
+
- report-template:报告模板(指标卡 + 表格 + 诊断结论)
|
|
88
|
+
|
|
89
|
+
### 3. 编译公式(详见 references/formula-dsl.md)
|
|
90
|
+
- 把自然语言/Excel 公式编译为 JSON AST(禁止 eval/new Function)
|
|
91
|
+
- 运算符走最小注册表(add/sub/mul/div/safeDivide/percentOf/if/case/sum/avg/lookup…)
|
|
92
|
+
- 数值用 Decimal 字符串,单位编译期推断,错误结构化传播
|
|
93
|
+
- 发布前跑依赖图检查:引用存在、无环、可见范围
|
|
94
|
+
|
|
95
|
+
### 4. 生成在线工具(详见 references/declarative-pages.md)
|
|
96
|
+
- 表单页:录入字段(按 field-catalog 自动生成)
|
|
97
|
+
- 指标卡页:公式结果 StatGrid
|
|
98
|
+
- 报告页:结构化输出 + 可导出
|
|
99
|
+
- 页面用声明式规格(ApplicationPageSpec),不手写重复模板
|
|
100
|
+
|
|
101
|
+
### 5. 验收与发布
|
|
102
|
+
- validate:确定性校验引擎定义(引用闭合、无环、单位一致、测试通过)
|
|
103
|
+
- 上传识别走导入 Profile(Excel 映射 + OCR 草稿确认,自动导入先进草稿)
|
|
104
|
+
- **完成前门禁(final-gate)**:每次项目完成之前,审计/测试/运维三智能体协调接管检测——
|
|
105
|
+
- **审计智能体**:引擎定义确定性校验 0 findings、公式仅走受控 AST(禁 eval)、引用闭合
|
|
106
|
+
- **测试智能体**:基准样例(testSuites)全部通过,一个不过都不放行
|
|
107
|
+
- **运维智能体**:环境探测成功、依赖分级适配、安装/启动命令可用、热更新就绪
|
|
108
|
+
- 三智能体全部符合通过(gate passed)才标记完成;任一未通过返回 findings,修复后重新接管检测
|
|
109
|
+
- 发布为版本化引擎,任何公式/字段/阈值变化都创建新版本,不原地修改
|
|
110
|
+
- 输出:可运行的在线工具 + 引擎定义包 + 验收报告 + 完成前门禁结论
|
|
111
|
+
|
|
112
|
+
## 多智能体蜂群模式(大脑协同,推荐复杂工具用)
|
|
113
|
+
|
|
114
|
+
单智能体 `compile-inline` 适合简单工具;复杂工具(多字段 + 多公式 + 规则 + 导入 + 报告)用**蜂群协同**,多智能体并行生成、独立复核、确定性合并——准确率更高、产出更强。
|
|
115
|
+
|
|
116
|
+
### 大脑模式(brain-handshake)
|
|
117
|
+
- `ide`:用当前 IDE 的多智能体(subagent)执行蜂群(默认)
|
|
118
|
+
- `hermes_local`:用用户本地安装的 Hermes 执行蜂群
|
|
119
|
+
|
|
120
|
+
### 蜂群流程(协议 calctool.coordinator.run-plan/1.0)
|
|
121
|
+
|
|
122
|
+
1. **brain-handshake**:协商大脑模式(ide/hermes_local),返回蜂群能力
|
|
123
|
+
2. **brain-invoke**:传需求 → **自动拆解**为蜂群任务(按需派发,需要几个派几个):
|
|
124
|
+
- `fields` 字段目录(入口,总是有)
|
|
125
|
+
- `formulas` 公式图(有公式才派)· 独立复核
|
|
126
|
+
- `rules` 规则包(有规则才派)· 独立复核
|
|
127
|
+
- `imports` 导入映射(有导入才派)
|
|
128
|
+
- `reports` 报告模板(有报告才派)
|
|
129
|
+
- `pages` 页面规格(总是有)
|
|
130
|
+
依赖图驱动:fields 先 → formulas/imports 并行 → reports → pages;maxParallel 控制并发
|
|
131
|
+
3. **brain-invoke 批量派发**:每个就绪 work item 派给一个独立智能体,收集产物
|
|
132
|
+
4. **brain-events / brain-status**:流式收集事件、查询蜂群状态(就绪/运行/阻塞)
|
|
133
|
+
5. **brain-complete**:提交全部产物 → **确定性合并**为引擎定义 → 校验 → 发布
|
|
134
|
+
6. **brain-cancel**:随时取消蜂群
|
|
135
|
+
|
|
136
|
+
### 准确率与用户控制
|
|
137
|
+
- **准确率**:合并后引擎定义必须通过确定性校验(引用闭合/公式链/单位/Decimal/无环),0 findings 才发布
|
|
138
|
+
- **用户控制**:每一步产物可查看、修改、重试(budget.maxAttempts);最终工具可测算、改公式、调阈值
|
|
139
|
+
- **编程能力**:蜂群产物是真实可编译的引擎定义(JSON AST + Decimal 运行时),不是伪代码
|
|
140
|
+
|
|
141
|
+
## 输出产物
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
<engine-id>/
|
|
145
|
+
├── manifest.yaml # 引擎身份与版本
|
|
146
|
+
├── field-catalog.json # 字段目录
|
|
147
|
+
├── formula-graph.json # 公式图(AST)
|
|
148
|
+
├── rule-packs.json # 规则包
|
|
149
|
+
├── import-profiles.json # 导入映射
|
|
150
|
+
├── report-template.json # 报告模板
|
|
151
|
+
└── tests/ # 确定性测试(样例 → 期望结果)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## 参考文档
|
|
155
|
+
|
|
156
|
+
- `references/engine-meta-model.md` —— 引擎元模型(字段/公式/规则/导入/报告)
|
|
157
|
+
- `references/formula-dsl.md` —— 公式 DSL 与运行时(AST/Decimal/依赖图/错误值)
|
|
158
|
+
- `references/declarative-pages.md` —— 声明式页面规格系统(表单/指标/报告渲染)
|
|
159
|
+
- `references/import-ocr.md` —— 导入与 OCR(Excel 映射/图片识别/草稿确认)
|
|
160
|
+
- `references/finance-example.md` —— 经营健康诊断完整范例(50 字段 → 10 指标 → 报告)
|
|
161
|
+
|
|
162
|
+
## 安全规则
|
|
163
|
+
|
|
164
|
+
- 不执行任意 JavaScript;公式只走受控 AST
|
|
165
|
+
- 上传文件先验证类型/大小/指纹,OCR 结果进草稿不覆盖正式数据
|
|
166
|
+
- 不虚构后端数据;未接入能力显示真实状态
|
|
167
|
+
- 财务/税务输出需明确"经营估算模型,生产使用前由专业人员复核"
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# calctool 平台模板
|
|
2
|
+
|
|
3
|
+
由 calctool 生成的**可运行计算工具**工程模板(配置驱动、框架不变)。
|
|
4
|
+
|
|
5
|
+
## 一键运行
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install # 或 pnpm install / yarn install(环境自动适配)
|
|
9
|
+
npm run dev # 启动开发服务器 http://localhost:5173
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 结构
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
├── src/
|
|
16
|
+
│ ├── main.tsx # 入口(Ant Design X ConfigProvider)
|
|
17
|
+
│ ├── App.tsx # 应用壳(录入/指标卡/链路/报告/授权 五页)
|
|
18
|
+
│ ├── engine-definition.json # ★ 引擎定义 + 链路(改这里 = 改工具,框架不动)
|
|
19
|
+
│ ├── engine/
|
|
20
|
+
│ │ ├── evaluate.ts # JSON AST + decimal.js 确定性求值
|
|
21
|
+
│ │ └── (recompute.ts 依赖图增量重算,按需扩展)
|
|
22
|
+
│ ├── pipeline.ts # ★ 链路编排(联通节点,非单页孤岛)
|
|
23
|
+
│ ├── authz.ts # ★ 授权管理(首次使用同意 + 逐能力授权,一次授权持久化)
|
|
24
|
+
│ └── store.ts # 存储层(localStorage,可换 sqlite)
|
|
25
|
+
├── vite.config.ts
|
|
26
|
+
└── package.json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 整套工具(联通节点,非单页孤岛)
|
|
30
|
+
|
|
31
|
+
工具由**联通节点**组成,数据流在节点间流动:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
录入/导入 → 数据校验 → 确定性计算 → 数据存储 → 指标卡/报告
|
|
35
|
+
↘ 自动化(可选)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- 改动指标/公式:只改 `engine-definition.json`,链路自动感知
|
|
39
|
+
- 新增能力:在 `pipeline.ts` 加节点(如导入、导出、告警),页面无需改
|
|
40
|
+
- 页面「链路」Tab 可视化每个节点及其上下游,改工具时定位影响范围
|
|
41
|
+
|
|
42
|
+
## 授权与消耗提示
|
|
43
|
+
|
|
44
|
+
1. **首次使用总提示**:打开工具时弹窗告知"可能调用其他技能辅助、可能增加消耗",同意后持久化不再提示(可按工具分别记录)
|
|
45
|
+
2. **逐能力授权**:实际调用外部能力(Blueprint/搜索/模型/存储/自动化)前询问,一次授权永久记住
|
|
46
|
+
3. **授权管理页**:随时查看已授权能力、撤销授权
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## 改指标/公式(需求变更,框架不变)
|
|
50
|
+
|
|
51
|
+
编辑 `src/engine-definition.json`:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"fields": [{ "key": "visitors", "label": "访客数", "type": "integer", "unit": "人" }],
|
|
56
|
+
"formulas": [
|
|
57
|
+
{ "key": "conversionRate", "label": "转化率",
|
|
58
|
+
"expression": { "op": "safeDivide", "args": [{ "ref": "orders" }, { "ref": "visitors" }] } }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
保存即热更新——**不用改任何代码**。
|
|
64
|
+
|
|
65
|
+
## 公式运算符(详见 formula-dsl.md)
|
|
66
|
+
|
|
67
|
+
`add / sub / mul / div(除零报错)/ safeDivide(除零回退)/ percentOf / round / if / ref / lit`
|
|
68
|
+
|
|
69
|
+
## 环境适配
|
|
70
|
+
|
|
71
|
+
- Node ≥18:全功能(可换 better-sqlite3 持久化)
|
|
72
|
+
- Node 16:兼容(sql.js WASM)
|
|
73
|
+
- Node <16:建议只用 L0 配置预览
|
|
74
|
+
- 包管理器:npm/pnpm/yarn 命令自动适配
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>calctool 计算工具</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|