@topmindspace/tms-skills 0.1.0 → 0.1.2

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.
Files changed (102) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +9 -3
  3. package/bin/tms-skills.js +200 -160
  4. package/package.json +12 -9
  5. package/top-ppt-html/README.md +162 -254
  6. package/top-ppt-html/SKILL.md +126 -111
  7. package/top-ppt-html/assets/examples/2026-09-09-architecture-graphite-dark.html +3926 -3926
  8. package/top-ppt-html/assets/examples/2026-09-09-architecture-graphite-dark.model.json +167 -167
  9. package/top-ppt-html/assets/examples/2026-09-09-presentation-business-blue.html +4325 -4325
  10. package/top-ppt-html/assets/examples/2026-09-09-presentation-business-blue.model.json +320 -320
  11. package/top-ppt-html/assets/examples/2026-09-09-research-mckinsey.html +5527 -5527
  12. package/top-ppt-html/assets/examples/2026-09-09-research-mckinsey.model.json +913 -913
  13. package/top-ppt-html/assets/pptx-export.js +1944 -1944
  14. package/top-ppt-html/assets/style-gallery.html +589 -589
  15. package/top-ppt-html/assets/templates/architecture.html +3728 -3728
  16. package/top-ppt-html/assets/templates/engine.css +840 -840
  17. package/top-ppt-html/assets/templates/presentation.html +3738 -3738
  18. package/top-ppt-html/assets/templates/research.html +4017 -4017
  19. package/top-ppt-html/assets/templates/ui.js +520 -520
  20. package/top-ppt-html/assets/theme-overview-architecture.png +0 -0
  21. package/top-ppt-html/assets/theme-overview-research.png +0 -0
  22. package/top-ppt-html/assets/theme-overview.png +0 -0
  23. package/top-ppt-html/evals/prompts.csv +15 -15
  24. package/top-ppt-html/evals/rubric.schema.json +25 -25
  25. package/top-ppt-html/evals/run_evals.py +220 -220
  26. package/top-ppt-html/evals/trace.example.json +16 -16
  27. package/top-ppt-html/package-lock.json +186 -0
  28. package/top-ppt-html/package.json +11 -11
  29. package/top-ppt-html/references/charts-basic.md +624 -624
  30. package/top-ppt-html/references/charts-discipline.md +110 -108
  31. package/top-ppt-html/references/charts-extended.md +482 -482
  32. package/top-ppt-html/references/charts.md +37 -28
  33. package/top-ppt-html/references/components-atoms.md +624 -624
  34. package/top-ppt-html/references/components.md +30 -30
  35. package/top-ppt-html/references/content-rules.md +510 -490
  36. package/top-ppt-html/references/default-surface.md +61 -0
  37. package/top-ppt-html/references/design-system.md +478 -478
  38. package/top-ppt-html/references/failure-modes.md +227 -214
  39. package/top-ppt-html/references/high-fidelity.md +127 -127
  40. package/top-ppt-html/references/icons.md +176 -397
  41. package/top-ppt-html/references/infographics-stats.md +308 -308
  42. package/top-ppt-html/references/infographics-structure.md +226 -226
  43. package/top-ppt-html/references/infographics.md +43 -43
  44. package/top-ppt-html/references/layout-grammar.md +325 -315
  45. package/top-ppt-html/references/layouts-architecture.md +108 -108
  46. package/top-ppt-html/references/layouts-combo.md +600 -600
  47. package/top-ppt-html/references/layouts-research.md +160 -160
  48. package/top-ppt-html/references/modes.md +259 -254
  49. package/top-ppt-html/references/outline-design.md +275 -275
  50. package/top-ppt-html/references/playbook.md +284 -266
  51. package/top-ppt-html/references/pptx-export.md +227 -209
  52. package/top-ppt-html/references/presentation-craft.md +69 -0
  53. package/top-ppt-html/references/styles.md +370 -370
  54. package/top-ppt-html/references/tech-design.md +138 -138
  55. package/top-ppt-html/scripts/audit_css.py +109 -109
  56. package/top-ppt-html/scripts/audit_docs.py +176 -176
  57. package/top-ppt-html/scripts/audit_skill.py +231 -220
  58. package/top-ppt-html/scripts/audit_styles.py +351 -351
  59. package/top-ppt-html/scripts/build_examples.py +55 -2276
  60. package/top-ppt-html/scripts/build_pptx.js +2386 -2380
  61. package/top-ppt-html/scripts/capture_theme_overview.js +79 -78
  62. package/top-ppt-html/scripts/checks_html.py +166 -127
  63. package/top-ppt-html/scripts/cross_verify.py +298 -294
  64. package/top-ppt-html/scripts/env_probe.py +158 -158
  65. package/top-ppt-html/scripts/extract_model.py +210 -210
  66. package/top-ppt-html/scripts/extract_snippet.py +374 -374
  67. package/top-ppt-html/scripts/gen_channel_a.js +214 -214
  68. package/top-ppt-html/scripts/layout-constants.json +111 -18
  69. package/top-ppt-html/scripts/lib_layout_regions.js +410 -412
  70. package/top-ppt-html/scripts/measure_height.py +178 -178
  71. package/top-ppt-html/scripts/negative_tests.py +433 -307
  72. package/top-ppt-html/scripts/package_skill.py +294 -291
  73. package/top-ppt-html/scripts/prepare_images.py +341 -341
  74. package/top-ppt-html/scripts/probe_image_export.py +187 -188
  75. package/top-ppt-html/scripts/quality_gate.py +309 -301
  76. package/top-ppt-html/scripts/recommend_layout.py +384 -0
  77. package/top-ppt-html/scripts/regression.py +308 -308
  78. package/top-ppt-html/scripts/render_compare.py +275 -275
  79. package/top-ppt-html/scripts/render_from_model.py +698 -698
  80. package/top-ppt-html/scripts/scaffold_report.py +1054 -1054
  81. package/top-ppt-html/scripts/section-file-map.json +104 -104
  82. package/top-ppt-html/scripts/smoke_pptx.sh +30 -0
  83. package/top-ppt-html/scripts/sync_runtime.py +659 -662
  84. package/top-ppt-html/scripts/validate_pptx.py +1579 -1510
  85. package/top-ppt-html/scripts/validate_report.py +1755 -1456
  86. package/top-ppt-html/assets/examples/2026-09-09-architecture-spectrum.html +0 -3926
  87. package/top-ppt-html/assets/examples/2026-09-09-architecture-spectrum.model.json +0 -168
  88. package/top-ppt-html/assets/examples/2026-09-09-presentation-apple-mono.html +0 -4325
  89. package/top-ppt-html/assets/examples/2026-09-09-presentation-apple-mono.model.json +0 -321
  90. package/top-ppt-html/assets/examples/2026-09-09-presentation-brand-red.html +0 -4325
  91. package/top-ppt-html/assets/examples/2026-09-09-presentation-brand-red.model.json +0 -321
  92. package/top-ppt-html/assets/examples/2026-09-09-research-deep-teal.html +0 -5527
  93. package/top-ppt-html/assets/examples/2026-09-09-research-deep-teal.model.json +0 -914
  94. package/top-ppt-html/assets/examples/2026-09-09-research-indigo-violet.html +0 -5527
  95. package/top-ppt-html/assets/examples/2026-09-09-research-indigo-violet.model.json +0 -914
  96. package/top-ppt-html/assets/examples/2026-09-09-research-warm-sand.html +0 -5527
  97. package/top-ppt-html/assets/examples/2026-09-09-research-warm-sand.model.json +0 -914
  98. package/top-ppt-html/assets/theme-overview-presentation.png +0 -0
  99. package/top-ppt-html/references/design-system-engine.md +0 -235
  100. package/top-ppt-html/references/industry-benchmark.md +0 -105
  101. package/top-ppt-html/references/reform-plan.md +0 -252
  102. package/top-ppt-html/scripts/layout_slots.json +0 -830
package/CHANGELOG.md CHANGED
@@ -1,5 +1,81 @@
1
+ ## Unreleased
2
+
3
+ ## 0.1.2 — 2026-09-24
4
+
5
+ ### top-ppt-html · P2 cleanup(advanced 按需 · Mode A 次级骨架 · icons 压缩)
6
+
7
+ - **Advanced charts 按需**:默认读面 = `charts-discipline` + 核图 8;`charts-extended.md` **禁止预读**,仅意图命中 `extract_snippet.py --chart`。`charts.variety.preferCoreFirst` + validate WARN(A/B);advanced **计入** `minTypes`(不降 `presentation=4`,不缩 registry)。
8
+ - **Mode A 骨架分层**:主力 P1–P4+P6/P10;次级 P7–P9/P11–P12(`layoutSystem.modeSkels` + layout-grammar / default-surface / recommend_layout 同口径);画廊侧重主力。
9
+ - **icons.md 压缩**:语义表 + 禁区 + 尺寸档 + 高频 20 SVG(~8.7KB);完整枚举 → `docs/archive/refs/icons-catalog.md`;package 仍 REQUIRED。
10
+ - **docs 对齐**:SKILL / playbook / presentation-craft / modes / charts 门面同步;Fast Mode + 长文溢出序保持不变。
11
+
12
+ ### Installer
13
+
14
+ - 安装器 `@topmindspace/tms-skills` → **0.1.2**(随技能包内容更新)。
15
+
16
+
17
+
18
+ ### top-ppt-html · Long-text / Quality round(反截断 + 门禁加深)
19
+
20
+ - **反截断政策**:Mode A / content-rules / presentation-craft「长文与信息承载」——溢出顺序固定为 重构→拆页/分章→换形态→有限 fontShrink;**禁止**静默截断 / 砍 so-what / 为疏朗删实质。单页字数改预警(presentation char 1800),不为「字多」单独 FAIL。
21
+ - **结构引导取代硬砍刀**:列表/卡片 `maxItemChars` 等改为引导 + prefer;checklist 同步。
22
+ - **layout-qa 加深**:`LAYOUT_QA_TRUNCATION` / `OVERFLOW_NO_SPLIT` / `HALF_EMPTY` / `ALIGN_RHYTHM`;presentation `--strict` 仍自动 layout-qa。负例 L4–L6。
23
+ - **recommend_layout**:高容量意图 → 多页序列(议程→主张→证据卡→明细),禁一页塞爆。
24
+ - **P1-3 charts facade**:纪律优先 → 核图 8 → extended 按需;**不降** `minTypes.presentation=4`。
25
+ - **P1-4 会场字号**:pptx-export venue 表(小会议室 / 默认 / 礼堂)。
26
+ - **P1-6 chrome**:跨页页脚 y 漂移 `CHROME_DRIFT` WARN + 文档说明。
27
+
28
+ ### top-ppt-html · Presentation Craft(Mode A 工艺)
29
+
30
+ - **P0-1 图表多样性(用户明确保留)**:**不降** `minTypes.presentation`(仍为 **4**);registry/advanced 图种保留。纪律改为「按内容选型拉开多样」+ 禁反模式(简单全幅 / 极偏 donut / 为过门禁硬上冷门图);playbook §五 / layout-qa 同步。
31
+ - **P0-2 default-surface**:升为 Mode A / Fast 演示主读面(12 页型 + 8 核图 + V1–V4;P5–P12/advanced 按需);SKILL L2 索引指向。
32
+ - **P0-3 layout-qa 默认**:`validate_report --strict` 在 presentation 下自动 `--layout-qa`;`quality_gate` 同口径;B/C 不强制。
33
+ - **P0-4 主张标题**:Mode A action/claim title(禁话题标签)写入 content-rules / modes;校验 WARN。
34
+ - **P0-5 `presentation-craft.md`**:中英术语一页纸清单(one idea / 3s / whitespace / CRAP / motion=none / WCAG…);package REQUIRED。
35
+ - **P1**:fillTarget A 58–75% + intentional whitespace 豁免;`recommend_layout` 偏 V1–V4、降 donut 默认权重;Fast 路演/汇报/发布/演讲/demo→A;motion=none 铁律短句。
36
+
37
+ ### top-ppt-html · Batch 3(瘦身)
38
+
39
+ - **归档 L2**:`industry-benchmark.md` / `design-system-engine.md` → `docs/archive/refs/`(生成路径不读)。
40
+ - **layoutSlots 单源**:删除 `scripts/layout_slots.json`;`lib_layout_regions.js` / `sync_runtime.py` 只读 `layout-constants.layoutSlots`。
41
+ - **示例**:`assets/examples/` 仅留 3 份黄金样张(每模式 1);其余 → `docs/archive/examples/`;`build_examples.py` 瘦身为自检(全量脚本归档)。
42
+ - **主题 PNG**:`theme-overview*.png` 量化压缩约 −70%。
43
+ - **default-surface.md**:12 页型 + 8 图 + V1–V4 速查;playbook §五标注默认 8 核心图。
44
+ - **package**:MIN refs ≥20、examples ≥3;`recommend_layout.py` 入 REQUIRED;README 缩为安装+命令索引。
45
+
46
+ ### top-ppt-html · Batch 2(布局选型 + layout-qa + PPTX 对齐)
47
+
48
+ - **recommend_layout.py**:`--mode A|B|C` + `--intent` / `--from-model` / `--stdin` → `{pageType,skel,chart,rationale,v?}`(V1–V4 / 极偏禁 donut / sizeByComplexity)。
49
+ - **validate_report.py --layout-qa**:缺 data-skel、连续同骨架、极偏 donut、演示简单全幅、V 契约;negative_tests 增 L1–L3。
50
+ - **cross_verify.py** 默认 SKIP,`--full-ab` 才跑;regression 同口径。
51
+ - **build_pptx.js** 尊重 `layoutPreset`(缺省由 pageToPreset 回填,写入备注)。
52
+ - **smoke_pptx.sh** + CI skill-gates 冒烟:extract_model → build_pptx → validate_pptx --strict。
53
+
1
54
  # Changelog
2
55
 
56
+ ## Unreleased
57
+
58
+ ### top-ppt-html 0.1.1 — Batch 1(工作流单写 · Fast Mode)
59
+
60
+ - **模型单写统一**:playbook / SKILL / pptx-export 命令链均为 scaffold → 只填 `REPORT_MODEL` → `render_from_model --inplace` → `validate_report --strict`(禁 HTML/模型双写)。
61
+ - **`render_from_model.py` 纳入 package REQUIRED**;references 最小篇数注释对齐实有数量(≥24)。
62
+ - **Fast Mode**:触发词跳过 Gate 0 + 六项;默认 B/mckinsey/light 等;标准路径仍为硬门禁;`audit_skill` 适配豁免声明。
63
+ - **归档** `references/reform-plan.md` → `docs/archive/reform-plan.md`;硬门禁改指 `qualityGates` + `failure-modes`。
64
+ - 技能 `package.json` 版本对齐仓库叙事 `0.1.1`(LC 仍为 `0.1`)。
65
+
66
+ ## 0.1.1 — 2026-09-24
67
+
68
+ ### Fixes (P0 / P1)
69
+
70
+ - **Release 顺序与稳健性**:Privacy → 技能门禁 → Package → Collect → GitHub Release → **npm publish(已发布则跳过,避免 E409)** → 再 Prune。
71
+ - **Prune 策略**:只删旧 GitHub Release(保留 2 个);**不再删除 git tags**。
72
+ - **多技能发现**:`scripts/discover_skills.js` + CI/Release 动态打包/门禁;`npm run sync:files` 同步 `package.json` `files`。
73
+ - **CLI**:校验 skill id;目标目录已存在时须 `--force`;文档口径与 README 对齐(npm 推荐 / GitHub 跟 HEAD)。
74
+ - **python3**:根与技能 `package.json`、workflows 统一 `python3`。
75
+ - **打包门禁**:`references/layout-grammar.md` 纳入 REQUIRED;去掉与 `theme-overview.png` 完全重复的 `theme-overview-presentation.png`。
76
+ - **Lockfile**:提交 `top-ppt-html/package-lock.json`;CI 优先 `npm ci --omit=dev`。
77
+ - **npm 2.x**:文档警告勿装 `^2`;提供 `scripts/deprecate-npm-2x.sh`(须维护者本地 npm 登录后执行)。
78
+
3
79
  ## 0.1.0 — 2026-09-24
4
80
 
5
81
  首个公开版本。
package/README.md CHANGED
@@ -18,6 +18,12 @@
18
18
 
19
19
  两条通道,装出来同一套技能。**npm = 钉版本快照**;**GitHub = 跟仓库 HEAD**。
20
20
 
21
+
22
+ > **警告 / Warning**:不要安装 `@topmindspace/tms-skills@^2`。npm 上残留的 **2.0.0–2.1.1** 是仓库重置前的过时线;当前线是 **0.1.x**(`latest` 亦指向 0.1.x)。维护者登录 npm 后可运行 `scripts/deprecate-npm-2x.sh` 标记弃用。
23
+ >
24
+ > Do **not** install `^2`. Versions 2.0.0–2.1.1 are obsolete after the repo reset; use **0.1.x**. Maintainers with npm auth should run `scripts/deprecate-npm-2x.sh`.
25
+
26
+
21
27
  ### npm(推荐)
22
28
 
23
29
  ```bash
@@ -74,7 +80,7 @@ tms-skills/
74
80
  | tag `vX.Y.Z` | Release + zip | **自动 publish** |
75
81
 
76
82
  - **push 不会更新 npm**;必须 bump 版本并打 tag。
77
- - **Release 只保留最近 2 个**(CI 自动清理);npm 可钉任意历史版本。
83
+ - **Release 只保留最近 2 个**(CI 只删旧 Release,**git tags 保留**);npm 可钉任意历史版本。
78
84
  - 安装器与技能 **版本各自独立**;默认 patch/minor,major 仅破坏性变更。
79
85
 
80
86
  详见 [docs/PUBLISHING.md](./docs/PUBLISHING.md)。
@@ -84,7 +90,7 @@ tms-skills/
84
90
  | 工作流 | 触发 | 做什么 |
85
91
  |--------|------|--------|
86
92
  | `ci.yml` | push / PR | 打包门禁、审计、隐私扫描、CLI 冒烟 |
87
- | `release.yml` | tag `v*` | 技能 zip → Release;npm publish;Release 保留 2 个 |
93
+ | `release.yml` | tag `v*` | 门禁 → zip → Release → npm publish(已存在则跳过)→ prune Release 留 2(tags 保留) |
88
94
 
89
95
  ```bash
90
96
  npm run check && npm run audit && npm run privacy
@@ -95,7 +101,7 @@ npm run check && npm run audit && npm run privacy
95
101
  1. 根目录建 `<skill-id>/`,`SKILL.md` 的 `name` 与目录一致。
96
102
  2. 人类说明写 `README.md`;智能体入口保持 `SKILL.md`。
97
103
  3. 发布前 `scripts/package_skill.py --check`。
98
- 4. 登记:根 README、`package.json` 的 `files`、`ci.yml`、`CHANGELOG.md`。
104
+ 4. 登记:根 README、`npm run sync:files`、`CHANGELOG.md`(CI 按发现的技能跑门禁,无需再硬编码)。
99
105
 
100
106
  ## 许可证
101
107
 
package/bin/tms-skills.js CHANGED
@@ -1,160 +1,200 @@
1
- #!/usr/bin/env node
2
- /**
3
- * tms-skills — TopMindspace agent skills installer
4
- *
5
- * Usage (GitHub is the primary install source — npm publish is optional):
6
- * npx github:topmindspace/tms-skills list
7
- * npx github:topmindspace/tms-skills install top-ppt-html
8
- * npx github:topmindspace/tms-skills install top-ppt-html --to ./skills-out
9
- * npx @topmindspace/tms-skills install top-ppt-html # only after npm publish
10
- */
11
- 'use strict';
12
-
13
- const fs = require('fs');
14
- const path = require('path');
15
-
16
- const ROOT = path.resolve(__dirname, '..');
17
- // Skills live at repo root (one directory per skill with SKILL.md).
18
- const INFRA_DIRS = new Set(['bin', 'docs', 'scripts', 'node_modules', 'dist', 'release-assets']);
19
-
20
- function die(msg, code = 1) {
21
- console.error(msg);
22
- process.exit(code);
23
- }
24
-
25
- function skillDir(skillId) {
26
- return path.join(ROOT, skillId);
27
- }
28
-
29
- function listSkillIds() {
30
- return fs
31
- .readdirSync(ROOT, { withFileTypes: true })
32
- .filter((d) => d.isDirectory() && !INFRA_DIRS.has(d.name) && !d.name.startsWith('.'))
33
- .filter((d) => fs.existsSync(path.join(ROOT, d.name, 'SKILL.md')))
34
- .map((d) => d.name)
35
- .sort();
36
- }
37
-
38
- function readSkillMeta(skillId) {
39
- const skillPath = skillDir(skillId);
40
- const skillMd = path.join(skillPath, 'SKILL.md');
41
- if (!fs.existsSync(skillMd)) return { id: skillId, description: '' };
42
- const text = fs.readFileSync(skillMd, 'utf8');
43
- const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
44
- if (!m) return { id: skillId, description: '' };
45
- const desc = (m[1].match(/^description:\s*"(.*)"\s*$/m) || m[1].match(/^description:\s*(.+)\s*$/m) || [])[1] || '';
46
- return { id: skillId, description: String(desc).slice(0, 120) };
47
- }
48
-
49
- function resolveDefaultTarget() {
50
- const candidates = [
51
- path.join(process.cwd(), '.agents', 'skills'),
52
- path.join(process.cwd(), '.claude', 'skills'),
53
- path.join(process.cwd(), '.mimocode', 'skills'),
54
- path.join(process.env.HOME || process.env.USERPROFILE || '', '.claude', 'skills'),
55
- path.join(process.env.HOME || process.env.USERPROFILE || '', '.agents', 'skills'),
56
- ];
57
- for (const dir of candidates) {
58
- if (dir && fs.existsSync(path.dirname(dir))) {
59
- return dir;
60
- }
61
- }
62
- return path.join(process.cwd(), '.agents', 'skills');
63
- }
64
-
65
- function copyDir(src, dest) {
66
- fs.mkdirSync(dest, { recursive: true });
67
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
68
- const s = path.join(src, entry.name);
69
- const d = path.join(dest, entry.name);
70
- if (entry.isDirectory()) {
71
- if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === '__pycache__') continue;
72
- copyDir(s, d);
73
- } else if (entry.isFile()) {
74
- if (entry.name.endsWith('.pyc')) continue;
75
- fs.copyFileSync(s, d);
76
- }
77
- }
78
- }
79
-
80
- function install(skillId, targetRoot) {
81
- const src = skillDir(skillId);
82
- if (!fs.existsSync(path.join(src, 'SKILL.md'))) {
83
- die(`Skill not found: ${skillId}\nAvailable: ${listSkillIds().join(', ') || '(none)'}`);
84
- }
85
- const dest = path.join(targetRoot, skillId);
86
- fs.mkdirSync(targetRoot, { recursive: true });
87
- if (fs.existsSync(dest)) {
88
- fs.rmSync(dest, { recursive: true, force: true });
89
- }
90
- copyDir(src, dest);
91
- console.log(`Installed ${skillId}`);
92
- console.log(` from ${src}`);
93
- console.log(` to ${dest}`);
94
- console.log('');
95
- console.log('Optional (PPTX export only):');
96
- console.log(` cd "${dest}" && npm install`);
97
- }
98
-
99
- function usage() {
100
- console.log(`tms-skills — install TopMindspace agent skills
101
-
102
- Usage:
103
- tms-skills list
104
- tms-skills install <skill-id> [--to <dir>]
105
- tms-skills help
106
-
107
- Examples:
108
- npx github:topmindspace/tms-skills list
109
- npx github:topmindspace/tms-skills install top-ppt-html
110
- npx github:topmindspace/tms-skills install top-ppt-html --to ./.agents/skills
111
-
112
- # Optional npm package (only after @topmindspace/tms-skills is published):
113
- npx @topmindspace/tms-skills install top-ppt-html
114
- `);
115
- }
116
-
117
- function main(argv) {
118
- const args = argv.slice(2);
119
- const cmd = args[0];
120
-
121
- if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
122
- usage();
123
- return;
124
- }
125
-
126
- if (cmd === 'list' || cmd === 'ls') {
127
- const ids = listSkillIds();
128
- if (!ids.length) {
129
- console.log('No skills found in package.');
130
- return;
131
- }
132
- for (const id of ids) {
133
- const meta = readSkillMeta(id);
134
- console.log(`${id}`);
135
- if (meta.description) console.log(` ${meta.description}…`);
136
- }
137
- return;
138
- }
139
-
140
- if (cmd === 'install') {
141
- const skillId = args[1];
142
- if (!skillId || skillId.startsWith('-')) {
143
- die('Missing skill id.\n\n' + usage());
144
- }
145
- let to = null;
146
- for (let i = 2; i < args.length; i++) {
147
- if (args[i] === '--to' || args[i] === '-t') {
148
- to = args[++i];
149
- if (!to) die('Option --to requires a directory path.');
150
- }
151
- }
152
- const targetRoot = to ? path.resolve(to) : resolveDefaultTarget();
153
- install(skillId, targetRoot);
154
- return;
155
- }
156
-
157
- die(`Unknown command: ${cmd}\n\n` + usage());
158
- }
159
-
160
- main(process.argv);
1
+ #!/usr/bin/env node
2
+ /**
3
+ * tms-skills — TopMindspace agent skills installer
4
+ *
5
+ * Recommended channel (when published): npm @topmindspace/tms-skills
6
+ * GitHub npx remains available for HEAD / offline clone.
7
+ *
8
+ * Usage:
9
+ * npx @topmindspace/tms-skills list
10
+ * npx @topmindspace/tms-skills install top-ppt-html
11
+ * npx @topmindspace/tms-skills install top-ppt-html --to ./skills-out
12
+ * npx @topmindspace/tms-skills install top-ppt-html --force
13
+ * npx github:topmindspace/tms-skills install top-ppt-html # follow repo HEAD
14
+ */
15
+ 'use strict';
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+
20
+ const ROOT = path.resolve(__dirname, '..');
21
+ // Skills live at repo root (one directory per skill with SKILL.md).
22
+ const INFRA_DIRS = new Set(['bin', 'docs', 'scripts', 'node_modules', 'dist', 'release-assets']);
23
+ const SKILL_ID_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
24
+
25
+ function die(msg, code = 1) {
26
+ console.error(msg);
27
+ process.exit(code);
28
+ }
29
+
30
+ function skillDir(skillId) {
31
+ return path.join(ROOT, skillId);
32
+ }
33
+
34
+ function assertSkillId(skillId) {
35
+ if (!skillId || typeof skillId !== 'string') {
36
+ die('Missing skill id.\n\n' + usageText());
37
+ }
38
+ if (
39
+ skillId.includes('..') ||
40
+ skillId.includes('/') ||
41
+ skillId.includes('\\') ||
42
+ path.isAbsolute(skillId) ||
43
+ !SKILL_ID_RE.test(skillId)
44
+ ) {
45
+ die(
46
+ `Invalid skill id: ${JSON.stringify(skillId)}\n` +
47
+ 'Skill ids must match ^[a-z0-9]+(?:-[a-z0-9]+)*$ (no paths, dots, or slashes).'
48
+ );
49
+ }
50
+ }
51
+
52
+ function listSkillIds() {
53
+ return fs
54
+ .readdirSync(ROOT, { withFileTypes: true })
55
+ .filter((d) => d.isDirectory() && !INFRA_DIRS.has(d.name) && !d.name.startsWith('.'))
56
+ .filter((d) => fs.existsSync(path.join(ROOT, d.name, 'SKILL.md')))
57
+ .map((d) => d.name)
58
+ .sort();
59
+ }
60
+
61
+ function readSkillMeta(skillId) {
62
+ const skillPath = skillDir(skillId);
63
+ const skillMd = path.join(skillPath, 'SKILL.md');
64
+ if (!fs.existsSync(skillMd)) return { id: skillId, description: '' };
65
+ const text = fs.readFileSync(skillMd, 'utf8');
66
+ const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
67
+ if (!m) return { id: skillId, description: '' };
68
+ const desc = (m[1].match(/^description:\s*"(.*)"\s*$/m) || m[1].match(/^description:\s*(.+)\s*$/m) || [])[1] || '';
69
+ return { id: skillId, description: String(desc).slice(0, 120) };
70
+ }
71
+
72
+ function resolveDefaultTarget() {
73
+ const candidates = [
74
+ path.join(process.cwd(), '.agents', 'skills'),
75
+ path.join(process.cwd(), '.claude', 'skills'),
76
+ path.join(process.cwd(), '.mimocode', 'skills'),
77
+ path.join(process.env.HOME || process.env.USERPROFILE || '', '.claude', 'skills'),
78
+ path.join(process.env.HOME || process.env.USERPROFILE || '', '.agents', 'skills'),
79
+ ];
80
+ for (const dir of candidates) {
81
+ if (dir && fs.existsSync(path.dirname(dir))) {
82
+ return dir;
83
+ }
84
+ }
85
+ return path.join(process.cwd(), '.agents', 'skills');
86
+ }
87
+
88
+ function copyDir(src, dest) {
89
+ fs.mkdirSync(dest, { recursive: true });
90
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
91
+ const s = path.join(src, entry.name);
92
+ const d = path.join(dest, entry.name);
93
+ if (entry.isDirectory()) {
94
+ if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === '__pycache__') continue;
95
+ copyDir(s, d);
96
+ } else if (entry.isFile()) {
97
+ if (entry.name.endsWith('.pyc')) continue;
98
+ fs.copyFileSync(s, d);
99
+ }
100
+ }
101
+ }
102
+
103
+ function install(skillId, targetRoot, { force = false } = {}) {
104
+ assertSkillId(skillId);
105
+ const src = skillDir(skillId);
106
+ if (!fs.existsSync(path.join(src, 'SKILL.md'))) {
107
+ die(`Skill not found: ${skillId}\nAvailable: ${listSkillIds().join(', ') || '(none)'}`);
108
+ }
109
+ const dest = path.join(targetRoot, skillId);
110
+ fs.mkdirSync(targetRoot, { recursive: true });
111
+ if (fs.existsSync(dest)) {
112
+ if (!force) {
113
+ die(
114
+ `Destination already exists: ${dest}\n` +
115
+ 'Refusing to overwrite. Pass --force (or -f) to replace.'
116
+ );
117
+ }
118
+ fs.rmSync(dest, { recursive: true, force: true });
119
+ }
120
+ copyDir(src, dest);
121
+ console.log(`Installed ${skillId}`);
122
+ console.log(` from ${src}`);
123
+ console.log(` to ${dest}`);
124
+ console.log('');
125
+ console.log('Optional (PPTX export only):');
126
+ console.log(` cd "${dest}" && npm install`);
127
+ }
128
+
129
+ function usageText() {
130
+ return `tms-skills — install TopMindspace agent skills
131
+
132
+ Usage:
133
+ tms-skills list
134
+ tms-skills install <skill-id> [--to <dir>] [--force|-f]
135
+ tms-skills help
136
+
137
+ Examples (npm recommended when published):
138
+ npx @topmindspace/tms-skills list
139
+ npx @topmindspace/tms-skills install top-ppt-html
140
+ npx @topmindspace/tms-skills install top-ppt-html --to ./.agents/skills
141
+ npx @topmindspace/tms-skills install top-ppt-html --force
142
+
143
+ # Follow repo HEAD:
144
+ npx github:topmindspace/tms-skills install top-ppt-html
145
+ `;
146
+ }
147
+
148
+ function usage() {
149
+ console.log(usageText());
150
+ }
151
+
152
+ function main(argv) {
153
+ const args = argv.slice(2);
154
+ const cmd = args[0];
155
+
156
+ if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
157
+ usage();
158
+ return;
159
+ }
160
+
161
+ if (cmd === 'list' || cmd === 'ls') {
162
+ const ids = listSkillIds();
163
+ if (!ids.length) {
164
+ console.log('No skills found in package.');
165
+ return;
166
+ }
167
+ for (const id of ids) {
168
+ const meta = readSkillMeta(id);
169
+ console.log(`${id}`);
170
+ if (meta.description) console.log(` ${meta.description}…`);
171
+ }
172
+ return;
173
+ }
174
+
175
+ if (cmd === 'install') {
176
+ const skillId = args[1];
177
+ if (!skillId || skillId.startsWith('-')) {
178
+ die('Missing skill id.\n\n' + usageText());
179
+ }
180
+ let to = null;
181
+ let force = false;
182
+ for (let i = 2; i < args.length; i++) {
183
+ if (args[i] === '--to' || args[i] === '-t') {
184
+ to = args[++i];
185
+ if (!to) die('Option --to requires a directory path.');
186
+ } else if (args[i] === '--force' || args[i] === '-f') {
187
+ force = true;
188
+ } else {
189
+ die(`Unknown option: ${args[i]}\n\n` + usageText());
190
+ }
191
+ }
192
+ const targetRoot = to ? path.resolve(to) : resolveDefaultTarget();
193
+ install(skillId, targetRoot, { force });
194
+ return;
195
+ }
196
+
197
+ die(`Unknown command: ${cmd}\n\n` + usageText());
198
+ }
199
+
200
+ main(process.argv);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@topmindspace/tms-skills",
3
- "version": "0.1.0",
4
- "description": "TopMindspace 智能体技能 monorepo — 通过 GitHub npx 安装技能(top-ppt-html 等)。",
3
+ "version": "0.1.2",
4
+ "description": "TopMindspace 智能体技能 monorepo — 通过 npm / GitHub npx 安装技能(top-ppt-html 等)。",
5
5
  "license": "MIT",
6
6
  "author": "TopMindspace",
7
7
  "repository": {
@@ -26,21 +26,24 @@
26
26
  },
27
27
  "files": [
28
28
  "bin",
29
- "top-ppt-html",
30
29
  "README.md",
31
30
  "LICENSE",
32
- "CHANGELOG.md"
31
+ "CHANGELOG.md",
32
+ "top-ppt-html"
33
33
  ],
34
34
  "engines": {
35
35
  "node": ">=18"
36
36
  },
37
37
  "scripts": {
38
38
  "list": "node bin/tms-skills.js list",
39
- "install:skills": "node bin/tms-skills.js install top-ppt-html",
40
- "check": "python top-ppt-html/scripts/package_skill.py --check",
41
- "privacy": "python scripts/ci_privacy_scan.py",
42
- "audit": "python top-ppt-html/scripts/audit_styles.py && python top-ppt-html/scripts/audit_docs.py && python top-ppt-html/scripts/audit_skill.py && python top-ppt-html/scripts/audit_css.py",
43
- "package:skill": "python top-ppt-html/scripts/package_skill.py"
39
+ "discover": "node scripts/discover_skills.js",
40
+ "sync:files": "node scripts/sync_npm_files.js",
41
+ "prepack": "node scripts/sync_npm_files.js",
42
+ "install:skills": "node -e \"const {discoverSkills}=require('./scripts/discover_skills'); const {spawnSync}=require('child_process'); for (const id of discoverSkills()) { const r=spawnSync(process.execPath,['bin/tms-skills.js','install',id],{stdio:'inherit'}); if(r.status) process.exit(r.status||1); }\"",
43
+ "check": "node scripts/run_skill_gates.js check",
44
+ "privacy": "python3 scripts/ci_privacy_scan.py",
45
+ "audit": "node scripts/run_skill_gates.js audit",
46
+ "package:skill": "node scripts/run_skill_gates.js package"
44
47
  },
45
48
  "publishConfig": {
46
49
  "access": "public"