@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.
Files changed (240) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +65 -6
  3. package/commands/rune.md +168 -168
  4. package/compiler/__tests__/detect-invariants.test.js +136 -0
  5. package/compiler/__tests__/doctor-mesh.test.js +229 -0
  6. package/compiler/__tests__/hook-dispatch.test.js +91 -0
  7. package/compiler/__tests__/hooks-antigravity.test.js +118 -0
  8. package/compiler/__tests__/hooks-cursor.test.js +139 -0
  9. package/compiler/__tests__/hooks-install.test.js +305 -0
  10. package/compiler/__tests__/hooks-merge.test.js +204 -0
  11. package/compiler/__tests__/hooks-tiers.test.js +519 -0
  12. package/compiler/__tests__/hooks-windsurf.test.js +115 -0
  13. package/compiler/__tests__/inject-claude-md.test.js +152 -0
  14. package/compiler/__tests__/load-invariants.test.js +408 -0
  15. package/compiler/__tests__/onboard-invariants.test.js +240 -0
  16. package/compiler/adapters/hooks/antigravity.js +140 -0
  17. package/compiler/adapters/hooks/claude.js +166 -0
  18. package/compiler/adapters/hooks/cursor.js +191 -0
  19. package/compiler/adapters/hooks/index.js +82 -0
  20. package/compiler/adapters/hooks/tier-emitter.js +182 -0
  21. package/compiler/adapters/hooks/windsurf.js +202 -0
  22. package/compiler/bin/rune.js +196 -6
  23. package/compiler/commands/hook-dispatch.js +87 -0
  24. package/compiler/commands/hooks/install.js +120 -0
  25. package/compiler/commands/hooks/merge.js +211 -0
  26. package/compiler/commands/hooks/presets.js +116 -0
  27. package/compiler/commands/hooks/status.js +112 -0
  28. package/compiler/commands/hooks/tiers.js +221 -0
  29. package/compiler/commands/hooks/uninstall.js +94 -0
  30. package/compiler/doctor.js +236 -0
  31. package/contexts/dev.md +34 -34
  32. package/contexts/research.md +43 -43
  33. package/contexts/review.md +55 -55
  34. package/extensions/ai-ml/PACK.md +88 -88
  35. package/extensions/ai-ml/skills/ai-agents.md +172 -172
  36. package/extensions/ai-ml/skills/code-sandbox.md +187 -187
  37. package/extensions/ai-ml/skills/deep-research.md +146 -146
  38. package/extensions/ai-ml/skills/embedding-search.md +66 -66
  39. package/extensions/ai-ml/skills/fine-tuning-guide.md +74 -74
  40. package/extensions/ai-ml/skills/llm-architect.md +125 -125
  41. package/extensions/ai-ml/skills/llm-integration.md +64 -64
  42. package/extensions/ai-ml/skills/prompt-patterns.md +72 -72
  43. package/extensions/ai-ml/skills/rag-patterns.md +66 -66
  44. package/extensions/ai-ml/skills/web-extraction.md +114 -114
  45. package/extensions/analytics/PACK.md +92 -92
  46. package/extensions/analytics/skills/ab-testing.md +72 -72
  47. package/extensions/analytics/skills/dashboard-patterns.md +83 -83
  48. package/extensions/analytics/skills/data-validation.md +68 -68
  49. package/extensions/analytics/skills/funnel-analysis.md +81 -81
  50. package/extensions/analytics/skills/sql-patterns.md +57 -57
  51. package/extensions/analytics/skills/statistical-analysis.md +79 -79
  52. package/extensions/analytics/skills/tracking-setup.md +71 -71
  53. package/extensions/backend/PACK.md +104 -104
  54. package/extensions/backend/skills/api-patterns.md +84 -84
  55. package/extensions/backend/skills/async-pipeline.md +193 -193
  56. package/extensions/backend/skills/auth-patterns.md +97 -97
  57. package/extensions/backend/skills/background-jobs.md +133 -133
  58. package/extensions/backend/skills/caching-patterns.md +108 -108
  59. package/extensions/backend/skills/cli-generation.md +133 -133
  60. package/extensions/backend/skills/database-patterns.md +87 -87
  61. package/extensions/backend/skills/middleware-patterns.md +104 -104
  62. package/extensions/chrome-ext/PACK.md +93 -93
  63. package/extensions/chrome-ext/skills/cws-preflight.md +143 -143
  64. package/extensions/chrome-ext/skills/cws-publish.md +104 -104
  65. package/extensions/chrome-ext/skills/ext-ai-integration.md +251 -251
  66. package/extensions/chrome-ext/skills/ext-messaging.md +139 -139
  67. package/extensions/chrome-ext/skills/ext-storage.md +133 -133
  68. package/extensions/chrome-ext/skills/mv3-scaffold.md +164 -164
  69. package/extensions/content/PACK.md +96 -96
  70. package/extensions/content/skills/blog-patterns.md +88 -88
  71. package/extensions/content/skills/cms-integration.md +131 -131
  72. package/extensions/content/skills/content-scoring.md +107 -107
  73. package/extensions/content/skills/i18n.md +83 -83
  74. package/extensions/content/skills/mdx-authoring.md +137 -137
  75. package/extensions/content/skills/reference.md +1014 -1014
  76. package/extensions/content/skills/seo-patterns.md +67 -67
  77. package/extensions/content/skills/video-repurpose.md +153 -153
  78. package/extensions/devops/PACK.md +101 -101
  79. package/extensions/devops/skills/chaos-testing.md +67 -67
  80. package/extensions/devops/skills/ci-cd.md +75 -75
  81. package/extensions/devops/skills/docker.md +58 -58
  82. package/extensions/devops/skills/edge-serverless.md +163 -163
  83. package/extensions/devops/skills/infra-as-code.md +158 -158
  84. package/extensions/devops/skills/kubernetes.md +110 -110
  85. package/extensions/devops/skills/monitoring.md +57 -57
  86. package/extensions/devops/skills/server-setup.md +64 -64
  87. package/extensions/devops/skills/ssl-domain.md +42 -42
  88. package/extensions/ecommerce/PACK.md +116 -116
  89. package/extensions/ecommerce/skills/cart-system.md +79 -79
  90. package/extensions/ecommerce/skills/inventory-mgmt.md +102 -102
  91. package/extensions/ecommerce/skills/order-management.md +126 -126
  92. package/extensions/ecommerce/skills/payment-integration.md +472 -472
  93. package/extensions/ecommerce/skills/shopify-dev.md +69 -69
  94. package/extensions/ecommerce/skills/subscription-billing.md +93 -93
  95. package/extensions/ecommerce/skills/tax-compliance.md +117 -117
  96. package/extensions/gamedev/PACK.md +142 -142
  97. package/extensions/gamedev/skills/asset-pipeline.md +74 -74
  98. package/extensions/gamedev/skills/audio-system.md +129 -129
  99. package/extensions/gamedev/skills/camera-system.md +87 -87
  100. package/extensions/gamedev/skills/ecs.md +98 -98
  101. package/extensions/gamedev/skills/game-loops.md +72 -72
  102. package/extensions/gamedev/skills/input-system.md +199 -199
  103. package/extensions/gamedev/skills/multiplayer.md +180 -180
  104. package/extensions/gamedev/skills/particles.md +105 -105
  105. package/extensions/gamedev/skills/physics-engine.md +89 -89
  106. package/extensions/gamedev/skills/scene-management.md +146 -146
  107. package/extensions/gamedev/skills/threejs-patterns.md +90 -90
  108. package/extensions/gamedev/skills/webgl.md +71 -71
  109. package/extensions/mobile/PACK.md +106 -106
  110. package/extensions/mobile/skills/app-store-connect.md +152 -152
  111. package/extensions/mobile/skills/app-store-prep.md +66 -66
  112. package/extensions/mobile/skills/deep-linking.md +109 -109
  113. package/extensions/mobile/skills/flutter.md +60 -60
  114. package/extensions/mobile/skills/ios-build-pipeline.md +142 -142
  115. package/extensions/mobile/skills/native-bridge.md +66 -66
  116. package/extensions/mobile/skills/ota-updates.md +97 -97
  117. package/extensions/mobile/skills/push-notifications.md +111 -111
  118. package/extensions/mobile/skills/react-native.md +82 -82
  119. package/extensions/saas/PACK.md +116 -116
  120. package/extensions/saas/skills/billing-integration.md +200 -200
  121. package/extensions/saas/skills/feature-flags.md +130 -130
  122. package/extensions/saas/skills/multi-tenant.md +103 -103
  123. package/extensions/saas/skills/onboarding-flow.md +139 -139
  124. package/extensions/saas/skills/subscription-flow.md +95 -95
  125. package/extensions/saas/skills/team-management.md +144 -144
  126. package/extensions/security/PACK.md +99 -99
  127. package/extensions/security/skills/api-security.md +140 -140
  128. package/extensions/security/skills/compliance.md +68 -68
  129. package/extensions/security/skills/owasp-audit.md +64 -64
  130. package/extensions/security/skills/pentest-patterns.md +77 -77
  131. package/extensions/security/skills/secret-mgmt.md +65 -65
  132. package/extensions/security/skills/supply-chain.md +65 -65
  133. package/extensions/trading/PACK.md +80 -80
  134. package/extensions/trading/skills/chart-components.md +55 -55
  135. package/extensions/trading/skills/experiment-loop.md +125 -125
  136. package/extensions/trading/skills/fintech-patterns.md +47 -47
  137. package/extensions/trading/skills/indicator-library.md +58 -58
  138. package/extensions/trading/skills/quant-analysis.md +111 -111
  139. package/extensions/trading/skills/realtime-data.md +58 -58
  140. package/extensions/trading/skills/trade-logic.md +104 -104
  141. package/extensions/ui/PACK.md +130 -130
  142. package/extensions/ui/skills/a11y-audit.md +91 -91
  143. package/extensions/ui/skills/animation-patterns.md +127 -127
  144. package/extensions/ui/skills/component-patterns.md +100 -100
  145. package/extensions/ui/skills/design-decision.md +108 -108
  146. package/extensions/ui/skills/design-system.md +68 -68
  147. package/extensions/ui/skills/landing-patterns.md +155 -155
  148. package/extensions/ui/skills/palette-picker.md +173 -173
  149. package/extensions/ui/skills/react-health.md +90 -90
  150. package/extensions/ui/skills/type-system.md +125 -125
  151. package/extensions/ui/skills/web-vitals.md +153 -153
  152. package/extensions/zalo/PACK.md +145 -145
  153. package/extensions/zalo/skills/zalo-oa-mcp.md +317 -317
  154. package/extensions/zalo/skills/zalo-oa-messaging.md +429 -429
  155. package/extensions/zalo/skills/zalo-oa-setup.md +236 -236
  156. package/extensions/zalo/skills/zalo-oa-webhook.md +189 -189
  157. package/extensions/zalo/skills/zalo-personal-messaging.md +194 -194
  158. package/extensions/zalo/skills/zalo-personal-setup.md +153 -153
  159. package/extensions/zalo/skills/zalo-rate-guard.md +219 -219
  160. package/hooks/auto-format/index.cjs +48 -48
  161. package/hooks/hooks.json +111 -111
  162. package/hooks/post-session-reflect/index.cjs +189 -189
  163. package/hooks/pre-compact/index.cjs +95 -95
  164. package/hooks/run-hook.cmd +1 -1
  165. package/hooks/secrets-scan/index.cjs +100 -100
  166. package/hooks/session-start/index.cjs +71 -71
  167. package/hooks/typecheck/index.cjs +65 -65
  168. package/package.json +63 -63
  169. package/references/ui-pro-max-data/LICENSE-UI-PRO-MAX +21 -21
  170. package/references/ui-pro-max-data/charts.csv +26 -26
  171. package/references/ui-pro-max-data/colors.csv +161 -161
  172. package/references/ui-pro-max-data/styles.csv +68 -68
  173. package/references/ui-pro-max-data/typography.csv +74 -74
  174. package/references/ui-pro-max-data/ui-reasoning.csv +162 -162
  175. package/references/ui-pro-max-data/ux-guidelines.csv +99 -99
  176. package/skills/adversary/SKILL.md +283 -283
  177. package/skills/asset-creator/SKILL.md +157 -157
  178. package/skills/audit/SKILL.md +147 -2
  179. package/skills/autopsy/SKILL.md +335 -335
  180. package/skills/ba/SKILL.md +85 -1
  181. package/skills/brainstorm/SKILL.md +380 -342
  182. package/skills/browser-pilot/SKILL.md +169 -168
  183. package/skills/constraint-check/SKILL.md +165 -165
  184. package/skills/context-engine/SKILL.md +408 -404
  185. package/skills/cook/SKILL.md +917 -863
  186. package/skills/db/SKILL.md +273 -273
  187. package/skills/debug/SKILL.md +465 -465
  188. package/skills/dependency-doctor/SKILL.md +265 -235
  189. package/skills/deploy/SKILL.md +274 -231
  190. package/skills/design/DESIGN-REFERENCE.md +365 -365
  191. package/skills/design/SKILL.md +590 -589
  192. package/skills/doc-processor/SKILL.md +254 -254
  193. package/skills/docs/SKILL.md +374 -374
  194. package/skills/docs-seeker/SKILL.md +178 -177
  195. package/skills/fix/SKILL.md +332 -330
  196. package/skills/git/SKILL.md +339 -339
  197. package/skills/hallucination-guard/SKILL.md +220 -219
  198. package/skills/incident/SKILL.md +254 -253
  199. package/skills/integrity-check/SKILL.md +169 -169
  200. package/skills/journal/SKILL.md +241 -240
  201. package/skills/launch/SKILL.md +344 -344
  202. package/skills/logic-guardian/SKILL.md +269 -251
  203. package/skills/marketing/SKILL.md +351 -289
  204. package/skills/mcp-builder/SKILL.md +425 -425
  205. package/skills/neural-memory/SKILL.md +359 -362
  206. package/skills/onboard/SKILL.md +432 -403
  207. package/skills/onboard/references/invariants-template.md +76 -0
  208. package/skills/onboard/scripts/detect-invariants.js +439 -0
  209. package/skills/onboard/scripts/inject-claude-md.js +150 -0
  210. package/skills/onboard/scripts/onboard-invariants.js +194 -0
  211. package/skills/perf/SKILL.md +347 -346
  212. package/skills/plan/SKILL.md +435 -428
  213. package/skills/preflight/SKILL.md +415 -415
  214. package/skills/problem-solver/SKILL.md +380 -284
  215. package/skills/rescue/SKILL.md +474 -474
  216. package/skills/research/SKILL.md +4 -0
  217. package/skills/retro/SKILL.md +3 -1
  218. package/skills/review/SKILL.md +614 -588
  219. package/skills/review-intake/SKILL.md +249 -249
  220. package/skills/safeguard/SKILL.md +200 -200
  221. package/skills/sast/SKILL.md +190 -190
  222. package/skills/scaffold/SKILL.md +328 -287
  223. package/skills/scope-guard/SKILL.md +183 -180
  224. package/skills/scout/SKILL.md +269 -263
  225. package/skills/sentinel/SKILL.md +384 -381
  226. package/skills/sentinel-env/SKILL.md +254 -254
  227. package/skills/sequential-thinking/SKILL.md +234 -234
  228. package/skills/session-bridge/SKILL.md +595 -543
  229. package/skills/session-bridge/scripts/load-invariants.js +397 -0
  230. package/skills/skill-forge/SKILL.md +581 -581
  231. package/skills/skill-router/SKILL.md +3 -0
  232. package/skills/slides/SKILL.md +19 -0
  233. package/skills/surgeon/SKILL.md +215 -215
  234. package/skills/team/SKILL.md +557 -537
  235. package/skills/test/SKILL.md +620 -614
  236. package/skills/trend-scout/SKILL.md +145 -145
  237. package/skills/verification/SKILL.md +334 -326
  238. package/skills/video-creator/SKILL.md +201 -201
  239. package/skills/watchdog/SKILL.md +168 -168
  240. package/skills/worktree/SKILL.md +140 -140
@@ -1,88 +1,88 @@
1
- ---
2
- name: "blog-patterns"
3
- pack: "@rune/content"
4
- description: "Post management, categories/tags, pagination, RSS feeds, reading time, related posts, comment systems."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # blog-patterns
10
-
11
- Blog system patterns — post management, categories/tags, pagination, RSS feeds, reading time, related posts, comment systems.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Detect blog architecture**
16
- Use Glob to find blog-related files: `blog/`, `posts/`, `articles/`, `*.mdx`, `*.md` in content directories. Use Grep to find blog utilities: `getStaticPaths`, `generateStaticParams`, `allPosts`, `contentlayer`, `reading-time`. Read the post listing page and individual post page to understand: data source, routing strategy, and rendering pipeline.
17
-
18
- **Step 2 — Audit blog completeness**
19
- Check for: missing RSS feed (`feed.xml` or `/api/rss`), no reading time estimation, pagination absent on listing pages (all posts loaded at once), no category/tag filtering, missing related posts, no draft/published state, and OG images not generated per-post.
20
-
21
- **Step 3 — Emit blog patterns**
22
- Emit: typed post schema with frontmatter validation, paginated listing with category filter, RSS feed generator, reading time calculator, and related posts by tag similarity.
23
-
24
- #### Example
25
-
26
- ```typescript
27
- // Next.js App Router — blog listing with pagination and categories
28
- import { allPosts, type Post } from 'contentlayer/generated';
29
-
30
- function getPublishedPosts(category?: string): Post[] {
31
- return allPosts
32
- .filter(p => p.status === 'published')
33
- .filter(p => !category || p.category === category)
34
- .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
35
- }
36
-
37
- // Reading time utility
38
- function readingTime(content: string): string {
39
- const words = content.trim().split(/\s+/).length;
40
- const minutes = Math.ceil(words / 238);
41
- return `${minutes} min read`;
42
- }
43
-
44
- // RSS feed — app/feed.xml/route.ts
45
- export async function GET() {
46
- const posts = getPublishedPosts();
47
- const xml = `<?xml version="1.0" encoding="UTF-8"?>
48
- <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
49
- <channel>
50
- <title>My Blog</title>
51
- <link>${process.env.SITE_URL}</link>
52
- <atom:link href="${process.env.SITE_URL}/feed.xml" rel="self" type="application/rss+xml"/>
53
- ${posts.slice(0, 20).map(p => `<item>
54
- <title>${escapeXml(p.title)}</title>
55
- <link>${process.env.SITE_URL}${p.url}</link>
56
- <pubDate>${new Date(p.date).toUTCString()}</pubDate>
57
- <description>${escapeXml(p.excerpt)}</description>
58
- </item>`).join('\n')}
59
- </channel>
60
- </rss>`;
61
- return new Response(xml, { headers: { 'Content-Type': 'application/xml' } });
62
- }
63
-
64
- // Related posts by tag overlap — score by number of shared tags
65
- function getRelatedPosts(current: Post, all: Post[], limit = 3): Post[] {
66
- const currentTags = new Set(current.tags ?? []);
67
- return all
68
- .filter(p => p.slug !== current.slug && p.status === 'published')
69
- .map(p => ({ post: p, score: (p.tags ?? []).filter(t => currentTags.has(t)).length }))
70
- .filter(({ score }) => score > 0)
71
- .sort((a, b) => b.score - a.score)
72
- .slice(0, limit)
73
- .map(({ post }) => post);
74
- }
75
-
76
- // Paginated listing
77
- const PAGE_SIZE = 10;
78
- function paginatePosts(posts: Post[], page: number) {
79
- const start = (page - 1) * PAGE_SIZE;
80
- return {
81
- posts: posts.slice(start, start + PAGE_SIZE),
82
- total: posts.length,
83
- totalPages: Math.ceil(posts.length / PAGE_SIZE),
84
- hasNext: start + PAGE_SIZE < posts.length,
85
- hasPrev: page > 1,
86
- };
87
- }
88
- ```
1
+ ---
2
+ name: "blog-patterns"
3
+ pack: "@rune/content"
4
+ description: "Post management, categories/tags, pagination, RSS feeds, reading time, related posts, comment systems."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # blog-patterns
10
+
11
+ Blog system patterns — post management, categories/tags, pagination, RSS feeds, reading time, related posts, comment systems.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Detect blog architecture**
16
+ Use Glob to find blog-related files: `blog/`, `posts/`, `articles/`, `*.mdx`, `*.md` in content directories. Use Grep to find blog utilities: `getStaticPaths`, `generateStaticParams`, `allPosts`, `contentlayer`, `reading-time`. Read the post listing page and individual post page to understand: data source, routing strategy, and rendering pipeline.
17
+
18
+ **Step 2 — Audit blog completeness**
19
+ Check for: missing RSS feed (`feed.xml` or `/api/rss`), no reading time estimation, pagination absent on listing pages (all posts loaded at once), no category/tag filtering, missing related posts, no draft/published state, and OG images not generated per-post.
20
+
21
+ **Step 3 — Emit blog patterns**
22
+ Emit: typed post schema with frontmatter validation, paginated listing with category filter, RSS feed generator, reading time calculator, and related posts by tag similarity.
23
+
24
+ #### Example
25
+
26
+ ```typescript
27
+ // Next.js App Router — blog listing with pagination and categories
28
+ import { allPosts, type Post } from 'contentlayer/generated';
29
+
30
+ function getPublishedPosts(category?: string): Post[] {
31
+ return allPosts
32
+ .filter(p => p.status === 'published')
33
+ .filter(p => !category || p.category === category)
34
+ .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
35
+ }
36
+
37
+ // Reading time utility
38
+ function readingTime(content: string): string {
39
+ const words = content.trim().split(/\s+/).length;
40
+ const minutes = Math.ceil(words / 238);
41
+ return `${minutes} min read`;
42
+ }
43
+
44
+ // RSS feed — app/feed.xml/route.ts
45
+ export async function GET() {
46
+ const posts = getPublishedPosts();
47
+ const xml = `<?xml version="1.0" encoding="UTF-8"?>
48
+ <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
49
+ <channel>
50
+ <title>My Blog</title>
51
+ <link>${process.env.SITE_URL}</link>
52
+ <atom:link href="${process.env.SITE_URL}/feed.xml" rel="self" type="application/rss+xml"/>
53
+ ${posts.slice(0, 20).map(p => `<item>
54
+ <title>${escapeXml(p.title)}</title>
55
+ <link>${process.env.SITE_URL}${p.url}</link>
56
+ <pubDate>${new Date(p.date).toUTCString()}</pubDate>
57
+ <description>${escapeXml(p.excerpt)}</description>
58
+ </item>`).join('\n')}
59
+ </channel>
60
+ </rss>`;
61
+ return new Response(xml, { headers: { 'Content-Type': 'application/xml' } });
62
+ }
63
+
64
+ // Related posts by tag overlap — score by number of shared tags
65
+ function getRelatedPosts(current: Post, all: Post[], limit = 3): Post[] {
66
+ const currentTags = new Set(current.tags ?? []);
67
+ return all
68
+ .filter(p => p.slug !== current.slug && p.status === 'published')
69
+ .map(p => ({ post: p, score: (p.tags ?? []).filter(t => currentTags.has(t)).length }))
70
+ .filter(({ score }) => score > 0)
71
+ .sort((a, b) => b.score - a.score)
72
+ .slice(0, limit)
73
+ .map(({ post }) => post);
74
+ }
75
+
76
+ // Paginated listing
77
+ const PAGE_SIZE = 10;
78
+ function paginatePosts(posts: Post[], page: number) {
79
+ const start = (page - 1) * PAGE_SIZE;
80
+ return {
81
+ posts: posts.slice(start, start + PAGE_SIZE),
82
+ total: posts.length,
83
+ totalPages: Math.ceil(posts.length / PAGE_SIZE),
84
+ hasNext: start + PAGE_SIZE < posts.length,
85
+ hasPrev: page > 1,
86
+ };
87
+ }
88
+ ```
@@ -1,131 +1,131 @@
1
- ---
2
- name: "cms-integration"
3
- pack: "@rune/content"
4
- description: "Sanity, Contentful, Strapi, PocketBase. Content modeling, preview mode, webhook-triggered rebuilds, draft/published workflows."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # cms-integration
10
-
11
- CMS integration — Sanity, Contentful, Strapi, PocketBase. Content modeling, preview mode, webhook-triggered rebuilds, draft/published workflows.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Detect CMS setup**
16
- Use Grep to find CMS SDK usage: `createClient` (Sanity), `contentful`, `strapi`, `PocketBase`, `GROQ`, `graphql` in content-fetching files. Read the CMS client initialization and content queries to understand: CMS provider, content types, preview mode setup, and caching strategy.
17
-
18
- **Step 2 — Audit CMS integration**
19
- Check for: no preview/draft mode (editors can't preview before publish), missing webhook for on-demand ISR (content updates require full rebuild), no content validation (malformed CMS data crashes the page), stale cache without revalidation strategy, images served from CMS without optimization (no next/image or equivalent), and missing error boundary for CMS fetch failures.
20
-
21
- **Step 3 — Emit CMS patterns**
22
- For Sanity: emit typed GROQ queries with Zod validation, preview mode toggle, and webhook handler. For Contentful: emit typed GraphQL queries, draft/published content switching. For any CMS: emit ISR revalidation endpoint and image optimization pipeline.
23
-
24
- #### Example — Sanity
25
-
26
- ```typescript
27
- // Sanity — typed client with preview mode and ISR webhook
28
- import { createClient, type QueryParams } from '@sanity/client';
29
- import { z } from 'zod';
30
-
31
- const client = createClient({
32
- projectId: process.env.SANITY_PROJECT_ID!,
33
- dataset: 'production',
34
- apiVersion: '2024-01-01',
35
- useCdn: true,
36
- });
37
-
38
- const previewClient = client.withConfig({ useCdn: false, token: process.env.SANITY_PREVIEW_TOKEN });
39
-
40
- const PostSchema = z.object({
41
- _id: z.string(),
42
- title: z.string(),
43
- slug: z.string(),
44
- body: z.array(z.any()),
45
- publishedAt: z.string().datetime(),
46
- author: z.object({ name: z.string(), image: z.string().url().optional() }),
47
- });
48
-
49
- export async function getPost(slug: string, preview = false) {
50
- const query = `*[_type == "post" && slug.current == $slug][0]{
51
- _id, title, "slug": slug.current, body, publishedAt,
52
- "author": author->{ name, "image": image.asset->url }
53
- }`;
54
- const result = await (preview ? previewClient : client).fetch(query, { slug });
55
- return PostSchema.parse(result);
56
- }
57
-
58
- // Webhook handler for on-demand ISR — app/api/revalidate/route.ts
59
- export async function POST(req: Request) {
60
- const body = await req.json();
61
- const secret = req.headers.get('x-sanity-webhook-secret');
62
- if (secret !== process.env.SANITY_WEBHOOK_SECRET) {
63
- return new Response('Unauthorized', { status: 401 });
64
- }
65
- const { revalidatePath } = await import('next/cache');
66
- revalidatePath(`/blog/${body.slug.current}`);
67
- return Response.json({ revalidated: true });
68
- }
69
- ```
70
-
71
- #### Example — Contentful
72
-
73
- ```typescript
74
- // Contentful — typed GraphQL with draft/published switching
75
- import { createClient } from 'contentful';
76
-
77
- const client = createClient({
78
- space: process.env.CONTENTFUL_SPACE_ID!,
79
- accessToken: process.env.CONTENTFUL_ACCESS_TOKEN!,
80
- });
81
-
82
- const previewClient = createClient({
83
- space: process.env.CONTENTFUL_SPACE_ID!,
84
- accessToken: process.env.CONTENTFUL_PREVIEW_TOKEN!,
85
- host: 'preview.contentful.com',
86
- });
87
-
88
- export async function getArticle(slug: string, preview = false) {
89
- const c = preview ? previewClient : client;
90
- const entries = await c.getEntries({
91
- content_type: 'article',
92
- 'fields.slug': slug,
93
- include: 2,
94
- limit: 1,
95
- });
96
- if (!entries.items.length) return null;
97
- const entry = entries.items[0];
98
- return {
99
- title: entry.fields.title as string,
100
- slug: entry.fields.slug as string,
101
- body: entry.fields.body,
102
- publishedAt: entry.sys.createdAt,
103
- };
104
- }
105
- ```
106
-
107
- #### Example — Strapi
108
-
109
- ```typescript
110
- // Strapi v5 — REST with populate and draft/live modes
111
- const STRAPI = process.env.STRAPI_URL ?? 'http://localhost:1337';
112
- const TOKEN = process.env.STRAPI_API_TOKEN!;
113
-
114
- async function strapiGet<T>(path: string, params: Record<string, string> = {}): Promise<T> {
115
- const url = new URL(`${STRAPI}/api${path}`);
116
- Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
117
- const res = await fetch(url.toString(), {
118
- headers: { Authorization: `Bearer ${TOKEN}` },
119
- next: { revalidate: 60 },
120
- });
121
- if (!res.ok) throw new Error(`Strapi error: ${res.status}`);
122
- return res.json();
123
- }
124
-
125
- export const getArticles = () =>
126
- strapiGet<{ data: StrapiArticle[] }>('/articles', {
127
- 'filters[publishedAt][$notNull]': 'true',
128
- 'populate': 'cover,author,category',
129
- 'sort': 'publishedAt:desc',
130
- });
131
- ```
1
+ ---
2
+ name: "cms-integration"
3
+ pack: "@rune/content"
4
+ description: "Sanity, Contentful, Strapi, PocketBase. Content modeling, preview mode, webhook-triggered rebuilds, draft/published workflows."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # cms-integration
10
+
11
+ CMS integration — Sanity, Contentful, Strapi, PocketBase. Content modeling, preview mode, webhook-triggered rebuilds, draft/published workflows.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Detect CMS setup**
16
+ Use Grep to find CMS SDK usage: `createClient` (Sanity), `contentful`, `strapi`, `PocketBase`, `GROQ`, `graphql` in content-fetching files. Read the CMS client initialization and content queries to understand: CMS provider, content types, preview mode setup, and caching strategy.
17
+
18
+ **Step 2 — Audit CMS integration**
19
+ Check for: no preview/draft mode (editors can't preview before publish), missing webhook for on-demand ISR (content updates require full rebuild), no content validation (malformed CMS data crashes the page), stale cache without revalidation strategy, images served from CMS without optimization (no next/image or equivalent), and missing error boundary for CMS fetch failures.
20
+
21
+ **Step 3 — Emit CMS patterns**
22
+ For Sanity: emit typed GROQ queries with Zod validation, preview mode toggle, and webhook handler. For Contentful: emit typed GraphQL queries, draft/published content switching. For any CMS: emit ISR revalidation endpoint and image optimization pipeline.
23
+
24
+ #### Example — Sanity
25
+
26
+ ```typescript
27
+ // Sanity — typed client with preview mode and ISR webhook
28
+ import { createClient, type QueryParams } from '@sanity/client';
29
+ import { z } from 'zod';
30
+
31
+ const client = createClient({
32
+ projectId: process.env.SANITY_PROJECT_ID!,
33
+ dataset: 'production',
34
+ apiVersion: '2024-01-01',
35
+ useCdn: true,
36
+ });
37
+
38
+ const previewClient = client.withConfig({ useCdn: false, token: process.env.SANITY_PREVIEW_TOKEN });
39
+
40
+ const PostSchema = z.object({
41
+ _id: z.string(),
42
+ title: z.string(),
43
+ slug: z.string(),
44
+ body: z.array(z.any()),
45
+ publishedAt: z.string().datetime(),
46
+ author: z.object({ name: z.string(), image: z.string().url().optional() }),
47
+ });
48
+
49
+ export async function getPost(slug: string, preview = false) {
50
+ const query = `*[_type == "post" && slug.current == $slug][0]{
51
+ _id, title, "slug": slug.current, body, publishedAt,
52
+ "author": author->{ name, "image": image.asset->url }
53
+ }`;
54
+ const result = await (preview ? previewClient : client).fetch(query, { slug });
55
+ return PostSchema.parse(result);
56
+ }
57
+
58
+ // Webhook handler for on-demand ISR — app/api/revalidate/route.ts
59
+ export async function POST(req: Request) {
60
+ const body = await req.json();
61
+ const secret = req.headers.get('x-sanity-webhook-secret');
62
+ if (secret !== process.env.SANITY_WEBHOOK_SECRET) {
63
+ return new Response('Unauthorized', { status: 401 });
64
+ }
65
+ const { revalidatePath } = await import('next/cache');
66
+ revalidatePath(`/blog/${body.slug.current}`);
67
+ return Response.json({ revalidated: true });
68
+ }
69
+ ```
70
+
71
+ #### Example — Contentful
72
+
73
+ ```typescript
74
+ // Contentful — typed GraphQL with draft/published switching
75
+ import { createClient } from 'contentful';
76
+
77
+ const client = createClient({
78
+ space: process.env.CONTENTFUL_SPACE_ID!,
79
+ accessToken: process.env.CONTENTFUL_ACCESS_TOKEN!,
80
+ });
81
+
82
+ const previewClient = createClient({
83
+ space: process.env.CONTENTFUL_SPACE_ID!,
84
+ accessToken: process.env.CONTENTFUL_PREVIEW_TOKEN!,
85
+ host: 'preview.contentful.com',
86
+ });
87
+
88
+ export async function getArticle(slug: string, preview = false) {
89
+ const c = preview ? previewClient : client;
90
+ const entries = await c.getEntries({
91
+ content_type: 'article',
92
+ 'fields.slug': slug,
93
+ include: 2,
94
+ limit: 1,
95
+ });
96
+ if (!entries.items.length) return null;
97
+ const entry = entries.items[0];
98
+ return {
99
+ title: entry.fields.title as string,
100
+ slug: entry.fields.slug as string,
101
+ body: entry.fields.body,
102
+ publishedAt: entry.sys.createdAt,
103
+ };
104
+ }
105
+ ```
106
+
107
+ #### Example — Strapi
108
+
109
+ ```typescript
110
+ // Strapi v5 — REST with populate and draft/live modes
111
+ const STRAPI = process.env.STRAPI_URL ?? 'http://localhost:1337';
112
+ const TOKEN = process.env.STRAPI_API_TOKEN!;
113
+
114
+ async function strapiGet<T>(path: string, params: Record<string, string> = {}): Promise<T> {
115
+ const url = new URL(`${STRAPI}/api${path}`);
116
+ Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
117
+ const res = await fetch(url.toString(), {
118
+ headers: { Authorization: `Bearer ${TOKEN}` },
119
+ next: { revalidate: 60 },
120
+ });
121
+ if (!res.ok) throw new Error(`Strapi error: ${res.status}`);
122
+ return res.json();
123
+ }
124
+
125
+ export const getArticles = () =>
126
+ strapiGet<{ data: StrapiArticle[] }>('/articles', {
127
+ 'filters[publishedAt][$notNull]': 'true',
128
+ 'populate': 'cover,author,category',
129
+ 'sort': 'publishedAt:desc',
130
+ });
131
+ ```
@@ -1,107 +1,107 @@
1
- ---
2
- name: "content-scoring"
3
- pack: "@rune/content"
4
- description: "Engagement and virality scoring for content pieces. Analyze hooks, readability, shareability, and platform fit."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # content-scoring
10
-
11
- Engagement and virality scoring for content pieces. Analyze hooks, readability, shareability, and platform fit. Works for both video clips and written articles.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Detect content type**
16
- Determine if scoring target is:
17
- - **Video clip** (from video-repurpose pipeline or standalone)
18
- - **Blog post / article** (markdown, MDX, or CMS content)
19
- - **Social post** (short-form text, tweet, thread)
20
-
21
- **Step 2 — Score across 4 dimensions**
22
- ```typescript
23
- interface ContentScore {
24
- hook: {
25
- score: number; // 0-25
26
- type: 'question' | 'statistic' | 'story' | 'contrast' | 'bold-claim' | 'how-to';
27
- assessment: string; // Why this hook works or doesn't
28
- };
29
- engagement: {
30
- score: number; // 0-25
31
- readability: number; // Flesch-Kincaid grade level
32
- pacing: string; // 'too-slow' | 'good' | 'too-fast'
33
- callToAction: boolean;
34
- };
35
- value: {
36
- score: number; // 0-25
37
- teaches: boolean;
38
- entertains: boolean;
39
- uniqueInsight: boolean;
40
- };
41
- shareability: {
42
- score: number; // 0-25
43
- emotionalTrigger: string | null; // 'surprise' | 'anger' | 'joy' | 'fear'
44
- quotable: string[]; // Extract quotable one-liners
45
- platformFit: Record<Platform, number>; // 0-10 per platform
46
- };
47
- total: number; // 0-100
48
- tier: 'viral' | 'strong' | 'average' | 'weak'; // >80 viral, >60 strong, >40 average
49
- }
50
- ```
51
-
52
- **Step 3 — Platform-specific optimization hints**
53
- Each platform has different engagement patterns:
54
- | Platform | Hook Window | Optimal Length | Key Factor |
55
- |----------|-------------|---------------|------------|
56
- | TikTok | 0-1s | 15-30s | Pattern interrupt, trend audio |
57
- | YouTube | 0-3s | 8-12 min (long), 30-60s (Shorts) | Curiosity gap, retention graph |
58
- | Twitter/X | First line | 280 chars or 4-tweet thread | Hot take, data point |
59
- | LinkedIn | First 2 lines | 150-300 words | Professional insight, personal story |
60
- | Blog | Title + first paragraph | 1500-2500 words | SEO keyword + value promise |
61
-
62
- **Step 4 — Emit improvement suggestions**
63
- For each dimension scoring < 20/25, emit specific actionable improvement:
64
- - Hook weak → suggest rewrite with stronger opening pattern
65
- - Engagement low → identify pacing issues, suggest cuts or restructures
66
- - Value low → identify where content is generic, suggest unique angle
67
- - Shareability low → suggest quotable reformulations, emotional triggers
68
-
69
- #### Example
70
-
71
- ```typescript
72
- // Scoring a blog post
73
- const score = await scoreContent({
74
- type: 'article',
75
- title: 'How We Cut Our AWS Bill by 60%',
76
- content: articleMarkdown,
77
- targetPlatforms: ['blog', 'twitter', 'linkedin'],
78
- });
79
-
80
- // Result:
81
- // {
82
- // hook: { score: 22, type: 'statistic', assessment: 'Strong — specific number creates curiosity' },
83
- // engagement: { score: 18, readability: 8.2, pacing: 'good', callToAction: true },
84
- // value: { score: 20, teaches: true, entertains: false, uniqueInsight: true },
85
- // shareability: {
86
- // score: 19, emotionalTrigger: 'surprise',
87
- // quotable: ['We were paying $12K/mo for a service we used 3% of'],
88
- // platformFit: { blog: 9, twitter: 8, linkedin: 9 }
89
- // },
90
- // total: 79, tier: 'strong'
91
- // }
92
-
93
- // Improvement suggestions:
94
- // - Shareability: Add a contrarian angle ("Everyone says X, but we found Y")
95
- // - Engagement: Add a visual comparison (before/after cost graph)
96
- ```
97
-
98
- ```typescript
99
- // Scoring a video clip
100
- const clipScore = await scoreContent({
101
- type: 'video-clip',
102
- transcript: clipTranscript,
103
- duration: 28_000, // 28 seconds
104
- hookType: 'question',
105
- targetPlatforms: ['tiktok', 'youtube-shorts', 'instagram-reels'],
106
- });
107
- ```
1
+ ---
2
+ name: "content-scoring"
3
+ pack: "@rune/content"
4
+ description: "Engagement and virality scoring for content pieces. Analyze hooks, readability, shareability, and platform fit."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # content-scoring
10
+
11
+ Engagement and virality scoring for content pieces. Analyze hooks, readability, shareability, and platform fit. Works for both video clips and written articles.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Detect content type**
16
+ Determine if scoring target is:
17
+ - **Video clip** (from video-repurpose pipeline or standalone)
18
+ - **Blog post / article** (markdown, MDX, or CMS content)
19
+ - **Social post** (short-form text, tweet, thread)
20
+
21
+ **Step 2 — Score across 4 dimensions**
22
+ ```typescript
23
+ interface ContentScore {
24
+ hook: {
25
+ score: number; // 0-25
26
+ type: 'question' | 'statistic' | 'story' | 'contrast' | 'bold-claim' | 'how-to';
27
+ assessment: string; // Why this hook works or doesn't
28
+ };
29
+ engagement: {
30
+ score: number; // 0-25
31
+ readability: number; // Flesch-Kincaid grade level
32
+ pacing: string; // 'too-slow' | 'good' | 'too-fast'
33
+ callToAction: boolean;
34
+ };
35
+ value: {
36
+ score: number; // 0-25
37
+ teaches: boolean;
38
+ entertains: boolean;
39
+ uniqueInsight: boolean;
40
+ };
41
+ shareability: {
42
+ score: number; // 0-25
43
+ emotionalTrigger: string | null; // 'surprise' | 'anger' | 'joy' | 'fear'
44
+ quotable: string[]; // Extract quotable one-liners
45
+ platformFit: Record<Platform, number>; // 0-10 per platform
46
+ };
47
+ total: number; // 0-100
48
+ tier: 'viral' | 'strong' | 'average' | 'weak'; // >80 viral, >60 strong, >40 average
49
+ }
50
+ ```
51
+
52
+ **Step 3 — Platform-specific optimization hints**
53
+ Each platform has different engagement patterns:
54
+ | Platform | Hook Window | Optimal Length | Key Factor |
55
+ |----------|-------------|---------------|------------|
56
+ | TikTok | 0-1s | 15-30s | Pattern interrupt, trend audio |
57
+ | YouTube | 0-3s | 8-12 min (long), 30-60s (Shorts) | Curiosity gap, retention graph |
58
+ | Twitter/X | First line | 280 chars or 4-tweet thread | Hot take, data point |
59
+ | LinkedIn | First 2 lines | 150-300 words | Professional insight, personal story |
60
+ | Blog | Title + first paragraph | 1500-2500 words | SEO keyword + value promise |
61
+
62
+ **Step 4 — Emit improvement suggestions**
63
+ For each dimension scoring < 20/25, emit specific actionable improvement:
64
+ - Hook weak → suggest rewrite with stronger opening pattern
65
+ - Engagement low → identify pacing issues, suggest cuts or restructures
66
+ - Value low → identify where content is generic, suggest unique angle
67
+ - Shareability low → suggest quotable reformulations, emotional triggers
68
+
69
+ #### Example
70
+
71
+ ```typescript
72
+ // Scoring a blog post
73
+ const score = await scoreContent({
74
+ type: 'article',
75
+ title: 'How We Cut Our AWS Bill by 60%',
76
+ content: articleMarkdown,
77
+ targetPlatforms: ['blog', 'twitter', 'linkedin'],
78
+ });
79
+
80
+ // Result:
81
+ // {
82
+ // hook: { score: 22, type: 'statistic', assessment: 'Strong — specific number creates curiosity' },
83
+ // engagement: { score: 18, readability: 8.2, pacing: 'good', callToAction: true },
84
+ // value: { score: 20, teaches: true, entertains: false, uniqueInsight: true },
85
+ // shareability: {
86
+ // score: 19, emotionalTrigger: 'surprise',
87
+ // quotable: ['We were paying $12K/mo for a service we used 3% of'],
88
+ // platformFit: { blog: 9, twitter: 8, linkedin: 9 }
89
+ // },
90
+ // total: 79, tier: 'strong'
91
+ // }
92
+
93
+ // Improvement suggestions:
94
+ // - Shareability: Add a contrarian angle ("Everyone says X, but we found Y")
95
+ // - Engagement: Add a visual comparison (before/after cost graph)
96
+ ```
97
+
98
+ ```typescript
99
+ // Scoring a video clip
100
+ const clipScore = await scoreContent({
101
+ type: 'video-clip',
102
+ transcript: clipTranscript,
103
+ duration: 28_000, // 28 seconds
104
+ hookType: 'question',
105
+ targetPlatforms: ['tiktok', 'youtube-shorts', 'instagram-reels'],
106
+ });
107
+ ```