@rune-kit/rune 2.8.0 → 2.11.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 (287) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +68 -34
  3. package/agents/adversary.md +27 -0
  4. package/agents/architect.md +19 -29
  5. package/agents/asset-creator.md +18 -4
  6. package/agents/audit.md +25 -4
  7. package/agents/autopsy.md +19 -4
  8. package/agents/ba.md +35 -0
  9. package/agents/brainstorm.md +31 -4
  10. package/agents/browser-pilot.md +21 -4
  11. package/agents/coder.md +21 -29
  12. package/agents/completion-gate.md +20 -4
  13. package/agents/constraint-check.md +18 -4
  14. package/agents/context-engine.md +22 -4
  15. package/agents/context-pack.md +32 -0
  16. package/agents/cook.md +41 -4
  17. package/agents/db.md +19 -4
  18. package/agents/debug.md +33 -4
  19. package/agents/dependency-doctor.md +20 -4
  20. package/agents/deploy.md +27 -4
  21. package/agents/design.md +22 -4
  22. package/agents/doc-processor.md +27 -0
  23. package/agents/docs-seeker.md +19 -4
  24. package/agents/docs.md +31 -0
  25. package/agents/fix.md +37 -4
  26. package/agents/git.md +29 -0
  27. package/agents/hallucination-guard.md +20 -4
  28. package/agents/incident.md +21 -4
  29. package/agents/integrity-check.md +18 -4
  30. package/agents/journal.md +19 -4
  31. package/agents/launch.md +32 -4
  32. package/agents/logic-guardian.md +26 -11
  33. package/agents/marketing.md +23 -4
  34. package/agents/mcp-builder.md +26 -0
  35. package/agents/neural-memory.md +30 -0
  36. package/agents/onboard.md +22 -4
  37. package/agents/perf.md +21 -4
  38. package/agents/plan.md +29 -4
  39. package/agents/preflight.md +22 -4
  40. package/agents/problem-solver.md +20 -4
  41. package/agents/rescue.md +23 -4
  42. package/agents/research.md +19 -4
  43. package/agents/researcher.md +19 -29
  44. package/agents/retro.md +32 -0
  45. package/agents/review-intake.md +20 -4
  46. package/agents/review.md +32 -4
  47. package/agents/reviewer.md +20 -28
  48. package/agents/safeguard.md +19 -4
  49. package/agents/sast.md +18 -4
  50. package/agents/scaffold.md +41 -0
  51. package/agents/scanner.md +19 -28
  52. package/agents/scope-guard.md +18 -4
  53. package/agents/scout.md +23 -4
  54. package/agents/sentinel-env.md +26 -0
  55. package/agents/sentinel.md +33 -4
  56. package/agents/sequential-thinking.md +20 -4
  57. package/agents/session-bridge.md +24 -4
  58. package/agents/skill-forge.md +22 -4
  59. package/agents/skill-router.md +26 -4
  60. package/agents/slides.md +24 -0
  61. package/agents/surgeon.md +19 -4
  62. package/agents/team.md +30 -4
  63. package/agents/test.md +36 -4
  64. package/agents/trend-scout.md +17 -4
  65. package/agents/verification.md +20 -4
  66. package/agents/video-creator.md +20 -4
  67. package/agents/watchdog.md +19 -4
  68. package/agents/worktree.md +17 -4
  69. package/commands/rune.md +168 -168
  70. package/compiler/__tests__/analytics.test.js +370 -0
  71. package/compiler/adapters/openclaw.js +2 -2
  72. package/compiler/analytics.js +385 -0
  73. package/compiler/bin/rune.js +68 -2
  74. package/compiler/dashboard.js +883 -0
  75. package/compiler/transforms/branding.js +1 -1
  76. package/contexts/dev.md +34 -34
  77. package/contexts/research.md +43 -43
  78. package/contexts/review.md +55 -55
  79. package/extensions/ai-ml/PACK.md +88 -88
  80. package/extensions/ai-ml/skills/ai-agents.md +172 -172
  81. package/extensions/ai-ml/skills/code-sandbox.md +187 -187
  82. package/extensions/ai-ml/skills/deep-research.md +146 -146
  83. package/extensions/ai-ml/skills/embedding-search.md +66 -66
  84. package/extensions/ai-ml/skills/fine-tuning-guide.md +74 -74
  85. package/extensions/ai-ml/skills/llm-architect.md +125 -125
  86. package/extensions/ai-ml/skills/llm-integration.md +64 -64
  87. package/extensions/ai-ml/skills/prompt-patterns.md +72 -72
  88. package/extensions/ai-ml/skills/rag-patterns.md +66 -66
  89. package/extensions/ai-ml/skills/web-extraction.md +114 -114
  90. package/extensions/analytics/PACK.md +92 -92
  91. package/extensions/analytics/skills/ab-testing.md +72 -72
  92. package/extensions/analytics/skills/dashboard-patterns.md +83 -83
  93. package/extensions/analytics/skills/data-validation.md +68 -68
  94. package/extensions/analytics/skills/funnel-analysis.md +81 -81
  95. package/extensions/analytics/skills/sql-patterns.md +57 -57
  96. package/extensions/analytics/skills/statistical-analysis.md +79 -79
  97. package/extensions/analytics/skills/tracking-setup.md +71 -71
  98. package/extensions/backend/PACK.md +104 -104
  99. package/extensions/backend/skills/api-patterns.md +84 -84
  100. package/extensions/backend/skills/async-pipeline.md +193 -193
  101. package/extensions/backend/skills/auth-patterns.md +97 -97
  102. package/extensions/backend/skills/background-jobs.md +133 -133
  103. package/extensions/backend/skills/caching-patterns.md +108 -108
  104. package/extensions/backend/skills/cli-generation.md +133 -133
  105. package/extensions/backend/skills/database-patterns.md +87 -87
  106. package/extensions/backend/skills/middleware-patterns.md +104 -104
  107. package/extensions/chrome-ext/PACK.md +93 -93
  108. package/extensions/chrome-ext/skills/cws-preflight.md +143 -143
  109. package/extensions/chrome-ext/skills/cws-publish.md +104 -104
  110. package/extensions/chrome-ext/skills/ext-ai-integration.md +251 -251
  111. package/extensions/chrome-ext/skills/ext-messaging.md +139 -139
  112. package/extensions/chrome-ext/skills/ext-storage.md +133 -133
  113. package/extensions/chrome-ext/skills/mv3-scaffold.md +164 -164
  114. package/extensions/content/PACK.md +96 -96
  115. package/extensions/content/skills/blog-patterns.md +88 -88
  116. package/extensions/content/skills/cms-integration.md +131 -131
  117. package/extensions/content/skills/content-scoring.md +107 -107
  118. package/extensions/content/skills/i18n.md +83 -83
  119. package/extensions/content/skills/mdx-authoring.md +137 -137
  120. package/extensions/content/skills/reference.md +1014 -1014
  121. package/extensions/content/skills/seo-patterns.md +67 -67
  122. package/extensions/content/skills/video-repurpose.md +153 -153
  123. package/extensions/devops/PACK.md +101 -101
  124. package/extensions/devops/skills/chaos-testing.md +67 -67
  125. package/extensions/devops/skills/ci-cd.md +75 -75
  126. package/extensions/devops/skills/docker.md +58 -58
  127. package/extensions/devops/skills/edge-serverless.md +163 -163
  128. package/extensions/devops/skills/infra-as-code.md +158 -158
  129. package/extensions/devops/skills/kubernetes.md +110 -110
  130. package/extensions/devops/skills/monitoring.md +57 -57
  131. package/extensions/devops/skills/server-setup.md +64 -64
  132. package/extensions/devops/skills/ssl-domain.md +42 -42
  133. package/extensions/ecommerce/PACK.md +116 -116
  134. package/extensions/ecommerce/skills/cart-system.md +79 -79
  135. package/extensions/ecommerce/skills/inventory-mgmt.md +102 -102
  136. package/extensions/ecommerce/skills/order-management.md +126 -126
  137. package/extensions/ecommerce/skills/payment-integration.md +472 -472
  138. package/extensions/ecommerce/skills/shopify-dev.md +69 -69
  139. package/extensions/ecommerce/skills/subscription-billing.md +93 -93
  140. package/extensions/ecommerce/skills/tax-compliance.md +117 -117
  141. package/extensions/gamedev/PACK.md +142 -142
  142. package/extensions/gamedev/skills/asset-pipeline.md +74 -74
  143. package/extensions/gamedev/skills/audio-system.md +129 -129
  144. package/extensions/gamedev/skills/camera-system.md +87 -87
  145. package/extensions/gamedev/skills/ecs.md +98 -98
  146. package/extensions/gamedev/skills/game-loops.md +72 -72
  147. package/extensions/gamedev/skills/input-system.md +199 -199
  148. package/extensions/gamedev/skills/multiplayer.md +180 -180
  149. package/extensions/gamedev/skills/particles.md +105 -105
  150. package/extensions/gamedev/skills/physics-engine.md +89 -89
  151. package/extensions/gamedev/skills/scene-management.md +146 -146
  152. package/extensions/gamedev/skills/threejs-patterns.md +90 -90
  153. package/extensions/gamedev/skills/webgl.md +71 -71
  154. package/extensions/mobile/PACK.md +106 -106
  155. package/extensions/mobile/skills/app-store-connect.md +152 -152
  156. package/extensions/mobile/skills/app-store-prep.md +66 -66
  157. package/extensions/mobile/skills/deep-linking.md +109 -109
  158. package/extensions/mobile/skills/flutter.md +60 -60
  159. package/extensions/mobile/skills/ios-build-pipeline.md +142 -142
  160. package/extensions/mobile/skills/native-bridge.md +66 -66
  161. package/extensions/mobile/skills/ota-updates.md +97 -97
  162. package/extensions/mobile/skills/push-notifications.md +111 -111
  163. package/extensions/mobile/skills/react-native.md +82 -82
  164. package/extensions/saas/PACK.md +116 -116
  165. package/extensions/saas/skills/billing-integration.md +200 -200
  166. package/extensions/saas/skills/feature-flags.md +130 -130
  167. package/extensions/saas/skills/multi-tenant.md +103 -103
  168. package/extensions/saas/skills/onboarding-flow.md +139 -139
  169. package/extensions/saas/skills/subscription-flow.md +95 -95
  170. package/extensions/saas/skills/team-management.md +144 -144
  171. package/extensions/security/PACK.md +99 -99
  172. package/extensions/security/skills/api-security.md +140 -140
  173. package/extensions/security/skills/compliance.md +68 -68
  174. package/extensions/security/skills/owasp-audit.md +64 -64
  175. package/extensions/security/skills/pentest-patterns.md +77 -77
  176. package/extensions/security/skills/secret-mgmt.md +65 -65
  177. package/extensions/security/skills/supply-chain.md +65 -65
  178. package/extensions/trading/PACK.md +80 -80
  179. package/extensions/trading/skills/chart-components.md +55 -55
  180. package/extensions/trading/skills/experiment-loop.md +125 -125
  181. package/extensions/trading/skills/fintech-patterns.md +47 -47
  182. package/extensions/trading/skills/indicator-library.md +58 -58
  183. package/extensions/trading/skills/quant-analysis.md +111 -111
  184. package/extensions/trading/skills/realtime-data.md +58 -58
  185. package/extensions/trading/skills/trade-logic.md +104 -104
  186. package/extensions/ui/PACK.md +130 -130
  187. package/extensions/ui/skills/a11y-audit.md +91 -91
  188. package/extensions/ui/skills/animation-patterns.md +127 -106
  189. package/extensions/ui/skills/component-patterns.md +100 -75
  190. package/extensions/ui/skills/design-decision.md +108 -108
  191. package/extensions/ui/skills/design-system.md +68 -68
  192. package/extensions/ui/skills/landing-patterns.md +155 -155
  193. package/extensions/ui/skills/palette-picker.md +173 -173
  194. package/extensions/ui/skills/react-health.md +90 -90
  195. package/extensions/ui/skills/type-system.md +125 -125
  196. package/extensions/ui/skills/web-vitals.md +153 -153
  197. package/extensions/zalo/PACK.md +145 -145
  198. package/extensions/zalo/skills/zalo-oa-mcp.md +317 -317
  199. package/extensions/zalo/skills/zalo-oa-messaging.md +429 -429
  200. package/extensions/zalo/skills/zalo-oa-setup.md +236 -236
  201. package/extensions/zalo/skills/zalo-oa-webhook.md +189 -189
  202. package/extensions/zalo/skills/zalo-personal-messaging.md +194 -194
  203. package/extensions/zalo/skills/zalo-personal-setup.md +153 -153
  204. package/extensions/zalo/skills/zalo-rate-guard.md +219 -219
  205. package/hooks/auto-format/index.cjs +48 -48
  206. package/hooks/context-watch/index.cjs +95 -68
  207. package/hooks/hooks.json +111 -111
  208. package/hooks/metrics-collector/index.cjs +86 -42
  209. package/hooks/post-session-reflect/index.cjs +189 -153
  210. package/hooks/pre-compact/index.cjs +95 -95
  211. package/hooks/run-hook.cmd +1 -1
  212. package/hooks/secrets-scan/index.cjs +100 -100
  213. package/hooks/session-start/index.cjs +71 -65
  214. package/hooks/typecheck/index.cjs +65 -65
  215. package/package.json +63 -63
  216. package/references/ui-pro-max-data/LICENSE-UI-PRO-MAX +21 -21
  217. package/references/ui-pro-max-data/charts.csv +26 -26
  218. package/references/ui-pro-max-data/colors.csv +161 -161
  219. package/references/ui-pro-max-data/styles.csv +68 -68
  220. package/references/ui-pro-max-data/typography.csv +74 -74
  221. package/references/ui-pro-max-data/ui-reasoning.csv +162 -162
  222. package/references/ui-pro-max-data/ux-guidelines.csv +99 -99
  223. package/skills/adversary/SKILL.md +283 -283
  224. package/skills/asset-creator/SKILL.md +157 -157
  225. package/skills/audit/SKILL.md +148 -2
  226. package/skills/autopsy/SKILL.md +335 -259
  227. package/skills/autopsy/references/repo-analysis-patterns.md +113 -0
  228. package/skills/ba/SKILL.md +72 -2
  229. package/skills/brainstorm/SKILL.md +342 -341
  230. package/skills/browser-pilot/SKILL.md +168 -168
  231. package/skills/constraint-check/SKILL.md +165 -165
  232. package/skills/context-engine/SKILL.md +404 -404
  233. package/skills/cook/SKILL.md +917 -834
  234. package/skills/cook/references/output-format.md +33 -0
  235. package/skills/db/SKILL.md +273 -272
  236. package/skills/debug/SKILL.md +465 -443
  237. package/skills/dependency-doctor/SKILL.md +265 -235
  238. package/skills/deploy/SKILL.md +274 -231
  239. package/skills/design/DESIGN-REFERENCE.md +365 -365
  240. package/skills/design/SKILL.md +589 -482
  241. package/skills/doc-processor/SKILL.md +254 -254
  242. package/skills/docs/SKILL.md +374 -373
  243. package/skills/docs-seeker/SKILL.md +177 -177
  244. package/skills/fix/SKILL.md +330 -308
  245. package/skills/git/SKILL.md +339 -339
  246. package/skills/graft/SKILL.md +352 -0
  247. package/skills/graft/references/challenge-framework.md +98 -0
  248. package/skills/graft/references/mode-decision.md +44 -0
  249. package/skills/hallucination-guard/SKILL.md +219 -219
  250. package/skills/incident/SKILL.md +254 -251
  251. package/skills/integrity-check/SKILL.md +169 -169
  252. package/skills/journal/SKILL.md +240 -238
  253. package/skills/launch/SKILL.md +344 -342
  254. package/skills/logic-guardian/SKILL.md +251 -251
  255. package/skills/marketing/SKILL.md +290 -245
  256. package/skills/mcp-builder/SKILL.md +425 -423
  257. package/skills/mcp-builder/references/auto-discovery-pattern.md +169 -0
  258. package/skills/neural-memory/SKILL.md +362 -362
  259. package/skills/onboard/SKILL.md +404 -403
  260. package/skills/perf/SKILL.md +346 -346
  261. package/skills/plan/SKILL.md +433 -370
  262. package/skills/plan/references/feature-map.md +84 -0
  263. package/skills/preflight/SKILL.md +415 -396
  264. package/skills/problem-solver/SKILL.md +380 -284
  265. package/skills/rescue/SKILL.md +474 -450
  266. package/skills/retro/SKILL.md +5 -1
  267. package/skills/review/SKILL.md +612 -535
  268. package/skills/review-intake/SKILL.md +249 -249
  269. package/skills/safeguard/SKILL.md +200 -200
  270. package/skills/sast/SKILL.md +190 -190
  271. package/skills/scaffold/SKILL.md +328 -286
  272. package/skills/scope-guard/SKILL.md +180 -162
  273. package/skills/scout/SKILL.md +263 -263
  274. package/skills/sentinel/SKILL.md +382 -353
  275. package/skills/sentinel-env/SKILL.md +254 -254
  276. package/skills/sequential-thinking/SKILL.md +234 -234
  277. package/skills/session-bridge/SKILL.md +543 -397
  278. package/skills/skill-forge/SKILL.md +581 -539
  279. package/skills/skill-router/{skill.md → SKILL.md} +30 -2
  280. package/skills/surgeon/SKILL.md +215 -215
  281. package/skills/team/SKILL.md +556 -514
  282. package/skills/test/SKILL.md +614 -587
  283. package/skills/trend-scout/SKILL.md +145 -145
  284. package/skills/verification/SKILL.md +326 -325
  285. package/skills/video-creator/SKILL.md +201 -201
  286. package/skills/watchdog/SKILL.md +168 -168
  287. package/skills/worktree/SKILL.md +140 -140
@@ -1,133 +1,133 @@
1
- ---
2
- name: "cli-generation"
3
- pack: "@rune/backend"
4
- description: "Generate production-grade CLI wrappers for backend services — command groups, dual output mode (human + JSON), stateful REPL, session management with undo/redo, and pip/npm-installable packaging."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # cli-generation
10
-
11
- Generate production-grade CLI wrappers for backend services — command groups, dual output mode (human + JSON), stateful REPL, session management with undo/redo, and pip/npm-installable packaging.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Analyze backend service surface**
16
- Map existing API endpoints, service methods, or data models to CLI command groups:
17
- ```typescript
18
- interface CLICommandGroup {
19
- name: string; // e.g., 'users', 'orders', 'config'
20
- source: string; // API route file or service class
21
- commands: CLICommand[];
22
- }
23
-
24
- interface CLICommand {
25
- name: string; // e.g., 'list', 'create', 'delete'
26
- sourceMethod: string; // e.g., 'UserService.findAll'
27
- params: CLIParam[];
28
- mutating: boolean; // true = needs confirmation/undo support
29
- }
30
- ```
31
-
32
- **Step 2 — Design dual output mode**
33
- Every command MUST support both human-readable and machine-readable output:
34
- ```typescript
35
- // Human mode (default): tables, colors, formatted text
36
- function formatHuman(data: any, format: 'table' | 'list' | 'detail'): string {
37
- if (format === 'table') return formatTable(data, { borders: true, colors: true });
38
- if (format === 'list') return data.map((d: any) => ` • ${d.name}`).join('\n');
39
- return JSON.stringify(data, null, 2);
40
- }
41
-
42
- // JSON mode (--json flag): structured output for piping/scripting
43
- function formatJSON(data: any): string {
44
- return JSON.stringify(data, null, 2);
45
- }
46
-
47
- // Error output follows same dual pattern
48
- function formatError(error: Error, jsonMode: boolean): string {
49
- if (jsonMode) return JSON.stringify({ error: error.message, type: error.constructor.name });
50
- return chalk.red(`Error: ${error.message}`);
51
- }
52
- ```
53
-
54
- **Step 3 — Implement session with undo/redo**
55
- For mutating operations, maintain session state:
56
- ```typescript
57
- interface CLISession {
58
- id: string;
59
- history: SessionSnapshot[];
60
- undoStack: SessionSnapshot[]; // max 50
61
- redoStack: SessionSnapshot[];
62
- modified: boolean;
63
- }
64
-
65
- function snapshot(session: CLISession, action: string): CLISession {
66
- return {
67
- ...session,
68
- undoStack: [...session.undoStack.slice(-49), { action, state: deepCopy(session) }],
69
- redoStack: [], // new action clears redo
70
- modified: true,
71
- };
72
- }
73
- ```
74
-
75
- **Step 4 — Build REPL mode**
76
- CLI enters REPL when invoked without subcommand:
77
- ```typescript
78
- // Click (Python) — invoke_without_command=True enters REPL
79
- @click.group(invoke_without_command=True)
80
- @click.pass_context
81
- def cli(ctx):
82
- if ctx.invoked_subcommand is None:
83
- start_repl(ctx)
84
-
85
- // Commander (Node.js) — detect no args
86
- if (process.argv.length <= 2) {
87
- startREPL({ history: '~/.myapp_history', prompt: 'myapp> ' });
88
- }
89
- ```
90
-
91
- REPL features: command history (file-persisted), auto-suggest from history, tab completion, colored prompt, help command, status bar showing connection state.
92
-
93
- **Step 5 — Package for distribution**
94
- ```bash
95
- # Python: PEP 420 namespace packages for independent installability
96
- # pyproject.toml or setup.py
97
- entry_points = {
98
- 'console_scripts': ['myapp = myapp.cli:main'],
99
- }
100
-
101
- # Node.js: bin field in package.json
102
- {
103
- "bin": { "myapp": "./bin/cli.js" },
104
- "files": ["bin/", "lib/"]
105
- }
106
- ```
107
-
108
- **Step 6 — Verify installation**
109
- After packaging: install locally (`pip install -e .` or `npm link`), verify binary on PATH (`which myapp`), run `myapp --version`, test `myapp --json` mode, and verify REPL launch.
110
-
111
- #### Example
112
-
113
- ```python
114
- # Generated CLI structure for a backend service
115
- # myapp/
116
- # ├── cli.py ← Click entry point + REPL
117
- # ├── commands/
118
- # │ ├── users.py ← User CRUD commands
119
- # │ ├── orders.py ← Order management
120
- # │ └── config.py ← Config operations
121
- # ├── core/
122
- # │ ├── session.py ← Session + undo/redo
123
- # │ └── client.py ← API client wrapper
124
- # └── utils/
125
- # ├── output.py ← Dual output (human + JSON)
126
- # └── repl.py ← REPL with prompt-toolkit
127
-
128
- # Usage:
129
- # myapp users list → human-readable table
130
- # myapp users list --json → JSON output for piping
131
- # myapp users create --name "Alice" → creates user, snapshots for undo
132
- # myapp → enters REPL mode
133
- ```
1
+ ---
2
+ name: "cli-generation"
3
+ pack: "@rune/backend"
4
+ description: "Generate production-grade CLI wrappers for backend services — command groups, dual output mode (human + JSON), stateful REPL, session management with undo/redo, and pip/npm-installable packaging."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # cli-generation
10
+
11
+ Generate production-grade CLI wrappers for backend services — command groups, dual output mode (human + JSON), stateful REPL, session management with undo/redo, and pip/npm-installable packaging.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Analyze backend service surface**
16
+ Map existing API endpoints, service methods, or data models to CLI command groups:
17
+ ```typescript
18
+ interface CLICommandGroup {
19
+ name: string; // e.g., 'users', 'orders', 'config'
20
+ source: string; // API route file or service class
21
+ commands: CLICommand[];
22
+ }
23
+
24
+ interface CLICommand {
25
+ name: string; // e.g., 'list', 'create', 'delete'
26
+ sourceMethod: string; // e.g., 'UserService.findAll'
27
+ params: CLIParam[];
28
+ mutating: boolean; // true = needs confirmation/undo support
29
+ }
30
+ ```
31
+
32
+ **Step 2 — Design dual output mode**
33
+ Every command MUST support both human-readable and machine-readable output:
34
+ ```typescript
35
+ // Human mode (default): tables, colors, formatted text
36
+ function formatHuman(data: any, format: 'table' | 'list' | 'detail'): string {
37
+ if (format === 'table') return formatTable(data, { borders: true, colors: true });
38
+ if (format === 'list') return data.map((d: any) => ` • ${d.name}`).join('\n');
39
+ return JSON.stringify(data, null, 2);
40
+ }
41
+
42
+ // JSON mode (--json flag): structured output for piping/scripting
43
+ function formatJSON(data: any): string {
44
+ return JSON.stringify(data, null, 2);
45
+ }
46
+
47
+ // Error output follows same dual pattern
48
+ function formatError(error: Error, jsonMode: boolean): string {
49
+ if (jsonMode) return JSON.stringify({ error: error.message, type: error.constructor.name });
50
+ return chalk.red(`Error: ${error.message}`);
51
+ }
52
+ ```
53
+
54
+ **Step 3 — Implement session with undo/redo**
55
+ For mutating operations, maintain session state:
56
+ ```typescript
57
+ interface CLISession {
58
+ id: string;
59
+ history: SessionSnapshot[];
60
+ undoStack: SessionSnapshot[]; // max 50
61
+ redoStack: SessionSnapshot[];
62
+ modified: boolean;
63
+ }
64
+
65
+ function snapshot(session: CLISession, action: string): CLISession {
66
+ return {
67
+ ...session,
68
+ undoStack: [...session.undoStack.slice(-49), { action, state: deepCopy(session) }],
69
+ redoStack: [], // new action clears redo
70
+ modified: true,
71
+ };
72
+ }
73
+ ```
74
+
75
+ **Step 4 — Build REPL mode**
76
+ CLI enters REPL when invoked without subcommand:
77
+ ```typescript
78
+ // Click (Python) — invoke_without_command=True enters REPL
79
+ @click.group(invoke_without_command=True)
80
+ @click.pass_context
81
+ def cli(ctx):
82
+ if ctx.invoked_subcommand is None:
83
+ start_repl(ctx)
84
+
85
+ // Commander (Node.js) — detect no args
86
+ if (process.argv.length <= 2) {
87
+ startREPL({ history: '~/.myapp_history', prompt: 'myapp> ' });
88
+ }
89
+ ```
90
+
91
+ REPL features: command history (file-persisted), auto-suggest from history, tab completion, colored prompt, help command, status bar showing connection state.
92
+
93
+ **Step 5 — Package for distribution**
94
+ ```bash
95
+ # Python: PEP 420 namespace packages for independent installability
96
+ # pyproject.toml or setup.py
97
+ entry_points = {
98
+ 'console_scripts': ['myapp = myapp.cli:main'],
99
+ }
100
+
101
+ # Node.js: bin field in package.json
102
+ {
103
+ "bin": { "myapp": "./bin/cli.js" },
104
+ "files": ["bin/", "lib/"]
105
+ }
106
+ ```
107
+
108
+ **Step 6 — Verify installation**
109
+ After packaging: install locally (`pip install -e .` or `npm link`), verify binary on PATH (`which myapp`), run `myapp --version`, test `myapp --json` mode, and verify REPL launch.
110
+
111
+ #### Example
112
+
113
+ ```python
114
+ # Generated CLI structure for a backend service
115
+ # myapp/
116
+ # ├── cli.py ← Click entry point + REPL
117
+ # ├── commands/
118
+ # │ ├── users.py ← User CRUD commands
119
+ # │ ├── orders.py ← Order management
120
+ # │ └── config.py ← Config operations
121
+ # ├── core/
122
+ # │ ├── session.py ← Session + undo/redo
123
+ # │ └── client.py ← API client wrapper
124
+ # └── utils/
125
+ # ├── output.py ← Dual output (human + JSON)
126
+ # └── repl.py ← REPL with prompt-toolkit
127
+
128
+ # Usage:
129
+ # myapp users list → human-readable table
130
+ # myapp users list --json → JSON output for piping
131
+ # myapp users create --name "Alice" → creates user, snapshots for undo
132
+ # myapp → enters REPL mode
133
+ ```
@@ -1,87 +1,87 @@
1
- ---
2
- name: "database-patterns"
3
- pack: "@rune/backend"
4
- description: "Database design and query patterns — schema design, migrations, indexing strategies, N+1 prevention, soft deletes, read replicas, connection pooling, seeding."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # database-patterns
10
-
11
- Database design and query patterns — schema design, migrations, indexing strategies, N+1 prevention, soft deletes, read replicas, connection pooling, seeding.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Detect ORM and query patterns**
16
- Use Grep to find ORM usage (`prisma.`, `knex(`, `sequelize.`, `typeorm`, `drizzle`, `mongoose.`, `db.query`) and raw SQL strings. Read schema files (`schema.prisma`, `migrations/`, `models/`) to understand the data model.
17
-
18
- **Step 2 — Detect N+1 and missing indexes**
19
- Scan for loops containing database calls (a query inside `for`, `map`, `forEach` → N+1). Check foreign key columns for missing indexes. Identify queries with `WHERE` clauses on unindexed columns. Flag each with the specific query and fix.
20
-
21
- **Step 3 — Emit optimized queries**
22
- For N+1: emit eager loading (`include`, `populate`, `JOIN`). For missing indexes: emit migration files. For unsafe raw SQL: emit parameterized version. For connection pooling: check pool config and recommend sizing based on max connections.
23
-
24
- **Step 4 — Soft delete and query scoping**
25
- Emit soft delete pattern: add `deleted_at TIMESTAMPTZ` column, update all `findMany`/`findUnique` calls to include `WHERE deleted_at IS NULL`. Cascade consideration: soft-delete parent should soft-delete children (emit trigger or application-level cascade). For Prisma: emit a custom extension that injects the filter automatically. Warn about index bloat from soft-deleted rows — add partial index `WHERE deleted_at IS NULL` to keep index lean.
26
-
27
- **Step 5 — Read replicas, connection pooling, and seeding**
28
- Read replicas: emit query routing — writes to primary, reads to replica. Handle replication lag: do not read from replica immediately after write in the same request (use primary for the read-after-write). For Prisma: emit `$extends` with read/write client split. Connection pooling deep dive: PgBouncer in transaction mode for serverless (each query gets a connection); Prisma's built-in pool for long-running servers. Pool sizing formula: `connections = (core_count * 2) + effective_spindle_count`. Seeding: emit factory functions using `@faker-js/faker` — deterministic seeds via `faker.seed(42)` for reproducible test data.
29
-
30
- #### Example
31
-
32
- ```typescript
33
- // BEFORE: N+1 — one query per post to get author
34
- const posts = await prisma.post.findMany();
35
- for (const post of posts) {
36
- post.author = await prisma.user.findUnique({ where: { id: post.authorId } });
37
- }
38
-
39
- // AFTER: eager loading, single query with JOIN
40
- const posts = await prisma.post.findMany({
41
- include: { author: { select: { id: true, name: true, avatar: true } } },
42
- });
43
-
44
- // Migration: missing indexes + soft delete column
45
- -- Migration: add_indexes_and_soft_delete_to_posts
46
- ALTER TABLE posts ADD COLUMN deleted_at TIMESTAMPTZ;
47
- CREATE INDEX idx_posts_author_id ON posts(author_id);
48
- CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
49
- CREATE INDEX idx_posts_active ON posts(author_id, created_at DESC) WHERE deleted_at IS NULL;
50
-
51
- // Prisma soft delete extension (auto-scopes all queries)
52
- const softDelete = Prisma.defineExtension({
53
- name: 'softDelete',
54
- query: {
55
- $allModels: {
56
- async findMany({ model, operation, args, query }) {
57
- args.where = { ...args.where, deletedAt: null };
58
- return query(args);
59
- },
60
- async delete({ model, args, query }) {
61
- return (query as any)({ ...args, data: { deletedAt: new Date() } } as any);
62
- },
63
- },
64
- },
65
- });
66
- const prisma = new PrismaClient().$extends(softDelete);
67
-
68
- // Read replica routing with Prisma
69
- const primaryClient = new PrismaClient({ datasources: { db: { url: PRIMARY_URL } } });
70
- const replicaClient = new PrismaClient({ datasources: { db: { url: REPLICA_URL } } });
71
- const db = { write: primaryClient, read: replicaClient };
72
- // Usage: db.write.user.create(...) vs db.read.user.findMany(...)
73
-
74
- // Factory seeding
75
- import { faker } from '@faker-js/faker';
76
- faker.seed(42); // reproducible
77
-
78
- const createUserFactory = (overrides = {}) => ({
79
- id: faker.string.uuid(),
80
- email: faker.internet.email(),
81
- name: faker.person.fullName(),
82
- createdAt: faker.date.past(),
83
- ...overrides,
84
- });
85
-
86
- await prisma.user.createMany({ data: Array.from({ length: 50 }, () => createUserFactory()) });
87
- ```
1
+ ---
2
+ name: "database-patterns"
3
+ pack: "@rune/backend"
4
+ description: "Database design and query patterns — schema design, migrations, indexing strategies, N+1 prevention, soft deletes, read replicas, connection pooling, seeding."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # database-patterns
10
+
11
+ Database design and query patterns — schema design, migrations, indexing strategies, N+1 prevention, soft deletes, read replicas, connection pooling, seeding.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Detect ORM and query patterns**
16
+ Use Grep to find ORM usage (`prisma.`, `knex(`, `sequelize.`, `typeorm`, `drizzle`, `mongoose.`, `db.query`) and raw SQL strings. Read schema files (`schema.prisma`, `migrations/`, `models/`) to understand the data model.
17
+
18
+ **Step 2 — Detect N+1 and missing indexes**
19
+ Scan for loops containing database calls (a query inside `for`, `map`, `forEach` → N+1). Check foreign key columns for missing indexes. Identify queries with `WHERE` clauses on unindexed columns. Flag each with the specific query and fix.
20
+
21
+ **Step 3 — Emit optimized queries**
22
+ For N+1: emit eager loading (`include`, `populate`, `JOIN`). For missing indexes: emit migration files. For unsafe raw SQL: emit parameterized version. For connection pooling: check pool config and recommend sizing based on max connections.
23
+
24
+ **Step 4 — Soft delete and query scoping**
25
+ Emit soft delete pattern: add `deleted_at TIMESTAMPTZ` column, update all `findMany`/`findUnique` calls to include `WHERE deleted_at IS NULL`. Cascade consideration: soft-delete parent should soft-delete children (emit trigger or application-level cascade). For Prisma: emit a custom extension that injects the filter automatically. Warn about index bloat from soft-deleted rows — add partial index `WHERE deleted_at IS NULL` to keep index lean.
26
+
27
+ **Step 5 — Read replicas, connection pooling, and seeding**
28
+ Read replicas: emit query routing — writes to primary, reads to replica. Handle replication lag: do not read from replica immediately after write in the same request (use primary for the read-after-write). For Prisma: emit `$extends` with read/write client split. Connection pooling deep dive: PgBouncer in transaction mode for serverless (each query gets a connection); Prisma's built-in pool for long-running servers. Pool sizing formula: `connections = (core_count * 2) + effective_spindle_count`. Seeding: emit factory functions using `@faker-js/faker` — deterministic seeds via `faker.seed(42)` for reproducible test data.
29
+
30
+ #### Example
31
+
32
+ ```typescript
33
+ // BEFORE: N+1 — one query per post to get author
34
+ const posts = await prisma.post.findMany();
35
+ for (const post of posts) {
36
+ post.author = await prisma.user.findUnique({ where: { id: post.authorId } });
37
+ }
38
+
39
+ // AFTER: eager loading, single query with JOIN
40
+ const posts = await prisma.post.findMany({
41
+ include: { author: { select: { id: true, name: true, avatar: true } } },
42
+ });
43
+
44
+ // Migration: missing indexes + soft delete column
45
+ -- Migration: add_indexes_and_soft_delete_to_posts
46
+ ALTER TABLE posts ADD COLUMN deleted_at TIMESTAMPTZ;
47
+ CREATE INDEX idx_posts_author_id ON posts(author_id);
48
+ CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
49
+ CREATE INDEX idx_posts_active ON posts(author_id, created_at DESC) WHERE deleted_at IS NULL;
50
+
51
+ // Prisma soft delete extension (auto-scopes all queries)
52
+ const softDelete = Prisma.defineExtension({
53
+ name: 'softDelete',
54
+ query: {
55
+ $allModels: {
56
+ async findMany({ model, operation, args, query }) {
57
+ args.where = { ...args.where, deletedAt: null };
58
+ return query(args);
59
+ },
60
+ async delete({ model, args, query }) {
61
+ return (query as any)({ ...args, data: { deletedAt: new Date() } } as any);
62
+ },
63
+ },
64
+ },
65
+ });
66
+ const prisma = new PrismaClient().$extends(softDelete);
67
+
68
+ // Read replica routing with Prisma
69
+ const primaryClient = new PrismaClient({ datasources: { db: { url: PRIMARY_URL } } });
70
+ const replicaClient = new PrismaClient({ datasources: { db: { url: REPLICA_URL } } });
71
+ const db = { write: primaryClient, read: replicaClient };
72
+ // Usage: db.write.user.create(...) vs db.read.user.findMany(...)
73
+
74
+ // Factory seeding
75
+ import { faker } from '@faker-js/faker';
76
+ faker.seed(42); // reproducible
77
+
78
+ const createUserFactory = (overrides = {}) => ({
79
+ id: faker.string.uuid(),
80
+ email: faker.internet.email(),
81
+ name: faker.person.fullName(),
82
+ createdAt: faker.date.past(),
83
+ ...overrides,
84
+ });
85
+
86
+ await prisma.user.createMany({ data: Array.from({ length: 50 }, () => createUserFactory()) });
87
+ ```
@@ -1,104 +1,104 @@
1
- ---
2
- name: "middleware-patterns"
3
- pack: "@rune/backend"
4
- description: "Middleware architecture — request validation, error handling, logging, CORS, compression, graceful shutdown, health checks, request ID tracking."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # middleware-patterns
10
-
11
- Middleware architecture — request validation, error handling, logging, CORS, compression, graceful shutdown, health checks, request ID tracking.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Audit middleware stack**
16
- Read the main server file (app.ts, server.ts, index.ts) to inventory all middleware in registration order. Check for: missing request ID generation, missing structured logging, inconsistent error responses, missing input validation, CORS misconfiguration (`*` in production).
17
-
18
- **Step 2 — Detect error handling gaps**
19
- Use Grep to find `catch` blocks, error middleware signatures (`err, req, res, next`), and unhandled promise rejections. Check if errors return consistent format (same envelope for 400, 401, 403, 404, 500). Flag any that leak stack traces or internal details in production.
20
-
21
- **Step 3 — Emit middleware improvements**
22
- For each gap, emit the middleware function: request ID (`X-Request-Id` header, UUID per request), structured JSON logger (request method, path, status, duration, request ID), global error handler with consistent envelope, Zod-based request validation middleware.
23
-
24
- **Step 4 — Compression strategy**
25
- Emit response compression middleware. Use `brotli` for static assets and pre-compressible responses (better ratio than gzip, supported by all modern clients). Use `gzip` as fallback for older clients. Conditional compression: skip for already-compressed content types (`image/*`, `video/*`, `application/zip`) — compressing these wastes CPU. In Express: use `compression` package with a `filter` function. In Fastify: `@fastify/compress` with `encodings: ['br', 'gzip']`. Minimum size threshold: do not compress responses < 1KB (overhead exceeds benefit).
26
-
27
- **Step 5 — Graceful shutdown and health checks**
28
- Graceful shutdown: on `SIGTERM`/`SIGINT`, stop accepting new connections, wait for in-flight requests to complete (timeout 30s), then close DB pools and exit. Emit the shutdown handler for Express (`server.close()`), Fastify (`fastify.close()`), and worker processes. Health check endpoints: `/health/live` (liveness — is the process alive? return 200 always unless process is broken), `/health/ready` (readiness — can it serve traffic? check DB connection, Redis connection, return 503 if dependencies are down). In Kubernetes: map liveness to `livenessProbe`, readiness to `readinessProbe`. Do NOT check external third-party APIs in readiness — only your own dependencies.
29
-
30
- #### Example
31
-
32
- ```typescript
33
- // Request ID middleware
34
- const requestId = (req, res, next) => {
35
- req.id = req.headers['x-request-id'] || crypto.randomUUID();
36
- res.setHeader('X-Request-Id', req.id);
37
- next();
38
- };
39
-
40
- // Structured error handler — consistent envelope, no stack leak
41
- const errorHandler = (err, req, res, _next) => {
42
- const status = err.status || 500;
43
- const message = status < 500 ? err.message : 'Internal server error';
44
- logger.error({ err, requestId: req.id, path: req.path });
45
- res.status(status).json({
46
- error: { code: err.code || 'INTERNAL_ERROR', message },
47
- request_id: req.id,
48
- });
49
- };
50
-
51
- // Zod validation middleware
52
- const validate = (schema: z.ZodSchema) => (req, res, next) => {
53
- const result = schema.safeParse({ body: req.body, query: req.query, params: req.params });
54
- if (!result.success) {
55
- return res.status(400).json({ error: { code: 'VALIDATION_ERROR', message: 'Invalid request', details: result.error.flatten() } });
56
- }
57
- Object.assign(req, result.data);
58
- next();
59
- };
60
-
61
- // Compression with conditional skip (Express)
62
- import compression from 'compression';
63
- app.use(compression({
64
- filter: (req, res) => {
65
- const contentType = res.getHeader('Content-Type') as string || '';
66
- if (/image|video|audio|zip|gz|br/.test(contentType)) return false;
67
- return compression.filter(req, res);
68
- },
69
- threshold: 1024, // skip responses < 1KB
70
- }));
71
-
72
- // Graceful shutdown
73
- const gracefulShutdown = async (signal: string) => {
74
- console.log(`Received ${signal}, shutting down gracefully...`);
75
- server.close(async () => {
76
- try {
77
- await prisma.$disconnect();
78
- await redis.quit();
79
- console.log('All connections closed. Exiting.');
80
- process.exit(0);
81
- } catch (err) {
82
- console.error('Error during shutdown:', err);
83
- process.exit(1);
84
- }
85
- });
86
- // Force exit after 30s if still not done
87
- setTimeout(() => { console.error('Forced shutdown after timeout'); process.exit(1); }, 30_000);
88
- };
89
- process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
90
- process.on('SIGINT', () => gracefulShutdown('SIGINT'));
91
-
92
- // Health check endpoints
93
- app.get('/health/live', (req, res) => res.json({ status: 'ok' }));
94
-
95
- app.get('/health/ready', async (req, res) => {
96
- const checks = await Promise.allSettled([
97
- prisma.$queryRaw`SELECT 1`, // DB check
98
- redis.ping(), // Redis check
99
- ]);
100
- const results = { db: checks[0].status, redis: checks[1].status };
101
- const allHealthy = checks.every(c => c.status === 'fulfilled');
102
- res.status(allHealthy ? 200 : 503).json({ status: allHealthy ? 'ready' : 'degraded', checks: results });
103
- });
104
- ```
1
+ ---
2
+ name: "middleware-patterns"
3
+ pack: "@rune/backend"
4
+ description: "Middleware architecture — request validation, error handling, logging, CORS, compression, graceful shutdown, health checks, request ID tracking."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # middleware-patterns
10
+
11
+ Middleware architecture — request validation, error handling, logging, CORS, compression, graceful shutdown, health checks, request ID tracking.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Audit middleware stack**
16
+ Read the main server file (app.ts, server.ts, index.ts) to inventory all middleware in registration order. Check for: missing request ID generation, missing structured logging, inconsistent error responses, missing input validation, CORS misconfiguration (`*` in production).
17
+
18
+ **Step 2 — Detect error handling gaps**
19
+ Use Grep to find `catch` blocks, error middleware signatures (`err, req, res, next`), and unhandled promise rejections. Check if errors return consistent format (same envelope for 400, 401, 403, 404, 500). Flag any that leak stack traces or internal details in production.
20
+
21
+ **Step 3 — Emit middleware improvements**
22
+ For each gap, emit the middleware function: request ID (`X-Request-Id` header, UUID per request), structured JSON logger (request method, path, status, duration, request ID), global error handler with consistent envelope, Zod-based request validation middleware.
23
+
24
+ **Step 4 — Compression strategy**
25
+ Emit response compression middleware. Use `brotli` for static assets and pre-compressible responses (better ratio than gzip, supported by all modern clients). Use `gzip` as fallback for older clients. Conditional compression: skip for already-compressed content types (`image/*`, `video/*`, `application/zip`) — compressing these wastes CPU. In Express: use `compression` package with a `filter` function. In Fastify: `@fastify/compress` with `encodings: ['br', 'gzip']`. Minimum size threshold: do not compress responses < 1KB (overhead exceeds benefit).
26
+
27
+ **Step 5 — Graceful shutdown and health checks**
28
+ Graceful shutdown: on `SIGTERM`/`SIGINT`, stop accepting new connections, wait for in-flight requests to complete (timeout 30s), then close DB pools and exit. Emit the shutdown handler for Express (`server.close()`), Fastify (`fastify.close()`), and worker processes. Health check endpoints: `/health/live` (liveness — is the process alive? return 200 always unless process is broken), `/health/ready` (readiness — can it serve traffic? check DB connection, Redis connection, return 503 if dependencies are down). In Kubernetes: map liveness to `livenessProbe`, readiness to `readinessProbe`. Do NOT check external third-party APIs in readiness — only your own dependencies.
29
+
30
+ #### Example
31
+
32
+ ```typescript
33
+ // Request ID middleware
34
+ const requestId = (req, res, next) => {
35
+ req.id = req.headers['x-request-id'] || crypto.randomUUID();
36
+ res.setHeader('X-Request-Id', req.id);
37
+ next();
38
+ };
39
+
40
+ // Structured error handler — consistent envelope, no stack leak
41
+ const errorHandler = (err, req, res, _next) => {
42
+ const status = err.status || 500;
43
+ const message = status < 500 ? err.message : 'Internal server error';
44
+ logger.error({ err, requestId: req.id, path: req.path });
45
+ res.status(status).json({
46
+ error: { code: err.code || 'INTERNAL_ERROR', message },
47
+ request_id: req.id,
48
+ });
49
+ };
50
+
51
+ // Zod validation middleware
52
+ const validate = (schema: z.ZodSchema) => (req, res, next) => {
53
+ const result = schema.safeParse({ body: req.body, query: req.query, params: req.params });
54
+ if (!result.success) {
55
+ return res.status(400).json({ error: { code: 'VALIDATION_ERROR', message: 'Invalid request', details: result.error.flatten() } });
56
+ }
57
+ Object.assign(req, result.data);
58
+ next();
59
+ };
60
+
61
+ // Compression with conditional skip (Express)
62
+ import compression from 'compression';
63
+ app.use(compression({
64
+ filter: (req, res) => {
65
+ const contentType = res.getHeader('Content-Type') as string || '';
66
+ if (/image|video|audio|zip|gz|br/.test(contentType)) return false;
67
+ return compression.filter(req, res);
68
+ },
69
+ threshold: 1024, // skip responses < 1KB
70
+ }));
71
+
72
+ // Graceful shutdown
73
+ const gracefulShutdown = async (signal: string) => {
74
+ console.log(`Received ${signal}, shutting down gracefully...`);
75
+ server.close(async () => {
76
+ try {
77
+ await prisma.$disconnect();
78
+ await redis.quit();
79
+ console.log('All connections closed. Exiting.');
80
+ process.exit(0);
81
+ } catch (err) {
82
+ console.error('Error during shutdown:', err);
83
+ process.exit(1);
84
+ }
85
+ });
86
+ // Force exit after 30s if still not done
87
+ setTimeout(() => { console.error('Forced shutdown after timeout'); process.exit(1); }, 30_000);
88
+ };
89
+ process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
90
+ process.on('SIGINT', () => gracefulShutdown('SIGINT'));
91
+
92
+ // Health check endpoints
93
+ app.get('/health/live', (req, res) => res.json({ status: 'ok' }));
94
+
95
+ app.get('/health/ready', async (req, res) => {
96
+ const checks = await Promise.allSettled([
97
+ prisma.$queryRaw`SELECT 1`, // DB check
98
+ redis.ping(), // Redis check
99
+ ]);
100
+ const results = { db: checks[0].status, redis: checks[1].status };
101
+ const allHealthy = checks.every(c => c.status === 'fulfilled');
102
+ res.status(allHealthy ? 200 : 503).json({ status: allHealthy ? 'ready' : 'degraded', checks: results });
103
+ });
104
+ ```