@rune-kit/rune 2.2.1 → 2.2.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 (65) hide show
  1. package/README.md +39 -13
  2. package/compiler/bin/rune.js +26 -4
  3. package/docs/ANTIGRAVITY-GAP-ANALYSIS.md +369 -0
  4. package/docs/ARCHITECTURE.md +332 -0
  5. package/docs/COMMUNITY-PACKS.md +109 -0
  6. package/docs/CONTRIBUTING-L4.md +215 -0
  7. package/docs/CROSS-IDE-ANALYSIS.md +164 -0
  8. package/docs/EXTENSION-TEMPLATE.md +108 -0
  9. package/docs/MESH-RULES.md +34 -0
  10. package/docs/MULTI-PLATFORM.md +804 -0
  11. package/docs/SKILL-DEPTH-AUDIT.md +191 -0
  12. package/docs/SKILL-TEMPLATE.md +72 -0
  13. package/docs/TRADE-MATRIX.md +327 -0
  14. package/docs/VERSIONING.md +91 -0
  15. package/docs/VISION.md +263 -0
  16. package/docs/assets/demo-subtitles.srt +215 -0
  17. package/docs/assets/end-card.html +276 -0
  18. package/docs/assets/mesh-diagram.html +654 -0
  19. package/docs/assets/thumbnail.html +295 -0
  20. package/docs/guides/cli.md +403 -0
  21. package/docs/guides/index.html +1346 -0
  22. package/docs/index.html +674 -0
  23. package/docs/references/claudekit-analysis.md +414 -0
  24. package/docs/references/voltagent-analysis.md +189 -0
  25. package/docs/script.js +277 -0
  26. package/docs/skills/index.html +832 -0
  27. package/docs/style.css +583 -0
  28. package/docs/video-demo-plan.md +172 -0
  29. package/extensions/ui/PACK.md +2 -0
  30. package/extensions/ui/skills/design-decision.md +10 -0
  31. package/extensions/ui/skills/palette-picker.md +11 -0
  32. package/hooks/.gitkeep +0 -0
  33. package/hooks/auto-format/index.cjs +48 -0
  34. package/hooks/context-watch/index.cjs +68 -0
  35. package/hooks/hooks.json +99 -0
  36. package/hooks/metrics-collector/index.cjs +42 -0
  37. package/hooks/post-session-reflect/index.cjs +153 -0
  38. package/hooks/pre-compact/index.cjs +95 -0
  39. package/hooks/pre-tool-guard/index.cjs +68 -0
  40. package/hooks/run-hook +17 -0
  41. package/hooks/run-hook.cjs +16 -0
  42. package/hooks/run-hook.cmd +1 -0
  43. package/hooks/secrets-scan/index.cjs +100 -0
  44. package/hooks/session-start/index.cjs +65 -0
  45. package/hooks/typecheck/index.cjs +65 -0
  46. package/package.json +9 -4
  47. package/references/ui-pro-max-data/LICENSE-UI-PRO-MAX +21 -0
  48. package/references/ui-pro-max-data/charts.csv +26 -0
  49. package/references/ui-pro-max-data/colors.csv +162 -0
  50. package/references/ui-pro-max-data/styles.csv +85 -0
  51. package/references/ui-pro-max-data/typography.csv +74 -0
  52. package/references/ui-pro-max-data/ui-reasoning.csv +162 -0
  53. package/references/ui-pro-max-data/ux-guidelines.csv +100 -0
  54. package/skills/ba/SKILL.md +10 -0
  55. package/skills/completion-gate/SKILL.md +34 -1
  56. package/skills/context-engine/SKILL.md +13 -0
  57. package/skills/cook/SKILL.md +71 -0
  58. package/skills/debug/SKILL.md +56 -1
  59. package/skills/design/SKILL.md +11 -0
  60. package/skills/fix/SKILL.md +26 -1
  61. package/skills/plan/SKILL.md +23 -6
  62. package/skills/review/SKILL.md +2 -0
  63. package/skills/skill-forge/SKILL.md +38 -3
  64. package/skills/test/SKILL.md +10 -1
  65. package/skills/verification/SKILL.md +60 -2
@@ -0,0 +1,172 @@
1
+ # Rune Demo Video — Production Plan
2
+
3
+ **Topic**: Rune plugin full demo — install to debug to ship
4
+ **Audience**: Developers using AI coding assistants (Claude Code, Cursor, Windsurf)
5
+ **Duration**: 180 seconds (3 minutes)
6
+ **Platform**: YouTube (primary), Twitter/X (60s cut), GitHub README (embedded)
7
+ **Style**: Screen recording + narration overlay, dark terminal theme
8
+
9
+ ---
10
+
11
+ ## Script (with timing marks)
12
+
13
+ ### HOOK (0:00–0:08)
14
+
15
+ > "You're debugging for the 4th time. Claude keeps suggesting the same fix. Same loop. Same frustration."
16
+ > [Screen: terminal showing repeated failed attempts]
17
+ > "What if your AI assistant had a structured workflow that actually worked?"
18
+
19
+ ### INTRO (0:08–0:20)
20
+
21
+ > "This is Rune — a 57-skill mesh that turns your AI coding assistant from a chatbot into an engineering team."
22
+ > [Screen: Rune GitHub page, star count, "57 skills | 200+ connections"]
23
+ > "It works on Claude Code, Cursor, Windsurf, and Antigravity. Let me show you."
24
+
25
+ ### SCENE 1: INSTALL (0:20–0:40)
26
+
27
+ > "Install takes 10 seconds."
28
+ > [Screen: terminal]
29
+ > ```
30
+ > claude plugin install rune-kit/rune
31
+ > ```
32
+ > [Plugin installs, shows "57 skills loaded"]
33
+ > "For Cursor or Windsurf, one command compiles all skills into your IDE's format."
34
+ > [Screen: terminal]
35
+ > ```
36
+ > npx --yes @rune-kit/rune init --platform cursor
37
+ > ```
38
+ > [Shows files being generated]
39
+
40
+ ### SCENE 2: ONBOARD (0:40–1:00)
41
+
42
+ > "First thing — let Rune understand your project."
43
+ > [Screen: terminal in a real project directory]
44
+ > ```
45
+ > /rune onboard
46
+ > ```
47
+ > [Shows scout scanning files, detecting Next.js + Prisma + TypeScript]
48
+ > [Shows .rune/ directory being created with decisions.md, conventions.md]
49
+ > "Rune scans your codebase, detects your stack, and creates context files that persist across sessions. No more re-explaining your project every time."
50
+
51
+ ### SCENE 3: DEBUG (1:00–1:30)
52
+
53
+ > "Now let's debug. Users report login returns 401 for valid credentials."
54
+ > [Screen: terminal]
55
+ > ```
56
+ > /rune debug "login returns 401 for valid credentials"
57
+ > ```
58
+ > [Shows debug skill activating]
59
+ > [Shows scout finding auth files → debug reading them → identifying root cause]
60
+ > "Rune's debug skill traces the code path, finds the root cause — an expired JWT secret rotation — and hands it to fix."
61
+ > [Shows fix skill writing the code change]
62
+ > [Shows verification running: lint pass, typecheck pass, tests pass]
63
+ > "Fixed. Verified. One command."
64
+
65
+ ### SCENE 4: BUILD A FEATURE (1:30–2:15)
66
+
67
+ > "Now let's build something. Add Stripe billing to our SaaS app."
68
+ > [Screen: terminal]
69
+ > ```
70
+ > /rune cook "add Stripe subscription billing with plan management"
71
+ > ```
72
+ > [Shows cook Phase 1: scout scanning → detecting @rune/saas pack]
73
+ > [Shows cook Phase 2: plan creating implementation steps]
74
+ > [Shows adversary challenging the plan: "Missing webhook signature verification — CRITICAL"]
75
+ > "See that? Before writing a single line of code, Rune's adversary skill red-teams the plan. Found a missing webhook security check."
76
+ > [Shows plan updated → user approves]
77
+ > [Shows cook Phase 3: test writing failing tests]
78
+ > [Shows cook Phase 4: fix implementing code]
79
+ > [Shows cook Phase 5: preflight + sentinel + review running in parallel]
80
+ > [Shows cook Phase 6: all green]
81
+ > "8 phases. TDD. Security scan. Code review. All orchestrated automatically."
82
+
83
+ ### SCENE 5: THE MESH (2:15–2:40)
84
+
85
+ > "This isn't a list of independent tools. It's a mesh."
86
+ > [Screen: animated diagram showing skill connections]
87
+ > "When debug can't find the cause, it escalates to problem-solver. When cook hits a wall 3 times, it pivots to brainstorm. When sentinel finds a vulnerability, it blocks the commit."
88
+ > [Shows mesh diagram with glowing connections]
89
+ > "57 skills. 200+ connections. They talk to each other so you don't have to."
90
+
91
+ ### CTA (2:40–3:00)
92
+
93
+ > "Rune is free and open source. MIT license."
94
+ > [Screen: GitHub repo]
95
+ > ```
96
+ > claude plugin install rune-kit/rune
97
+ > ```
98
+ > "Or for any IDE:"
99
+ > ```
100
+ > npx --yes @rune-kit/rune init
101
+ > ```
102
+ > [Screen: landing page with GitHub stars]
103
+ > "Less skills. Deeper connections. Link in description."
104
+
105
+ ---
106
+
107
+ ## Storyboard
108
+
109
+ | Time | Visual | Audio | Transition |
110
+ |------|--------|-------|------------|
111
+ | 0:00 | Dark terminal, red error messages repeating | Narration: frustration hook | Fade in |
112
+ | 0:08 | Rune GitHub page, hero section | Narration: intro | Cut |
113
+ | 0:20 | Terminal: plugin install command | Narration: install | Cut |
114
+ | 0:30 | Terminal: npx init for Cursor | Narration: multi-platform | Cut |
115
+ | 0:40 | Terminal: /rune onboard in real project | Narration: onboard | Cut |
116
+ | 0:50 | .rune/ directory tree appearing | Narration: context persistence | Slide in |
117
+ | 1:00 | Terminal: /rune debug command | Narration: debug scenario | Cut |
118
+ | 1:10 | Code files being read, root cause highlighted | Narration: tracing | Zoom |
119
+ | 1:20 | Fix being written, tests passing | Narration: fixed + verified | Cut |
120
+ | 1:30 | Terminal: /rune cook command | Narration: build feature | Cut |
121
+ | 1:45 | Plan appearing, adversary challenge in red | Narration: red-team | Highlight |
122
+ | 2:00 | TDD cycle: red → green → refactor | Narration: phases | Split screen |
123
+ | 2:10 | Quality gates all green | Narration: automatic orchestration | Cut |
124
+ | 2:15 | Mesh diagram (animated) | Narration: mesh explanation | Fade |
125
+ | 2:30 | Connections glowing between skills | Narration: resilience | Pulse animation |
126
+ | 2:40 | GitHub repo + install command | Narration: CTA | Cut |
127
+ | 2:50 | Landing page | Narration: tagline | Fade out |
128
+
129
+ ---
130
+
131
+ ## Shot List
132
+
133
+ | # | Type | Content | Duration | Notes |
134
+ |---|------|---------|----------|-------|
135
+ | 1 | Screen rec | Terminal with repeated errors | 8s | Use real project, dark theme |
136
+ | 2 | Screen rec | Rune GitHub page scroll | 5s | Show stars, description |
137
+ | 3 | Screen rec | `claude plugin install` | 8s | Real-time, no speedup |
138
+ | 4 | Screen rec | `npx @rune-kit/rune init` | 8s | Show file generation |
139
+ | 5 | Screen rec | `/rune onboard` full flow | 15s | Speed up 2x, show key moments |
140
+ | 6 | Screen rec | `/rune debug` full flow | 25s | Speed up 2x, pause on root cause |
141
+ | 7 | Screen rec | `/rune cook` full flow | 40s | Speed up 3x, pause on adversary + quality |
142
+ | 8 | Graphic | Mesh diagram animation | 20s | Create with Motion Canvas or After Effects |
143
+ | 9 | Screen rec | GitHub + install commands | 15s | Clean, centered text |
144
+ | 10 | Graphic | Landing page + tagline | 10s | End card with links |
145
+
146
+ ---
147
+
148
+ ## Asset Checklist
149
+
150
+ - [ ] Real project for demo (Next.js + Prisma SaaS app recommended)
151
+ - [ ] Rune plugin installed and working
152
+ - [ ] Terminal theme: dark, high contrast, large font (18-20pt)
153
+ - [ ] Screen recording tool: OBS or Loom
154
+ - [ ] Mesh diagram: create SVG or use Motion Canvas
155
+ - [ ] Background music: lo-fi or minimal electronic (royalty-free)
156
+ - [ ] Microphone for narration (or use ElevenLabs/AI voice)
157
+ - [ ] Thumbnail: terminal screenshot + "57 Skills" text overlay
158
+ - [ ] Captions/subtitles file (.srt) for accessibility
159
+
160
+ ## 60-Second Twitter/X Cut
161
+
162
+ Use shots: 1 (3s) → 3 (5s) → 6 (15s) → 7 (20s) → 8 (10s) → 9 (7s)
163
+ Skip: onboard detail, mesh explanation
164
+ Hook: "Your AI assistant keeps failing? Try giving it a brain." + demo
165
+
166
+ ## Distribution
167
+
168
+ - YouTube: full 3-min version with chapters
169
+ - Twitter/X: 60s cut, captions baked in, no music
170
+ - GitHub README: YouTube embed at top
171
+ - Landing page: YouTube embed in hero section
172
+ - Reddit r/ClaudeAI, r/cursor, r/webdev: link + text summary
@@ -12,6 +12,8 @@ metadata:
12
12
 
13
13
  # @rune/ui
14
14
 
15
+ > Design intelligence data: [UI/UX Pro Max](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill) (MIT) — 161 palettes, 84 styles, 73 font pairings, 99 UX guidelines. Located at `references/ui-pro-max-data/`.
16
+
15
17
  ## Purpose
16
18
 
17
19
  Frontend development accumulates invisible debt: ad-hoc color variables, mismatched font pairings, prop-drilled components, untested accessibility, janky animations, React anti-patterns, and slow page loads — all before you even decide what the product should *look* like. This pack addresses all layers systematically. Ten skills cover the full UI lifecycle: React codebase health scoring, Core Web Vitals performance auditing, token consistency, color palette selection, typography pairing, component composability, landing page structure, design-domain mapping, WCAG compliance, and motion polish. Run any skill independently or chain all ten as a comprehensive UI health check + design foundation generator.
@@ -23,6 +23,8 @@ Emit a `design-system.md` file in the project root (or `.rune/`) with: color tok
23
23
 
24
24
  #### Domain → Style Matrix
25
25
 
26
+ The matrix below provides default mappings. When `references/ui-pro-max-data/styles.csv` is available, query it for **84 additional styles** with industry-specific parameters — filter by domain column for expanded recommendations beyond these 10 defaults.
27
+
26
28
  ```
27
29
  Domain Style Palette Typography Component Aesthetic
28
30
  ─────────────────────────────────────────────────────────────────────────────────────────────
@@ -40,6 +42,14 @@ DevTools Terminal + Crisp terminal-dark JetBrains Mono+Inter C
40
42
  * Palette not shown in palette-picker example block — generate with same CSS custom props pattern.
41
43
  ```
42
44
 
45
+ #### Extended Data (UI/UX Pro Max)
46
+
47
+ When `references/ui-pro-max-data/` exists:
48
+ - `styles.csv` — 84 styles with color params, animation, WCAG levels, mobile flags
49
+ - `typography.csv` — 73 font pairings with Google Fonts URLs, Tailwind config, mood keywords
50
+ - `ui-reasoning.csv` — 161 industry-specific reasoning rules (filter by domain)
51
+ - Query: filter CSV by domain/category column → get expanded recommendations
52
+
43
53
  #### Style Characteristic Reference
44
54
 
45
55
  ```
@@ -26,6 +26,8 @@ Run contrast checks: primary text on background (≥ 4.5:1), large headings (≥
26
26
 
27
27
  #### Decision Tree
28
28
 
29
+ The tree below provides 10 default palettes. When `references/ui-pro-max-data/colors.csv` is available, query it for **161 industry-specific palettes** with full dark/light variants, semantic tokens, and design psychology notes. Filter by domain column for expanded options.
30
+
29
31
  ```
30
32
  Product Type → Palette Recommendation
31
33
  ─────────────────────────────────────────────────
@@ -41,6 +43,15 @@ productivity / tools → Calm Focus (gray-50 + indigo-700, minimal noise)
41
43
  developer tools → Terminal Dark (zinc-950 + emerald-400 mono)
42
44
  ```
43
45
 
46
+ #### Extended Palette DB (UI/UX Pro Max)
47
+
48
+ When `references/ui-pro-max-data/colors.csv` exists:
49
+ - 161 palettes with Primary, Secondary, Accent, Background, Foreground (dark+light)
50
+ - Semantic tokens: Card, Muted, Border, Destructive, Ring variants
51
+ - Design psychology notes per palette
52
+ - Query: `grep -i "<domain>" references/ui-pro-max-data/colors.csv` → get domain-matched palettes
53
+ - Anti-AI check: if selected palette uses #6366f1 (indigo) or #8b5cf6 (violet) as primary → flag and suggest alternatives from DB
54
+
44
55
  #### Palette Reference
45
56
 
46
57
  ```css
package/hooks/.gitkeep ADDED
File without changes
@@ -0,0 +1,48 @@
1
+ // Rune Auto-Format Hook
2
+ // PostToolUse hook on Edit/Write — runs Prettier on JS/TS files after modification
3
+ //
4
+ // Only runs if Prettier is available in the project.
5
+ // Silent pass-through if not applicable.
6
+
7
+ const { execSync } = require('child_process');
8
+ const path = require('path');
9
+
10
+ const input = JSON.parse(process.env.CLAUDE_TOOL_INPUT || '{}');
11
+ const filePath = input.file_path || input.filePath || '';
12
+
13
+ // Only format JS/TS/JSON/CSS files
14
+ if (!/\.(js|jsx|ts|tsx|json|css|scss|md|html|yaml|yml)$/i.test(filePath)) {
15
+ process.exit(0);
16
+ }
17
+
18
+ // Check if file exists and is within a project with Prettier
19
+ const dir = path.dirname(filePath);
20
+
21
+ // Try to find prettier in the project
22
+ let hasPrettier = false;
23
+ try {
24
+ execSync('npx prettier --version', { cwd: dir, encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
25
+ hasPrettier = true;
26
+ } catch {
27
+ // No Prettier available — skip silently
28
+ }
29
+
30
+ if (!hasPrettier) {
31
+ process.exit(0);
32
+ }
33
+
34
+ // Run Prettier on the file
35
+ try {
36
+ execSync(`npx prettier --write "${filePath}"`, {
37
+ cwd: dir,
38
+ encoding: 'utf-8',
39
+ stdio: 'pipe',
40
+ timeout: 10000,
41
+ });
42
+ // Silent success — formatted files are seamless
43
+ } catch (e) {
44
+ // Prettier failed — non-critical, just warn
45
+ console.log(`[Rune auto-format] Prettier failed on ${path.basename(filePath)}: ${e.message.split('\n')[0]}`);
46
+ }
47
+
48
+ process.exit(0);
@@ -0,0 +1,68 @@
1
+ // Rune Context Watch Hook
2
+ // Lightweight tool call counter — detects context pressure and suggests rune:context-engine
3
+ // Runs as PreToolUse hook on Edit/Write (high-cost operations)
4
+ //
5
+ // H3 Intelligence: also tracks tool type distribution and session start timestamp
6
+ // for metrics aggregation at session end.
7
+ //
8
+ // Uses a temp file counter (survives across hook invocations within same session).
9
+ // Zero overhead: just reads/increments a number. No token cost.
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const os = require('os');
14
+
15
+ // Counter file scoped to current working directory (hash of cwd)
16
+ const cwd = process.cwd();
17
+ const hash = Buffer.from(cwd).toString('base64url').slice(0, 16);
18
+ const counterFile = path.join(os.tmpdir(), `rune-context-watch-${hash}.json`);
19
+
20
+ // Thresholds
21
+ const FIRST_WARNING = 40;
22
+ const REPEAT_INTERVAL = 20;
23
+ const CRITICAL_THRESHOLD = 80;
24
+
25
+ // Detect tool type from environment
26
+ const toolName = process.env.CLAUDE_TOOL_NAME || 'unknown';
27
+
28
+ // Read current state
29
+ let state = { count: 0, lastWarning: 0, sessionStart: null, toolCounts: {} };
30
+ try {
31
+ const raw = fs.readFileSync(counterFile, 'utf-8');
32
+ state = JSON.parse(raw);
33
+ // Ensure toolCounts exists (upgrade from old format)
34
+ if (!state.toolCounts) state.toolCounts = {};
35
+ if (!state.sessionStart) state.sessionStart = new Date().toISOString();
36
+ } catch {
37
+ // First run or corrupted — start fresh
38
+ state.sessionStart = new Date().toISOString();
39
+ }
40
+
41
+ // Increment total and per-tool counters
42
+ state.count += 1;
43
+ state.toolCounts[toolName] = (state.toolCounts[toolName] || 0) + 1;
44
+
45
+ // Check thresholds
46
+ const count = state.count;
47
+ const sinceLast = count - state.lastWarning;
48
+
49
+ if (count >= CRITICAL_THRESHOLD && sinceLast >= REPEAT_INTERVAL) {
50
+ console.log(`\n🔴 [Rune context-watch] ${count} tool calls — context likely RED (>85%).`);
51
+ console.log(' RECOMMENDED: Invoke rune:context-engine for state save + /compact.');
52
+ console.log(' Risk: auto-compaction may lose critical decisions without state save.\n');
53
+ state.lastWarning = count;
54
+ } else if (count >= FIRST_WARNING && sinceLast >= REPEAT_INTERVAL) {
55
+ console.log(`\n🟡 [Rune context-watch] ${count} tool calls — context filling up.`);
56
+ console.log(' Consider invoking rune:context-engine at the next logical boundary.');
57
+ console.log(' Or run /compact manually if at a good stopping point.\n');
58
+ state.lastWarning = count;
59
+ }
60
+
61
+ // Persist
62
+ try {
63
+ fs.writeFileSync(counterFile, JSON.stringify(state));
64
+ } catch {
65
+ // Non-critical — counter resets next run
66
+ }
67
+
68
+ process.exit(0);
@@ -0,0 +1,99 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "matcher": "startup|resume|clear|compact",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" session-start",
10
+ "async": false
11
+ }
12
+ ]
13
+ }
14
+ ],
15
+ "PreToolUse": [
16
+ {
17
+ "matcher": "Read|Write|Edit",
18
+ "hooks": [
19
+ {
20
+ "type": "command",
21
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" pre-tool-guard",
22
+ "async": false
23
+ }
24
+ ]
25
+ },
26
+ {
27
+ "matcher": "Edit|Write",
28
+ "hooks": [
29
+ {
30
+ "type": "command",
31
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" context-watch",
32
+ "async": true
33
+ }
34
+ ]
35
+ },
36
+ {
37
+ "matcher": "Bash",
38
+ "hooks": [
39
+ {
40
+ "type": "command",
41
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" secrets-scan",
42
+ "async": false
43
+ }
44
+ ]
45
+ }
46
+ ],
47
+ "PostToolUse": [
48
+ {
49
+ "matcher": "Edit|Write",
50
+ "hooks": [
51
+ {
52
+ "type": "command",
53
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" auto-format",
54
+ "async": true
55
+ },
56
+ {
57
+ "type": "command",
58
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" typecheck",
59
+ "async": true
60
+ }
61
+ ]
62
+ },
63
+ {
64
+ "matcher": "Skill",
65
+ "hooks": [
66
+ {
67
+ "type": "command",
68
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" metrics-collector",
69
+ "async": true
70
+ }
71
+ ]
72
+ }
73
+ ],
74
+ "PreCompact": [
75
+ {
76
+ "matcher": ".*",
77
+ "hooks": [
78
+ {
79
+ "type": "command",
80
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" pre-compact",
81
+ "async": false
82
+ }
83
+ ]
84
+ }
85
+ ],
86
+ "Stop": [
87
+ {
88
+ "matcher": ".*",
89
+ "hooks": [
90
+ {
91
+ "type": "command",
92
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" post-session-reflect",
93
+ "async": false
94
+ }
95
+ ]
96
+ }
97
+ ]
98
+ }
99
+ }
@@ -0,0 +1,42 @@
1
+ // Rune Metrics Collector Hook
2
+ // PostToolUse on Skill — captures skill invocations for H3 mesh analytics
3
+ // Append-only JSONL to tmpdir. Flushed to .rune/metrics/ at session end.
4
+ // Async: true — never blocks skill execution.
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const os = require('os');
9
+
10
+ const cwd = process.cwd();
11
+ const hash = Buffer.from(cwd).toString('base64url').slice(0, 16);
12
+ const metricsFile = path.join(os.tmpdir(), `rune-metrics-${hash}.jsonl`);
13
+
14
+ // Extract skill name from tool input
15
+ const toolInput = process.env.CLAUDE_TOOL_INPUT || '';
16
+ let skillName = 'unknown';
17
+ try {
18
+ const parsed = JSON.parse(toolInput);
19
+ // Skill tool input has { skill: "rune:cook" } or { skill: "cook" }
20
+ const raw = parsed.skill || parsed.name || '';
21
+ skillName = raw.replace(/^rune:/, '');
22
+ } catch {
23
+ // If not JSON, try raw string match
24
+ const match = toolInput.match(/(?:rune:)?([a-z][\w-]*)/i);
25
+ if (match) skillName = match[1];
26
+ }
27
+
28
+ if (skillName && skillName !== 'unknown') {
29
+ const entry = JSON.stringify({
30
+ ts: new Date().toISOString(),
31
+ skill: skillName,
32
+ event: 'invoke'
33
+ });
34
+
35
+ try {
36
+ fs.appendFileSync(metricsFile, entry + '\n');
37
+ } catch {
38
+ // Non-critical — metrics are best-effort
39
+ }
40
+ }
41
+
42
+ process.exit(0);
@@ -0,0 +1,153 @@
1
+ // Rune Post-Session Reflect Hook
2
+ // 1. Flushes session metrics from tmpdir to .rune/metrics/ (H3 Intelligence)
3
+ // 2. Displays structured self-review checklist at session end (Stop event)
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const os = require('os');
8
+
9
+ const cwd = process.cwd();
10
+ const hash = Buffer.from(cwd).toString('base64url').slice(0, 16);
11
+
12
+ // === H3: Flush Session Metrics ===
13
+
14
+ const metricsJsonl = path.join(os.tmpdir(), `rune-metrics-${hash}.jsonl`);
15
+ const counterFile = path.join(os.tmpdir(), `rune-context-watch-${hash}.json`);
16
+ const runeMetricsDir = path.join(cwd, '.rune', 'metrics');
17
+
18
+ try {
19
+ flushMetrics();
20
+ } catch (e) {
21
+ // Metrics flush is best-effort — never block session end
22
+ // Silently ignore errors
23
+ }
24
+
25
+ function flushMetrics() {
26
+ // Read session skill invocations from tmpdir JSONL
27
+ let skillEvents = [];
28
+ if (fs.existsSync(metricsJsonl)) {
29
+ const lines = fs.readFileSync(metricsJsonl, 'utf-8').trim().split('\n').filter(Boolean);
30
+ for (const line of lines) {
31
+ try { skillEvents.push(JSON.parse(line)); } catch { /* skip malformed */ }
32
+ }
33
+ }
34
+
35
+ // Read context-watch state for tool counts and session timing
36
+ let watchState = { count: 0, sessionStart: null, toolCounts: {} };
37
+ if (fs.existsSync(counterFile)) {
38
+ try {
39
+ watchState = JSON.parse(fs.readFileSync(counterFile, 'utf-8'));
40
+ } catch { /* use defaults */ }
41
+ }
42
+
43
+ // Nothing to flush if no data
44
+ if (skillEvents.length === 0 && watchState.count === 0) return;
45
+
46
+ // Ensure .rune/metrics/ exists
47
+ fs.mkdirSync(runeMetricsDir, { recursive: true });
48
+
49
+ const now = new Date().toISOString();
50
+ const sessionStart = watchState.sessionStart || now;
51
+ const durationMin = Math.round((new Date(now) - new Date(sessionStart)) / 60000);
52
+
53
+ // Build skill usage map
54
+ const skillCounts = {};
55
+ const skillChain = [];
56
+ for (const evt of skillEvents) {
57
+ skillCounts[evt.skill] = (skillCounts[evt.skill] || 0) + 1;
58
+ skillChain.push(evt.skill);
59
+ }
60
+
61
+ // Determine primary skill (most invoked)
62
+ const primarySkill = Object.entries(skillCounts)
63
+ .sort((a, b) => b[1] - a[1])[0]?.[0] || 'none';
64
+
65
+ // Generate session ID
66
+ const sessionId = `s-${now.slice(0, 10).replace(/-/g, '')}-${now.slice(11, 19).replace(/:/g, '')}`;
67
+
68
+ // 1. Append to sessions.jsonl
69
+ const sessionEntry = {
70
+ id: sessionId,
71
+ date: now.slice(0, 10),
72
+ duration_min: durationMin,
73
+ tool_calls: watchState.count,
74
+ tool_distribution: watchState.toolCounts,
75
+ skill_invocations: skillEvents.length,
76
+ skills_used: Object.keys(skillCounts),
77
+ primary_skill: primarySkill
78
+ };
79
+
80
+ const sessionsFile = path.join(runeMetricsDir, 'sessions.jsonl');
81
+ fs.appendFileSync(sessionsFile, JSON.stringify(sessionEntry) + '\n');
82
+
83
+ // Cap at 100 sessions (rotate oldest)
84
+ try {
85
+ const allLines = fs.readFileSync(sessionsFile, 'utf-8').trim().split('\n').filter(Boolean);
86
+ if (allLines.length > 100) {
87
+ fs.writeFileSync(sessionsFile, allLines.slice(-100).join('\n') + '\n');
88
+ }
89
+ } catch { /* cap is best-effort */ }
90
+
91
+ // 2. Merge into skills.json (running totals)
92
+ const skillsFile = path.join(runeMetricsDir, 'skills.json');
93
+ let skillsData = { version: 1, updated: now, skills: {} };
94
+ if (fs.existsSync(skillsFile)) {
95
+ try {
96
+ skillsData = JSON.parse(fs.readFileSync(skillsFile, 'utf-8'));
97
+ } catch { /* start fresh */ }
98
+ }
99
+
100
+ for (const [skill, count] of Object.entries(skillCounts)) {
101
+ if (!skillsData.skills[skill]) {
102
+ skillsData.skills[skill] = { total_invocations: 0, last_used: now.slice(0, 10) };
103
+ }
104
+ skillsData.skills[skill].total_invocations += count;
105
+ skillsData.skills[skill].last_used = now.slice(0, 10);
106
+ }
107
+ skillsData.updated = now;
108
+
109
+ fs.writeFileSync(skillsFile, JSON.stringify(skillsData, null, 2) + '\n');
110
+
111
+ // 3. Append to chains.jsonl
112
+ if (skillChain.length > 0) {
113
+ const chainsFile = path.join(runeMetricsDir, 'chains.jsonl');
114
+ const chainEntry = {
115
+ session: sessionId,
116
+ chain: skillChain,
117
+ depth: skillChain.length
118
+ };
119
+ fs.appendFileSync(chainsFile, JSON.stringify(chainEntry) + '\n');
120
+ }
121
+
122
+ // 4. Cleanup tmpdir files
123
+ try { fs.unlinkSync(metricsJsonl); } catch { /* already gone */ }
124
+ // Note: counterFile is cleaned by session-start hook on next session
125
+
126
+ // Report metrics flush
127
+ const skillList = Object.entries(skillCounts)
128
+ .sort((a, b) => b[1] - a[1])
129
+ .map(([s, c]) => `${s}(${c})`)
130
+ .join(', ');
131
+
132
+ console.log(`\n📊 [Rune metrics] Session ${sessionId} — ${durationMin}min, ${watchState.count} tool calls, ${skillEvents.length} skill invocations`);
133
+ if (skillList) console.log(` Skills: ${skillList}`);
134
+ console.log(` Saved to .rune/metrics/\n`);
135
+ }
136
+
137
+ // === Original: Verification Checklist ===
138
+
139
+ console.log(`
140
+ ┌─────────────────────────────────────────────────────┐
141
+ │ Rune Session End — Verification Checklist │
142
+ ├─────────────────────────────────────────────────────┤
143
+ │ Before closing this session, confirm: │
144
+ │ │
145
+ │ □ All TodoWrite tasks marked complete? │
146
+ │ □ Tests ran and passing? │
147
+ │ □ No hardcoded secrets introduced? │
148
+ │ □ If schema changed: migration + rollback exist? │
149
+ │ □ Verification ran (lint + types + build)? │
150
+ │ │
151
+ │ If any item is unclear → address it now. │
152
+ └─────────────────────────────────────────────────────┘
153
+ `);