@rune-kit/rune 2.1.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/LICENSE +21 -0
- package/README.md +357 -0
- package/agents/.gitkeep +0 -0
- package/agents/architect.md +29 -0
- package/agents/asset-creator.md +11 -0
- package/agents/audit.md +11 -0
- package/agents/autopsy.md +11 -0
- package/agents/brainstorm.md +11 -0
- package/agents/browser-pilot.md +11 -0
- package/agents/coder.md +29 -0
- package/agents/completion-gate.md +11 -0
- package/agents/constraint-check.md +11 -0
- package/agents/context-engine.md +11 -0
- package/agents/cook.md +11 -0
- package/agents/db.md +11 -0
- package/agents/debug.md +11 -0
- package/agents/dependency-doctor.md +11 -0
- package/agents/deploy.md +11 -0
- package/agents/design.md +11 -0
- package/agents/docs-seeker.md +11 -0
- package/agents/fix.md +11 -0
- package/agents/hallucination-guard.md +11 -0
- package/agents/incident.md +11 -0
- package/agents/integrity-check.md +11 -0
- package/agents/journal.md +11 -0
- package/agents/launch.md +11 -0
- package/agents/logic-guardian.md +11 -0
- package/agents/marketing.md +11 -0
- package/agents/onboard.md +11 -0
- package/agents/perf.md +11 -0
- package/agents/plan.md +11 -0
- package/agents/preflight.md +11 -0
- package/agents/problem-solver.md +11 -0
- package/agents/rescue.md +11 -0
- package/agents/research.md +11 -0
- package/agents/researcher.md +29 -0
- package/agents/review-intake.md +11 -0
- package/agents/review.md +11 -0
- package/agents/reviewer.md +28 -0
- package/agents/safeguard.md +11 -0
- package/agents/sast.md +11 -0
- package/agents/scanner.md +28 -0
- package/agents/scope-guard.md +11 -0
- package/agents/scout.md +11 -0
- package/agents/sentinel.md +11 -0
- package/agents/sequential-thinking.md +11 -0
- package/agents/session-bridge.md +11 -0
- package/agents/skill-forge.md +11 -0
- package/agents/skill-router.md +11 -0
- package/agents/surgeon.md +11 -0
- package/agents/team.md +11 -0
- package/agents/test.md +11 -0
- package/agents/trend-scout.md +11 -0
- package/agents/verification.md +11 -0
- package/agents/video-creator.md +11 -0
- package/agents/watchdog.md +11 -0
- package/agents/worktree.md +11 -0
- package/commands/.gitkeep +0 -0
- package/commands/rune.md +168 -0
- package/compiler/__tests__/openclaw-adapter.test.js +140 -0
- package/compiler/__tests__/parser.test.js +55 -0
- package/compiler/adapters/antigravity.js +59 -0
- package/compiler/adapters/claude.js +37 -0
- package/compiler/adapters/cursor.js +67 -0
- package/compiler/adapters/generic.js +60 -0
- package/compiler/adapters/index.js +45 -0
- package/compiler/adapters/openclaw.js +150 -0
- package/compiler/adapters/windsurf.js +60 -0
- package/compiler/bin/rune.js +288 -0
- package/compiler/doctor.js +153 -0
- package/compiler/emitter.js +240 -0
- package/compiler/parser.js +208 -0
- package/compiler/transformer.js +69 -0
- package/compiler/transforms/branding.js +27 -0
- package/compiler/transforms/cross-references.js +29 -0
- package/compiler/transforms/frontmatter.js +38 -0
- package/compiler/transforms/hooks.js +68 -0
- package/compiler/transforms/subagents.js +36 -0
- package/compiler/transforms/tool-names.js +60 -0
- package/contexts/dev.md +34 -0
- package/contexts/research.md +43 -0
- package/contexts/review.md +55 -0
- package/extensions/ai-ml/PACK.md +517 -0
- package/extensions/analytics/PACK.md +557 -0
- package/extensions/backend/PACK.md +678 -0
- package/extensions/chrome-ext/PACK.md +995 -0
- package/extensions/content/PACK.md +381 -0
- package/extensions/devops/PACK.md +520 -0
- package/extensions/ecommerce/PACK.md +280 -0
- package/extensions/gamedev/PACK.md +393 -0
- package/extensions/mobile/PACK.md +273 -0
- package/extensions/saas/PACK.md +805 -0
- package/extensions/security/PACK.md +536 -0
- package/extensions/trading/PACK.md +597 -0
- package/extensions/ui/PACK.md +947 -0
- package/package.json +47 -0
- package/skills/.gitkeep +0 -0
- package/skills/adversary/SKILL.md +271 -0
- package/skills/asset-creator/SKILL.md +157 -0
- package/skills/audit/SKILL.md +466 -0
- package/skills/autopsy/SKILL.md +200 -0
- package/skills/ba/SKILL.md +279 -0
- package/skills/brainstorm/SKILL.md +266 -0
- package/skills/browser-pilot/SKILL.md +168 -0
- package/skills/completion-gate/SKILL.md +151 -0
- package/skills/constraint-check/SKILL.md +165 -0
- package/skills/context-engine/SKILL.md +176 -0
- package/skills/cook/SKILL.md +636 -0
- package/skills/db/SKILL.md +256 -0
- package/skills/debug/SKILL.md +240 -0
- package/skills/dependency-doctor/SKILL.md +235 -0
- package/skills/deploy/SKILL.md +174 -0
- package/skills/design/DESIGN-REFERENCE.md +365 -0
- package/skills/design/SKILL.md +462 -0
- package/skills/doc-processor/SKILL.md +254 -0
- package/skills/docs/SKILL.md +336 -0
- package/skills/docs-seeker/SKILL.md +166 -0
- package/skills/fix/SKILL.md +192 -0
- package/skills/git/SKILL.md +285 -0
- package/skills/hallucination-guard/SKILL.md +204 -0
- package/skills/incident/SKILL.md +241 -0
- package/skills/integrity-check/SKILL.md +169 -0
- package/skills/journal/SKILL.md +190 -0
- package/skills/launch/SKILL.md +330 -0
- package/skills/logic-guardian/SKILL.md +240 -0
- package/skills/marketing/SKILL.md +229 -0
- package/skills/mcp-builder/SKILL.md +311 -0
- package/skills/onboard/SKILL.md +298 -0
- package/skills/perf/SKILL.md +297 -0
- package/skills/plan/SKILL.md +520 -0
- package/skills/preflight/SKILL.md +231 -0
- package/skills/problem-solver/SKILL.md +284 -0
- package/skills/rescue/SKILL.md +434 -0
- package/skills/research/SKILL.md +122 -0
- package/skills/review/SKILL.md +354 -0
- package/skills/review-intake/SKILL.md +222 -0
- package/skills/safeguard/SKILL.md +188 -0
- package/skills/sast/SKILL.md +190 -0
- package/skills/scaffold/SKILL.md +276 -0
- package/skills/scope-guard/SKILL.md +150 -0
- package/skills/scout/SKILL.md +232 -0
- package/skills/sentinel/SKILL.md +320 -0
- package/skills/sentinel-env/SKILL.md +226 -0
- package/skills/sequential-thinking/SKILL.md +234 -0
- package/skills/session-bridge/SKILL.md +287 -0
- package/skills/skill-forge/SKILL.md +317 -0
- package/skills/skill-router/SKILL.md +267 -0
- package/skills/surgeon/SKILL.md +203 -0
- package/skills/team/SKILL.md +397 -0
- package/skills/test/SKILL.md +271 -0
- package/skills/trend-scout/SKILL.md +145 -0
- package/skills/verification/SKILL.md +201 -0
- package/skills/video-creator/SKILL.md +201 -0
- package/skills/watchdog/SKILL.md +166 -0
- package/skills/worktree/SKILL.md +140 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import openclaw from '../adapters/openclaw.js';
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
import assert from 'node:assert';
|
|
4
|
+
|
|
5
|
+
// --- Adapter shape ---
|
|
6
|
+
|
|
7
|
+
test('openclaw adapter has all required properties', () => {
|
|
8
|
+
const required = [
|
|
9
|
+
'name', 'outputDir', 'fileExtension', 'skillPrefix', 'skillSuffix',
|
|
10
|
+
'transformReference', 'transformToolName', 'generateHeader', 'generateFooter',
|
|
11
|
+
'transformSubagentInstruction', 'postProcess',
|
|
12
|
+
'generateManifest', 'generateEntryPoint',
|
|
13
|
+
];
|
|
14
|
+
for (const prop of required) {
|
|
15
|
+
assert.ok(prop in openclaw, `missing property: ${prop}`);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('openclaw adapter has correct name and outputDir', () => {
|
|
20
|
+
assert.strictEqual(openclaw.name, 'openclaw');
|
|
21
|
+
assert.strictEqual(openclaw.outputDir, '.openclaw/rune/skills');
|
|
22
|
+
assert.strictEqual(openclaw.fileExtension, '.md');
|
|
23
|
+
assert.strictEqual(openclaw.skillPrefix, 'rune-');
|
|
24
|
+
assert.strictEqual(openclaw.skillSuffix, '');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// --- transformReference ---
|
|
28
|
+
|
|
29
|
+
test('transformReference returns correct skill file reference', () => {
|
|
30
|
+
const result = openclaw.transformReference('cook', 'cook');
|
|
31
|
+
assert.strictEqual(result, 'rune-cook.md');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('transformReference preserves backticks', () => {
|
|
35
|
+
const result = openclaw.transformReference('plan', '`plan`');
|
|
36
|
+
assert.strictEqual(result, '`rune-plan.md`');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// --- transformToolName ---
|
|
40
|
+
|
|
41
|
+
test('transformToolName maps Claude Code tools to OpenClaw equivalents', () => {
|
|
42
|
+
assert.strictEqual(openclaw.transformToolName('Read'), 'read_file');
|
|
43
|
+
assert.strictEqual(openclaw.transformToolName('Write'), 'write_file');
|
|
44
|
+
assert.strictEqual(openclaw.transformToolName('Edit'), 'edit_file');
|
|
45
|
+
assert.strictEqual(openclaw.transformToolName('Bash'), 'run_command');
|
|
46
|
+
assert.strictEqual(openclaw.transformToolName('Glob'), 'glob');
|
|
47
|
+
assert.strictEqual(openclaw.transformToolName('Grep'), 'grep');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('transformToolName passes through unknown tools', () => {
|
|
51
|
+
assert.strictEqual(openclaw.transformToolName('CustomTool'), 'CustomTool');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// --- generateHeader / generateFooter ---
|
|
55
|
+
|
|
56
|
+
test('generateHeader produces valid markdown', () => {
|
|
57
|
+
const skill = { name: 'cook', layer: 'L1', group: 'orchestrator' };
|
|
58
|
+
const header = openclaw.generateHeader(skill);
|
|
59
|
+
assert.ok(header.startsWith('# rune-cook'));
|
|
60
|
+
assert.ok(header.includes('L1'));
|
|
61
|
+
assert.ok(header.includes('orchestrator'));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('generateFooter includes Rune branding', () => {
|
|
65
|
+
const footer = openclaw.generateFooter();
|
|
66
|
+
assert.ok(footer.includes('Rune Skill Mesh'));
|
|
67
|
+
assert.ok(footer.includes('github.com/rune-kit/rune'));
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// --- postProcess ---
|
|
71
|
+
|
|
72
|
+
test('postProcess strips Claude-specific directives', () => {
|
|
73
|
+
const input = 'context: fork\nsome content\nagent: general-purpose\nmore content';
|
|
74
|
+
const result = openclaw.postProcess(input);
|
|
75
|
+
assert.ok(!result.includes('context: fork'));
|
|
76
|
+
assert.ok(!result.includes('agent: general-purpose'));
|
|
77
|
+
assert.ok(result.includes('some content'));
|
|
78
|
+
assert.ok(result.includes('more content'));
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// --- generateManifest ---
|
|
82
|
+
|
|
83
|
+
test('generateManifest returns valid openclaw.plugin.json structure', () => {
|
|
84
|
+
const skills = [
|
|
85
|
+
{ name: 'cook', layer: 'L1', group: 'orchestrator' },
|
|
86
|
+
{ name: 'plan', layer: 'L2', group: 'workflow' },
|
|
87
|
+
];
|
|
88
|
+
const pluginJson = { version: '2.1.1', name: 'rune' };
|
|
89
|
+
|
|
90
|
+
const manifest = openclaw.generateManifest(skills, pluginJson);
|
|
91
|
+
|
|
92
|
+
assert.strictEqual(manifest.id, 'rune');
|
|
93
|
+
assert.strictEqual(manifest.name, 'Rune');
|
|
94
|
+
assert.strictEqual(manifest.kind, 'skills');
|
|
95
|
+
assert.strictEqual(manifest.version, '2.1.1');
|
|
96
|
+
assert.ok(Array.isArray(manifest.skills));
|
|
97
|
+
assert.deepStrictEqual(manifest.skills, ['./skills']);
|
|
98
|
+
assert.ok(manifest.configSchema);
|
|
99
|
+
assert.ok(manifest.configSchema.jsonSchema);
|
|
100
|
+
assert.strictEqual(manifest.configSchema.jsonSchema.type, 'object');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('generateManifest defaults version when missing', () => {
|
|
104
|
+
const manifest = openclaw.generateManifest([], {});
|
|
105
|
+
assert.strictEqual(manifest.version, '0.0.0');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// --- generateEntryPoint ---
|
|
109
|
+
|
|
110
|
+
test('generateEntryPoint returns valid TypeScript with register(api)', () => {
|
|
111
|
+
const skills = [
|
|
112
|
+
{ name: 'cook', layer: 'L1', group: 'orchestrator', description: 'Feature orchestrator' },
|
|
113
|
+
{ name: 'fix', layer: 'L2', group: 'workflow', description: 'Apply fixes' },
|
|
114
|
+
];
|
|
115
|
+
const routerContent = '# skill-router\n\nRoute all tasks.';
|
|
116
|
+
|
|
117
|
+
const ts = openclaw.generateEntryPoint(skills, routerContent);
|
|
118
|
+
|
|
119
|
+
assert.ok(ts.includes('register(api'));
|
|
120
|
+
assert.ok(ts.includes("before_agent_start"));
|
|
121
|
+
assert.ok(ts.includes('prependSystemContext'));
|
|
122
|
+
assert.ok(ts.includes('export default plugin'));
|
|
123
|
+
assert.ok(ts.includes('cook'));
|
|
124
|
+
assert.ok(ts.includes('fix'));
|
|
125
|
+
assert.ok(ts.includes('skill-router'));
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('generateEntryPoint handles empty router content', () => {
|
|
129
|
+
const ts = openclaw.generateEntryPoint([], '');
|
|
130
|
+
assert.ok(ts.includes('register(api'));
|
|
131
|
+
assert.ok(ts.includes('export default plugin'));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('generateEntryPoint escapes backticks in router content', () => {
|
|
135
|
+
const routerContent = 'Use `cook` skill for code tasks';
|
|
136
|
+
const ts = openclaw.generateEntryPoint([], routerContent);
|
|
137
|
+
// Should not have unescaped backticks inside template literal
|
|
138
|
+
assert.ok(!ts.includes('Use `cook`'));
|
|
139
|
+
assert.ok(ts.includes('\\`cook\\`'));
|
|
140
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { parseSkill } from '../parser.js';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { test } from 'node:test';
|
|
4
|
+
import assert from 'node:assert';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const SKILLS_DIR = path.resolve(__dirname, '../../skills');
|
|
10
|
+
|
|
11
|
+
test('parse cook SKILL.md', () => {
|
|
12
|
+
const content = readFileSync(path.join(SKILLS_DIR, 'cook/SKILL.md'), 'utf-8');
|
|
13
|
+
const parsed = parseSkill(content, 'cook/SKILL.md');
|
|
14
|
+
|
|
15
|
+
console.log('name:', JSON.stringify(parsed.name));
|
|
16
|
+
console.log('description:', JSON.stringify(parsed.description?.substring(0, 50)));
|
|
17
|
+
console.log('layer:', parsed.layer);
|
|
18
|
+
console.log('model:', parsed.model);
|
|
19
|
+
console.log('group:', parsed.group);
|
|
20
|
+
console.log('contextFork:', parsed.contextFork);
|
|
21
|
+
console.log('agentType:', parsed.agentType);
|
|
22
|
+
console.log('crossRefs:', parsed.crossRefs.length);
|
|
23
|
+
console.log('toolRefs:', parsed.toolRefs.length);
|
|
24
|
+
console.log('hardGates:', parsed.hardGates.length);
|
|
25
|
+
console.log('sections:', [...parsed.sections.keys()]);
|
|
26
|
+
console.log('frontmatter keys:', Object.keys(parsed.frontmatter));
|
|
27
|
+
|
|
28
|
+
assert.strictEqual(parsed.name, 'cook');
|
|
29
|
+
assert.strictEqual(parsed.layer, 'L1');
|
|
30
|
+
assert.ok(parsed.crossRefs.length > 0);
|
|
31
|
+
assert.ok(parsed.hardGates.length > 0);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('parse fix SKILL.md', () => {
|
|
35
|
+
const content = readFileSync(path.join(SKILLS_DIR, 'fix/SKILL.md'), 'utf-8');
|
|
36
|
+
const parsed = parseSkill(content, 'fix/SKILL.md');
|
|
37
|
+
|
|
38
|
+
console.log('fix name:', JSON.stringify(parsed.name));
|
|
39
|
+
console.log('fix layer:', parsed.layer);
|
|
40
|
+
|
|
41
|
+
assert.strictEqual(parsed.name, 'fix');
|
|
42
|
+
assert.strictEqual(parsed.layer, 'L2');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('parse verification SKILL.md', () => {
|
|
46
|
+
const content = readFileSync(path.join(SKILLS_DIR, 'verification/SKILL.md'), 'utf-8');
|
|
47
|
+
const parsed = parseSkill(content, 'verification/SKILL.md');
|
|
48
|
+
|
|
49
|
+
console.log('verification name:', JSON.stringify(parsed.name));
|
|
50
|
+
console.log('verification layer:', parsed.layer);
|
|
51
|
+
console.log('verification toolRefs:', parsed.toolRefs.length);
|
|
52
|
+
|
|
53
|
+
assert.strictEqual(parsed.name, 'verification');
|
|
54
|
+
assert.strictEqual(parsed.layer, 'L3');
|
|
55
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Antigravity (Jules) Adapter
|
|
3
|
+
*
|
|
4
|
+
* Emits .md rule files for .agent/rules/ directory.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const TOOL_MAP = {
|
|
8
|
+
Read: 'read the file',
|
|
9
|
+
Write: 'write/create the file',
|
|
10
|
+
Edit: 'edit the file',
|
|
11
|
+
Glob: 'find files by pattern',
|
|
12
|
+
Grep: 'search file contents',
|
|
13
|
+
Bash: 'run a shell command',
|
|
14
|
+
TodoWrite: 'track task progress',
|
|
15
|
+
Skill: 'follow the referenced skill',
|
|
16
|
+
Agent: 'execute the workflow',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
name: 'antigravity',
|
|
21
|
+
outputDir: '.agent/rules',
|
|
22
|
+
fileExtension: '.md',
|
|
23
|
+
skillPrefix: 'rune-',
|
|
24
|
+
skillSuffix: '',
|
|
25
|
+
|
|
26
|
+
transformReference(skillName, raw) {
|
|
27
|
+
const isBackticked = raw.startsWith('`') && raw.endsWith('`');
|
|
28
|
+
const ref = `the rune-${skillName} rule`;
|
|
29
|
+
return isBackticked ? `\`${ref}\`` : ref;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
transformToolName(toolName) {
|
|
33
|
+
return TOOL_MAP[toolName] || toolName;
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
generateHeader(skill) {
|
|
37
|
+
return `# rune-${skill.name}\n\n> Rune ${skill.layer} Skill | ${skill.group}\n\n`;
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
generateFooter() {
|
|
41
|
+
return [
|
|
42
|
+
'',
|
|
43
|
+
'---',
|
|
44
|
+
'> **Rune Skill Mesh** — 49 skills, 170+ connections',
|
|
45
|
+
'> Source: https://github.com/rune-kit/rune',
|
|
46
|
+
'> Full experience with subagents, hooks, adaptive routing → use Rune on Claude Code.',
|
|
47
|
+
].join('\n');
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
transformSubagentInstruction(text) {
|
|
51
|
+
return text;
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
postProcess(content) {
|
|
55
|
+
return content
|
|
56
|
+
.replace(/^context: fork\n/gm, '')
|
|
57
|
+
.replace(/^agent: general-purpose\n/gm, '');
|
|
58
|
+
},
|
|
59
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Adapter (Passthrough)
|
|
3
|
+
*
|
|
4
|
+
* No transformation needed — source IS the output.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
name: 'claude',
|
|
9
|
+
outputDir: null,
|
|
10
|
+
fileExtension: '.md',
|
|
11
|
+
skillPrefix: '',
|
|
12
|
+
skillSuffix: '',
|
|
13
|
+
|
|
14
|
+
transformReference(skillName, raw) {
|
|
15
|
+
return raw;
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
transformToolName(toolName) {
|
|
19
|
+
return toolName;
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
generateHeader(_skill) {
|
|
23
|
+
return '';
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
generateFooter() {
|
|
27
|
+
return '';
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
transformSubagentInstruction(text) {
|
|
31
|
+
return text;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
postProcess(content) {
|
|
35
|
+
return content;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor Adapter
|
|
3
|
+
*
|
|
4
|
+
* Emits .mdc rule files for .cursor/rules/ directory.
|
|
5
|
+
* Uses @file references for cross-skill mesh.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const TOOL_MAP = {
|
|
9
|
+
Read: 'read the file',
|
|
10
|
+
Write: 'write/create the file',
|
|
11
|
+
Edit: 'edit the file',
|
|
12
|
+
Glob: 'search for files by pattern',
|
|
13
|
+
Grep: 'search file contents',
|
|
14
|
+
Bash: 'run a terminal command',
|
|
15
|
+
TodoWrite: 'track progress',
|
|
16
|
+
Skill: 'follow the referenced skill rules',
|
|
17
|
+
Agent: 'execute the workflow',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
name: 'cursor',
|
|
22
|
+
outputDir: '.cursor/rules',
|
|
23
|
+
fileExtension: '.mdc',
|
|
24
|
+
skillPrefix: 'rune-',
|
|
25
|
+
skillSuffix: '',
|
|
26
|
+
|
|
27
|
+
transformReference(skillName, raw) {
|
|
28
|
+
const isBackticked = raw.startsWith('`') && raw.endsWith('`');
|
|
29
|
+
const ref = `@rune-${skillName}.mdc`;
|
|
30
|
+
return isBackticked ? `\`${ref}\`` : ref;
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
transformToolName(toolName) {
|
|
34
|
+
return TOOL_MAP[toolName] || toolName;
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
generateHeader(skill) {
|
|
38
|
+
return [
|
|
39
|
+
'---',
|
|
40
|
+
`description: "${skill.description}"`,
|
|
41
|
+
'globs: []',
|
|
42
|
+
`alwaysApply: ${skill.layer === 'L0'}`,
|
|
43
|
+
'---',
|
|
44
|
+
'',
|
|
45
|
+
].join('\n');
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
generateFooter() {
|
|
49
|
+
return [
|
|
50
|
+
'',
|
|
51
|
+
'---',
|
|
52
|
+
'> **Rune Skill Mesh** — 49 skills, 170+ connections',
|
|
53
|
+
'> Source: https://github.com/rune-kit/rune',
|
|
54
|
+
'> Full experience with subagents, hooks, adaptive routing → use Rune on Claude Code.',
|
|
55
|
+
].join('\n');
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
transformSubagentInstruction(text) {
|
|
59
|
+
return text;
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
postProcess(content) {
|
|
63
|
+
return content
|
|
64
|
+
.replace(/^context: fork\n/gm, '')
|
|
65
|
+
.replace(/^agent: general-purpose\n/gm, '');
|
|
66
|
+
},
|
|
67
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic Adapter (Fallback)
|
|
3
|
+
*
|
|
4
|
+
* For unknown or future platforms. Emits to .ai/rules/ directory.
|
|
5
|
+
* Uses the most portable format possible.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const TOOL_MAP = {
|
|
9
|
+
Read: 'read the file',
|
|
10
|
+
Write: 'write/create the file',
|
|
11
|
+
Edit: 'edit the file',
|
|
12
|
+
Glob: 'find files by pattern',
|
|
13
|
+
Grep: 'search file contents',
|
|
14
|
+
Bash: 'run a shell command',
|
|
15
|
+
TodoWrite: 'track task progress',
|
|
16
|
+
Skill: 'follow the referenced skill',
|
|
17
|
+
Agent: 'execute the workflow',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
name: 'generic',
|
|
22
|
+
outputDir: '.ai/rules',
|
|
23
|
+
fileExtension: '.md',
|
|
24
|
+
skillPrefix: 'rune-',
|
|
25
|
+
skillSuffix: '',
|
|
26
|
+
|
|
27
|
+
transformReference(skillName, raw) {
|
|
28
|
+
const isBackticked = raw.startsWith('`') && raw.endsWith('`');
|
|
29
|
+
const ref = `the rune-${skillName} rule file`;
|
|
30
|
+
return isBackticked ? `\`${ref}\`` : ref;
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
transformToolName(toolName) {
|
|
34
|
+
return TOOL_MAP[toolName] || toolName;
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
generateHeader(skill) {
|
|
38
|
+
return `# rune-${skill.name}\n\n> Rune ${skill.layer} Skill | ${skill.group}\n\n`;
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
generateFooter() {
|
|
42
|
+
return [
|
|
43
|
+
'',
|
|
44
|
+
'---',
|
|
45
|
+
'> **Rune Skill Mesh** — 49 skills, 170+ connections',
|
|
46
|
+
'> Source: https://github.com/rune-kit/rune',
|
|
47
|
+
'> Full experience with subagents, hooks, adaptive routing → use Rune on Claude Code.',
|
|
48
|
+
].join('\n');
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
transformSubagentInstruction(text) {
|
|
52
|
+
return text;
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
postProcess(content) {
|
|
56
|
+
return content
|
|
57
|
+
.replace(/^context: fork\n/gm, '')
|
|
58
|
+
.replace(/^agent: general-purpose\n/gm, '');
|
|
59
|
+
},
|
|
60
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter Registry
|
|
3
|
+
*
|
|
4
|
+
* Central registry for all platform adapters.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import claude from './claude.js';
|
|
8
|
+
import cursor from './cursor.js';
|
|
9
|
+
import windsurf from './windsurf.js';
|
|
10
|
+
import antigravity from './antigravity.js';
|
|
11
|
+
import generic from './generic.js';
|
|
12
|
+
import openclaw from './openclaw.js';
|
|
13
|
+
|
|
14
|
+
const adapters = {
|
|
15
|
+
claude,
|
|
16
|
+
cursor,
|
|
17
|
+
windsurf,
|
|
18
|
+
antigravity,
|
|
19
|
+
generic,
|
|
20
|
+
openclaw,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get adapter by platform name
|
|
25
|
+
* @param {string} platform
|
|
26
|
+
* @returns {object} adapter
|
|
27
|
+
*/
|
|
28
|
+
export function getAdapter(platform) {
|
|
29
|
+
const adapter = adapters[platform];
|
|
30
|
+
if (!adapter) {
|
|
31
|
+
const available = Object.keys(adapters).join(', ');
|
|
32
|
+
throw new Error(`Unknown platform "${platform}". Available: ${available}`);
|
|
33
|
+
}
|
|
34
|
+
return adapter;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* List all available platform names
|
|
39
|
+
* @returns {string[]}
|
|
40
|
+
*/
|
|
41
|
+
export function listPlatforms() {
|
|
42
|
+
return Object.keys(adapters);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { adapters };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Adapter
|
|
3
|
+
*
|
|
4
|
+
* Emits an OpenClaw plugin structure:
|
|
5
|
+
* .openclaw/rune/openclaw.plugin.json (manifest)
|
|
6
|
+
* .openclaw/rune/src/index.ts (register entrypoint)
|
|
7
|
+
* .openclaw/rune/skills/*.md (transformed skill files)
|
|
8
|
+
*
|
|
9
|
+
* Follows the NeuralMemory OpenClaw plugin pattern.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const TOOL_MAP = {
|
|
13
|
+
Read: 'read_file',
|
|
14
|
+
Write: 'write_file',
|
|
15
|
+
Edit: 'edit_file',
|
|
16
|
+
Glob: 'glob',
|
|
17
|
+
Grep: 'grep',
|
|
18
|
+
Bash: 'run_command',
|
|
19
|
+
TodoWrite: 'todo_write',
|
|
20
|
+
Skill: 'follow the referenced skill',
|
|
21
|
+
Agent: 'execute the workflow',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
name: 'openclaw',
|
|
26
|
+
outputDir: '.openclaw/rune/skills',
|
|
27
|
+
fileExtension: '.md',
|
|
28
|
+
skillPrefix: 'rune-',
|
|
29
|
+
skillSuffix: '',
|
|
30
|
+
|
|
31
|
+
transformReference(skillName, raw) {
|
|
32
|
+
const isBackticked = raw.startsWith('`') && raw.endsWith('`');
|
|
33
|
+
const ref = `rune-${skillName}.md`;
|
|
34
|
+
return isBackticked ? `\`${ref}\`` : ref;
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
transformToolName(toolName) {
|
|
38
|
+
return TOOL_MAP[toolName] || toolName;
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
generateHeader(skill) {
|
|
42
|
+
return `# rune-${skill.name}\n\n> Rune ${skill.layer} Skill | ${skill.group}\n\n`;
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
generateFooter() {
|
|
46
|
+
return [
|
|
47
|
+
'',
|
|
48
|
+
'---',
|
|
49
|
+
'> **Rune Skill Mesh** — 55 skills, 200+ connections',
|
|
50
|
+
'> Source: https://github.com/rune-kit/rune',
|
|
51
|
+
].join('\n');
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
transformSubagentInstruction(text) {
|
|
55
|
+
return text;
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
postProcess(content) {
|
|
59
|
+
return content
|
|
60
|
+
.replace(/^context: fork\n/gm, '')
|
|
61
|
+
.replace(/^agent: general-purpose\n/gm, '');
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Generate openclaw.plugin.json manifest
|
|
66
|
+
*
|
|
67
|
+
* @param {object[]} skills - parsed skill objects
|
|
68
|
+
* @param {object} pluginJson - Rune's .claude-plugin/plugin.json
|
|
69
|
+
* @returns {object} manifest object
|
|
70
|
+
*/
|
|
71
|
+
generateManifest(skills, pluginJson) {
|
|
72
|
+
return {
|
|
73
|
+
id: 'rune',
|
|
74
|
+
name: 'Rune',
|
|
75
|
+
kind: 'skills',
|
|
76
|
+
description: '55-skill mesh for AI coding assistants. Routes all code tasks through specialized skills.',
|
|
77
|
+
version: pluginJson.version || '0.0.0',
|
|
78
|
+
skills: ['./skills'],
|
|
79
|
+
configSchema: {
|
|
80
|
+
jsonSchema: {
|
|
81
|
+
type: 'object',
|
|
82
|
+
properties: {
|
|
83
|
+
disabledSkills: {
|
|
84
|
+
type: 'array',
|
|
85
|
+
items: { type: 'string' },
|
|
86
|
+
description: 'Skills to disable (by name)',
|
|
87
|
+
default: [],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
additionalProperties: false,
|
|
91
|
+
},
|
|
92
|
+
uiHints: {
|
|
93
|
+
disabledSkills: {
|
|
94
|
+
label: 'Disabled Skills',
|
|
95
|
+
help: 'Comma-separated list of skill names to exclude from routing',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Generate src/index.ts entry point with register(api) pattern
|
|
104
|
+
*
|
|
105
|
+
* @param {object[]} skills - parsed skill objects
|
|
106
|
+
* @param {string} routerContent - skill-router SKILL.md content for injection
|
|
107
|
+
* @returns {string} TypeScript source
|
|
108
|
+
*/
|
|
109
|
+
generateEntryPoint(skills, routerContent) {
|
|
110
|
+
const skillNames = skills.map(s => s.name);
|
|
111
|
+
const routingTable = skills
|
|
112
|
+
.map(s => `// ${s.name} (${s.layer}) — ${s.description || s.group}`)
|
|
113
|
+
.join('\n');
|
|
114
|
+
|
|
115
|
+
// Escape backticks and backslashes in router content for template literal
|
|
116
|
+
const escapedRouter = (routerContent || '')
|
|
117
|
+
.replace(/\\/g, '\\\\')
|
|
118
|
+
.replace(/`/g, '\\`')
|
|
119
|
+
.replace(/\$/g, '\\$');
|
|
120
|
+
|
|
121
|
+
return `/**
|
|
122
|
+
* Rune — OpenClaw Plugin Entry Point
|
|
123
|
+
*
|
|
124
|
+
* Auto-generated by Rune compiler.
|
|
125
|
+
* Do not edit manually — regenerate with: rune build --platform openclaw
|
|
126
|
+
*
|
|
127
|
+
* Skills (${skillNames.length}):
|
|
128
|
+
${routingTable}
|
|
129
|
+
*/
|
|
130
|
+
|
|
131
|
+
const SKILL_ROUTER_INSTRUCTIONS = \`${escapedRouter}\`;
|
|
132
|
+
|
|
133
|
+
const plugin = {
|
|
134
|
+
id: 'rune',
|
|
135
|
+
name: 'Rune',
|
|
136
|
+
|
|
137
|
+
register(api: any): void {
|
|
138
|
+
// Inject skill-router instructions so the agent routes through Rune skills
|
|
139
|
+
api.on('before_agent_start', async () => {
|
|
140
|
+
return {
|
|
141
|
+
prependSystemContext: SKILL_ROUTER_INSTRUCTIONS,
|
|
142
|
+
};
|
|
143
|
+
}, { priority: 5 });
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export default plugin;
|
|
148
|
+
`;
|
|
149
|
+
},
|
|
150
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windsurf Adapter
|
|
3
|
+
*
|
|
4
|
+
* Emits .md rule files for .windsurf/rules/ directory.
|
|
5
|
+
* Uses prose references for cross-skill mesh (no @file support).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const TOOL_MAP = {
|
|
9
|
+
Read: 'read the file',
|
|
10
|
+
Write: 'write/create the file',
|
|
11
|
+
Edit: 'edit the file',
|
|
12
|
+
Glob: 'find files matching a pattern',
|
|
13
|
+
Grep: 'search for text in files',
|
|
14
|
+
Bash: 'run a shell command',
|
|
15
|
+
TodoWrite: 'track task progress',
|
|
16
|
+
Skill: 'follow the referenced skill workflow',
|
|
17
|
+
Agent: 'execute the workflow',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
name: 'windsurf',
|
|
22
|
+
outputDir: '.windsurf/rules',
|
|
23
|
+
fileExtension: '.md',
|
|
24
|
+
skillPrefix: 'rune-',
|
|
25
|
+
skillSuffix: '',
|
|
26
|
+
|
|
27
|
+
transformReference(skillName, raw) {
|
|
28
|
+
const isBackticked = raw.startsWith('`') && raw.endsWith('`');
|
|
29
|
+
const ref = `the rune-${skillName} rule file`;
|
|
30
|
+
return isBackticked ? `\`${ref}\`` : ref;
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
transformToolName(toolName) {
|
|
34
|
+
return TOOL_MAP[toolName] || toolName;
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
generateHeader(skill) {
|
|
38
|
+
return `# rune-${skill.name}\n\n> Layer: ${skill.layer} | Group: ${skill.group}\n\n`;
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
generateFooter() {
|
|
42
|
+
return [
|
|
43
|
+
'',
|
|
44
|
+
'---',
|
|
45
|
+
'> **Rune Skill Mesh** — 49 skills, 170+ connections',
|
|
46
|
+
'> Source: https://github.com/rune-kit/rune',
|
|
47
|
+
'> Full experience with subagents, hooks, adaptive routing → use Rune on Claude Code.',
|
|
48
|
+
].join('\n');
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
transformSubagentInstruction(text) {
|
|
52
|
+
return text;
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
postProcess(content) {
|
|
56
|
+
return content
|
|
57
|
+
.replace(/^context: fork\n/gm, '')
|
|
58
|
+
.replace(/^agent: general-purpose\n/gm, '');
|
|
59
|
+
},
|
|
60
|
+
};
|