@olierjs/fugue-cli 0.1.0 → 0.1.3
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 +54 -2
- package/THIRD_PARTY_NOTICES +52 -1
- package/dist/darwin-arm64/fugue-cli +0 -0
- package/dist/darwin-x64/fugue-cli +0 -0
- package/dist/linux-arm64/fugue-cli +0 -0
- package/dist/linux-x64/fugue-cli +0 -0
- package/dist/win32-arm64/fugue-cli.exe +0 -0
- package/dist/win32-x64/fugue-cli.exe +0 -0
- package/package.json +2 -1
- package/skills/fugue-show-me/SKILL.md +44 -0
- package/skills/fugue-show-me/assets/diagram.css +77 -0
- package/skills/fugue-show-me/references/pele.md +68 -0
- package/skills/fugue-show-me/scripts/render-html.mjs +116 -0
- package/skills/show-me/SKILL.md +128 -0
- package/skills/show-me/agents/openai.yaml +2 -0
- package/skills/statechart/SKILL.md +36 -0
- package/skills/statechart/scripts/bug-states.mjs +81 -0
- package/skills/statechart/scripts/chart-edges.mjs +68 -0
- package/skills/statechart/scripts/chart-parts.mjs +21 -0
- package/skills/statechart/scripts/chart-to-tla.mjs +205 -0
- package/skills/statechart/scripts/compare-charts.mjs +74 -0
- package/skills/statechart/scripts/lib.mjs +970 -0
- package/skills/statechart/scripts/map-view.mjs +92 -0
- package/skills/statechart/scripts/property-loop.mjs +60 -0
- package/skills/statechart/scripts/read-check.mjs +79 -0
- package/skills/statechart/scripts/regions-chart.mjs +307 -0
- package/skills/statechart/scripts/render.mjs +531 -0
- package/skills/statechart/scripts/rule-book.mjs +84 -0
- package/skills/statechart/scripts/second-replay.mjs +122 -0
- package/skills/statechart/scripts/snapshot.mjs +74 -0
- package/skills/statechart/scripts/spec-text.mjs +126 -0
- package/skills/statechart/scripts/statechart-help.mjs +350 -0
- package/skills/statechart/scripts/statechart.mjs +903 -0
- package/skills/statechart/scripts/test/band.mmd +15 -0
- package/skills/statechart/scripts/test/regions.mmd +62 -0
- package/skills/statechart/scripts/test/statechart.test.mjs +6854 -0
- package/skills/statechart/scripts/test/sync.mmd +19 -0
- package/skills/statechart/scripts/test/upload.mmd +16 -0
- package/skills/statechart/scripts/tlc-to-chart-args.mjs +52 -0
- package/skills/statechart/scripts/tlc-to-chart.mjs +802 -0
- package/skills/statechart/scripts/tlc-tools.mjs +69 -0
- package/skills/statechart/scripts/ways-in.mjs +69 -0
- package/upstream-skills.json +18 -0
package/README.md
CHANGED
|
@@ -13,7 +13,9 @@ fugue-cli guide
|
|
|
13
13
|
|
|
14
14
|
后续更新执行同一条安装命令。包内提供 macOS、Linux、Windows 的 x64 和 arm64 二进制。
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
使用 nvm 管理 Node 时,先在当前终端执行 `nvm use 22.19.0` 或选择更高版本,再安装和运行。启动 Agent 的环境也需要能通过 `PATH` 找到 `fugue-cli`。
|
|
17
|
+
|
|
18
|
+
安装脚本自动将包内 Skill 同步到 `~/.agents/skills`,包括薄入口 `fugue-stack`、远端规划 `plan-with-remote`、原版 `show-me`、原版 `statechart` 和可视化解释适配 `fugue-show-me`。无需手动复制目录。替换同名旧 Skill 或清理本工具管理的过时 Skill 前,会先保存备份;其他 Skill 保持原样。备份放在 `~/.local/share/fugue-cli/backups`,位于技能发现目录之外。
|
|
17
19
|
|
|
18
20
|
自动同步通过 npm 的 `postinstall` 执行,需要允许安装脚本运行。清理发生在安装或升级时,针对新版已移除的受管理 Skill;`npm uninstall` 没有对应的自动清理钩子。
|
|
19
21
|
|
|
@@ -27,24 +29,74 @@ fugue-cli --help
|
|
|
27
29
|
fugue-cli --version
|
|
28
30
|
```
|
|
29
31
|
|
|
32
|
+
在目标项目中启动支持 Skill 的 Agent,描述要完成的工作,例如:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
$fugue-stack 根据这份已确认需求实现功能,完成后审查差异并验证。
|
|
36
|
+
$fugue-stack 审查当前代码变更,列出有实际影响的问题。
|
|
37
|
+
$fugue-show-me 用最小的结构图解释这次改动。
|
|
38
|
+
$fugue-show-me 检查取消与重试交错时的状态变化,画出可能的缺陷路径。
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`fugue-cli guide` 输出工作指南,编码、审查和解释由当前 Agent 按指南执行。若安装后暂时看不到新 Skill,可重新启动 Agent 后再选择入口。
|
|
42
|
+
|
|
30
43
|
需求理解、规划和需求或方案解释继续由 `plan-with-remote` 及远端规划服务负责。指南提供规划技能的绝对路径;该技能的客户端需要 Git、已配置的规划服务,以及已在服务中登记的目标仓库,配置说明见 [configuration.md](skills/plan-with-remote/references/configuration.md)。
|
|
31
44
|
|
|
32
45
|
编码、代码审查与验证、面向人的实现解释由当前 Agent 按指南完成。读取指南本身不会发起规划、修改项目或调用模型。远端规划返回的正式文档继续按 Markdown 原文保存,批准版本由规划客户端和服务端管理。
|
|
33
46
|
|
|
47
|
+
## 上游技能
|
|
48
|
+
|
|
49
|
+
`show-me` 完整目录原样引入自 [humanlayer/skills](https://github.com/humanlayer/skills/tree/653b6411c1f70c275a18e37673b042ff99f67ceb/plugins/show-me/skills/show-me),保留原始说明和 Agent 调用配置。来源、固定提交和目录记录在 [upstream-skills.json](upstream-skills.json),MIT 许可保留在 [THIRD_PARTY_NOTICES](THIRD_PARTY_NOTICES)。
|
|
50
|
+
|
|
51
|
+
`statechart` 完整目录原样引入自 [cursor/plugins 的 pstack](https://github.com/cursor/plugins/tree/99b609a72323b70204eab407c622f436e858e112/pstack/skills/statechart),包括原始说明、脚本和测试。同样在来源记录中固定提交,并保留 MIT 许可。
|
|
52
|
+
|
|
53
|
+
需要可视化解释时,总览路由到 [fugue-show-me](skills/fugue-show-me/SKILL.md):由 `show-me` 选择通用表达形式,需要分析状态变化、检查行为规则或展示缺陷路径时配合 `statechart`。适配维护在独立目录中;更新上游时整体替换原版目录并更新来源记录。
|
|
54
|
+
|
|
55
|
+
`fugue-show-me` 根据这些方法组织全局视图和必要的交互、状态细节,再通过本层的 [Pele 输出脚本](skills/fugue-show-me/scripts/render-html.mjs) 将 Mermaid 统一展示为单文件 HTML。图在正文直接可见,采用 Flexoki 浅色与深色主题,按信息角色分色,支持自适应和缩放。首次生成页面会将 `pele@1.12.0` 安装到独立用户缓存,生成的页面可离线打开;该展示链路不导入或修改上游的内部渲染模块。
|
|
56
|
+
|
|
57
|
+
## 状态图依赖
|
|
58
|
+
|
|
59
|
+
`statechart` 使用 Node.js 和 npm;模型检查还需要 [mise](https://mise.jdx.dev/getting-started.html)。macOS 可先安装:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
brew install mise
|
|
63
|
+
node ~/.agents/skills/statechart/scripts/statechart.mjs --help
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
首次模型检查由原版脚本通过 mise 安装 Java Temurin 25 和 TLC 1.7.4,需要联网下载约 305 MB。若使用已有环境,可按上游帮助设置 `JAVA` 和 `TLA2TOOLS`。首次 PNG 出图会将 `pele@1.8.0` 和 `@resvg/resvg-js@2.6.2` 安装到用户缓存目录;仅渲染现成 Mermaid 图时不运行 TLC。
|
|
67
|
+
|
|
68
|
+
该版 TLC 无法解析模型字符串中的中文。模型使用 ASCII 标识符和字符串值,中文标签放在映射文件中,从模型生成中文状态图。
|
|
69
|
+
|
|
70
|
+
输入和产物放在目标仓库之外的临时目录,按上游要求交付 PNG、Mermaid 源码、缺陷说明和再生成命令。模型检查结果与真实代码复现结果分别说明。
|
|
71
|
+
|
|
34
72
|
## 开发与发布
|
|
35
73
|
|
|
36
74
|
开发与打包需要 Go >=1.23 和 Node >=22.19.0。
|
|
37
75
|
|
|
76
|
+
验证尚未发布到 npm 的仓库版本时,在仓库根目录打包,再安装生成的本地包:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
npm pack
|
|
80
|
+
npm install -g ./olierjs-fugue-cli-0.1.3.tgz
|
|
81
|
+
fugue-cli --version
|
|
82
|
+
fugue-cli guide
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
本地包安装同样会运行 Skill 自动同步。`@latest` 使用 npm 上的已发布版本,本地包使用本次构建的仓库版本。
|
|
86
|
+
|
|
38
87
|
```sh
|
|
39
88
|
go test ./...
|
|
40
89
|
node --test tests/*.test.mjs
|
|
90
|
+
node --test skills/statechart/scripts/test/statechart.test.mjs
|
|
41
91
|
npm pack
|
|
42
92
|
```
|
|
43
93
|
|
|
94
|
+
上游测试包含 Linux 的 `LD_PRELOAD` 故障注入,并对临时路径和英文 Java 诊断文本作精确断言;macOS 上需单独核对这些环境差异。
|
|
95
|
+
|
|
44
96
|
`npm pack` 的 `prepack` 自动构建各平台二进制,并将版本写入命令。发布目标固定为 npmjs,包名为 `@olierjs/fugue-cli`。发布验收后的包:
|
|
45
97
|
|
|
46
98
|
```sh
|
|
47
|
-
npm publish ./olierjs-fugue-cli-0.1.
|
|
99
|
+
npm publish ./olierjs-fugue-cli-0.1.3.tgz --access public
|
|
48
100
|
```
|
|
49
101
|
|
|
50
102
|
Go 命令入口位于 [cmd/fugue-cli](cmd/fugue-cli/main.go),指南源码位于 [guide.md](internal/cli/guide.md),入口技能位于 [SKILL.md](skills/fugue-stack/SKILL.md)。
|
package/THIRD_PARTY_NOTICES
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Third-party
|
|
1
|
+
Third-party components distributed with fugue-cli.
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
github.com/spf13/cobra v1.10.2
|
|
@@ -414,3 +414,54 @@ github.com/inconshreveable/mousetrap v1.1.0
|
|
|
414
414
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
415
415
|
See the License for the specific language governing permissions and
|
|
416
416
|
limitations under the License.
|
|
417
|
+
|
|
418
|
+
humanlayer/skills: show-me (653b6411c1f70c275a18e37673b042ff99f67ceb)
|
|
419
|
+
https://github.com/humanlayer/skills/tree/653b6411c1f70c275a18e37673b042ff99f67ceb/plugins/show-me/skills/show-me
|
|
420
|
+
|
|
421
|
+
MIT License
|
|
422
|
+
|
|
423
|
+
Copyright (c) 2026 HumanLayer
|
|
424
|
+
|
|
425
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
426
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
427
|
+
in the Software without restriction, including without limitation the rights
|
|
428
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
429
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
430
|
+
furnished to do so, subject to the following conditions:
|
|
431
|
+
|
|
432
|
+
The above copyright notice and this permission notice shall be included in all
|
|
433
|
+
copies or substantial portions of the Software.
|
|
434
|
+
|
|
435
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
436
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
437
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
438
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
439
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
440
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
441
|
+
SOFTWARE.
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
cursor/plugins: pstack statechart (99b609a72323b70204eab407c622f436e858e112)
|
|
445
|
+
https://github.com/cursor/plugins/tree/99b609a72323b70204eab407c622f436e858e112/pstack/skills/statechart
|
|
446
|
+
|
|
447
|
+
MIT License
|
|
448
|
+
|
|
449
|
+
Copyright (c) 2026 Lauren Tan
|
|
450
|
+
|
|
451
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
452
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
453
|
+
in the Software without restriction, including without limitation the rights
|
|
454
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
455
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
456
|
+
furnished to do so, subject to the following conditions:
|
|
457
|
+
|
|
458
|
+
The above copyright notice and this permission notice shall be included in all
|
|
459
|
+
copies or substantial portions of the Software.
|
|
460
|
+
|
|
461
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
462
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
463
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
464
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
465
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
466
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
467
|
+
SOFTWARE.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/linux-x64/fugue-cli
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olierjs/fugue-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Fugue 需求交付工作指南与 Agent 技能",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": { "fugue-cli": "bin/fugue-cli.mjs" },
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"scripts/postinstall.mjs",
|
|
11
11
|
"scripts/skills.mjs",
|
|
12
12
|
"skills/",
|
|
13
|
+
"upstream-skills.json",
|
|
13
14
|
"THIRD_PARTY_NOTICES"
|
|
14
15
|
],
|
|
15
16
|
"engines": { "node": ">=22.19.0" },
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fugue-show-me
|
|
3
|
+
description: 组合 show-me 与 statechart 的分析视角,用 Pele 将 Mermaid 展示为可读的 HTML 图解;解释实现、代码变更、运行结果、状态变化或缺陷路径时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 可视化解释
|
|
7
|
+
|
|
8
|
+
上游 skill 保持独立。本层负责按问题选择分析方法、组织面向人的视图,再用 Pele 统一展示;不修改上游,也不调用它们的内部渲染模块。
|
|
9
|
+
|
|
10
|
+
## 获取信息与组织视图
|
|
11
|
+
|
|
12
|
+
先阅读并遵循[上游 show-me](../show-me/SKILL.md),由它指导表达形式的选择。技能提供分析方法,事实来自当前源码、差异、文档和实际运行结果。
|
|
13
|
+
|
|
14
|
+
| 问题需要的视角 | 方法与信息 | 适合的图 |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| 系统全貌、职责边界、数据流 | 按 `show-me` 从材料中提取组件、输入输出与关系 | 流程图、分组结构图 |
|
|
17
|
+
| 谁先做什么、谁调用谁 | 按 `show-me` 跟随真实调用或事件顺序 | 时序图 |
|
|
18
|
+
| 状态、并发、重试、取消、恢复、缺陷路径 | 阅读并遵循[上游 statechart](../statechart/SKILL.md),获取模型状态、转换、规则、检查结果和复现证据 | 上游生成的状态图与缺陷路径图 |
|
|
19
|
+
|
|
20
|
+
按问题选用必要的方法;普通结构解释不强制建模。任务中其他已选技能的输出也可作为材料,使用前核对其依据和适用范围。
|
|
21
|
+
|
|
22
|
+
模型负责组织信息:统一不同材料的对象名称、版本和粒度;区分已确认行为、模型假设与待确认关系。涉及多个组件或分支时先给出边界和主路径的总览,再按问题展开关键交互或状态细节。一张图回答一个问题,避免把全部实现细节堆进总览;说明使用用户的语言,标签优先写读者关心的行为。
|
|
23
|
+
|
|
24
|
+
图中按职责或状态区分颜色,沿用 [Pele 展示说明](references/pele.md)中的颜色角色;由模型明确标注输入、处理、判断、外部交互、完成、失败和跳过,保留对应文字标签。不要按节点顺序轮流染色,也不让脚本从节点名称猜业务含义。浅色和深色使用同一套颜色含义,原模型的规则结果和缺陷路径标记优先。
|
|
25
|
+
|
|
26
|
+
使用 `statechart` 时保留上游的建模、模型检查、复现及交付要求。原版 TLC 使用 ASCII 模型标识符和字符串值,中文状态与步骤标签写在映射文件中。将它生成的 `.mmd` 直接交给展示层,保留状态、边、步骤编号和缺陷标记;另画的简洁总览不能替代经检查的模型图,Pele 的渲染成功也不证明行为正确。
|
|
27
|
+
|
|
28
|
+
## 用 Pele 交付图示
|
|
29
|
+
|
|
30
|
+
选择 Mermaid 表达并需要 HTML 时,用本层的 [Pele 输出脚本](scripts/render-html.mjs) 渲染。输入可以同时包含模型编写的总览、时序图和 `statechart` 生成的状态图,顺序就是页面阅读顺序。用易懂的文件名作为各图标题。
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
node <本 skill 目录>/scripts/render-html.mjs --title "发布流程说明" --out /绝对路径/说明.html /绝对路径/全局视图.mmd /绝对路径/状态流转.mmd
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
脚本通过 Pele 的公开 API 生成内嵌 SVG,并将 Pele 的浏览器包一并嵌入 HTML,用它提供自适应、中文字体测量和缩放。采用官方站点的 Flexoki 浅色与深色配色,页面内可切换,`--theme light|dark` 指定初始主题。首次安装固定版本依赖,后续复用本层的独立缓存;页面打开时无需联网或启动服务。集成到已有 HTML、调整主题或定位兼容问题时,阅读 [Pele 展示说明](references/pele.md)。
|
|
37
|
+
|
|
38
|
+
核心图放在对应说明旁、默认可见,简短说明补充结论、范围与必要证据。源码和模型检查材料可放附录,下载入口仅作补充。在支持 Mermaid 的对话或文档中可直接使用会渲染的 `mermaid` 代码块;表达形式更适合树、伪代码或表格时,继续遵循 `show-me`,无需强制转成图。
|
|
39
|
+
|
|
40
|
+
## 交付检查
|
|
41
|
+
|
|
42
|
+
打开最终交付的 HTML 或图片,检查实际图示;不能用“文件已生成”、HTML 源码或下载链接存在代替检查。HTML 检查桌面和窄屏,确认核心图已显示、中文标签及连线可读、大图可查看完整内容;本地静态页面还需确认离线可显示。渲染失败就修复后重新检查,不把下载源码当成完成。无法预览时明确说明未验证的范围。
|
|
43
|
+
|
|
44
|
+
将上游的 `Bash(open ...)` 对应为当前宿主可用的终端或文件预览工具,按实际操作系统打开 HTML 或图片。交付本地文件时提供绝对路径链接;仅在实际打开成功后说明已打开。
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* Flexoki light/dark palettes from https://pele.run/theming and the official site. */
|
|
2
|
+
:root {
|
|
3
|
+
color-scheme: light;
|
|
4
|
+
--bg: #fffcf0; --surface: #f2f0e5; --surface-alt: #e6e4d9;
|
|
5
|
+
--text: #100f0f; --muted: #6f6e69; --border: #cecdc3; --accent: #205ea6;
|
|
6
|
+
--page-muted: #575653; --link: #205ea6;
|
|
7
|
+
--role-input: #24837b; --role-process: #205ea6; --role-decision: #ad8301;
|
|
8
|
+
--role-external: #5e409d; --role-success: #66800b; --role-failure: #af3029; --role-skipped: #6f6e69;
|
|
9
|
+
--role-strength: 18%;
|
|
10
|
+
--pele-series-1: #af3029; --pele-series-2: #bc5215; --pele-series-3: #ad8301; --pele-series-4: #66800b;
|
|
11
|
+
--pele-series-5: #24837b; --pele-series-6: #205ea6; --pele-series-7: #5e409d; --pele-series-8: #a02f6f;
|
|
12
|
+
}
|
|
13
|
+
html[data-theme="dark"] {
|
|
14
|
+
color-scheme: dark;
|
|
15
|
+
--bg: #100f0f; --surface: #1c1b1a; --surface-alt: #282726;
|
|
16
|
+
--text: #cecdc3; --muted: #878580; --border: #403e3c; --accent: #4385be;
|
|
17
|
+
--page-muted: #878580; --link: #66a0c8;
|
|
18
|
+
--role-input: #3aa99f; --role-process: #4385be; --role-decision: #d0a215;
|
|
19
|
+
--role-external: #8b7ec8; --role-success: #879a39; --role-failure: #d14d41; --role-skipped: #878580;
|
|
20
|
+
--role-strength: 24%;
|
|
21
|
+
--pele-series-1: #d14d41; --pele-series-2: #da702c; --pele-series-3: #d0a215; --pele-series-4: #879a39;
|
|
22
|
+
--pele-series-5: #3aa99f; --pele-series-6: #4385be; --pele-series-7: #8b7ec8; --pele-series-8: #ce5d97;
|
|
23
|
+
}
|
|
24
|
+
* { box-sizing: border-box; }
|
|
25
|
+
body { margin: 0; background: var(--surface); color: var(--text); font: 16px/1.65 var(--font); }
|
|
26
|
+
main { max-width: 1200px; margin: auto; padding: 40px 28px; }
|
|
27
|
+
.page-heading { display: flex; justify-content: space-between; align-items: start; gap: 20px; }
|
|
28
|
+
h1 { font-size: clamp(26px,4vw,38px); line-height: 1.3; margin: 0 0 12px; }
|
|
29
|
+
h2 { font-size: 20px; margin: 0 0 16px; }
|
|
30
|
+
header p { color: var(--page-muted); font-size: 14px; }
|
|
31
|
+
.theme-controls { display: flex; flex-shrink: 0; padding: 3px; gap: 3px; border: 1px solid var(--border); border-radius: 9px; background: var(--bg); }
|
|
32
|
+
.theme-controls button { cursor: pointer; font: inherit; font-size: 13px; min-height: 36px; padding: 5px 14px; border: 0; border-radius: 6px; background: transparent; color: var(--muted); }
|
|
33
|
+
.theme-controls button[aria-pressed="true"] { background: var(--surface-alt); color: var(--text); font-weight: 600; }
|
|
34
|
+
nav { display: flex; flex-wrap: wrap; gap: 10px 20px; margin: 20px 0; }
|
|
35
|
+
a { color: var(--link); text-decoration: underline; text-underline-offset: 4px; overflow-wrap: anywhere; }
|
|
36
|
+
.legend { display: flex; flex-wrap: wrap; gap: 10px 22px; padding: 0; margin: 22px 0 32px; list-style: none; font-size: 13px; color: var(--page-muted); }
|
|
37
|
+
.legend li { display: inline-flex; align-items: center; gap: 8px; }
|
|
38
|
+
.legend i { width: 12px; height: 12px; border-radius: 3px; background: var(--role-color); }
|
|
39
|
+
section { min-width: 0; margin: 24px 0; padding: 24px; background: var(--bg); border: 1px solid var(--border); border-radius: 12px; }
|
|
40
|
+
.diagram {
|
|
41
|
+
width: 100%; min-width: 0;
|
|
42
|
+
--pele-bg: var(--bg); --pele-fg: var(--text); --pele-fg-on-light: #100f0f; --pele-fg-on-dark: #fffcf0;
|
|
43
|
+
--pele-muted: var(--muted); --pele-line: var(--muted); --pele-surface: var(--surface);
|
|
44
|
+
--pele-surface-alt: var(--surface-alt); --pele-border: var(--border); --pele-accent: var(--accent);
|
|
45
|
+
--pele-critical: var(--role-failure); --pele-error: var(--role-failure); --pele-font: var(--font);
|
|
46
|
+
}
|
|
47
|
+
.diagram > svg { display: block; max-width: 100%; height: auto; margin-inline: auto; }
|
|
48
|
+
.fugueInput { --role-color: var(--role-input); }
|
|
49
|
+
.fugueProcess { --role-color: var(--role-process); }
|
|
50
|
+
.fugueDecision { --role-color: var(--role-decision); }
|
|
51
|
+
.fugueExternal { --role-color: var(--role-external); }
|
|
52
|
+
.fugueSuccess { --role-color: var(--role-success); }
|
|
53
|
+
.fugueFailure { --role-color: var(--role-failure); }
|
|
54
|
+
.fugueSkipped { --role-color: var(--role-skipped); }
|
|
55
|
+
|
|
56
|
+
/* Neutral model states follow the theme; rule outcomes keep their source colors. */
|
|
57
|
+
.diagram .pele-state:is(.works,.worksPath) > :is(rect,path,circle,ellipse,polygon) { fill: var(--surface) !important; }
|
|
58
|
+
.diagram .pele-state:is(.works,.worksPath) .pele-label { fill: var(--text) !important; }
|
|
59
|
+
|
|
60
|
+
/* Roles are explicit Mermaid classes, never guessed from labels or source order. */
|
|
61
|
+
.diagram .pele-node:is(.fugueInput,.fugueProcess,.fugueDecision,.fugueExternal,.fugueSuccess,.fugueFailure,.fugueSkipped):not([class*="wrong" i]):not([class*="fixed" i]):not([class*="mixed" i]):not([class*="after" i]):not([class*="worse" i]) > :is(rect,path,circle,ellipse,polygon) {
|
|
62
|
+
fill: color-mix(in srgb, var(--role-color) var(--role-strength), var(--bg)) !important;
|
|
63
|
+
stroke: var(--path-border, var(--role-color)) !important;
|
|
64
|
+
}
|
|
65
|
+
.diagram .pele-node:is(.fugueInput,.fugueProcess,.fugueDecision,.fugueExternal,.fugueSuccess,.fugueFailure,.fugueSkipped):not([class*="wrong" i]):not([class*="fixed" i]):not([class*="mixed" i]):not([class*="after" i]):not([class*="worse" i]) .pele-label { fill: var(--text) !important; }
|
|
66
|
+
|
|
67
|
+
/* Blue path borders remain blue, with their original width and step numbers. */
|
|
68
|
+
.diagram .pele-state[class*="Path"] { --path-border: var(--role-process); }
|
|
69
|
+
.diagram .pele-state[class*="Path"] > :is(rect,path,circle,ellipse,polygon) { stroke: var(--role-process) !important; }
|
|
70
|
+
a:focus-visible,button:focus-visible,.diagram:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
|
|
71
|
+
noscript { color: var(--page-muted); }
|
|
72
|
+
@media(max-width:640px) {
|
|
73
|
+
main { padding: 24px 14px; }
|
|
74
|
+
.page-heading { flex-direction: column; gap: 8px; }
|
|
75
|
+
section { padding: 16px 10px; }
|
|
76
|
+
h2 { font-size: 18px; }
|
|
77
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Pele 展示层
|
|
2
|
+
|
|
3
|
+
Pele 只负责把 Mermaid 画成 SVG。模型决定要解释什么、采用哪个视角和保留哪些关系;源码、运行结果与上游检查结果提供事实依据。展示层不重新判断这些事实。
|
|
4
|
+
|
|
5
|
+
## 生成单文件 HTML
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
node <本 skill 目录>/scripts/render-html.mjs \
|
|
9
|
+
--title "取消与恢复的实现" \
|
|
10
|
+
--out /绝对路径/说明.html \
|
|
11
|
+
/绝对路径/全局视图.mmd \
|
|
12
|
+
/绝对路径/调用顺序.mmd \
|
|
13
|
+
/绝对路径/状态与缺陷.mmd
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
仅传入本次解释需要的图,不要求凑齐示例中的三种视角。输入与产物放在目标源码仓库之外,除非用户明确要求保存到仓库。
|
|
17
|
+
|
|
18
|
+
脚本使用 `pele@1.12.0`,首次通过 npm 安装到用户缓存目录的 `fugue-show-me/pele-1.12.0`,遵循 `XDG_CACHE_HOME`,默认在 `~/.cache` 下。缓存独立于 `statechart`;不读取上游缓存、导入上游私有模块或依赖上游 PNG 渲染实现。
|
|
19
|
+
|
|
20
|
+
所有输入先调用 `render()` 检查并生成 SVG,成功后才写 HTML;错误会使命令失败,不生成仅剩下载入口的页面。HTML 同时内嵌 SVG、Mermaid 源码和 Pele 的浏览器包。浏览器通过 `mount()` 使用实际字体和容器宽度布局,缩放、拖动、复位及键盘操作复用 Pele 自带能力。
|
|
21
|
+
|
|
22
|
+
打开后查看每张图,而不是仅检查命令成功。浏览器发生绘图错误时,Pele 会在图旁显示错误;这仍是不完整的交付,需要修复并重新检查。
|
|
23
|
+
|
|
24
|
+
## 主题与颜色含义
|
|
25
|
+
|
|
26
|
+
使用 Pele 官方站点的 Flexoki 浅色与深色配色:浅色为暖白 `#fffcf0`,深色为墨黑 `#100f0f`。页面内提供切换按钮;命令加 `--theme dark` 可指定初始深色,默认浅色。颜色通过同一份 CSS 变量切换,不重新布局图,也不改变缩放位置。
|
|
27
|
+
|
|
28
|
+
| 信息角色 | Mermaid 类名 | 色系 |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| 输入、上下文与事实 | `fugueInput` | 青色 |
|
|
31
|
+
| 程序处理步骤 | `fugueProcess` | 蓝色 |
|
|
32
|
+
| 判断、确认与等待 | `fugueDecision` | 黄色 |
|
|
33
|
+
| 外部系统交互 | `fugueExternal` | 紫色 |
|
|
34
|
+
| 完成与目标达成 | `fugueSuccess` | 绿色 |
|
|
35
|
+
| 失败与阻断 | `fugueFailure` | 红色 |
|
|
36
|
+
| 跳过与未执行 | `fugueSkipped` | 灰色 |
|
|
37
|
+
|
|
38
|
+
流程图用标准 Mermaid 类标注,类的主题样式由本层 HTML 提供:
|
|
39
|
+
|
|
40
|
+
```mermaid
|
|
41
|
+
flowchart LR
|
|
42
|
+
input[任务事实]:::fugueInput --> check{来源是否完整}:::fugueDecision
|
|
43
|
+
check -->|完整| run[执行处理]:::fugueProcess
|
|
44
|
+
check -->|缺失| stop[失败并保留事实]:::fugueFailure
|
|
45
|
+
run --> done[交付结果]:::fugueSuccess
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
状态图在展示副本中增加 `class s0 fugueInput` 这样的颜色角色即可,保留原 `class`、状态、边、编号和规则标记。已标记的错误或修复状态保持原有结果配色;缺陷路径继续使用蓝框及原有线宽。不得为了颜色修改模型或把失败状态改成通过。
|
|
49
|
+
|
|
50
|
+
时序图用标准 `box rgba(...) 分组名` 区分参与方,透明填色能与浅、深背景叠合;分组名写明职责。需要突出某段交互时可使用 `rect rgba(...)`。采用上表的对应色系,不按参与方顺序随机分色。
|
|
51
|
+
|
|
52
|
+
页面图例只列出图中实际使用的颜色角色。颜色增强信息分组,文字标签继续承载含义。两种主题均需检查实际节点填色、标签和连线,测量文字与其真实背景的对比度。
|
|
53
|
+
|
|
54
|
+
配色来源:[官方站点 Flexoki 主题定义](https://github.com/obsidianmd/pele/blob/bdbad5df4dea13b9a14a83a92aed62c4769e49f5/website/src/styles/pele-theme.scss)。
|
|
55
|
+
|
|
56
|
+
## 集成到已有 HTML
|
|
57
|
+
|
|
58
|
+
可以调整生成页面的布局、说明和 CSS,保留每张图的容器、源码数据与初始化脚本。也可按以下原则自行组装:
|
|
59
|
+
|
|
60
|
+
- 使用 Pele 的公开 `render()` / `mount()` API;浏览器单文件使用 `pele/global` 导出的包并内嵌它,不依赖 CDN。
|
|
61
|
+
- 把 SVG 放在相应说明旁。多张图各用独立的 `idPrefix`,避免箭头、渐变、标题和描述的 ID 冲突。
|
|
62
|
+
- 图示 CSS 位于 `assets/diagram.css`,生成时内嵌到 HTML。用 `--pele-bg`、`--pele-fg`、`--pele-muted`、`--pele-line`、`--pele-surface`、`--pele-surface-alt`、`--pele-border` 等 CSS 变量匹配宿主页面。源图的 `classDef` 可能表达错误、修复和缺陷路径,不为统一配色覆盖这些语义。
|
|
63
|
+
- 用 `mount()` 读取实际中文字体并随容器宽度重排;需要缩放时使用它的 `zoom` 选项,不自行实现图布局或缩放系统。仍然过密的图应先拆分视角,而不是继续缩小文字。
|
|
64
|
+
- 内嵌源码、标题和说明时正确转义 HTML 与脚本结束标签。图中禁用外部图片以保持离线显示,保留 Pele 的许可文本。
|
|
65
|
+
|
|
66
|
+
Pele 使用自己的布局与主题;Mermaid 的 `themeVariables` 不生效,任意 HTML 标签也不受支持。遇到不支持的语法,按原含义调整或拆图后重新验证;状态与缺陷路径的含义必须保持,不静默改用另一套渲染器。
|
|
67
|
+
|
|
68
|
+
官方依据:[API](https://pele.run/api)、[主题](https://pele.run/theming)、[兼容性](https://pele.run/compatibility)、[安全与嵌入](https://pele.run/security)。
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { mkdir, mkdtemp, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { basename, dirname, extname, join, resolve } from 'node:path';
|
|
7
|
+
import { pathToFileURL } from 'node:url';
|
|
8
|
+
import { parseArgs } from 'node:util';
|
|
9
|
+
|
|
10
|
+
const version = '1.12.0';
|
|
11
|
+
const fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif";
|
|
12
|
+
const html = text => text.replace(/[&<>"']/g, char => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[char]);
|
|
13
|
+
const json = value => JSON.stringify(value).replace(/</g, '\\u003c');
|
|
14
|
+
const roles = [
|
|
15
|
+
['fugueInput', '输入事实'], ['fugueProcess', '处理步骤'], ['fugueDecision', '判断与等待'],
|
|
16
|
+
['fugueExternal', '外部交互'], ['fugueSuccess', '完成'], ['fugueFailure', '失败与阻断'], ['fugueSkipped', '跳过'],
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
async function loadPele() {
|
|
20
|
+
const cache = join(process.env.XDG_CACHE_HOME || join(homedir(), '.cache'), 'fugue-show-me', `pele-${version}`);
|
|
21
|
+
if (!existsSync(join(cache, 'node_modules', 'pele', 'package.json'))) {
|
|
22
|
+
await mkdir(dirname(cache), { recursive: true });
|
|
23
|
+
const staging = await mkdtemp(`${cache}-`);
|
|
24
|
+
try {
|
|
25
|
+
await writeFile(join(staging, 'package.json'), '{"private":true}\n');
|
|
26
|
+
console.error(`首次安装 pele@${version},缓存位置:${cache}`);
|
|
27
|
+
const result = spawnSync('npm', ['install', '--no-audit', '--no-fund', '--ignore-scripts', '--save-exact', `pele@${version}`], {
|
|
28
|
+
cwd: staging,
|
|
29
|
+
encoding: 'utf8',
|
|
30
|
+
env: { ...process.env, PATH: `${dirname(process.execPath)}${process.platform === 'win32' ? ';' : ':'}${process.env.PATH || ''}` },
|
|
31
|
+
shell: process.platform === 'win32',
|
|
32
|
+
});
|
|
33
|
+
if (result.status !== 0) throw new Error(result.error?.message || result.stderr || 'Pele 安装失败');
|
|
34
|
+
try { await rename(staging, cache); }
|
|
35
|
+
catch (error) { if (!existsSync(join(cache, 'node_modules', 'pele', 'package.json'))) throw error; }
|
|
36
|
+
} finally {
|
|
37
|
+
await rm(staging, { recursive: true, force: true });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const require = createRequire(join(cache, 'package.json'));
|
|
41
|
+
const { render } = await import(pathToFileURL(require.resolve('pele')).href);
|
|
42
|
+
const bundle = await readFile(require.resolve('pele/global'), 'utf8');
|
|
43
|
+
const license = await readFile(join(dirname(require.resolve('pele/package.json')), 'LICENSE'), 'utf8');
|
|
44
|
+
return { render, bundle, license };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function main() {
|
|
48
|
+
const { values, positionals } = parseArgs({ options: {
|
|
49
|
+
out: { type: 'string', short: 'o' }, title: { type: 'string' }, theme: { type: 'string', default: 'light' }, help: { type: 'boolean', short: 'h' },
|
|
50
|
+
}, allowPositionals: true });
|
|
51
|
+
const usage = '用法:node render-html.mjs --out 说明.html [--title 标题] [--theme light|dark] 总览.mmd [细节.mmd ...]';
|
|
52
|
+
if (values.help) { console.log(usage); return; }
|
|
53
|
+
if (!values.out || !positionals.length) throw new Error(usage);
|
|
54
|
+
if (!['light', 'dark'].includes(values.theme)) throw new Error('主题必须是 light 或 dark');
|
|
55
|
+
const sources = await Promise.all(positionals.map(async file => ({
|
|
56
|
+
title: basename(file, extname(file)), source: await readFile(file, 'utf8'),
|
|
57
|
+
})));
|
|
58
|
+
const { render, bundle, license } = await loadPele();
|
|
59
|
+
const diagrams = sources.map((diagram, index) => {
|
|
60
|
+
const id = `diagram-${index + 1}`;
|
|
61
|
+
try {
|
|
62
|
+
const { svg } = render(diagram.source, { idPrefix: id, fontFamily, images: false });
|
|
63
|
+
return { ...diagram, id, svg };
|
|
64
|
+
} catch (error) { throw new Error(`${positionals[index]}:${error.message}`, { cause: error }); }
|
|
65
|
+
});
|
|
66
|
+
const title = values.title || '图解说明';
|
|
67
|
+
const css = await readFile(new URL('../assets/diagram.css', import.meta.url), 'utf8');
|
|
68
|
+
const nodeClasses = diagrams.flatMap(({ svg }) => [...svg.matchAll(/<g\b[^>]*\bclass="([^"]*)"/g)].map(match => match[1].split(/\s+/)))
|
|
69
|
+
.filter(classes => classes.includes('pele-node') && !classes.some(name => /wrong|fixed|mixed|after|worse/i.test(name)));
|
|
70
|
+
const usedRoles = roles.filter(([name]) => nodeClasses.some(classes => classes.includes(name)));
|
|
71
|
+
const legend = usedRoles.length ? `<ul class="legend" aria-label="颜色含义">${usedRoles.map(([name, label]) => `<li class="${name}"><i aria-hidden="true"></i>${label}</li>`).join('')}</ul>` : '';
|
|
72
|
+
const sections = diagrams.map(({ title, id, svg }) => `<section aria-labelledby="${id}-heading">
|
|
73
|
+
<h2 id="${id}-heading">${html(title)}</h2>
|
|
74
|
+
<div class="diagram" id="${id}" role="region" aria-label="${html(title)}">${svg}</div>
|
|
75
|
+
</section>`).join('\n');
|
|
76
|
+
const page = `<!doctype html>
|
|
77
|
+
<html lang="zh-CN" data-theme="${values.theme}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
78
|
+
<title>${html(title)}</title><style>
|
|
79
|
+
:root { --font: ${fontFamily}; }
|
|
80
|
+
${css}
|
|
81
|
+
</style></head><body><main>
|
|
82
|
+
<header><div class="page-heading"><h1>${html(title)}</h1><div class="theme-controls" role="group" aria-label="页面主题"><button type="button" data-theme-option="light" aria-pressed="${values.theme === 'light'}">浅色</button><button type="button" data-theme-option="dark" aria-pressed="${values.theme === 'dark'}">深色</button></div></div><p>先看全局,再查看需要的细节。图内可缩放、拖动和复位;聚焦图后也可使用 +、−、0 和方向键。</p></header>
|
|
83
|
+
<nav aria-label="图示目录">${diagrams.map(({ id, title }) => `<a href="#${id}-heading">${html(title)}</a>`).join('')}</nav>
|
|
84
|
+
${legend}
|
|
85
|
+
${sections}
|
|
86
|
+
<noscript>当前展示静态图;启用 JavaScript 后可使用自适应布局和缩放。</noscript>
|
|
87
|
+
</main>
|
|
88
|
+
<script id="diagram-sources" type="application/json">${json(diagrams.map(({ id, source }) => ({ id, source })))}</script>
|
|
89
|
+
<script>/* Pele ${version}\n${license.replace(/\*\//g, '* /')}\n*/\n${bundle.replace(/<\/script/gi, '<\\/script')}</script>
|
|
90
|
+
<script>
|
|
91
|
+
for (const button of document.querySelectorAll('[data-theme-option]')) {
|
|
92
|
+
button.addEventListener('click', () => {
|
|
93
|
+
document.documentElement.dataset.theme = button.dataset.themeOption;
|
|
94
|
+
for (const option of document.querySelectorAll('[data-theme-option]')) {
|
|
95
|
+
option.setAttribute('aria-pressed', String(option === button));
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
for (const { id, source } of JSON.parse(document.getElementById('diagram-sources').textContent)) {
|
|
100
|
+
const container = document.getElementById(id);
|
|
101
|
+
pele.mount(container, source, {
|
|
102
|
+
idPrefix: id,
|
|
103
|
+
images: false,
|
|
104
|
+
zoom: { always: true, labels: { zoomIn: '放大', zoomOut: '缩小', reset: '显示全图' } },
|
|
105
|
+
onRender() { container.dataset.rendered = 'true'; delete container.dataset.renderError; },
|
|
106
|
+
onError(error) { container.dataset.renderError = String(error); },
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
</script></body></html>`;
|
|
110
|
+
const output = resolve(values.out);
|
|
111
|
+
await mkdir(dirname(output), { recursive: true });
|
|
112
|
+
await writeFile(output, page);
|
|
113
|
+
console.log(`已生成 ${diagrams.length} 张图:${output}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
main().catch(error => { console.error(error.message); process.exitCode = 1; });
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: show-me
|
|
3
|
+
description: Help the user understand the current topic visually with concise diagrams, code-shape sketches, and focused HTML artifacts.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Help the user understand the current topic of conversation visually. Skip the preamble and keep prose brief. Pick the smallest view that makes the key point clear.
|
|
8
|
+
|
|
9
|
+
- Show logic or an algorithm as pseudocode:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
on(save)
|
|
13
|
+
if content is unchanged
|
|
14
|
+
return cached result
|
|
15
|
+
write new content
|
|
16
|
+
return fresh result
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
- Show runtime control flow as a call tree:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
submitForm
|
|
23
|
+
createSession
|
|
24
|
+
persistPrompt
|
|
25
|
+
launchAgent
|
|
26
|
+
navigateToSession
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Show UI structure as a component tree, including state and module boundaries that matter:
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
<SessionPage> (apps/example/src/routes/session.tsx)
|
|
33
|
+
useSessionEvents()
|
|
34
|
+
<SessionToolbar>
|
|
35
|
+
<RunSkillButton> (packages/ui)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- Show file responsibility or a broad refactor as a shallow file tree:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
src/
|
|
42
|
+
├── commands/ # parses user actions
|
|
43
|
+
├── sessions/ # owns session state
|
|
44
|
+
└── transport/ # sends API requests
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- Show component interaction, control flow, or data flow with Mermaid:
|
|
48
|
+
|
|
49
|
+
```mermaid
|
|
50
|
+
sequenceDiagram
|
|
51
|
+
participant User
|
|
52
|
+
participant UI
|
|
53
|
+
participant Daemon
|
|
54
|
+
User->>UI: choose command
|
|
55
|
+
UI->>Daemon: send expanded prompt
|
|
56
|
+
Daemon-->>UI: stream result
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- Use `diff` when the point is what changes and the surrounding shape already exists. Match the diff shape to the topic.
|
|
60
|
+
|
|
61
|
+
For a component change:
|
|
62
|
+
|
|
63
|
+
```diff
|
|
64
|
+
<SessionPage>
|
|
65
|
+
useSessionEvents()
|
|
66
|
+
<SessionToolbar>
|
|
67
|
+
+ <RunSkillButton />
|
|
68
|
+
<SessionTimeline>
|
|
69
|
+
+ <SkillResultCard />
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
For a file-layout change:
|
|
73
|
+
|
|
74
|
+
```diff
|
|
75
|
+
src/
|
|
76
|
+
├── commands/
|
|
77
|
+
+│ └── show-me.ts # expands the slash command
|
|
78
|
+
├── sessions/
|
|
79
|
+
-└── transport.ts
|
|
80
|
+
+└── transport/
|
|
81
|
+
+ ├── client.ts
|
|
82
|
+
+ └── stream.ts
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
For a call-tree or call-stack change:
|
|
86
|
+
|
|
87
|
+
```diff
|
|
88
|
+
submitForm
|
|
89
|
+
createSession
|
|
90
|
+
persistPrompt
|
|
91
|
+
+ expandSkillMention
|
|
92
|
+
launchAgent
|
|
93
|
+
- navigateToSession
|
|
94
|
+
+ navigateToSession
|
|
95
|
+
+ subscribeToEvents
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
For a state or control-flow change:
|
|
99
|
+
|
|
100
|
+
```diff
|
|
101
|
+
on(save)
|
|
102
|
+
- write content
|
|
103
|
+
+ if content is unchanged
|
|
104
|
+
+ return cached result
|
|
105
|
+
+ write new content
|
|
106
|
+
+ invalidate cache
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- Show the whole block when most of it is new, when omitted context would hide ownership or order, or when the user needs a copyable target shape:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
function expandSkill(command: string): string {
|
|
113
|
+
const skillName = command.slice(1)
|
|
114
|
+
return `use the ${skillName} skill`
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- For a visual UI, layout, state comparison, or concept too dense for Mermaid, write one focused HTML file — a diagram, an infographic, or a short slide deck, whichever fits the point. Match the product's colors, type, spacing, and components; use real labels and data; support desktop and mobile. Then open it for the user:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
Bash(open path/to/show-me-{description}.html)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### guidance
|
|
125
|
+
|
|
126
|
+
Place each visual next to the short text it supports. Keep only the calls, files, props, states, and boundaries needed to answer the user's current question or the options to resolve the current discussion point.
|
|
127
|
+
|
|
128
|
+
You may use one of these, you may use several, it is unlikely you will use all of them. Use your judgement and don't overwhelm the user.
|