@minhduydev/mdpi 0.3.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 (561) hide show
  1. package/README.md +31 -0
  2. package/dist/index.js +1187 -0
  3. package/dist/template/.pi/.env.example +28 -0
  4. package/dist/template/.pi/AGENTS.md +226 -0
  5. package/dist/template/.pi/QUALITY.md +13 -0
  6. package/dist/template/.pi/README.md +452 -0
  7. package/dist/template/.pi/VERSION +1 -0
  8. package/dist/template/.pi/agents/INDEX.md +54 -0
  9. package/dist/template/.pi/agents/build.md +194 -0
  10. package/dist/template/.pi/agents/explore.md +85 -0
  11. package/dist/template/.pi/agents/general.md +189 -0
  12. package/dist/template/.pi/agents/plan.md +407 -0
  13. package/dist/template/.pi/agents/review.md +198 -0
  14. package/dist/template/.pi/agents/scout.md +142 -0
  15. package/dist/template/.pi/agents/vision.md +157 -0
  16. package/dist/template/.pi/artifacts/example/plan.md +12 -0
  17. package/dist/template/.pi/artifacts/example/progress.md +4 -0
  18. package/dist/template/.pi/artifacts/example/research.md +4 -0
  19. package/dist/template/.pi/artifacts/example/spec.md +16 -0
  20. package/dist/template/.pi/context/architecture.md +141 -0
  21. package/dist/template/.pi/context/fallow.md +137 -0
  22. package/dist/template/.pi/extensions/templates-injector.ts +76 -0
  23. package/dist/template/.pi/extensions/workflows-runner.ts +301 -0
  24. package/dist/template/.pi/guard.example.json +75 -0
  25. package/dist/template/.pi/prompts/INDEX.md +78 -0
  26. package/dist/template/.pi/prompts/audit.md +109 -0
  27. package/dist/template/.pi/prompts/close.md +88 -0
  28. package/dist/template/.pi/prompts/create.md +197 -0
  29. package/dist/template/.pi/prompts/fix.md +117 -0
  30. package/dist/template/.pi/prompts/gc.md +112 -0
  31. package/dist/template/.pi/prompts/init.md +206 -0
  32. package/dist/template/.pi/prompts/loop-check.md +87 -0
  33. package/dist/template/.pi/prompts/loop-init.md +157 -0
  34. package/dist/template/.pi/prompts/loop-review.md +90 -0
  35. package/dist/template/.pi/prompts/plan.md +254 -0
  36. package/dist/template/.pi/prompts/research.md +136 -0
  37. package/dist/template/.pi/prompts/ship.md +219 -0
  38. package/dist/template/.pi/prompts/status.md +92 -0
  39. package/dist/template/.pi/prompts/verify.md +154 -0
  40. package/dist/template/.pi/scripts/gc-check.sh +86 -0
  41. package/dist/template/.pi/settings.json +15 -0
  42. package/dist/template/.pi/skills/INDEX.md +331 -0
  43. package/dist/template/.pi/skills/accessibility-audit/SKILL.md +205 -0
  44. package/dist/template/.pi/skills/accessibility-audit/references/accessibility-checklist.md +109 -0
  45. package/dist/template/.pi/skills/agent-code-quality-gate/SKILL.md +131 -0
  46. package/dist/template/.pi/skills/api-and-interface-design/SKILL.md +159 -0
  47. package/dist/template/.pi/skills/behavioral-kernel/SKILL.md +92 -0
  48. package/dist/template/.pi/skills/brainstorming/SKILL.md +138 -0
  49. package/dist/template/.pi/skills/browser-testing-with-devtools/SKILL.md +90 -0
  50. package/dist/template/.pi/skills/chrome-devtools/SKILL.md +129 -0
  51. package/dist/template/.pi/skills/ci-cd-and-automation/SKILL.md +199 -0
  52. package/dist/template/.pi/skills/cloudflare/SKILL.md +271 -0
  53. package/dist/template/.pi/skills/cloudflare/references/agents-sdk/README.md +35 -0
  54. package/dist/template/.pi/skills/cloudflare/references/agents-sdk/api.md +100 -0
  55. package/dist/template/.pi/skills/cloudflare/references/agents-sdk/configuration.md +99 -0
  56. package/dist/template/.pi/skills/cloudflare/references/agents-sdk/gotchas.md +59 -0
  57. package/dist/template/.pi/skills/cloudflare/references/agents-sdk/patterns.md +89 -0
  58. package/dist/template/.pi/skills/cloudflare/references/ai-gateway/README.md +695 -0
  59. package/dist/template/.pi/skills/cloudflare/references/ai-search/README.md +14 -0
  60. package/dist/template/.pi/skills/cloudflare/references/ai-search/api.md +38 -0
  61. package/dist/template/.pi/skills/cloudflare/references/ai-search/configuration.md +52 -0
  62. package/dist/template/.pi/skills/cloudflare/references/ai-search/gotchas.md +41 -0
  63. package/dist/template/.pi/skills/cloudflare/references/ai-search/patterns.md +45 -0
  64. package/dist/template/.pi/skills/cloudflare/references/analytics-engine/README.md +14 -0
  65. package/dist/template/.pi/skills/cloudflare/references/analytics-engine/api.md +27 -0
  66. package/dist/template/.pi/skills/cloudflare/references/analytics-engine/configuration.md +45 -0
  67. package/dist/template/.pi/skills/cloudflare/references/analytics-engine/gotchas.md +3 -0
  68. package/dist/template/.pi/skills/cloudflare/references/analytics-engine/patterns.md +36 -0
  69. package/dist/template/.pi/skills/cloudflare/references/api/README.md +21 -0
  70. package/dist/template/.pi/skills/cloudflare/references/api/api.md +31 -0
  71. package/dist/template/.pi/skills/cloudflare/references/api/configuration.md +20 -0
  72. package/dist/template/.pi/skills/cloudflare/references/api/gotchas.md +28 -0
  73. package/dist/template/.pi/skills/cloudflare/references/api/patterns.md +47 -0
  74. package/dist/template/.pi/skills/cloudflare/references/api-shield/README.md +20 -0
  75. package/dist/template/.pi/skills/cloudflare/references/api-shield/api.md +78 -0
  76. package/dist/template/.pi/skills/cloudflare/references/api-shield/configuration.md +128 -0
  77. package/dist/template/.pi/skills/cloudflare/references/api-shield/gotchas.md +51 -0
  78. package/dist/template/.pi/skills/cloudflare/references/api-shield/patterns.md +145 -0
  79. package/dist/template/.pi/skills/cloudflare/references/argo-smart-routing/README.md +16 -0
  80. package/dist/template/.pi/skills/cloudflare/references/argo-smart-routing/api.md +50 -0
  81. package/dist/template/.pi/skills/cloudflare/references/argo-smart-routing/configuration.md +53 -0
  82. package/dist/template/.pi/skills/cloudflare/references/argo-smart-routing/gotchas.md +16 -0
  83. package/dist/template/.pi/skills/cloudflare/references/argo-smart-routing/patterns.md +45 -0
  84. package/dist/template/.pi/skills/cloudflare/references/bindings/README.md +14 -0
  85. package/dist/template/.pi/skills/cloudflare/references/bindings/api.md +3 -0
  86. package/dist/template/.pi/skills/cloudflare/references/bindings/configuration.md +58 -0
  87. package/dist/template/.pi/skills/cloudflare/references/bindings/gotchas.md +35 -0
  88. package/dist/template/.pi/skills/cloudflare/references/bindings/patterns.md +37 -0
  89. package/dist/template/.pi/skills/cloudflare/references/bot-management/README.md +71 -0
  90. package/dist/template/.pi/skills/cloudflare/references/bot-management/api.md +168 -0
  91. package/dist/template/.pi/skills/cloudflare/references/bot-management/configuration.md +114 -0
  92. package/dist/template/.pi/skills/cloudflare/references/bot-management/gotchas.md +99 -0
  93. package/dist/template/.pi/skills/cloudflare/references/bot-management/patterns.md +125 -0
  94. package/dist/template/.pi/skills/cloudflare/references/browser-rendering/README.md +16 -0
  95. package/dist/template/.pi/skills/cloudflare/references/browser-rendering/api.md +54 -0
  96. package/dist/template/.pi/skills/cloudflare/references/browser-rendering/configuration.md +47 -0
  97. package/dist/template/.pi/skills/cloudflare/references/browser-rendering/gotchas.md +29 -0
  98. package/dist/template/.pi/skills/cloudflare/references/browser-rendering/patterns.md +29 -0
  99. package/dist/template/.pi/skills/cloudflare/references/c3/README.md +264 -0
  100. package/dist/template/.pi/skills/cloudflare/references/cache-reserve/README.md +93 -0
  101. package/dist/template/.pi/skills/cloudflare/references/cache-reserve/api.md +176 -0
  102. package/dist/template/.pi/skills/cloudflare/references/cache-reserve/configuration.md +164 -0
  103. package/dist/template/.pi/skills/cloudflare/references/cache-reserve/gotchas.md +203 -0
  104. package/dist/template/.pi/skills/cloudflare/references/cache-reserve/patterns.md +180 -0
  105. package/dist/template/.pi/skills/cloudflare/references/containers/README.md +16 -0
  106. package/dist/template/.pi/skills/cloudflare/references/containers/api.md +43 -0
  107. package/dist/template/.pi/skills/cloudflare/references/containers/configuration.md +56 -0
  108. package/dist/template/.pi/skills/cloudflare/references/containers/gotchas.md +21 -0
  109. package/dist/template/.pi/skills/cloudflare/references/containers/patterns.md +40 -0
  110. package/dist/template/.pi/skills/cloudflare/references/cron-triggers/README.md +85 -0
  111. package/dist/template/.pi/skills/cloudflare/references/cron-triggers/api.md +198 -0
  112. package/dist/template/.pi/skills/cloudflare/references/cron-triggers/configuration.md +151 -0
  113. package/dist/template/.pi/skills/cloudflare/references/cron-triggers/gotchas.md +129 -0
  114. package/dist/template/.pi/skills/cloudflare/references/cron-triggers/patterns.md +122 -0
  115. package/dist/template/.pi/skills/cloudflare/references/d1/README.md +92 -0
  116. package/dist/template/.pi/skills/cloudflare/references/d1/api.md +141 -0
  117. package/dist/template/.pi/skills/cloudflare/references/d1/configuration.md +127 -0
  118. package/dist/template/.pi/skills/cloudflare/references/d1/gotchas.md +70 -0
  119. package/dist/template/.pi/skills/cloudflare/references/d1/patterns.md +144 -0
  120. package/dist/template/.pi/skills/cloudflare/references/ddos/README.md +34 -0
  121. package/dist/template/.pi/skills/cloudflare/references/ddos/api.md +136 -0
  122. package/dist/template/.pi/skills/cloudflare/references/ddos/configuration.md +67 -0
  123. package/dist/template/.pi/skills/cloudflare/references/ddos/gotchas.md +114 -0
  124. package/dist/template/.pi/skills/cloudflare/references/ddos/patterns.md +158 -0
  125. package/dist/template/.pi/skills/cloudflare/references/do-storage/README.md +62 -0
  126. package/dist/template/.pi/skills/cloudflare/references/do-storage/api.md +89 -0
  127. package/dist/template/.pi/skills/cloudflare/references/do-storage/configuration.md +116 -0
  128. package/dist/template/.pi/skills/cloudflare/references/do-storage/gotchas.md +93 -0
  129. package/dist/template/.pi/skills/cloudflare/references/do-storage/patterns.md +112 -0
  130. package/dist/template/.pi/skills/cloudflare/references/durable-objects/README.md +125 -0
  131. package/dist/template/.pi/skills/cloudflare/references/durable-objects/api.md +152 -0
  132. package/dist/template/.pi/skills/cloudflare/references/durable-objects/configuration.md +148 -0
  133. package/dist/template/.pi/skills/cloudflare/references/durable-objects/gotchas.md +158 -0
  134. package/dist/template/.pi/skills/cloudflare/references/durable-objects/patterns.md +255 -0
  135. package/dist/template/.pi/skills/cloudflare/references/email-routing/README.md +18 -0
  136. package/dist/template/.pi/skills/cloudflare/references/email-routing/api.md +46 -0
  137. package/dist/template/.pi/skills/cloudflare/references/email-routing/configuration.md +63 -0
  138. package/dist/template/.pi/skills/cloudflare/references/email-routing/gotchas.md +16 -0
  139. package/dist/template/.pi/skills/cloudflare/references/email-routing/patterns.md +46 -0
  140. package/dist/template/.pi/skills/cloudflare/references/email-workers/README.md +598 -0
  141. package/dist/template/.pi/skills/cloudflare/references/hyperdrive/README.md +62 -0
  142. package/dist/template/.pi/skills/cloudflare/references/hyperdrive/api.md +137 -0
  143. package/dist/template/.pi/skills/cloudflare/references/hyperdrive/configuration.md +133 -0
  144. package/dist/template/.pi/skills/cloudflare/references/hyperdrive/gotchas.md +184 -0
  145. package/dist/template/.pi/skills/cloudflare/references/hyperdrive/patterns.md +176 -0
  146. package/dist/template/.pi/skills/cloudflare/references/images/README.md +14 -0
  147. package/dist/template/.pi/skills/cloudflare/references/images/api.md +3 -0
  148. package/dist/template/.pi/skills/cloudflare/references/images/configuration.md +45 -0
  149. package/dist/template/.pi/skills/cloudflare/references/images/gotchas.md +23 -0
  150. package/dist/template/.pi/skills/cloudflare/references/images/patterns.md +31 -0
  151. package/dist/template/.pi/skills/cloudflare/references/kv/README.md +60 -0
  152. package/dist/template/.pi/skills/cloudflare/references/kv/api.md +114 -0
  153. package/dist/template/.pi/skills/cloudflare/references/kv/configuration.md +92 -0
  154. package/dist/template/.pi/skills/cloudflare/references/kv/gotchas.md +117 -0
  155. package/dist/template/.pi/skills/cloudflare/references/kv/patterns.md +139 -0
  156. package/dist/template/.pi/skills/cloudflare/references/miniflare/README.md +64 -0
  157. package/dist/template/.pi/skills/cloudflare/references/miniflare/api.md +144 -0
  158. package/dist/template/.pi/skills/cloudflare/references/miniflare/configuration.md +203 -0
  159. package/dist/template/.pi/skills/cloudflare/references/miniflare/gotchas.md +187 -0
  160. package/dist/template/.pi/skills/cloudflare/references/miniflare/patterns.md +211 -0
  161. package/dist/template/.pi/skills/cloudflare/references/network-interconnect/README.md +60 -0
  162. package/dist/template/.pi/skills/cloudflare/references/network-interconnect/api.md +240 -0
  163. package/dist/template/.pi/skills/cloudflare/references/network-interconnect/configuration.md +127 -0
  164. package/dist/template/.pi/skills/cloudflare/references/network-interconnect/gotchas.md +171 -0
  165. package/dist/template/.pi/skills/cloudflare/references/network-interconnect/patterns.md +171 -0
  166. package/dist/template/.pi/skills/cloudflare/references/observability/README.md +18 -0
  167. package/dist/template/.pi/skills/cloudflare/references/observability/api.md +51 -0
  168. package/dist/template/.pi/skills/cloudflare/references/observability/configuration.md +60 -0
  169. package/dist/template/.pi/skills/cloudflare/references/observability/gotchas.md +36 -0
  170. package/dist/template/.pi/skills/cloudflare/references/observability/patterns.md +42 -0
  171. package/dist/template/.pi/skills/cloudflare/references/pages/README.md +76 -0
  172. package/dist/template/.pi/skills/cloudflare/references/pages/api.md +200 -0
  173. package/dist/template/.pi/skills/cloudflare/references/pages/configuration.md +228 -0
  174. package/dist/template/.pi/skills/cloudflare/references/pages/gotchas.md +161 -0
  175. package/dist/template/.pi/skills/cloudflare/references/pages/patterns.md +145 -0
  176. package/dist/template/.pi/skills/cloudflare/references/pages-functions/README.md +57 -0
  177. package/dist/template/.pi/skills/cloudflare/references/pages-functions/api.md +201 -0
  178. package/dist/template/.pi/skills/cloudflare/references/pages-functions/configuration.md +159 -0
  179. package/dist/template/.pi/skills/cloudflare/references/pages-functions/gotchas.md +151 -0
  180. package/dist/template/.pi/skills/cloudflare/references/pages-functions/patterns.md +190 -0
  181. package/dist/template/.pi/skills/cloudflare/references/pipelines/README.md +664 -0
  182. package/dist/template/.pi/skills/cloudflare/references/pulumi/README.md +107 -0
  183. package/dist/template/.pi/skills/cloudflare/references/pulumi/api.md +194 -0
  184. package/dist/template/.pi/skills/cloudflare/references/pulumi/configuration.md +216 -0
  185. package/dist/template/.pi/skills/cloudflare/references/pulumi/gotchas.md +223 -0
  186. package/dist/template/.pi/skills/cloudflare/references/pulumi/patterns.md +139 -0
  187. package/dist/template/.pi/skills/cloudflare/references/queues/README.md +69 -0
  188. package/dist/template/.pi/skills/cloudflare/references/queues/api.md +138 -0
  189. package/dist/template/.pi/skills/cloudflare/references/queues/configuration.md +125 -0
  190. package/dist/template/.pi/skills/cloudflare/references/queues/gotchas.md +112 -0
  191. package/dist/template/.pi/skills/cloudflare/references/queues/patterns.md +155 -0
  192. package/dist/template/.pi/skills/cloudflare/references/r2/README.md +61 -0
  193. package/dist/template/.pi/skills/cloudflare/references/r2/api.md +127 -0
  194. package/dist/template/.pi/skills/cloudflare/references/r2/configuration.md +76 -0
  195. package/dist/template/.pi/skills/cloudflare/references/r2/gotchas.md +94 -0
  196. package/dist/template/.pi/skills/cloudflare/references/r2/patterns.md +127 -0
  197. package/dist/template/.pi/skills/cloudflare/references/r2-data-catalog/README.md +18 -0
  198. package/dist/template/.pi/skills/cloudflare/references/r2-data-catalog/api.md +29 -0
  199. package/dist/template/.pi/skills/cloudflare/references/r2-data-catalog/configuration.md +39 -0
  200. package/dist/template/.pi/skills/cloudflare/references/r2-data-catalog/gotchas.md +20 -0
  201. package/dist/template/.pi/skills/cloudflare/references/r2-data-catalog/patterns.md +46 -0
  202. package/dist/template/.pi/skills/cloudflare/references/r2-sql/README.md +512 -0
  203. package/dist/template/.pi/skills/cloudflare/references/realtime-sfu/README.md +21 -0
  204. package/dist/template/.pi/skills/cloudflare/references/realtime-sfu/api.md +135 -0
  205. package/dist/template/.pi/skills/cloudflare/references/realtime-sfu/configuration.md +63 -0
  206. package/dist/template/.pi/skills/cloudflare/references/realtime-sfu/gotchas.md +75 -0
  207. package/dist/template/.pi/skills/cloudflare/references/realtime-sfu/patterns.md +102 -0
  208. package/dist/template/.pi/skills/cloudflare/references/realtimekit/README.md +81 -0
  209. package/dist/template/.pi/skills/cloudflare/references/realtimekit/api.md +164 -0
  210. package/dist/template/.pi/skills/cloudflare/references/realtimekit/configuration.md +147 -0
  211. package/dist/template/.pi/skills/cloudflare/references/realtimekit/gotchas.md +172 -0
  212. package/dist/template/.pi/skills/cloudflare/references/realtimekit/patterns.md +155 -0
  213. package/dist/template/.pi/skills/cloudflare/references/sandbox/README.md +90 -0
  214. package/dist/template/.pi/skills/cloudflare/references/sandbox/api.md +178 -0
  215. package/dist/template/.pi/skills/cloudflare/references/sandbox/configuration.md +131 -0
  216. package/dist/template/.pi/skills/cloudflare/references/sandbox/gotchas.md +156 -0
  217. package/dist/template/.pi/skills/cloudflare/references/sandbox/patterns.md +203 -0
  218. package/dist/template/.pi/skills/cloudflare/references/secrets-store/README.md +58 -0
  219. package/dist/template/.pi/skills/cloudflare/references/secrets-store/api.md +182 -0
  220. package/dist/template/.pi/skills/cloudflare/references/secrets-store/configuration.md +140 -0
  221. package/dist/template/.pi/skills/cloudflare/references/secrets-store/gotchas.md +129 -0
  222. package/dist/template/.pi/skills/cloudflare/references/secrets-store/patterns.md +218 -0
  223. package/dist/template/.pi/skills/cloudflare/references/smart-placement/README.md +91 -0
  224. package/dist/template/.pi/skills/cloudflare/references/smart-placement/api.md +139 -0
  225. package/dist/template/.pi/skills/cloudflare/references/smart-placement/configuration.md +129 -0
  226. package/dist/template/.pi/skills/cloudflare/references/smart-placement/gotchas.md +87 -0
  227. package/dist/template/.pi/skills/cloudflare/references/smart-placement/patterns.md +135 -0
  228. package/dist/template/.pi/skills/cloudflare/references/snippets/README.md +15 -0
  229. package/dist/template/.pi/skills/cloudflare/references/snippets/api.md +47 -0
  230. package/dist/template/.pi/skills/cloudflare/references/snippets/configuration.md +33 -0
  231. package/dist/template/.pi/skills/cloudflare/references/snippets/gotchas.md +21 -0
  232. package/dist/template/.pi/skills/cloudflare/references/snippets/patterns.md +34 -0
  233. package/dist/template/.pi/skills/cloudflare/references/spectrum/README.md +16 -0
  234. package/dist/template/.pi/skills/cloudflare/references/spectrum/api.md +24 -0
  235. package/dist/template/.pi/skills/cloudflare/references/spectrum/configuration.md +43 -0
  236. package/dist/template/.pi/skills/cloudflare/references/spectrum/gotchas.md +42 -0
  237. package/dist/template/.pi/skills/cloudflare/references/spectrum/patterns.md +40 -0
  238. package/dist/template/.pi/skills/cloudflare/references/static-assets/README.md +14 -0
  239. package/dist/template/.pi/skills/cloudflare/references/static-assets/api.md +3 -0
  240. package/dist/template/.pi/skills/cloudflare/references/static-assets/configuration.md +47 -0
  241. package/dist/template/.pi/skills/cloudflare/references/static-assets/gotchas.md +44 -0
  242. package/dist/template/.pi/skills/cloudflare/references/static-assets/patterns.md +42 -0
  243. package/dist/template/.pi/skills/cloudflare/references/stream/README.md +103 -0
  244. package/dist/template/.pi/skills/cloudflare/references/stream/api.md +204 -0
  245. package/dist/template/.pi/skills/cloudflare/references/stream/configuration.md +127 -0
  246. package/dist/template/.pi/skills/cloudflare/references/stream/gotchas.md +131 -0
  247. package/dist/template/.pi/skills/cloudflare/references/stream/patterns.md +152 -0
  248. package/dist/template/.pi/skills/cloudflare/references/tail-workers/README.md +640 -0
  249. package/dist/template/.pi/skills/cloudflare/references/terraform/README.md +76 -0
  250. package/dist/template/.pi/skills/cloudflare/references/terraform/api.md +159 -0
  251. package/dist/template/.pi/skills/cloudflare/references/terraform/configuration.md +156 -0
  252. package/dist/template/.pi/skills/cloudflare/references/terraform/gotchas.md +207 -0
  253. package/dist/template/.pi/skills/cloudflare/references/terraform/patterns.md +135 -0
  254. package/dist/template/.pi/skills/cloudflare/references/tunnel/README.md +82 -0
  255. package/dist/template/.pi/skills/cloudflare/references/tunnel/api.md +105 -0
  256. package/dist/template/.pi/skills/cloudflare/references/tunnel/configuration.md +113 -0
  257. package/dist/template/.pi/skills/cloudflare/references/tunnel/gotchas.md +115 -0
  258. package/dist/template/.pi/skills/cloudflare/references/tunnel/patterns.md +157 -0
  259. package/dist/template/.pi/skills/cloudflare/references/turn/README.md +699 -0
  260. package/dist/template/.pi/skills/cloudflare/references/turnstile/README.md +14 -0
  261. package/dist/template/.pi/skills/cloudflare/references/turnstile/api.md +3 -0
  262. package/dist/template/.pi/skills/cloudflare/references/turnstile/configuration.md +19 -0
  263. package/dist/template/.pi/skills/cloudflare/references/turnstile/gotchas.md +27 -0
  264. package/dist/template/.pi/skills/cloudflare/references/turnstile/patterns.md +41 -0
  265. package/dist/template/.pi/skills/cloudflare/references/vectorize/README.md +682 -0
  266. package/dist/template/.pi/skills/cloudflare/references/waf/README.md +14 -0
  267. package/dist/template/.pi/skills/cloudflare/references/waf/api.md +3 -0
  268. package/dist/template/.pi/skills/cloudflare/references/waf/configuration.md +44 -0
  269. package/dist/template/.pi/skills/cloudflare/references/waf/gotchas.md +24 -0
  270. package/dist/template/.pi/skills/cloudflare/references/waf/patterns.md +29 -0
  271. package/dist/template/.pi/skills/cloudflare/references/web-analytics/README.md +19 -0
  272. package/dist/template/.pi/skills/cloudflare/references/web-analytics/api.md +52 -0
  273. package/dist/template/.pi/skills/cloudflare/references/web-analytics/configuration.md +31 -0
  274. package/dist/template/.pi/skills/cloudflare/references/web-analytics/gotchas.md +28 -0
  275. package/dist/template/.pi/skills/cloudflare/references/web-analytics/patterns.md +52 -0
  276. package/dist/template/.pi/skills/cloudflare/references/workerd/README.md +47 -0
  277. package/dist/template/.pi/skills/cloudflare/references/workerd/api.md +199 -0
  278. package/dist/template/.pi/skills/cloudflare/references/workerd/configuration.md +185 -0
  279. package/dist/template/.pi/skills/cloudflare/references/workerd/gotchas.md +203 -0
  280. package/dist/template/.pi/skills/cloudflare/references/workerd/patterns.md +216 -0
  281. package/dist/template/.pi/skills/cloudflare/references/workers/README.md +96 -0
  282. package/dist/template/.pi/skills/cloudflare/references/workers/api.md +137 -0
  283. package/dist/template/.pi/skills/cloudflare/references/workers/configuration.md +147 -0
  284. package/dist/template/.pi/skills/cloudflare/references/workers/gotchas.md +99 -0
  285. package/dist/template/.pi/skills/cloudflare/references/workers/patterns.md +149 -0
  286. package/dist/template/.pi/skills/cloudflare/references/workers-ai/README.md +116 -0
  287. package/dist/template/.pi/skills/cloudflare/references/workers-for-platforms/README.md +48 -0
  288. package/dist/template/.pi/skills/cloudflare/references/workers-for-platforms/api.md +169 -0
  289. package/dist/template/.pi/skills/cloudflare/references/workers-for-platforms/configuration.md +136 -0
  290. package/dist/template/.pi/skills/cloudflare/references/workers-for-platforms/gotchas.md +130 -0
  291. package/dist/template/.pi/skills/cloudflare/references/workers-for-platforms/patterns.md +170 -0
  292. package/dist/template/.pi/skills/cloudflare/references/workers-playground/README.md +16 -0
  293. package/dist/template/.pi/skills/cloudflare/references/workers-playground/api.md +20 -0
  294. package/dist/template/.pi/skills/cloudflare/references/workers-playground/configuration.md +3 -0
  295. package/dist/template/.pi/skills/cloudflare/references/workers-playground/gotchas.md +35 -0
  296. package/dist/template/.pi/skills/cloudflare/references/workers-playground/patterns.md +42 -0
  297. package/dist/template/.pi/skills/cloudflare/references/workers-vpc/README.md +579 -0
  298. package/dist/template/.pi/skills/cloudflare/references/workflows/README.md +62 -0
  299. package/dist/template/.pi/skills/cloudflare/references/workflows/api.md +125 -0
  300. package/dist/template/.pi/skills/cloudflare/references/workflows/configuration.md +177 -0
  301. package/dist/template/.pi/skills/cloudflare/references/workflows/gotchas.md +136 -0
  302. package/dist/template/.pi/skills/cloudflare/references/workflows/patterns.md +132 -0
  303. package/dist/template/.pi/skills/cloudflare/references/wrangler/README.md +90 -0
  304. package/dist/template/.pi/skills/cloudflare/references/wrangler/api.md +140 -0
  305. package/dist/template/.pi/skills/cloudflare/references/wrangler/configuration.md +128 -0
  306. package/dist/template/.pi/skills/cloudflare/references/wrangler/gotchas.md +93 -0
  307. package/dist/template/.pi/skills/cloudflare/references/wrangler/patterns.md +150 -0
  308. package/dist/template/.pi/skills/cloudflare/references/zaraz/README.md +360 -0
  309. package/dist/template/.pi/skills/code-cleanup/SKILL.md +232 -0
  310. package/dist/template/.pi/skills/code-review-and-quality/SKILL.md +344 -0
  311. package/dist/template/.pi/skills/code-simplification/SKILL.md +348 -0
  312. package/dist/template/.pi/skills/context-engineering/SKILL.md +296 -0
  313. package/dist/template/.pi/skills/core-data-expert/SKILL.md +117 -0
  314. package/dist/template/.pi/skills/core-data-expert/references/batch-operations.md +543 -0
  315. package/dist/template/.pi/skills/core-data-expert/references/cloudkit-integration.md +259 -0
  316. package/dist/template/.pi/skills/core-data-expert/references/concurrency.md +522 -0
  317. package/dist/template/.pi/skills/core-data-expert/references/fetch-requests.md +643 -0
  318. package/dist/template/.pi/skills/core-data-expert/references/glossary.md +233 -0
  319. package/dist/template/.pi/skills/core-data-expert/references/migration.md +393 -0
  320. package/dist/template/.pi/skills/core-data-expert/references/model-configuration.md +597 -0
  321. package/dist/template/.pi/skills/core-data-expert/references/performance.md +300 -0
  322. package/dist/template/.pi/skills/core-data-expert/references/persistent-history.md +553 -0
  323. package/dist/template/.pi/skills/core-data-expert/references/project-audit.md +60 -0
  324. package/dist/template/.pi/skills/core-data-expert/references/saving.md +574 -0
  325. package/dist/template/.pi/skills/core-data-expert/references/stack-setup.md +625 -0
  326. package/dist/template/.pi/skills/core-data-expert/references/testing.md +300 -0
  327. package/dist/template/.pi/skills/core-data-expert/references/threading.md +589 -0
  328. package/dist/template/.pi/skills/debugging-and-error-recovery/SKILL.md +274 -0
  329. package/dist/template/.pi/skills/deep-module-design/SKILL.md +218 -0
  330. package/dist/template/.pi/skills/defense-in-depth/SKILL.md +161 -0
  331. package/dist/template/.pi/skills/deprecation-and-migration/SKILL.md +186 -0
  332. package/dist/template/.pi/skills/design-system-audit/SKILL.md +176 -0
  333. package/dist/template/.pi/skills/design-taste-frontend/SKILL.md +255 -0
  334. package/dist/template/.pi/skills/development-lifecycle/SKILL.md +285 -0
  335. package/dist/template/.pi/skills/documentation-and-adrs/SKILL.md +217 -0
  336. package/dist/template/.pi/skills/doubt-driven-development/SKILL.md +207 -0
  337. package/dist/template/.pi/skills/fallow/SKILL.md +457 -0
  338. package/dist/template/.pi/skills/fallow/references/cli-reference.md +1905 -0
  339. package/dist/template/.pi/skills/fallow/references/gotchas.md +644 -0
  340. package/dist/template/.pi/skills/fallow/references/patterns.md +791 -0
  341. package/dist/template/.pi/skills/figma/SKILL.md +241 -0
  342. package/dist/template/.pi/skills/frontend-design/SKILL.md +262 -0
  343. package/dist/template/.pi/skills/frontend-design/references/animation/motion-advanced.md +224 -0
  344. package/dist/template/.pi/skills/frontend-design/references/animation/motion-core.md +181 -0
  345. package/dist/template/.pi/skills/frontend-design/references/canvas/execution.md +90 -0
  346. package/dist/template/.pi/skills/frontend-design/references/canvas/philosophy.md +94 -0
  347. package/dist/template/.pi/skills/frontend-design/references/design/color-system.md +111 -0
  348. package/dist/template/.pi/skills/frontend-design/references/design/interaction.md +149 -0
  349. package/dist/template/.pi/skills/frontend-design/references/design/typography-rules.md +106 -0
  350. package/dist/template/.pi/skills/frontend-design/references/design/ux-writing.md +99 -0
  351. package/dist/template/.pi/skills/frontend-design/references/shadcn/accessibility.md +132 -0
  352. package/dist/template/.pi/skills/frontend-design/references/shadcn/core-components.md +153 -0
  353. package/dist/template/.pi/skills/frontend-design/references/shadcn/form-components.md +158 -0
  354. package/dist/template/.pi/skills/frontend-design/references/shadcn/setup.md +69 -0
  355. package/dist/template/.pi/skills/frontend-design/references/shadcn/theming.md +152 -0
  356. package/dist/template/.pi/skills/frontend-design/references/tailwind/responsive.md +112 -0
  357. package/dist/template/.pi/skills/frontend-design/references/tailwind/utilities-layout.md +134 -0
  358. package/dist/template/.pi/skills/frontend-design/references/tailwind/utilities-styling.md +165 -0
  359. package/dist/template/.pi/skills/frontend-design/references/tailwind/v4-config.md +147 -0
  360. package/dist/template/.pi/skills/frontend-design/references/tailwind/v4-features.md +128 -0
  361. package/dist/template/.pi/skills/frontend-ui-engineering/SKILL.md +217 -0
  362. package/dist/template/.pi/skills/gemini-large-context/SKILL.md +238 -0
  363. package/dist/template/.pi/skills/git-workflow-and-versioning/SKILL.md +217 -0
  364. package/dist/template/.pi/skills/grill-me/SKILL.md +162 -0
  365. package/dist/template/.pi/skills/high-end-visual-design/SKILL.md +128 -0
  366. package/dist/template/.pi/skills/idea-refine/SKILL.md +195 -0
  367. package/dist/template/.pi/skills/idea-refine/examples.md +62 -0
  368. package/dist/template/.pi/skills/idea-refine/frameworks.md +63 -0
  369. package/dist/template/.pi/skills/idea-refine/refinement-criteria.md +56 -0
  370. package/dist/template/.pi/skills/incremental-implementation/SKILL.md +190 -0
  371. package/dist/template/.pi/skills/industrial-brutalist-ui/SKILL.md +131 -0
  372. package/dist/template/.pi/skills/interview-me/SKILL.md +227 -0
  373. package/dist/template/.pi/skills/jira/SKILL.md +306 -0
  374. package/dist/template/.pi/skills/loop-audit/SKILL.md +141 -0
  375. package/dist/template/.pi/skills/loop-cost/SKILL.md +130 -0
  376. package/dist/template/.pi/skills/loop-engineering/SKILL.md +175 -0
  377. package/dist/template/.pi/skills/minimalist-ui/SKILL.md +124 -0
  378. package/dist/template/.pi/skills/mockup-to-code/SKILL.md +197 -0
  379. package/dist/template/.pi/skills/observability-and-instrumentation/SKILL.md +202 -0
  380. package/dist/template/.pi/skills/opensrc/SKILL.md +297 -0
  381. package/dist/template/.pi/skills/opensrc/references/architecture.md +176 -0
  382. package/dist/template/.pi/skills/opensrc/references/cli-usage.md +176 -0
  383. package/dist/template/.pi/skills/opensrc/references/registry-support.md +137 -0
  384. package/dist/template/.pi/skills/pdf-extract/SKILL.md +461 -0
  385. package/dist/template/.pi/skills/performance-optimization/SKILL.md +233 -0
  386. package/dist/template/.pi/skills/performance-optimization/references/performance-checklist.md +85 -0
  387. package/dist/template/.pi/skills/planning-and-task-breakdown/SKILL.md +204 -0
  388. package/dist/template/.pi/skills/playwright/SKILL.md +404 -0
  389. package/dist/template/.pi/skills/playwright/references/agent-browser-cli.md +405 -0
  390. package/dist/template/.pi/skills/polar/SKILL.md +125 -0
  391. package/dist/template/.pi/skills/react-best-practices/SKILL.md +156 -0
  392. package/dist/template/.pi/skills/react-best-practices/rules/_sections.md +46 -0
  393. package/dist/template/.pi/skills/react-best-practices/rules/_template.md +28 -0
  394. package/dist/template/.pi/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  395. package/dist/template/.pi/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  396. package/dist/template/.pi/skills/react-best-practices/rules/async-api-routes.md +38 -0
  397. package/dist/template/.pi/skills/react-best-practices/rules/async-defer-await.md +80 -0
  398. package/dist/template/.pi/skills/react-best-practices/rules/async-dependencies.md +36 -0
  399. package/dist/template/.pi/skills/react-best-practices/rules/async-parallel.md +28 -0
  400. package/dist/template/.pi/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  401. package/dist/template/.pi/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  402. package/dist/template/.pi/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  403. package/dist/template/.pi/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  404. package/dist/template/.pi/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  405. package/dist/template/.pi/skills/react-best-practices/rules/bundle-preload.md +50 -0
  406. package/dist/template/.pi/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  407. package/dist/template/.pi/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
  408. package/dist/template/.pi/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  409. package/dist/template/.pi/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  410. package/dist/template/.pi/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  411. package/dist/template/.pi/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  412. package/dist/template/.pi/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  413. package/dist/template/.pi/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  414. package/dist/template/.pi/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  415. package/dist/template/.pi/skills/react-best-practices/rules/js-early-exit.md +50 -0
  416. package/dist/template/.pi/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  417. package/dist/template/.pi/skills/react-best-practices/rules/js-index-maps.md +37 -0
  418. package/dist/template/.pi/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  419. package/dist/template/.pi/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  420. package/dist/template/.pi/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  421. package/dist/template/.pi/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  422. package/dist/template/.pi/skills/react-best-practices/rules/rendering-activity.md +26 -0
  423. package/dist/template/.pi/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  424. package/dist/template/.pi/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  425. package/dist/template/.pi/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  426. package/dist/template/.pi/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  427. package/dist/template/.pi/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  428. package/dist/template/.pi/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  429. package/dist/template/.pi/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  430. package/dist/template/.pi/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  431. package/dist/template/.pi/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  432. package/dist/template/.pi/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  433. package/dist/template/.pi/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  434. package/dist/template/.pi/skills/react-best-practices/rules/rerender-memo.md +44 -0
  435. package/dist/template/.pi/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  436. package/dist/template/.pi/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  437. package/dist/template/.pi/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  438. package/dist/template/.pi/skills/react-best-practices/rules/server-cache-react.md +76 -0
  439. package/dist/template/.pi/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  440. package/dist/template/.pi/skills/react-best-practices/rules/server-serialization.md +38 -0
  441. package/dist/template/.pi/skills/redesign-existing-projects/SKILL.md +217 -0
  442. package/dist/template/.pi/skills/resend/SKILL.md +196 -0
  443. package/dist/template/.pi/skills/resend/references/react-email.md +287 -0
  444. package/dist/template/.pi/skills/resend/references/receive-email.md +248 -0
  445. package/dist/template/.pi/skills/resend/references/send-email.md +318 -0
  446. package/dist/template/.pi/skills/root-cause-tracing/SKILL.md +216 -0
  447. package/dist/template/.pi/skills/security-and-hardening/SKILL.md +293 -0
  448. package/dist/template/.pi/skills/security-and-hardening/references/security-checklist.md +105 -0
  449. package/dist/template/.pi/skills/shipping-and-launch/SKILL.md +101 -0
  450. package/dist/template/.pi/skills/source-driven-development/SKILL.md +108 -0
  451. package/dist/template/.pi/skills/spec-driven-development/SKILL.md +177 -0
  452. package/dist/template/.pi/skills/srcwalk/SKILL.md +182 -0
  453. package/dist/template/.pi/skills/subagent-driven-development/SKILL.md +253 -0
  454. package/dist/template/.pi/skills/supabase/SKILL.md +153 -0
  455. package/dist/template/.pi/skills/supabase-postgres-best-practices/SKILL.md +88 -0
  456. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/advanced-full-text-search.md +55 -0
  457. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/advanced-jsonb-indexing.md +49 -0
  458. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/conn-idle-timeout.md +46 -0
  459. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/conn-limits.md +44 -0
  460. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/conn-pooling.md +41 -0
  461. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/conn-prepared-statements.md +46 -0
  462. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/data-batch-inserts.md +54 -0
  463. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/data-n-plus-one.md +53 -0
  464. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/data-pagination.md +50 -0
  465. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/data-upsert.md +50 -0
  466. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/lock-advisory.md +56 -0
  467. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/lock-deadlock-prevention.md +68 -0
  468. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/lock-short-transactions.md +50 -0
  469. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/lock-skip-locked.md +54 -0
  470. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/monitor-explain-analyze.md +45 -0
  471. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/monitor-pg-stat-statements.md +55 -0
  472. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/monitor-vacuum-analyze.md +55 -0
  473. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/query-composite-indexes.md +44 -0
  474. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/query-covering-indexes.md +40 -0
  475. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/query-index-types.md +45 -0
  476. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/query-missing-indexes.md +43 -0
  477. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/query-partial-indexes.md +45 -0
  478. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/schema-data-types.md +46 -0
  479. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/schema-foreign-key-indexes.md +59 -0
  480. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/schema-lowercase-identifiers.md +55 -0
  481. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/schema-partitioning.md +55 -0
  482. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/schema-primary-keys.md +61 -0
  483. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/security-privileges.md +54 -0
  484. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/security-rls-basics.md +50 -0
  485. package/dist/template/.pi/skills/supabase-postgres-best-practices/rules/security-rls-performance.md +57 -0
  486. package/dist/template/.pi/skills/swift-concurrency/SKILL.md +290 -0
  487. package/dist/template/.pi/skills/swift-concurrency/references/actors.md +640 -0
  488. package/dist/template/.pi/skills/swift-concurrency/references/async-algorithms.md +822 -0
  489. package/dist/template/.pi/skills/swift-concurrency/references/async-await-basics.md +249 -0
  490. package/dist/template/.pi/skills/swift-concurrency/references/async-sequences.md +670 -0
  491. package/dist/template/.pi/skills/swift-concurrency/references/core-data.md +533 -0
  492. package/dist/template/.pi/skills/swift-concurrency/references/glossary.md +128 -0
  493. package/dist/template/.pi/skills/swift-concurrency/references/linting.md +142 -0
  494. package/dist/template/.pi/skills/swift-concurrency/references/memory-management.md +542 -0
  495. package/dist/template/.pi/skills/swift-concurrency/references/migration.md +1076 -0
  496. package/dist/template/.pi/skills/swift-concurrency/references/performance.md +574 -0
  497. package/dist/template/.pi/skills/swift-concurrency/references/sendable.md +578 -0
  498. package/dist/template/.pi/skills/swift-concurrency/references/tasks.md +604 -0
  499. package/dist/template/.pi/skills/swift-concurrency/references/testing.md +565 -0
  500. package/dist/template/.pi/skills/swift-concurrency/references/threading.md +452 -0
  501. package/dist/template/.pi/skills/swiftui-expert-skill/SKILL.md +343 -0
  502. package/dist/template/.pi/skills/swiftui-expert-skill/references/animation-advanced.md +351 -0
  503. package/dist/template/.pi/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
  504. package/dist/template/.pi/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
  505. package/dist/template/.pi/skills/swiftui-expert-skill/references/image-optimization.md +286 -0
  506. package/dist/template/.pi/skills/swiftui-expert-skill/references/layout-best-practices.md +312 -0
  507. package/dist/template/.pi/skills/swiftui-expert-skill/references/liquid-glass.md +377 -0
  508. package/dist/template/.pi/skills/swiftui-expert-skill/references/list-patterns.md +153 -0
  509. package/dist/template/.pi/skills/swiftui-expert-skill/references/modern-apis.md +400 -0
  510. package/dist/template/.pi/skills/swiftui-expert-skill/references/performance-patterns.md +377 -0
  511. package/dist/template/.pi/skills/swiftui-expert-skill/references/scroll-patterns.md +305 -0
  512. package/dist/template/.pi/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +292 -0
  513. package/dist/template/.pi/skills/swiftui-expert-skill/references/state-management.md +447 -0
  514. package/dist/template/.pi/skills/swiftui-expert-skill/references/text-formatting.md +285 -0
  515. package/dist/template/.pi/skills/swiftui-expert-skill/references/view-structure.md +276 -0
  516. package/dist/template/.pi/skills/test-driven-development/SKILL.md +400 -0
  517. package/dist/template/.pi/skills/test-driven-development/references/testing-patterns.md +155 -0
  518. package/dist/template/.pi/skills/testing-anti-patterns/SKILL.md +339 -0
  519. package/dist/template/.pi/skills/using-agent-skills/SKILL.md +371 -0
  520. package/dist/template/.pi/skills/using-git-worktrees/SKILL.md +275 -0
  521. package/dist/template/.pi/skills/vercel-deploy-claimable/SKILL.md +144 -0
  522. package/dist/template/.pi/skills/vercel-deploy-claimable/scripts/deploy.sh +249 -0
  523. package/dist/template/.pi/skills/verification-before-completion/SKILL.md +348 -0
  524. package/dist/template/.pi/skills/webclaw/SKILL.md +188 -0
  525. package/dist/template/.pi/skills/writing-skills/SKILL.md +329 -0
  526. package/dist/template/.pi/skills/writing-skills/references/anti-patterns.md +25 -0
  527. package/dist/template/.pi/skills/writing-skills/references/claude-search-optimization.md +140 -0
  528. package/dist/template/.pi/skills/writing-skills/references/discovery-workflow.md +11 -0
  529. package/dist/template/.pi/skills/writing-skills/references/file-organization.md +32 -0
  530. package/dist/template/.pi/skills/writing-skills/references/flowcharts-and-examples.md +57 -0
  531. package/dist/template/.pi/skills/writing-skills/references/rationalization-hardening.md +75 -0
  532. package/dist/template/.pi/skills/writing-skills/references/testing-methodology.md +397 -0
  533. package/dist/template/.pi/skills/writing-skills/references/testing-skill-types.md +52 -0
  534. package/dist/template/.pi/subagents.json +10 -0
  535. package/dist/template/.pi/templates/adr.md +47 -0
  536. package/dist/template/.pi/templates/design.md +61 -0
  537. package/dist/template/.pi/templates/loop-github-action.yml +162 -0
  538. package/dist/template/.pi/templates/loop-orchestrator.sh +514 -0
  539. package/dist/template/.pi/templates/loop-orchestrator.test.ts +332 -0
  540. package/dist/template/.pi/templates/loop-orchestrator.ts +936 -0
  541. package/dist/template/.pi/templates/loop-state.json +24 -0
  542. package/dist/template/.pi/templates/loop-state.md +98 -0
  543. package/dist/template/.pi/templates/loop-vision.md +110 -0
  544. package/dist/template/.pi/templates/prd.md +204 -0
  545. package/dist/template/.pi/templates/progress.md +55 -0
  546. package/dist/template/.pi/templates/project.md +58 -0
  547. package/dist/template/.pi/templates/proposal.md +40 -0
  548. package/dist/template/.pi/templates/review-state.json +20 -0
  549. package/dist/template/.pi/templates/roadmap.md +93 -0
  550. package/dist/template/.pi/templates/state.md +97 -0
  551. package/dist/template/.pi/templates/tasks.md +202 -0
  552. package/dist/template/.pi/templates/tech-stack.md +85 -0
  553. package/dist/template/.pi/templates/user.md +26 -0
  554. package/dist/template/.pi/workflows/INDEX.md +63 -0
  555. package/dist/template/.pi/workflows/audit-pattern.md +84 -0
  556. package/dist/template/.pi/workflows/batch-implement.md +121 -0
  557. package/dist/template/.pi/workflows/deep-research.md +89 -0
  558. package/dist/template/.pi/workflows/development-lifecycle-workflow.md +175 -0
  559. package/dist/template/.pi/workflows/garbage-collection.md +144 -0
  560. package/dist/template/.pi/workflows/quality-loop.md +211 -0
  561. package/package.json +57 -0
package/dist/index.js ADDED
@@ -0,0 +1,1187 @@
1
+ #!/usr/bin/env node
2
+ import { cac } from "cac";
3
+ import { dirname, join, relative } from "node:path";
4
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
5
+ import * as p from "@clack/prompts";
6
+ import color from "picocolors";
7
+ import { createHash } from "node:crypto";
8
+ import { fileURLToPath } from "node:url";
9
+ import { mkdir, readdir } from "node:fs/promises";
10
+ //#region package.json
11
+ var version = "0.3.0";
12
+ //#endregion
13
+ //#region src/utils/manifest.ts
14
+ /**
15
+ * Template manifest — SHA-256 hash map of every installed kit file.
16
+ *
17
+ * Generated by `mdpi init` after copying the kit into a project's .pi/.
18
+ * Used by `mdpi upgrade` (future) to detect user-modified files:
19
+ * - "unmodified" → file matches template hash, safe to overwrite on upgrade
20
+ * - "modified" → user edited it, preserve on upgrade
21
+ * - "unknown" → not a template file (user-added) or no manifest present
22
+ *
23
+ * Ported from OpenCodeKit's utils/manifest.ts (paradigm-agnostic — file/hash
24
+ * ops only, no OpenCode-specific coupling).
25
+ */
26
+ const MANIFEST_FILE = ".template-manifest.json";
27
+ /** Compute SHA-256 hash of a file's content. */
28
+ function hashFile(filePath) {
29
+ return createHash("sha256").update(readFileSync(filePath, "utf-8")).digest("hex");
30
+ }
31
+ /** Walk a directory recursively → {relativePath: sha256}. */
32
+ function buildManifestFromDir(dir, skipDirs = [
33
+ "node_modules",
34
+ ".git",
35
+ "dist",
36
+ "coverage"
37
+ ]) {
38
+ const files = {};
39
+ function walk(currentDir) {
40
+ for (const entry of readdirSync(currentDir, { withFileTypes: true })) if (entry.isDirectory()) {
41
+ if (skipDirs.includes(entry.name)) continue;
42
+ walk(join(currentDir, entry.name));
43
+ } else if (entry.isFile()) {
44
+ if (entry.name === ".template-manifest.json") continue;
45
+ const fullPath = join(currentDir, entry.name);
46
+ files[relative(dir, fullPath)] = hashFile(fullPath);
47
+ }
48
+ }
49
+ walk(dir);
50
+ return files;
51
+ }
52
+ /** Generate + write the manifest into a kit directory. */
53
+ function generateManifest(piDir, version) {
54
+ const manifest = {
55
+ version,
56
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
57
+ files: buildManifestFromDir(piDir)
58
+ };
59
+ writeFileSync(join(piDir, MANIFEST_FILE), JSON.stringify(manifest, null, 2));
60
+ return manifest;
61
+ }
62
+ /** Load an existing manifest, or null if none. */
63
+ function loadManifest(piDir) {
64
+ const manifestPath = join(piDir, MANIFEST_FILE);
65
+ if (!existsSync(manifestPath)) return null;
66
+ try {
67
+ return JSON.parse(readFileSync(manifestPath, "utf-8"));
68
+ } catch {
69
+ return null;
70
+ }
71
+ }
72
+ /** Has the user modified a template file since install? */
73
+ function fileModificationStatus(filePath, relativePath, manifest) {
74
+ if (!manifest) return "unknown";
75
+ const templateHash = manifest.files[relativePath];
76
+ if (!templateHash) return "unknown";
77
+ if (!existsSync(filePath)) return "unmodified";
78
+ return hashFile(filePath) === templateHash ? "unmodified" : "modified";
79
+ }
80
+ //#endregion
81
+ //#region src/utils/template.ts
82
+ /** Shared template + version helpers used by init / upgrade / doctor. */
83
+ const DEFAULT_SKIP_DIRS = [
84
+ "node_modules",
85
+ ".git",
86
+ "dist",
87
+ "coverage",
88
+ ".next",
89
+ ".turbo"
90
+ ];
91
+ /** Resolve the bundled template root: dist/template (published) or repo root (dev tsx). */
92
+ function getTemplateRoot() {
93
+ const __dirname = dirname(fileURLToPath(import.meta.url));
94
+ const candidates = [join(__dirname, "template"), join(__dirname, "..", "..")];
95
+ for (const candidate of candidates) if (existsSync(join(candidate, ".pi"))) return candidate;
96
+ return null;
97
+ }
98
+ /** Resolve the mdpi package version (inlined by tsdown from package.json at build). */
99
+ function getPackageVersion() {
100
+ const __dirname = dirname(fileURLToPath(import.meta.url));
101
+ const pkgPaths = [join(__dirname, "..", "..", "package.json"), join(__dirname, "..", "package.json")];
102
+ for (const pkgPath of pkgPaths) {
103
+ if (!existsSync(pkgPath)) continue;
104
+ try {
105
+ return JSON.parse(readFileSync(pkgPath, "utf-8")).version ?? "unknown";
106
+ } catch {
107
+ continue;
108
+ }
109
+ }
110
+ return "unknown";
111
+ }
112
+ /** Walk a directory recursively → relative file paths (excludes skipDirs + skipFiles). */
113
+ function listFilesRel(dir, skipDirs = DEFAULT_SKIP_DIRS, skipFiles = []) {
114
+ const out = [];
115
+ function walk(d) {
116
+ for (const e of readdirSync(d, { withFileTypes: true })) if (e.isDirectory()) {
117
+ if (skipDirs.includes(e.name)) continue;
118
+ walk(join(d, e.name));
119
+ } else if (e.isFile()) {
120
+ if (skipFiles.includes(e.name)) continue;
121
+ out.push(relative(dir, join(d, e.name)));
122
+ }
123
+ }
124
+ walk(dir);
125
+ return out;
126
+ }
127
+ //#endregion
128
+ //#region src/commands/lint.ts
129
+ /**
130
+ * mdpi lint — governance checks for the .pi/ kit.
131
+ *
132
+ * Adapted from OpenCodeKit's validation/ suite to pi conventions:
133
+ * - skill-lint: pi frontmatter (name + description required, NOT version/tags/
134
+ * dependencies which pi doesn't use), H1, When to Use / NOT to Use, line
135
+ * limits, references/ depth, and DEAD CROSS-REF detection (the bug class
136
+ * fixed manually in commit 0a20e46 — skills referencing non-existent skills).
137
+ * - docs-drift: .pi/README.md counts + slash-command refs vs actual content.
138
+ *
139
+ * Usage: mdpi lint [skills|docs|all] [--json] [--fix]
140
+ * --fix auto-applies the safely-fixable rules:
141
+ * - name-match → set frontmatter `name:` to the skill directory name
142
+ * - count-* → rewrite the README kit-summary counts to match reality
143
+ * Non-fixable rules (dead-cross-ref, missing H1/frontmatter, missing/unknown
144
+ * prompt refs, max-lines, refs-depth) are still reported.
145
+ * Exit code: 1 if any error-severity issue remains, else 0.
146
+ */
147
+ const REQUIRED_FRONTMATTER = ["name", "description"];
148
+ const MAX_LINES = 500;
149
+ const MAX_LINES_WARNING = 400;
150
+ /** Kit categories whose README "(N)" counts are verified + auto-fixable. */
151
+ const COUNT_LABELS = [
152
+ "skill",
153
+ "prompt",
154
+ "agent",
155
+ "workflow",
156
+ "template"
157
+ ];
158
+ const KNOWN_PI_BUILTINS = /* @__PURE__ */ new Set([
159
+ "reload",
160
+ "skill",
161
+ "memory",
162
+ "agent",
163
+ "agents",
164
+ "clear",
165
+ "compact",
166
+ "new",
167
+ "help",
168
+ "exit",
169
+ "quit",
170
+ "model",
171
+ "theme",
172
+ "tools",
173
+ "keys",
174
+ "config",
175
+ "ask",
176
+ "dcp",
177
+ "vcc",
178
+ "observation",
179
+ "session"
180
+ ]);
181
+ function parseFrontmatter(content) {
182
+ const m = content.match(/^---\n([\s\S]*?)\n---/);
183
+ if (!m) return null;
184
+ const fields = {};
185
+ for (const line of m[1].split("\n")) {
186
+ const kv = line.match(/^(\w[\w-]*):\s*(.*)$/);
187
+ if (kv) {
188
+ const [, key, value] = kv;
189
+ fields[key] = value.replace(/^['"]|['"]$/g, "").trim();
190
+ }
191
+ }
192
+ return fields;
193
+ }
194
+ function skillDirNames(skillsDir) {
195
+ if (!existsSync(skillsDir)) return /* @__PURE__ */ new Set();
196
+ return new Set(readdirSync(skillsDir).filter((n) => statSync(join(skillsDir, n)).isDirectory() && !n.startsWith(".")));
197
+ }
198
+ /** Extract skill names referenced in body: `/skill:<n>`, `skill:<n>`, `` `<n>` skill ``. */
199
+ function findCrossRefs(content) {
200
+ const refs = /* @__PURE__ */ new Set();
201
+ for (const m of content.matchAll(/(?:\/skill:|skill:)([a-z0-9][a-z0-9-]*)/g)) refs.add(m[1]);
202
+ for (const m of content.matchAll(/`([a-z0-9][a-z0-9-]*)`\s+skill\b/g)) refs.add(m[1]);
203
+ return [...refs];
204
+ }
205
+ /** Lint one skill. With `fix=true`, rewrites the frontmatter `name:` to match the dir. */
206
+ function lintSkill(skillsDir, name, valid, fix) {
207
+ const issues = [];
208
+ let fixed = 0;
209
+ const skillPath = join(skillsDir, name, "SKILL.md");
210
+ if (!existsSync(skillPath)) {
211
+ issues.push({
212
+ scope: name,
213
+ rule: "file-exists",
214
+ severity: "error",
215
+ message: "Missing SKILL.md",
216
+ fix: "Create SKILL.md with name + description frontmatter"
217
+ });
218
+ return {
219
+ issues,
220
+ fixed
221
+ };
222
+ }
223
+ const content = readFileSync(skillPath, "utf-8");
224
+ const lineCount = content.split("\n").length;
225
+ if (lineCount > MAX_LINES) issues.push({
226
+ scope: name,
227
+ rule: "max-lines",
228
+ severity: "error",
229
+ message: `${lineCount} lines (max ${MAX_LINES}); move detail to references/`,
230
+ fix: "Extract examples/patterns to references/"
231
+ });
232
+ else if (lineCount > MAX_LINES_WARNING) issues.push({
233
+ scope: name,
234
+ rule: "max-lines-warn",
235
+ severity: "warning",
236
+ message: `${lineCount} lines (warn ${MAX_LINES_WARNING})`
237
+ });
238
+ const fm = parseFrontmatter(content);
239
+ if (!fm) issues.push({
240
+ scope: name,
241
+ rule: "frontmatter",
242
+ severity: "error",
243
+ message: "Missing YAML frontmatter (--- … ---)",
244
+ fix: "Add frontmatter with name + description"
245
+ });
246
+ else {
247
+ for (const f of REQUIRED_FRONTMATTER) if (!(f in fm) || !fm[f]) issues.push({
248
+ scope: name,
249
+ rule: `frontmatter-${f}`,
250
+ severity: "error",
251
+ message: `Missing frontmatter field: ${f}`,
252
+ fix: `Add '${f}:'`
253
+ });
254
+ const nm = fm.name;
255
+ if (typeof nm === "string" && nm !== name) if (fix) {
256
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
257
+ if (fmMatch) {
258
+ const fmBody = fmMatch[1].replace(/^(\s*name:\s*).*$/m, `$1${name}`);
259
+ if (fmBody !== fmMatch[1]) {
260
+ writeFileSync(skillPath, content.replace(fmMatch[0], `---\n${fmBody}\n---`));
261
+ fixed++;
262
+ }
263
+ }
264
+ } else issues.push({
265
+ scope: name,
266
+ rule: "name-match",
267
+ severity: "warning",
268
+ message: `frontmatter name '${nm}' ≠ directory '${name}'`,
269
+ fix: `Set frontmatter name: ${name} (or run: mdpi lint --fix)`
270
+ });
271
+ }
272
+ if (!/^#\s+\S/m.test(content)) issues.push({
273
+ scope: name,
274
+ rule: "h1",
275
+ severity: "error",
276
+ message: "Missing H1 title",
277
+ fix: "Add '# Title' after frontmatter"
278
+ });
279
+ if (!/^##\s+When\s+to\s+Use/im.test(content)) issues.push({
280
+ scope: name,
281
+ rule: "when-to-use",
282
+ severity: "warning",
283
+ message: "Missing '## When to Use'"
284
+ });
285
+ if (!/^##\s+When\s+NOT\s+to\s+Use/im.test(content)) issues.push({
286
+ scope: name,
287
+ rule: "when-not-to-use",
288
+ severity: "warning",
289
+ message: "Missing '## When NOT to Use'"
290
+ });
291
+ for (const ref of findCrossRefs(content)) if (!valid.has(ref)) issues.push({
292
+ scope: name,
293
+ rule: "dead-cross-ref",
294
+ severity: "error",
295
+ message: `references skill '${ref}' which does not exist in .pi/skills/`,
296
+ fix: `Remove the reference or add skill '${ref}'`
297
+ });
298
+ const refsDir = join(skillsDir, name, "references");
299
+ if (existsSync(refsDir)) {
300
+ const nested = readdirSync(refsDir).filter((e) => statSync(join(refsDir, e)).isDirectory());
301
+ if (nested.length) issues.push({
302
+ scope: name,
303
+ rule: "refs-depth",
304
+ severity: "warning",
305
+ message: `${nested.length} nested dir(s) in references/ — prefer flat`,
306
+ fix: "Flatten references/ to one level"
307
+ });
308
+ }
309
+ return {
310
+ issues,
311
+ fixed
312
+ };
313
+ }
314
+ function lintSkills(piDir, fix = false) {
315
+ const skillsDir = join(piDir, "skills");
316
+ if (!existsSync(skillsDir)) return {
317
+ ok: false,
318
+ issues: [{
319
+ scope: "(root)",
320
+ rule: "skills-dir",
321
+ severity: "error",
322
+ message: `skills/ not found: ${skillsDir}`
323
+ }],
324
+ stats: {
325
+ total: 0,
326
+ passed: 0,
327
+ failed: 0,
328
+ warnings: 0,
329
+ fixed: 0
330
+ }
331
+ };
332
+ const valid = skillDirNames(skillsDir);
333
+ const names = [...valid].sort();
334
+ const issues = [];
335
+ let failed = 0;
336
+ let warns = 0;
337
+ let fixed = 0;
338
+ for (const n of names) {
339
+ const si = lintSkill(skillsDir, n, valid, fix);
340
+ issues.push(...si.issues);
341
+ if (si.issues.some((i) => i.severity === "error")) failed++;
342
+ warns += si.issues.filter((i) => i.severity === "warning").length;
343
+ fixed += si.fixed;
344
+ }
345
+ return {
346
+ ok: failed === 0,
347
+ issues,
348
+ stats: {
349
+ total: names.length,
350
+ passed: names.length - failed,
351
+ failed,
352
+ warnings: warns,
353
+ fixed
354
+ }
355
+ };
356
+ }
357
+ /**
358
+ * Rewrite the README kit-summary counts to match reality. For each label, finds
359
+ * the first `` `label/` (N…) `` form and replaces N with the actual count,
360
+ * preserving any suffix (e.g. ` + INDEX`). Only matches the backtick-wrapped
361
+ * kit-summary form — leaves prose mentions of counts untouched.
362
+ */
363
+ function fixReadmeCounts(readme, counts) {
364
+ let out = readme;
365
+ for (const [label, actual] of Object.entries(counts)) {
366
+ const re = new RegExp("(`" + label + "s?/?`\\s*\\()(\\d+)([^)]*\\))");
367
+ out = out.replace(re, (_m, pre, _n, suf) => `${pre}${actual}${suf}`);
368
+ }
369
+ return out;
370
+ }
371
+ function lintDocs(piDir, fix = false) {
372
+ const readmePath = join(piDir, "README.md");
373
+ if (!existsSync(readmePath)) return {
374
+ ok: true,
375
+ issues: [],
376
+ stats: {
377
+ total: 0,
378
+ passed: 0,
379
+ failed: 0,
380
+ warnings: 0,
381
+ fixed: 0
382
+ }
383
+ };
384
+ const readme = readFileSync(readmePath, "utf-8");
385
+ const issues = [];
386
+ const list = (sub) => existsSync(join(piDir, sub)) ? readdirSync(join(piDir, sub)).filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, "")) : [];
387
+ const actualPrompts = list("prompts").filter((n) => n !== "INDEX").sort();
388
+ const actualAgents = list("agents").filter((n) => n !== "INDEX").length;
389
+ const actualSkills = existsSync(join(piDir, "skills")) ? readdirSync(join(piDir, "skills")).filter((n) => statSync(join(piDir, "skills", n)).isDirectory()).length : 0;
390
+ const actualWorkflows = list("workflows").filter((n) => n !== "INDEX").length;
391
+ const actualTemplates = list("templates").filter((n) => n !== "INDEX").length;
392
+ const counts = {
393
+ skill: actualSkills,
394
+ prompt: actualPrompts.length,
395
+ agent: actualAgents,
396
+ workflow: actualWorkflows,
397
+ template: actualTemplates
398
+ };
399
+ const documented = /* @__PURE__ */ new Set();
400
+ for (const m of readme.matchAll(/`\/([a-z0-9-]+)`/g)) documented.add(m[1]);
401
+ for (const cmd of actualPrompts) if (!documented.has(cmd)) issues.push({
402
+ scope: "README",
403
+ rule: "readme-missing-prompt",
404
+ severity: "warning",
405
+ message: `README missing '/${cmd}' (prompt exists)`
406
+ });
407
+ for (const cmd of documented) if (!actualPrompts.includes(cmd) && !KNOWN_PI_BUILTINS.has(cmd)) issues.push({
408
+ scope: "README",
409
+ rule: "readme-unknown-prompt",
410
+ severity: "warning",
411
+ message: `README references unknown '/${cmd}'`
412
+ });
413
+ const drift = (label) => {
414
+ const actual = counts[label];
415
+ const m = readme.match(new RegExp(`\\b${label}s?[^\\(\\n]*\\((\\d+)[^)]*\\)`));
416
+ if (!m) return null;
417
+ const doc = Number.parseInt(m[1], 10);
418
+ return doc === actual ? null : {
419
+ doc,
420
+ actual
421
+ };
422
+ };
423
+ const driftedLabeled = COUNT_LABELS.map((label) => ({
424
+ label,
425
+ d: drift(label)
426
+ })).filter((x) => x.d);
427
+ let fixed = 0;
428
+ if (fix) {
429
+ if (driftedLabeled.length) {
430
+ const fixedReadme = fixReadmeCounts(readme, counts);
431
+ if (fixedReadme !== readme) {
432
+ writeFileSync(readmePath, fixedReadme);
433
+ fixed = driftedLabeled.length;
434
+ }
435
+ }
436
+ } else for (const { label, d } of driftedLabeled) issues.push({
437
+ scope: "README",
438
+ rule: `count-${label}`,
439
+ severity: "warning",
440
+ message: `${label} count (${d.doc}) ≠ actual (${d.actual})`,
441
+ fix: `Update README ${label} count to ${d.actual} (or run: mdpi lint --fix)`
442
+ });
443
+ return {
444
+ ok: issues.length === 0,
445
+ issues,
446
+ stats: {
447
+ total: 1,
448
+ passed: issues.length === 0 ? 1 : 0,
449
+ failed: 0,
450
+ warnings: issues.length,
451
+ fixed
452
+ }
453
+ };
454
+ }
455
+ function lintAll(piDir, opts = {}) {
456
+ const target = opts.target ?? "all";
457
+ const fix = opts.fix ?? false;
458
+ const results = [];
459
+ if (target === "skills" || target === "all") results.push({
460
+ name: "skills",
461
+ r: lintSkills(piDir, fix)
462
+ });
463
+ if (target === "docs" || target === "all") results.push({
464
+ name: "docs",
465
+ r: lintDocs(piDir, fix)
466
+ });
467
+ if (opts.json) {
468
+ console.log(JSON.stringify(results, null, 2));
469
+ const anyFail = results.some(({ r }) => !r.ok);
470
+ process.exitCode = anyFail ? 1 : 0;
471
+ return;
472
+ }
473
+ const totalFixed = results.reduce((s, { r }) => s + r.stats.fixed, 0);
474
+ for (const { name, r } of results) {
475
+ const fixedNote = r.stats.fixed ? color.green(` · ${r.stats.fixed} fixed`) : "";
476
+ console.log(`\n${color.bold(color.cyan(name))}: ${r.stats.total} total · ${r.stats.passed} passed · ${r.stats.failed} failed · ${r.stats.warnings} warnings${fixedNote}`);
477
+ const byScope = /* @__PURE__ */ new Map();
478
+ for (const i of r.issues) {
479
+ const a = byScope.get(i.scope) ?? [];
480
+ a.push(i);
481
+ byScope.set(i.scope, a);
482
+ }
483
+ for (const [scope, iss] of byScope) {
484
+ const hasErr = iss.some((i) => i.severity === "error");
485
+ console.log(` ${hasErr ? color.red("✗") : color.yellow("⚠")} ${scope}`);
486
+ for (const i of iss) {
487
+ console.log(` ${i.severity === "error" ? color.red("ERR ") : color.yellow("WARN")} [${i.rule}] ${i.message}`);
488
+ if (i.fix) console.log(` fix: ${i.fix}`);
489
+ }
490
+ }
491
+ }
492
+ if (totalFixed) console.log(`\n${color.green("✓")} auto-fixed ${totalFixed} issue(s)`);
493
+ const anyFail = results.some(({ r }) => !r.ok);
494
+ process.exitCode = anyFail ? 1 : 0;
495
+ }
496
+ //#endregion
497
+ //#region src/commands/doctor.ts
498
+ /**
499
+ * mdpi doctor — .pi/ health check.
500
+ *
501
+ * Verifies: mdpi version match, manifest valid, settings.json valid JSON, kit
502
+ * dirs present (skills/prompts/agents/templates/workflows/extensions), orphan
503
+ * detection (manifest files no longer in template), and a lint summary.
504
+ */
505
+ function row(ok, label, detail) {
506
+ console.log(` ${ok ? color.green("✓") : color.red("✗")} ${label}: ${detail}`);
507
+ }
508
+ async function doctorCommand(options = {}) {
509
+ const quiet = process.argv.includes("--quiet");
510
+ if (!quiet) p.intro(color.bgCyan(color.black(" mdpi doctor ")));
511
+ const piDir = join(process.cwd(), ".pi");
512
+ if (!existsSync(piDir)) {
513
+ if (!quiet) {
514
+ p.log.error(".pi/ not found — run `mdpi init`");
515
+ p.outro(color.red("Failed"));
516
+ }
517
+ process.exitCode = 1;
518
+ return;
519
+ }
520
+ const mdpiVersion = getPackageVersion();
521
+ const installedVersion = existsSync(join(piDir, ".version")) ? readFileSync(join(piDir, ".version"), "utf-8").trim() : "(none)";
522
+ let manifest = loadManifest(piDir);
523
+ let manifestOk = !!manifest && typeof manifest.version === "string" && !!manifest.files;
524
+ let manifestFixed = false;
525
+ if (!manifestOk && options.fix) {
526
+ manifest = generateManifest(piDir, installedVersion !== "(none)" ? installedVersion : mdpiVersion);
527
+ manifestOk = !!manifest && !!manifest.files;
528
+ manifestFixed = manifestOk;
529
+ }
530
+ let settingsOk = false;
531
+ try {
532
+ JSON.parse(readFileSync(join(piDir, "settings.json"), "utf-8"));
533
+ settingsOk = true;
534
+ } catch {
535
+ settingsOk = false;
536
+ }
537
+ const countMd = (sub) => existsSync(join(piDir, sub)) ? readdirSync(join(piDir, sub)).filter((f) => f.endsWith(".md") && f !== "INDEX.md").length : 0;
538
+ const countExt = (sub, ext) => existsSync(join(piDir, sub)) ? readdirSync(join(piDir, sub)).filter((f) => f.endsWith(ext)).length : 0;
539
+ const skillCount = existsSync(join(piDir, "skills")) ? readdirSync(join(piDir, "skills")).filter((n) => statSync(join(piDir, "skills", n)).isDirectory()).length : 0;
540
+ const templateRoot = getTemplateRoot();
541
+ let orphans = 0;
542
+ if (templateRoot && manifest) {
543
+ const srcPi = join(templateRoot, ".pi");
544
+ const newFiles = new Set(listFilesRel(srcPi, [
545
+ "node_modules",
546
+ ".git",
547
+ "dist",
548
+ "coverage"
549
+ ], [".template-manifest.json"]));
550
+ orphans = Object.keys(manifest.files).filter((f) => !newFiles.has(f) && f !== ".version").length;
551
+ }
552
+ console.log(`\n${color.bold("mdpi doctor")} — .pi/ health\n`);
553
+ row(true, "mdpi version", `installed ${installedVersion} · cli ${mdpiVersion}` + (installedVersion !== mdpiVersion ? color.yellow(" (out of date — run mdpi upgrade)") : ""));
554
+ row(manifestOk, "manifest", manifestOk ? `${Object.keys(manifest.files).length} files tracked (v${manifest.version})` + (manifestFixed ? color.green(" (regenerated by --fix)") : "") : "missing or invalid .template-manifest.json" + (options.fix ? "" : " (run: mdpi doctor --fix)"));
555
+ row(settingsOk, "settings.json", settingsOk ? "valid JSON" : "INVALID JSON");
556
+ row(skillCount > 0, "skills", `${skillCount} skill dirs`);
557
+ row(countMd("prompts") > 0, "prompts", `${countMd("prompts")} prompts`);
558
+ row(countMd("agents") > 0, "agents", `${countMd("agents")} agents`);
559
+ row(countMd("templates") > 0, "templates", `${countMd("templates")} templates`);
560
+ row(countMd("workflows") > 0, "workflows", `${countMd("workflows")} workflows`);
561
+ row(countExt("extensions", ".ts") > 0, "extensions", `${countExt("extensions", ".ts")} extensions`);
562
+ if (templateRoot) row(orphans === 0, "orphans", orphans === 0 ? "none (template-removed files)" : `${orphans} orphan(s) — run mdpi upgrade --prune-all`);
563
+ const lr = lintSkills(piDir);
564
+ console.log(` ${lr.ok ? color.green("✓") : color.red("✗")} lint: ${lr.stats.failed} errors · ${lr.stats.warnings} warnings (run ${color.cyan("mdpi lint")} for detail)`);
565
+ const healthy = manifestOk && settingsOk && skillCount > 0 && lr.stats.failed === 0;
566
+ if (!quiet) p.outro(healthy ? color.green("Healthy") : color.yellow("Issues found"));
567
+ process.exitCode = healthy ? 0 : 1;
568
+ }
569
+ //#endregion
570
+ //#region src/commands/init.ts
571
+ /**
572
+ * mdpi init — scaffold a Pi coding-agent kit (.pi/) into the current repo.
573
+ *
574
+ * Mirrors OpenCodeKit's `ock init` but pi-native:
575
+ * - No license gate (open MIT).
576
+ * - No --global (pi global dir ~/.pi/agent/ is pi's own config; installing the
577
+ * full kit there is a footgun). Project-local only.
578
+ * - Bundled template is the CURATED kit (runtime dirs already stripped at
579
+ * build time by scripts/bundle-template.mjs).
580
+ *
581
+ * After copy, writes .pi/.version and generates .pi/.template-manifest.json
582
+ * (SHA-256 map) so a future `mdpi upgrade` can detect user modifications.
583
+ *
584
+ * --only <cats> installs only the listed category dirs (plus the always-on kit
585
+ * config/docs) and rewrites settings.json to drop references to the excluded
586
+ * `skills`/`prompts`/`extensions` dirs so pi doesn't resolve dangling paths.
587
+ * Caveat: `mdpi upgrade` always compares against the FULL template — a subset
588
+ * install is not remembered as partial, so upgrade will offer the missing
589
+ * categories (use `--check` first, or re-run `init` without `--only`).
590
+ *
591
+ * --quiet suppresses the @clack UI but still performs the install (emits one
592
+ * machine-readable line). --force overwrites template files but preserves any
593
+ * extra user-created files under .pi/ (safe, non-destructive to custom work).
594
+ */
595
+ const EXCLUDED_DIRS = [
596
+ "node_modules",
597
+ ".git",
598
+ "dist",
599
+ ".DS_Store",
600
+ "coverage",
601
+ ".next",
602
+ ".turbo"
603
+ ];
604
+ const EXCLUDED_FILES = [
605
+ "bun.lock",
606
+ "package-lock.json",
607
+ "yarn.lock",
608
+ "pnpm-lock.yaml"
609
+ ];
610
+ /** Selectable kit categories for `--only`. */
611
+ const CATEGORIES = [
612
+ "agents",
613
+ "prompts",
614
+ "skills",
615
+ "templates",
616
+ "workflows",
617
+ "context",
618
+ "extensions"
619
+ ];
620
+ /** Kit infrastructure always installed (not selectable via --only). */
621
+ const ALWAYS_ENTRIES = [
622
+ "scripts",
623
+ "artifacts/example",
624
+ "settings.json",
625
+ "AGENTS.md",
626
+ "README.md",
627
+ "QUALITY.md",
628
+ "VERSION",
629
+ ".env.example",
630
+ "guard.example.json",
631
+ "subagents.json"
632
+ ];
633
+ /** Recursively copy a directory, skipping runtime/lockfile noise. */
634
+ async function copyDir(src, dest) {
635
+ await mkdir(dest, { recursive: true });
636
+ for (const entry of await readdir(src, { withFileTypes: true })) {
637
+ if (EXCLUDED_DIRS.includes(entry.name)) continue;
638
+ if (!entry.isDirectory() && EXCLUDED_FILES.includes(entry.name)) continue;
639
+ const srcPath = join(src, entry.name);
640
+ const destPath = join(dest, entry.name);
641
+ if (entry.isSymbolicLink()) continue;
642
+ if (entry.isDirectory()) await copyDir(srcPath, destPath);
643
+ else writeFileSync(destPath, readFileSync(srcPath, "utf-8"));
644
+ }
645
+ }
646
+ /** Copy one template entry (dir or file) into the kit, creating parent dirs. */
647
+ async function copyEntry(srcPi, piDir, rel) {
648
+ const from = join(srcPi, rel);
649
+ if (!existsSync(from)) return;
650
+ const to = join(piDir, rel);
651
+ if (statSync(from).isDirectory()) await copyDir(from, to);
652
+ else {
653
+ await mkdir(join(to, ".."), { recursive: true });
654
+ writeFileSync(to, readFileSync(from, "utf-8"));
655
+ }
656
+ }
657
+ /** Parse `--only cats` into a Set. Throws on an unknown category. */
658
+ function parseOnly(only) {
659
+ if (!only) return null;
660
+ const cats = /* @__PURE__ */ new Set();
661
+ for (const raw of only.split(",").map((s) => s.trim()).filter(Boolean)) {
662
+ if (!CATEGORIES.includes(raw)) throw new Error(`unknown --only category '${raw}'. Valid: ${CATEGORIES.join(", ")}`);
663
+ cats.add(raw);
664
+ }
665
+ return cats;
666
+ }
667
+ /**
668
+ * Drop settings.json keys that reference excluded category dirs so pi doesn't
669
+ * resolve dangling `./skills`, `./prompts`, `./extensions` paths. `packages`
670
+ * (general pi runtime deps) is left untouched — agents/skills may still use
671
+ * those tools even when a category dir is absent.
672
+ */
673
+ function adaptSettingsJson(piDir, only) {
674
+ const path = join(piDir, "settings.json");
675
+ if (!existsSync(path)) return false;
676
+ let json;
677
+ try {
678
+ json = JSON.parse(readFileSync(path, "utf-8"));
679
+ } catch {
680
+ return false;
681
+ }
682
+ let changed = false;
683
+ for (const key of [
684
+ "skills",
685
+ "prompts",
686
+ "extensions"
687
+ ]) if (!only.has(key) && key in json) {
688
+ delete json[key];
689
+ changed = true;
690
+ }
691
+ if (changed) writeFileSync(path, JSON.stringify(json, null, 2) + "\n");
692
+ return changed;
693
+ }
694
+ async function initCommand(options = {}) {
695
+ const quiet = process.argv.includes("--quiet");
696
+ if (!quiet) p.intro(color.bgCyan(color.black(" mdpi ")));
697
+ let only = null;
698
+ if (options.only) try {
699
+ only = parseOnly(options.only);
700
+ } catch (error) {
701
+ if (!quiet) {
702
+ p.log.error(error instanceof Error ? error.message : String(error));
703
+ p.outro(color.red("Failed"));
704
+ }
705
+ process.exitCode = 1;
706
+ return;
707
+ }
708
+ const piDir = join(process.cwd(), ".pi");
709
+ if (!quiet) p.log.info(`Installing Pi kit to: ${color.cyan(piDir)}`);
710
+ if (existsSync(piDir) && !options.force) {
711
+ if (!quiet) {
712
+ p.log.warn(".pi/ already exists in this project");
713
+ p.log.info(`Use ${color.cyan("--force")} to overwrite template files (preserves extra user files)`);
714
+ p.outro("Nothing to do");
715
+ }
716
+ return;
717
+ }
718
+ const templateRoot = getTemplateRoot();
719
+ if (!templateRoot) {
720
+ if (!quiet) {
721
+ p.log.error("Template not found. Please reinstall mdpi.");
722
+ p.outro(color.red("Failed"));
723
+ }
724
+ process.exitCode = 1;
725
+ return;
726
+ }
727
+ const srcPi = join(templateRoot, ".pi");
728
+ if (!existsSync(srcPi)) {
729
+ if (!quiet) {
730
+ p.log.error("Template .pi/ not found");
731
+ p.outro(color.red("Failed"));
732
+ }
733
+ process.exitCode = 1;
734
+ return;
735
+ }
736
+ const spinner = quiet ? null : p.spinner();
737
+ spinner?.start(only ? `Copying subset (${[...only].join(",")}) to .pi/` : "Copying kit to .pi/");
738
+ try {
739
+ if (only) {
740
+ for (const entry of ALWAYS_ENTRIES) await copyEntry(srcPi, piDir, entry);
741
+ for (const cat of CATEGORIES) if (only.has(cat)) await copyEntry(srcPi, piDir, cat);
742
+ } else await copyDir(srcPi, piDir);
743
+ } catch (error) {
744
+ spinner?.stop("Failed");
745
+ if (!quiet) {
746
+ p.log.error(error instanceof Error ? error.message : String(error));
747
+ p.outro(color.red("Failed"));
748
+ }
749
+ process.exitCode = 1;
750
+ return;
751
+ }
752
+ spinner?.stop("Done");
753
+ const version = getPackageVersion();
754
+ writeFileSync(join(piDir, ".version"), version);
755
+ if (only) adaptSettingsJson(piDir, only);
756
+ const manifest = generateManifest(piDir, version);
757
+ const fileCount = Object.keys(manifest.files).length;
758
+ if (quiet) {
759
+ const subset = only ? ` subset=[${[...only].join(",")}]` : "";
760
+ console.log(`mdpi: installed ${fileCount} files to ${piDir} (v${version})${subset}`);
761
+ } else {
762
+ const subsetNote = only ? `Subset: ${[...only].join(", ")} (+ always-on config).\n\nsettings.json trimmed to drop references to excluded\nskills/prompts/extensions dirs.\n\nNote: mdpi upgrade compares against the FULL template —\nrun \`mdpi upgrade --check\` before applying.\n\n` : "";
763
+ p.note(`Pi kit installed at:\n${piDir}\n\n${fileCount} template files tracked via manifest.\n\n` + subsetNote + `Next: open pi in this repo to use the kit.`, "Installation complete");
764
+ p.outro(color.green("Ready!"));
765
+ }
766
+ }
767
+ //#endregion
768
+ //#region src/commands/new.ts
769
+ /**
770
+ * mdpi new — scaffold a new kit component from a lint-passing skeleton.
771
+ *
772
+ * mdpi new <kind> <name> [--description <text>] [--force]
773
+ *
774
+ * Kinds + destinations:
775
+ * skill → .pi/skills/<name>/SKILL.md
776
+ * prompt → .pi/prompts/<name>.md
777
+ * agent → .pi/agents/<name>.md
778
+ * workflow → .pi/workflows/<name>.md
779
+ * template → .pi/templates/<name>.md
780
+ *
781
+ * Skeletons are pre-shaped to pass `mdpi lint` immediately (skills get
782
+ * frontmatter + H1 + When to Use / NOT; workflows get the DAG phase format;
783
+ * prompts get the $ARGUMENTS + argument table). Idempotent: refuses to
784
+ * overwrite an existing file unless --force.
785
+ */
786
+ const KINDS = [
787
+ "skill",
788
+ "prompt",
789
+ "agent",
790
+ "workflow",
791
+ "template"
792
+ ];
793
+ /** Title-case a kebab name for H1s: "my-skill" → "My Skill". */
794
+ function titleCase(name) {
795
+ return name.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
796
+ }
797
+ /** Validate a kebab-case file/dir name (lowercase letters, digits, hyphens). */
798
+ function validName(name) {
799
+ return /^[a-z][a-z0-9-]*[a-z0-9]$|^[a-z]$/.test(name) && !name.includes("--");
800
+ }
801
+ /** Build the skeleton body for a kind, substituting name + description. */
802
+ function skeleton(kind, name, desc) {
803
+ const title = titleCase(name);
804
+ const description = desc || `TODO: when to use this ${kind}`;
805
+ switch (kind) {
806
+ case "skill": return `---
807
+ name: ${name}
808
+ description: ${description}
809
+ ---
810
+
811
+ # ${title}
812
+
813
+ TODO: what this skill does and when to reach for it.
814
+
815
+ ## When to Use
816
+
817
+ - TODO: trigger conditions and boundaries
818
+
819
+ ## When NOT to Use
820
+
821
+ - TODO: when to avoid this skill (overlapping skills, anti-patterns)
822
+
823
+ ## Procedure
824
+
825
+ 1. TODO: first concrete step
826
+ 2. TODO: second step
827
+
828
+ ## Pitfalls
829
+
830
+ - TODO: common mistake / caveat
831
+
832
+ ## Verification
833
+
834
+ - TODO: how to confirm success
835
+ `;
836
+ case "prompt": return `---
837
+ description: ${description}
838
+ argument-hint: "[<args>] [--help]"
839
+ ---
840
+
841
+ # ${title}: $ARGUMENTS
842
+
843
+ TODO: what this slash command does.
844
+
845
+ ## Parse Arguments
846
+
847
+ | Argument | Default | Description |
848
+ | ------------ | -------- | -------------------------- |
849
+ | \`<args>\` | required | TODO: what the user passes |
850
+ | \`--help\` | false | Show this usage |
851
+
852
+ ## Phase 1: TODO
853
+
854
+ TODO: first step.
855
+ `;
856
+ case "agent": return `---
857
+ name: ${name}
858
+ description: ${description}
859
+ tools: read, grep, find, ls, bash, edit, write
860
+ model: ollama-cloud/glm-5.2
861
+ ---
862
+
863
+ You are a Pi subagent.
864
+
865
+ # ${title}
866
+
867
+ **Purpose**: TODO — one line on what this agent is for.
868
+
869
+ ## When to dispatch
870
+
871
+ TODO: trigger conditions.
872
+
873
+ ## Constraints
874
+
875
+ - TODO: scope boundaries (files touched, tools allowed)
876
+ `;
877
+ case "workflow": return `---
878
+ description: ${description}
879
+ ---
880
+
881
+ # ${name}
882
+
883
+ TODO: what this workflow does. Use when ...
884
+
885
+ ## Args
886
+
887
+ - \`arg1\` (required) — TODO: what the caller passes
888
+
889
+ ## Phases
890
+
891
+ ### Phase 1: TODO
892
+
893
+ - **Agent:** general
894
+ - **Concurrency:** 1
895
+ - **Depends on:** —
896
+ - **Tool:** \`subagent\`
897
+
898
+ **Prompt:**
899
+
900
+ \`\`\`
901
+ TODO: prompt for phase 1.
902
+ \`\`\`
903
+ `;
904
+ case "template": return `# ${title} Template
905
+
906
+ > **Template Instructions:**
907
+ >
908
+ > - Replace ALL bracketed placeholders with real content
909
+ > - If you cannot fill a section, use \`[NEEDS CLARIFICATION: reason]\` instead of guessing
910
+
911
+ ## Section 1
912
+
913
+ TODO: content.
914
+ `;
915
+ }
916
+ }
917
+ /** Resolve the destination path for a kind + name. */
918
+ function destPath(piDir, kind, name) {
919
+ switch (kind) {
920
+ case "skill": return join(piDir, "skills", name, "SKILL.md");
921
+ case "prompt": return join(piDir, "prompts", `${name}.md`);
922
+ case "agent": return join(piDir, "agents", `${name}.md`);
923
+ case "workflow": return join(piDir, "workflows", `${name}.md`);
924
+ case "template": return join(piDir, "templates", `${name}.md`);
925
+ }
926
+ }
927
+ async function newCommand(kindArg, name, options = {}) {
928
+ const quiet = process.argv.includes("--quiet");
929
+ if (!quiet) p.intro(color.bgCyan(color.black(" mdpi new ")));
930
+ if (!KINDS.includes(kindArg)) {
931
+ if (!quiet) {
932
+ p.log.error(`unknown kind '${kindArg}'. Valid: ${KINDS.join(", ")}`);
933
+ p.outro(color.red("Failed"));
934
+ }
935
+ process.exitCode = 1;
936
+ return;
937
+ }
938
+ const kind = kindArg;
939
+ if (!name || !validName(name)) {
940
+ if (!quiet) {
941
+ p.log.error(`invalid name '${name ?? ""}'. Use kebab-case (lowercase letters, digits, hyphens; no leading/trailing/double hyphen).`);
942
+ p.outro(color.red("Failed"));
943
+ }
944
+ process.exitCode = 1;
945
+ return;
946
+ }
947
+ const piDir = join(process.cwd(), ".pi");
948
+ if (!existsSync(piDir)) {
949
+ if (!quiet) {
950
+ p.log.error(".pi/ not found — run `mdpi init` first");
951
+ p.outro(color.red("Failed"));
952
+ }
953
+ process.exitCode = 1;
954
+ return;
955
+ }
956
+ const dest = destPath(piDir, kind, name);
957
+ if (existsSync(dest) && !options.force) {
958
+ if (!quiet) {
959
+ p.log.warn(`${dest} already exists`);
960
+ p.log.info(`Use ${color.cyan("--force")} to overwrite`);
961
+ p.outro("Nothing to do");
962
+ }
963
+ return;
964
+ }
965
+ mkdirSync(join(dest, ".."), { recursive: true });
966
+ writeFileSync(dest, skeleton(kind, name, options.description ?? ""));
967
+ if (quiet) console.log(`mdpi: created ${kind} '${name}' → ${dest}`);
968
+ else {
969
+ p.note(`Created: ${color.cyan(dest)}\n\nEdit the skeleton, then run ${color.cyan("mdpi lint")} to verify.`, "Scaffolded");
970
+ p.outro(color.green("Ready!"));
971
+ }
972
+ }
973
+ //#endregion
974
+ //#region src/commands/upgrade.ts
975
+ /**
976
+ * mdpi upgrade — bring an installed .pi/ kit up to the bundled template version.
977
+ *
978
+ * Manifest-based (no patch files): for each template file, compare the user's
979
+ * current file hash against the install-time manifest:
980
+ * - "unmodified" → safe to overwrite with the new template version
981
+ * - "modified" → user edited it → preserve (skip) unless --force
982
+ * - "unknown" → not in manifest (new template file, or no manifest) → add
983
+ * (or, with no manifest, preserve unless --force)
984
+ *
985
+ * Orphans = files in the manifest but no longer in the new template
986
+ * (template-removed). Listed by default; --prune-all deletes them.
987
+ *
988
+ * Flags: --check (dry-run), --force (overwrite modified), --prune-all (delete
989
+ * orphans). --quiet → 1-line machine output.
990
+ */
991
+ const SKIP_DIRS = [
992
+ "node_modules",
993
+ ".git",
994
+ "dist",
995
+ "coverage",
996
+ ".next",
997
+ ".turbo"
998
+ ];
999
+ /**
1000
+ * Classify each template file against the install-time manifest.
1001
+ * Pure logic (no fs writes) — extracted so it can be unit-tested.
1002
+ *
1003
+ * unmodified → toUpdate (hash matches manifest)
1004
+ * modified → preserved unless force (user edited it)
1005
+ * unknown → toAdd if a manifest exists (new template file); with no
1006
+ * manifest, preserved unless force (can't detect edits)
1007
+ */
1008
+ function classifyFiles(newFiles, piDir, manifest, force) {
1009
+ const toUpdate = [];
1010
+ const toAdd = [];
1011
+ const preserved = [];
1012
+ for (const rel of newFiles) {
1013
+ const status = fileModificationStatus(join(piDir, rel), rel, manifest);
1014
+ if (status === "unmodified") toUpdate.push(rel);
1015
+ else if (status === "modified") if (force) toUpdate.push(rel);
1016
+ else preserved.push(rel);
1017
+ else if (manifest) toAdd.push(rel);
1018
+ else if (force) toAdd.push(rel);
1019
+ else preserved.push(rel);
1020
+ }
1021
+ return {
1022
+ toUpdate,
1023
+ toAdd,
1024
+ preserved
1025
+ };
1026
+ }
1027
+ /**
1028
+ * Orphans: files in the manifest but no longer in the new template
1029
+ * (template-removed since install). Excludes `.version` — it is mdpi-managed
1030
+ * (regenerated each init/upgrade), not a template file, so it must never be a
1031
+ * prune candidate. Returns [] when there is no manifest.
1032
+ */
1033
+ function findOrphans(installedFiles, newFiles, manifest) {
1034
+ if (!manifest) return [];
1035
+ const newSet = new Set(newFiles);
1036
+ return installedFiles.filter((f) => !newSet.has(f) && f in manifest.files && f !== ".version");
1037
+ }
1038
+ async function upgradeCommand(options = {}) {
1039
+ const quiet = process.argv.includes("--quiet");
1040
+ if (!quiet) p.intro(color.bgCyan(color.black(" mdpi upgrade ")));
1041
+ const piDir = join(process.cwd(), ".pi");
1042
+ if (!existsSync(piDir)) {
1043
+ if (!quiet) {
1044
+ p.log.error(".pi/ not found — run `mdpi init` first");
1045
+ p.outro(color.red("Failed"));
1046
+ }
1047
+ process.exitCode = 1;
1048
+ return;
1049
+ }
1050
+ const templateRoot = getTemplateRoot();
1051
+ if (!templateRoot) {
1052
+ if (!quiet) {
1053
+ p.log.error("Template not found. Reinstall mdpi.");
1054
+ p.outro(color.red("Failed"));
1055
+ }
1056
+ process.exitCode = 1;
1057
+ return;
1058
+ }
1059
+ const srcPi = join(templateRoot, ".pi");
1060
+ const currentVersion = existsSync(join(piDir, ".version")) ? readFileSync(join(piDir, ".version"), "utf-8").trim() : "unknown";
1061
+ const targetVersion = getPackageVersion();
1062
+ const manifest = loadManifest(piDir);
1063
+ const newFiles = listFilesRel(srcPi, SKIP_DIRS, [MANIFEST_FILE]);
1064
+ const installedFiles = listFilesRel(piDir, SKIP_DIRS, [MANIFEST_FILE]);
1065
+ const { toUpdate, toAdd, preserved } = classifyFiles(newFiles, piDir, manifest, !!options.force);
1066
+ const orphans = findOrphans(installedFiles, newFiles, manifest);
1067
+ if (!quiet) {
1068
+ p.log.info(`v${currentVersion} → v${targetVersion}`);
1069
+ p.log.info(`update ${toUpdate.length} · add ${toAdd.length} · preserve ${preserved.length} (user-modified) · orphans ${orphans.length}`);
1070
+ if (preserved.length) p.log.warn(`preserved: ${preserved.slice(0, 5).join(", ")}${preserved.length > 5 ? " …" : ""}`);
1071
+ if (orphans.length && !options.pruneAll) p.log.warn(`orphans kept: ${orphans.slice(0, 5).join(", ")}${orphans.length > 5 ? " …" : ""} — use --prune-all to delete`);
1072
+ }
1073
+ if (currentVersion === targetVersion && toUpdate.length === 0 && toAdd.length === 0 && !options.force) {
1074
+ if (!quiet) p.outro(color.green("Already up to date"));
1075
+ return;
1076
+ }
1077
+ if (options.check) {
1078
+ if (!quiet) p.outro("dry-run (--check), no changes written");
1079
+ return;
1080
+ }
1081
+ if (!manifest && !options.force) {
1082
+ if (!quiet) {
1083
+ p.log.error("no manifest — cannot safely detect user modifications. Use --force to overwrite everything.");
1084
+ p.outro(color.red("Aborted"));
1085
+ }
1086
+ process.exitCode = 1;
1087
+ return;
1088
+ }
1089
+ const spinner = quiet ? null : p.spinner();
1090
+ spinner?.start("Applying upgrade");
1091
+ try {
1092
+ for (const rel of [...toUpdate, ...toAdd]) {
1093
+ const dest = join(piDir, rel);
1094
+ mkdirSync(dirname(dest), { recursive: true });
1095
+ cpSync(join(srcPi, rel), dest);
1096
+ }
1097
+ if (options.pruneAll) for (const rel of orphans) rmSync(join(piDir, rel));
1098
+ } catch (error) {
1099
+ spinner?.stop("Failed");
1100
+ if (!quiet) {
1101
+ p.log.error(error instanceof Error ? error.message : String(error));
1102
+ p.outro(color.red("Failed"));
1103
+ }
1104
+ process.exitCode = 1;
1105
+ return;
1106
+ }
1107
+ spinner?.stop("Done");
1108
+ writeFileSync(join(piDir, ".version"), targetVersion);
1109
+ const newManifest = generateManifest(piDir, targetVersion);
1110
+ const total = Object.keys(newManifest.files).length;
1111
+ const prunedNote = options.pruneAll ? ` · pruned ${orphans.length}` : "";
1112
+ if (quiet) console.log(`mdpi: upgraded v${currentVersion}→v${targetVersion} (${toUpdate.length} updated, ${toAdd.length} added${prunedNote}, ${total} tracked)`);
1113
+ else {
1114
+ p.note(`Upgraded v${currentVersion} → v${targetVersion}\n\n${toUpdate.length} updated · ${toAdd.length} added · ${preserved.length} preserved${prunedNote}\n${total} files now tracked.`, "Upgrade complete");
1115
+ p.outro(color.green("Ready!"));
1116
+ }
1117
+ }
1118
+ //#endregion
1119
+ //#region src/utils/logger.ts
1120
+ const WEIGHT = {
1121
+ debug: 10,
1122
+ info: 20,
1123
+ warn: 30,
1124
+ error: 40
1125
+ };
1126
+ let threshold = "info";
1127
+ function setLogLevel(level) {
1128
+ threshold = level;
1129
+ }
1130
+ function emit(level, message) {
1131
+ if (WEIGHT[level] < WEIGHT[threshold]) return;
1132
+ const tag = level === "error" ? "error:" : level === "warn" ? "warn:" : level === "debug" ? "debug:" : "";
1133
+ if (level === "error") console.error(tag ? `${tag} ${message}` : message);
1134
+ else console.log(tag ? `${tag} ${message}` : message);
1135
+ }
1136
+ const logger = {
1137
+ debug: (msg) => emit("debug", msg),
1138
+ info: (msg) => emit("info", msg),
1139
+ warn: (msg) => emit("warn", msg),
1140
+ error: (msg) => emit("error", msg)
1141
+ };
1142
+ //#endregion
1143
+ //#region src/index.ts
1144
+ if (process.stdout.setEncoding) process.stdout.setEncoding("utf8");
1145
+ if (process.stderr.setEncoding) process.stderr.setEncoding("utf8");
1146
+ const packageVersion = version;
1147
+ const cli = cac("mdpi");
1148
+ cli.option("--verbose", "Enable verbose (debug) logging");
1149
+ cli.option("--quiet", "Suppress UI output");
1150
+ cli.version(`${packageVersion}`);
1151
+ cli.help();
1152
+ cli.command("init", "Scaffold a Pi coding-agent kit (.pi/) into the current repo").option("--force", "Overwrite existing .pi/ template files (preserves extra user files)").option("-y, --yes", "Skip prompts, use defaults (for CI)").option("--only <cats>", "Install only these categories (comma-sep: agents,prompts,skills,templates,workflows,context,extensions)").action(async (options) => {
1153
+ await initCommand(options);
1154
+ });
1155
+ cli.command("upgrade", "Bring .pi/ up to the bundled template version").option("--force", "Overwrite user-modified files (default: preserve them)").option("--check", "Dry-run: report what would change without writing").option("--prune-all", "Delete orphan files (template-removed since install)").action(async (options) => {
1156
+ await upgradeCommand(options);
1157
+ });
1158
+ cli.command("new <kind> [name]", "Scaffold a new kit component (skill|prompt|agent|workflow|template)").option("-d, --description <text>", "Set the frontmatter description (default: TODO placeholder)").option("--force", "Overwrite an existing file at the destination").action(async (kind, name, options) => {
1159
+ await newCommand(kind, name, {
1160
+ force: options?.force,
1161
+ description: options?.description
1162
+ });
1163
+ });
1164
+ cli.command("lint [target]", "Governance checks (skills|docs|all)").option("--json", "Output machine-readable JSON").option("--fix", "Auto-fix fixable issues (name-match, README counts)").action(async (target, options) => {
1165
+ lintAll(join(process.cwd(), ".pi"), {
1166
+ target: target ?? "all",
1167
+ json: options?.json,
1168
+ fix: options?.fix
1169
+ });
1170
+ });
1171
+ cli.command("doctor", "Check .pi/ health").option("--fix", "Auto-fix: regenerate manifest if missing/invalid").action(async (options) => {
1172
+ await doctorCommand({ fix: options?.fix });
1173
+ });
1174
+ cli.command("", "Show help").action(() => {
1175
+ cli.outputHelp();
1176
+ });
1177
+ try {
1178
+ const argv = process.argv.slice(2);
1179
+ if (argv.includes("--verbose")) setLogLevel("debug");
1180
+ if (argv.includes("--quiet")) setLogLevel("error");
1181
+ cli.parse(process.argv);
1182
+ } catch (error) {
1183
+ logger.error(error instanceof Error ? error.message : String(error));
1184
+ process.exit(1);
1185
+ }
1186
+ //#endregion
1187
+ export { cli };