@rune-kit/rune 2.4.0 → 2.7.0
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 +47 -17
- package/compiler/__tests__/executive-dashboards.test.js +285 -0
- package/compiler/__tests__/inject.test.js +128 -0
- package/compiler/__tests__/orchestrators.test.js +151 -0
- package/compiler/__tests__/org-templates.test.js +447 -0
- package/compiler/__tests__/pack-split.test.js +141 -1
- package/compiler/__tests__/parser.test.js +147 -1
- package/compiler/__tests__/scripts-bundling.test.js +10 -11
- package/compiler/__tests__/skill-index.test.js +218 -0
- package/compiler/__tests__/status.test.js +336 -0
- package/compiler/__tests__/templates.test.js +245 -0
- package/compiler/__tests__/visualizer.test.js +325 -0
- package/compiler/adapters/antigravity.js +18 -4
- package/compiler/bin/rune.js +90 -1
- package/compiler/doctor.js +283 -2
- package/compiler/emitter.js +490 -17
- package/compiler/parser.js +255 -4
- package/compiler/status.js +342 -0
- package/compiler/visualizer.js +622 -0
- package/hooks/hooks.json +12 -0
- package/hooks/intent-router/index.cjs +108 -0
- package/hooks/pre-tool-guard/index.cjs +177 -68
- package/package.json +63 -63
- package/skills/autopsy/SKILL.md +48 -1
- package/skills/brainstorm/SKILL.md +2 -0
- package/skills/completion-gate/SKILL.md +26 -1
- package/skills/context-engine/SKILL.md +93 -2
- package/skills/cook/SKILL.md +794 -648
- package/skills/debug/SKILL.md +409 -392
- package/skills/deploy/SKILL.md +2 -0
- package/skills/docs/SKILL.md +28 -3
- package/skills/fix/SKILL.md +284 -281
- package/skills/mcp-builder/SKILL.md +53 -1
- package/skills/onboard/SKILL.md +58 -1
- package/skills/perf/SKILL.md +34 -1
- package/skills/plan/SKILL.md +372 -342
- package/skills/preflight/SKILL.md +396 -360
- package/skills/retro/SKILL.md +95 -1
- package/skills/review/SKILL.md +535 -489
- package/skills/scope-guard/SKILL.md +1 -0
- package/skills/scout/SKILL.md +1 -0
- package/skills/sentinel/SKILL.md +353 -299
- package/skills/sentinel/references/policy-driven-constraints.md +424 -0
- package/skills/session-bridge/SKILL.md +58 -2
- package/skills/session-bridge/references/evolutionary-memory-patterns.md +312 -0
- package/skills/team/SKILL.md +16 -1
- package/skills/test/SKILL.md +587 -585
- package/skills/verification/SKILL.md +1 -0
- package/skills/watchdog/SKILL.md +2 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Rune Intent Router Hook — Compiled Intent Mesh (CIM)
|
|
2
|
+
// Auto-suggests skill routing based on user prompt analysis
|
|
3
|
+
// Runs as UserPromptSubmit hook — scores prompt against compiled skill-index.json
|
|
4
|
+
//
|
|
5
|
+
// Key difference from runtime scoring approaches:
|
|
6
|
+
// - Compile-time generated index (zero runtime deps)
|
|
7
|
+
// - Mesh-aware chain prediction (uses actual connection graph)
|
|
8
|
+
// - Works on all platforms (index ships with every build)
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
// Read user prompt from Claude Code hook stdin
|
|
14
|
+
let input = '';
|
|
15
|
+
process.stdin.setEncoding('utf-8');
|
|
16
|
+
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
17
|
+
process.stdin.on('end', () => {
|
|
18
|
+
let userPrompt = '';
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(input);
|
|
21
|
+
userPrompt = parsed.user_prompt || parsed.prompt || parsed.content || '';
|
|
22
|
+
} catch {
|
|
23
|
+
// Raw text input
|
|
24
|
+
userPrompt = input.trim();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!userPrompt || userPrompt.length < 3) {
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Find skill-index.json — check multiple locations
|
|
32
|
+
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || path.resolve(__dirname, '../..');
|
|
33
|
+
const candidates = [
|
|
34
|
+
path.join(pluginRoot, '.cursor', 'rules', 'skill-index.json'),
|
|
35
|
+
path.join(pluginRoot, '.windsurf', 'rules', 'skill-index.json'),
|
|
36
|
+
path.join(pluginRoot, 'dist', 'cursor', 'skill-index.json'),
|
|
37
|
+
path.join(pluginRoot, 'dist', 'generic', 'skill-index.json'),
|
|
38
|
+
// Also check .rune/ for locally cached index
|
|
39
|
+
path.join(process.cwd(), '.rune', 'skill-index.json'),
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
let index = null;
|
|
43
|
+
for (const candidate of candidates) {
|
|
44
|
+
try {
|
|
45
|
+
if (fs.existsSync(candidate)) {
|
|
46
|
+
index = JSON.parse(fs.readFileSync(candidate, 'utf-8'));
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
// Try next candidate
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!index || !index.intents) {
|
|
55
|
+
// No index available — exit silently (not an error, just not built yet)
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Score prompt against intent patterns
|
|
60
|
+
const promptLower = userPrompt.toLowerCase();
|
|
61
|
+
const scores = [];
|
|
62
|
+
|
|
63
|
+
for (const [skillName, intent] of Object.entries(index.intents)) {
|
|
64
|
+
let score = 0;
|
|
65
|
+
|
|
66
|
+
for (const keyword of intent.keywords) {
|
|
67
|
+
if (promptLower.includes(keyword)) {
|
|
68
|
+
// Exact word boundary match scores higher
|
|
69
|
+
const wordBoundary = new RegExp(`\\b${keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'i');
|
|
70
|
+
score += wordBoundary.test(userPrompt) ? 3 : 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Layer priority boost: L1 orchestrators get a small bonus (they're entry points)
|
|
75
|
+
if (intent.layer === 'L1') score += 1;
|
|
76
|
+
|
|
77
|
+
if (score > 0) {
|
|
78
|
+
scores.push({ skill: skillName, score, chain: intent.chain, model: intent.model, layer: intent.layer });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (scores.length === 0) {
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Sort by score descending, take top match
|
|
87
|
+
scores.sort((a, b) => b.score - a.score);
|
|
88
|
+
const top = scores[0];
|
|
89
|
+
|
|
90
|
+
// Only suggest if confidence is reasonable (score >= 3 = at least one strong keyword match)
|
|
91
|
+
if (top.score < 3) {
|
|
92
|
+
process.exit(0);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Format chain for display
|
|
96
|
+
const chainDisplay = top.chain.slice(0, 4).join(' → ');
|
|
97
|
+
const alternates = scores.slice(1, 3).map((s) => s.skill).join(', ');
|
|
98
|
+
|
|
99
|
+
// Output routing suggestion
|
|
100
|
+
console.log(`\n🧭 [Rune intent-router] Suggested: rune:${top.skill} (${top.layer}, ${top.model})`);
|
|
101
|
+
console.log(` Chain: ${chainDisplay}`);
|
|
102
|
+
if (alternates) {
|
|
103
|
+
console.log(` Also consider: ${alternates}`);
|
|
104
|
+
}
|
|
105
|
+
console.log('');
|
|
106
|
+
|
|
107
|
+
process.exit(0);
|
|
108
|
+
});
|
|
@@ -1,68 +1,177 @@
|
|
|
1
|
-
// Rune Pre-Tool Guard Hook
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
1
|
+
// Rune Pre-Tool Guard Hook — Privacy Mesh
|
|
2
|
+
// Three-tier security gate: ALLOW / WARN / BLOCK
|
|
3
|
+
// Configurable via .rune/privacy.json per project
|
|
4
|
+
// Skill-aware: sentinel/review can access files other skills cannot
|
|
5
|
+
//
|
|
6
|
+
// Upgrades over basic path matching:
|
|
7
|
+
// - Per-project .rune/privacy.json config (custom patterns + overrides)
|
|
8
|
+
// - Three tiers: ALLOW (silent), WARN (log), BLOCK (exit code 2)
|
|
9
|
+
// - Content-aware: scans first bytes for secret patterns on WARN files
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
// Read tool_input from Claude Code hook stdin
|
|
15
|
+
let input = '';
|
|
16
|
+
process.stdin.setEncoding('utf-8');
|
|
17
|
+
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
18
|
+
process.stdin.on('end', () => {
|
|
19
|
+
let toolInput = {};
|
|
20
|
+
let toolName = '';
|
|
21
|
+
try {
|
|
22
|
+
const parsed = JSON.parse(input);
|
|
23
|
+
toolInput = parsed.tool_input || parsed;
|
|
24
|
+
toolName = parsed.tool_name || '';
|
|
25
|
+
} catch {
|
|
26
|
+
// If no stdin or parse fails, exit cleanly (non-blocking)
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const filePath = toolInput.file_path || toolInput.path || '';
|
|
31
|
+
if (!filePath) process.exit(0);
|
|
32
|
+
|
|
33
|
+
const basename = path.basename(filePath);
|
|
34
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
35
|
+
|
|
36
|
+
// Load project-specific privacy config
|
|
37
|
+
const privacyConfig = loadPrivacyConfig();
|
|
38
|
+
|
|
39
|
+
// Default sensitive file patterns — BLOCK tier (hard block)
|
|
40
|
+
const blockPatterns = [
|
|
41
|
+
/^id_rsa$/,
|
|
42
|
+
/^id_ed25519$/,
|
|
43
|
+
/^id_ecdsa$/,
|
|
44
|
+
/\.p12$/,
|
|
45
|
+
/\.pfx$/,
|
|
46
|
+
/\.pem$/,
|
|
47
|
+
/^\.netrc$/,
|
|
48
|
+
/private[-_.]?key/i,
|
|
49
|
+
...privacyConfig.block.map((p) => new RegExp(p)),
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
// WARN tier (log warning, allow through)
|
|
53
|
+
const warnPatterns = [
|
|
54
|
+
/^\.env$/,
|
|
55
|
+
/^\.env\.[^e]/, // .env.* but NOT .env.example
|
|
56
|
+
/\.key$/,
|
|
57
|
+
/^credentials\.json$/,
|
|
58
|
+
/\.secret$/,
|
|
59
|
+
/secret[-_.]?key/i,
|
|
60
|
+
...privacyConfig.warn.map((p) => new RegExp(p)),
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
// Safe exceptions (always allow)
|
|
64
|
+
const safeExceptions = [
|
|
65
|
+
/\.env\.example$/,
|
|
66
|
+
/\.env\.sample$/,
|
|
67
|
+
/\.env\.template$/,
|
|
68
|
+
/\.env\.test$/,
|
|
69
|
+
/test.*credential/i,
|
|
70
|
+
/fixture/i,
|
|
71
|
+
/mock/i,
|
|
72
|
+
...privacyConfig.allow.map((p) => new RegExp(p)),
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
// Skills with elevated access (can read WARN-tier files without warning)
|
|
76
|
+
const elevatedSkills = new Set([
|
|
77
|
+
'sentinel', 'review', 'audit', 'secrets-scan', 'onboard',
|
|
78
|
+
...privacyConfig.elevatedSkills,
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
// Detect active skill from environment (set by metrics-collector or skill invocation)
|
|
82
|
+
const activeSkill = process.env.RUNE_ACTIVE_SKILL || '';
|
|
83
|
+
const isElevated = elevatedSkills.has(activeSkill);
|
|
84
|
+
|
|
85
|
+
const isSafe = safeExceptions.some((p) => p.test(basename) || p.test(normalized));
|
|
86
|
+
if (isSafe) process.exit(0);
|
|
87
|
+
|
|
88
|
+
const isBlocked = blockPatterns.some((p) => p.test(basename) || p.test(normalized));
|
|
89
|
+
if (isBlocked) {
|
|
90
|
+
console.log(`\n🚫 [Rune privacy-mesh] BLOCKED: ${filePath}`);
|
|
91
|
+
console.log(' This file matches a BLOCK-tier pattern (private keys, certificates).');
|
|
92
|
+
console.log(' Override: add path to .rune/privacy.json "allow" list if intentional.\n');
|
|
93
|
+
process.exit(2); // Exit code 2 = BLOCK
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const isWarned = warnPatterns.some((p) => p.test(basename) || p.test(normalized));
|
|
97
|
+
if (isWarned && !isElevated) {
|
|
98
|
+
// Content-aware check: scan first 4KB for secret patterns
|
|
99
|
+
const contentWarning = scanContentForSecrets(filePath);
|
|
100
|
+
|
|
101
|
+
console.log(`\n⚠ [Rune privacy-mesh] Sensitive file: ${filePath}`);
|
|
102
|
+
if (contentWarning) {
|
|
103
|
+
console.log(` Content scan: ${contentWarning}`);
|
|
104
|
+
}
|
|
105
|
+
console.log(' This file may contain secrets. Confirm access is intentional.');
|
|
106
|
+
console.log(' Elevated skills (sentinel, review, audit) bypass this warning.\n');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
process.exit(0);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Load .rune/privacy.json from project root
|
|
114
|
+
* Returns merged config with defaults
|
|
115
|
+
*/
|
|
116
|
+
function loadPrivacyConfig() {
|
|
117
|
+
const defaults = { block: [], warn: [], allow: [], elevatedSkills: [] };
|
|
118
|
+
|
|
119
|
+
const candidates = [
|
|
120
|
+
path.join(process.cwd(), '.rune', 'privacy.json'),
|
|
121
|
+
path.join(process.cwd(), 'privacy.json'),
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
for (const configPath of candidates) {
|
|
125
|
+
try {
|
|
126
|
+
if (fs.existsSync(configPath)) {
|
|
127
|
+
const raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
128
|
+
return {
|
|
129
|
+
block: Array.isArray(raw.block) ? raw.block : defaults.block,
|
|
130
|
+
warn: Array.isArray(raw.warn) ? raw.warn : defaults.warn,
|
|
131
|
+
allow: Array.isArray(raw.allow) ? raw.allow : defaults.allow,
|
|
132
|
+
elevatedSkills: Array.isArray(raw.elevatedSkills) ? raw.elevatedSkills : defaults.elevatedSkills,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
} catch {
|
|
136
|
+
// Invalid config — use defaults
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return defaults;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Scan first 4KB of a file for common secret patterns
|
|
145
|
+
* Returns a warning string if secrets detected, null otherwise
|
|
146
|
+
*/
|
|
147
|
+
function scanContentForSecrets(filePath) {
|
|
148
|
+
try {
|
|
149
|
+
const fd = fs.openSync(filePath, 'r');
|
|
150
|
+
const buffer = Buffer.alloc(4096);
|
|
151
|
+
const bytesRead = fs.readSync(fd, buffer, 0, 4096, 0);
|
|
152
|
+
fs.closeSync(fd);
|
|
153
|
+
|
|
154
|
+
if (bytesRead === 0) return null;
|
|
155
|
+
|
|
156
|
+
const content = buffer.toString('utf-8', 0, bytesRead);
|
|
157
|
+
|
|
158
|
+
const secretPatterns = [
|
|
159
|
+
{ pattern: /AKIA[0-9A-Z]{16}/, label: 'AWS access key' },
|
|
160
|
+
{ pattern: /gh[ps]_[A-Za-z0-9_]{36,}/, label: 'GitHub token' },
|
|
161
|
+
{ pattern: /sk_(live|test)_[0-9a-zA-Z]{24,}/, label: 'Stripe key' },
|
|
162
|
+
{ pattern: /-----BEGIN .* PRIVATE KEY-----/, label: 'Private key' },
|
|
163
|
+
{ pattern: /xox[bpors]-[0-9a-zA-Z-]{10,}/, label: 'Slack token' },
|
|
164
|
+
{ pattern: /sk-[a-zA-Z0-9]{32,}/, label: 'OpenAI/API key' },
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
for (const { pattern, label } of secretPatterns) {
|
|
168
|
+
if (pattern.test(content)) {
|
|
169
|
+
return `Found ${label} pattern in file content`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
// Can't read file (doesn't exist yet, permissions, etc.) — skip silently
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return null;
|
|
177
|
+
}
|
package/package.json
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@rune-kit/rune",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"rune": "./compiler/bin/rune.js"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"build": "node compiler/bin/rune.js build",
|
|
11
|
-
"doctor": "node compiler/bin/rune.js doctor && node scripts/version-sync-check.js",
|
|
12
|
-
"test": "node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js",
|
|
13
|
-
"test:coverage": "c8 --reporter=text --reporter=lcov node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js",
|
|
14
|
-
"lint": "biome check .",
|
|
15
|
-
"lint:fix": "biome check --fix .",
|
|
16
|
-
"format": "biome format --write .",
|
|
17
|
-
"ci": "biome check . && node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js && node compiler/bin/rune.js doctor",
|
|
18
|
-
"version-check": "node scripts/version-sync-check.js",
|
|
19
|
-
"prepublishOnly": "node scripts/version-sync-check.js"
|
|
20
|
-
},
|
|
21
|
-
"keywords": [
|
|
22
|
-
"claude-code",
|
|
23
|
-
"cursor",
|
|
24
|
-
"windsurf",
|
|
25
|
-
"antigravity",
|
|
26
|
-
"codex",
|
|
27
|
-
"opencode",
|
|
28
|
-
"openclaw",
|
|
29
|
-
"ai-assistant",
|
|
30
|
-
"ai-coding",
|
|
31
|
-
"skills",
|
|
32
|
-
"coding-agent",
|
|
33
|
-
"tdd",
|
|
34
|
-
"multi-platform"
|
|
35
|
-
],
|
|
36
|
-
"author": "runedev",
|
|
37
|
-
"license": "MIT",
|
|
38
|
-
"repository": {
|
|
39
|
-
"type": "git",
|
|
40
|
-
"url": "https://github.com/rune-kit/rune"
|
|
41
|
-
},
|
|
42
|
-
"engines": {
|
|
43
|
-
"node": ">=18"
|
|
44
|
-
},
|
|
45
|
-
"files": [
|
|
46
|
-
"compiler/",
|
|
47
|
-
"skills/",
|
|
48
|
-
"extensions/",
|
|
49
|
-
"contexts/",
|
|
50
|
-
"commands/",
|
|
51
|
-
"agents/",
|
|
52
|
-
"hooks/",
|
|
53
|
-
"references/"
|
|
54
|
-
],
|
|
55
|
-
"homepage": "https://rune-kit.github.io/rune",
|
|
56
|
-
"bugs": {
|
|
57
|
-
"url": "https://github.com/rune-kit/rune/issues"
|
|
58
|
-
},
|
|
59
|
-
"devDependencies": {
|
|
60
|
-
"@biomejs/biome": "^2.4.7",
|
|
61
|
-
"c8": "^10.1.3"
|
|
62
|
-
}
|
|
63
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@rune-kit/rune",
|
|
3
|
+
"version": "2.7.0",
|
|
4
|
+
"description": "61-skill mesh for AI coding assistants — 5-layer architecture, 200+ connections, 8 platforms (Claude Code, Cursor, Windsurf, Antigravity, Codex, OpenCode, OpenClaw, Generic)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"rune": "./compiler/bin/rune.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "node compiler/bin/rune.js build",
|
|
11
|
+
"doctor": "node compiler/bin/rune.js doctor && node scripts/version-sync-check.js",
|
|
12
|
+
"test": "node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js",
|
|
13
|
+
"test:coverage": "c8 --reporter=text --reporter=lcov node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js",
|
|
14
|
+
"lint": "biome check .",
|
|
15
|
+
"lint:fix": "biome check --fix .",
|
|
16
|
+
"format": "biome format --write .",
|
|
17
|
+
"ci": "biome check . && node --test compiler/__tests__/*.test.js scripts/__tests__/*.test.js && node compiler/bin/rune.js doctor",
|
|
18
|
+
"version-check": "node scripts/version-sync-check.js",
|
|
19
|
+
"prepublishOnly": "node scripts/version-sync-check.js"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"claude-code",
|
|
23
|
+
"cursor",
|
|
24
|
+
"windsurf",
|
|
25
|
+
"antigravity",
|
|
26
|
+
"codex",
|
|
27
|
+
"opencode",
|
|
28
|
+
"openclaw",
|
|
29
|
+
"ai-assistant",
|
|
30
|
+
"ai-coding",
|
|
31
|
+
"skills",
|
|
32
|
+
"coding-agent",
|
|
33
|
+
"tdd",
|
|
34
|
+
"multi-platform"
|
|
35
|
+
],
|
|
36
|
+
"author": "runedev",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/rune-kit/rune"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18"
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"compiler/",
|
|
47
|
+
"skills/",
|
|
48
|
+
"extensions/",
|
|
49
|
+
"contexts/",
|
|
50
|
+
"commands/",
|
|
51
|
+
"agents/",
|
|
52
|
+
"hooks/",
|
|
53
|
+
"references/"
|
|
54
|
+
],
|
|
55
|
+
"homepage": "https://rune-kit.github.io/rune",
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/rune-kit/rune/issues"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@biomejs/biome": "^2.4.7",
|
|
61
|
+
"c8": "^10.1.3"
|
|
62
|
+
}
|
|
63
|
+
}
|
package/skills/autopsy/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: autopsy
|
|
|
3
3
|
description: Full codebase health assessment. Analyzes complexity, dependencies, dead code, tech debt, and git hotspots. Produces a health score and rescue plan.
|
|
4
4
|
metadata:
|
|
5
5
|
author: runedev
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.3.0"
|
|
7
7
|
layer: L2
|
|
8
8
|
model: opus
|
|
9
9
|
group: rescue
|
|
@@ -210,3 +210,50 @@ Known failure modes for this skill. Check these before declaring done.
|
|
|
210
210
|
~5000-10000 tokens input, ~2000-4000 tokens output. Opus for deep analysis. Most expensive L2 skill but runs once per rescue.
|
|
211
211
|
|
|
212
212
|
**Scope guardrail:** autopsy assesses — it does not refactor. All surgery is delegated to `surgeon` after the report is complete.
|
|
213
|
+
|
|
214
|
+
## Executive Mode (--executive)
|
|
215
|
+
|
|
216
|
+
When invoked as `/rune autopsy --executive`, generate a board-ready HTML health assessment. Requires Business tier.
|
|
217
|
+
|
|
218
|
+
### Executive Execution Steps
|
|
219
|
+
|
|
220
|
+
1. **Standard Autopsy**: Run Steps 1-5 (structure scan, module analysis, health scoring, risk assessment, RESCUE-REPORT.md)
|
|
221
|
+
2. **Org Context**: Read `.rune/org/org.md` for team structure and governance level
|
|
222
|
+
3. **Cross-Domain Impact**: Map module health to business domains (which team owns which modules)
|
|
223
|
+
4. **Business Risk Translation**: Convert technical health scores to business risk language:
|
|
224
|
+
- Critical modules in revenue path → "Revenue infrastructure at risk"
|
|
225
|
+
- Low test coverage on auth → "Security compliance gap"
|
|
226
|
+
- High churn in customer-facing code → "Customer experience degradation risk"
|
|
227
|
+
5. **HTML Render**: Load `report-templates/autopsy-executive.html` from Business pack and populate all `{{placeholder}}` fields:
|
|
228
|
+
- SVG health ring (score → stroke-dasharray calculation: `score / 100 * 440`)
|
|
229
|
+
- Dimension bars (6 dimensions with color coding)
|
|
230
|
+
- Module table (sorted by priority)
|
|
231
|
+
- Surgery queue (top 5 modules)
|
|
232
|
+
- Risk matrix (6 categories)
|
|
233
|
+
- Git archaeology summary
|
|
234
|
+
- Cross-domain impact table
|
|
235
|
+
- Recommended actions (numbered, prioritized)
|
|
236
|
+
6. **Save**: Write HTML to `EXECUTIVE-HEALTH.html` at project root
|
|
237
|
+
|
|
238
|
+
### Executive Output
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
EXECUTIVE-HEALTH.html — Board-ready HTML report
|
|
242
|
+
RESCUE-REPORT.md — Detailed technical report (standard autopsy)
|
|
243
|
+
.rune/retros/{date}.json — Health metrics for trend tracking
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Color Coding
|
|
247
|
+
|
|
248
|
+
| Score Range | Color | Tier |
|
|
249
|
+
|-------------|-------|------|
|
|
250
|
+
| 80-100 | var(--success) #10b981 | Healthy |
|
|
251
|
+
| 60-79 | var(--warning) #f59e0b | Watch |
|
|
252
|
+
| 40-59 | #f97316 (orange) | At-risk |
|
|
253
|
+
| 0-39 | var(--danger) #ef4444 | Critical |
|
|
254
|
+
|
|
255
|
+
### Graceful Degradation
|
|
256
|
+
|
|
257
|
+
- If no Business pack installed: skip executive mode, produce standard RESCUE-REPORT.md only
|
|
258
|
+
- If `.rune/org/org.md` missing: skip team mapping, show modules without domain ownership
|
|
259
|
+
- If org teams don't map to code modules: show "Unmapped" in cross-domain table
|
|
@@ -4,7 +4,7 @@ description: "Validates agent claims against evidence trail. Catches 'done' with
|
|
|
4
4
|
user-invocable: false
|
|
5
5
|
metadata:
|
|
6
6
|
author: runedev
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.7.0"
|
|
8
8
|
layer: L3
|
|
9
9
|
model: haiku
|
|
10
10
|
group: validation
|
|
@@ -210,6 +210,29 @@ Before emitting verdict, verify evidence quality:
|
|
|
210
210
|
| Quote matches claim exactly | CONFIRMED |
|
|
211
211
|
| Quote contradicts claim | CONTRADICTED |
|
|
212
212
|
|
|
213
|
+
### Step 5.5 — Plan Diff Check
|
|
214
|
+
|
|
215
|
+
When validating a phase within a master plan, diff actual changes against the phase plan file:
|
|
216
|
+
|
|
217
|
+
1. **Read the active phase plan** — `Glob` for `.rune/plan-*-phase*.md` matching the current phase
|
|
218
|
+
2. **Extract `## Files Touched`** — build a list of expected files (new/modify/delete)
|
|
219
|
+
3. **Extract `## Tasks`** — build a list of all `- [ ]` and `- [x]` items
|
|
220
|
+
4. **Compare against actual changes** — `git diff --name-only` (or file system scan)
|
|
221
|
+
5. **Report**:
|
|
222
|
+
|
|
223
|
+
| Check | Status |
|
|
224
|
+
|-------|--------|
|
|
225
|
+
| Unchecked task in phase plan (`- [ ]` still exists) | **INCOMPLETE** — task was not done |
|
|
226
|
+
| File in plan's "Files Touched" but not in actual diff | **MISSING** — planned file was never touched |
|
|
227
|
+
| File in actual diff but NOT in plan's "Files Touched" | **UNPLANNED** — scope creep (warn, not block) |
|
|
228
|
+
| All tasks `[x]` AND all planned files touched | **PLAN-ALIGNED** |
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
Plan Diff: PLAN-ALIGNED | INCOMPLETE (2 unchecked tasks) | MISSING (1 file never touched)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Skip if**: No active phase plan found (single-task, no master plan). **MANDATORY** for multi-phase master plans.
|
|
235
|
+
|
|
213
236
|
## Verdict Rules
|
|
214
237
|
|
|
215
238
|
```
|
|
@@ -245,6 +268,7 @@ Completion Gate Report with status (CONFIRMED/UNCONFIRMED/CONTRADICTED), claim v
|
|
|
245
268
|
| Rubber-stamping — all CONFIRMED without scrutiny | HIGH | Default-FAIL mindset: actively seek 3-5 issues. Zero issues = red flag, apply skeptic sweep on weakest 2 claims |
|
|
246
269
|
| Partial completion claimed as full — 80% done but "implemented" | HIGH | Adversarial checklist: check for partial completion, scope mismatch, evidence-claim alignment |
|
|
247
270
|
| Self-Validation skipped — skill has checks but gate ignores them | HIGH | Step 1c: extract Self-Validation from skill's SKILL.md, treat each as implicit claim. Missing = UNCONFIRMED |
|
|
271
|
+
| Plan says done but phase file has unchecked tasks | HIGH | Step 5.5: diff changed files vs phase plan's Files Touched + Tasks sections |
|
|
248
272
|
|
|
249
273
|
## Done When
|
|
250
274
|
|
|
@@ -252,6 +276,7 @@ Completion Gate Report with status (CONFIRMED/UNCONFIRMED/CONTRADICTED), claim v
|
|
|
252
276
|
- Each claim matched against tool output evidence
|
|
253
277
|
- Verdict table emitted with claim/evidence/verdict for each item
|
|
254
278
|
- All 3 verification axes (Completeness/Correctness/Coherence) have at least one claim checked
|
|
279
|
+
- Plan diff check passed (if multi-phase): all tasks checked, all planned files touched
|
|
255
280
|
- Overall verdict: CONFIRMED / UNCONFIRMED / CONTRADICTED
|
|
256
281
|
- If not CONFIRMED: specific gaps listed with remediation steps
|
|
257
282
|
|