@rune-kit/rune 2.10.0 ā 2.12.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/LICENSE +21 -21
- package/README.md +65 -6
- package/commands/rune.md +168 -168
- package/compiler/__tests__/detect-invariants.test.js +136 -0
- package/compiler/__tests__/doctor-mesh.test.js +229 -0
- package/compiler/__tests__/hook-dispatch.test.js +91 -0
- package/compiler/__tests__/hooks-antigravity.test.js +118 -0
- package/compiler/__tests__/hooks-cursor.test.js +139 -0
- package/compiler/__tests__/hooks-install.test.js +305 -0
- package/compiler/__tests__/hooks-merge.test.js +204 -0
- package/compiler/__tests__/hooks-tiers.test.js +519 -0
- package/compiler/__tests__/hooks-windsurf.test.js +115 -0
- package/compiler/__tests__/inject-claude-md.test.js +152 -0
- package/compiler/__tests__/load-invariants.test.js +408 -0
- package/compiler/__tests__/onboard-invariants.test.js +240 -0
- package/compiler/adapters/hooks/antigravity.js +140 -0
- package/compiler/adapters/hooks/claude.js +166 -0
- package/compiler/adapters/hooks/cursor.js +191 -0
- package/compiler/adapters/hooks/index.js +82 -0
- package/compiler/adapters/hooks/tier-emitter.js +182 -0
- package/compiler/adapters/hooks/windsurf.js +202 -0
- package/compiler/bin/rune.js +196 -6
- package/compiler/commands/hook-dispatch.js +87 -0
- package/compiler/commands/hooks/install.js +120 -0
- package/compiler/commands/hooks/merge.js +211 -0
- package/compiler/commands/hooks/presets.js +116 -0
- package/compiler/commands/hooks/status.js +112 -0
- package/compiler/commands/hooks/tiers.js +221 -0
- package/compiler/commands/hooks/uninstall.js +94 -0
- package/compiler/doctor.js +236 -0
- package/contexts/dev.md +34 -34
- package/contexts/research.md +43 -43
- package/contexts/review.md +55 -55
- package/extensions/ai-ml/PACK.md +88 -88
- package/extensions/ai-ml/skills/ai-agents.md +172 -172
- package/extensions/ai-ml/skills/code-sandbox.md +187 -187
- package/extensions/ai-ml/skills/deep-research.md +146 -146
- package/extensions/ai-ml/skills/embedding-search.md +66 -66
- package/extensions/ai-ml/skills/fine-tuning-guide.md +74 -74
- package/extensions/ai-ml/skills/llm-architect.md +125 -125
- package/extensions/ai-ml/skills/llm-integration.md +64 -64
- package/extensions/ai-ml/skills/prompt-patterns.md +72 -72
- package/extensions/ai-ml/skills/rag-patterns.md +66 -66
- package/extensions/ai-ml/skills/web-extraction.md +114 -114
- package/extensions/analytics/PACK.md +92 -92
- package/extensions/analytics/skills/ab-testing.md +72 -72
- package/extensions/analytics/skills/dashboard-patterns.md +83 -83
- package/extensions/analytics/skills/data-validation.md +68 -68
- package/extensions/analytics/skills/funnel-analysis.md +81 -81
- package/extensions/analytics/skills/sql-patterns.md +57 -57
- package/extensions/analytics/skills/statistical-analysis.md +79 -79
- package/extensions/analytics/skills/tracking-setup.md +71 -71
- package/extensions/backend/PACK.md +104 -104
- package/extensions/backend/skills/api-patterns.md +84 -84
- package/extensions/backend/skills/async-pipeline.md +193 -193
- package/extensions/backend/skills/auth-patterns.md +97 -97
- package/extensions/backend/skills/background-jobs.md +133 -133
- package/extensions/backend/skills/caching-patterns.md +108 -108
- package/extensions/backend/skills/cli-generation.md +133 -133
- package/extensions/backend/skills/database-patterns.md +87 -87
- package/extensions/backend/skills/middleware-patterns.md +104 -104
- package/extensions/chrome-ext/PACK.md +93 -93
- package/extensions/chrome-ext/skills/cws-preflight.md +143 -143
- package/extensions/chrome-ext/skills/cws-publish.md +104 -104
- package/extensions/chrome-ext/skills/ext-ai-integration.md +251 -251
- package/extensions/chrome-ext/skills/ext-messaging.md +139 -139
- package/extensions/chrome-ext/skills/ext-storage.md +133 -133
- package/extensions/chrome-ext/skills/mv3-scaffold.md +164 -164
- package/extensions/content/PACK.md +96 -96
- package/extensions/content/skills/blog-patterns.md +88 -88
- package/extensions/content/skills/cms-integration.md +131 -131
- package/extensions/content/skills/content-scoring.md +107 -107
- package/extensions/content/skills/i18n.md +83 -83
- package/extensions/content/skills/mdx-authoring.md +137 -137
- package/extensions/content/skills/reference.md +1014 -1014
- package/extensions/content/skills/seo-patterns.md +67 -67
- package/extensions/content/skills/video-repurpose.md +153 -153
- package/extensions/devops/PACK.md +101 -101
- package/extensions/devops/skills/chaos-testing.md +67 -67
- package/extensions/devops/skills/ci-cd.md +75 -75
- package/extensions/devops/skills/docker.md +58 -58
- package/extensions/devops/skills/edge-serverless.md +163 -163
- package/extensions/devops/skills/infra-as-code.md +158 -158
- package/extensions/devops/skills/kubernetes.md +110 -110
- package/extensions/devops/skills/monitoring.md +57 -57
- package/extensions/devops/skills/server-setup.md +64 -64
- package/extensions/devops/skills/ssl-domain.md +42 -42
- package/extensions/ecommerce/PACK.md +116 -116
- package/extensions/ecommerce/skills/cart-system.md +79 -79
- package/extensions/ecommerce/skills/inventory-mgmt.md +102 -102
- package/extensions/ecommerce/skills/order-management.md +126 -126
- package/extensions/ecommerce/skills/payment-integration.md +472 -472
- package/extensions/ecommerce/skills/shopify-dev.md +69 -69
- package/extensions/ecommerce/skills/subscription-billing.md +93 -93
- package/extensions/ecommerce/skills/tax-compliance.md +117 -117
- package/extensions/gamedev/PACK.md +142 -142
- package/extensions/gamedev/skills/asset-pipeline.md +74 -74
- package/extensions/gamedev/skills/audio-system.md +129 -129
- package/extensions/gamedev/skills/camera-system.md +87 -87
- package/extensions/gamedev/skills/ecs.md +98 -98
- package/extensions/gamedev/skills/game-loops.md +72 -72
- package/extensions/gamedev/skills/input-system.md +199 -199
- package/extensions/gamedev/skills/multiplayer.md +180 -180
- package/extensions/gamedev/skills/particles.md +105 -105
- package/extensions/gamedev/skills/physics-engine.md +89 -89
- package/extensions/gamedev/skills/scene-management.md +146 -146
- package/extensions/gamedev/skills/threejs-patterns.md +90 -90
- package/extensions/gamedev/skills/webgl.md +71 -71
- package/extensions/mobile/PACK.md +106 -106
- package/extensions/mobile/skills/app-store-connect.md +152 -152
- package/extensions/mobile/skills/app-store-prep.md +66 -66
- package/extensions/mobile/skills/deep-linking.md +109 -109
- package/extensions/mobile/skills/flutter.md +60 -60
- package/extensions/mobile/skills/ios-build-pipeline.md +142 -142
- package/extensions/mobile/skills/native-bridge.md +66 -66
- package/extensions/mobile/skills/ota-updates.md +97 -97
- package/extensions/mobile/skills/push-notifications.md +111 -111
- package/extensions/mobile/skills/react-native.md +82 -82
- package/extensions/saas/PACK.md +116 -116
- package/extensions/saas/skills/billing-integration.md +200 -200
- package/extensions/saas/skills/feature-flags.md +130 -130
- package/extensions/saas/skills/multi-tenant.md +103 -103
- package/extensions/saas/skills/onboarding-flow.md +139 -139
- package/extensions/saas/skills/subscription-flow.md +95 -95
- package/extensions/saas/skills/team-management.md +144 -144
- package/extensions/security/PACK.md +99 -99
- package/extensions/security/skills/api-security.md +140 -140
- package/extensions/security/skills/compliance.md +68 -68
- package/extensions/security/skills/owasp-audit.md +64 -64
- package/extensions/security/skills/pentest-patterns.md +77 -77
- package/extensions/security/skills/secret-mgmt.md +65 -65
- package/extensions/security/skills/supply-chain.md +65 -65
- package/extensions/trading/PACK.md +80 -80
- package/extensions/trading/skills/chart-components.md +55 -55
- package/extensions/trading/skills/experiment-loop.md +125 -125
- package/extensions/trading/skills/fintech-patterns.md +47 -47
- package/extensions/trading/skills/indicator-library.md +58 -58
- package/extensions/trading/skills/quant-analysis.md +111 -111
- package/extensions/trading/skills/realtime-data.md +58 -58
- package/extensions/trading/skills/trade-logic.md +104 -104
- package/extensions/ui/PACK.md +130 -130
- package/extensions/ui/skills/a11y-audit.md +91 -91
- package/extensions/ui/skills/animation-patterns.md +127 -127
- package/extensions/ui/skills/component-patterns.md +100 -100
- package/extensions/ui/skills/design-decision.md +108 -108
- package/extensions/ui/skills/design-system.md +68 -68
- package/extensions/ui/skills/landing-patterns.md +155 -155
- package/extensions/ui/skills/palette-picker.md +173 -173
- package/extensions/ui/skills/react-health.md +90 -90
- package/extensions/ui/skills/type-system.md +125 -125
- package/extensions/ui/skills/web-vitals.md +153 -153
- package/extensions/zalo/PACK.md +145 -145
- package/extensions/zalo/skills/zalo-oa-mcp.md +317 -317
- package/extensions/zalo/skills/zalo-oa-messaging.md +429 -429
- package/extensions/zalo/skills/zalo-oa-setup.md +236 -236
- package/extensions/zalo/skills/zalo-oa-webhook.md +189 -189
- package/extensions/zalo/skills/zalo-personal-messaging.md +194 -194
- package/extensions/zalo/skills/zalo-personal-setup.md +153 -153
- package/extensions/zalo/skills/zalo-rate-guard.md +219 -219
- package/hooks/auto-format/index.cjs +48 -48
- package/hooks/hooks.json +111 -111
- package/hooks/post-session-reflect/index.cjs +189 -189
- package/hooks/pre-compact/index.cjs +95 -95
- package/hooks/run-hook.cmd +1 -1
- package/hooks/secrets-scan/index.cjs +100 -100
- package/hooks/session-start/index.cjs +71 -71
- package/hooks/typecheck/index.cjs +65 -65
- package/package.json +63 -63
- package/references/ui-pro-max-data/LICENSE-UI-PRO-MAX +21 -21
- package/references/ui-pro-max-data/charts.csv +26 -26
- package/references/ui-pro-max-data/colors.csv +161 -161
- package/references/ui-pro-max-data/styles.csv +68 -68
- package/references/ui-pro-max-data/typography.csv +74 -74
- package/references/ui-pro-max-data/ui-reasoning.csv +162 -162
- package/references/ui-pro-max-data/ux-guidelines.csv +99 -99
- package/skills/adversary/SKILL.md +283 -283
- package/skills/asset-creator/SKILL.md +157 -157
- package/skills/audit/SKILL.md +147 -2
- package/skills/autopsy/SKILL.md +335 -335
- package/skills/ba/SKILL.md +85 -1
- package/skills/brainstorm/SKILL.md +380 -342
- package/skills/browser-pilot/SKILL.md +169 -168
- package/skills/constraint-check/SKILL.md +165 -165
- package/skills/context-engine/SKILL.md +408 -404
- package/skills/cook/SKILL.md +917 -863
- package/skills/db/SKILL.md +273 -273
- package/skills/debug/SKILL.md +465 -465
- package/skills/dependency-doctor/SKILL.md +265 -235
- package/skills/deploy/SKILL.md +274 -231
- package/skills/design/DESIGN-REFERENCE.md +365 -365
- package/skills/design/SKILL.md +590 -589
- package/skills/doc-processor/SKILL.md +254 -254
- package/skills/docs/SKILL.md +374 -374
- package/skills/docs-seeker/SKILL.md +178 -177
- package/skills/fix/SKILL.md +332 -330
- package/skills/git/SKILL.md +339 -339
- package/skills/hallucination-guard/SKILL.md +220 -219
- package/skills/incident/SKILL.md +254 -253
- package/skills/integrity-check/SKILL.md +169 -169
- package/skills/journal/SKILL.md +241 -240
- package/skills/launch/SKILL.md +344 -344
- package/skills/logic-guardian/SKILL.md +269 -251
- package/skills/marketing/SKILL.md +351 -289
- package/skills/mcp-builder/SKILL.md +425 -425
- package/skills/neural-memory/SKILL.md +359 -362
- package/skills/onboard/SKILL.md +432 -403
- package/skills/onboard/references/invariants-template.md +76 -0
- package/skills/onboard/scripts/detect-invariants.js +439 -0
- package/skills/onboard/scripts/inject-claude-md.js +150 -0
- package/skills/onboard/scripts/onboard-invariants.js +194 -0
- package/skills/perf/SKILL.md +347 -346
- package/skills/plan/SKILL.md +435 -428
- package/skills/preflight/SKILL.md +415 -415
- package/skills/problem-solver/SKILL.md +380 -284
- package/skills/rescue/SKILL.md +474 -474
- package/skills/research/SKILL.md +4 -0
- package/skills/retro/SKILL.md +3 -1
- package/skills/review/SKILL.md +614 -588
- package/skills/review-intake/SKILL.md +249 -249
- package/skills/safeguard/SKILL.md +200 -200
- package/skills/sast/SKILL.md +190 -190
- package/skills/scaffold/SKILL.md +328 -287
- package/skills/scope-guard/SKILL.md +183 -180
- package/skills/scout/SKILL.md +269 -263
- package/skills/sentinel/SKILL.md +384 -381
- package/skills/sentinel-env/SKILL.md +254 -254
- package/skills/sequential-thinking/SKILL.md +234 -234
- package/skills/session-bridge/SKILL.md +595 -543
- package/skills/session-bridge/scripts/load-invariants.js +397 -0
- package/skills/skill-forge/SKILL.md +581 -581
- package/skills/skill-router/SKILL.md +3 -0
- package/skills/slides/SKILL.md +19 -0
- package/skills/surgeon/SKILL.md +215 -215
- package/skills/team/SKILL.md +557 -537
- package/skills/test/SKILL.md +620 -614
- package/skills/trend-scout/SKILL.md +145 -145
- package/skills/verification/SKILL.md +334 -326
- package/skills/video-creator/SKILL.md +201 -201
- package/skills/watchdog/SKILL.md +168 -168
- package/skills/worktree/SKILL.md +140 -140
package/hooks/hooks.json
CHANGED
|
@@ -1,111 +1,111 @@
|
|
|
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
|
-
"UserPromptSubmit": [
|
|
16
|
-
{
|
|
17
|
-
"matcher": ".*",
|
|
18
|
-
"hooks": [
|
|
19
|
-
{
|
|
20
|
-
"type": "command",
|
|
21
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" intent-router",
|
|
22
|
-
"async": true
|
|
23
|
-
}
|
|
24
|
-
]
|
|
25
|
-
}
|
|
26
|
-
],
|
|
27
|
-
"PreToolUse": [
|
|
28
|
-
{
|
|
29
|
-
"matcher": "Read|Write|Edit",
|
|
30
|
-
"hooks": [
|
|
31
|
-
{
|
|
32
|
-
"type": "command",
|
|
33
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" pre-tool-guard",
|
|
34
|
-
"async": false
|
|
35
|
-
}
|
|
36
|
-
]
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"matcher": "Edit|Write",
|
|
40
|
-
"hooks": [
|
|
41
|
-
{
|
|
42
|
-
"type": "command",
|
|
43
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" context-watch",
|
|
44
|
-
"async": true
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"matcher": "Bash",
|
|
50
|
-
"hooks": [
|
|
51
|
-
{
|
|
52
|
-
"type": "command",
|
|
53
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" secrets-scan",
|
|
54
|
-
"async": false
|
|
55
|
-
}
|
|
56
|
-
]
|
|
57
|
-
}
|
|
58
|
-
],
|
|
59
|
-
"PostToolUse": [
|
|
60
|
-
{
|
|
61
|
-
"matcher": "Edit|Write",
|
|
62
|
-
"hooks": [
|
|
63
|
-
{
|
|
64
|
-
"type": "command",
|
|
65
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" auto-format",
|
|
66
|
-
"async": true
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
"type": "command",
|
|
70
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" typecheck",
|
|
71
|
-
"async": true
|
|
72
|
-
}
|
|
73
|
-
]
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"matcher": "Skill",
|
|
77
|
-
"hooks": [
|
|
78
|
-
{
|
|
79
|
-
"type": "command",
|
|
80
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" metrics-collector",
|
|
81
|
-
"async": true
|
|
82
|
-
}
|
|
83
|
-
]
|
|
84
|
-
}
|
|
85
|
-
],
|
|
86
|
-
"PreCompact": [
|
|
87
|
-
{
|
|
88
|
-
"matcher": ".*",
|
|
89
|
-
"hooks": [
|
|
90
|
-
{
|
|
91
|
-
"type": "command",
|
|
92
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" pre-compact",
|
|
93
|
-
"async": false
|
|
94
|
-
}
|
|
95
|
-
]
|
|
96
|
-
}
|
|
97
|
-
],
|
|
98
|
-
"Stop": [
|
|
99
|
-
{
|
|
100
|
-
"matcher": ".*",
|
|
101
|
-
"hooks": [
|
|
102
|
-
{
|
|
103
|
-
"type": "command",
|
|
104
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" post-session-reflect",
|
|
105
|
-
"async": false
|
|
106
|
-
}
|
|
107
|
-
]
|
|
108
|
-
}
|
|
109
|
-
]
|
|
110
|
-
}
|
|
111
|
-
}
|
|
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
|
+
"UserPromptSubmit": [
|
|
16
|
+
{
|
|
17
|
+
"matcher": ".*",
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" intent-router",
|
|
22
|
+
"async": true
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"PreToolUse": [
|
|
28
|
+
{
|
|
29
|
+
"matcher": "Read|Write|Edit",
|
|
30
|
+
"hooks": [
|
|
31
|
+
{
|
|
32
|
+
"type": "command",
|
|
33
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" pre-tool-guard",
|
|
34
|
+
"async": false
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"matcher": "Edit|Write",
|
|
40
|
+
"hooks": [
|
|
41
|
+
{
|
|
42
|
+
"type": "command",
|
|
43
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" context-watch",
|
|
44
|
+
"async": true
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"matcher": "Bash",
|
|
50
|
+
"hooks": [
|
|
51
|
+
{
|
|
52
|
+
"type": "command",
|
|
53
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" secrets-scan",
|
|
54
|
+
"async": false
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"PostToolUse": [
|
|
60
|
+
{
|
|
61
|
+
"matcher": "Edit|Write",
|
|
62
|
+
"hooks": [
|
|
63
|
+
{
|
|
64
|
+
"type": "command",
|
|
65
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" auto-format",
|
|
66
|
+
"async": true
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "command",
|
|
70
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" typecheck",
|
|
71
|
+
"async": true
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"matcher": "Skill",
|
|
77
|
+
"hooks": [
|
|
78
|
+
{
|
|
79
|
+
"type": "command",
|
|
80
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" metrics-collector",
|
|
81
|
+
"async": true
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"PreCompact": [
|
|
87
|
+
{
|
|
88
|
+
"matcher": ".*",
|
|
89
|
+
"hooks": [
|
|
90
|
+
{
|
|
91
|
+
"type": "command",
|
|
92
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" pre-compact",
|
|
93
|
+
"async": false
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"Stop": [
|
|
99
|
+
{
|
|
100
|
+
"matcher": ".*",
|
|
101
|
+
"hooks": [
|
|
102
|
+
{
|
|
103
|
+
"type": "command",
|
|
104
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cjs\" post-session-reflect",
|
|
105
|
+
"async": false
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -1,189 +1,189 @@
|
|
|
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
|
-
// Resolve skill names ā expected model from agent frontmatter
|
|
19
|
-
// Reads agents/*.md at flush time ā no runtime model detection needed
|
|
20
|
-
// Map skill names ā models, weighted by invocation count
|
|
21
|
-
// skillCounts: { skillName: invocationCount }
|
|
22
|
-
function resolveSkillModels(skillCounts) {
|
|
23
|
-
const models = {};
|
|
24
|
-
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || path.join(__dirname, '..', '..');
|
|
25
|
-
const agentsDir = path.join(pluginRoot, 'agents');
|
|
26
|
-
|
|
27
|
-
if (!fs.existsSync(agentsDir)) return models;
|
|
28
|
-
|
|
29
|
-
for (const [skill, count] of Object.entries(skillCounts)) {
|
|
30
|
-
try {
|
|
31
|
-
const agentFile = path.join(agentsDir, `${skill}.md`);
|
|
32
|
-
if (!fs.existsSync(agentFile)) continue;
|
|
33
|
-
const content = fs.readFileSync(agentFile, 'utf-8');
|
|
34
|
-
const match = content.match(/^model:\s*(\w+)/m);
|
|
35
|
-
if (match) {
|
|
36
|
-
const model = match[1];
|
|
37
|
-
models[model] = (models[model] || 0) + count;
|
|
38
|
-
}
|
|
39
|
-
} catch { /* best-effort */ }
|
|
40
|
-
}
|
|
41
|
-
return models;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
flushMetrics();
|
|
46
|
-
} catch (e) {
|
|
47
|
-
// Metrics flush is best-effort ā never block session end
|
|
48
|
-
// Silently ignore errors
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function flushMetrics() {
|
|
52
|
-
// Read session skill invocations from tmpdir JSONL
|
|
53
|
-
let skillEvents = [];
|
|
54
|
-
if (fs.existsSync(metricsJsonl)) {
|
|
55
|
-
const lines = fs.readFileSync(metricsJsonl, 'utf-8').trim().split('\n').filter(Boolean);
|
|
56
|
-
for (const line of lines) {
|
|
57
|
-
try { skillEvents.push(JSON.parse(line)); } catch { /* skip malformed */ }
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Read context-watch state for tool counts and session timing
|
|
62
|
-
let watchState = { count: 0, sessionStart: null, sessionId: null, toolCounts: {} };
|
|
63
|
-
if (fs.existsSync(counterFile)) {
|
|
64
|
-
try {
|
|
65
|
-
watchState = JSON.parse(fs.readFileSync(counterFile, 'utf-8'));
|
|
66
|
-
} catch { /* use defaults */ }
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Nothing to flush if no data
|
|
70
|
-
if (skillEvents.length === 0 && watchState.count === 0) return;
|
|
71
|
-
|
|
72
|
-
// Ensure .rune/metrics/ exists
|
|
73
|
-
fs.mkdirSync(runeMetricsDir, { recursive: true });
|
|
74
|
-
|
|
75
|
-
const now = new Date().toISOString();
|
|
76
|
-
const sessionStart = watchState.sessionStart || now;
|
|
77
|
-
const durationMin = Math.round((new Date(now) - new Date(sessionStart)) / 60000);
|
|
78
|
-
|
|
79
|
-
// Build skill usage map and duration aggregation
|
|
80
|
-
const skillCounts = {};
|
|
81
|
-
const skillDurations = {};
|
|
82
|
-
const skillChain = [];
|
|
83
|
-
for (const evt of skillEvents) {
|
|
84
|
-
skillCounts[evt.skill] = (skillCounts[evt.skill] || 0) + 1;
|
|
85
|
-
skillChain.push(evt.skill);
|
|
86
|
-
if (evt.duration_ms != null) {
|
|
87
|
-
skillDurations[evt.skill] = (skillDurations[evt.skill] || 0) + evt.duration_ms;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Determine primary skill (most invoked)
|
|
92
|
-
const primarySkill = Object.entries(skillCounts)
|
|
93
|
-
.sort((a, b) => b[1] - a[1])[0]?.[0] || 'none';
|
|
94
|
-
|
|
95
|
-
// Map skills to expected models from agent definitions (weighted by invocation count)
|
|
96
|
-
const modelsUsed = resolveSkillModels(skillCounts);
|
|
97
|
-
|
|
98
|
-
// Use session ID from context-watch (shared) or generate new
|
|
99
|
-
const sessionId = watchState.sessionId
|
|
100
|
-
|| `s-${now.slice(0, 10).replace(/-/g, '')}-${now.slice(11, 19).replace(/:/g, '')}`;
|
|
101
|
-
|
|
102
|
-
// 1. Append to sessions.jsonl
|
|
103
|
-
const sessionEntry = {
|
|
104
|
-
id: sessionId,
|
|
105
|
-
date: now.slice(0, 10),
|
|
106
|
-
duration_min: durationMin,
|
|
107
|
-
tool_calls: watchState.count,
|
|
108
|
-
tool_distribution: watchState.toolCounts,
|
|
109
|
-
skill_invocations: skillEvents.length,
|
|
110
|
-
skills_used: Object.keys(skillCounts),
|
|
111
|
-
primary_skill: primarySkill,
|
|
112
|
-
models_used: modelsUsed,
|
|
113
|
-
skill_durations: Object.keys(skillDurations).length > 0 ? skillDurations : undefined
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const sessionsFile = path.join(runeMetricsDir, 'sessions.jsonl');
|
|
117
|
-
fs.appendFileSync(sessionsFile, JSON.stringify(sessionEntry) + '\n');
|
|
118
|
-
|
|
119
|
-
// Cap at 100 sessions (rotate oldest)
|
|
120
|
-
try {
|
|
121
|
-
const allLines = fs.readFileSync(sessionsFile, 'utf-8').trim().split('\n').filter(Boolean);
|
|
122
|
-
if (allLines.length > 100) {
|
|
123
|
-
fs.writeFileSync(sessionsFile, allLines.slice(-100).join('\n') + '\n');
|
|
124
|
-
}
|
|
125
|
-
} catch { /* cap is best-effort */ }
|
|
126
|
-
|
|
127
|
-
// 2. Merge into skills.json (running totals)
|
|
128
|
-
const skillsFile = path.join(runeMetricsDir, 'skills.json');
|
|
129
|
-
let skillsData = { version: 1, updated: now, skills: {} };
|
|
130
|
-
if (fs.existsSync(skillsFile)) {
|
|
131
|
-
try {
|
|
132
|
-
skillsData = JSON.parse(fs.readFileSync(skillsFile, 'utf-8'));
|
|
133
|
-
} catch { /* start fresh */ }
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
for (const [skill, count] of Object.entries(skillCounts)) {
|
|
137
|
-
if (!skillsData.skills[skill]) {
|
|
138
|
-
skillsData.skills[skill] = { total_invocations: 0, last_used: now.slice(0, 10) };
|
|
139
|
-
}
|
|
140
|
-
skillsData.skills[skill].total_invocations += count;
|
|
141
|
-
skillsData.skills[skill].last_used = now.slice(0, 10);
|
|
142
|
-
}
|
|
143
|
-
skillsData.updated = now;
|
|
144
|
-
|
|
145
|
-
fs.writeFileSync(skillsFile, JSON.stringify(skillsData, null, 2) + '\n');
|
|
146
|
-
|
|
147
|
-
// 3. Append to chains.jsonl
|
|
148
|
-
if (skillChain.length > 0) {
|
|
149
|
-
const chainsFile = path.join(runeMetricsDir, 'chains.jsonl');
|
|
150
|
-
const chainEntry = {
|
|
151
|
-
session: sessionId,
|
|
152
|
-
chain: skillChain,
|
|
153
|
-
depth: skillChain.length
|
|
154
|
-
};
|
|
155
|
-
fs.appendFileSync(chainsFile, JSON.stringify(chainEntry) + '\n');
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 4. Cleanup tmpdir files
|
|
159
|
-
try { fs.unlinkSync(metricsJsonl); } catch { /* already gone */ }
|
|
160
|
-
// Note: counterFile is cleaned by session-start hook on next session
|
|
161
|
-
|
|
162
|
-
// Report metrics flush
|
|
163
|
-
const skillList = Object.entries(skillCounts)
|
|
164
|
-
.sort((a, b) => b[1] - a[1])
|
|
165
|
-
.map(([s, c]) => `${s}(${c})`)
|
|
166
|
-
.join(', ');
|
|
167
|
-
|
|
168
|
-
console.log(`\nš [Rune metrics] Session ${sessionId} ā ${durationMin}min, ${watchState.count} tool calls, ${skillEvents.length} skill invocations`);
|
|
169
|
-
if (skillList) console.log(` Skills: ${skillList}`);
|
|
170
|
-
console.log(` Saved to .rune/metrics/\n`);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// === Original: Verification Checklist ===
|
|
174
|
-
|
|
175
|
-
console.log(`
|
|
176
|
-
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
177
|
-
ā Rune Session End ā Verification Checklist ā
|
|
178
|
-
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
|
|
179
|
-
ā Before closing this session, confirm: ā
|
|
180
|
-
ā ā
|
|
181
|
-
ā ā” All TodoWrite tasks marked complete? ā
|
|
182
|
-
ā ā” Tests ran and passing? ā
|
|
183
|
-
ā ā” No hardcoded secrets introduced? ā
|
|
184
|
-
ā ā” If schema changed: migration + rollback exist? ā
|
|
185
|
-
ā ā” Verification ran (lint + types + build)? ā
|
|
186
|
-
ā ā
|
|
187
|
-
ā If any item is unclear ā address it now. ā
|
|
188
|
-
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
189
|
-
`);
|
|
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
|
+
// Resolve skill names ā expected model from agent frontmatter
|
|
19
|
+
// Reads agents/*.md at flush time ā no runtime model detection needed
|
|
20
|
+
// Map skill names ā models, weighted by invocation count
|
|
21
|
+
// skillCounts: { skillName: invocationCount }
|
|
22
|
+
function resolveSkillModels(skillCounts) {
|
|
23
|
+
const models = {};
|
|
24
|
+
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || path.join(__dirname, '..', '..');
|
|
25
|
+
const agentsDir = path.join(pluginRoot, 'agents');
|
|
26
|
+
|
|
27
|
+
if (!fs.existsSync(agentsDir)) return models;
|
|
28
|
+
|
|
29
|
+
for (const [skill, count] of Object.entries(skillCounts)) {
|
|
30
|
+
try {
|
|
31
|
+
const agentFile = path.join(agentsDir, `${skill}.md`);
|
|
32
|
+
if (!fs.existsSync(agentFile)) continue;
|
|
33
|
+
const content = fs.readFileSync(agentFile, 'utf-8');
|
|
34
|
+
const match = content.match(/^model:\s*(\w+)/m);
|
|
35
|
+
if (match) {
|
|
36
|
+
const model = match[1];
|
|
37
|
+
models[model] = (models[model] || 0) + count;
|
|
38
|
+
}
|
|
39
|
+
} catch { /* best-effort */ }
|
|
40
|
+
}
|
|
41
|
+
return models;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
flushMetrics();
|
|
46
|
+
} catch (e) {
|
|
47
|
+
// Metrics flush is best-effort ā never block session end
|
|
48
|
+
// Silently ignore errors
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function flushMetrics() {
|
|
52
|
+
// Read session skill invocations from tmpdir JSONL
|
|
53
|
+
let skillEvents = [];
|
|
54
|
+
if (fs.existsSync(metricsJsonl)) {
|
|
55
|
+
const lines = fs.readFileSync(metricsJsonl, 'utf-8').trim().split('\n').filter(Boolean);
|
|
56
|
+
for (const line of lines) {
|
|
57
|
+
try { skillEvents.push(JSON.parse(line)); } catch { /* skip malformed */ }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Read context-watch state for tool counts and session timing
|
|
62
|
+
let watchState = { count: 0, sessionStart: null, sessionId: null, toolCounts: {} };
|
|
63
|
+
if (fs.existsSync(counterFile)) {
|
|
64
|
+
try {
|
|
65
|
+
watchState = JSON.parse(fs.readFileSync(counterFile, 'utf-8'));
|
|
66
|
+
} catch { /* use defaults */ }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Nothing to flush if no data
|
|
70
|
+
if (skillEvents.length === 0 && watchState.count === 0) return;
|
|
71
|
+
|
|
72
|
+
// Ensure .rune/metrics/ exists
|
|
73
|
+
fs.mkdirSync(runeMetricsDir, { recursive: true });
|
|
74
|
+
|
|
75
|
+
const now = new Date().toISOString();
|
|
76
|
+
const sessionStart = watchState.sessionStart || now;
|
|
77
|
+
const durationMin = Math.round((new Date(now) - new Date(sessionStart)) / 60000);
|
|
78
|
+
|
|
79
|
+
// Build skill usage map and duration aggregation
|
|
80
|
+
const skillCounts = {};
|
|
81
|
+
const skillDurations = {};
|
|
82
|
+
const skillChain = [];
|
|
83
|
+
for (const evt of skillEvents) {
|
|
84
|
+
skillCounts[evt.skill] = (skillCounts[evt.skill] || 0) + 1;
|
|
85
|
+
skillChain.push(evt.skill);
|
|
86
|
+
if (evt.duration_ms != null) {
|
|
87
|
+
skillDurations[evt.skill] = (skillDurations[evt.skill] || 0) + evt.duration_ms;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Determine primary skill (most invoked)
|
|
92
|
+
const primarySkill = Object.entries(skillCounts)
|
|
93
|
+
.sort((a, b) => b[1] - a[1])[0]?.[0] || 'none';
|
|
94
|
+
|
|
95
|
+
// Map skills to expected models from agent definitions (weighted by invocation count)
|
|
96
|
+
const modelsUsed = resolveSkillModels(skillCounts);
|
|
97
|
+
|
|
98
|
+
// Use session ID from context-watch (shared) or generate new
|
|
99
|
+
const sessionId = watchState.sessionId
|
|
100
|
+
|| `s-${now.slice(0, 10).replace(/-/g, '')}-${now.slice(11, 19).replace(/:/g, '')}`;
|
|
101
|
+
|
|
102
|
+
// 1. Append to sessions.jsonl
|
|
103
|
+
const sessionEntry = {
|
|
104
|
+
id: sessionId,
|
|
105
|
+
date: now.slice(0, 10),
|
|
106
|
+
duration_min: durationMin,
|
|
107
|
+
tool_calls: watchState.count,
|
|
108
|
+
tool_distribution: watchState.toolCounts,
|
|
109
|
+
skill_invocations: skillEvents.length,
|
|
110
|
+
skills_used: Object.keys(skillCounts),
|
|
111
|
+
primary_skill: primarySkill,
|
|
112
|
+
models_used: modelsUsed,
|
|
113
|
+
skill_durations: Object.keys(skillDurations).length > 0 ? skillDurations : undefined
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const sessionsFile = path.join(runeMetricsDir, 'sessions.jsonl');
|
|
117
|
+
fs.appendFileSync(sessionsFile, JSON.stringify(sessionEntry) + '\n');
|
|
118
|
+
|
|
119
|
+
// Cap at 100 sessions (rotate oldest)
|
|
120
|
+
try {
|
|
121
|
+
const allLines = fs.readFileSync(sessionsFile, 'utf-8').trim().split('\n').filter(Boolean);
|
|
122
|
+
if (allLines.length > 100) {
|
|
123
|
+
fs.writeFileSync(sessionsFile, allLines.slice(-100).join('\n') + '\n');
|
|
124
|
+
}
|
|
125
|
+
} catch { /* cap is best-effort */ }
|
|
126
|
+
|
|
127
|
+
// 2. Merge into skills.json (running totals)
|
|
128
|
+
const skillsFile = path.join(runeMetricsDir, 'skills.json');
|
|
129
|
+
let skillsData = { version: 1, updated: now, skills: {} };
|
|
130
|
+
if (fs.existsSync(skillsFile)) {
|
|
131
|
+
try {
|
|
132
|
+
skillsData = JSON.parse(fs.readFileSync(skillsFile, 'utf-8'));
|
|
133
|
+
} catch { /* start fresh */ }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
for (const [skill, count] of Object.entries(skillCounts)) {
|
|
137
|
+
if (!skillsData.skills[skill]) {
|
|
138
|
+
skillsData.skills[skill] = { total_invocations: 0, last_used: now.slice(0, 10) };
|
|
139
|
+
}
|
|
140
|
+
skillsData.skills[skill].total_invocations += count;
|
|
141
|
+
skillsData.skills[skill].last_used = now.slice(0, 10);
|
|
142
|
+
}
|
|
143
|
+
skillsData.updated = now;
|
|
144
|
+
|
|
145
|
+
fs.writeFileSync(skillsFile, JSON.stringify(skillsData, null, 2) + '\n');
|
|
146
|
+
|
|
147
|
+
// 3. Append to chains.jsonl
|
|
148
|
+
if (skillChain.length > 0) {
|
|
149
|
+
const chainsFile = path.join(runeMetricsDir, 'chains.jsonl');
|
|
150
|
+
const chainEntry = {
|
|
151
|
+
session: sessionId,
|
|
152
|
+
chain: skillChain,
|
|
153
|
+
depth: skillChain.length
|
|
154
|
+
};
|
|
155
|
+
fs.appendFileSync(chainsFile, JSON.stringify(chainEntry) + '\n');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 4. Cleanup tmpdir files
|
|
159
|
+
try { fs.unlinkSync(metricsJsonl); } catch { /* already gone */ }
|
|
160
|
+
// Note: counterFile is cleaned by session-start hook on next session
|
|
161
|
+
|
|
162
|
+
// Report metrics flush
|
|
163
|
+
const skillList = Object.entries(skillCounts)
|
|
164
|
+
.sort((a, b) => b[1] - a[1])
|
|
165
|
+
.map(([s, c]) => `${s}(${c})`)
|
|
166
|
+
.join(', ');
|
|
167
|
+
|
|
168
|
+
console.log(`\nš [Rune metrics] Session ${sessionId} ā ${durationMin}min, ${watchState.count} tool calls, ${skillEvents.length} skill invocations`);
|
|
169
|
+
if (skillList) console.log(` Skills: ${skillList}`);
|
|
170
|
+
console.log(` Saved to .rune/metrics/\n`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// === Original: Verification Checklist ===
|
|
174
|
+
|
|
175
|
+
console.log(`
|
|
176
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
177
|
+
ā Rune Session End ā Verification Checklist ā
|
|
178
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
|
|
179
|
+
ā Before closing this session, confirm: ā
|
|
180
|
+
ā ā
|
|
181
|
+
ā ā” All TodoWrite tasks marked complete? ā
|
|
182
|
+
ā ā” Tests ran and passing? ā
|
|
183
|
+
ā ā” No hardcoded secrets introduced? ā
|
|
184
|
+
ā ā” If schema changed: migration + rollback exist? ā
|
|
185
|
+
ā ā” Verification ran (lint + types + build)? ā
|
|
186
|
+
ā ā
|
|
187
|
+
ā If any item is unclear ā address it now. ā
|
|
188
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
189
|
+
`);
|