@rune-kit/rune 2.2.1 → 2.2.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 +39 -13
- package/compiler/__tests__/adapters.test.js +109 -0
- package/compiler/__tests__/openclaw-adapter.test.js +149 -140
- package/compiler/__tests__/pack-split.test.js +145 -145
- package/compiler/__tests__/parser.test.js +3 -3
- package/compiler/__tests__/pipeline.test.js +110 -0
- package/compiler/__tests__/skill-validation.test.js +148 -0
- package/compiler/__tests__/transformer.test.js +70 -0
- package/compiler/__tests__/transforms.test.js +92 -0
- package/compiler/adapters/antigravity.js +5 -6
- package/compiler/adapters/claude.js +1 -1
- package/compiler/adapters/codex.js +69 -77
- package/compiler/adapters/cursor.js +5 -6
- package/compiler/adapters/generic.js +5 -6
- package/compiler/adapters/index.js +3 -3
- package/compiler/adapters/openclaw.js +146 -150
- package/compiler/adapters/opencode.js +78 -86
- package/compiler/adapters/windsurf.js +5 -6
- package/compiler/bin/rune.js +52 -21
- package/compiler/doctor.js +19 -7
- package/compiler/emitter.js +11 -18
- package/compiler/parser.js +5 -5
- package/compiler/transformer.js +3 -5
- package/compiler/transforms/branding.js +5 -4
- package/compiler/transforms/compliance.js +40 -40
- package/compiler/transforms/frontmatter.js +1 -1
- package/compiler/transforms/hooks.js +12 -14
- package/compiler/transforms/subagents.js +1 -3
- package/compiler/transforms/tool-names.js +1 -1
- package/docs/ANTIGRAVITY-GAP-ANALYSIS.md +369 -0
- package/docs/ARCHITECTURE.md +332 -0
- package/docs/COMMUNITY-PACKS.md +109 -0
- package/docs/CONTRIBUTING-L4.md +215 -0
- package/docs/CROSS-IDE-ANALYSIS.md +164 -0
- package/docs/EXTENSION-TEMPLATE.md +108 -0
- package/docs/MESH-RULES.md +34 -0
- package/docs/MULTI-PLATFORM.md +804 -0
- package/docs/SKILL-DEPTH-AUDIT.md +191 -0
- package/docs/SKILL-TEMPLATE.md +72 -0
- package/docs/TRADE-MATRIX.md +327 -0
- package/docs/VERSIONING.md +91 -0
- package/docs/VISION.md +263 -0
- package/docs/assets/demo-subtitles.srt +215 -0
- package/docs/assets/end-card.html +276 -0
- package/docs/assets/mesh-diagram.html +654 -0
- package/docs/assets/thumbnail.html +295 -0
- package/docs/guides/cli.md +403 -0
- package/docs/guides/index.html +1387 -0
- package/docs/index.html +739 -0
- package/docs/references/claudekit-analysis.md +414 -0
- package/docs/references/voltagent-analysis.md +189 -0
- package/docs/script.js +277 -0
- package/docs/skills/index.html +832 -0
- package/docs/style.css +600 -0
- package/docs/video-demo-plan.md +172 -0
- package/extensions/security/PACK.md +4 -3
- package/extensions/security/skills/defense-in-depth.md +103 -0
- package/extensions/ui/PACK.md +2 -0
- package/extensions/ui/skills/design-decision.md +10 -0
- package/extensions/ui/skills/palette-picker.md +11 -0
- package/hooks/.gitkeep +0 -0
- package/hooks/auto-format/index.cjs +48 -0
- package/hooks/context-watch/index.cjs +68 -0
- package/hooks/hooks.json +99 -0
- package/hooks/metrics-collector/index.cjs +42 -0
- package/hooks/post-session-reflect/index.cjs +153 -0
- package/hooks/pre-compact/index.cjs +95 -0
- package/hooks/pre-tool-guard/index.cjs +68 -0
- package/hooks/run-hook +17 -0
- package/hooks/run-hook.cjs +16 -0
- package/hooks/run-hook.cmd +1 -0
- package/hooks/secrets-scan/index.cjs +100 -0
- package/hooks/session-start/index.cjs +65 -0
- package/hooks/typecheck/index.cjs +65 -0
- package/package.json +16 -4
- package/references/ui-pro-max-data/LICENSE-UI-PRO-MAX +21 -0
- package/references/ui-pro-max-data/charts.csv +26 -0
- package/references/ui-pro-max-data/colors.csv +162 -0
- package/references/ui-pro-max-data/styles.csv +85 -0
- package/references/ui-pro-max-data/typography.csv +74 -0
- package/references/ui-pro-max-data/ui-reasoning.csv +162 -0
- package/references/ui-pro-max-data/ux-guidelines.csv +100 -0
- package/skills/ba/SKILL.md +10 -0
- package/skills/completion-gate/SKILL.md +34 -1
- package/skills/context-engine/SKILL.md +13 -0
- package/skills/cook/SKILL.md +71 -0
- package/skills/debug/SKILL.md +71 -1
- package/skills/design/SKILL.md +11 -0
- package/skills/fix/SKILL.md +26 -1
- package/skills/plan/SKILL.md +23 -6
- package/skills/review/SKILL.md +2 -0
- package/skills/skill-forge/SKILL.md +94 -3
- package/skills/test/SKILL.md +44 -2
- package/skills/verification/SKILL.md +60 -2
package/README.md
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/banner.svg" alt="Rune — Skill Mesh for AI Coding Assistants" width="100%">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>Less skills. Deeper connections.</strong><br>
|
|
7
|
+
A lean, interconnected skill ecosystem for AI coding assistants.<br>
|
|
8
|
+
58 skills · 200+ mesh connections · 8 platforms · MIT
|
|
9
|
+
</p>
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
<p align="center">
|
|
12
|
+
<strong>Claude Code</strong> (native plugin) · <strong>Cursor</strong> · <strong>Windsurf</strong> · <strong>Google Antigravity</strong> · <strong>OpenAI Codex</strong> · <strong>OpenCode</strong> · any AI IDE
|
|
13
|
+
</p>
|
|
8
14
|
|
|
9
15
|
## Why Rune?
|
|
10
16
|
|
|
@@ -20,9 +26,11 @@ Mesh: A ↔ B ↔ C (B fails = A reaches C via D→E)
|
|
|
20
26
|
D ↔ E ↔ F
|
|
21
27
|
```
|
|
22
28
|
|
|
23
|
-
## What's New (v2.2.
|
|
29
|
+
## What's New (v2.2.2)
|
|
24
30
|
|
|
25
|
-
- **
|
|
31
|
+
- **UI/UX Pro Max Integration** — 161 palettes, 84 styles, 73 font pairings, 161 reasoning rules from [UI/UX Pro Max](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill) (MIT, 42.8k★) meshed into `design` skill + `@rune/ui` pack
|
|
32
|
+
- **11 Core Skill Enrichments** — deviation rules, repair operators, evidence quality gate, decision classification, debug knowledge base, CSO discipline, YAGNI pushback, formal pause/resume
|
|
33
|
+
- **Enforcement Upgrade** — Antigravity-level IDE compliance: 5-type Request Classifier, File Ownership Matrix, Self-Verification HARD-GATE, Routing Proof, Clarification Gate, Phase Transition Protocol
|
|
26
34
|
- **All 14 Free Packs Deep** — every L4 extension pack now exceeds 500 lines of production-ready patterns and code examples
|
|
27
35
|
- **8 Platform Adapters** — Claude Code, Cursor, Windsurf, Google Antigravity, OpenAI Codex, OpenCode, OpenClaw, Generic
|
|
28
36
|
- **58 Core Skills** — +3 since v2.1.0: adversary (red team), sentinel-env (env validation), chrome-ext pack
|
|
@@ -62,11 +70,12 @@ Rune started as a **Claude Code plugin** and now compiles to **every major AI ID
|
|
|
62
70
|
### Claude Code (Native Plugin)
|
|
63
71
|
|
|
64
72
|
```bash
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
/plugin install rune@rune-kit
|
|
73
|
+
# Install via Claude Code CLI
|
|
74
|
+
claude plugin add rune-kit/rune
|
|
68
75
|
```
|
|
69
76
|
|
|
77
|
+
Or add manually in `~/.claude/settings.json` under `installed_plugins`.
|
|
78
|
+
|
|
70
79
|
Full mesh: subagents, hooks, adaptive routing, mesh analytics.
|
|
71
80
|
|
|
72
81
|
### Cursor / Windsurf / Antigravity / Any IDE
|
|
@@ -315,7 +324,20 @@ Business department packs for product, sales, and data teams. Same PACK.md forma
|
|
|
315
324
|
| @rune-pro/data-science | data-exploration, sql-advanced, visualization, statistical-testing, dashboards | Data Science |
|
|
316
325
|
| @rune-pro/support | ticket-triage, response-drafting, knowledge-base, escalation, faq, metrics | Customer Support |
|
|
317
326
|
|
|
318
|
-
**$49 lifetime**
|
|
327
|
+
**$49 lifetime** — [rune-kit/rune-pro](https://github.com/rune-kit/rune-pro)
|
|
328
|
+
|
|
329
|
+
### Rune Business (Enterprise)
|
|
330
|
+
|
|
331
|
+
Department packs for finance, legal, HR, and cross-system search. Requires Rune Free core.
|
|
332
|
+
|
|
333
|
+
| Pack | Skills | For |
|
|
334
|
+
|------|--------|-----|
|
|
335
|
+
| @rune-pro/finance | budget-planning, expense-analysis, revenue-forecasting, financial-reporting, compliance, invoicing, cash-flow | Finance Ops |
|
|
336
|
+
| @rune-pro/legal | contract-review, compliance-check, policy-generator, nda-triage, ip-protection, incident-legal | Legal & Compliance |
|
|
337
|
+
| @rune-pro/hr | jd-writer, resume-screener, interview-planner, scorecard, onboarding, comp-benchmarker, policy-writer | HR & Recruiting |
|
|
338
|
+
| @rune-pro/enterprise-search | query-planner, source-connector, result-merger, permission-guard, knowledge-graph, search-analytics | Knowledge Retrieval |
|
|
339
|
+
|
|
340
|
+
**$149 lifetime** — [rune-kit/rune-business](https://github.com/rune-kit/rune-business)
|
|
319
341
|
|
|
320
342
|
## Multi-Platform Compiler
|
|
321
343
|
|
|
@@ -349,15 +371,19 @@ See [docs/MULTI-PLATFORM.md](docs/MULTI-PLATFORM.md) for the full architecture.
|
|
|
349
371
|
|
|
350
372
|
```
|
|
351
373
|
Core Skills: 58 (L0: 1 │ L1: 5 │ L2: 27 │ L3: 25)
|
|
352
|
-
Extension Packs: 14 free + 4 pro +
|
|
374
|
+
Extension Packs: 14 free + 4 pro + 4 business
|
|
353
375
|
Mesh Connections: 200+ cross-references
|
|
354
376
|
Connections/Skill: 3.4 avg
|
|
355
377
|
Platforms: 8 (Claude Code, Cursor, Windsurf, Antigravity, Codex, OpenCode, OpenClaw, Generic)
|
|
356
378
|
Compiler: ~1400 LOC (parser + 8 transforms + 8 adapters + CLI)
|
|
357
379
|
Quality: 58/58 skills with Output Format, Sharp Edges, Done When, Cost Profile
|
|
358
|
-
Pack Depth:
|
|
380
|
+
Pack Depth: 22 packs total (14 free + 4 pro + 4 business, all free packs rated Deep)
|
|
359
381
|
```
|
|
360
382
|
|
|
383
|
+
## Acknowledgments
|
|
384
|
+
|
|
385
|
+
- **[UI/UX Pro Max](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill)** (MIT, 42.8k★) — Design intelligence databases powering Rune's `design` skill and `@rune/ui` pack: 161 color palettes, 84 UI styles, 73 font pairings, 99 UX guidelines, 161 industry reasoning rules.
|
|
386
|
+
|
|
361
387
|
## License
|
|
362
388
|
|
|
363
389
|
MIT
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { describe, test } from 'node:test';
|
|
3
|
+
import { getAdapter, listPlatforms } from '../adapters/index.js';
|
|
4
|
+
|
|
5
|
+
// --- Adapter registry ---
|
|
6
|
+
|
|
7
|
+
test('listPlatforms returns all 8 platform adapters', () => {
|
|
8
|
+
const adapters = listPlatforms();
|
|
9
|
+
const expected = ['claude', 'cursor', 'windsurf', 'antigravity', 'codex', 'opencode', 'openclaw', 'generic'];
|
|
10
|
+
for (const name of expected) {
|
|
11
|
+
assert.ok(adapters.includes(name), `missing adapter: ${name}`);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('getAdapter returns adapter by name', () => {
|
|
16
|
+
const cursor = getAdapter('cursor');
|
|
17
|
+
assert.strictEqual(cursor.name, 'cursor');
|
|
18
|
+
assert.strictEqual(cursor.fileExtension, '.mdc');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('getAdapter throws for unknown adapter', () => {
|
|
22
|
+
assert.throws(() => getAdapter('nonexistent'), /unknown/i);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// --- Shared adapter contract ---
|
|
26
|
+
|
|
27
|
+
const REQUIRED_METHODS = [
|
|
28
|
+
'transformReference',
|
|
29
|
+
'transformToolName',
|
|
30
|
+
'generateHeader',
|
|
31
|
+
'generateFooter',
|
|
32
|
+
'transformSubagentInstruction',
|
|
33
|
+
'postProcess',
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const REQUIRED_PROPS = ['name', 'outputDir', 'fileExtension', 'skillPrefix', 'skillSuffix'];
|
|
37
|
+
|
|
38
|
+
const ADAPTER_NAMES = ['cursor', 'windsurf', 'antigravity', 'codex', 'opencode', 'generic'];
|
|
39
|
+
|
|
40
|
+
for (const adapterName of ADAPTER_NAMES) {
|
|
41
|
+
describe(`${adapterName} adapter contract`, () => {
|
|
42
|
+
const adapter = getAdapter(adapterName);
|
|
43
|
+
|
|
44
|
+
test('has all required properties', () => {
|
|
45
|
+
for (const prop of REQUIRED_PROPS) {
|
|
46
|
+
assert.ok(prop in adapter, `${adapterName} missing prop: ${prop}`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('has all required methods', () => {
|
|
51
|
+
for (const method of REQUIRED_METHODS) {
|
|
52
|
+
assert.strictEqual(typeof adapter[method], 'function', `${adapterName} missing method: ${method}`);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('transformReference handles plain and backticked refs', () => {
|
|
57
|
+
const plain = adapter.transformReference('cook', 'cook');
|
|
58
|
+
assert.ok(typeof plain === 'string' && plain.length > 0);
|
|
59
|
+
|
|
60
|
+
const backticked = adapter.transformReference('cook', '`cook`');
|
|
61
|
+
assert.ok(typeof backticked === 'string' && backticked.length > 0);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('transformToolName maps known tools', () => {
|
|
65
|
+
const result = adapter.transformToolName('Read');
|
|
66
|
+
assert.ok(typeof result === 'string' && result.length > 0);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('generateHeader returns string', () => {
|
|
70
|
+
const skill = { name: 'test', layer: 'L2', group: 'workflow', description: 'Test skill' };
|
|
71
|
+
const header = adapter.generateHeader(skill);
|
|
72
|
+
assert.strictEqual(typeof header, 'string');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('generateFooter includes Rune branding', () => {
|
|
76
|
+
const footer = adapter.generateFooter();
|
|
77
|
+
assert.ok(footer.includes('Rune'), `${adapterName} footer missing Rune branding`);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('postProcess strips Claude-specific directives', () => {
|
|
81
|
+
const input = 'context: fork\ncontent\nagent: general-purpose\nmore';
|
|
82
|
+
const result = adapter.postProcess(input);
|
|
83
|
+
assert.ok(!result.includes('context: fork'));
|
|
84
|
+
assert.ok(!result.includes('agent: general-purpose'));
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// --- Cursor-specific ---
|
|
90
|
+
|
|
91
|
+
test('cursor adapter generates .mdc frontmatter with alwaysApply', () => {
|
|
92
|
+
const cursor = getAdapter('cursor');
|
|
93
|
+
const l0Skill = { name: 'router', layer: 'L0', group: 'meta', description: 'Routes tasks' };
|
|
94
|
+
const l2Skill = { name: 'fix', layer: 'L2', group: 'workflow', description: 'Fix code' };
|
|
95
|
+
|
|
96
|
+
const l0Header = cursor.generateHeader(l0Skill);
|
|
97
|
+
assert.ok(l0Header.includes('alwaysApply: true'));
|
|
98
|
+
|
|
99
|
+
const l2Header = cursor.generateHeader(l2Skill);
|
|
100
|
+
assert.ok(l2Header.includes('alwaysApply: false'));
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// --- Codex-specific ---
|
|
104
|
+
|
|
105
|
+
test('codex adapter uses skill directories', () => {
|
|
106
|
+
const codex = getAdapter('codex');
|
|
107
|
+
assert.strictEqual(codex.useSkillDirectories, true);
|
|
108
|
+
assert.strictEqual(codex.skillFileName, 'SKILL.md');
|
|
109
|
+
});
|
|
@@ -1,140 +1,149 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { test } from 'node:test';
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
// --- Adapter shape ---
|
|
6
|
-
|
|
7
|
-
test('openclaw adapter has all required properties', () => {
|
|
8
|
-
const required = [
|
|
9
|
-
'name',
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
assert.strictEqual(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
assert.strictEqual(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
test('transformToolName
|
|
51
|
-
assert.strictEqual(openclaw.transformToolName('
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
assert.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
assert.ok(
|
|
76
|
-
assert.ok(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
assert.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
assert.ok(ts.includes('
|
|
131
|
-
assert.ok(ts.includes('export default plugin'));
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
assert.ok(ts.includes('
|
|
140
|
-
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
import openclaw from '../adapters/openclaw.js';
|
|
4
|
+
|
|
5
|
+
// --- Adapter shape ---
|
|
6
|
+
|
|
7
|
+
test('openclaw adapter has all required properties', () => {
|
|
8
|
+
const required = [
|
|
9
|
+
'name',
|
|
10
|
+
'outputDir',
|
|
11
|
+
'fileExtension',
|
|
12
|
+
'skillPrefix',
|
|
13
|
+
'skillSuffix',
|
|
14
|
+
'transformReference',
|
|
15
|
+
'transformToolName',
|
|
16
|
+
'generateHeader',
|
|
17
|
+
'generateFooter',
|
|
18
|
+
'transformSubagentInstruction',
|
|
19
|
+
'postProcess',
|
|
20
|
+
'generateManifest',
|
|
21
|
+
'generateEntryPoint',
|
|
22
|
+
];
|
|
23
|
+
for (const prop of required) {
|
|
24
|
+
assert.ok(prop in openclaw, `missing property: ${prop}`);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('openclaw adapter has correct name and outputDir', () => {
|
|
29
|
+
assert.strictEqual(openclaw.name, 'openclaw');
|
|
30
|
+
assert.strictEqual(openclaw.outputDir, '.openclaw/rune/skills');
|
|
31
|
+
assert.strictEqual(openclaw.fileExtension, '.md');
|
|
32
|
+
assert.strictEqual(openclaw.skillPrefix, 'rune-');
|
|
33
|
+
assert.strictEqual(openclaw.skillSuffix, '');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// --- transformReference ---
|
|
37
|
+
|
|
38
|
+
test('transformReference returns correct skill file reference', () => {
|
|
39
|
+
const result = openclaw.transformReference('cook', 'cook');
|
|
40
|
+
assert.strictEqual(result, 'rune-cook.md');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('transformReference preserves backticks', () => {
|
|
44
|
+
const result = openclaw.transformReference('plan', '`plan`');
|
|
45
|
+
assert.strictEqual(result, '`rune-plan.md`');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// --- transformToolName ---
|
|
49
|
+
|
|
50
|
+
test('transformToolName maps Claude Code tools to OpenClaw equivalents', () => {
|
|
51
|
+
assert.strictEqual(openclaw.transformToolName('Read'), 'read_file');
|
|
52
|
+
assert.strictEqual(openclaw.transformToolName('Write'), 'write_file');
|
|
53
|
+
assert.strictEqual(openclaw.transformToolName('Edit'), 'edit_file');
|
|
54
|
+
assert.strictEqual(openclaw.transformToolName('Bash'), 'run_command');
|
|
55
|
+
assert.strictEqual(openclaw.transformToolName('Glob'), 'glob');
|
|
56
|
+
assert.strictEqual(openclaw.transformToolName('Grep'), 'grep');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('transformToolName passes through unknown tools', () => {
|
|
60
|
+
assert.strictEqual(openclaw.transformToolName('CustomTool'), 'CustomTool');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// --- generateHeader / generateFooter ---
|
|
64
|
+
|
|
65
|
+
test('generateHeader produces valid markdown', () => {
|
|
66
|
+
const skill = { name: 'cook', layer: 'L1', group: 'orchestrator' };
|
|
67
|
+
const header = openclaw.generateHeader(skill);
|
|
68
|
+
assert.ok(header.startsWith('# rune-cook'));
|
|
69
|
+
assert.ok(header.includes('L1'));
|
|
70
|
+
assert.ok(header.includes('orchestrator'));
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('generateFooter includes Rune branding', () => {
|
|
74
|
+
const footer = openclaw.generateFooter();
|
|
75
|
+
assert.ok(footer.includes('Rune Skill Mesh'));
|
|
76
|
+
assert.ok(footer.includes('github.com/rune-kit/rune'));
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// --- postProcess ---
|
|
80
|
+
|
|
81
|
+
test('postProcess strips Claude-specific directives', () => {
|
|
82
|
+
const input = 'context: fork\nsome content\nagent: general-purpose\nmore content';
|
|
83
|
+
const result = openclaw.postProcess(input);
|
|
84
|
+
assert.ok(!result.includes('context: fork'));
|
|
85
|
+
assert.ok(!result.includes('agent: general-purpose'));
|
|
86
|
+
assert.ok(result.includes('some content'));
|
|
87
|
+
assert.ok(result.includes('more content'));
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// --- generateManifest ---
|
|
91
|
+
|
|
92
|
+
test('generateManifest returns valid openclaw.plugin.json structure', () => {
|
|
93
|
+
const skills = [
|
|
94
|
+
{ name: 'cook', layer: 'L1', group: 'orchestrator' },
|
|
95
|
+
{ name: 'plan', layer: 'L2', group: 'workflow' },
|
|
96
|
+
];
|
|
97
|
+
const pluginJson = { version: '2.1.1', name: 'rune' };
|
|
98
|
+
|
|
99
|
+
const manifest = openclaw.generateManifest(skills, pluginJson);
|
|
100
|
+
|
|
101
|
+
assert.strictEqual(manifest.id, 'rune');
|
|
102
|
+
assert.strictEqual(manifest.name, 'Rune');
|
|
103
|
+
assert.strictEqual(manifest.kind, 'skills');
|
|
104
|
+
assert.strictEqual(manifest.version, '2.1.1');
|
|
105
|
+
assert.ok(Array.isArray(manifest.skills));
|
|
106
|
+
assert.deepStrictEqual(manifest.skills, ['./skills']);
|
|
107
|
+
assert.ok(manifest.configSchema);
|
|
108
|
+
assert.ok(manifest.configSchema.jsonSchema);
|
|
109
|
+
assert.strictEqual(manifest.configSchema.jsonSchema.type, 'object');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('generateManifest defaults version when missing', () => {
|
|
113
|
+
const manifest = openclaw.generateManifest([], {});
|
|
114
|
+
assert.strictEqual(manifest.version, '0.0.0');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// --- generateEntryPoint ---
|
|
118
|
+
|
|
119
|
+
test('generateEntryPoint returns valid TypeScript with register(api)', () => {
|
|
120
|
+
const skills = [
|
|
121
|
+
{ name: 'cook', layer: 'L1', group: 'orchestrator', description: 'Feature orchestrator' },
|
|
122
|
+
{ name: 'fix', layer: 'L2', group: 'workflow', description: 'Apply fixes' },
|
|
123
|
+
];
|
|
124
|
+
const routerContent = '# skill-router\n\nRoute all tasks.';
|
|
125
|
+
|
|
126
|
+
const ts = openclaw.generateEntryPoint(skills, routerContent);
|
|
127
|
+
|
|
128
|
+
assert.ok(ts.includes('register(api'));
|
|
129
|
+
assert.ok(ts.includes('before_agent_start'));
|
|
130
|
+
assert.ok(ts.includes('prependSystemContext'));
|
|
131
|
+
assert.ok(ts.includes('export default plugin'));
|
|
132
|
+
assert.ok(ts.includes('cook'));
|
|
133
|
+
assert.ok(ts.includes('fix'));
|
|
134
|
+
assert.ok(ts.includes('skill-router'));
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('generateEntryPoint handles empty router content', () => {
|
|
138
|
+
const ts = openclaw.generateEntryPoint([], '');
|
|
139
|
+
assert.ok(ts.includes('register(api'));
|
|
140
|
+
assert.ok(ts.includes('export default plugin'));
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test('generateEntryPoint escapes backticks in router content', () => {
|
|
144
|
+
const routerContent = 'Use `cook` skill for code tasks';
|
|
145
|
+
const ts = openclaw.generateEntryPoint([], routerContent);
|
|
146
|
+
// Should not have unescaped backticks inside template literal
|
|
147
|
+
assert.ok(!ts.includes('Use `cook`'));
|
|
148
|
+
assert.ok(ts.includes('\\`cook\\`'));
|
|
149
|
+
});
|