codymaster 4.1.4 โ†’ 4.4.1

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 (662) hide show
  1. package/CHANGELOG.md +22 -2
  2. package/README.md +56 -86
  3. package/dist/index.js +130 -16
  4. package/dist/ui/box.js +2 -2
  5. package/dist/ui/onboarding.js +11 -5
  6. package/install.sh +317 -35
  7. package/package.json +8 -8
  8. package/public/dashboard/app.js +1270 -0
  9. package/public/dashboard/index.html +218 -0
  10. package/public/dashboard/style.css +440 -0
  11. package/skills/AGENTS.md +61 -0
  12. package/skills/CLAUDE.md +158 -0
  13. package/skills/boxme-git-config/SKILL.md +56 -0
  14. package/skills/boxme-local-dev/SKILL.md +66 -0
  15. package/skills/build.sh +30 -0
  16. package/skills/cf +314 -0
  17. package/skills/cf 2 +313 -0
  18. package/skills/cm-ads-tracker/SKILL.md +364 -69
  19. package/skills/cm-auto-publisher/SKILL.md +81 -0
  20. package/skills/cm-booking-calendar/SKILL.md +521 -0
  21. package/skills/cm-booking-calendar/references/industry-patterns.md +527 -0
  22. package/skills/cm-booking-calendar/templates/booking-form.css +626 -0
  23. package/skills/cm-booking-calendar/templates/booking-form.html +477 -0
  24. package/skills/cm-booking-calendar/templates/calendar-engine.js +419 -0
  25. package/skills/cm-booking-calendar/templates/calendar-export.js +395 -0
  26. package/skills/cm-booking-calendar/templates/reminder-config.js +629 -0
  27. package/skills/cm-brainstorm-idea/SKILL.md +15 -24
  28. package/skills/cm-clean-code/SKILL.md +300 -0
  29. package/skills/cm-code-review/SKILL.md +0 -27
  30. package/skills/cm-codeintell/SKILL.md +598 -0
  31. package/skills/cm-content-factory/.content-factory-state.json +132 -0
  32. package/skills/cm-content-factory/.git 2/logs/refs/heads/main +1 -0
  33. package/skills/cm-content-factory/.git 2/logs/refs/remotes/origin/main +1 -0
  34. package/skills/cm-content-factory/.git 2/objects/02/fb0956734b5f8ba3f918b7defd04a89cfe0076 +0 -0
  35. package/skills/cm-content-factory/.git 2/objects/08/1e129d75dc6feac6c02037272e6bd1a04e3324 +0 -0
  36. package/skills/cm-content-factory/.git 2/objects/0c/5393416f3c5e01c9a655a802bff0dd52f76f0a +0 -0
  37. package/skills/cm-content-factory/.git 2/objects/10/0b9be46978a946a77188f68be725098a122001 +0 -0
  38. package/skills/cm-content-factory/.git 2/objects/10/cf041167fc9843610eb3d90259ef3396315fdc +0 -0
  39. package/skills/cm-content-factory/.git 2/objects/12/5e19538dd6e1338ffe74f6c4c165b00435bf48 +0 -0
  40. package/skills/cm-content-factory/.git 2/objects/16/a9b9d0088d5c1347628b45a2620b479d8ad57c +0 -0
  41. package/skills/cm-content-factory/.git 2/objects/17/8c2a9ef93c33ae4eec9d58e82321f9229843a1 +0 -0
  42. package/skills/cm-content-factory/.git 2/objects/25/397ae41d09104d763bdcac2695209d85cdea89 +0 -0
  43. package/skills/cm-content-factory/.git 2/objects/2f/a836b7947f2d458e1f639788bf4bb0983a3305 +0 -0
  44. package/skills/cm-content-factory/.git 2/objects/3a/baaaf0a1c0909c0828335791557125fba911e0 +0 -0
  45. package/skills/cm-content-factory/.git 2/objects/42/2924221b81f5ce3c4e4daac9a64a24f9b01f9a +0 -0
  46. package/skills/cm-content-factory/.git 2/objects/42/ec0ce707447dc11446a34c9995fb8533801731 +0 -0
  47. package/skills/cm-content-factory/.git 2/objects/46/e43ce92866d56ce74b1d750db307cfe6154a15 +0 -0
  48. package/skills/cm-content-factory/.git 2/objects/48/5e41b633c63f55b8277bcc59f44f67681f671a +0 -0
  49. package/skills/cm-content-factory/.git 2/objects/49/49c596a3a89fa240642acd95dd3258e261eb09 +0 -0
  50. package/skills/cm-content-factory/.git 2/objects/50/9d42d8412ef8eaf7f7e138476bac2e4d10ce60 +0 -0
  51. package/skills/cm-content-factory/.git 2/objects/55/0c8c389d981b463ef849aeb792d8be3ccb6ec8 +0 -0
  52. package/skills/cm-content-factory/.git 2/objects/5d/82d3b18410cdda3ace3677436f0cb599dbe2d2 +0 -0
  53. package/skills/cm-content-factory/.git 2/objects/60/0617c58e871a38b33bf29e282d132bb3c381ad +0 -0
  54. package/skills/cm-content-factory/.git 2/objects/6a/8369a99c687b7245c92ffaf0e0f0dab9014504 +0 -0
  55. package/skills/cm-content-factory/.git 2/objects/79/bea435d40ab531c1aaf6be0432c6a5b7aaed21 +0 -0
  56. package/skills/cm-content-factory/.git 2/objects/7e/5ebd79251c2f14e4aceb86c74b6b6daae6b500 +0 -0
  57. package/skills/cm-content-factory/.git 2/objects/81/98a822a60178d6d5023ddb3e222cddf048742e +0 -0
  58. package/skills/cm-content-factory/.git 2/objects/86/0a0e1943dfe53411d2e499a1f16f46a96ef758 +0 -0
  59. package/skills/cm-content-factory/.git 2/objects/86/971fb55fdc081fdbae52376f0f13e57a4e9b04 +0 -0
  60. package/skills/cm-content-factory/.git 2/objects/88/b89dd609a0a03f8d4fe8bfde20d5b8fc1d326d +0 -0
  61. package/skills/cm-content-factory/.git 2/objects/90/8737edb6b7809e32cc01590b4e08ba42a9d40d +0 -0
  62. package/skills/cm-content-factory/.git 2/objects/93/d5a8a9a7d4fb7f11491cb596a6880528725118 +0 -0
  63. package/skills/cm-content-factory/.git 2/objects/98/46a2ab81d0c3b3eb00ef88fc56989aa7e9f316 +0 -0
  64. package/skills/cm-content-factory/.git 2/objects/9b/d8dd1e49cf274eaf9c555f3ab39dce7af5715e +0 -0
  65. package/skills/cm-content-factory/.git 2/objects/a1/13329fb0cec96ae78b222d33a24c3b5bc7fa1f +0 -0
  66. package/skills/cm-content-factory/.git 2/objects/a9/e6effe626e8a3aea3a8fc3364b492191c6e7d0 +0 -0
  67. package/skills/cm-content-factory/.git 2/objects/ad/6de7e48d9782cca9353d1ff0aa1aab7fe1df85 +0 -0
  68. package/skills/cm-content-factory/.git 2/objects/af/54ae316f771ff692e299ffcd8bf2f06b413b59 +0 -0
  69. package/skills/cm-content-factory/.git 2/objects/b0/4cb8b0b00dad633e731c1472161419e738d674 +0 -0
  70. package/skills/cm-content-factory/.git 2/objects/b3/094abb0b9ed46419b269e4a4e36a459690e3b0 +0 -0
  71. package/skills/cm-content-factory/.git 2/objects/b9/435c5d4baac2cfc5c83009ddd27b46b60db5f1 +0 -0
  72. package/skills/cm-content-factory/.git 2/objects/ba/5da17dbaec5ec2dcfdfd126aead518d1171d5c +0 -0
  73. package/skills/cm-content-factory/.git 2/objects/c0/bf58703aa258ba5dd63083bebaec8f223d844c +0 -0
  74. package/skills/cm-content-factory/.git 2/objects/c4/701a34edf1fc1bad58ccc57bd03f9426acb59a +0 -0
  75. package/skills/cm-content-factory/.git 2/objects/c7/5ccce9a4e5cc74d9b3174550cf6d993ca43638 +0 -0
  76. package/skills/cm-content-factory/.git 2/objects/c7/710d59b5a35b0f1f0a0399386643a0bd94c929 +0 -0
  77. package/skills/cm-content-factory/.git 2/objects/d1/fe58237112e953e5fec52da22cf38e08be3df9 +5 -0
  78. package/skills/cm-content-factory/.git 2/objects/d2/2bbe9fd2f74c95bc5583e803f5e435f1e2cd86 +0 -0
  79. package/skills/cm-content-factory/.git 2/objects/d7/e72852ea2bff74581dbf247d400120086229f4 +0 -0
  80. package/skills/cm-content-factory/.git 2/objects/d8/d4c3b5553e4fd72807e1d4b49ef07d9ef3ac35 +0 -0
  81. package/skills/cm-content-factory/.git 2/objects/dc/75050c2876f6a02ae2a53a3c886f395b622977 +0 -0
  82. package/skills/cm-content-factory/.git 2/objects/ee/e8546f95acec500187c08a28a8b9ee02db0dec +0 -0
  83. package/skills/cm-content-factory/.git 2/objects/ef/263c059208b416c2146434f10cb2b9fabcba16 +0 -0
  84. package/skills/cm-content-factory/.git 2/objects/f3/ae597e84d9a59b88acd21c99bde2eaf686d785 +0 -0
  85. package/skills/cm-content-factory/.git 2/objects/f3/f6f5673c821d3d8e76fa267a9e882e7a5387ea +0 -0
  86. package/skills/cm-content-factory/.git 2/objects/f9/6e6d0ad02624dd11d5848594d056caef7a5e8b +0 -0
  87. package/skills/cm-content-factory/.git 2/objects/ff/278988fc1edf0db3abcf18de795f4cc0b4f3e1 +0 -0
  88. package/skills/cm-content-factory/.git 2/refs/heads/main +1 -0
  89. package/skills/cm-content-factory/.git 2/refs/remotes/origin/main +1 -0
  90. package/skills/cm-content-factory/.pytest_cache 2/v/cache/nodeids +76 -0
  91. package/skills/cm-content-factory/.pytest_cache 2/v/cache/stepwise +1 -0
  92. package/skills/cm-content-factory/AGENTS.md +61 -0
  93. package/skills/cm-content-factory/CLAUDE.md +63 -0
  94. package/skills/cm-content-factory/CURSOR.md +43 -0
  95. package/skills/cm-content-factory/Content Factory.zip +0 -0
  96. package/skills/cm-content-factory/cf +313 -0
  97. package/skills/cm-content-factory/config.schema.json +397 -0
  98. package/skills/cm-content-factory/dashboard/app.js +556 -0
  99. package/skills/cm-content-factory/dashboard/index.html +397 -0
  100. package/skills/cm-content-factory/dashboard/style.css +1211 -0
  101. package/skills/cm-content-factory/examples/01-real-estate.config.json +146 -0
  102. package/skills/cm-content-factory/examples/02-personal-finance.config.json +146 -0
  103. package/skills/cm-content-factory/examples/03-health-wellness.config.json +147 -0
  104. package/skills/cm-content-factory/examples/04-saas-software.config.json +147 -0
  105. package/skills/cm-content-factory/examples/05-legal-services.config.json +147 -0
  106. package/skills/cm-content-factory/examples/06-insurance.config.json +146 -0
  107. package/skills/cm-content-factory/examples/07-ecommerce-dropship.config.json +146 -0
  108. package/skills/cm-content-factory/examples/08-online-education.config.json +147 -0
  109. package/skills/cm-content-factory/examples/09-crypto-defi.config.json +147 -0
  110. package/skills/cm-content-factory/examples/10-beauty-skincare.config.json +147 -0
  111. package/skills/cm-content-factory/examples/11-home-services.config.json +146 -0
  112. package/skills/cm-content-factory/examples/12-dental-clinic.config.json +147 -0
  113. package/skills/cm-content-factory/examples/13-pet-care.config.json +147 -0
  114. package/skills/cm-content-factory/examples/14-travel-hospitality.config.json +147 -0
  115. package/skills/cm-content-factory/examples/15-ai-automation.config.json +147 -0
  116. package/skills/cm-content-factory/examples/16-wedding-events.config.json +147 -0
  117. package/skills/cm-content-factory/examples/17-fitness-coaching.config.json +148 -0
  118. package/skills/cm-content-factory/examples/18-cybersecurity.config.json +147 -0
  119. package/skills/cm-content-factory/examples/19-food-restaurant.config.json +148 -0
  120. package/skills/cm-content-factory/examples/20-solar-energy.config.json +147 -0
  121. package/skills/cm-content-factory/examples/fitness-blog.config.json +116 -0
  122. package/skills/cm-content-factory/examples/tech-blog.config.json +107 -0
  123. package/skills/cm-content-factory/extensions/EXTENSION_GUIDE.md +72 -0
  124. package/skills/cm-content-factory/extensions/hooks.py +126 -0
  125. package/skills/cm-content-factory/extensions/openclaw_adapter.py +132 -0
  126. package/skills/cm-content-factory/landing/index.html +680 -0
  127. package/skills/cm-content-factory/landing/script.js +101 -0
  128. package/skills/cm-content-factory/landing/style.css +1216 -0
  129. package/skills/cm-content-factory/landing/translations.js +508 -0
  130. package/skills/cm-content-factory/logs/events.jsonl +11 -0
  131. package/skills/cm-content-factory/profiles/_template.profile.json +231 -0
  132. package/skills/cm-content-factory/profiles/finance.profile.json +278 -0
  133. package/skills/cm-content-factory/profiles/legal.profile.json +263 -0
  134. package/skills/cm-content-factory/profiles/medical-research.profile.json +321 -0
  135. package/skills/cm-content-factory/profiles/technology.profile.json +275 -0
  136. package/skills/cm-content-factory/scripts/agent_dispatcher.py +266 -0
  137. package/skills/cm-content-factory/scripts/audit.py +106 -0
  138. package/skills/cm-content-factory/scripts/dashboard_server.py +225 -0
  139. package/skills/cm-content-factory/scripts/deploy.py +146 -0
  140. package/skills/cm-content-factory/scripts/extract.py +132 -0
  141. package/skills/cm-content-factory/scripts/landing_generator.py +459 -0
  142. package/skills/cm-content-factory/scripts/memory.py +521 -0
  143. package/skills/cm-content-factory/scripts/monetize.py +239 -0
  144. package/skills/cm-content-factory/scripts/pipeline.py +357 -0
  145. package/skills/cm-content-factory/scripts/plan.py +163 -0
  146. package/skills/cm-content-factory/scripts/publish.py +145 -0
  147. package/skills/cm-content-factory/scripts/research.py +337 -0
  148. package/skills/cm-content-factory/scripts/scaffold.py +464 -0
  149. package/skills/cm-content-factory/scripts/scoreboard.py +336 -0
  150. package/skills/cm-content-factory/scripts/seo.py +90 -0
  151. package/skills/cm-content-factory/scripts/state_manager.py +320 -0
  152. package/skills/cm-content-factory/scripts/token_manager.py +268 -0
  153. package/skills/cm-content-factory/scripts/validate.py +221 -0
  154. package/skills/cm-content-factory/scripts/wizard.py +329 -0
  155. package/skills/cm-content-factory/scripts/write.py +93 -0
  156. package/skills/cm-content-factory/sites/docs-site/src/assets/houston.webp +0 -0
  157. package/skills/cm-content-factory/sites/docs-site/src/content/docs/architecture.md +90 -0
  158. package/skills/cm-content-factory/sites/docs-site/src/content/docs/data-flow.md +54 -0
  159. package/skills/cm-content-factory/sites/docs-site/src/content/docs/deployment.md +38 -0
  160. package/skills/cm-content-factory/sites/docs-site/src/content/docs/flows/index.md +65 -0
  161. package/skills/cm-content-factory/sites/docs-site/src/content/docs/flows/lc-content-lifecycle.md +48 -0
  162. package/skills/cm-content-factory/sites/docs-site/src/content/docs/flows/seq-write-mode.md +39 -0
  163. package/skills/cm-content-factory/sites/docs-site/src/content/docs/flows/uj-first-batch.md +42 -0
  164. package/skills/cm-content-factory/sites/docs-site/src/content/docs/flows/wf-content-pipeline.md +51 -0
  165. package/skills/cm-content-factory/sites/docs-site/src/content/docs/flows/wf-learning-cycle.md +52 -0
  166. package/skills/cm-content-factory/sites/docs-site/src/content/docs/getting-started/configuration.md +86 -0
  167. package/skills/cm-content-factory/sites/docs-site/src/content/docs/getting-started/installation.md +80 -0
  168. package/skills/cm-content-factory/sites/docs-site/src/content/docs/getting-started/intro.md +58 -0
  169. package/skills/cm-content-factory/sites/docs-site/src/content/docs/index.md +102 -0
  170. package/skills/cm-content-factory/sites/docs-site/src/content/docs/jtbd/index.md +45 -0
  171. package/skills/cm-content-factory/sites/docs-site/src/content/docs/jtbd/optimize-seo.md +29 -0
  172. package/skills/cm-content-factory/sites/docs-site/src/content/docs/jtbd/scale-content-production.md +55 -0
  173. package/skills/cm-content-factory/sites/docs-site/src/content/docs/jtbd/standardize-quality.md +29 -0
  174. package/skills/cm-content-factory/sites/docs-site/src/content/docs/personas/buyer-cmo-huong.md +41 -0
  175. package/skills/cm-content-factory/sites/docs-site/src/content/docs/personas/buyer-content-lead-khoa.md +40 -0
  176. package/skills/cm-content-factory/sites/docs-site/src/content/docs/personas/index.md +56 -0
  177. package/skills/cm-content-factory/sites/docs-site/src/content/docs/personas/user-content-manager-lan.md +46 -0
  178. package/skills/cm-content-factory/sites/docs-site/src/content/docs/personas/user-seo-minh.md +45 -0
  179. package/skills/cm-content-factory/sites/docs-site/src/content/docs/personas/user-writer-tu.md +45 -0
  180. package/skills/cm-content-factory/sites/docs-site/src/content/docs/sop/content-pipeline.md +108 -0
  181. package/skills/cm-content-factory/sites/docs-site/src/content/docs/sop/index.md +22 -0
  182. package/skills/cm-content-factory/sites/docs-site/src/content/docs/sop/memory-system.md +52 -0
  183. package/skills/cm-content-factory/sites/docs-site/src/content/docs/sop/seo-optimization.md +58 -0
  184. package/skills/cm-content-factory/sites/docs-site/src/content/docs/sop/troubleshooting-guide.md +92 -0
  185. package/skills/cm-content-factory/sites/docs-site/src/styles/custom.css +575 -0
  186. package/skills/cm-content-factory/tests/conftest.py +66 -0
  187. package/skills/cm-content-factory/tests/test_agent_dispatcher.py +125 -0
  188. package/skills/cm-content-factory/tests/test_memory.py +128 -0
  189. package/skills/cm-content-factory/tests/test_pipeline.py +107 -0
  190. package/skills/cm-content-factory/tests/test_research.py +56 -0
  191. package/skills/cm-content-factory/tests/test_state_manager.py +131 -0
  192. package/skills/cm-content-factory/tests/test_token_manager.py +110 -0
  193. package/skills/cm-content-factory/tests/test_wizard.py +121 -0
  194. package/skills/cm-continuity/SKILL.md +7 -0
  195. package/skills/cm-cro-methodology/SKILL.md +290 -0
  196. package/skills/cm-dashboard/SKILL.md +7 -525
  197. package/skills/cm-debugging/SKILL.md +7 -116
  198. package/skills/cm-deep-search/SKILL.md +5 -1
  199. package/skills/cm-dockit/README.md +6 -15
  200. package/skills/cm-dockit/SKILL.md +20 -37
  201. package/skills/cm-execution/SKILL.md +6 -1
  202. package/skills/cm-frappe-agent/SKILL.md +134 -0
  203. package/skills/cm-frappe-agent/agents/doctype-architect.md +596 -0
  204. package/skills/cm-frappe-agent/agents/erpnext-customizer.md +643 -0
  205. package/skills/cm-frappe-agent/agents/frappe-backend.md +814 -0
  206. package/skills/cm-frappe-agent/agents/frappe-custom-frontend.md +557 -0
  207. package/skills/cm-frappe-agent/agents/frappe-debugger.md +625 -0
  208. package/skills/cm-frappe-agent/agents/frappe-fixer.md +275 -0
  209. package/skills/cm-frappe-agent/agents/frappe-frontend.md +660 -0
  210. package/skills/cm-frappe-agent/agents/frappe-installer.md +158 -0
  211. package/skills/cm-frappe-agent/agents/frappe-performance.md +307 -0
  212. package/skills/cm-frappe-agent/agents/frappe-planner.md +419 -0
  213. package/skills/cm-frappe-agent/agents/frappe-remote-ops.md +153 -0
  214. package/skills/cm-frappe-agent/agents/github-workflow.md +286 -0
  215. package/skills/cm-frappe-agent/commands/frappe-app.md +351 -0
  216. package/skills/cm-frappe-agent/commands/frappe-backend.md +162 -0
  217. package/skills/cm-frappe-agent/commands/frappe-bench.md +254 -0
  218. package/skills/cm-frappe-agent/commands/frappe-debug.md +263 -0
  219. package/skills/cm-frappe-agent/commands/frappe-doctype-create.md +272 -0
  220. package/skills/cm-frappe-agent/commands/frappe-doctype-field.md +310 -0
  221. package/skills/cm-frappe-agent/commands/frappe-erpnext.md +210 -0
  222. package/skills/cm-frappe-agent/commands/frappe-fix.md +59 -0
  223. package/skills/cm-frappe-agent/commands/frappe-frontend.md +210 -0
  224. package/skills/cm-frappe-agent/commands/frappe-fullstack.md +243 -0
  225. package/skills/cm-frappe-agent/commands/frappe-github.md +57 -0
  226. package/skills/cm-frappe-agent/commands/frappe-install.md +52 -0
  227. package/skills/cm-frappe-agent/commands/frappe-plan.md +442 -0
  228. package/skills/cm-frappe-agent/commands/frappe-remote.md +58 -0
  229. package/skills/cm-frappe-agent/commands/frappe-test.md +356 -0
  230. package/skills/cm-frappe-agent/docs/README.md +51 -0
  231. package/skills/cm-frappe-agent/docs/agents-catalog.md +113 -0
  232. package/skills/cm-frappe-agent/docs/architecture.md +149 -0
  233. package/skills/cm-frappe-agent/docs/commands-catalog.md +82 -0
  234. package/skills/cm-frappe-agent/docs/resources-catalog.md +66 -0
  235. package/skills/cm-frappe-agent/docs/sitemap-urls.txt +52 -0
  236. package/skills/cm-frappe-agent/docs/sitemap.md +81 -0
  237. package/skills/cm-frappe-agent/docs/sop/user-guide.md +178 -0
  238. package/skills/cm-frappe-agent/docs/sop/vibe-coding-guide.md +122 -0
  239. package/skills/cm-frappe-agent/resources/7-layer-architecture.md +985 -0
  240. package/skills/cm-frappe-agent/resources/bench_commands.md +73 -0
  241. package/skills/cm-frappe-agent/resources/code-patterns-guide.md +948 -0
  242. package/skills/cm-frappe-agent/resources/common_pitfalls.md +266 -0
  243. package/skills/cm-frappe-agent/resources/doctype-registry.md +158 -0
  244. package/skills/cm-frappe-agent/resources/installation-guide.md +289 -0
  245. package/skills/cm-frappe-agent/resources/rest-api-patterns.md +182 -0
  246. package/skills/cm-frappe-agent/resources/scaffold_checklist.md +82 -0
  247. package/skills/cm-frappe-agent/resources/upgrade_patterns.md +113 -0
  248. package/skills/cm-frappe-agent/resources/web-form-patterns.md +252 -0
  249. package/skills/cm-frappe-agent/skills/bench-commands/SKILL.md +621 -0
  250. package/skills/cm-frappe-agent/skills/client-scripts/SKILL.md +642 -0
  251. package/skills/cm-frappe-agent/skills/doctype-patterns/SKILL.md +576 -0
  252. package/skills/cm-frappe-agent/skills/frappe-api/SKILL.md +740 -0
  253. package/skills/cm-frappe-agent/skills/remote-operations/SKILL.md +47 -0
  254. package/skills/cm-frappe-agent/skills/server-scripts/SKILL.md +608 -0
  255. package/skills/cm-frappe-agent/skills/web-forms/SKILL.md +46 -0
  256. package/skills/cm-git-worktrees/SKILL.md +0 -7
  257. package/skills/cm-google-form/SKILL.md +266 -0
  258. package/skills/cm-google-form/templates/apps-script.js +55 -0
  259. package/skills/cm-google-form/templates/form-markup.html +110 -0
  260. package/skills/cm-google-form/templates/form-submit.js +201 -0
  261. package/skills/cm-google-form/templates/toast.css +152 -0
  262. package/skills/cm-growth-hacking/SKILL.md +293 -0
  263. package/skills/cm-growth-hacking/bottom-sheet-engine.md +261 -0
  264. package/skills/cm-growth-hacking/calendar-integration.md +264 -0
  265. package/skills/cm-growth-hacking/references/engagement-patterns.md +346 -0
  266. package/skills/cm-growth-hacking/templates/bottom-sheet.css +528 -0
  267. package/skills/cm-growth-hacking/templates/bottom-sheet.js +269 -0
  268. package/skills/cm-growth-hacking/templates/calendar-cta.js +213 -0
  269. package/skills/cm-growth-hacking/templates/tracking-events.js +211 -0
  270. package/skills/cm-growth-hacking/templates/trigger-manager.js +254 -0
  271. package/skills/cm-growth-hacking/tracking-events.md +246 -0
  272. package/skills/cm-growth-hacking/trigger-system.md +342 -0
  273. package/skills/cm-how-it-work/SKILL.md +20 -4
  274. package/skills/cm-identity-guard/SKILL.md +0 -11
  275. package/skills/cm-jtbd/SKILL.md +1 -1
  276. package/skills/cm-notebooklm/SKILL.md +172 -0
  277. package/skills/cm-notebooklm/references/command_reference.md +94 -0
  278. package/skills/cm-notebooklm/references/workflows.md +60 -0
  279. package/skills/cm-notebooklm/resources/knowledge_sources.md +106 -0
  280. package/skills/cm-notebooklm/scripts/brain-sync.sh +453 -0
  281. package/skills/cm-notebooklm/scripts/graduate_wisdom.py +101 -0
  282. package/skills/cm-planning/SKILL.md +39 -52
  283. package/skills/cm-project-bootstrap/SKILL.md +1308 -99
  284. package/skills/cm-quality-gate/SKILL.md +13 -106
  285. package/skills/cm-reactor/SKILL.md +274 -0
  286. package/skills/cm-safe-deploy/SKILL.md +415 -52
  287. package/skills/cm-safe-i18n/SKILL.md +1 -22
  288. package/skills/cm-secret-shield/SKILL.md +2 -2
  289. package/skills/cm-security-gate/SKILL.md +114 -0
  290. package/skills/cm-skill-chain/SKILL.md +2 -2
  291. package/skills/cm-skill-index/SKILL.md +9 -6
  292. package/skills/cm-skill-mastery/SKILL.md +2 -15
  293. package/skills/cm-start/SKILL.md +9 -0
  294. package/skills/cm-tdd/SKILL.md +16 -49
  295. package/skills/cm-ui-preview/SKILL.md +35 -173
  296. package/skills/cm-ux-master/FEATURES-v4.md +305 -0
  297. package/skills/cm-ux-master/README-ru.md +135 -0
  298. package/skills/cm-ux-master/README-vi.md +135 -0
  299. package/skills/cm-ux-master/README-zh.md +135 -0
  300. package/skills/cm-ux-master/README.md +489 -0
  301. package/skills/cm-ux-master/SKILL.md +773 -62
  302. package/skills/cm-ux-master/cli/README.md +180 -0
  303. package/skills/cm-ux-master/cli/pyproject.toml +106 -0
  304. package/skills/cm-ux-master/cli/requirements.txt +21 -0
  305. package/skills/cm-ux-master/cli/templates/base/skill-core.md +262 -0
  306. package/skills/cm-ux-master/cli/templates/platforms/claude.yaml +21 -0
  307. package/skills/cm-ux-master/cli/templates/platforms/cursor.yaml +21 -0
  308. package/skills/cm-ux-master/cli/templates/platforms/figma.yaml +24 -0
  309. package/skills/cm-ux-master/cli/templates/platforms/vscode-mcp.yaml +28 -0
  310. package/skills/cm-ux-master/cli/templates/platforms/windsurf.yaml +21 -0
  311. package/skills/cm-ux-master/cli/uxmaster/__init__.py +10 -0
  312. package/skills/cm-ux-master/cli/uxmaster/__main__.py +19 -0
  313. package/skills/cm-ux-master/cli/uxmaster/cli.py +349 -0
  314. package/skills/cm-ux-master/cli/uxmaster/commands/__init__.py +8 -0
  315. package/skills/cm-ux-master/cli/uxmaster/commands/extract.py +18 -0
  316. package/skills/cm-ux-master/cli/uxmaster/commands/init.py +58 -0
  317. package/skills/cm-ux-master/cli/uxmaster/commands/mcp.py +194 -0
  318. package/skills/cm-ux-master/cli/uxmaster/commands/search.py +23 -0
  319. package/skills/cm-ux-master/cli/uxmaster/commands/validate.py +270 -0
  320. package/skills/cm-ux-master/cli/uxmaster/search_engine.py +532 -0
  321. package/skills/cm-ux-master/cli/uxmaster/template_engine.py +458 -0
  322. package/skills/cm-ux-master/cli/uxmaster/utils/__init__.py +9 -0
  323. package/skills/cm-ux-master/cli/uxmaster/utils/console.py +42 -0
  324. package/skills/cm-ux-master/cli/uxmaster/utils/detect.py +83 -0
  325. package/skills/cm-ux-master/data/accessibility-advanced.csv +26 -0
  326. package/skills/cm-ux-master/data/animation.csv +31 -0
  327. package/skills/cm-ux-master/data/charts.csv +26 -0
  328. package/skills/cm-ux-master/data/colors.csv +97 -0
  329. package/skills/cm-ux-master/data/design-tests.csv +37 -0
  330. package/skills/cm-ux-master/data/devices.csv +21 -0
  331. package/skills/cm-ux-master/data/icons.csv +101 -0
  332. package/skills/cm-ux-master/data/landing.csv +31 -0
  333. package/skills/cm-ux-master/data/products.csv +97 -0
  334. package/skills/cm-ux-master/data/react-performance.csv +45 -0
  335. package/skills/cm-ux-master/data/responsive.csv +26 -0
  336. package/skills/cm-ux-master/data/semi-tokens.csv +52 -0
  337. package/skills/cm-ux-master/data/stacks/angular.csv +34 -0
  338. package/skills/cm-ux-master/data/stacks/astro.csv +54 -0
  339. package/skills/cm-ux-master/data/stacks/electron.csv +32 -0
  340. package/skills/cm-ux-master/data/stacks/flutter.csv +53 -0
  341. package/skills/cm-ux-master/data/stacks/html-tailwind.csv +56 -0
  342. package/skills/cm-ux-master/data/stacks/htmx.csv +28 -0
  343. package/skills/cm-ux-master/data/stacks/jetpack-compose.csv +53 -0
  344. package/skills/cm-ux-master/data/stacks/nextjs.csv +53 -0
  345. package/skills/cm-ux-master/data/stacks/nuxt-ui.csv +51 -0
  346. package/skills/cm-ux-master/data/stacks/nuxtjs.csv +59 -0
  347. package/skills/cm-ux-master/data/stacks/react-native.csv +52 -0
  348. package/skills/cm-ux-master/data/stacks/react.csv +54 -0
  349. package/skills/cm-ux-master/data/stacks/shadcn.csv +61 -0
  350. package/skills/cm-ux-master/data/stacks/svelte.csv +54 -0
  351. package/skills/cm-ux-master/data/stacks/swiftui.csv +51 -0
  352. package/skills/cm-ux-master/data/stacks/tauri.csv +29 -0
  353. package/skills/cm-ux-master/data/stacks/vue.csv +50 -0
  354. package/skills/cm-ux-master/data/styles.csv +68 -0
  355. package/skills/cm-ux-master/data/typography.csv +58 -0
  356. package/skills/cm-ux-master/data/ui-reasoning.csv +101 -0
  357. package/skills/cm-ux-master/data/ux-guidelines.csv +100 -0
  358. package/skills/cm-ux-master/data/ux-laws.csv +49 -0
  359. package/skills/cm-ux-master/data/web-interface.csv +31 -0
  360. package/skills/cm-ux-master/docs/LANDING-PAGE.html +377 -0
  361. package/skills/cm-ux-master/docs/README.md +108 -0
  362. package/skills/cm-ux-master/docs/css/styles.css +573 -0
  363. package/skills/cm-ux-master/docs/examples/demo-script.md +319 -0
  364. package/skills/cm-ux-master/docs/guides/for-designers.md +692 -0
  365. package/skills/cm-ux-master/docs/guides/for-developers.md +778 -0
  366. package/skills/cm-ux-master/docs/guides/for-product-managers.md +693 -0
  367. package/skills/cm-ux-master/docs/guides/react-guide-vi.md +50 -0
  368. package/skills/cm-ux-master/docs/index.html +1062 -0
  369. package/skills/cm-ux-master/docs/js/i18n.js +84 -0
  370. package/skills/cm-ux-master/docs/js/lang/de.js +145 -0
  371. package/skills/cm-ux-master/docs/js/lang/en.js +145 -0
  372. package/skills/cm-ux-master/docs/js/lang/fr.js +145 -0
  373. package/skills/cm-ux-master/docs/js/lang/hi.js +145 -0
  374. package/skills/cm-ux-master/docs/js/lang/id.js +145 -0
  375. package/skills/cm-ux-master/docs/js/lang/ja.js +145 -0
  376. package/skills/cm-ux-master/docs/js/lang/ko.js +145 -0
  377. package/skills/cm-ux-master/docs/js/lang/ru.js +145 -0
  378. package/skills/cm-ux-master/docs/js/lang/vi.js +145 -0
  379. package/skills/cm-ux-master/docs/js/lang/zh.js +145 -0
  380. package/skills/cm-ux-master/docs/js/main.js +117 -0
  381. package/skills/cm-ux-master/docs/plan/PHASE1-COMPLETION.md +217 -0
  382. package/skills/cm-ux-master/docs/plan/PHASE2-COMPLETION.md +199 -0
  383. package/skills/cm-ux-master/docs/plan/PHASE2-ENHANCED-COMPLETION.md +352 -0
  384. package/skills/cm-ux-master/docs/plan/PHASE3-VALIDATION-COMPLETION.md +499 -0
  385. package/skills/cm-ux-master/docs/plan/PHASE4-TESTING-POLISH-COMPLETION.md +483 -0
  386. package/skills/cm-ux-master/docs/plan/UXM-2.0-ROADMAP.md +681 -0
  387. package/skills/cm-ux-master/docs/plan/WOW-PITCH.md +410 -0
  388. package/skills/cm-ux-master/docs/technical/api-reference.md +824 -0
  389. package/skills/cm-ux-master/docs/technical/harvester-v4.md +328 -0
  390. package/skills/cm-ux-master/docs/technical/how-it-works.md +1128 -0
  391. package/skills/cm-ux-master/docs/tutorials/quickstart.md +339 -0
  392. package/skills/cm-ux-master/docs/tutorials/tutorials.md +939 -0
  393. package/skills/cm-ux-master/docs/tutorials/user-guide.md +716 -0
  394. package/skills/cm-ux-master/examples/README.md +63 -0
  395. package/skills/cm-ux-master/mcp/__init__.py +3 -0
  396. package/skills/cm-ux-master/mcp/integrations/__init__.py +11 -0
  397. package/skills/cm-ux-master/mcp/integrations/figma/__init__.py +6 -0
  398. package/skills/cm-ux-master/mcp/integrations/figma/client.py +293 -0
  399. package/skills/cm-ux-master/mcp/integrations/figma/plugin/code.js +561 -0
  400. package/skills/cm-ux-master/mcp/integrations/figma/plugin/ui.html +334 -0
  401. package/skills/cm-ux-master/mcp/integrations/stitch/__init__.py +5 -0
  402. package/skills/cm-ux-master/mcp/integrations/stitch/client.py +410 -0
  403. package/skills/cm-ux-master/mcp/integrations/vscode/package.json +167 -0
  404. package/skills/cm-ux-master/mcp/integrations/vscode/src/extension.ts +81 -0
  405. package/skills/cm-ux-master/mcp/mcp-config.json +274 -0
  406. package/skills/cm-ux-master/mcp/server.py +771 -0
  407. package/skills/cm-ux-master/mcp/tools/__init__.py +13 -0
  408. package/skills/cm-ux-master/mcp-server/server.py +595 -0
  409. package/skills/cm-ux-master/output/fila/FilaDashboard.tsx +47 -0
  410. package/skills/cm-ux-master/output/fila/components/badge/component.tsx +35 -0
  411. package/skills/cm-ux-master/output/fila/components/badge/index.ts +1 -0
  412. package/skills/cm-ux-master/output/fila/components/button/component.tsx +53 -0
  413. package/skills/cm-ux-master/output/fila/components/button/index.ts +1 -0
  414. package/skills/cm-ux-master/output/fila/components/card/component.tsx +35 -0
  415. package/skills/cm-ux-master/output/fila/components/card/index.ts +1 -0
  416. package/skills/cm-ux-master/output/fila/components/input/component.tsx +41 -0
  417. package/skills/cm-ux-master/output/fila/components/input/index.ts +1 -0
  418. package/skills/cm-ux-master/output/fila/design-system.css +151 -0
  419. package/skills/cm-ux-master/output/fila/design-system.html +1596 -0
  420. package/skills/cm-ux-master/output/fila/design-system.json +168 -0
  421. package/skills/cm-ux-master/output/fila/figma-tokens.json +523 -0
  422. package/skills/cm-ux-master/output/fila/harvest-v4-raw.json +406 -0
  423. package/skills/cm-ux-master/output/fila/semi-theme-override.css +95 -0
  424. package/skills/cm-ux-master/output/haravan/HaravanDashboard.tsx +103 -0
  425. package/skills/cm-ux-master/output/haravan/design-system-v3-live.html +2716 -0
  426. package/skills/cm-ux-master/output/haravan/design-system-v3.html +1770 -0
  427. package/skills/cm-ux-master/output/haravan/design-system.html +914 -0
  428. package/skills/cm-ux-master/output/haravan/figma-tokens.json +84 -0
  429. package/skills/cm-ux-master/output/haravan/haravan-harvest.json +33 -0
  430. package/skills/cm-ux-master/output/haravan/harvest-v3-raw.json +167 -0
  431. package/skills/cm-ux-master/output/haravan/semi-theme-override.css +39 -0
  432. package/skills/cm-ux-master/references/audit-template.md +257 -0
  433. package/skills/cm-ux-master/references/cultural-ux.md +346 -0
  434. package/skills/cm-ux-master/references/dark-patterns.md +362 -0
  435. package/skills/cm-ux-master/references/heuristic-conflicts.md +296 -0
  436. package/skills/cm-ux-master/references/krug-principles.md +289 -0
  437. package/skills/cm-ux-master/references/nielsen-heuristics.md +360 -0
  438. package/skills/cm-ux-master/references/wcag-checklist.md +306 -0
  439. package/skills/cm-ux-master/scripts/component_generator.py +631 -0
  440. package/skills/cm-ux-master/scripts/core.py +305 -0
  441. package/skills/cm-ux-master/scripts/demo_validation.py +452 -0
  442. package/skills/cm-ux-master/scripts/design_doc_generator.py +1325 -0
  443. package/skills/cm-ux-master/scripts/design_system.py +1141 -0
  444. package/skills/cm-ux-master/scripts/design_system_indexer.py +889 -0
  445. package/skills/cm-ux-master/scripts/extract_i18n.py +251 -0
  446. package/skills/cm-ux-master/scripts/extractor.py +1437 -0
  447. package/skills/cm-ux-master/scripts/figma_bridge.py +406 -0
  448. package/skills/cm-ux-master/scripts/generate.py +147 -0
  449. package/skills/cm-ux-master/scripts/harvest_session.py +207 -0
  450. package/skills/cm-ux-master/scripts/harvester.js +240 -0
  451. package/skills/cm-ux-master/scripts/harvester_browser.py +717 -0
  452. package/skills/cm-ux-master/scripts/harvester_cli.py +431 -0
  453. package/skills/cm-ux-master/scripts/harvester_v1.js +275 -0
  454. package/skills/cm-ux-master/scripts/harvester_v3.js +620 -0
  455. package/skills/cm-ux-master/scripts/harvester_v4.js +1003 -0
  456. package/skills/cm-ux-master/scripts/install.py +528 -0
  457. package/skills/cm-ux-master/scripts/license.py +81 -0
  458. package/skills/cm-ux-master/scripts/media/qrpayment.png +0 -0
  459. package/skills/cm-ux-master/scripts/pro_stubs.py +120 -0
  460. package/skills/cm-ux-master/scripts/project_registry.py +217 -0
  461. package/skills/cm-ux-master/scripts/search.py +114 -0
  462. package/skills/cm-ux-master/scripts/semi_mcp_bridge.py +425 -0
  463. package/skills/cm-ux-master/scripts/stitch_integration.py +583 -0
  464. package/skills/cm-ux-master/scripts/test_harvester_v4.py +335 -0
  465. package/skills/cm-ux-master/scripts/token_mapper.py +626 -0
  466. package/skills/cm-ux-master/scripts/validation_engine.py +1571 -0
  467. package/skills/cm-ux-master/scripts/wizard.py +653 -0
  468. package/skills/cm-ux-master/setup.py +93 -0
  469. package/skills/cm-ux-master/templates/base/flutter-widget.dart +69 -0
  470. package/skills/cm-ux-master/templates/base/html-page.html +152 -0
  471. package/skills/cm-ux-master/templates/base/react-component.tsx +47 -0
  472. package/skills/cm-ux-master/templates/base/swiftui-view.swift +62 -0
  473. package/skills/cm-ux-master/templates/quick-start.sh +176 -0
  474. package/skills/cm-ux-master/tests/automation/batch-validate.sh +250 -0
  475. package/skills/cm-ux-master/tests/automation/generate-test-projects.sh +561 -0
  476. package/skills/cm-ux-master/tests/automation/run-all-tests.sh +315 -0
  477. package/skills/cm-ux-master/tests/test_design_doc.py +145 -0
  478. package/skills/cm-ux-master/tests/test_devices.py +74 -0
  479. package/skills/cm-ux-master/tests/test_generator.py +116 -0
  480. package/skills/cm-ux-master/tests/test_harvest_session.py +131 -0
  481. package/skills/cm-ux-master/tests/test_harvester.py +127 -0
  482. package/skills/cm-ux-master/tests/test_harvester_v3.py +324 -0
  483. package/skills/cm-ux-master/tests/test_mcp_server.py +496 -0
  484. package/skills/cm-ux-master/tests/test_new_domains.py +108 -0
  485. package/skills/cm-ux-master/tests/test_new_stacks.py +103 -0
  486. package/skills/cm-ux-master/tests/test_project_registry.py +146 -0
  487. package/skills/cm-ux-master/tests/test_semi_mcp_bridge.py +207 -0
  488. package/skills/cm-ux-master/tests/test_token_mapper.py +247 -0
  489. package/skills/cm-ux-master/tests/test_validation_engine.py +617 -0
  490. package/skills/config.schema.json +397 -0
  491. package/skills/frappe-app-builder.zip +0 -0
  492. package/skills/jobs-to-be-done/SKILL.md +266 -0
  493. package/skills/jobs-to-be-done/references/case-studies.md +154 -0
  494. package/skills/jobs-to-be-done/references/competitive-strategy.md +280 -0
  495. package/skills/jobs-to-be-done/references/diagnostics.md +158 -0
  496. package/skills/jobs-to-be-done/references/innovation-process.md +392 -0
  497. package/skills/jobs-to-be-done/references/organizational-change.md +328 -0
  498. package/skills/marketplace-report-crawler/SKILL.md +176 -0
  499. package/skills/marketplace-report-crawler/config/accounts.json +41 -0
  500. package/skills/marketplace-report-crawler/config/report-types.json +422 -0
  501. package/skills/marketplace-report-crawler/config/sessions.json +3 -0
  502. package/skills/marketplace-report-crawler/scripts/ab-wrapper.sh +102 -0
  503. package/skills/marketplace-report-crawler/scripts/browser-actions/lazada/lazada-actions.js +114 -0
  504. package/skills/marketplace-report-crawler/scripts/browser-actions/shopee/shopee-actions.js +94 -0
  505. package/skills/marketplace-report-crawler/scripts/browser-actions/tiktok/tiktok-actions.js +272 -0
  506. package/skills/marketplace-report-crawler/scripts/crawl-runner.js +281 -0
  507. package/skills/marketplace-report-crawler/scripts/session-check.sh +72 -0
  508. package/skills/marketplace-report-crawler/scripts/session-manager.sh +349 -0
  509. package/skills/marketplace-report-crawler/scripts/setup-folders.sh +83 -0
  510. package/skills/medical-research/SKILL.md +194 -0
  511. package/skills/medical-research/scripts/evidence_checker.py +288 -0
  512. package/skills/mom-test/SKILL.md +267 -0
  513. package/skills/mom-test/references/avoiding-bad-data.md +221 -0
  514. package/skills/mom-test/references/case-studies.md +306 -0
  515. package/skills/mom-test/references/commitment-advancement.md +219 -0
  516. package/skills/mom-test/references/finding-conversations.md +251 -0
  517. package/skills/mom-test/references/processing-learning.md +256 -0
  518. package/skills/mom-test/references/question-patterns.md +198 -0
  519. package/skills/pandasai-analytics/SKILL.md +251 -0
  520. package/skills/release-it/SKILL.md +235 -0
  521. package/skills/release-it/references/anti-patterns.md +279 -0
  522. package/skills/release-it/references/capacity-planning.md +285 -0
  523. package/skills/release-it/references/chaos-engineering.md +325 -0
  524. package/skills/release-it/references/deployment-strategies.md +331 -0
  525. package/skills/release-it/references/observability.md +301 -0
  526. package/skills/release-it/references/stability-patterns.md +355 -0
  527. package/skills/scripts/sync-ide-skills.sh +61 -0
  528. package/skills/skill-creator-ultra/.agents/workflows/skill-audit.md +37 -0
  529. package/skills/skill-creator-ultra/.agents/workflows/skill-compare.md +34 -0
  530. package/skills/skill-creator-ultra/.agents/workflows/skill-export.md +51 -0
  531. package/skills/skill-creator-ultra/.agents/workflows/skill-generate.md +39 -0
  532. package/skills/skill-creator-ultra/.agents/workflows/skill-scaffold.md +52 -0
  533. package/skills/skill-creator-ultra/.agents/workflows/skill-simulate.md +25 -0
  534. package/skills/skill-creator-ultra/.agents/workflows/skill-stats.md +31 -0
  535. package/skills/skill-creator-ultra/.agents/workflows/skill-validate.md +25 -0
  536. package/skills/skill-creator-ultra/README.md +1242 -0
  537. package/skills/skill-creator-ultra/SKILL.md +388 -0
  538. package/skills/skill-creator-ultra/agents/analyzer.md +274 -0
  539. package/skills/skill-creator-ultra/agents/comparator.md +202 -0
  540. package/skills/skill-creator-ultra/agents/grader.md +223 -0
  541. package/skills/skill-creator-ultra/assets/eval_review.html +146 -0
  542. package/skills/skill-creator-ultra/eval-viewer/generate_review.py +471 -0
  543. package/skills/skill-creator-ultra/eval-viewer/viewer.html +1325 -0
  544. package/skills/skill-creator-ultra/examples/example_anthropic_frontend.md +109 -0
  545. package/skills/skill-creator-ultra/examples/example_anthropic_pdf.md +116 -0
  546. package/skills/skill-creator-ultra/examples/example_api_docs.md +189 -0
  547. package/skills/skill-creator-ultra/examples/example_db_migration.md +253 -0
  548. package/skills/skill-creator-ultra/examples/example_git_commit.md +111 -0
  549. package/skills/skill-creator-ultra/install.ps1 +289 -0
  550. package/skills/skill-creator-ultra/install.sh +313 -0
  551. package/skills/skill-creator-ultra/phases/phase1_interview.md +202 -0
  552. package/skills/skill-creator-ultra/phases/phase2_extract.md +55 -0
  553. package/skills/skill-creator-ultra/phases/phase3_detect.md +57 -0
  554. package/skills/skill-creator-ultra/phases/phase4_generate.md +543 -0
  555. package/skills/skill-creator-ultra/phases/phase5_test.md +319 -0
  556. package/skills/skill-creator-ultra/phases/phase6_eval.md +301 -0
  557. package/skills/skill-creator-ultra/phases/phase7_iterate.md +103 -0
  558. package/skills/skill-creator-ultra/phases/phase8_optimize.md +113 -0
  559. package/skills/skill-creator-ultra/resources/advanced_patterns.md +499 -0
  560. package/skills/skill-creator-ultra/resources/anti_patterns.md +376 -0
  561. package/skills/skill-creator-ultra/resources/blueprints.md +498 -0
  562. package/skills/skill-creator-ultra/resources/checklist.md +243 -0
  563. package/skills/skill-creator-ultra/resources/composition_cookbook.md +291 -0
  564. package/skills/skill-creator-ultra/resources/description_optimization.md +90 -0
  565. package/skills/skill-creator-ultra/resources/eval_guide.md +133 -0
  566. package/skills/skill-creator-ultra/resources/industry_questions.md +189 -0
  567. package/skills/skill-creator-ultra/resources/interview_questions.md +200 -0
  568. package/skills/skill-creator-ultra/resources/pattern_detection.md +200 -0
  569. package/skills/skill-creator-ultra/resources/prompt_engineering.md +531 -0
  570. package/skills/skill-creator-ultra/resources/schemas.md +430 -0
  571. package/skills/skill-creator-ultra/resources/script_integration.md +593 -0
  572. package/skills/skill-creator-ultra/resources/scripts_guide.md +339 -0
  573. package/skills/skill-creator-ultra/resources/skill_template.md +124 -0
  574. package/skills/skill-creator-ultra/resources/skill_writing_guide.md +634 -0
  575. package/skills/skill-creator-ultra/resources/versioning_guide.md +193 -0
  576. package/skills/skill-creator-ultra/scripts/ci_eval.py +200 -0
  577. package/skills/skill-creator-ultra/scripts/package_skill.py +165 -0
  578. package/skills/skill-creator-ultra/scripts/simulate_skill.py +398 -0
  579. package/skills/skill-creator-ultra/scripts/skill_audit.py +611 -0
  580. package/skills/skill-creator-ultra/scripts/skill_compare.py +265 -0
  581. package/skills/skill-creator-ultra/scripts/skill_export.py +334 -0
  582. package/skills/skill-creator-ultra/scripts/skill_scaffold.py +403 -0
  583. package/skills/skill-creator-ultra/scripts/skill_stats.py +339 -0
  584. package/skills/skill-creator-ultra/scripts/validate_skill.py +411 -0
  585. package/skills/tailwind-mastery/SKILL.md +229 -0
  586. package/skills/vercel-react-best-practices/AGENTS.md +3373 -0
  587. package/skills/vercel-react-best-practices/README.md +123 -0
  588. package/skills/vercel-react-best-practices/SKILL.md +143 -0
  589. package/skills/vercel-react-best-practices/rules/_sections.md +46 -0
  590. package/skills/vercel-react-best-practices/rules/_template.md +28 -0
  591. package/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  592. package/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
  593. package/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
  594. package/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  595. package/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  596. package/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
  597. package/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  598. package/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  599. package/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  600. package/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  601. package/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  602. package/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  603. package/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  604. package/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  605. package/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
  606. package/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
  607. package/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  608. package/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
  609. package/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  610. package/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  611. package/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  612. package/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  613. package/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  614. package/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
  615. package/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  616. package/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  617. package/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  618. package/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  619. package/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  620. package/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  621. package/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  622. package/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  623. package/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  624. package/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  625. package/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  626. package/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  627. package/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  628. package/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
  629. package/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
  630. package/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  631. package/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  632. package/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  633. package/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  634. package/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  635. package/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  636. package/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  637. package/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  638. package/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  639. package/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  640. package/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  641. package/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
  642. package/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  643. package/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
  644. package/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  645. package/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
  646. package/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  647. package/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  648. package/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
  649. package/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  650. package/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
  651. package/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
  652. package/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +142 -0
  653. package/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
  654. package/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  655. package/skills/web-design-guidelines/SKILL.md +39 -0
  656. package/skills/cro-methodology/SKILL.md +0 -98
  657. /package/skills/{cro-methodology โ†’ cm-cro-methodology}/references/COPYWRITING.md +0 -0
  658. /package/skills/{cro-methodology โ†’ cm-cro-methodology}/references/OBJECTIONS.md +0 -0
  659. /package/skills/{cro-methodology โ†’ cm-cro-methodology}/references/PERSUASION.md +0 -0
  660. /package/skills/{cro-methodology โ†’ cm-cro-methodology}/references/RESEARCH.md +0 -0
  661. /package/skills/{cro-methodology โ†’ cm-cro-methodology}/references/funnel-analysis.md +0 -0
  662. /package/skills/{cro-methodology โ†’ cm-cro-methodology}/references/testing-methodology.md +0 -0
@@ -0,0 +1,1270 @@
1
+ /* CodyMaster Mission Control v4 โ€” Multi-Project, History, Deploy, Changelog, Auto-Sync */
2
+
3
+ (function () {
4
+ 'use strict';
5
+
6
+ // โ”€โ”€ Theme Management โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
7
+ const THEME_KEY = 'cm-theme';
8
+ const darkMQ = window.matchMedia('(prefers-color-scheme: dark)');
9
+
10
+ function getEffectiveTheme() {
11
+ const saved = localStorage.getItem(THEME_KEY);
12
+ if (saved === 'light' || saved === 'dark') return saved;
13
+ return 'dark'; // New premium UI is dark by default
14
+ }
15
+
16
+ function applyTheme(theme) {
17
+ document.documentElement.setAttribute('data-theme', theme);
18
+ const sunIcon = document.getElementById('theme-icon-sun');
19
+ const moonIcon = document.getElementById('theme-icon-moon');
20
+ if (sunIcon && moonIcon) {
21
+ sunIcon.style.display = theme === 'dark' ? 'block' : 'none';
22
+ moonIcon.style.display = theme === 'dark' ? 'none' : 'block';
23
+ }
24
+ }
25
+
26
+ // Apply immediately to avoid flash
27
+ applyTheme(getEffectiveTheme());
28
+
29
+ // Listen for OS preference changes (only when no manual override)
30
+ darkMQ.addEventListener('change', () => {
31
+ if (!localStorage.getItem(THEME_KEY)) {
32
+ applyTheme(getEffectiveTheme());
33
+ }
34
+ });
35
+ const API = '/api';
36
+ const AGENT_COLORS = {
37
+ 'antigravity': '#3fb950', 'claude-code': '#bc8cff', 'cursor': '#58a6ff',
38
+ 'gemini-cli': '#d29922', 'windsurf': '#f97316', 'cline': '#a1887f',
39
+ 'copilot': '#8b949e', 'manual': '#e6edf3',
40
+ };
41
+ const AGENT_LABELS = {
42
+ 'antigravity': 'Antigravity', 'claude-code': 'Claude Code', 'cursor': 'Cursor',
43
+ 'gemini-cli': 'Gemini CLI', 'windsurf': 'Windsurf', 'cline': 'Cline',
44
+ 'copilot': 'Copilot', 'manual': 'Manual',
45
+ };
46
+ const ACTIVITY_ICONS = {
47
+ 'task_created': 'โœจ', 'task_moved': 'โ†”๏ธ', 'task_done': 'โœ…', 'task_deleted': '๐Ÿ—‘๏ธ', 'task_updated': 'โœ๏ธ',
48
+ 'task_dispatched': '๐Ÿš€', 'task_transitioned': '๐Ÿ”€',
49
+ 'project_created': '๐Ÿ“ฆ', 'project_deleted': '๐Ÿ—‘๏ธ',
50
+ 'deploy_staging': '๐ŸŸก', 'deploy_production': '๐Ÿš€', 'deploy_failed': 'โŒ', 'rollback': 'โช',
51
+ 'git_push': '๐Ÿ“ค', 'changelog_added': '๐Ÿ“',
52
+ 'learning_deleted': '๐Ÿงน', 'decision_deleted': '๐Ÿงน',
53
+ };
54
+
55
+ // โ”€โ”€ Valid Transition Map โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
56
+ const VALID_TRANSITIONS = {
57
+ 'backlog': ['in-progress'],
58
+ 'in-progress': ['review', 'done', 'backlog'],
59
+ 'review': ['done', 'in-progress'],
60
+ 'done': ['backlog'],
61
+ };
62
+
63
+ const TRANSITION_LABELS = {
64
+ 'in-progress': { label: 'โ–ถ Start', icon: 'โ–ถ' },
65
+ 'review': { label: 'โ†’ Review', icon: '๐Ÿ”' },
66
+ 'done': { label: 'โœ“ Done', icon: 'โœ…' },
67
+ 'backlog': { label: 'โ† Backlog', icon: '๐Ÿ“‹' },
68
+ };
69
+
70
+ // โ”€โ”€ State โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
71
+ let projects = [], tasks = [], activities = [], deployments = [], changelog = [];
72
+ let selectedProjectId = null;
73
+ let draggedTaskId = null;
74
+ let currentTab = 'kanban';
75
+
76
+ // โ”€โ”€ Auto-Refresh State โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
77
+ const AUTO_REFRESH_KEY = 'cm-auto-refresh';
78
+ const AUTO_REFRESH_INTERVAL = 15000; // 15 seconds
79
+ let autoRefreshEnabled = localStorage.getItem(AUTO_REFRESH_KEY) !== 'false'; // default ON
80
+ let autoRefreshTimer = null;
81
+ let lastSyncTime = Date.now();
82
+ let isModalOpen = false;
83
+ let isDragging = false;
84
+ let syncTickTimer = null;
85
+
86
+ // โ”€โ”€ DOM Refs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
87
+ const columns = {
88
+ backlog: document.getElementById('list-backlog'),
89
+ 'in-progress': document.getElementById('list-in-progress'),
90
+ review: document.getElementById('list-review'),
91
+ done: document.getElementById('list-done'),
92
+ };
93
+
94
+ const sidebar = document.getElementById('sidebar');
95
+ const projectListEl = document.getElementById('project-list');
96
+ const agentListEl = document.getElementById('agent-list');
97
+ const headerProjectName = document.getElementById('header-project-name');
98
+ const taskStats = document.getElementById('task-stats');
99
+
100
+ const modalOverlay = document.getElementById('modal-overlay');
101
+ const modalTitle = document.getElementById('modal-title');
102
+ const taskForm = document.getElementById('task-form');
103
+ const formId = document.getElementById('form-id');
104
+ const formTitle = document.getElementById('form-title');
105
+ const formDescription = document.getElementById('form-description');
106
+ const formPriority = document.getElementById('form-priority');
107
+ const formColumn = document.getElementById('form-column');
108
+ const formAgent = document.getElementById('form-agent');
109
+ const formSkill = document.getElementById('form-skill');
110
+ const btnSubmit = document.getElementById('btn-submit');
111
+
112
+
113
+ const deployModalOverlay = document.getElementById('deploy-modal-overlay');
114
+ const deployForm = document.getElementById('deploy-form');
115
+ const changelogModalOverlay = document.getElementById('changelog-modal-overlay');
116
+ const changelogForm = document.getElementById('changelog-form');
117
+
118
+ const deleteOverlay = document.getElementById('delete-overlay');
119
+ const deleteTaskName = document.getElementById('delete-task-name');
120
+ const deleteConfirm = document.getElementById('delete-confirm');
121
+
122
+ const dispatchOverlay = document.getElementById('dispatch-overlay');
123
+ const dispatchClose = document.getElementById('dispatch-close');
124
+ const dispatchPrompt = document.getElementById('dispatch-prompt');
125
+ const dispatchCommand = document.getElementById('dispatch-command');
126
+ const copyPromptBtn = document.getElementById('copy-prompt');
127
+ const copyCommandBtn = document.getElementById('copy-command');
128
+ const dispatchDoneBtn = document.getElementById('dispatch-done-btn');
129
+
130
+ const toastContainer = document.getElementById('toast-container');
131
+ const refreshBtn = document.getElementById('btn-refresh');
132
+ const autoRefreshBtn = document.getElementById('btn-auto-refresh');
133
+ const syncDot = document.getElementById('sync-dot');
134
+ const syncLabel = document.getElementById('sync-label');
135
+ const syncStatus = document.getElementById('sync-status');
136
+
137
+ // โ”€โ”€ API Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
138
+ async function fetchJSON(url, opts) {
139
+ const res = await fetch(url, opts);
140
+ if (res.status === 204) return null;
141
+ if (!res.ok) { const e = await res.json().catch(() => ({})); throw new Error(e.error || 'Request failed'); }
142
+ return res.json();
143
+ }
144
+
145
+ // โ”€โ”€ Data Loading โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
146
+ async function loadAll() {
147
+ const pq = selectedProjectId ? 'projectId=' + selectedProjectId : '';
148
+ const aq = [pq, 'limit=100'].filter(Boolean).join('&');
149
+ const qs = pq ? '?' + pq : '';
150
+ const [p, t, a, d, c] = await Promise.all([
151
+ fetchJSON(`${API}/projects`),
152
+ fetchJSON(`${API}/tasks${qs}`),
153
+ fetchJSON(`${API}/activities?${aq}`),
154
+ fetchJSON(`${API}/deployments${qs}`),
155
+ fetchJSON(`${API}/changelog${qs}`),
156
+ ]);
157
+ projects = p || []; tasks = t || [];
158
+ activities = a || []; deployments = d || []; changelog = c || [];
159
+ }
160
+
161
+ async function refreshData(silent = false) {
162
+ refreshBtn.classList.add('refreshing');
163
+ updateSyncStatus('syncing');
164
+ try {
165
+ await loadAll();
166
+ renderSidebar();
167
+ renderCurrentTab();
168
+ lastSyncTime = Date.now();
169
+ updateSyncStatus('synced');
170
+ if (!silent) showToast('info', 'Refreshed');
171
+ } catch (err) {
172
+ updateSyncStatus('error');
173
+ if (!silent) showToast('error', 'Refresh failed: ' + err.message);
174
+ }
175
+ setTimeout(() => refreshBtn.classList.remove('refreshing'), 600);
176
+ }
177
+
178
+ // โ”€โ”€ Sync Status Indicator โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
179
+ function updateSyncStatus(state) {
180
+ if (!syncDot || !syncLabel) return;
181
+ syncDot.className = 'sync-dot ' + state;
182
+ if (state === 'syncing') {
183
+ syncLabel.textContent = 'Syncingโ€ฆ';
184
+ } else if (state === 'synced') {
185
+ syncLabel.textContent = 'Synced';
186
+ } else if (state === 'error') {
187
+ syncLabel.textContent = 'Error';
188
+ }
189
+ }
190
+
191
+ function updateSyncTimeTick() {
192
+ if (!syncLabel || !syncDot) return;
193
+ if (syncDot.classList.contains('syncing')) return;
194
+ const elapsed = Math.floor((Date.now() - lastSyncTime) / 1000);
195
+ if (elapsed < 5) {
196
+ syncLabel.textContent = 'Synced';
197
+ } else if (elapsed < 60) {
198
+ syncLabel.textContent = `${elapsed}s ago`;
199
+ } else {
200
+ syncLabel.textContent = `${Math.floor(elapsed / 60)}m ago`;
201
+ }
202
+ }
203
+
204
+ // โ”€โ”€ Auto-Refresh Engine โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
205
+ function startAutoRefresh() {
206
+ stopAutoRefresh();
207
+ if (!autoRefreshEnabled) return;
208
+ autoRefreshTimer = setInterval(() => {
209
+ // Skip if modal open or dragging
210
+ if (isModalOpen || isDragging) return;
211
+ refreshData(true); // silent refresh
212
+ }, AUTO_REFRESH_INTERVAL);
213
+ // Update time tick every 5s
214
+ syncTickTimer = setInterval(updateSyncTimeTick, 5000);
215
+ updateAutoRefreshUI();
216
+ }
217
+
218
+ function stopAutoRefresh() {
219
+ if (autoRefreshTimer) { clearInterval(autoRefreshTimer); autoRefreshTimer = null; }
220
+ if (syncTickTimer) { clearInterval(syncTickTimer); syncTickTimer = null; }
221
+ }
222
+
223
+ function toggleAutoRefresh() {
224
+ autoRefreshEnabled = !autoRefreshEnabled;
225
+ localStorage.setItem(AUTO_REFRESH_KEY, autoRefreshEnabled ? 'true' : 'false');
226
+ if (autoRefreshEnabled) {
227
+ startAutoRefresh();
228
+ showToast('info', 'โšก Auto-refresh ON (every 15s)');
229
+ } else {
230
+ stopAutoRefresh();
231
+ showToast('info', 'โธ Auto-refresh OFF');
232
+ }
233
+ updateAutoRefreshUI();
234
+ }
235
+
236
+ function updateAutoRefreshUI() {
237
+ if (!autoRefreshBtn) return;
238
+ autoRefreshBtn.classList.toggle('active', autoRefreshEnabled);
239
+ autoRefreshBtn.title = autoRefreshEnabled ? 'Auto-refresh ON (click to disable)' : 'Auto-refresh OFF (click to enable)';
240
+ if (syncStatus) {
241
+ syncStatus.style.opacity = autoRefreshEnabled ? '1' : '0.4';
242
+ syncStatus.title = autoRefreshEnabled ? 'Auto-refresh active' : 'Auto-refresh paused';
243
+ }
244
+ }
245
+
246
+ // Track modal state for smart pause
247
+ function setModalOpen(open) {
248
+ isModalOpen = open;
249
+ }
250
+
251
+ // โ”€โ”€ Tab Navigation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
252
+ function switchTab(tabName) {
253
+ currentTab = tabName;
254
+ document.querySelectorAll('.tab-btn').forEach(b => b.classList.toggle('active', b.dataset.tab === tabName));
255
+ document.querySelectorAll('.tab-panel').forEach(p => p.classList.toggle('active', p.id === 'panel-' + tabName));
256
+ renderCurrentTab();
257
+ }
258
+
259
+ function renderCurrentTab() {
260
+ switch (currentTab) {
261
+ case 'kanban': renderBoard(); break;
262
+ case 'history': renderHistory(); break;
263
+ case 'deploys': renderDeploys(); break;
264
+ case 'changelog': renderChangelog(); break;
265
+ case 'brain': renderBrain(); break;
266
+ }
267
+ }
268
+
269
+ document.querySelectorAll('.tab-btn').forEach(btn => {
270
+ btn.addEventListener('click', () => switchTab(btn.dataset.tab));
271
+ });
272
+
273
+ // โ”€โ”€ Sidebar Rendering โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
274
+ function renderSidebar() {
275
+ let html = `<div class="project-item project-item-all ${!selectedProjectId ? 'active' : ''}" data-project-id="">
276
+ <span class="project-icon">๐Ÿ“</span><span class="project-name">All Projects</span>
277
+ <span class="project-task-count">${tasks.length || countAllTasks()}</span></div>`;
278
+ projects.forEach(p => {
279
+ html += `<div class="project-item ${selectedProjectId === p.id ? 'active' : ''}" data-project-id="${p.id}">
280
+ <span class="project-icon">๐Ÿ“ฆ</span><span class="project-name" title="${esc(p.path)}">${esc(p.name)}</span>
281
+ <span class="project-task-count">${p.taskCount || 0}</span>
282
+ <button class="project-delete-btn" data-delete-project="${p.id}" title="Delete project">โœ•</button></div>`;
283
+ });
284
+ projectListEl.innerHTML = html;
285
+
286
+ projectListEl.querySelectorAll('.project-item').forEach(el => {
287
+ el.addEventListener('click', async e => {
288
+ if (e.target.closest('.project-delete-btn')) return;
289
+ selectedProjectId = el.dataset.projectId || null;
290
+ await refreshData();
291
+ });
292
+ });
293
+
294
+ projectListEl.querySelectorAll('.project-delete-btn').forEach(btn => {
295
+ btn.addEventListener('click', async e => {
296
+ e.stopPropagation();
297
+ const pid = btn.dataset.deleteProject;
298
+ const proj = projects.find(p => p.id === pid);
299
+ if (!proj || !confirm(`Delete "${proj.name}" and all its tasks?`)) return;
300
+ try {
301
+ await fetchJSON(`${API}/projects/${pid}`, { method: 'DELETE' });
302
+ if (selectedProjectId === pid) selectedProjectId = null;
303
+ await refreshData();
304
+ showToast('success', 'Project deleted');
305
+ } catch (err) { showToast('error', err.message); }
306
+ });
307
+ });
308
+
309
+ // Agents
310
+ const allAgents = {};
311
+ tasks.forEach(t => { if (t.agent) allAgents[t.agent] = (allAgents[t.agent] || 0) + 1; });
312
+ if (Object.keys(allAgents).length === 0) {
313
+ agentListEl.innerHTML = '<div class="agent-empty">No active agents</div>';
314
+ } else {
315
+ agentListEl.innerHTML = Object.entries(allAgents).sort((a, b) => b[1] - a[1]).map(([agent, count]) => {
316
+ const color = AGENT_COLORS[agent] || '#8b949e';
317
+ return `<div class="agent-badge"><span class="agent-dot" style="background:${color}"></span><span>${esc(AGENT_LABELS[agent] || agent)}</span><span class="agent-task-count">${count}</span></div>`;
318
+ }).join('');
319
+ }
320
+
321
+ headerProjectName.textContent = selectedProjectId ? (projects.find(p => p.id === selectedProjectId)?.name || 'Unknown') : 'All Projects';
322
+ }
323
+
324
+ function countAllTasks() { return projects.reduce((s, p) => s + (p.taskCount || 0), 0); }
325
+
326
+ // โ”€โ”€ Board Rendering โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
327
+ function renderBoard() {
328
+ const colNames = ['backlog', 'in-progress', 'review', 'done'];
329
+ const emptyIcons = { backlog: '๐Ÿ“‹', 'in-progress': 'โšก', review: '๐Ÿ”', done: 'โœ…' };
330
+ const emptyTexts = { backlog: 'No tasks in backlog', 'in-progress': 'Nothing in progress', review: 'No tasks to review', done: 'No completed tasks' };
331
+
332
+ colNames.forEach(col => {
333
+ const list = columns[col];
334
+ const colTasks = tasks.filter(t => t.column === col).sort((a, b) => a.order - b.order);
335
+ list.innerHTML = '';
336
+ if (colTasks.length === 0) {
337
+ list.innerHTML = `<div class="empty-state"><span class="empty-state-icon">${emptyIcons[col]}</span><span class="empty-state-text">${emptyTexts[col]}</span></div>`;
338
+ } else {
339
+ colTasks.forEach(task => list.appendChild(createCard(task)));
340
+ }
341
+ const ce = document.querySelector(`[data-count="${col}"]`);
342
+ if (ce) ce.textContent = colTasks.length;
343
+ });
344
+ renderStats();
345
+ renderStuckBanner();
346
+ }
347
+
348
+ function createCard(task) {
349
+ const card = document.createElement('div');
350
+ card.className = 'task-card'; card.dataset.taskId = task.id; card.draggable = true;
351
+ const ac = AGENT_COLORS[task.agent] || '#8b949e';
352
+ const al = AGENT_LABELS[task.agent] || task.agent;
353
+ const priLabels = { low: 'Low', medium: 'Medium', high: 'High', urgent: 'Urgent' };
354
+
355
+ // Stuck indicator
356
+ const elapsed = Date.now() - new Date(task.updatedAt).getTime();
357
+ const isStuck = task.column === 'in-progress' && elapsed > 30 * 60 * 1000;
358
+ if (isStuck) card.classList.add('stuck');
359
+
360
+ // Dispatch status badge
361
+ let dispatchBadge = '';
362
+ if (task.dispatchStatus === 'dispatched') {
363
+ dispatchBadge = '<span class="dispatch-badge dispatched" title="Dispatched to agent">๐Ÿš€ Dispatched</span>';
364
+ } else if (task.dispatchStatus === 'failed') {
365
+ dispatchBadge = `<span class="dispatch-badge failed" title="${esc(task.dispatchError || 'Dispatch failed')}">โŒ Failed</span>`;
366
+ }
367
+
368
+ // Dispatch button (only if agent is assigned and not manual)
369
+ let dispatchBtn = '';
370
+ if (task.agent && task.agent !== 'manual') {
371
+ const isRedispatch = task.dispatchStatus === 'dispatched';
372
+ const dispatchTitle = isRedispatch ? 'Re-dispatch to agent' : 'Dispatch to agent';
373
+ dispatchBtn = `<button class="card-action-btn dispatch" title="${dispatchTitle}" data-id="${task.id}"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M8 1v10M4 8l4 4 4-4M2 14h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></button>`;
374
+ }
375
+
376
+ let meta = '';
377
+ if (task.agent || task.skill || dispatchBadge) {
378
+ meta = '<div class="card-meta">';
379
+ if (task.agent) meta += `<span class="card-agent-badge"><span class="card-agent-dot" style="background:${ac}"></span>${esc(al)}</span>`;
380
+ if (task.skill) meta += `<span class="card-skill-badge">${esc(task.skill)}</span>`;
381
+ if (dispatchBadge) meta += dispatchBadge;
382
+ meta += '</div>';
383
+ }
384
+
385
+ // Quick transition buttons
386
+ const transitions = VALID_TRANSITIONS[task.column] || [];
387
+ let transitionBtns = '';
388
+ if (transitions.length > 0) {
389
+ transitionBtns = '<div class="card-transitions">';
390
+ transitions.forEach(target => {
391
+ const info = TRANSITION_LABELS[target] || { label: target, icon: 'โ†’' };
392
+ const cls = target === 'done' ? 'transition-done' : target === 'backlog' ? 'transition-back' : 'transition-forward';
393
+ transitionBtns += `<button class="transition-btn ${cls}" data-task-id="${task.id}" data-target="${target}" title="Move to ${target}">${info.icon} ${info.label}</button>`;
394
+ });
395
+ transitionBtns += '</div>';
396
+ }
397
+
398
+ card.innerHTML = `<div class="card-top"><span class="card-title">${esc(task.title)}</span>
399
+ <div class="card-actions">
400
+ ${dispatchBtn}
401
+ <button class="card-action-btn edit" title="Edit" data-id="${task.id}"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M11.5 1.5l3 3L5 14H2v-3L11.5 1.5z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
402
+ <button class="card-action-btn delete" title="Delete" data-id="${task.id}"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M2 4h12M5.34 4V2.67a1.34 1.34 0 011.34-1.34h2.66a1.34 1.34 0 011.34 1.34V4m2 0v9.33a1.34 1.34 0 01-1.34 1.34H4.67a1.34 1.34 0 01-1.34-1.34V4h9.34z" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
403
+ </div></div>
404
+ ${task.description ? `<p class="card-description">${esc(task.description)}</p>` : ''}
405
+ ${meta}
406
+ <div class="card-footer"><span class="priority-badge priority-${task.priority}">${priLabels[task.priority] || task.priority}</span><span class="card-time">${formatTimeAgo(task.updatedAt)}</span></div>
407
+ ${transitionBtns}`;
408
+ card.addEventListener('dragstart', handleDragStart);
409
+ card.addEventListener('dragend', handleDragEnd);
410
+ card.querySelector('.edit').addEventListener('click', e => { e.stopPropagation(); openEditModal(task); });
411
+ card.querySelector('.delete').addEventListener('click', e => { e.stopPropagation(); openDeleteModal(task); });
412
+ const dispatchEl = card.querySelector('.dispatch');
413
+ if (dispatchEl) {
414
+ dispatchEl.addEventListener('click', e => { e.stopPropagation(); handleDispatch(task); });
415
+ }
416
+ // Bind transition buttons
417
+ card.querySelectorAll('.transition-btn').forEach(btn => {
418
+ btn.addEventListener('click', e => { e.stopPropagation(); handleTransition(btn.dataset.taskId, btn.dataset.target); });
419
+ });
420
+ return card;
421
+ }
422
+
423
+ function renderStats() {
424
+ const total = tasks.length, done = tasks.filter(t => t.column === 'done').length, ip = tasks.filter(t => t.column === 'in-progress').length;
425
+ taskStats.innerHTML = `<span class="stat"><span class="stat-dot" style="background:var(--col-in-progress)"></span>${ip} active</span>
426
+ <span class="stat"><span class="stat-dot" style="background:var(--col-done)"></span>${done}/${total} done</span>`;
427
+ }
428
+
429
+ // โ”€โ”€ History Rendering โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
430
+ function renderHistory() {
431
+ const container = document.getElementById('timeline');
432
+ const countEl = document.getElementById('activity-count');
433
+ countEl.textContent = `${activities.length} events`;
434
+
435
+ if (activities.length === 0) {
436
+ container.innerHTML = '<div class="timeline-empty">No activity yet. Create tasks, deploy, or add changelog entries to see history.</div>';
437
+ return;
438
+ }
439
+
440
+ container.innerHTML = activities.map(a => {
441
+ const icon = ACTIVITY_ICONS[a.type] || '๐Ÿ“Œ';
442
+ const ac = AGENT_COLORS[a.agent] || '#8b949e';
443
+ const al = AGENT_LABELS[a.agent] || a.agent;
444
+ const agentHtml = a.agent ? `<span class="timeline-agent"><span class="timeline-agent-dot" style="background:${ac}"></span>${esc(al)}</span>` : '';
445
+ const proj = projects.find(p => p.id === a.projectId);
446
+ const projName = proj ? proj.name : '';
447
+
448
+ return `<div class="timeline-item type-${a.type}">
449
+ <span class="timeline-icon">${icon}</span>
450
+ <div class="timeline-content">
451
+ <div class="timeline-message">${esc(a.message)}</div>
452
+ <div class="timeline-meta">
453
+ <span>${formatTimeAgo(a.createdAt)}</span>
454
+ ${agentHtml}
455
+ ${projName ? `<span style="color:var(--text-muted)">๐Ÿ“ฆ ${esc(projName)}</span>` : ''}
456
+ </div>
457
+ </div></div>`;
458
+ }).join('');
459
+ }
460
+
461
+ // โ”€โ”€ Deploys Rendering โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
462
+ function renderDeploys() {
463
+ const container = document.getElementById('deploy-list');
464
+ if (deployments.length === 0) {
465
+ container.innerHTML = '<div class="deploy-empty">No deployments yet. Deploy from CLI with: <code>codymaster deploy staging</code></div>';
466
+ return;
467
+ }
468
+
469
+ container.innerHTML = deployments.map(d => {
470
+ const proj = projects.find(p => p.id === d.projectId);
471
+ const canRollback = d.status === 'success' && !d.rollbackOf;
472
+ return `<div class="deploy-card ${d.rollbackOf ? 'is-rollback' : ''}">
473
+ <span class="deploy-status-dot ${d.status}"></span>
474
+ <div class="deploy-info">
475
+ <div class="deploy-message">${esc(d.message)}</div>
476
+ <div class="deploy-detail">
477
+ <span class="deploy-env-badge ${d.env}">${d.env}</span>
478
+ <span class="deploy-status-badge ${d.status}">${d.status.replace('_', ' ')}</span>
479
+ ${d.commit ? `<span>๐Ÿ”— ${esc(d.commit.substring(0, 7))}</span>` : ''}
480
+ ${d.branch ? `<span>๐ŸŒฟ ${esc(d.branch)}</span>` : ''}
481
+ ${proj ? `<span>๐Ÿ“ฆ ${esc(proj.name)}</span>` : ''}
482
+ <span>${formatTimeAgo(d.startedAt)}</span>
483
+ </div>
484
+ </div>
485
+ <div class="deploy-actions">
486
+ ${canRollback ? `<button class="btn-rollback" data-rollback="${d.id}">โช Rollback</button>` : ''}
487
+ </div></div>`;
488
+ }).join('');
489
+
490
+ container.querySelectorAll('.btn-rollback').forEach(btn => {
491
+ btn.addEventListener('click', async () => {
492
+ const depId = btn.dataset.rollback;
493
+ if (!confirm('Rollback this deployment?')) return;
494
+ try {
495
+ await fetchJSON(`${API}/deployments/${depId}/rollback`, {
496
+ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}),
497
+ });
498
+ await loadAll();
499
+ renderDeploys();
500
+ renderSidebar();
501
+ showToast('success', 'Deployment rolled back');
502
+ } catch (err) { showToast('error', err.message); }
503
+ });
504
+ });
505
+ }
506
+
507
+ // โ”€โ”€ Changelog Rendering โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
508
+ function renderChangelog() {
509
+ const container = document.getElementById('changelog-list');
510
+ if (changelog.length === 0) {
511
+ container.innerHTML = '<div class="changelog-empty">No changelog entries yet. Add one with the button above or CLI: <code>codymaster changelog add</code></div>';
512
+ return;
513
+ }
514
+
515
+ container.innerHTML = changelog.map(c => {
516
+ const changesHtml = c.changes.length > 0 ? `<ul class="changelog-changes">${c.changes.map(ch => `<li>${esc(ch)}</li>`).join('')}</ul>` : '';
517
+ return `<div class="changelog-entry">
518
+ <div class="changelog-version">
519
+ <span class="changelog-version-badge">${esc(c.version)}</span>
520
+ <span class="changelog-title">${esc(c.title)}</span>
521
+ <span class="changelog-date">${formatTimeAgo(c.createdAt)}</span>
522
+ </div>
523
+ ${changesHtml}
524
+ </div>`;
525
+ }).join('');
526
+ }
527
+
528
+ // โ”€โ”€ Drag & Drop โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
529
+ function handleDragStart(e) {
530
+ isDragging = true;
531
+ draggedTaskId = e.currentTarget.dataset.taskId;
532
+ // Store the source column for validation
533
+ const sourceTask = tasks.find(t => t.id === draggedTaskId);
534
+ e.currentTarget.dataset.sourceColumn = sourceTask ? sourceTask.column : '';
535
+ e.currentTarget.classList.add('dragging');
536
+ e.dataTransfer.effectAllowed = 'move';
537
+ e.dataTransfer.setData('text/plain', draggedTaskId);
538
+ e.dataTransfer.setData('source-column', sourceTask ? sourceTask.column : '');
539
+ requestAnimationFrame(() => { e.currentTarget.style.opacity = '0.4'; });
540
+ }
541
+ function handleDragEnd(e) {
542
+ isDragging = false;
543
+ e.currentTarget.classList.remove('dragging'); e.currentTarget.style.opacity = '';
544
+ draggedTaskId = null;
545
+ document.querySelectorAll('.column').forEach(c => c.classList.remove('drag-over', 'drag-blocked'));
546
+ document.querySelectorAll('.drop-placeholder').forEach(el => el.remove());
547
+ }
548
+
549
+ // Allow all valid transitions
550
+ function isDropAllowed(sourceColumn, targetColumn) {
551
+ if (sourceColumn === targetColumn) return true; // Reorder within same column
552
+ const allowed = VALID_TRANSITIONS[sourceColumn] || [];
553
+ return allowed.includes(targetColumn);
554
+ }
555
+
556
+ Object.keys(columns).forEach(colName => {
557
+ const list = columns[colName];
558
+ const column = list.closest('.column');
559
+
560
+ list.addEventListener('dragover', e => {
561
+ e.preventDefault();
562
+ // Check if drop is allowed
563
+ const sourceTask = tasks.find(t => t.id === draggedTaskId);
564
+ const sourceCol = sourceTask ? sourceTask.column : '';
565
+ const allowed = isDropAllowed(sourceCol, colName);
566
+
567
+ if (allowed) {
568
+ e.dataTransfer.dropEffect = 'move';
569
+ column.classList.add('drag-over');
570
+ column.classList.remove('drag-blocked');
571
+ if (!list.querySelector('.drop-placeholder')) { const ph = document.createElement('div'); ph.className = 'drop-placeholder'; list.appendChild(ph); }
572
+ const after = getDragAfterElement(list, e.clientY);
573
+ const ph = list.querySelector('.drop-placeholder');
574
+ if (after) list.insertBefore(ph, after); else list.appendChild(ph);
575
+ } else {
576
+ e.dataTransfer.dropEffect = 'none';
577
+ column.classList.add('drag-blocked');
578
+ column.classList.remove('drag-over');
579
+ }
580
+ });
581
+
582
+ list.addEventListener('dragleave', e => {
583
+ if (!column.contains(e.relatedTarget)) {
584
+ column.classList.remove('drag-over', 'drag-blocked');
585
+ const ph = list.querySelector('.drop-placeholder'); if (ph) ph.remove();
586
+ }
587
+ });
588
+
589
+ list.addEventListener('drop', async e => {
590
+ e.preventDefault(); column.classList.remove('drag-over', 'drag-blocked');
591
+ const ph = list.querySelector('.drop-placeholder');
592
+ // Save taskId locally โ€” handleDragEnd will null draggedTaskId before async completes
593
+ const taskId = draggedTaskId;
594
+ if (!taskId) return;
595
+
596
+ // Validate drop
597
+ const sourceTask = tasks.find(t => t.id === taskId);
598
+ const sourceCol = sourceTask ? sourceTask.column : '';
599
+ if (!isDropAllowed(sourceCol, colName)) {
600
+ if (ph) ph.remove();
601
+ const allowed = (VALID_TRANSITIONS[sourceCol] || []).join(', ');
602
+ showToast('error', `Cannot move from ${sourceCol} โ†’ ${colName}. Allowed: ${allowed}`);
603
+ return;
604
+ }
605
+
606
+ let newOrder = 0;
607
+ if (ph) {
608
+ newOrder = [...list.children].slice(0, [...list.children].indexOf(ph)).filter(el => el.classList.contains('task-card') && el.dataset.taskId !== taskId).length;
609
+ ph.remove();
610
+ }
611
+
612
+ const isMovingToInProgress = sourceCol === 'backlog' && colName === 'in-progress';
613
+ const isCrossColumn = sourceCol !== colName;
614
+
615
+ try {
616
+ if (isCrossColumn) {
617
+ // Use transition API for cross-column moves (validated)
618
+ await fetchJSON(`${API}/tasks/${taskId}/transition`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ column: colName }) });
619
+ } else {
620
+ // Use move API for reorder within same column
621
+ await fetchJSON(`${API}/tasks/${taskId}/move`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ column: colName, order: newOrder }) });
622
+ }
623
+ await loadAll(); renderBoard(); renderSidebar();
624
+
625
+ if (isMovingToInProgress) {
626
+ // Auto-dispatch if task has an agent assigned
627
+ const movedTask = tasks.find(t => t.id === taskId);
628
+ if (movedTask && movedTask.agent && movedTask.agent !== 'manual') {
629
+ showToast('info', 'โšก Starting dispatch...');
630
+ try {
631
+ const forceParam = movedTask.dispatchStatus === 'dispatched' ? '?force=true' : '';
632
+ const res = await fetchJSON(`${API}/tasks/${taskId}/dispatch${forceParam}`, {
633
+ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}),
634
+ });
635
+ await loadAll(); renderBoard(); renderSidebar();
636
+ openDispatchModal(res);
637
+ } catch (dispatchErr) {
638
+ showToast('error', 'Dispatch failed: ' + dispatchErr.message);
639
+ }
640
+ } else if (movedTask && !movedTask.agent) {
641
+ showToast('success', 'Task moved to In Progress (no agent assigned โ€” dispatch skipped)');
642
+ } else {
643
+ showToast('success', 'Task moved to In Progress');
644
+ }
645
+ } else if (isCrossColumn) {
646
+ showToast('success', `Task moved: ${sourceCol} โ†’ ${colName}`);
647
+ } else {
648
+ showToast('success', 'Task reordered');
649
+ }
650
+ } catch (err) { showToast('error', err.message); }
651
+ });
652
+ });
653
+
654
+ function getDragAfterElement(list, y) {
655
+ const cards = [...list.querySelectorAll('.task-card:not(.dragging)')];
656
+ let closest = null, closestOffset = Number.NEGATIVE_INFINITY;
657
+ cards.forEach(card => { const box = card.getBoundingClientRect(); const offset = y - box.top - box.height / 2; if (offset < 0 && offset > closestOffset) { closestOffset = offset; closest = card; } });
658
+ return closest;
659
+ }
660
+
661
+ // โ”€โ”€ Task Modal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
662
+ function openAddModal() {
663
+ modalTitle.textContent = 'New Task'; btnSubmit.textContent = 'Create Task';
664
+ formId.value = ''; taskForm.reset();
665
+ formPriority.value = 'medium'; formColumn.value = 'backlog'; formAgent.value = ''; formSkill.value = '';
666
+ modalOverlay.classList.add('active');
667
+ setModalOpen(true);
668
+ setTimeout(() => formTitle.focus(), 200);
669
+ }
670
+ function openEditModal(task) {
671
+ modalTitle.textContent = 'Edit Task'; btnSubmit.textContent = 'Save Changes';
672
+ formId.value = task.id; formTitle.value = task.title; formDescription.value = task.description;
673
+ formPriority.value = task.priority; formColumn.value = task.column;
674
+ formAgent.value = task.agent || ''; formSkill.value = task.skill || '';
675
+ modalOverlay.classList.add('active');
676
+ setTimeout(() => formTitle.focus(), 200);
677
+ }
678
+ function closeModal() { modalOverlay.classList.remove('active'); setModalOpen(false); }
679
+
680
+ // โ”€โ”€ Project Modal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
681
+
682
+
683
+ // โ”€โ”€ Deploy Modal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
684
+ function openDeployModal() { deployForm.reset(); document.getElementById('deploy-branch').value = 'main'; deployModalOverlay.classList.add('active'); setModalOpen(true); }
685
+ function closeDeployModal() { deployModalOverlay.classList.remove('active'); setModalOpen(false); }
686
+
687
+ // โ”€โ”€ Changelog Modal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
688
+ function openChangelogModal() { changelogForm.reset(); changelogModalOverlay.classList.add('active'); setModalOpen(true); }
689
+ function closeChangelogModal() { changelogModalOverlay.classList.remove('active'); setModalOpen(false); }
690
+
691
+ // โ”€โ”€ Delete Modal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
692
+ let deleteTaskId = null;
693
+ function openDeleteModal(task) { deleteTaskId = task.id; deleteTaskName.textContent = task.title; deleteOverlay.classList.add('active'); }
694
+ function closeDeleteModal() { deleteOverlay.classList.remove('active'); deleteTaskId = null; }
695
+
696
+ // โ”€โ”€ Event Handlers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
697
+ function setupEventListeners() {
698
+ const btnAddTask = document.getElementById('btn-add-task');
699
+ if (btnAddTask) btnAddTask.addEventListener('click', openAddModal);
700
+
701
+ const sidebarRefreshBtn = document.getElementById('btn-sidebar-refresh');
702
+ if (sidebarRefreshBtn) sidebarRefreshBtn.addEventListener('click', () => refreshData(false));
703
+
704
+ const newDeployBtn = document.getElementById('btn-new-deploy');
705
+ if (newDeployBtn) newDeployBtn.addEventListener('click', openDeployModal);
706
+
707
+ const newChangelogBtn = document.getElementById('btn-new-changelog');
708
+ if (newChangelogBtn) newChangelogBtn.addEventListener('click', openChangelogModal);
709
+
710
+ if (refreshBtn) refreshBtn.addEventListener('click', () => refreshData(false));
711
+ if (autoRefreshBtn) autoRefreshBtn.addEventListener('click', toggleAutoRefresh);
712
+
713
+ // Sidebar toggles
714
+ const sbToggleBtn = document.getElementById('sidebar-toggle');
715
+ if (sbToggleBtn) {
716
+ sbToggleBtn.addEventListener('click', () => {
717
+ const sb = document.getElementById('sidebar');
718
+ if (sb) sb.classList.toggle('collapsed');
719
+ });
720
+ }
721
+
722
+ const sbCloseBtn = document.getElementById('sidebar-close');
723
+ if (sbCloseBtn) {
724
+ sbCloseBtn.addEventListener('click', () => {
725
+ const sb = document.getElementById('sidebar');
726
+ if (sb) sb.classList.add('collapsed');
727
+ });
728
+ }
729
+
730
+ // Auto collapse on small screens
731
+ if (window.innerWidth <= 900) {
732
+ document.getElementById('sidebar')?.classList.add('collapsed');
733
+ }
734
+
735
+ // Theme toggle
736
+ const themeBtn = document.getElementById('theme-toggle');
737
+ if (themeBtn) {
738
+ themeBtn.addEventListener('click', () => {
739
+ const current = getEffectiveTheme();
740
+ const next = current === 'dark' ? 'light' : 'dark';
741
+ localStorage.setItem(THEME_KEY, next);
742
+ applyTheme(next);
743
+ });
744
+ }
745
+
746
+ // Close modals
747
+ const modalClose = document.getElementById('modal-close');
748
+ if (modalClose) modalClose.addEventListener('click', closeModal);
749
+
750
+ const cancelBtn = document.getElementById('btn-cancel');
751
+ if (cancelBtn) cancelBtn.addEventListener('click', closeModal);
752
+
753
+ if (modalOverlay) {
754
+ modalOverlay.addEventListener('click', e => { if (e.target === modalOverlay) closeModal(); });
755
+ }
756
+
757
+ const deployClose = document.getElementById('deploy-modal-close');
758
+ if (deployClose) deployClose.addEventListener('click', closeDeployModal);
759
+
760
+ const deployCancel = document.getElementById('deploy-cancel');
761
+ if (deployCancel) deployCancel.addEventListener('click', closeDeployModal);
762
+
763
+ if (deployModalOverlay) {
764
+ deployModalOverlay.addEventListener('click', e => { if (e.target === deployModalOverlay) closeDeployModal(); });
765
+ }
766
+
767
+ const changelogClose = document.getElementById('cl-modal-close') || document.getElementById('changelog-modal-close');
768
+ if (changelogClose) changelogClose.addEventListener('click', closeChangelogModal);
769
+
770
+ const changelogCancel = document.getElementById('cl-cancel') || document.getElementById('changelog-cancel');
771
+ if (changelogCancel) changelogCancel.addEventListener('click', closeChangelogModal);
772
+
773
+ if (changelogModalOverlay) {
774
+ changelogModalOverlay.addEventListener('click', e => { if (e.target === changelogModalOverlay) closeChangelogModal(); });
775
+ }
776
+
777
+ const deleteClose = document.getElementById('delete-close') || document.getElementById('delete-modal-close');
778
+ if (deleteClose) deleteClose.addEventListener('click', closeDeleteModal);
779
+
780
+ const deleteCancel = document.getElementById('delete-cancel');
781
+ if (deleteCancel) deleteCancel.addEventListener('click', closeDeleteModal);
782
+
783
+ if (deleteOverlay) {
784
+ deleteOverlay.addEventListener('click', e => { if (e.target === deleteOverlay) closeDeleteModal(); });
785
+ }
786
+
787
+ if (deleteConfirm) {
788
+ deleteConfirm.addEventListener('click', async () => {
789
+ if (!deleteTaskId) return;
790
+ try {
791
+ await fetchJSON(`${API}/tasks/${deleteTaskId}`, { method: 'DELETE' });
792
+ tasks = tasks.filter(t => t.id !== deleteTaskId);
793
+ renderBoard(); renderSidebar(); closeDeleteModal();
794
+ showToast('success', 'Task deleted');
795
+ } catch (err) { showToast('error', err.message); }
796
+ });
797
+ }
798
+
799
+ // Dispatch
800
+ if (dispatchClose) dispatchClose.addEventListener('click', closeDispatchModal);
801
+ if (dispatchOverlay) {
802
+ dispatchOverlay.addEventListener('click', e => { if (e.target === dispatchOverlay) closeDispatchModal(); });
803
+ }
804
+ if (copyPromptBtn) {
805
+ copyPromptBtn.addEventListener('click', () => {
806
+ navigator.clipboard.writeText(dispatchPrompt.textContent);
807
+ showToast('success', 'Prompt copied');
808
+ });
809
+ }
810
+ if (copyCommandBtn) {
811
+ copyCommandBtn.addEventListener('click', () => {
812
+ navigator.clipboard.writeText(dispatchCommand.textContent);
813
+ showToast('success', 'Command copied');
814
+ });
815
+ }
816
+ if (dispatchDoneBtn) dispatchDoneBtn.addEventListener('click', closeDispatchModal);
817
+
818
+ // Form submission
819
+ const taskFormEl = document.getElementById('task-form');
820
+ if (taskFormEl) {
821
+ taskFormEl.addEventListener('submit', async e => {
822
+ e.preventDefault();
823
+ const title = formTitle.value.trim(); if (!title) return;
824
+ const data = {
825
+ title, description: formDescription.value.trim(),
826
+ priority: formPriority.value, column: formColumn.value,
827
+ agent: formAgent.value, skill: formSkill.value,
828
+ projectId: selectedProjectId || undefined,
829
+ };
830
+ try {
831
+ if (formId.value) {
832
+ await fetchJSON(`${API}/tasks/${formId.value}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) });
833
+ const et = tasks.find(t => t.id === formId.value);
834
+ if (et && et.column !== data.column) {
835
+ await fetchJSON(`${API}/tasks/${formId.value}/move`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ column: data.column, order: 0 }) });
836
+ }
837
+ showToast('success', 'Task updated');
838
+ } else {
839
+ await fetchJSON(`${API}/tasks`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) });
840
+ showToast('success', 'Task created');
841
+ }
842
+ await loadAll(); renderBoard(); renderSidebar(); closeModal();
843
+ } catch (err) { showToast('error', err.message); }
844
+ });
845
+ }
846
+
847
+ const deployFormEl = document.getElementById('deploy-form');
848
+ if (deployFormEl) {
849
+ deployFormEl.addEventListener('submit', async e => {
850
+ e.preventDefault();
851
+ const pid = selectedProjectId || (projects.length > 0 ? projects[0].id : '');
852
+ try {
853
+ await fetchJSON(`${API}/deployments`, {
854
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
855
+ body: JSON.stringify({
856
+ projectId: pid, env: document.getElementById('deploy-env').value,
857
+ message: document.getElementById('deploy-message').value.trim() || `Deploy to ${document.getElementById('deploy-env').value}`,
858
+ commit: document.getElementById('deploy-commit').value.trim(),
859
+ branch: document.getElementById('deploy-branch').value.trim() || 'main',
860
+ }),
861
+ });
862
+ await loadAll(); renderDeploys(); renderSidebar(); closeDeployModal();
863
+ showToast('success', 'Deployment recorded');
864
+ } catch (err) { showToast('error', err.message); }
865
+ });
866
+ }
867
+
868
+ const changelogFormEl = document.getElementById('changelog-form');
869
+ if (changelogFormEl) {
870
+ changelogFormEl.addEventListener('submit', async e => {
871
+ e.preventDefault();
872
+ const version = document.getElementById('cl-version')?.value.trim() || document.getElementById('changelog-version')?.value.trim();
873
+ const title = document.getElementById('cl-title')?.value.trim() || 'Release';
874
+ if (!version) return;
875
+ const changes = document.getElementById('cl-changes')?.value.split('\n').map(l => l.trim()).filter(Boolean) || [];
876
+ const pid = selectedProjectId || (projects.length > 0 ? projects[0].id : '');
877
+ try {
878
+ await fetchJSON(`${API}/changelog`, {
879
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
880
+ body: JSON.stringify({ projectId: pid, version, title, changes }),
881
+ });
882
+ await loadAll(); renderChangelog(); closeChangelogModal();
883
+ showToast('success', 'Changelog entry added');
884
+ } catch (err) { showToast('error', err.message); }
885
+ });
886
+ }
887
+
888
+ // Keyboard shortcuts
889
+ document.addEventListener('keydown', e => {
890
+ if (e.key === 'Escape') { closeModal(); closeDeployModal(); closeChangelogModal(); closeDeleteModal(); }
891
+ if ((e.ctrlKey || e.metaKey) && e.key === 'n') { e.preventDefault(); openAddModal(); }
892
+ if ((e.ctrlKey || e.metaKey) && e.key === 'r' && !e.shiftKey) { e.preventDefault(); refreshData(); }
893
+ if ((e.ctrlKey || e.metaKey) && e.shiftKey && (e.key === 't' || e.key === 'T')) {
894
+ e.preventDefault();
895
+ const current = getEffectiveTheme();
896
+ const next = current === 'dark' ? 'light' : 'dark';
897
+ localStorage.setItem(THEME_KEY, next);
898
+ applyTheme(next);
899
+ }
900
+ });
901
+
902
+ // Header Dropdown Toggle
903
+ const btnMoreMenu = document.getElementById('btn-more-menu');
904
+ const headerActions = document.getElementById('header-actions');
905
+ if (btnMoreMenu && headerActions) {
906
+ btnMoreMenu.addEventListener('click', (e) => {
907
+ e.stopPropagation();
908
+ headerActions.classList.toggle('active');
909
+ });
910
+ document.addEventListener('click', (e) => {
911
+ if (!headerActions.contains(e.target) && !btnMoreMenu.contains(e.target)) {
912
+ headerActions.classList.remove('active');
913
+ }
914
+ });
915
+ }
916
+ }
917
+
918
+ // โ”€โ”€ Toast System โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
919
+ function showToast(type, message) {
920
+ const icons = { success: 'โœ…', error: 'โŒ', info: 'โ„น๏ธ' };
921
+ const toast = document.createElement('div');
922
+ toast.className = `toast toast-${type}`;
923
+ toast.innerHTML = `<span class="toast-icon">${icons[type] || '๐Ÿ“Œ'}</span><span>${esc(message)}</span>`;
924
+ toastContainer.appendChild(toast);
925
+ setTimeout(() => { toast.classList.add('toast-out'); toast.addEventListener('animationend', () => toast.remove()); }, 2800);
926
+ }
927
+
928
+ // โ”€โ”€ Utilities โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
929
+ function esc(str) { const d = document.createElement('div'); d.textContent = str; return d.innerHTML; }
930
+ function formatTimeAgo(dateStr) {
931
+ const ms = Date.now() - new Date(dateStr).getTime();
932
+ const m = Math.floor(ms / 60000), h = Math.floor(ms / 3600000), d = Math.floor(ms / 86400000);
933
+ if (m < 1) return 'just now'; if (m < 60) return `${m}m ago`; if (h < 24) return `${h}h ago`;
934
+ if (d < 7) return `${d}d ago`;
935
+ return new Date(dateStr).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
936
+ }
937
+
938
+ // โ”€โ”€ Quick Transition Handler โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
939
+ async function handleTransition(taskId, targetColumn) {
940
+ try {
941
+ await fetchJSON(`${API}/tasks/${taskId}/transition`, {
942
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
943
+ body: JSON.stringify({ column: targetColumn }),
944
+ });
945
+ await loadAll(); renderBoard(); renderSidebar();
946
+
947
+ // Auto-dispatch when moving to in-progress
948
+ if (targetColumn === 'in-progress') {
949
+ const movedTask = tasks.find(t => t.id === taskId);
950
+ if (movedTask && movedTask.agent && movedTask.agent !== 'manual') {
951
+ showToast('info', 'โšก Starting dispatch...');
952
+ try {
953
+ const forceParam = movedTask.dispatchStatus === 'dispatched' ? '?force=true' : '';
954
+ const res = await fetchJSON(`${API}/tasks/${taskId}/dispatch${forceParam}`, {
955
+ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}),
956
+ });
957
+ await loadAll(); renderBoard(); renderSidebar();
958
+ openDispatchModal(res);
959
+ } catch (dispatchErr) {
960
+ showToast('error', 'Dispatch failed: ' + dispatchErr.message);
961
+ }
962
+ return;
963
+ }
964
+ }
965
+ showToast('success', `Task moved to ${targetColumn}`);
966
+ } catch (err) { showToast('error', err.message); }
967
+ }
968
+
969
+ // โ”€โ”€ Stuck Tasks Banner โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
970
+ async function renderStuckBanner() {
971
+ let bannerEl = document.getElementById('stuck-banner');
972
+ try {
973
+ const pq = selectedProjectId ? `?projectId=${selectedProjectId}` : '';
974
+ const stuckTasks = await fetchJSON(`${API}/tasks/stuck${pq}`);
975
+ if (!stuckTasks || stuckTasks.length === 0) {
976
+ if (bannerEl) bannerEl.remove();
977
+ return;
978
+ }
979
+
980
+ if (!bannerEl) {
981
+ bannerEl = document.createElement('div');
982
+ bannerEl.id = 'stuck-banner';
983
+ const kanbanPanel = document.getElementById('panel-kanban');
984
+ if (kanbanPanel) kanbanPanel.insertBefore(bannerEl, kanbanPanel.querySelector('.board'));
985
+ }
986
+
987
+ const taskNames = stuckTasks.slice(0, 3).map(t => `"${esc(t.title)}"`).join(', ');
988
+ const extra = stuckTasks.length > 3 ? ` +${stuckTasks.length - 3} more` : '';
989
+ bannerEl.innerHTML = `<div class="stuck-banner-content">
990
+ <span class="stuck-banner-icon">โš ๏ธ</span>
991
+ <span class="stuck-banner-text"><strong>${stuckTasks.length} task${stuckTasks.length > 1 ? 's' : ''} stuck</strong> in progress: ${taskNames}${extra}</span>
992
+ <div class="stuck-banner-actions">
993
+ <button class="stuck-btn review" data-action="review">โ†’ Move to Review</button>
994
+ <button class="stuck-btn done" data-action="done">โœ“ Mark Done</button>
995
+ <button class="stuck-btn backlog" data-action="backlog">โ† Back to Backlog</button>
996
+ </div>
997
+ </div>`;
998
+
999
+ bannerEl.querySelectorAll('.stuck-btn').forEach(btn => {
1000
+ btn.addEventListener('click', async () => {
1001
+ const targetCol = btn.dataset.action;
1002
+ const ids = stuckTasks.map(t => t.id);
1003
+ try {
1004
+ await fetchJSON(`${API}/tasks/bulk-transition`, {
1005
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
1006
+ body: JSON.stringify({ taskIds: ids, column: targetCol, reason: 'Bulk action from stuck banner' }),
1007
+ });
1008
+ await loadAll(); renderBoard(); renderSidebar();
1009
+ showToast('success', `${ids.length} tasks moved to ${targetCol}`);
1010
+ } catch (err) { showToast('error', err.message); }
1011
+ });
1012
+ });
1013
+ } catch { /* silently fail */ }
1014
+ }
1015
+
1016
+ // โ”€โ”€ Dispatch Handler โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
1017
+ async function handleDispatch(task) {
1018
+ const isRedispatch = task.dispatchStatus === 'dispatched';
1019
+ if (isRedispatch) {
1020
+ if (!confirm(`Task "${task.title}" was already dispatched. Re-dispatch?`)) return;
1021
+ }
1022
+ const forceParam = isRedispatch ? '?force=true' : '';
1023
+ try {
1024
+ const result = await fetchJSON(`${API}/tasks/${task.id}/dispatch${forceParam}`, {
1025
+ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}),
1026
+ });
1027
+ await loadAll(); renderBoard(); renderSidebar();
1028
+ openDispatchModal(result);
1029
+ } catch (err) {
1030
+ showToast('error', 'Dispatch failed: ' + err.message);
1031
+ }
1032
+ }
1033
+
1034
+ // โ”€โ”€ Dispatch Modal Logic โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
1035
+ function openDispatchModal(result) {
1036
+ if (!result || !result.prompt) return;
1037
+ dispatchPrompt.textContent = result.prompt;
1038
+ dispatchCommand.textContent = result.cliCommand;
1039
+ dispatchOverlay.classList.add('active');
1040
+ }
1041
+
1042
+ function closeDispatchModal() {
1043
+ dispatchOverlay.classList.remove('active');
1044
+ }
1045
+
1046
+ // Event listeners for Dispatch Modal
1047
+ if (dispatchClose) dispatchClose.addEventListener('click', closeDispatchModal);
1048
+ if (dispatchDoneBtn) dispatchDoneBtn.addEventListener('click', closeDispatchModal);
1049
+
1050
+ if (copyPromptBtn) copyPromptBtn.addEventListener('click', () => {
1051
+ navigator.clipboard.writeText(dispatchPrompt.textContent)
1052
+ .then(() => showToast('success', 'Prompt copied to clipboard!'))
1053
+ .catch(err => showToast('error', 'Failed to copy: ' + err));
1054
+ });
1055
+
1056
+ if (copyCommandBtn) copyCommandBtn.addEventListener('click', () => {
1057
+ navigator.clipboard.writeText(dispatchCommand.textContent)
1058
+ .then(() => showToast('success', 'CLI command copied!'))
1059
+ .catch(err => showToast('error', 'Failed to copy: ' + err));
1060
+ });
1061
+
1062
+ // โ”€โ”€ Brain Tab Rendering โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
1063
+ let brainData = { continuity: null, learnings: [], decisions: [] };
1064
+ let brainSearchQuery = '';
1065
+
1066
+ async function loadBrainData() {
1067
+ if (!selectedProjectId) {
1068
+ // Load from first project with .cm/
1069
+ for (const p of projects) {
1070
+ try {
1071
+ const status = await fetchJSON(`${API}/continuity/${p.id}`);
1072
+ if (status && status.initialized) {
1073
+ const [learnings, decisions] = await Promise.all([
1074
+ fetchJSON(`${API}/learnings/${p.id}`),
1075
+ fetchJSON(`${API}/decisions/${p.id}`),
1076
+ ]);
1077
+ brainData = { continuity: status, learnings: learnings || [], decisions: decisions || [], projectId: p.id, projectName: p.name };
1078
+ return;
1079
+ }
1080
+ } catch { /* skip */ }
1081
+ }
1082
+ brainData = { continuity: null, learnings: [], decisions: [], projectId: null, projectName: null };
1083
+ return;
1084
+ }
1085
+ try {
1086
+ const [status, learnings, decisions] = await Promise.all([
1087
+ fetchJSON(`${API}/continuity/${selectedProjectId}`),
1088
+ fetchJSON(`${API}/learnings/${selectedProjectId}`),
1089
+ fetchJSON(`${API}/decisions/${selectedProjectId}`),
1090
+ ]);
1091
+ const proj = projects.find(p => p.id === selectedProjectId);
1092
+ brainData = { continuity: status, learnings: learnings || [], decisions: decisions || [], projectId: selectedProjectId, projectName: proj ? proj.name : 'Unknown' };
1093
+ } catch {
1094
+ brainData = { continuity: null, learnings: [], decisions: [], projectId: selectedProjectId, projectName: null };
1095
+ }
1096
+ }
1097
+
1098
+ async function renderBrain() {
1099
+ await loadBrainData();
1100
+ const { continuity, learnings, decisions, projectId, projectName } = brainData;
1101
+ const statsEl = document.getElementById('brain-stats');
1102
+ const contEl = document.getElementById('brain-continuity-content');
1103
+ const learnEl = document.getElementById('brain-learnings-list');
1104
+ const decEl = document.getElementById('brain-decisions-list');
1105
+ const searchEl = document.getElementById('brain-search');
1106
+
1107
+ if (!continuity || !continuity.initialized) {
1108
+ statsEl.innerHTML = '';
1109
+ contEl.innerHTML = `<div class="brain-empty"><div class="brain-empty-icon">๐Ÿง </div><div>Working memory not initialized for this project.</div>${projectId ? `<button class="brain-init-btn" data-init-project="${projectId}">โšก Initialize Memory</button>` : '<div style="margin-top:8px;font-size:12px">Select a project from the sidebar first.</div>'}</div>`;
1110
+ learnEl.innerHTML = '';
1111
+ decEl.innerHTML = '';
1112
+ // Wire init button
1113
+ const initBtn = contEl.querySelector('.brain-init-btn');
1114
+ if (initBtn) {
1115
+ initBtn.addEventListener('click', async () => {
1116
+ try {
1117
+ await fetch(`${API}/continuity/${projectId}/init`, { method: 'POST' });
1118
+ showToast('success', 'โœ… Memory initialized!');
1119
+ renderBrain();
1120
+ } catch { showToast('error', 'Failed to initialize memory'); }
1121
+ });
1122
+ }
1123
+ return;
1124
+ }
1125
+
1126
+ // Stats cards
1127
+ const phase = continuity.phase || 'idle';
1128
+ const phaseClass = 'phase-' + phase;
1129
+ statsEl.innerHTML = `
1130
+ <div class="brain-stat-card stat-learnings">
1131
+ <div class="brain-stat-label">Learnings</div>
1132
+ <div class="brain-stat-value">${learnings.length}</div>
1133
+ <div class="brain-stat-detail">Mistakes captured</div>
1134
+ </div>
1135
+ <div class="brain-stat-card stat-decisions">
1136
+ <div class="brain-stat-label">Decisions</div>
1137
+ <div class="brain-stat-value">${decisions.length}</div>
1138
+ <div class="brain-stat-detail">Architecture choices</div>
1139
+ </div>
1140
+ <div class="brain-stat-card stat-phase">
1141
+ <div class="brain-stat-label">Phase</div>
1142
+ <div class="brain-stat-value ${phaseClass}" style="font-size:20px">${phase.charAt(0).toUpperCase() + phase.slice(1)}</div>
1143
+ <div class="brain-stat-detail">${projectName || 'No project'}</div>
1144
+ </div>
1145
+ <div class="brain-stat-card stat-updated">
1146
+ <div class="brain-stat-label">Last Updated</div>
1147
+ <div class="brain-stat-value" style="font-size:16px">${continuity.lastUpdated ? formatTimeAgo(continuity.lastUpdated) : 'Never'}</div>
1148
+ <div class="brain-stat-detail">Iteration ${continuity.iteration || 0}</div>
1149
+ </div>`;
1150
+
1151
+ // Continuity status
1152
+ contEl.innerHTML = `<div class="brain-continuity-grid">
1153
+ <div class="brain-continuity-item"><div class="brain-continuity-label">Project</div><div class="brain-continuity-value">${esc(continuity.project || 'โ€”')}</div></div>
1154
+ <div class="brain-continuity-item"><div class="brain-continuity-label">Active Goal</div><div class="brain-continuity-value">${esc(continuity.activeGoal || 'No active goal')}</div></div>
1155
+ <div class="brain-continuity-item"><div class="brain-continuity-label">Current Task</div><div class="brain-continuity-value">${esc(continuity.currentTask || 'No active task')}</div></div>
1156
+ <div class="brain-continuity-item"><div class="brain-continuity-label">Blockers</div><div class="brain-continuity-value">${continuity.blockerCount > 0 ? `๐Ÿšง ${continuity.blockerCount} blocker(s)` : 'โœ… No blockers'}</div></div>
1157
+ <div class="brain-continuity-item"><div class="brain-continuity-label">Completed</div><div class="brain-continuity-value">${continuity.completedCount || 0} items</div></div>
1158
+ <div class="brain-continuity-item"><div class="brain-continuity-label">Iteration</div><div class="brain-continuity-value">#${continuity.iteration || 0}</div></div>
1159
+ </div>`;
1160
+
1161
+ // Search filter
1162
+ const query = brainSearchQuery.toLowerCase();
1163
+ const filteredLearnings = query
1164
+ ? learnings.filter(l => (l.whatFailed || '').toLowerCase().includes(query) || (l.whyFailed || '').toLowerCase().includes(query) || (l.howToPrevent || '').toLowerCase().includes(query))
1165
+ : learnings;
1166
+
1167
+ // Learnings
1168
+ if (filteredLearnings.length === 0) {
1169
+ learnEl.innerHTML = `<div class="brain-empty"><div class="brain-empty-icon">๐ŸŽ‰</div>${query ? 'No learnings match your search.' : 'No learnings captured yet. Great start!'}</div>`;
1170
+ } else {
1171
+ learnEl.innerHTML = filteredLearnings.slice().reverse().map(l => `
1172
+ <div class="brain-learning-card" data-learning-id="${l.id}">
1173
+ <div class="brain-learning-header">
1174
+ <div class="brain-learning-what">${esc(l.whatFailed)}</div>
1175
+ <button class="brain-delete-btn" data-delete-learning="${l.id}" title="Delete">๐Ÿ—‘๏ธ</button>
1176
+ </div>
1177
+ <div class="brain-learning-body">
1178
+ <div class="brain-learning-why">${esc(l.whyFailed || '')}</div>
1179
+ <div class="brain-learning-fix">${esc(l.howToPrevent || '')}</div>
1180
+ <div class="brain-learning-meta">
1181
+ <span>${l.agent || 'unknown agent'}</span>
1182
+ <span>${l.timestamp ? formatTimeAgo(l.timestamp) : ''}</span>
1183
+ ${l.module ? `<span>๐Ÿ“ฆ ${esc(l.module)}</span>` : ''}
1184
+ </div>
1185
+ </div>
1186
+ </div>`).join('');
1187
+ }
1188
+
1189
+ // Decisions
1190
+ if (decisions.length === 0) {
1191
+ decEl.innerHTML = '<div class="brain-empty"><div class="brain-empty-icon">๐Ÿ“‹</div>No decisions recorded yet.</div>';
1192
+ } else {
1193
+ decEl.innerHTML = decisions.slice().reverse().map(d => `
1194
+ <div class="brain-decision-card" data-decision-id="${d.id}">
1195
+ <div class="brain-decision-header">
1196
+ <div class="brain-decision-what">${esc(d.decision)}</div>
1197
+ <button class="brain-delete-btn" data-delete-decision="${d.id}" title="Delete">๐Ÿ—‘๏ธ</button>
1198
+ </div>
1199
+ <div class="brain-decision-rationale">${esc(d.rationale || '')}</div>
1200
+ <div class="brain-decision-meta">
1201
+ <span>${d.agent || 'unknown'}</span>
1202
+ <span>${d.timestamp ? formatTimeAgo(d.timestamp) : ''}</span>
1203
+ </div>
1204
+ </div>`).join('');
1205
+ }
1206
+
1207
+ // Wire learning card expand/collapse
1208
+ learnEl.querySelectorAll('.brain-learning-card').forEach(card => {
1209
+ card.addEventListener('click', e => {
1210
+ if (e.target.closest('.brain-delete-btn')) return;
1211
+ card.classList.toggle('expanded');
1212
+ });
1213
+ });
1214
+
1215
+ // Wire delete learning buttons
1216
+ learnEl.querySelectorAll('[data-delete-learning]').forEach(btn => {
1217
+ btn.addEventListener('click', async e => {
1218
+ e.stopPropagation();
1219
+ const lid = btn.dataset.deleteLearning;
1220
+ if (!confirm('Delete this learning?')) return;
1221
+ try {
1222
+ await fetch(`${API}/learnings/${brainData.projectId}/${lid}`, { method: 'DELETE' });
1223
+ showToast('success', '๐Ÿงน Learning deleted');
1224
+ renderBrain();
1225
+ } catch { showToast('error', 'Failed to delete learning'); }
1226
+ });
1227
+ });
1228
+
1229
+ // Wire delete decision buttons
1230
+ decEl.querySelectorAll('[data-delete-decision]').forEach(btn => {
1231
+ btn.addEventListener('click', async e => {
1232
+ e.stopPropagation();
1233
+ const did = btn.dataset.deleteDecision;
1234
+ if (!confirm('Delete this decision?')) return;
1235
+ try {
1236
+ await fetch(`${API}/decisions/${brainData.projectId}/${did}`, { method: 'DELETE' });
1237
+ showToast('success', '๐Ÿงน Decision deleted');
1238
+ renderBrain();
1239
+ } catch { showToast('error', 'Failed to delete decision'); }
1240
+ });
1241
+ });
1242
+
1243
+ // Wire search
1244
+ if (searchEl && !searchEl._brainWired) {
1245
+ searchEl._brainWired = true;
1246
+ searchEl.addEventListener('input', e => {
1247
+ brainSearchQuery = e.target.value;
1248
+ renderBrain();
1249
+ });
1250
+ }
1251
+ }
1252
+
1253
+ // โ”€โ”€ Init โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
1254
+ async function init() {
1255
+ try {
1256
+ await loadAll();
1257
+ renderSidebar();
1258
+ renderCurrentTab();
1259
+ setupEventListeners(); // Initialize listeners after first render
1260
+ lastSyncTime = Date.now();
1261
+ updateSyncStatus('synced');
1262
+ updateAutoRefreshUI();
1263
+ startAutoRefresh();
1264
+ } catch (err) {
1265
+ showToast('error', 'Failed to load: ' + err.message);
1266
+ updateSyncStatus('error');
1267
+ }
1268
+ }
1269
+ init();
1270
+ })();