devskill 2.0.7 → 2.0.8

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 (1016) hide show
  1. package/meta.ts +4 -0
  2. package/package.json +1 -1
  3. package/skills/add-educational-comments/LICENSE.md +21 -0
  4. package/skills/add-educational-comments/SKILL.md +128 -0
  5. package/skills/add-educational-comments/SYNC.md +5 -0
  6. package/skills/agent-governance/LICENSE.md +21 -0
  7. package/skills/agent-governance/SKILL.md +569 -0
  8. package/skills/agent-governance/SYNC.md +5 -0
  9. package/skills/agentic-eval/LICENSE.md +21 -0
  10. package/skills/agentic-eval/SKILL.md +189 -0
  11. package/skills/agentic-eval/SYNC.md +5 -0
  12. package/skills/ai-prompt-engineering-safety-review/LICENSE.md +21 -0
  13. package/skills/ai-prompt-engineering-safety-review/SKILL.md +230 -0
  14. package/skills/ai-prompt-engineering-safety-review/SYNC.md +5 -0
  15. package/skills/appinsights-instrumentation/LICENSE.md +21 -0
  16. package/skills/appinsights-instrumentation/LICENSE.txt +21 -0
  17. package/skills/appinsights-instrumentation/SKILL.md +48 -0
  18. package/skills/appinsights-instrumentation/SYNC.md +5 -0
  19. package/skills/appinsights-instrumentation/examples/appinsights.bicep +30 -0
  20. package/skills/appinsights-instrumentation/references/ASPNETCORE.md +29 -0
  21. package/skills/appinsights-instrumentation/references/AUTO.md +13 -0
  22. package/skills/appinsights-instrumentation/references/NODEJS.md +28 -0
  23. package/skills/appinsights-instrumentation/references/PYTHON.md +48 -0
  24. package/skills/appinsights-instrumentation/scripts/appinsights.ps1 +20 -0
  25. package/skills/apple-appstore-reviewer/LICENSE.md +21 -0
  26. package/skills/apple-appstore-reviewer/SKILL.md +305 -0
  27. package/skills/apple-appstore-reviewer/SYNC.md +5 -0
  28. package/skills/arch-linux-triage/LICENSE.md +21 -0
  29. package/skills/arch-linux-triage/SKILL.md +31 -0
  30. package/skills/arch-linux-triage/SYNC.md +5 -0
  31. package/skills/architecture-blueprint-generator/LICENSE.md +21 -0
  32. package/skills/architecture-blueprint-generator/SKILL.md +322 -0
  33. package/skills/architecture-blueprint-generator/SYNC.md +5 -0
  34. package/skills/aspire/LICENSE.md +21 -0
  35. package/skills/aspire/SKILL.md +231 -0
  36. package/skills/aspire/SYNC.md +5 -0
  37. package/skills/aspire/references/architecture.md +341 -0
  38. package/skills/aspire/references/cli-reference.md +307 -0
  39. package/skills/aspire/references/dashboard.md +226 -0
  40. package/skills/aspire/references/deployment.md +237 -0
  41. package/skills/aspire/references/integrations-catalog.md +68 -0
  42. package/skills/aspire/references/mcp-server.md +195 -0
  43. package/skills/aspire/references/polyglot-apis.md +296 -0
  44. package/skills/aspire/references/testing.md +281 -0
  45. package/skills/aspire/references/troubleshooting.md +194 -0
  46. package/skills/aspnet-minimal-api-openapi/LICENSE.md +21 -0
  47. package/skills/aspnet-minimal-api-openapi/SKILL.md +41 -0
  48. package/skills/aspnet-minimal-api-openapi/SYNC.md +5 -0
  49. package/skills/automate-this/LICENSE.md +21 -0
  50. package/skills/automate-this/SKILL.md +244 -0
  51. package/skills/automate-this/SYNC.md +5 -0
  52. package/skills/autoresearch/LICENSE.md +21 -0
  53. package/skills/autoresearch/SKILL.md +275 -0
  54. package/skills/autoresearch/SYNC.md +5 -0
  55. package/skills/aws-cdk-python-setup/LICENSE.md +21 -0
  56. package/skills/aws-cdk-python-setup/SKILL.md +111 -0
  57. package/skills/aws-cdk-python-setup/SYNC.md +5 -0
  58. package/skills/az-cost-optimize/LICENSE.md +21 -0
  59. package/skills/az-cost-optimize/SKILL.md +305 -0
  60. package/skills/az-cost-optimize/SYNC.md +5 -0
  61. package/skills/azure-deployment-preflight/LICENSE.md +21 -0
  62. package/skills/azure-deployment-preflight/SKILL.md +216 -0
  63. package/skills/azure-deployment-preflight/SYNC.md +5 -0
  64. package/skills/azure-deployment-preflight/references/ERROR-HANDLING.md +392 -0
  65. package/skills/azure-deployment-preflight/references/REPORT-TEMPLATE.md +352 -0
  66. package/skills/azure-deployment-preflight/references/VALIDATION-COMMANDS.md +379 -0
  67. package/skills/azure-devops-cli/LICENSE.md +21 -0
  68. package/skills/azure-devops-cli/SKILL.md +94 -0
  69. package/skills/azure-devops-cli/SYNC.md +5 -0
  70. package/skills/azure-devops-cli/references/advanced-usage.md +197 -0
  71. package/skills/azure-devops-cli/references/boards-and-iterations.md +258 -0
  72. package/skills/azure-devops-cli/references/org-and-security.md +469 -0
  73. package/skills/azure-devops-cli/references/pipelines-and-builds.md +245 -0
  74. package/skills/azure-devops-cli/references/repos-and-prs.md +333 -0
  75. package/skills/azure-devops-cli/references/variables-and-agents.md +212 -0
  76. package/skills/azure-devops-cli/references/workflows-and-patterns.md +668 -0
  77. package/skills/azure-pricing/LICENSE.md +21 -0
  78. package/skills/azure-pricing/SKILL.md +189 -0
  79. package/skills/azure-pricing/SYNC.md +5 -0
  80. package/skills/azure-pricing/references/COPILOT-STUDIO-RATES.md +135 -0
  81. package/skills/azure-pricing/references/COST-ESTIMATOR.md +142 -0
  82. package/skills/azure-pricing/references/REGIONS.md +84 -0
  83. package/skills/azure-pricing/references/SERVICE-NAMES.md +106 -0
  84. package/skills/azure-resource-health-diagnose/LICENSE.md +21 -0
  85. package/skills/azure-resource-health-diagnose/SKILL.md +290 -0
  86. package/skills/azure-resource-health-diagnose/SYNC.md +5 -0
  87. package/skills/azure-resource-visualizer/LICENSE.md +21 -0
  88. package/skills/azure-resource-visualizer/LICENSE.txt +21 -0
  89. package/skills/azure-resource-visualizer/SKILL.md +233 -0
  90. package/skills/azure-resource-visualizer/SYNC.md +5 -0
  91. package/skills/azure-resource-visualizer/assets/template-architecture.md +41 -0
  92. package/skills/azure-role-selector/LICENSE.md +21 -0
  93. package/skills/azure-role-selector/LICENSE.txt +21 -0
  94. package/skills/azure-role-selector/SKILL.md +6 -0
  95. package/skills/azure-role-selector/SYNC.md +5 -0
  96. package/skills/azure-static-web-apps/LICENSE.md +21 -0
  97. package/skills/azure-static-web-apps/SKILL.md +315 -0
  98. package/skills/azure-static-web-apps/SYNC.md +5 -0
  99. package/skills/bigquery-pipeline-audit/LICENSE.md +21 -0
  100. package/skills/bigquery-pipeline-audit/SKILL.md +129 -0
  101. package/skills/bigquery-pipeline-audit/SYNC.md +5 -0
  102. package/skills/boost-prompt/LICENSE.md +21 -0
  103. package/skills/boost-prompt/SKILL.md +25 -0
  104. package/skills/boost-prompt/SYNC.md +5 -0
  105. package/skills/breakdown-epic-arch/LICENSE.md +21 -0
  106. package/skills/breakdown-epic-arch/SKILL.md +66 -0
  107. package/skills/breakdown-epic-arch/SYNC.md +5 -0
  108. package/skills/breakdown-epic-pm/LICENSE.md +21 -0
  109. package/skills/breakdown-epic-pm/SKILL.md +58 -0
  110. package/skills/breakdown-epic-pm/SYNC.md +5 -0
  111. package/skills/breakdown-feature-implementation/LICENSE.md +21 -0
  112. package/skills/breakdown-feature-implementation/SKILL.md +128 -0
  113. package/skills/breakdown-feature-implementation/SYNC.md +5 -0
  114. package/skills/breakdown-feature-prd/LICENSE.md +21 -0
  115. package/skills/breakdown-feature-prd/SKILL.md +61 -0
  116. package/skills/breakdown-feature-prd/SYNC.md +5 -0
  117. package/skills/breakdown-plan/LICENSE.md +21 -0
  118. package/skills/breakdown-plan/SKILL.md +509 -0
  119. package/skills/breakdown-plan/SYNC.md +5 -0
  120. package/skills/breakdown-test/LICENSE.md +21 -0
  121. package/skills/breakdown-test/SKILL.md +365 -0
  122. package/skills/breakdown-test/SYNC.md +5 -0
  123. package/skills/centos-linux-triage/LICENSE.md +21 -0
  124. package/skills/centos-linux-triage/SKILL.md +31 -0
  125. package/skills/centos-linux-triage/SYNC.md +5 -0
  126. package/skills/chrome-devtools/LICENSE.md +21 -0
  127. package/skills/chrome-devtools/SKILL.md +97 -0
  128. package/skills/chrome-devtools/SYNC.md +5 -0
  129. package/skills/cli-mastery/LICENSE.md +21 -0
  130. package/skills/cli-mastery/SKILL.md +43 -0
  131. package/skills/cli-mastery/SYNC.md +5 -0
  132. package/skills/cli-mastery/references/final-exam.md +24 -0
  133. package/skills/cli-mastery/references/module-1-slash-commands.md +88 -0
  134. package/skills/cli-mastery/references/module-2-keyboard-shortcuts.md +38 -0
  135. package/skills/cli-mastery/references/module-3-modes.md +33 -0
  136. package/skills/cli-mastery/references/module-4-agents.md +42 -0
  137. package/skills/cli-mastery/references/module-5-skills.md +33 -0
  138. package/skills/cli-mastery/references/module-6-mcp.md +50 -0
  139. package/skills/cli-mastery/references/module-7-advanced.md +38 -0
  140. package/skills/cli-mastery/references/module-8-configuration.md +34 -0
  141. package/skills/cli-mastery/references/scenarios.md +44 -0
  142. package/skills/cloud-design-patterns/LICENSE.md +21 -0
  143. package/skills/cloud-design-patterns/SKILL.md +62 -0
  144. package/skills/cloud-design-patterns/SYNC.md +5 -0
  145. package/skills/cloud-design-patterns/references/architecture-design.md +127 -0
  146. package/skills/cloud-design-patterns/references/azure-service-mappings.md +13 -0
  147. package/skills/cloud-design-patterns/references/best-practices.md +34 -0
  148. package/skills/cloud-design-patterns/references/deployment-operational.md +91 -0
  149. package/skills/cloud-design-patterns/references/event-driven.md +21 -0
  150. package/skills/cloud-design-patterns/references/messaging-integration.md +127 -0
  151. package/skills/cloud-design-patterns/references/performance.md +180 -0
  152. package/skills/cloud-design-patterns/references/reliability-resilience.md +156 -0
  153. package/skills/cloud-design-patterns/references/security.md +55 -0
  154. package/skills/code-exemplars-blueprint-generator/LICENSE.md +21 -0
  155. package/skills/code-exemplars-blueprint-generator/SKILL.md +126 -0
  156. package/skills/code-exemplars-blueprint-generator/SYNC.md +5 -0
  157. package/skills/codeql/LICENSE.md +21 -0
  158. package/skills/codeql/SKILL.md +405 -0
  159. package/skills/codeql/SYNC.md +5 -0
  160. package/skills/codeql/references/alert-management.md +170 -0
  161. package/skills/codeql/references/cli-commands.md +283 -0
  162. package/skills/codeql/references/compiled-languages.md +284 -0
  163. package/skills/codeql/references/sarif-output.md +265 -0
  164. package/skills/codeql/references/troubleshooting.md +259 -0
  165. package/skills/codeql/references/workflow-configuration.md +398 -0
  166. package/skills/comment-code-generate-a-tutorial/LICENSE.md +21 -0
  167. package/skills/comment-code-generate-a-tutorial/SKILL.md +26 -0
  168. package/skills/comment-code-generate-a-tutorial/SYNC.md +5 -0
  169. package/skills/containerize-aspnet-framework/LICENSE.md +21 -0
  170. package/skills/containerize-aspnet-framework/SKILL.md +454 -0
  171. package/skills/containerize-aspnet-framework/SYNC.md +5 -0
  172. package/skills/containerize-aspnetcore/LICENSE.md +21 -0
  173. package/skills/containerize-aspnetcore/SKILL.md +392 -0
  174. package/skills/containerize-aspnetcore/SYNC.md +5 -0
  175. package/skills/context-map/LICENSE.md +21 -0
  176. package/skills/context-map/SKILL.md +52 -0
  177. package/skills/context-map/SYNC.md +5 -0
  178. package/skills/conventional-commit/LICENSE.md +21 -0
  179. package/skills/conventional-commit/SKILL.md +72 -0
  180. package/skills/conventional-commit/SYNC.md +5 -0
  181. package/skills/convert-plaintext-to-md/LICENSE.md +21 -0
  182. package/skills/convert-plaintext-to-md/SKILL.md +362 -0
  183. package/skills/convert-plaintext-to-md/SYNC.md +5 -0
  184. package/skills/copilot-cli-quickstart/LICENSE.md +21 -0
  185. package/skills/copilot-cli-quickstart/SKILL.md +774 -0
  186. package/skills/copilot-cli-quickstart/SYNC.md +5 -0
  187. package/skills/copilot-instructions-blueprint-generator/LICENSE.md +21 -0
  188. package/skills/copilot-instructions-blueprint-generator/SKILL.md +294 -0
  189. package/skills/copilot-instructions-blueprint-generator/SYNC.md +5 -0
  190. package/skills/copilot-sdk/LICENSE.md +21 -0
  191. package/skills/copilot-sdk/SKILL.md +914 -0
  192. package/skills/copilot-sdk/SYNC.md +5 -0
  193. package/skills/copilot-spaces/LICENSE.md +21 -0
  194. package/skills/copilot-spaces/SKILL.md +205 -0
  195. package/skills/copilot-spaces/SYNC.md +5 -0
  196. package/skills/copilot-usage-metrics/LICENSE.md +21 -0
  197. package/skills/copilot-usage-metrics/SKILL.md +52 -0
  198. package/skills/copilot-usage-metrics/SYNC.md +5 -0
  199. package/skills/copilot-usage-metrics/get-enterprise-metrics.sh +22 -0
  200. package/skills/copilot-usage-metrics/get-enterprise-user-metrics.sh +22 -0
  201. package/skills/copilot-usage-metrics/get-org-metrics.sh +22 -0
  202. package/skills/copilot-usage-metrics/get-org-user-metrics.sh +22 -0
  203. package/skills/cosmosdb-datamodeling/LICENSE.md +21 -0
  204. package/skills/cosmosdb-datamodeling/SKILL.md +1045 -0
  205. package/skills/cosmosdb-datamodeling/SYNC.md +5 -0
  206. package/skills/create-agentsmd/LICENSE.md +21 -0
  207. package/skills/create-agentsmd/SKILL.md +249 -0
  208. package/skills/create-agentsmd/SYNC.md +5 -0
  209. package/skills/create-architectural-decision-record/LICENSE.md +21 -0
  210. package/skills/create-architectural-decision-record/SKILL.md +97 -0
  211. package/skills/create-architectural-decision-record/SYNC.md +5 -0
  212. package/skills/create-github-action-workflow-specification/LICENSE.md +21 -0
  213. package/skills/create-github-action-workflow-specification/SKILL.md +276 -0
  214. package/skills/create-github-action-workflow-specification/SYNC.md +5 -0
  215. package/skills/create-github-issue-feature-from-specification/LICENSE.md +21 -0
  216. package/skills/create-github-issue-feature-from-specification/SKILL.md +28 -0
  217. package/skills/create-github-issue-feature-from-specification/SYNC.md +5 -0
  218. package/skills/create-github-issues-feature-from-implementation-plan/LICENSE.md +21 -0
  219. package/skills/create-github-issues-feature-from-implementation-plan/SKILL.md +28 -0
  220. package/skills/create-github-issues-feature-from-implementation-plan/SYNC.md +5 -0
  221. package/skills/create-github-issues-for-unmet-specification-requirements/LICENSE.md +21 -0
  222. package/skills/create-github-issues-for-unmet-specification-requirements/SKILL.md +35 -0
  223. package/skills/create-github-issues-for-unmet-specification-requirements/SYNC.md +5 -0
  224. package/skills/create-github-pull-request-from-specification/LICENSE.md +21 -0
  225. package/skills/create-github-pull-request-from-specification/SKILL.md +24 -0
  226. package/skills/create-github-pull-request-from-specification/SYNC.md +5 -0
  227. package/skills/create-implementation-plan/LICENSE.md +21 -0
  228. package/skills/create-implementation-plan/SKILL.md +157 -0
  229. package/skills/create-implementation-plan/SYNC.md +5 -0
  230. package/skills/create-llms/LICENSE.md +21 -0
  231. package/skills/create-llms/SKILL.md +210 -0
  232. package/skills/create-llms/SYNC.md +5 -0
  233. package/skills/create-readme/LICENSE.md +21 -0
  234. package/skills/create-readme/SKILL.md +21 -0
  235. package/skills/create-readme/SYNC.md +5 -0
  236. package/skills/create-specification/LICENSE.md +21 -0
  237. package/skills/create-specification/SKILL.md +127 -0
  238. package/skills/create-specification/SYNC.md +5 -0
  239. package/skills/create-spring-boot-java-project/LICENSE.md +21 -0
  240. package/skills/create-spring-boot-java-project/SKILL.md +163 -0
  241. package/skills/create-spring-boot-java-project/SYNC.md +5 -0
  242. package/skills/create-spring-boot-kotlin-project/LICENSE.md +21 -0
  243. package/skills/create-spring-boot-kotlin-project/SKILL.md +147 -0
  244. package/skills/create-spring-boot-kotlin-project/SYNC.md +5 -0
  245. package/skills/create-technical-spike/LICENSE.md +21 -0
  246. package/skills/create-technical-spike/SKILL.md +230 -0
  247. package/skills/create-technical-spike/SYNC.md +5 -0
  248. package/skills/create-tldr-page/LICENSE.md +21 -0
  249. package/skills/create-tldr-page/SKILL.md +210 -0
  250. package/skills/create-tldr-page/SYNC.md +5 -0
  251. package/skills/creating-oracle-to-postgres-master-migration-plan/LICENSE.md +21 -0
  252. package/skills/creating-oracle-to-postgres-master-migration-plan/SKILL.md +83 -0
  253. package/skills/creating-oracle-to-postgres-master-migration-plan/SYNC.md +5 -0
  254. package/skills/creating-oracle-to-postgres-migration-bug-report/LICENSE.md +21 -0
  255. package/skills/creating-oracle-to-postgres-migration-bug-report/SKILL.md +43 -0
  256. package/skills/creating-oracle-to-postgres-migration-bug-report/SYNC.md +5 -0
  257. package/skills/creating-oracle-to-postgres-migration-bug-report/references/BUG-REPORT-TEMPLATE.md +79 -0
  258. package/skills/creating-oracle-to-postgres-migration-integration-tests/LICENSE.md +21 -0
  259. package/skills/creating-oracle-to-postgres-migration-integration-tests/SKILL.md +60 -0
  260. package/skills/creating-oracle-to-postgres-migration-integration-tests/SYNC.md +5 -0
  261. package/skills/csharp-async/LICENSE.md +21 -0
  262. package/skills/csharp-async/SKILL.md +49 -0
  263. package/skills/csharp-async/SYNC.md +5 -0
  264. package/skills/csharp-docs/LICENSE.md +21 -0
  265. package/skills/csharp-docs/SKILL.md +62 -0
  266. package/skills/csharp-docs/SYNC.md +5 -0
  267. package/skills/csharp-mcp-server-generator/LICENSE.md +21 -0
  268. package/skills/csharp-mcp-server-generator/SKILL.md +59 -0
  269. package/skills/csharp-mcp-server-generator/SYNC.md +5 -0
  270. package/skills/csharp-mstest/LICENSE.md +21 -0
  271. package/skills/csharp-mstest/SKILL.md +478 -0
  272. package/skills/csharp-mstest/SYNC.md +5 -0
  273. package/skills/csharp-nunit/LICENSE.md +21 -0
  274. package/skills/csharp-nunit/SKILL.md +71 -0
  275. package/skills/csharp-nunit/SYNC.md +5 -0
  276. package/skills/csharp-tunit/LICENSE.md +21 -0
  277. package/skills/csharp-tunit/SKILL.md +100 -0
  278. package/skills/csharp-tunit/SYNC.md +5 -0
  279. package/skills/csharp-xunit/LICENSE.md +21 -0
  280. package/skills/csharp-xunit/SKILL.md +68 -0
  281. package/skills/csharp-xunit/SYNC.md +5 -0
  282. package/skills/datanalysis-credit-risk/LICENSE.md +21 -0
  283. package/skills/datanalysis-credit-risk/SKILL.md +113 -0
  284. package/skills/datanalysis-credit-risk/SYNC.md +5 -0
  285. package/skills/datanalysis-credit-risk/references/analysis.py +1223 -0
  286. package/skills/datanalysis-credit-risk/references/func.py +228 -0
  287. package/skills/datanalysis-credit-risk/scripts/example.py +391 -0
  288. package/skills/dataverse-python-advanced-patterns/LICENSE.md +21 -0
  289. package/skills/dataverse-python-advanced-patterns/SKILL.md +17 -0
  290. package/skills/dataverse-python-advanced-patterns/SYNC.md +5 -0
  291. package/skills/dataverse-python-production-code/LICENSE.md +21 -0
  292. package/skills/dataverse-python-production-code/SKILL.md +116 -0
  293. package/skills/dataverse-python-production-code/SYNC.md +5 -0
  294. package/skills/dataverse-python-quickstart/LICENSE.md +21 -0
  295. package/skills/dataverse-python-quickstart/SKILL.md +14 -0
  296. package/skills/dataverse-python-quickstart/SYNC.md +5 -0
  297. package/skills/dataverse-python-usecase-builder/LICENSE.md +21 -0
  298. package/skills/dataverse-python-usecase-builder/SKILL.md +246 -0
  299. package/skills/dataverse-python-usecase-builder/SYNC.md +5 -0
  300. package/skills/debian-linux-triage/LICENSE.md +21 -0
  301. package/skills/debian-linux-triage/SKILL.md +31 -0
  302. package/skills/debian-linux-triage/SYNC.md +5 -0
  303. package/skills/declarative-agents/LICENSE.md +21 -0
  304. package/skills/declarative-agents/SKILL.md +94 -0
  305. package/skills/declarative-agents/SYNC.md +5 -0
  306. package/skills/dependabot/LICENSE.md +21 -0
  307. package/skills/dependabot/SKILL.md +422 -0
  308. package/skills/dependabot/SYNC.md +5 -0
  309. package/skills/dependabot/references/dependabot-yml-reference.md +374 -0
  310. package/skills/dependabot/references/example-configs.md +409 -0
  311. package/skills/dependabot/references/pr-commands.md +91 -0
  312. package/skills/devops-rollout-plan/LICENSE.md +21 -0
  313. package/skills/devops-rollout-plan/SKILL.md +117 -0
  314. package/skills/devops-rollout-plan/SYNC.md +5 -0
  315. package/skills/documentation-writer/LICENSE.md +21 -0
  316. package/skills/documentation-writer/SKILL.md +45 -0
  317. package/skills/documentation-writer/SYNC.md +5 -0
  318. package/skills/dotnet-best-practices/LICENSE.md +21 -0
  319. package/skills/dotnet-best-practices/SKILL.md +85 -0
  320. package/skills/dotnet-best-practices/SYNC.md +5 -0
  321. package/skills/dotnet-design-pattern-review/LICENSE.md +21 -0
  322. package/skills/dotnet-design-pattern-review/SKILL.md +42 -0
  323. package/skills/dotnet-design-pattern-review/SYNC.md +5 -0
  324. package/skills/dotnet-timezone/LICENSE.md +21 -0
  325. package/skills/dotnet-timezone/SKILL.md +109 -0
  326. package/skills/dotnet-timezone/SYNC.md +5 -0
  327. package/skills/dotnet-timezone/references/code-patterns.md +153 -0
  328. package/skills/dotnet-timezone/references/timezone-index.md +87 -0
  329. package/skills/dotnet-upgrade/LICENSE.md +21 -0
  330. package/skills/dotnet-upgrade/SKILL.md +116 -0
  331. package/skills/dotnet-upgrade/SYNC.md +5 -0
  332. package/skills/doublecheck/LICENSE.md +21 -0
  333. package/skills/doublecheck/SKILL.md +277 -0
  334. package/skills/doublecheck/SYNC.md +5 -0
  335. package/skills/doublecheck/assets/verification-report-template.md +92 -0
  336. package/skills/editorconfig/LICENSE.md +21 -0
  337. package/skills/editorconfig/SKILL.md +63 -0
  338. package/skills/editorconfig/SYNC.md +5 -0
  339. package/skills/ef-core/LICENSE.md +21 -0
  340. package/skills/ef-core/SKILL.md +75 -0
  341. package/skills/ef-core/SYNC.md +5 -0
  342. package/skills/entra-agent-user/LICENSE.md +21 -0
  343. package/skills/entra-agent-user/SKILL.md +270 -0
  344. package/skills/entra-agent-user/SYNC.md +5 -0
  345. package/skills/eval-driven-dev/LICENSE.md +21 -0
  346. package/skills/eval-driven-dev/SKILL.md +862 -0
  347. package/skills/eval-driven-dev/SYNC.md +5 -0
  348. package/skills/eval-driven-dev/references/pixie-api.md +195 -0
  349. package/skills/excalidraw-diagram-generator/LICENSE.md +21 -0
  350. package/skills/excalidraw-diagram-generator/SKILL.md +613 -0
  351. package/skills/excalidraw-diagram-generator/SYNC.md +5 -0
  352. package/skills/excalidraw-diagram-generator/references/element-types.md +497 -0
  353. package/skills/excalidraw-diagram-generator/references/excalidraw-schema.md +350 -0
  354. package/skills/excalidraw-diagram-generator/scripts/README.md +193 -0
  355. package/skills/excalidraw-diagram-generator/scripts/add-arrow.py +312 -0
  356. package/skills/excalidraw-diagram-generator/scripts/add-icon-to-diagram.py +404 -0
  357. package/skills/excalidraw-diagram-generator/scripts/split-excalidraw-library.py +183 -0
  358. package/skills/excalidraw-diagram-generator/templates/business-flow-swimlane-template.excalidraw +334 -0
  359. package/skills/excalidraw-diagram-generator/templates/class-diagram-template.excalidraw +558 -0
  360. package/skills/excalidraw-diagram-generator/templates/data-flow-diagram-template.excalidraw +279 -0
  361. package/skills/excalidraw-diagram-generator/templates/er-diagram-template.excalidraw +662 -0
  362. package/skills/excalidraw-diagram-generator/templates/flowchart-template.excalidraw +179 -0
  363. package/skills/excalidraw-diagram-generator/templates/mindmap-template.excalidraw +244 -0
  364. package/skills/excalidraw-diagram-generator/templates/relationship-template.excalidraw +145 -0
  365. package/skills/excalidraw-diagram-generator/templates/sequence-diagram-template.excalidraw +509 -0
  366. package/skills/fabric-lakehouse/LICENSE.md +21 -0
  367. package/skills/fabric-lakehouse/SKILL.md +106 -0
  368. package/skills/fabric-lakehouse/SYNC.md +5 -0
  369. package/skills/fabric-lakehouse/references/getdata.md +36 -0
  370. package/skills/fabric-lakehouse/references/pyspark.md +189 -0
  371. package/skills/fedora-linux-triage/LICENSE.md +21 -0
  372. package/skills/fedora-linux-triage/SKILL.md +31 -0
  373. package/skills/fedora-linux-triage/SYNC.md +5 -0
  374. package/skills/finalize-agent-prompt/LICENSE.md +21 -0
  375. package/skills/finalize-agent-prompt/SKILL.md +26 -0
  376. package/skills/finalize-agent-prompt/SYNC.md +5 -0
  377. package/skills/finnish-humanizer/LICENSE.md +21 -0
  378. package/skills/finnish-humanizer/SKILL.md +145 -0
  379. package/skills/finnish-humanizer/SYNC.md +5 -0
  380. package/skills/finnish-humanizer/references/patterns.md +338 -0
  381. package/skills/first-ask/LICENSE.md +21 -0
  382. package/skills/first-ask/SKILL.md +30 -0
  383. package/skills/first-ask/SYNC.md +5 -0
  384. package/skills/flowstudio-power-automate-build/LICENSE.md +21 -0
  385. package/skills/flowstudio-power-automate-build/SKILL.md +460 -0
  386. package/skills/flowstudio-power-automate-build/SYNC.md +5 -0
  387. package/skills/flowstudio-power-automate-build/references/action-patterns-connectors.md +542 -0
  388. package/skills/flowstudio-power-automate-build/references/action-patterns-core.md +542 -0
  389. package/skills/flowstudio-power-automate-build/references/action-patterns-data.md +735 -0
  390. package/skills/flowstudio-power-automate-build/references/build-patterns.md +108 -0
  391. package/skills/flowstudio-power-automate-build/references/flow-schema.md +225 -0
  392. package/skills/flowstudio-power-automate-build/references/trigger-types.md +211 -0
  393. package/skills/flowstudio-power-automate-debug/LICENSE.md +21 -0
  394. package/skills/flowstudio-power-automate-debug/SKILL.md +322 -0
  395. package/skills/flowstudio-power-automate-debug/SYNC.md +5 -0
  396. package/skills/flowstudio-power-automate-debug/references/common-errors.md +188 -0
  397. package/skills/flowstudio-power-automate-debug/references/debug-workflow.md +157 -0
  398. package/skills/flowstudio-power-automate-mcp/LICENSE.md +21 -0
  399. package/skills/flowstudio-power-automate-mcp/SKILL.md +450 -0
  400. package/skills/flowstudio-power-automate-mcp/SYNC.md +5 -0
  401. package/skills/flowstudio-power-automate-mcp/references/MCP-BOOTSTRAP.md +53 -0
  402. package/skills/flowstudio-power-automate-mcp/references/action-types.md +79 -0
  403. package/skills/flowstudio-power-automate-mcp/references/connection-references.md +115 -0
  404. package/skills/flowstudio-power-automate-mcp/references/tool-reference.md +445 -0
  405. package/skills/fluentui-blazor/LICENSE.md +21 -0
  406. package/skills/fluentui-blazor/SKILL.md +231 -0
  407. package/skills/fluentui-blazor/SYNC.md +5 -0
  408. package/skills/fluentui-blazor/references/DATAGRID.md +162 -0
  409. package/skills/fluentui-blazor/references/LAYOUT-AND-NAVIGATION.md +173 -0
  410. package/skills/fluentui-blazor/references/SETUP.md +129 -0
  411. package/skills/fluentui-blazor/references/THEMING.md +103 -0
  412. package/skills/folder-structure-blueprint-generator/LICENSE.md +21 -0
  413. package/skills/folder-structure-blueprint-generator/SKILL.md +405 -0
  414. package/skills/folder-structure-blueprint-generator/SYNC.md +5 -0
  415. package/skills/game-engine/LICENSE.md +21 -0
  416. package/skills/game-engine/SKILL.md +139 -0
  417. package/skills/game-engine/SYNC.md +5 -0
  418. package/skills/game-engine/assets/2d-maze-game.md +528 -0
  419. package/skills/game-engine/assets/2d-platform-game.md +1855 -0
  420. package/skills/game-engine/assets/gameBase-template-repo.md +310 -0
  421. package/skills/game-engine/assets/paddle-game-template.md +1528 -0
  422. package/skills/game-engine/assets/simple-2d-engine.md +507 -0
  423. package/skills/game-engine/references/3d-web-games.md +754 -0
  424. package/skills/game-engine/references/algorithms.md +843 -0
  425. package/skills/game-engine/references/basics.md +343 -0
  426. package/skills/game-engine/references/game-control-mechanisms.md +617 -0
  427. package/skills/game-engine/references/game-engine-core-principles.md +695 -0
  428. package/skills/game-engine/references/game-publishing.md +352 -0
  429. package/skills/game-engine/references/techniques.md +894 -0
  430. package/skills/game-engine/references/terminology.md +354 -0
  431. package/skills/game-engine/references/web-apis.md +1394 -0
  432. package/skills/gen-specs-as-issues/LICENSE.md +21 -0
  433. package/skills/gen-specs-as-issues/SKILL.md +165 -0
  434. package/skills/gen-specs-as-issues/SYNC.md +5 -0
  435. package/skills/generate-custom-instructions-from-codebase/LICENSE.md +21 -0
  436. package/skills/generate-custom-instructions-from-codebase/SKILL.md +240 -0
  437. package/skills/generate-custom-instructions-from-codebase/SYNC.md +5 -0
  438. package/skills/geofeed-tuner/LICENSE.md +21 -0
  439. package/skills/geofeed-tuner/SKILL.md +864 -0
  440. package/skills/geofeed-tuner/SYNC.md +5 -0
  441. package/skills/geofeed-tuner/assets/example/01-user-input-rfc8805-feed.csv +5 -0
  442. package/skills/geofeed-tuner/assets/iso3166-1.json +1249 -0
  443. package/skills/geofeed-tuner/assets/iso3166-2.json +20188 -0
  444. package/skills/geofeed-tuner/assets/small-territories.json +106 -0
  445. package/skills/geofeed-tuner/references/rfc8805.txt +735 -0
  446. package/skills/geofeed-tuner/references/snippets-python3.md +85 -0
  447. package/skills/geofeed-tuner/scripts/templates/index.html +2305 -0
  448. package/skills/gh-cli/LICENSE.md +21 -0
  449. package/skills/gh-cli/SKILL.md +2187 -0
  450. package/skills/gh-cli/SYNC.md +5 -0
  451. package/skills/git-commit/LICENSE.md +21 -0
  452. package/skills/git-commit/SKILL.md +124 -0
  453. package/skills/git-commit/SYNC.md +5 -0
  454. package/skills/git-flow-branch-creator/LICENSE.md +21 -0
  455. package/skills/git-flow-branch-creator/SKILL.md +292 -0
  456. package/skills/git-flow-branch-creator/SYNC.md +5 -0
  457. package/skills/github-copilot-starter/LICENSE.md +21 -0
  458. package/skills/github-copilot-starter/SKILL.md +402 -0
  459. package/skills/github-copilot-starter/SYNC.md +5 -0
  460. package/skills/github-issues/LICENSE.md +21 -0
  461. package/skills/github-issues/SKILL.md +201 -0
  462. package/skills/github-issues/SYNC.md +5 -0
  463. package/skills/github-issues/references/dependencies.md +71 -0
  464. package/skills/github-issues/references/images.md +116 -0
  465. package/skills/github-issues/references/issue-fields.md +191 -0
  466. package/skills/github-issues/references/issue-types.md +72 -0
  467. package/skills/github-issues/references/projects.md +273 -0
  468. package/skills/github-issues/references/search.md +231 -0
  469. package/skills/github-issues/references/sub-issues.md +137 -0
  470. package/skills/github-issues/references/templates.md +90 -0
  471. package/skills/go-mcp-server-generator/LICENSE.md +21 -0
  472. package/skills/go-mcp-server-generator/SKILL.md +334 -0
  473. package/skills/go-mcp-server-generator/SYNC.md +5 -0
  474. package/skills/gtm-0-to-1-launch/LICENSE.md +21 -0
  475. package/skills/gtm-0-to-1-launch/SKILL.md +321 -0
  476. package/skills/gtm-0-to-1-launch/SYNC.md +5 -0
  477. package/skills/gtm-ai-gtm/LICENSE.md +21 -0
  478. package/skills/gtm-ai-gtm/SKILL.md +569 -0
  479. package/skills/gtm-ai-gtm/SYNC.md +5 -0
  480. package/skills/gtm-board-and-investor-communication/LICENSE.md +21 -0
  481. package/skills/gtm-board-and-investor-communication/SKILL.md +456 -0
  482. package/skills/gtm-board-and-investor-communication/SYNC.md +5 -0
  483. package/skills/gtm-developer-ecosystem/LICENSE.md +21 -0
  484. package/skills/gtm-developer-ecosystem/SKILL.md +310 -0
  485. package/skills/gtm-developer-ecosystem/SYNC.md +5 -0
  486. package/skills/gtm-enterprise-account-planning/LICENSE.md +21 -0
  487. package/skills/gtm-enterprise-account-planning/SKILL.md +429 -0
  488. package/skills/gtm-enterprise-account-planning/SYNC.md +5 -0
  489. package/skills/gtm-enterprise-onboarding/LICENSE.md +21 -0
  490. package/skills/gtm-enterprise-onboarding/SKILL.md +457 -0
  491. package/skills/gtm-enterprise-onboarding/SYNC.md +5 -0
  492. package/skills/gtm-operating-cadence/LICENSE.md +21 -0
  493. package/skills/gtm-operating-cadence/SKILL.md +420 -0
  494. package/skills/gtm-operating-cadence/SYNC.md +5 -0
  495. package/skills/gtm-partnership-architecture/LICENSE.md +21 -0
  496. package/skills/gtm-partnership-architecture/SKILL.md +470 -0
  497. package/skills/gtm-partnership-architecture/SYNC.md +5 -0
  498. package/skills/gtm-positioning-strategy/LICENSE.md +21 -0
  499. package/skills/gtm-positioning-strategy/SKILL.md +438 -0
  500. package/skills/gtm-positioning-strategy/SYNC.md +5 -0
  501. package/skills/gtm-product-led-growth/LICENSE.md +21 -0
  502. package/skills/gtm-product-led-growth/SKILL.md +339 -0
  503. package/skills/gtm-product-led-growth/SYNC.md +5 -0
  504. package/skills/gtm-technical-product-pricing/LICENSE.md +21 -0
  505. package/skills/gtm-technical-product-pricing/SKILL.md +353 -0
  506. package/skills/gtm-technical-product-pricing/SYNC.md +5 -0
  507. package/skills/image-manipulation-image-magick/LICENSE.md +21 -0
  508. package/skills/image-manipulation-image-magick/SKILL.md +252 -0
  509. package/skills/image-manipulation-image-magick/SYNC.md +5 -0
  510. package/skills/import-infrastructure-as-code/LICENSE.md +21 -0
  511. package/skills/import-infrastructure-as-code/SKILL.md +367 -0
  512. package/skills/import-infrastructure-as-code/SYNC.md +5 -0
  513. package/skills/issue-fields-migration/LICENSE.md +21 -0
  514. package/skills/issue-fields-migration/SKILL.md +533 -0
  515. package/skills/issue-fields-migration/SYNC.md +5 -0
  516. package/skills/issue-fields-migration/references/issue-fields-api.md +129 -0
  517. package/skills/issue-fields-migration/references/labels-api.md +74 -0
  518. package/skills/issue-fields-migration/references/projects-api.md +116 -0
  519. package/skills/java-add-graalvm-native-image-support/LICENSE.md +21 -0
  520. package/skills/java-add-graalvm-native-image-support/SKILL.md +449 -0
  521. package/skills/java-add-graalvm-native-image-support/SYNC.md +5 -0
  522. package/skills/java-docs/LICENSE.md +21 -0
  523. package/skills/java-docs/SKILL.md +23 -0
  524. package/skills/java-docs/SYNC.md +5 -0
  525. package/skills/java-junit/LICENSE.md +21 -0
  526. package/skills/java-junit/SKILL.md +63 -0
  527. package/skills/java-junit/SYNC.md +5 -0
  528. package/skills/java-mcp-server-generator/LICENSE.md +21 -0
  529. package/skills/java-mcp-server-generator/SKILL.md +756 -0
  530. package/skills/java-mcp-server-generator/SYNC.md +5 -0
  531. package/skills/java-refactoring-extract-method/LICENSE.md +21 -0
  532. package/skills/java-refactoring-extract-method/SKILL.md +104 -0
  533. package/skills/java-refactoring-extract-method/SYNC.md +5 -0
  534. package/skills/java-refactoring-remove-parameter/LICENSE.md +21 -0
  535. package/skills/java-refactoring-remove-parameter/SKILL.md +84 -0
  536. package/skills/java-refactoring-remove-parameter/SYNC.md +5 -0
  537. package/skills/java-springboot/LICENSE.md +21 -0
  538. package/skills/java-springboot/SKILL.md +65 -0
  539. package/skills/java-springboot/SYNC.md +5 -0
  540. package/skills/javascript-typescript-jest/LICENSE.md +21 -0
  541. package/skills/javascript-typescript-jest/SKILL.md +44 -0
  542. package/skills/javascript-typescript-jest/SYNC.md +5 -0
  543. package/skills/kotlin-mcp-server-generator/LICENSE.md +21 -0
  544. package/skills/kotlin-mcp-server-generator/SKILL.md +449 -0
  545. package/skills/kotlin-mcp-server-generator/SYNC.md +5 -0
  546. package/skills/kotlin-springboot/LICENSE.md +21 -0
  547. package/skills/kotlin-springboot/SKILL.md +70 -0
  548. package/skills/kotlin-springboot/SYNC.md +5 -0
  549. package/skills/legacy-circuit-mockups/LICENSE.md +21 -0
  550. package/skills/legacy-circuit-mockups/SKILL.md +276 -0
  551. package/skills/legacy-circuit-mockups/SYNC.md +5 -0
  552. package/skills/legacy-circuit-mockups/references/28256-eeprom.md +190 -0
  553. package/skills/legacy-circuit-mockups/references/555.md +861 -0
  554. package/skills/legacy-circuit-mockups/references/6502.md +221 -0
  555. package/skills/legacy-circuit-mockups/references/6522.md +211 -0
  556. package/skills/legacy-circuit-mockups/references/6C62256.md +177 -0
  557. package/skills/legacy-circuit-mockups/references/7400-series.md +177 -0
  558. package/skills/legacy-circuit-mockups/references/assembly-compiler.md +258 -0
  559. package/skills/legacy-circuit-mockups/references/assembly-language.md +226 -0
  560. package/skills/legacy-circuit-mockups/references/basic-electronic-components.md +86 -0
  561. package/skills/legacy-circuit-mockups/references/breadboard.md +214 -0
  562. package/skills/legacy-circuit-mockups/references/common-breadboard-components.md +281 -0
  563. package/skills/legacy-circuit-mockups/references/connecting-electronic-components.md +310 -0
  564. package/skills/legacy-circuit-mockups/references/emulator-28256-eeprom.md +245 -0
  565. package/skills/legacy-circuit-mockups/references/emulator-6502.md +251 -0
  566. package/skills/legacy-circuit-mockups/references/emulator-6522.md +288 -0
  567. package/skills/legacy-circuit-mockups/references/emulator-6C62256.md +233 -0
  568. package/skills/legacy-circuit-mockups/references/emulator-lcd.md +266 -0
  569. package/skills/legacy-circuit-mockups/references/lcd.md +208 -0
  570. package/skills/legacy-circuit-mockups/references/minipro.md +211 -0
  571. package/skills/legacy-circuit-mockups/references/t48eeprom-programmer.md +174 -0
  572. package/skills/make-repo-contribution/LICENSE.md +21 -0
  573. package/skills/make-repo-contribution/SKILL.md +90 -0
  574. package/skills/make-repo-contribution/SYNC.md +5 -0
  575. package/skills/make-repo-contribution/assets/issue-template.md +37 -0
  576. package/skills/make-repo-contribution/assets/pr-template.md +36 -0
  577. package/skills/make-skill-template/LICENSE.md +21 -0
  578. package/skills/make-skill-template/SKILL.md +147 -0
  579. package/skills/make-skill-template/SYNC.md +5 -0
  580. package/skills/markdown-to-html/LICENSE.md +21 -0
  581. package/skills/markdown-to-html/SKILL.md +916 -0
  582. package/skills/markdown-to-html/SYNC.md +5 -0
  583. package/skills/markdown-to-html/references/basic-markdown-to-html.md +420 -0
  584. package/skills/markdown-to-html/references/basic-markdown.md +496 -0
  585. package/skills/markdown-to-html/references/code-blocks-to-html.md +165 -0
  586. package/skills/markdown-to-html/references/code-blocks.md +70 -0
  587. package/skills/markdown-to-html/references/collapsed-sections-to-html.md +136 -0
  588. package/skills/markdown-to-html/references/collapsed-sections.md +48 -0
  589. package/skills/markdown-to-html/references/gomarkdown.md +253 -0
  590. package/skills/markdown-to-html/references/hugo.md +394 -0
  591. package/skills/markdown-to-html/references/jekyll.md +321 -0
  592. package/skills/markdown-to-html/references/marked.md +121 -0
  593. package/skills/markdown-to-html/references/pandoc.md +226 -0
  594. package/skills/markdown-to-html/references/tables-to-html.md +169 -0
  595. package/skills/markdown-to-html/references/tables.md +72 -0
  596. package/skills/markdown-to-html/references/writing-mathematical-expressions-to-html.md +350 -0
  597. package/skills/markdown-to-html/references/writing-mathematical-expressions.md +76 -0
  598. package/skills/mcp-cli/LICENSE.md +21 -0
  599. package/skills/mcp-cli/SKILL.md +78 -0
  600. package/skills/mcp-cli/SYNC.md +5 -0
  601. package/skills/mcp-copilot-studio-server-generator/LICENSE.md +21 -0
  602. package/skills/mcp-copilot-studio-server-generator/SKILL.md +118 -0
  603. package/skills/mcp-copilot-studio-server-generator/SYNC.md +5 -0
  604. package/skills/mcp-create-adaptive-cards/LICENSE.md +21 -0
  605. package/skills/mcp-create-adaptive-cards/SKILL.md +532 -0
  606. package/skills/mcp-create-adaptive-cards/SYNC.md +5 -0
  607. package/skills/mcp-create-declarative-agent/LICENSE.md +21 -0
  608. package/skills/mcp-create-declarative-agent/SKILL.md +315 -0
  609. package/skills/mcp-create-declarative-agent/SYNC.md +5 -0
  610. package/skills/mcp-deploy-manage-agents/LICENSE.md +21 -0
  611. package/skills/mcp-deploy-manage-agents/SKILL.md +341 -0
  612. package/skills/mcp-deploy-manage-agents/SYNC.md +5 -0
  613. package/skills/meeting-minutes/LICENSE.md +21 -0
  614. package/skills/meeting-minutes/SKILL.md +235 -0
  615. package/skills/meeting-minutes/SYNC.md +5 -0
  616. package/skills/memory-merger/LICENSE.md +21 -0
  617. package/skills/memory-merger/SKILL.md +108 -0
  618. package/skills/memory-merger/SYNC.md +5 -0
  619. package/skills/mentoring-juniors/LICENSE.md +21 -0
  620. package/skills/mentoring-juniors/SKILL.md +310 -0
  621. package/skills/mentoring-juniors/SYNC.md +5 -0
  622. package/skills/microsoft-agent-framework/LICENSE.md +21 -0
  623. package/skills/microsoft-agent-framework/SKILL.md +65 -0
  624. package/skills/microsoft-agent-framework/SYNC.md +5 -0
  625. package/skills/microsoft-agent-framework/references/dotnet.md +24 -0
  626. package/skills/microsoft-agent-framework/references/python.md +24 -0
  627. package/skills/microsoft-code-reference/LICENSE.md +21 -0
  628. package/skills/microsoft-code-reference/SKILL.md +99 -0
  629. package/skills/microsoft-code-reference/SYNC.md +5 -0
  630. package/skills/microsoft-docs/LICENSE.md +21 -0
  631. package/skills/microsoft-docs/SKILL.md +134 -0
  632. package/skills/microsoft-docs/SYNC.md +5 -0
  633. package/skills/microsoft-skill-creator/LICENSE.md +21 -0
  634. package/skills/microsoft-skill-creator/SKILL.md +250 -0
  635. package/skills/microsoft-skill-creator/SYNC.md +5 -0
  636. package/skills/microsoft-skill-creator/references/skill-templates.md +345 -0
  637. package/skills/migrating-oracle-to-postgres-stored-procedures/LICENSE.md +21 -0
  638. package/skills/migrating-oracle-to-postgres-stored-procedures/SKILL.md +42 -0
  639. package/skills/migrating-oracle-to-postgres-stored-procedures/SYNC.md +5 -0
  640. package/skills/mkdocs-translations/LICENSE.md +21 -0
  641. package/skills/mkdocs-translations/SKILL.md +108 -0
  642. package/skills/mkdocs-translations/SYNC.md +5 -0
  643. package/skills/model-recommendation/LICENSE.md +21 -0
  644. package/skills/model-recommendation/SKILL.md +672 -0
  645. package/skills/model-recommendation/SYNC.md +5 -0
  646. package/skills/msstore-cli/LICENSE.md +21 -0
  647. package/skills/msstore-cli/SKILL.md +600 -0
  648. package/skills/msstore-cli/SYNC.md +5 -0
  649. package/skills/multi-stage-dockerfile/LICENSE.md +21 -0
  650. package/skills/multi-stage-dockerfile/SKILL.md +46 -0
  651. package/skills/multi-stage-dockerfile/SYNC.md +5 -0
  652. package/skills/my-issues/LICENSE.md +21 -0
  653. package/skills/my-issues/SKILL.md +8 -0
  654. package/skills/my-issues/SYNC.md +5 -0
  655. package/skills/my-pull-requests/LICENSE.md +21 -0
  656. package/skills/my-pull-requests/SKILL.md +14 -0
  657. package/skills/my-pull-requests/SYNC.md +5 -0
  658. package/skills/nano-banana-pro-openrouter/LICENSE.md +21 -0
  659. package/skills/nano-banana-pro-openrouter/SKILL.md +74 -0
  660. package/skills/nano-banana-pro-openrouter/SYNC.md +5 -0
  661. package/skills/nano-banana-pro-openrouter/assets/SYSTEM_TEMPLATE +14 -0
  662. package/skills/nano-banana-pro-openrouter/scripts/generate_image.py +191 -0
  663. package/skills/napkin/LICENSE.md +21 -0
  664. package/skills/napkin/SKILL.md +154 -0
  665. package/skills/napkin/SYNC.md +5 -0
  666. package/skills/napkin/assets/napkin.html +2019 -0
  667. package/skills/napkin/assets/step1-activate.svg +107 -0
  668. package/skills/napkin/assets/step2-whiteboard.svg +157 -0
  669. package/skills/napkin/assets/step3-draw.svg +143 -0
  670. package/skills/napkin/assets/step4-share.svg +98 -0
  671. package/skills/napkin/assets/step5-response.svg +112 -0
  672. package/skills/next-intl-add-language/LICENSE.md +21 -0
  673. package/skills/next-intl-add-language/SKILL.md +19 -0
  674. package/skills/next-intl-add-language/SYNC.md +5 -0
  675. package/skills/noob-mode/LICENSE.md +21 -0
  676. package/skills/noob-mode/SKILL.md +263 -0
  677. package/skills/noob-mode/SYNC.md +5 -0
  678. package/skills/noob-mode/references/examples.md +418 -0
  679. package/skills/noob-mode/references/glossary.md +368 -0
  680. package/skills/nuget-manager/LICENSE.md +21 -0
  681. package/skills/nuget-manager/SKILL.md +68 -0
  682. package/skills/nuget-manager/SYNC.md +5 -0
  683. package/skills/oo-component-documentation/LICENSE.md +21 -0
  684. package/skills/oo-component-documentation/SKILL.md +74 -0
  685. package/skills/oo-component-documentation/SYNC.md +5 -0
  686. package/skills/oo-component-documentation/assets/documentation-template.md +97 -0
  687. package/skills/oo-component-documentation/references/create-mode.md +32 -0
  688. package/skills/oo-component-documentation/references/update-mode.md +32 -0
  689. package/skills/openapi-to-application-code/LICENSE.md +21 -0
  690. package/skills/openapi-to-application-code/SKILL.md +112 -0
  691. package/skills/openapi-to-application-code/SYNC.md +5 -0
  692. package/skills/pdftk-server/LICENSE.md +21 -0
  693. package/skills/pdftk-server/SKILL.md +162 -0
  694. package/skills/pdftk-server/SYNC.md +5 -0
  695. package/skills/pdftk-server/references/download.md +75 -0
  696. package/skills/pdftk-server/references/pdftk-cli-examples.md +193 -0
  697. package/skills/pdftk-server/references/pdftk-man-page.md +232 -0
  698. package/skills/pdftk-server/references/pdftk-server-license.md +25 -0
  699. package/skills/pdftk-server/references/third-party-materials.md +103 -0
  700. package/skills/penpot-uiux-design/LICENSE.md +21 -0
  701. package/skills/penpot-uiux-design/SKILL.md +342 -0
  702. package/skills/penpot-uiux-design/SYNC.md +5 -0
  703. package/skills/penpot-uiux-design/references/accessibility.md +329 -0
  704. package/skills/penpot-uiux-design/references/component-patterns.md +339 -0
  705. package/skills/penpot-uiux-design/references/platform-guidelines.md +367 -0
  706. package/skills/penpot-uiux-design/references/setup-troubleshooting.md +328 -0
  707. package/skills/php-mcp-server-generator/LICENSE.md +21 -0
  708. package/skills/php-mcp-server-generator/SKILL.md +522 -0
  709. package/skills/php-mcp-server-generator/SYNC.md +5 -0
  710. package/skills/planning-oracle-to-postgres-migration-integration-testing/LICENSE.md +21 -0
  711. package/skills/planning-oracle-to-postgres-migration-integration-testing/SKILL.md +44 -0
  712. package/skills/planning-oracle-to-postgres-migration-integration-testing/SYNC.md +5 -0
  713. package/skills/plantuml-ascii/LICENSE.md +21 -0
  714. package/skills/plantuml-ascii/SKILL.md +305 -0
  715. package/skills/plantuml-ascii/SYNC.md +5 -0
  716. package/skills/playwright-automation-fill-in-form/LICENSE.md +21 -0
  717. package/skills/playwright-automation-fill-in-form/SKILL.md +28 -0
  718. package/skills/playwright-automation-fill-in-form/SYNC.md +5 -0
  719. package/skills/playwright-explore-website/LICENSE.md +21 -0
  720. package/skills/playwright-explore-website/SKILL.md +17 -0
  721. package/skills/playwright-explore-website/SYNC.md +5 -0
  722. package/skills/playwright-generate-test/LICENSE.md +21 -0
  723. package/skills/playwright-generate-test/SKILL.md +17 -0
  724. package/skills/playwright-generate-test/SYNC.md +5 -0
  725. package/skills/polyglot-test-agent/LICENSE.md +21 -0
  726. package/skills/polyglot-test-agent/SKILL.md +161 -0
  727. package/skills/polyglot-test-agent/SYNC.md +5 -0
  728. package/skills/polyglot-test-agent/unit-test-generation.prompt.md +155 -0
  729. package/skills/postgresql-code-review/LICENSE.md +21 -0
  730. package/skills/postgresql-code-review/SKILL.md +212 -0
  731. package/skills/postgresql-code-review/SYNC.md +5 -0
  732. package/skills/postgresql-optimization/LICENSE.md +21 -0
  733. package/skills/postgresql-optimization/SKILL.md +404 -0
  734. package/skills/postgresql-optimization/SYNC.md +5 -0
  735. package/skills/power-apps-code-app-scaffold/LICENSE.md +21 -0
  736. package/skills/power-apps-code-app-scaffold/SKILL.md +146 -0
  737. package/skills/power-apps-code-app-scaffold/SYNC.md +5 -0
  738. package/skills/power-bi-dax-optimization/LICENSE.md +21 -0
  739. package/skills/power-bi-dax-optimization/SKILL.md +173 -0
  740. package/skills/power-bi-dax-optimization/SYNC.md +5 -0
  741. package/skills/power-bi-model-design-review/LICENSE.md +21 -0
  742. package/skills/power-bi-model-design-review/SKILL.md +403 -0
  743. package/skills/power-bi-model-design-review/SYNC.md +5 -0
  744. package/skills/power-bi-performance-troubleshooting/LICENSE.md +21 -0
  745. package/skills/power-bi-performance-troubleshooting/SKILL.md +382 -0
  746. package/skills/power-bi-performance-troubleshooting/SYNC.md +5 -0
  747. package/skills/power-bi-report-design-consultation/LICENSE.md +21 -0
  748. package/skills/power-bi-report-design-consultation/SKILL.md +351 -0
  749. package/skills/power-bi-report-design-consultation/SYNC.md +5 -0
  750. package/skills/power-platform-mcp-connector-suite/LICENSE.md +21 -0
  751. package/skills/power-platform-mcp-connector-suite/SKILL.md +156 -0
  752. package/skills/power-platform-mcp-connector-suite/SYNC.md +5 -0
  753. package/skills/powerbi-modeling/LICENSE.md +21 -0
  754. package/skills/powerbi-modeling/SKILL.md +153 -0
  755. package/skills/powerbi-modeling/SYNC.md +5 -0
  756. package/skills/powerbi-modeling/references/MEASURES-DAX.md +195 -0
  757. package/skills/powerbi-modeling/references/PERFORMANCE.md +215 -0
  758. package/skills/powerbi-modeling/references/RELATIONSHIPS.md +147 -0
  759. package/skills/powerbi-modeling/references/RLS.md +226 -0
  760. package/skills/powerbi-modeling/references/STAR-SCHEMA.md +103 -0
  761. package/skills/prd/LICENSE.md +21 -0
  762. package/skills/prd/SKILL.md +143 -0
  763. package/skills/prd/SYNC.md +5 -0
  764. package/skills/premium-frontend-ui/LICENSE.md +21 -0
  765. package/skills/premium-frontend-ui/SKILL.md +110 -0
  766. package/skills/premium-frontend-ui/SYNC.md +5 -0
  767. package/skills/project-workflow-analysis-blueprint-generator/LICENSE.md +21 -0
  768. package/skills/project-workflow-analysis-blueprint-generator/SKILL.md +293 -0
  769. package/skills/project-workflow-analysis-blueprint-generator/SYNC.md +5 -0
  770. package/skills/prompt-builder/LICENSE.md +21 -0
  771. package/skills/prompt-builder/SKILL.md +141 -0
  772. package/skills/prompt-builder/SYNC.md +5 -0
  773. package/skills/publish-to-pages/LICENSE.md +21 -0
  774. package/skills/publish-to-pages/SKILL.md +107 -0
  775. package/skills/publish-to-pages/SYNC.md +5 -0
  776. package/skills/publish-to-pages/scripts/convert-pdf.py +176 -0
  777. package/skills/publish-to-pages/scripts/convert-pptx.py +376 -0
  778. package/skills/publish-to-pages/scripts/publish.sh +51 -0
  779. package/skills/pytest-coverage/LICENSE.md +21 -0
  780. package/skills/pytest-coverage/SKILL.md +28 -0
  781. package/skills/pytest-coverage/SYNC.md +5 -0
  782. package/skills/python-mcp-server-generator/LICENSE.md +21 -0
  783. package/skills/python-mcp-server-generator/SKILL.md +105 -0
  784. package/skills/python-mcp-server-generator/SYNC.md +5 -0
  785. package/skills/quasi-coder/LICENSE.md +21 -0
  786. package/skills/quasi-coder/SKILL.md +369 -0
  787. package/skills/quasi-coder/SYNC.md +5 -0
  788. package/skills/readme-blueprint-generator/LICENSE.md +21 -0
  789. package/skills/readme-blueprint-generator/SKILL.md +78 -0
  790. package/skills/readme-blueprint-generator/SYNC.md +5 -0
  791. package/skills/refactor/LICENSE.md +21 -0
  792. package/skills/refactor/SKILL.md +645 -0
  793. package/skills/refactor/SYNC.md +5 -0
  794. package/skills/refactor-method-complexity-reduce/LICENSE.md +21 -0
  795. package/skills/refactor-method-complexity-reduce/SKILL.md +98 -0
  796. package/skills/refactor-method-complexity-reduce/SYNC.md +5 -0
  797. package/skills/refactor-plan/LICENSE.md +21 -0
  798. package/skills/refactor-plan/SKILL.md +65 -0
  799. package/skills/refactor-plan/SYNC.md +5 -0
  800. package/skills/remember/LICENSE.md +21 -0
  801. package/skills/remember/SKILL.md +126 -0
  802. package/skills/remember/SYNC.md +5 -0
  803. package/skills/remember-interactive-programming/LICENSE.md +21 -0
  804. package/skills/remember-interactive-programming/SKILL.md +13 -0
  805. package/skills/remember-interactive-programming/SYNC.md +5 -0
  806. package/skills/repo-story-time/LICENSE.md +21 -0
  807. package/skills/repo-story-time/SKILL.md +154 -0
  808. package/skills/repo-story-time/SYNC.md +5 -0
  809. package/skills/review-and-refactor/LICENSE.md +21 -0
  810. package/skills/review-and-refactor/SKILL.md +15 -0
  811. package/skills/review-and-refactor/SYNC.md +5 -0
  812. package/skills/reviewing-oracle-to-postgres-migration/LICENSE.md +21 -0
  813. package/skills/reviewing-oracle-to-postgres-migration/SKILL.md +67 -0
  814. package/skills/reviewing-oracle-to-postgres-migration/SYNC.md +5 -0
  815. package/skills/reviewing-oracle-to-postgres-migration/references/REFERENCE.md +13 -0
  816. package/skills/reviewing-oracle-to-postgres-migration/references/empty-strings-handling.md +69 -0
  817. package/skills/reviewing-oracle-to-postgres-migration/references/no-data-found-exceptions.md +99 -0
  818. package/skills/reviewing-oracle-to-postgres-migration/references/oracle-parentheses-from-clause.md +190 -0
  819. package/skills/reviewing-oracle-to-postgres-migration/references/oracle-to-postgres-sorting.md +51 -0
  820. package/skills/reviewing-oracle-to-postgres-migration/references/oracle-to-postgres-timestamp-timezone.md +187 -0
  821. package/skills/reviewing-oracle-to-postgres-migration/references/oracle-to-postgres-to-char-numeric.md +145 -0
  822. package/skills/reviewing-oracle-to-postgres-migration/references/oracle-to-postgres-type-coercion.md +182 -0
  823. package/skills/reviewing-oracle-to-postgres-migration/references/postgres-concurrent-transactions.md +259 -0
  824. package/skills/reviewing-oracle-to-postgres-migration/references/postgres-refcursor-handling.md +148 -0
  825. package/skills/ruby-mcp-server-generator/LICENSE.md +21 -0
  826. package/skills/ruby-mcp-server-generator/SKILL.md +660 -0
  827. package/skills/ruby-mcp-server-generator/SYNC.md +5 -0
  828. package/skills/rust-mcp-server-generator/LICENSE.md +21 -0
  829. package/skills/rust-mcp-server-generator/SKILL.md +577 -0
  830. package/skills/rust-mcp-server-generator/SYNC.md +5 -0
  831. package/skills/sandbox-npm-install/LICENSE.md +21 -0
  832. package/skills/sandbox-npm-install/SKILL.md +80 -0
  833. package/skills/sandbox-npm-install/SYNC.md +5 -0
  834. package/skills/sandbox-npm-install/scripts/install.sh +193 -0
  835. package/skills/scaffolding-oracle-to-postgres-migration-test-project/LICENSE.md +21 -0
  836. package/skills/scaffolding-oracle-to-postgres-migration-test-project/SKILL.md +54 -0
  837. package/skills/scaffolding-oracle-to-postgres-migration-test-project/SYNC.md +5 -0
  838. package/skills/scoutqa-test/LICENSE.md +21 -0
  839. package/skills/scoutqa-test/SKILL.md +375 -0
  840. package/skills/scoutqa-test/SYNC.md +5 -0
  841. package/skills/secret-scanning/LICENSE.md +21 -0
  842. package/skills/secret-scanning/SKILL.md +224 -0
  843. package/skills/secret-scanning/SYNC.md +5 -0
  844. package/skills/secret-scanning/references/alerts-and-remediation.md +245 -0
  845. package/skills/secret-scanning/references/custom-patterns.md +158 -0
  846. package/skills/secret-scanning/references/push-protection.md +164 -0
  847. package/skills/semantic-kernel/LICENSE.md +21 -0
  848. package/skills/semantic-kernel/SKILL.md +56 -0
  849. package/skills/semantic-kernel/SYNC.md +5 -0
  850. package/skills/semantic-kernel/references/dotnet.md +15 -0
  851. package/skills/semantic-kernel/references/python.md +15 -0
  852. package/skills/shuffle-json-data/LICENSE.md +21 -0
  853. package/skills/shuffle-json-data/SKILL.md +150 -0
  854. package/skills/shuffle-json-data/SYNC.md +5 -0
  855. package/skills/snowflake-semanticview/LICENSE.md +21 -0
  856. package/skills/snowflake-semanticview/SKILL.md +83 -0
  857. package/skills/snowflake-semanticview/SYNC.md +5 -0
  858. package/skills/sponsor-finder/LICENSE.md +21 -0
  859. package/skills/sponsor-finder/SKILL.md +258 -0
  860. package/skills/sponsor-finder/SYNC.md +5 -0
  861. package/skills/spring-boot-testing/LICENSE.md +21 -0
  862. package/skills/spring-boot-testing/SKILL.md +189 -0
  863. package/skills/spring-boot-testing/SYNC.md +5 -0
  864. package/skills/spring-boot-testing/references/assertj-basics.md +207 -0
  865. package/skills/spring-boot-testing/references/assertj-collections.md +183 -0
  866. package/skills/spring-boot-testing/references/context-caching.md +115 -0
  867. package/skills/spring-boot-testing/references/datajpatest.md +197 -0
  868. package/skills/spring-boot-testing/references/instancio.md +230 -0
  869. package/skills/spring-boot-testing/references/mockitobean.md +232 -0
  870. package/skills/spring-boot-testing/references/mockmvc-classic.md +206 -0
  871. package/skills/spring-boot-testing/references/mockmvc-tester.md +311 -0
  872. package/skills/spring-boot-testing/references/restclienttest.md +227 -0
  873. package/skills/spring-boot-testing/references/resttestclient.md +278 -0
  874. package/skills/spring-boot-testing/references/sb4-migration.md +181 -0
  875. package/skills/spring-boot-testing/references/test-slices-overview.md +203 -0
  876. package/skills/spring-boot-testing/references/testcontainers-jdbc.md +234 -0
  877. package/skills/spring-boot-testing/references/webmvctest.md +177 -0
  878. package/skills/sql-code-review/LICENSE.md +21 -0
  879. package/skills/sql-code-review/SKILL.md +301 -0
  880. package/skills/sql-code-review/SYNC.md +5 -0
  881. package/skills/sql-optimization/LICENSE.md +21 -0
  882. package/skills/sql-optimization/SKILL.md +296 -0
  883. package/skills/sql-optimization/SYNC.md +5 -0
  884. package/skills/structured-autonomy-generate/LICENSE.md +21 -0
  885. package/skills/structured-autonomy-generate/SKILL.md +125 -0
  886. package/skills/structured-autonomy-generate/SYNC.md +5 -0
  887. package/skills/structured-autonomy-implement/LICENSE.md +21 -0
  888. package/skills/structured-autonomy-implement/SKILL.md +19 -0
  889. package/skills/structured-autonomy-implement/SYNC.md +5 -0
  890. package/skills/structured-autonomy-plan/LICENSE.md +21 -0
  891. package/skills/structured-autonomy-plan/SKILL.md +81 -0
  892. package/skills/structured-autonomy-plan/SYNC.md +5 -0
  893. package/skills/suggest-awesome-github-copilot-agents/LICENSE.md +21 -0
  894. package/skills/suggest-awesome-github-copilot-agents/SKILL.md +106 -0
  895. package/skills/suggest-awesome-github-copilot-agents/SYNC.md +5 -0
  896. package/skills/suggest-awesome-github-copilot-instructions/LICENSE.md +21 -0
  897. package/skills/suggest-awesome-github-copilot-instructions/SKILL.md +122 -0
  898. package/skills/suggest-awesome-github-copilot-instructions/SYNC.md +5 -0
  899. package/skills/suggest-awesome-github-copilot-skills/LICENSE.md +21 -0
  900. package/skills/suggest-awesome-github-copilot-skills/SKILL.md +130 -0
  901. package/skills/suggest-awesome-github-copilot-skills/SYNC.md +5 -0
  902. package/skills/swift-mcp-server-generator/LICENSE.md +21 -0
  903. package/skills/swift-mcp-server-generator/SKILL.md +669 -0
  904. package/skills/swift-mcp-server-generator/SYNC.md +5 -0
  905. package/skills/technology-stack-blueprint-generator/LICENSE.md +21 -0
  906. package/skills/technology-stack-blueprint-generator/SKILL.md +242 -0
  907. package/skills/technology-stack-blueprint-generator/SYNC.md +5 -0
  908. package/skills/terraform-azurerm-set-diff-analyzer/LICENSE.md +21 -0
  909. package/skills/terraform-azurerm-set-diff-analyzer/SKILL.md +48 -0
  910. package/skills/terraform-azurerm-set-diff-analyzer/SYNC.md +5 -0
  911. package/skills/terraform-azurerm-set-diff-analyzer/references/azurerm_set_attributes.json +154 -0
  912. package/skills/terraform-azurerm-set-diff-analyzer/references/azurerm_set_attributes.md +145 -0
  913. package/skills/terraform-azurerm-set-diff-analyzer/scripts/README.md +205 -0
  914. package/skills/terraform-azurerm-set-diff-analyzer/scripts/analyze_plan.py +940 -0
  915. package/skills/tldr-prompt/LICENSE.md +21 -0
  916. package/skills/tldr-prompt/SKILL.md +304 -0
  917. package/skills/tldr-prompt/SYNC.md +5 -0
  918. package/skills/transloadit-media-processing/LICENSE.md +21 -0
  919. package/skills/transloadit-media-processing/SKILL.md +194 -0
  920. package/skills/transloadit-media-processing/SYNC.md +5 -0
  921. package/skills/typescript-mcp-server-generator/LICENSE.md +21 -0
  922. package/skills/typescript-mcp-server-generator/SKILL.md +90 -0
  923. package/skills/typescript-mcp-server-generator/SYNC.md +5 -0
  924. package/skills/typespec-api-operations/LICENSE.md +21 -0
  925. package/skills/typespec-api-operations/SKILL.md +418 -0
  926. package/skills/typespec-api-operations/SYNC.md +5 -0
  927. package/skills/typespec-create-agent/LICENSE.md +21 -0
  928. package/skills/typespec-create-agent/SKILL.md +91 -0
  929. package/skills/typespec-create-agent/SYNC.md +5 -0
  930. package/skills/typespec-create-api-plugin/LICENSE.md +21 -0
  931. package/skills/typespec-create-api-plugin/SKILL.md +164 -0
  932. package/skills/typespec-create-api-plugin/SYNC.md +5 -0
  933. package/skills/unit-test-vue-pinia/LICENSE.md +21 -0
  934. package/skills/unit-test-vue-pinia/SKILL.md +198 -0
  935. package/skills/unit-test-vue-pinia/SYNC.md +5 -0
  936. package/skills/unit-test-vue-pinia/references/pinia-patterns.md +95 -0
  937. package/skills/update-avm-modules-in-bicep/LICENSE.md +21 -0
  938. package/skills/update-avm-modules-in-bicep/SKILL.md +60 -0
  939. package/skills/update-avm-modules-in-bicep/SYNC.md +5 -0
  940. package/skills/update-implementation-plan/LICENSE.md +21 -0
  941. package/skills/update-implementation-plan/SKILL.md +157 -0
  942. package/skills/update-implementation-plan/SYNC.md +5 -0
  943. package/skills/update-llms/LICENSE.md +21 -0
  944. package/skills/update-llms/SKILL.md +216 -0
  945. package/skills/update-llms/SYNC.md +5 -0
  946. package/skills/update-markdown-file-index/LICENSE.md +21 -0
  947. package/skills/update-markdown-file-index/SKILL.md +76 -0
  948. package/skills/update-markdown-file-index/SYNC.md +5 -0
  949. package/skills/update-specification/LICENSE.md +21 -0
  950. package/skills/update-specification/SKILL.md +127 -0
  951. package/skills/update-specification/SYNC.md +5 -0
  952. package/skills/vscode-ext-commands/LICENSE.md +21 -0
  953. package/skills/vscode-ext-commands/SKILL.md +21 -0
  954. package/skills/vscode-ext-commands/SYNC.md +5 -0
  955. package/skills/vscode-ext-localization/LICENSE.md +21 -0
  956. package/skills/vscode-ext-localization/SKILL.md +25 -0
  957. package/skills/vscode-ext-localization/SYNC.md +5 -0
  958. package/skills/web-coder/LICENSE.md +21 -0
  959. package/skills/web-coder/SKILL.md +563 -0
  960. package/skills/web-coder/SYNC.md +5 -0
  961. package/skills/web-coder/references/accessibility.md +346 -0
  962. package/skills/web-coder/references/architecture-patterns.md +625 -0
  963. package/skills/web-coder/references/browsers-engines.md +358 -0
  964. package/skills/web-coder/references/css-styling.md +696 -0
  965. package/skills/web-coder/references/data-formats-encoding.md +411 -0
  966. package/skills/web-coder/references/development-tools.md +502 -0
  967. package/skills/web-coder/references/glossary.md +649 -0
  968. package/skills/web-coder/references/html-markup.md +387 -0
  969. package/skills/web-coder/references/http-networking.md +538 -0
  970. package/skills/web-coder/references/javascript-programming.md +807 -0
  971. package/skills/web-coder/references/media-graphics.md +504 -0
  972. package/skills/web-coder/references/performance-optimization.md +546 -0
  973. package/skills/web-coder/references/security-authentication.md +603 -0
  974. package/skills/web-coder/references/servers-infrastructure.md +615 -0
  975. package/skills/web-coder/references/web-apis-dom.md +654 -0
  976. package/skills/web-coder/references/web-protocols-standards.md +265 -0
  977. package/skills/web-design-reviewer/LICENSE.md +21 -0
  978. package/skills/web-design-reviewer/SKILL.md +368 -0
  979. package/skills/web-design-reviewer/SYNC.md +5 -0
  980. package/skills/web-design-reviewer/references/framework-fixes.md +475 -0
  981. package/skills/web-design-reviewer/references/visual-checklist.md +236 -0
  982. package/skills/webapp-testing/LICENSE.md +21 -0
  983. package/skills/webapp-testing/SKILL.md +104 -67
  984. package/skills/webapp-testing/SYNC.md +2 -2
  985. package/skills/webapp-testing/assets/test-helper.js +56 -0
  986. package/skills/what-context-needed/LICENSE.md +21 -0
  987. package/skills/what-context-needed/SKILL.md +39 -0
  988. package/skills/what-context-needed/SYNC.md +5 -0
  989. package/skills/winapp-cli/LICENSE.md +21 -0
  990. package/skills/winapp-cli/SKILL.md +217 -0
  991. package/skills/winapp-cli/SYNC.md +5 -0
  992. package/skills/winmd-api-search/LICENSE.md +21 -0
  993. package/skills/winmd-api-search/LICENSE.txt +21 -0
  994. package/skills/winmd-api-search/SKILL.md +192 -0
  995. package/skills/winmd-api-search/SYNC.md +5 -0
  996. package/skills/winmd-api-search/scripts/Invoke-WinMdQuery.ps1 +505 -0
  997. package/skills/winmd-api-search/scripts/Update-WinMdCache.ps1 +208 -0
  998. package/skills/winmd-api-search/scripts/cache-generator/CacheGenerator.csproj +29 -0
  999. package/skills/winmd-api-search/scripts/cache-generator/Directory.Build.props +3 -0
  1000. package/skills/winmd-api-search/scripts/cache-generator/Directory.Build.targets +3 -0
  1001. package/skills/winmd-api-search/scripts/cache-generator/Directory.Packages.props +3 -0
  1002. package/skills/winmd-api-search/scripts/cache-generator/Program.cs +1222 -0
  1003. package/skills/winui3-migration-guide/LICENSE.md +21 -0
  1004. package/skills/winui3-migration-guide/SKILL.md +277 -0
  1005. package/skills/winui3-migration-guide/SYNC.md +5 -0
  1006. package/skills/workiq-copilot/LICENSE.md +21 -0
  1007. package/skills/workiq-copilot/SKILL.md +98 -0
  1008. package/skills/workiq-copilot/SYNC.md +5 -0
  1009. package/skills/write-coding-standards-from-file/LICENSE.md +21 -0
  1010. package/skills/write-coding-standards-from-file/SKILL.md +316 -0
  1011. package/skills/write-coding-standards-from-file/SYNC.md +5 -0
  1012. package/skills/webapp-testing/LICENSE.txt +0 -202
  1013. package/skills/webapp-testing/examples/console_logging.py +0 -35
  1014. package/skills/webapp-testing/examples/element_discovery.py +0 -40
  1015. package/skills/webapp-testing/examples/static_html_automation.py +0 -33
  1016. package/skills/webapp-testing/scripts/with_server.py +0 -106
@@ -0,0 +1,2019 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Napkin — Whiteboard for Copilot</title>
7
+ <style>
8
+ *, *::before, *::after {
9
+ box-sizing: border-box;
10
+ margin: 0;
11
+ padding: 0;
12
+ }
13
+
14
+ html, body {
15
+ width: 100%;
16
+ height: 100%;
17
+ overflow: hidden;
18
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
19
+ background: #f5f5f5;
20
+ user-select: none;
21
+ -webkit-user-select: none;
22
+ }
23
+
24
+ /* ── Toolbar ───────────────────────────────────────────────────── */
25
+ #toolbar {
26
+ position: fixed;
27
+ top: 0;
28
+ left: 0;
29
+ right: 0;
30
+ height: 72px;
31
+ background: #fafafa;
32
+ border-bottom: 1px solid #e0e0e0;
33
+ display: flex;
34
+ align-items: center;
35
+ padding: 0 12px;
36
+ gap: 4px;
37
+ z-index: 1000;
38
+ box-shadow: 0 1px 3px rgba(0,0,0,0.06);
39
+ }
40
+
41
+ .toolbar-group {
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 2px;
45
+ padding: 0 6px;
46
+ }
47
+
48
+ .toolbar-group + .toolbar-group {
49
+ border-left: 1px solid #e0e0e0;
50
+ margin-left: 4px;
51
+ padding-left: 10px;
52
+ }
53
+
54
+ .tool-btn {
55
+ display: flex;
56
+ flex-direction: column;
57
+ align-items: center;
58
+ justify-content: center;
59
+ width: 56px;
60
+ height: 56px;
61
+ border: 2px solid transparent;
62
+ border-radius: 10px;
63
+ background: transparent;
64
+ cursor: pointer;
65
+ transition: all 0.15s ease;
66
+ padding: 4px 2px 2px;
67
+ }
68
+
69
+ .tool-btn:hover {
70
+ background: #eee;
71
+ }
72
+
73
+ .tool-btn.active {
74
+ background: #e3f2fd;
75
+ border-color: #1e88e5;
76
+ }
77
+
78
+ .tool-btn .icon {
79
+ font-size: 20px;
80
+ line-height: 1;
81
+ height: 24px;
82
+ display: flex;
83
+ align-items: center;
84
+ justify-content: center;
85
+ }
86
+
87
+ .tool-btn .label {
88
+ font-size: 9px;
89
+ color: #666;
90
+ margin-top: 2px;
91
+ white-space: nowrap;
92
+ font-weight: 500;
93
+ letter-spacing: 0.02em;
94
+ }
95
+
96
+ .tool-btn.active .label {
97
+ color: #1e88e5;
98
+ }
99
+
100
+ /* Color picker */
101
+ .color-picker {
102
+ display: flex;
103
+ gap: 3px;
104
+ align-items: center;
105
+ padding: 0 4px;
106
+ }
107
+
108
+ .color-swatch {
109
+ width: 22px;
110
+ height: 22px;
111
+ border-radius: 50%;
112
+ border: 2px solid #ddd;
113
+ cursor: pointer;
114
+ transition: transform 0.1s ease;
115
+ }
116
+
117
+ .color-swatch:hover {
118
+ transform: scale(1.15);
119
+ }
120
+
121
+ .color-swatch.active {
122
+ border-color: #333;
123
+ box-shadow: 0 0 0 2px #fff, 0 0 0 4px #333;
124
+ }
125
+
126
+ /* Stroke width buttons */
127
+ .stroke-btn {
128
+ display: flex;
129
+ flex-direction: column;
130
+ align-items: center;
131
+ justify-content: center;
132
+ width: 40px;
133
+ height: 40px;
134
+ border: 2px solid transparent;
135
+ border-radius: 8px;
136
+ background: transparent;
137
+ cursor: pointer;
138
+ }
139
+
140
+ .stroke-btn:hover {
141
+ background: #eee;
142
+ }
143
+
144
+ .stroke-btn.active {
145
+ background: #e3f2fd;
146
+ border-color: #1e88e5;
147
+ }
148
+
149
+ .stroke-btn .stroke-line {
150
+ background: #333;
151
+ border-radius: 4px;
152
+ width: 20px;
153
+ }
154
+
155
+ .stroke-btn .label {
156
+ font-size: 8px;
157
+ color: #888;
158
+ margin-top: 2px;
159
+ }
160
+
161
+ /* Share button */
162
+ .share-btn {
163
+ display: flex;
164
+ align-items: center;
165
+ gap: 8px;
166
+ padding: 10px 20px;
167
+ background: #0d9488;
168
+ color: #fff;
169
+ border: none;
170
+ border-radius: 10px;
171
+ font-size: 14px;
172
+ font-weight: 600;
173
+ cursor: pointer;
174
+ transition: background 0.15s ease, transform 0.1s ease;
175
+ margin-left: auto;
176
+ white-space: nowrap;
177
+ box-shadow: 0 2px 8px rgba(13,148,136,0.3);
178
+ font-family: inherit;
179
+ }
180
+
181
+ .share-btn:hover {
182
+ background: #0f766e;
183
+ transform: translateY(-1px);
184
+ }
185
+
186
+ .share-btn:active {
187
+ transform: translateY(0);
188
+ }
189
+
190
+ .share-btn .icon {
191
+ font-size: 18px;
192
+ }
193
+
194
+ /* Help button */
195
+ .help-btn {
196
+ width: 36px;
197
+ height: 36px;
198
+ border-radius: 50%;
199
+ border: 2px solid #ccc;
200
+ background: #fff;
201
+ color: #888;
202
+ font-size: 16px;
203
+ font-weight: 700;
204
+ cursor: pointer;
205
+ display: flex;
206
+ align-items: center;
207
+ justify-content: center;
208
+ margin-left: 8px;
209
+ flex-shrink: 0;
210
+ font-family: inherit;
211
+ }
212
+
213
+ .help-btn:hover {
214
+ border-color: #999;
215
+ color: #555;
216
+ }
217
+
218
+ /* ── Canvas area ───────────────────────────────────────────────── */
219
+ #canvas-container {
220
+ position: fixed;
221
+ top: 72px;
222
+ left: 0;
223
+ right: 0;
224
+ bottom: 0;
225
+ overflow: hidden;
226
+ background: #f0f0f0;
227
+ cursor: crosshair;
228
+ }
229
+
230
+ #canvas-container.panning {
231
+ cursor: grab;
232
+ }
233
+
234
+ #canvas-container.panning:active {
235
+ cursor: grabbing;
236
+ }
237
+
238
+ #drawing-canvas {
239
+ position: absolute;
240
+ background: #fff;
241
+ box-shadow: 0 2px 20px rgba(0,0,0,0.08);
242
+ }
243
+
244
+ /* ── Sticky notes ──────────────────────────────────────────────── */
245
+ .sticky-note {
246
+ position: absolute;
247
+ min-width: 140px;
248
+ min-height: 100px;
249
+ border-radius: 4px;
250
+ box-shadow: 2px 3px 12px rgba(0,0,0,0.12), 0 1px 4px rgba(0,0,0,0.06);
251
+ display: flex;
252
+ flex-direction: column;
253
+ z-index: 500;
254
+ font-family: inherit;
255
+ }
256
+
257
+ .sticky-note .note-header {
258
+ height: 24px;
259
+ border-radius: 4px 4px 0 0;
260
+ cursor: move;
261
+ display: flex;
262
+ align-items: center;
263
+ justify-content: flex-end;
264
+ padding: 0 4px;
265
+ flex-shrink: 0;
266
+ opacity: 0.8;
267
+ }
268
+
269
+ .sticky-note .note-delete {
270
+ width: 18px;
271
+ height: 18px;
272
+ border: none;
273
+ background: rgba(0,0,0,0.15);
274
+ color: rgba(0,0,0,0.5);
275
+ border-radius: 50%;
276
+ font-size: 12px;
277
+ line-height: 1;
278
+ cursor: pointer;
279
+ display: flex;
280
+ align-items: center;
281
+ justify-content: center;
282
+ opacity: 0;
283
+ transition: opacity 0.15s;
284
+ font-family: inherit;
285
+ }
286
+
287
+ .sticky-note:hover .note-delete {
288
+ opacity: 1;
289
+ }
290
+
291
+ .sticky-note .note-delete:hover {
292
+ background: rgba(0,0,0,0.3);
293
+ color: rgba(0,0,0,0.8);
294
+ }
295
+
296
+ .sticky-note .note-body {
297
+ flex: 1;
298
+ padding: 8px 12px 12px;
299
+ font-size: 14px;
300
+ line-height: 1.4;
301
+ outline: none;
302
+ cursor: text;
303
+ overflow-wrap: break-word;
304
+ word-break: break-word;
305
+ white-space: pre-wrap;
306
+ border-radius: 0 0 4px 4px;
307
+ min-height: 76px;
308
+ }
309
+
310
+ .sticky-note .note-resize {
311
+ position: absolute;
312
+ bottom: 0;
313
+ right: 0;
314
+ width: 16px;
315
+ height: 16px;
316
+ cursor: nwse-resize;
317
+ opacity: 0;
318
+ transition: opacity 0.15s;
319
+ }
320
+
321
+ .sticky-note:hover .note-resize {
322
+ opacity: 0.4;
323
+ }
324
+
325
+ .sticky-note .note-resize::after {
326
+ content: '';
327
+ position: absolute;
328
+ bottom: 3px;
329
+ right: 3px;
330
+ width: 8px;
331
+ height: 8px;
332
+ border-right: 2px solid rgba(0,0,0,0.3);
333
+ border-bottom: 2px solid rgba(0,0,0,0.3);
334
+ }
335
+
336
+ /* Sticky note colors */
337
+ .sticky-yellow { background: #fff9c4; }
338
+ .sticky-yellow .note-header { background: #fff176; }
339
+ .sticky-pink { background: #fce4ec; }
340
+ .sticky-pink .note-header { background: #f48fb1; }
341
+ .sticky-blue { background: #e3f2fd; }
342
+ .sticky-blue .note-header { background: #90caf9; }
343
+ .sticky-green { background: #e8f5e9; }
344
+ .sticky-green .note-header { background: #a5d6a7; }
345
+
346
+ /* Sticky note color picker in toolbar */
347
+ .note-color-picker {
348
+ display: none;
349
+ position: absolute;
350
+ top: 60px;
351
+ background: #fff;
352
+ border-radius: 10px;
353
+ padding: 8px;
354
+ box-shadow: 0 4px 16px rgba(0,0,0,0.15);
355
+ gap: 6px;
356
+ z-index: 1001;
357
+ }
358
+
359
+ .note-color-picker.show {
360
+ display: flex;
361
+ }
362
+
363
+ .note-color-opt {
364
+ width: 30px;
365
+ height: 30px;
366
+ border-radius: 6px;
367
+ border: 2px solid #ddd;
368
+ cursor: pointer;
369
+ }
370
+
371
+ .note-color-opt:hover {
372
+ border-color: #999;
373
+ }
374
+
375
+ /* ── Text labels on canvas ─────────────────────────────────────── */
376
+ .canvas-text-label {
377
+ position: absolute;
378
+ font-size: 16px;
379
+ color: #333;
380
+ outline: none;
381
+ cursor: text;
382
+ padding: 2px 4px;
383
+ min-width: 20px;
384
+ min-height: 20px;
385
+ white-space: pre-wrap;
386
+ z-index: 400;
387
+ border: 1px dashed transparent;
388
+ border-radius: 3px;
389
+ font-family: inherit;
390
+ background: transparent;
391
+ }
392
+
393
+ .canvas-text-label:focus {
394
+ border-color: #90caf9;
395
+ background: rgba(255,255,255,0.85);
396
+ }
397
+
398
+ /* ── Overlays ──────────────────────────────────────────────────── */
399
+ .overlay-backdrop {
400
+ position: fixed;
401
+ inset: 0;
402
+ background: rgba(0,0,0,0.45);
403
+ display: flex;
404
+ align-items: center;
405
+ justify-content: center;
406
+ z-index: 9999;
407
+ }
408
+
409
+ .overlay-backdrop.hidden {
410
+ display: none;
411
+ }
412
+
413
+ .overlay-card {
414
+ background: #fff;
415
+ border-radius: 16px;
416
+ padding: 40px 44px;
417
+ max-width: 500px;
418
+ width: 90%;
419
+ box-shadow: 0 16px 48px rgba(0,0,0,0.18);
420
+ text-align: center;
421
+ }
422
+
423
+ .overlay-card h1 {
424
+ font-size: 26px;
425
+ font-weight: 700;
426
+ color: #222;
427
+ margin-bottom: 8px;
428
+ }
429
+
430
+ .overlay-card .subtitle {
431
+ font-size: 15px;
432
+ color: #666;
433
+ margin-bottom: 24px;
434
+ }
435
+
436
+ .overlay-card .steps {
437
+ text-align: left;
438
+ margin: 0 auto 28px;
439
+ max-width: 380px;
440
+ }
441
+
442
+ .overlay-card .steps .step {
443
+ display: flex;
444
+ gap: 12px;
445
+ margin-bottom: 14px;
446
+ font-size: 14px;
447
+ line-height: 1.5;
448
+ color: #444;
449
+ }
450
+
451
+ .overlay-card .steps .step-num {
452
+ flex-shrink: 0;
453
+ width: 26px;
454
+ height: 26px;
455
+ background: #0d9488;
456
+ color: #fff;
457
+ border-radius: 50%;
458
+ display: flex;
459
+ align-items: center;
460
+ justify-content: center;
461
+ font-size: 13px;
462
+ font-weight: 700;
463
+ }
464
+
465
+ .overlay-card .cta-btn {
466
+ display: inline-block;
467
+ padding: 14px 32px;
468
+ background: #0d9488;
469
+ color: #fff;
470
+ border: none;
471
+ border-radius: 10px;
472
+ font-size: 16px;
473
+ font-weight: 600;
474
+ cursor: pointer;
475
+ transition: background 0.15s ease;
476
+ font-family: inherit;
477
+ }
478
+
479
+ .overlay-card .cta-btn:hover {
480
+ background: #0f766e;
481
+ }
482
+
483
+ /* Share confirmation */
484
+ .overlay-card .confirm-icon {
485
+ font-size: 48px;
486
+ margin-bottom: 12px;
487
+ }
488
+
489
+ .overlay-card .confirm-detail {
490
+ text-align: left;
491
+ background: #f5f5f5;
492
+ border-radius: 10px;
493
+ padding: 16px 20px;
494
+ margin: 16px 0 24px;
495
+ font-size: 13px;
496
+ line-height: 1.7;
497
+ color: #555;
498
+ }
499
+
500
+ .overlay-card .confirm-detail .clipboard-hint {
501
+ display: inline-block;
502
+ background: #e8f5e9;
503
+ color: #2e7d32;
504
+ padding: 2px 8px;
505
+ border-radius: 4px;
506
+ font-family: monospace;
507
+ font-size: 13px;
508
+ margin-top: 4px;
509
+ }
510
+
511
+ /* ── Keyboard shortcuts panel ──────────────────────────────────── */
512
+ .shortcuts-panel {
513
+ position: fixed;
514
+ bottom: 16px;
515
+ right: 16px;
516
+ background: #fff;
517
+ border-radius: 12px;
518
+ padding: 16px 20px;
519
+ box-shadow: 0 4px 20px rgba(0,0,0,0.12);
520
+ z-index: 1001;
521
+ font-size: 12px;
522
+ display: none;
523
+ min-width: 220px;
524
+ }
525
+
526
+ .shortcuts-panel.show {
527
+ display: block;
528
+ }
529
+
530
+ .shortcuts-panel h3 {
531
+ font-size: 13px;
532
+ font-weight: 700;
533
+ margin-bottom: 10px;
534
+ color: #333;
535
+ }
536
+
537
+ .shortcuts-panel .shortcut-row {
538
+ display: flex;
539
+ justify-content: space-between;
540
+ padding: 3px 0;
541
+ color: #555;
542
+ }
543
+
544
+ .shortcuts-panel .shortcut-row kbd {
545
+ background: #f0f0f0;
546
+ border: 1px solid #ddd;
547
+ border-radius: 4px;
548
+ padding: 1px 6px;
549
+ font-family: monospace;
550
+ font-size: 11px;
551
+ color: #444;
552
+ }
553
+
554
+ .shortcuts-panel .close-shortcuts {
555
+ position: absolute;
556
+ top: 8px;
557
+ right: 10px;
558
+ border: none;
559
+ background: none;
560
+ cursor: pointer;
561
+ font-size: 16px;
562
+ color: #999;
563
+ }
564
+
565
+ /* ── Zoom indicator ────────────────────────────────────────────── */
566
+ .zoom-indicator {
567
+ position: fixed;
568
+ bottom: 16px;
569
+ left: 16px;
570
+ display: flex;
571
+ align-items: center;
572
+ gap: 6px;
573
+ background: #fff;
574
+ border-radius: 8px;
575
+ padding: 6px 12px;
576
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
577
+ font-size: 12px;
578
+ color: #555;
579
+ z-index: 1001;
580
+ }
581
+
582
+ .zoom-indicator button {
583
+ width: 26px;
584
+ height: 26px;
585
+ border: 1px solid #ddd;
586
+ border-radius: 6px;
587
+ background: #fff;
588
+ cursor: pointer;
589
+ font-size: 14px;
590
+ display: flex;
591
+ align-items: center;
592
+ justify-content: center;
593
+ color: #555;
594
+ font-family: inherit;
595
+ }
596
+
597
+ .zoom-indicator button:hover {
598
+ background: #f5f5f5;
599
+ }
600
+
601
+ /* ── Toast notification ────────────────────────────────────────── */
602
+ .toast {
603
+ position: fixed;
604
+ bottom: 60px;
605
+ left: 50%;
606
+ transform: translateX(-50%) translateY(20px);
607
+ background: #333;
608
+ color: #fff;
609
+ padding: 10px 20px;
610
+ border-radius: 8px;
611
+ font-size: 13px;
612
+ opacity: 0;
613
+ transition: all 0.3s ease;
614
+ z-index: 9998;
615
+ pointer-events: none;
616
+ }
617
+
618
+ .toast.show {
619
+ opacity: 1;
620
+ transform: translateX(-50%) translateY(0);
621
+ }
622
+ </style>
623
+ </head>
624
+ <body>
625
+
626
+ <!-- ── Toolbar ──────────────────────────────────────────────────── -->
627
+ <div id="toolbar">
628
+ <!-- Drawing tools -->
629
+ <div class="toolbar-group">
630
+ <button class="tool-btn active" data-tool="select" title="Select / Move (V)">
631
+ <span class="icon">
632
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 3l14 9-7 2-4 7z"/></svg>
633
+ </span>
634
+ <span class="label">Select</span>
635
+ </button>
636
+ <button class="tool-btn" data-tool="pen" title="Pen (P)">
637
+ <span class="icon">
638
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 013 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
639
+ </span>
640
+ <span class="label">Pen</span>
641
+ </button>
642
+ <button class="tool-btn" data-tool="line" title="Line (L)">
643
+ <span class="icon">
644
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="5" y1="19" x2="19" y2="5"/></svg>
645
+ </span>
646
+ <span class="label">Line</span>
647
+ </button>
648
+ <button class="tool-btn" data-tool="arrow" title="Arrow (A)">
649
+ <span class="icon">
650
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="5" y1="19" x2="19" y2="5"/><polyline points="10 5 19 5 19 14"/></svg>
651
+ </span>
652
+ <span class="label">Arrow</span>
653
+ </button>
654
+ <button class="tool-btn" data-tool="rect" title="Rectangle (R)">
655
+ <span class="icon">
656
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="5" width="18" height="14" rx="2"/></svg>
657
+ </span>
658
+ <span class="label">Rect</span>
659
+ </button>
660
+ <button class="tool-btn" data-tool="ellipse" title="Circle (C)">
661
+ <span class="icon">
662
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><ellipse cx="12" cy="12" rx="10" ry="8"/></svg>
663
+ </span>
664
+ <span class="label">Circle</span>
665
+ </button>
666
+ <button class="tool-btn" data-tool="eraser" title="Eraser (E)">
667
+ <span class="icon">
668
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 20H7L3 16l9-9 8 8-4 5z"/><path d="M6 11l8 8"/></svg>
669
+ </span>
670
+ <span class="label">Eraser</span>
671
+ </button>
672
+ </div>
673
+
674
+ <!-- Text & Notes -->
675
+ <div class="toolbar-group">
676
+ <button class="tool-btn" data-tool="text" title="Text (T)">
677
+ <span class="icon">
678
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 7 4 4 20 4 20 7"/><line x1="12" y1="4" x2="12" y2="20"/><line x1="8" y1="20" x2="16" y2="20"/></svg>
679
+ </span>
680
+ <span class="label">Text</span>
681
+ </button>
682
+ <button class="tool-btn" data-tool="note" id="note-tool-btn" title="Sticky Note (N)">
683
+ <span class="icon">
684
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M14 3v8h8"/></svg>
685
+ </span>
686
+ <span class="label">Note</span>
687
+ </button>
688
+ <div class="note-color-picker" id="note-color-picker">
689
+ <div class="note-color-opt" data-note-color="yellow" style="background:#fff9c4;" title="Yellow"></div>
690
+ <div class="note-color-opt" data-note-color="pink" style="background:#fce4ec;" title="Pink"></div>
691
+ <div class="note-color-opt" data-note-color="blue" style="background:#e3f2fd;" title="Blue"></div>
692
+ <div class="note-color-opt" data-note-color="green" style="background:#e8f5e9;" title="Green"></div>
693
+ </div>
694
+ </div>
695
+
696
+ <!-- Color & stroke -->
697
+ <div class="toolbar-group">
698
+ <div class="color-picker">
699
+ <div class="color-swatch active" data-color="#222222" style="background:#222222;" title="Black"></div>
700
+ <div class="color-swatch" data-color="#e53935" style="background:#e53935;" title="Red"></div>
701
+ <div class="color-swatch" data-color="#1e88e5" style="background:#1e88e5;" title="Blue"></div>
702
+ <div class="color-swatch" data-color="#43a047" style="background:#43a047;" title="Green"></div>
703
+ <div class="color-swatch" data-color="#fb8c00" style="background:#fb8c00;" title="Orange"></div>
704
+ <div class="color-swatch" data-color="#8e24aa" style="background:#8e24aa;" title="Purple"></div>
705
+ </div>
706
+ </div>
707
+
708
+ <div class="toolbar-group">
709
+ <button class="stroke-btn active" data-stroke="2" title="Thin">
710
+ <div class="stroke-line" style="height:2px;"></div>
711
+ <span class="label">Thin</span>
712
+ </button>
713
+ <button class="stroke-btn" data-stroke="4" title="Medium">
714
+ <div class="stroke-line" style="height:4px;"></div>
715
+ <span class="label">Med</span>
716
+ </button>
717
+ <button class="stroke-btn" data-stroke="7" title="Thick">
718
+ <div class="stroke-line" style="height:7px;"></div>
719
+ <span class="label">Thick</span>
720
+ </button>
721
+ </div>
722
+
723
+ <!-- Undo / Redo -->
724
+ <div class="toolbar-group">
725
+ <button class="tool-btn" id="undo-btn" title="Undo (Ctrl/Cmd+Z)">
726
+ <span class="icon">
727
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 105.64-10.36L1 10"/></svg>
728
+ </span>
729
+ <span class="label">Undo</span>
730
+ </button>
731
+ <button class="tool-btn" id="redo-btn" title="Redo (Ctrl/Cmd+Shift+Z)">
732
+ <span class="icon">
733
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-5.64-10.36L23 10"/></svg>
734
+ </span>
735
+ <span class="label">Redo</span>
736
+ </button>
737
+ </div>
738
+
739
+ <!-- Share button -->
740
+ <button class="share-btn" id="share-btn">
741
+ <span class="icon">&#9993;</span>
742
+ Share with Copilot
743
+ </button>
744
+
745
+ <!-- Help -->
746
+ <button class="help-btn" id="help-btn" title="Help">?</button>
747
+ </div>
748
+
749
+ <!-- ── Canvas ──────────────────────────────────────────────────── -->
750
+ <div id="canvas-container">
751
+ <canvas id="drawing-canvas"></canvas>
752
+ </div>
753
+
754
+ <!-- ── Onboarding overlay ──────────────────────────────────────── -->
755
+ <div class="overlay-backdrop" id="onboarding-overlay">
756
+ <div class="overlay-card">
757
+ <h1>Welcome to Napkin!</h1>
758
+ <p class="subtitle">Your whiteboard for brainstorming with Copilot.</p>
759
+ <div class="steps">
760
+ <div class="step">
761
+ <div class="step-num">1</div>
762
+ <div>Draw, sketch, or add sticky notes &mdash; whatever helps you think</div>
763
+ </div>
764
+ <div class="step">
765
+ <div class="step-num">2</div>
766
+ <div>When you're ready, click <strong>"Share with Copilot"</strong> (the green button)</div>
767
+ </div>
768
+ <div class="step">
769
+ <div class="step-num">3</div>
770
+ <div>Go back to your terminal and say <strong>"check the napkin"</strong></div>
771
+ </div>
772
+ <div class="step">
773
+ <div class="step-num">4</div>
774
+ <div>Copilot will look at your whiteboard and respond</div>
775
+ </div>
776
+ </div>
777
+ <p style="font-size:14px;color:#888;margin-bottom:20px;">That's it. Let's go!</p>
778
+ <button class="cta-btn" id="onboarding-dismiss">Got it &mdash; start drawing</button>
779
+ </div>
780
+ </div>
781
+
782
+ <!-- ── Share confirmation overlay ──────────────────────────────── -->
783
+ <div class="overlay-backdrop hidden" id="share-overlay">
784
+ <div class="overlay-card">
785
+ <div class="confirm-icon">&#10004;&#65039;</div>
786
+ <h1>Shared with Copilot!</h1>
787
+ <div class="confirm-detail">
788
+ &#128190; A screenshot was saved (check your Downloads or Desktop).<br>
789
+ &#128203; The text content was copied to your clipboard.<br><br>
790
+ Go back to Copilot CLI and say:<br>
791
+ <span class="clipboard-hint">"check the napkin"</span>
792
+ </div>
793
+ <button class="cta-btn" id="share-overlay-close">Got it</button>
794
+ </div>
795
+ </div>
796
+
797
+ <!-- ── Keyboard shortcuts panel ────────────────────────────────── -->
798
+ <div class="shortcuts-panel" id="shortcuts-panel">
799
+ <button class="close-shortcuts" id="close-shortcuts">&times;</button>
800
+ <h3>Keyboard Shortcuts</h3>
801
+ <div class="shortcut-row"><span>Select / Move</span><kbd>V</kbd></div>
802
+ <div class="shortcut-row"><span>Pen</span><kbd>P</kbd></div>
803
+ <div class="shortcut-row"><span>Rectangle</span><kbd>R</kbd></div>
804
+ <div class="shortcut-row"><span>Circle</span><kbd>C</kbd></div>
805
+ <div class="shortcut-row"><span>Arrow</span><kbd>A</kbd></div>
806
+ <div class="shortcut-row"><span>Line</span><kbd>L</kbd></div>
807
+ <div class="shortcut-row"><span>Text</span><kbd>T</kbd></div>
808
+ <div class="shortcut-row"><span>Sticky Note</span><kbd>N</kbd></div>
809
+ <div class="shortcut-row"><span>Eraser</span><kbd>E</kbd></div>
810
+ <div class="shortcut-row"><span>Undo</span><kbd>Ctrl/Cmd+Z</kbd></div>
811
+ <div class="shortcut-row"><span>Redo</span><kbd>Ctrl/Cmd+Shift+Z</kbd></div>
812
+ <div class="shortcut-row"><span>Pan canvas</span><kbd>Space+Drag</kbd></div>
813
+ </div>
814
+
815
+ <!-- ── Zoom indicator ──────────────────────────────────────────── -->
816
+ <div class="zoom-indicator">
817
+ <button id="zoom-out-btn" title="Zoom out">&minus;</button>
818
+ <span id="zoom-level">100%</span>
819
+ <button id="zoom-in-btn" title="Zoom in">+</button>
820
+ <button id="fit-btn" title="Fit to content" style="font-size:11px;width:auto;padding:0 8px;">Fit</button>
821
+ </div>
822
+
823
+ <!-- ── Toast ───────────────────────────────────────────────────── -->
824
+ <div class="toast" id="toast"></div>
825
+
826
+ <script>
827
+ // ═══════════════════════════════════════════════════════════════════
828
+ // NAPKIN — Self-contained whiteboard for Copilot collaboration
829
+ // ═══════════════════════════════════════════════════════════════════
830
+
831
+ (function () {
832
+ 'use strict';
833
+
834
+ // ── DOM references ───────────────────────────────────────────────
835
+ const container = document.getElementById('canvas-container');
836
+ const canvas = document.getElementById('drawing-canvas');
837
+ const ctx = canvas.getContext('2d');
838
+ const toolbar = document.getElementById('toolbar');
839
+ const toastEl = document.getElementById('toast');
840
+ const onboarding = document.getElementById('onboarding-overlay');
841
+ const shareOverlay = document.getElementById('share-overlay');
842
+ const noteColorPicker = document.getElementById('note-color-picker');
843
+
844
+ // ── State ────────────────────────────────────────────────────────
845
+ const CANVAS_W = 3840;
846
+ const CANVAS_H = 2160;
847
+
848
+ let currentTool = 'select';
849
+ let currentColor = '#222222';
850
+ let currentStroke = 2;
851
+ let noteColor = 'yellow';
852
+
853
+ // View transform
854
+ let viewX = 0, viewY = 0, viewScale = 1;
855
+
856
+ // Drawing state
857
+ let isDrawing = false;
858
+ let isPanning = false;
859
+ let spaceHeld = false;
860
+ let eraserDidErase = false;
861
+ let panStartX = 0, panStartY = 0;
862
+ let panViewStartX = 0, panViewStartY = 0;
863
+
864
+ // Objects
865
+ let drawingObjects = []; // { type, points?, x?, y?, ... }
866
+ let stickyNotes = []; // { id, text, x, y, w, h, color }
867
+ let textLabels = []; // { id, text, x, y, fontSize }
868
+
869
+ // Current in-progress drawing
870
+ let currentPath = null;
871
+
872
+ // Undo/redo stacks
873
+ let undoStack = [];
874
+ let redoStack = [];
875
+
876
+ // Unique ID counter
877
+ let idCounter = Date.now();
878
+ function uid() { return 'n' + (idCounter++); }
879
+
880
+ // ── Utility ──────────────────────────────────────────────────────
881
+ function screenToCanvas(sx, sy) {
882
+ const rect = container.getBoundingClientRect();
883
+ return {
884
+ x: (sx - rect.left - viewX) / viewScale,
885
+ y: (sy - rect.top - viewY) / viewScale
886
+ };
887
+ }
888
+
889
+ function showToast(msg, duration) {
890
+ toastEl.textContent = msg;
891
+ toastEl.classList.add('show');
892
+ clearTimeout(showToast._t);
893
+ showToast._t = setTimeout(() => toastEl.classList.remove('show'), duration || 2500);
894
+ }
895
+
896
+ // ── Onboarding ───────────────────────────────────────────────────
897
+ function initOnboarding() {
898
+ if (localStorage.getItem('napkin_onboarded')) {
899
+ onboarding.classList.add('hidden');
900
+ }
901
+ document.getElementById('onboarding-dismiss').addEventListener('click', () => {
902
+ onboarding.classList.add('hidden');
903
+ localStorage.setItem('napkin_onboarded', '1');
904
+ });
905
+ document.getElementById('help-btn').addEventListener('click', () => {
906
+ onboarding.classList.remove('hidden');
907
+ });
908
+ }
909
+
910
+ // ── Canvas setup ─────────────────────────────────────────────────
911
+ function initCanvas() {
912
+ canvas.width = CANVAS_W;
913
+ canvas.height = CANVAS_H;
914
+ centerView();
915
+ render();
916
+ }
917
+
918
+ function centerView() {
919
+ const cw = container.clientWidth;
920
+ const ch = container.clientHeight;
921
+ viewScale = Math.min(cw / CANVAS_W, ch / CANVAS_H, 1) * 0.9;
922
+ viewX = (cw - CANVAS_W * viewScale) / 2;
923
+ viewY = (ch - CANVAS_H * viewScale) / 2;
924
+ updateCanvasTransform();
925
+ }
926
+
927
+ function updateCanvasTransform() {
928
+ canvas.style.left = viewX + 'px';
929
+ canvas.style.top = viewY + 'px';
930
+ canvas.style.width = (CANVAS_W * viewScale) + 'px';
931
+ canvas.style.height = (CANVAS_H * viewScale) + 'px';
932
+ document.getElementById('zoom-level').textContent = Math.round(viewScale * 100) + '%';
933
+
934
+ // Reposition sticky notes and text labels
935
+ repositionOverlays();
936
+ }
937
+
938
+ function repositionOverlays() {
939
+ document.querySelectorAll('.sticky-note').forEach(el => {
940
+ const note = stickyNotes.find(n => n.id === el.dataset.noteId);
941
+ if (!note) return;
942
+ el.style.left = (viewX + note.x * viewScale) + 'px';
943
+ el.style.top = (viewY + note.y * viewScale) + 'px';
944
+ el.style.width = (note.w * viewScale) + 'px';
945
+ el.style.height = (note.h * viewScale) + 'px';
946
+ el.style.fontSize = (14 * viewScale) + 'px';
947
+ });
948
+ document.querySelectorAll('.canvas-text-label').forEach(el => {
949
+ const lbl = textLabels.find(l => l.id === el.dataset.labelId);
950
+ if (!lbl) return;
951
+ el.style.left = (viewX + lbl.x * viewScale) + 'px';
952
+ el.style.top = (viewY + lbl.y * viewScale) + 'px';
953
+ el.style.fontSize = (lbl.fontSize * viewScale) + 'px';
954
+ });
955
+ }
956
+
957
+ // ── Render canvas objects ────────────────────────────────────────
958
+ function render() {
959
+ ctx.clearRect(0, 0, CANVAS_W, CANVAS_H);
960
+ ctx.fillStyle = '#ffffff';
961
+ ctx.fillRect(0, 0, CANVAS_W, CANVAS_H);
962
+
963
+ // Draw grid (very subtle)
964
+ ctx.strokeStyle = '#f0f0f0';
965
+ ctx.lineWidth = 1;
966
+ for (let x = 0; x < CANVAS_W; x += 40) {
967
+ ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, CANVAS_H); ctx.stroke();
968
+ }
969
+ for (let y = 0; y < CANVAS_H; y += 40) {
970
+ ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(CANVAS_W, y); ctx.stroke();
971
+ }
972
+
973
+ // Draw all objects
974
+ drawingObjects.forEach(obj => drawObject(ctx, obj));
975
+
976
+ // Draw current in-progress path
977
+ if (currentPath) {
978
+ drawObject(ctx, currentPath);
979
+ }
980
+ }
981
+
982
+ function drawObject(c, obj) {
983
+ c.lineCap = 'round';
984
+ c.lineJoin = 'round';
985
+
986
+ switch (obj.type) {
987
+ case 'pen': {
988
+ if (obj.points.length < 2) return;
989
+ c.strokeStyle = obj.color;
990
+ c.lineWidth = obj.stroke;
991
+ c.beginPath();
992
+ c.moveTo(obj.points[0].x, obj.points[0].y);
993
+ for (let i = 1; i < obj.points.length; i++) {
994
+ c.lineTo(obj.points[i].x, obj.points[i].y);
995
+ }
996
+ c.stroke();
997
+ break;
998
+ }
999
+ case 'line': {
1000
+ c.strokeStyle = obj.color;
1001
+ c.lineWidth = obj.stroke;
1002
+ c.beginPath();
1003
+ c.moveTo(obj.x1, obj.y1);
1004
+ c.lineTo(obj.x2, obj.y2);
1005
+ c.stroke();
1006
+ break;
1007
+ }
1008
+ case 'arrow': {
1009
+ c.strokeStyle = obj.color;
1010
+ c.lineWidth = obj.stroke;
1011
+ c.fillStyle = obj.color;
1012
+ c.beginPath();
1013
+ c.moveTo(obj.x1, obj.y1);
1014
+ c.lineTo(obj.x2, obj.y2);
1015
+ c.stroke();
1016
+ // Arrowhead
1017
+ const angle = Math.atan2(obj.y2 - obj.y1, obj.x2 - obj.x1);
1018
+ const headLen = 12 + obj.stroke * 2;
1019
+ c.beginPath();
1020
+ c.moveTo(obj.x2, obj.y2);
1021
+ c.lineTo(obj.x2 - headLen * Math.cos(angle - 0.4), obj.y2 - headLen * Math.sin(angle - 0.4));
1022
+ c.lineTo(obj.x2 - headLen * Math.cos(angle + 0.4), obj.y2 - headLen * Math.sin(angle + 0.4));
1023
+ c.closePath();
1024
+ c.fill();
1025
+ break;
1026
+ }
1027
+ case 'rect': {
1028
+ c.strokeStyle = obj.color;
1029
+ c.lineWidth = obj.stroke;
1030
+ c.beginPath();
1031
+ c.rect(obj.x, obj.y, obj.w, obj.h);
1032
+ c.stroke();
1033
+ break;
1034
+ }
1035
+ case 'ellipse': {
1036
+ c.strokeStyle = obj.color;
1037
+ c.lineWidth = obj.stroke;
1038
+ c.beginPath();
1039
+ const cx = obj.x + obj.w / 2;
1040
+ const cy = obj.y + obj.h / 2;
1041
+ c.ellipse(cx, cy, Math.abs(obj.w / 2), Math.abs(obj.h / 2), 0, 0, Math.PI * 2);
1042
+ c.stroke();
1043
+ break;
1044
+ }
1045
+ }
1046
+ }
1047
+
1048
+ // ── Shape recognition ────────────────────────────────────────────
1049
+ function recognizeShape(points) {
1050
+ if (points.length < 10) return null;
1051
+
1052
+ const first = points[0];
1053
+ const last = points[points.length - 1];
1054
+ const dist = Math.hypot(last.x - first.x, last.y - first.y);
1055
+
1056
+ // Bounding box
1057
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
1058
+ points.forEach(p => {
1059
+ if (p.x < minX) minX = p.x;
1060
+ if (p.y < minY) minY = p.y;
1061
+ if (p.x > maxX) maxX = p.x;
1062
+ if (p.y > maxY) maxY = p.y;
1063
+ });
1064
+ const bw = maxX - minX;
1065
+ const bh = maxY - minY;
1066
+ const diagonal = Math.hypot(bw, bh);
1067
+
1068
+ // Check if path closes (endpoints near each other relative to size)
1069
+ if (dist > diagonal * 0.25) return null;
1070
+
1071
+ // Compute total path length
1072
+ let pathLen = 0;
1073
+ for (let i = 1; i < points.length; i++) {
1074
+ pathLen += Math.hypot(points[i].x - points[i - 1].x, points[i].y - points[i - 1].y);
1075
+ }
1076
+
1077
+ // Skip tiny shapes
1078
+ if (bw < 20 || bh < 20) return null;
1079
+
1080
+ // Check rectangularity by analyzing corner angles
1081
+ const cx = (minX + maxX) / 2;
1082
+ const cy = (minY + maxY) / 2;
1083
+
1084
+ // Measure how well points fit an ellipse vs a rectangle
1085
+ let ellipseError = 0;
1086
+ let rectError = 0;
1087
+ const rx = bw / 2;
1088
+ const ry = bh / 2;
1089
+
1090
+ points.forEach(p => {
1091
+ // Ellipse error: distance from ellipse boundary
1092
+ const dx = (p.x - cx) / rx;
1093
+ const dy = (p.y - cy) / ry;
1094
+ const r = Math.sqrt(dx * dx + dy * dy);
1095
+ ellipseError += Math.abs(r - 1);
1096
+
1097
+ // Rectangle error: distance from nearest rectangle edge
1098
+ const distToLeft = Math.abs(p.x - minX);
1099
+ const distToRight = Math.abs(p.x - maxX);
1100
+ const distToTop = Math.abs(p.y - minY);
1101
+ const distToBottom = Math.abs(p.y - maxY);
1102
+ rectError += Math.min(distToLeft, distToRight, distToTop, distToBottom);
1103
+ });
1104
+
1105
+ ellipseError /= points.length;
1106
+ rectError /= points.length;
1107
+
1108
+ // Normalize errors
1109
+ const normEllipse = ellipseError;
1110
+ const normRect = rectError / Math.max(bw, bh) * 4;
1111
+
1112
+ if (normEllipse < 0.35 && normEllipse < normRect) {
1113
+ return { type: 'ellipse', x: minX, y: minY, w: bw, h: bh };
1114
+ }
1115
+
1116
+ if (normRect < 0.25) {
1117
+ return { type: 'rect', x: minX, y: minY, w: bw, h: bh };
1118
+ }
1119
+
1120
+ return null;
1121
+ }
1122
+
1123
+ // ── roundRect fallback for older browsers ──────────────────────
1124
+ function safeRoundRect(ctx, x, y, w, h, radii) {
1125
+ if (typeof ctx.roundRect === 'function') {
1126
+ ctx.roundRect(x, y, w, h, radii);
1127
+ return;
1128
+ }
1129
+ const r = Array.isArray(radii) ? radii : [radii, radii, radii, radii];
1130
+ const [tl, tr, br, bl] = r.length === 4 ? r : r.length === 2 ? [r[0], r[1], r[0], r[1]] : [r[0], r[0], r[0], r[0]];
1131
+ ctx.moveTo(x + tl, y);
1132
+ ctx.lineTo(x + w - tr, y);
1133
+ ctx.arcTo(x + w, y, x + w, y + tr, tr);
1134
+ ctx.lineTo(x + w, y + h - br);
1135
+ ctx.arcTo(x + w, y + h, x + w - br, y + h, br);
1136
+ ctx.lineTo(x + bl, y + h);
1137
+ ctx.arcTo(x, y + h, x, y + h - bl, bl);
1138
+ ctx.lineTo(x, y + tl);
1139
+ ctx.arcTo(x, y, x + tl, y, tl);
1140
+ ctx.closePath();
1141
+ }
1142
+
1143
+ // ── Eraser ───────────────────────────────────────────────────────
1144
+ function eraseAt(cx, cy, radius) {
1145
+ const r2 = radius * radius;
1146
+ const before = drawingObjects.length;
1147
+
1148
+ drawingObjects = drawingObjects.filter(obj => {
1149
+ switch (obj.type) {
1150
+ case 'pen':
1151
+ return !obj.points.some(p => (p.x - cx) ** 2 + (p.y - cy) ** 2 < r2);
1152
+ case 'line':
1153
+ case 'arrow':
1154
+ return distToSegment(cx, cy, obj.x1, obj.y1, obj.x2, obj.y2) > radius;
1155
+ case 'rect':
1156
+ return !(cx > obj.x - radius && cx < obj.x + obj.w + radius &&
1157
+ cy > obj.y - radius && cy < obj.y + obj.h + radius);
1158
+ case 'ellipse': {
1159
+ const ecx = obj.x + obj.w / 2;
1160
+ const ecy = obj.y + obj.h / 2;
1161
+ const dx = (cx - ecx) / (Math.abs(obj.w) / 2 + radius);
1162
+ const dy = (cy - ecy) / (Math.abs(obj.h) / 2 + radius);
1163
+ return (dx * dx + dy * dy) > 1.0;
1164
+ }
1165
+ default: return true;
1166
+ }
1167
+ });
1168
+
1169
+ if (drawingObjects.length !== before) {
1170
+ eraserDidErase = true;
1171
+ render();
1172
+ return true;
1173
+ }
1174
+ return false;
1175
+ }
1176
+
1177
+ function distToSegment(px, py, x1, y1, x2, y2) {
1178
+ const dx = x2 - x1, dy = y2 - y1;
1179
+ const lenSq = dx * dx + dy * dy;
1180
+ if (lenSq === 0) return Math.hypot(px - x1, py - y1);
1181
+ let t = ((px - x1) * dx + (py - y1) * dy) / lenSq;
1182
+ t = Math.max(0, Math.min(1, t));
1183
+ return Math.hypot(px - (x1 + t * dx), py - (y1 + t * dy));
1184
+ }
1185
+
1186
+ // ── Undo / Redo ──────────────────────────────────────────────────
1187
+ function saveState() {
1188
+ undoStack.push({
1189
+ objects: JSON.parse(JSON.stringify(drawingObjects)),
1190
+ notes: JSON.parse(JSON.stringify(stickyNotes)),
1191
+ labels: JSON.parse(JSON.stringify(textLabels))
1192
+ });
1193
+ if (undoStack.length > 60) undoStack.shift();
1194
+ redoStack = [];
1195
+ scheduleAutoSave();
1196
+ }
1197
+
1198
+ function undo() {
1199
+ if (undoStack.length === 0) return;
1200
+ redoStack.push({
1201
+ objects: JSON.parse(JSON.stringify(drawingObjects)),
1202
+ notes: JSON.parse(JSON.stringify(stickyNotes)),
1203
+ labels: JSON.parse(JSON.stringify(textLabels))
1204
+ });
1205
+ const state = undoStack.pop();
1206
+ drawingObjects = state.objects;
1207
+ stickyNotes = state.notes;
1208
+ textLabels = state.labels;
1209
+ rebuildOverlays();
1210
+ render();
1211
+ scheduleAutoSave();
1212
+ }
1213
+
1214
+ function redo() {
1215
+ if (redoStack.length === 0) return;
1216
+ undoStack.push({
1217
+ objects: JSON.parse(JSON.stringify(drawingObjects)),
1218
+ notes: JSON.parse(JSON.stringify(stickyNotes)),
1219
+ labels: JSON.parse(JSON.stringify(textLabels))
1220
+ });
1221
+ const state = redoStack.pop();
1222
+ drawingObjects = state.objects;
1223
+ stickyNotes = state.notes;
1224
+ textLabels = state.labels;
1225
+ rebuildOverlays();
1226
+ render();
1227
+ scheduleAutoSave();
1228
+ }
1229
+
1230
+ document.getElementById('undo-btn').addEventListener('click', undo);
1231
+ document.getElementById('redo-btn').addEventListener('click', redo);
1232
+
1233
+ // ── Tool selection ───────────────────────────────────────────────
1234
+ function setTool(tool) {
1235
+ currentTool = tool;
1236
+ document.querySelectorAll('.tool-btn[data-tool]').forEach(btn => {
1237
+ btn.classList.toggle('active', btn.dataset.tool === tool);
1238
+ });
1239
+ container.style.cursor = tool === 'select' ? 'default' :
1240
+ tool === 'eraser' ? 'cell' : 'crosshair';
1241
+ noteColorPicker.classList.remove('show');
1242
+ }
1243
+
1244
+ toolbar.addEventListener('click', e => {
1245
+ const btn = e.target.closest('.tool-btn[data-tool]');
1246
+ if (!btn) return;
1247
+ const tool = btn.dataset.tool;
1248
+
1249
+ if (tool === 'note') {
1250
+ noteColorPicker.classList.toggle('show');
1251
+ const rect = btn.getBoundingClientRect();
1252
+ noteColorPicker.style.left = rect.left + 'px';
1253
+ } else {
1254
+ setTool(tool);
1255
+ }
1256
+ });
1257
+
1258
+ // Note color picker
1259
+ noteColorPicker.addEventListener('click', e => {
1260
+ const opt = e.target.closest('.note-color-opt');
1261
+ if (!opt) return;
1262
+ noteColor = opt.dataset.noteColor;
1263
+ noteColorPicker.classList.remove('show');
1264
+ setTool('note');
1265
+ });
1266
+
1267
+ // Color swatches
1268
+ document.querySelectorAll('.color-swatch').forEach(s => {
1269
+ s.addEventListener('click', () => {
1270
+ document.querySelectorAll('.color-swatch').forEach(el => el.classList.remove('active'));
1271
+ s.classList.add('active');
1272
+ currentColor = s.dataset.color;
1273
+ });
1274
+ });
1275
+
1276
+ // Stroke buttons
1277
+ document.querySelectorAll('.stroke-btn').forEach(s => {
1278
+ s.addEventListener('click', () => {
1279
+ document.querySelectorAll('.stroke-btn').forEach(el => el.classList.remove('active'));
1280
+ s.classList.add('active');
1281
+ currentStroke = parseInt(s.dataset.stroke, 10);
1282
+ });
1283
+ });
1284
+
1285
+ // ── Mouse / pointer events on canvas ─────────────────────────────
1286
+ let drawStartX, drawStartY;
1287
+
1288
+ container.addEventListener('pointerdown', e => {
1289
+ if (e.target.closest('#toolbar') || e.target.closest('.sticky-note') ||
1290
+ e.target.closest('.canvas-text-label') || e.target.closest('.overlay-backdrop') ||
1291
+ e.target.closest('.shortcuts-panel') || e.target.closest('.zoom-indicator')) return;
1292
+
1293
+ const pt = screenToCanvas(e.clientX, e.clientY);
1294
+
1295
+ // Pan with space or middle button
1296
+ if (spaceHeld || e.button === 1) {
1297
+ isPanning = true;
1298
+ panStartX = e.clientX;
1299
+ panStartY = e.clientY;
1300
+ panViewStartX = viewX;
1301
+ panViewStartY = viewY;
1302
+ container.classList.add('panning');
1303
+ e.preventDefault();
1304
+ return;
1305
+ }
1306
+
1307
+ if (e.button !== 0) return;
1308
+
1309
+ switch (currentTool) {
1310
+ case 'pen':
1311
+ case 'eraser': {
1312
+ isDrawing = true;
1313
+ if (currentTool === 'pen') {
1314
+ currentPath = { type: 'pen', points: [pt], color: currentColor, stroke: currentStroke };
1315
+ } else {
1316
+ eraserDidErase = false;
1317
+ const redoStackBeforeEraser = redoStack.slice();
1318
+ saveState();
1319
+ eraseAt(pt.x, pt.y, 16);
1320
+ if (!eraserDidErase) {
1321
+ redoStack = redoStackBeforeEraser;
1322
+ }
1323
+ }
1324
+ break;
1325
+ }
1326
+ case 'line':
1327
+ case 'arrow':
1328
+ case 'rect':
1329
+ case 'ellipse': {
1330
+ isDrawing = true;
1331
+ drawStartX = pt.x;
1332
+ drawStartY = pt.y;
1333
+ if (currentTool === 'line' || currentTool === 'arrow') {
1334
+ currentPath = { type: currentTool, x1: pt.x, y1: pt.y, x2: pt.x, y2: pt.y, color: currentColor, stroke: currentStroke };
1335
+ } else {
1336
+ currentPath = { type: currentTool, x: pt.x, y: pt.y, w: 0, h: 0, color: currentColor, stroke: currentStroke };
1337
+ }
1338
+ break;
1339
+ }
1340
+ case 'text': {
1341
+ createTextLabel(pt.x, pt.y);
1342
+ break;
1343
+ }
1344
+ case 'note': {
1345
+ createStickyNote(pt.x, pt.y);
1346
+ setTool('select');
1347
+ break;
1348
+ }
1349
+ case 'select': {
1350
+ // In select mode, clicking empty canvas does nothing special
1351
+ break;
1352
+ }
1353
+ }
1354
+ });
1355
+
1356
+ container.addEventListener('pointermove', e => {
1357
+ if (isPanning) {
1358
+ viewX = panViewStartX + (e.clientX - panStartX);
1359
+ viewY = panViewStartY + (e.clientY - panStartY);
1360
+ updateCanvasTransform();
1361
+ return;
1362
+ }
1363
+
1364
+ if (!isDrawing) return;
1365
+ const pt = screenToCanvas(e.clientX, e.clientY);
1366
+
1367
+ switch (currentTool) {
1368
+ case 'pen': {
1369
+ if (currentPath) {
1370
+ currentPath.points.push(pt);
1371
+ render();
1372
+ }
1373
+ break;
1374
+ }
1375
+ case 'eraser': {
1376
+ eraseAt(pt.x, pt.y, 16);
1377
+ break;
1378
+ }
1379
+ case 'line':
1380
+ case 'arrow': {
1381
+ if (currentPath) {
1382
+ currentPath.x2 = pt.x;
1383
+ currentPath.y2 = pt.y;
1384
+ render();
1385
+ }
1386
+ break;
1387
+ }
1388
+ case 'rect':
1389
+ case 'ellipse': {
1390
+ if (currentPath) {
1391
+ currentPath.x = Math.min(drawStartX, pt.x);
1392
+ currentPath.y = Math.min(drawStartY, pt.y);
1393
+ currentPath.w = Math.abs(pt.x - drawStartX);
1394
+ currentPath.h = Math.abs(pt.y - drawStartY);
1395
+ render();
1396
+ }
1397
+ break;
1398
+ }
1399
+ }
1400
+ });
1401
+
1402
+ function finishDrawing() {
1403
+ if (isPanning) {
1404
+ isPanning = false;
1405
+ container.classList.remove('panning');
1406
+ return;
1407
+ }
1408
+
1409
+ if (!isDrawing) return;
1410
+ isDrawing = false;
1411
+
1412
+ if (currentTool === 'eraser') {
1413
+ if (!eraserDidErase) {
1414
+ // Nothing was erased — pop the pre-erase state we saved on pointerdown
1415
+ undoStack.pop();
1416
+ }
1417
+ return;
1418
+ }
1419
+
1420
+ if (!currentPath) return;
1421
+
1422
+ // Shape recognition for pen tool
1423
+ if (currentPath.type === 'pen') {
1424
+ const recognized = recognizeShape(currentPath.points);
1425
+ if (recognized) {
1426
+ currentPath = {
1427
+ ...recognized,
1428
+ color: currentPath.color,
1429
+ stroke: currentPath.stroke
1430
+ };
1431
+ }
1432
+ }
1433
+
1434
+ // Don't save degenerate shapes
1435
+ if (currentPath.type === 'pen' && currentPath.points.length < 2) {
1436
+ currentPath = null;
1437
+ return;
1438
+ }
1439
+ if ((currentPath.type === 'rect' || currentPath.type === 'ellipse') &&
1440
+ (Math.abs(currentPath.w) < 3 && Math.abs(currentPath.h) < 3)) {
1441
+ currentPath = null;
1442
+ render();
1443
+ return;
1444
+ }
1445
+ if ((currentPath.type === 'line' || currentPath.type === 'arrow') &&
1446
+ Math.hypot(currentPath.x2 - currentPath.x1, currentPath.y2 - currentPath.y1) < 3) {
1447
+ currentPath = null;
1448
+ render();
1449
+ return;
1450
+ }
1451
+
1452
+ saveState();
1453
+ drawingObjects.push(currentPath);
1454
+ currentPath = null;
1455
+ render();
1456
+ scheduleAutoSave();
1457
+ }
1458
+
1459
+ container.addEventListener('pointerup', finishDrawing);
1460
+ container.addEventListener('pointerleave', finishDrawing);
1461
+
1462
+ // ── Zoom ─────────────────────────────────────────────────────────
1463
+ container.addEventListener('wheel', e => {
1464
+ e.preventDefault();
1465
+ const delta = e.deltaY > 0 ? 0.92 : 1.08;
1466
+ zoomAt(e.clientX, e.clientY, delta);
1467
+ }, { passive: false });
1468
+
1469
+ function zoomAt(sx, sy, factor) {
1470
+ const rect = container.getBoundingClientRect();
1471
+ const mx = sx - rect.left;
1472
+ const my = sy - rect.top;
1473
+
1474
+ const newScale = Math.min(Math.max(viewScale * factor, 0.1), 5);
1475
+ const scaleRatio = newScale / viewScale;
1476
+
1477
+ viewX = mx - (mx - viewX) * scaleRatio;
1478
+ viewY = my - (my - viewY) * scaleRatio;
1479
+ viewScale = newScale;
1480
+ updateCanvasTransform();
1481
+ }
1482
+
1483
+ document.getElementById('zoom-in-btn').addEventListener('click', () => {
1484
+ const rect = container.getBoundingClientRect();
1485
+ zoomAt(rect.left + rect.width / 2, rect.top + rect.height / 2, 1.2);
1486
+ });
1487
+ document.getElementById('zoom-out-btn').addEventListener('click', () => {
1488
+ const rect = container.getBoundingClientRect();
1489
+ zoomAt(rect.left + rect.width / 2, rect.top + rect.height / 2, 0.8);
1490
+ });
1491
+ document.getElementById('fit-btn').addEventListener('click', fitToContent);
1492
+
1493
+ function fitToContent() {
1494
+ // Find bounding box of all content
1495
+ let minX = CANVAS_W, minY = CANVAS_H, maxX = 0, maxY = 0;
1496
+ let hasContent = false;
1497
+
1498
+ drawingObjects.forEach(obj => {
1499
+ hasContent = true;
1500
+ switch (obj.type) {
1501
+ case 'pen':
1502
+ obj.points.forEach(p => {
1503
+ minX = Math.min(minX, p.x); minY = Math.min(minY, p.y);
1504
+ maxX = Math.max(maxX, p.x); maxY = Math.max(maxY, p.y);
1505
+ });
1506
+ break;
1507
+ case 'line': case 'arrow':
1508
+ minX = Math.min(minX, obj.x1, obj.x2); minY = Math.min(minY, obj.y1, obj.y2);
1509
+ maxX = Math.max(maxX, obj.x1, obj.x2); maxY = Math.max(maxY, obj.y1, obj.y2);
1510
+ break;
1511
+ case 'rect': case 'ellipse':
1512
+ minX = Math.min(minX, obj.x); minY = Math.min(minY, obj.y);
1513
+ maxX = Math.max(maxX, obj.x + obj.w); maxY = Math.max(maxY, obj.y + obj.h);
1514
+ break;
1515
+ }
1516
+ });
1517
+ stickyNotes.forEach(n => {
1518
+ hasContent = true;
1519
+ minX = Math.min(minX, n.x); minY = Math.min(minY, n.y);
1520
+ maxX = Math.max(maxX, n.x + n.w); maxY = Math.max(maxY, n.y + n.h);
1521
+ });
1522
+ textLabels.forEach(l => {
1523
+ hasContent = true;
1524
+ minX = Math.min(minX, l.x); minY = Math.min(minY, l.y);
1525
+ maxX = Math.max(maxX, l.x + 200); maxY = Math.max(maxY, l.y + 30);
1526
+ });
1527
+
1528
+ if (!hasContent) {
1529
+ centerView();
1530
+ return;
1531
+ }
1532
+
1533
+ const pad = 80;
1534
+ minX -= pad; minY -= pad; maxX += pad; maxY += pad;
1535
+ const cw = container.clientWidth;
1536
+ const ch = container.clientHeight;
1537
+ viewScale = Math.min(cw / (maxX - minX), ch / (maxY - minY), 2);
1538
+ viewX = (cw - (maxX - minX) * viewScale) / 2 - minX * viewScale;
1539
+ viewY = (ch - (maxY - minY) * viewScale) / 2 - minY * viewScale;
1540
+ updateCanvasTransform();
1541
+ }
1542
+
1543
+ // ── Keyboard ─────────────────────────────────────────────────────
1544
+ document.addEventListener('keydown', e => {
1545
+ // Don't capture when typing in inputs
1546
+ if (e.target.isContentEditable || e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
1547
+ if (e.key === 'Escape') e.target.blur();
1548
+ return;
1549
+ }
1550
+
1551
+ if (e.key === ' ') {
1552
+ e.preventDefault();
1553
+ spaceHeld = true;
1554
+ container.classList.add('panning');
1555
+ }
1556
+
1557
+ // Ctrl/Cmd shortcuts
1558
+ if (e.metaKey || e.ctrlKey) {
1559
+ if (e.key === 'z' && !e.shiftKey) { e.preventDefault(); undo(); }
1560
+ if (e.key === 'z' && e.shiftKey) { e.preventDefault(); redo(); }
1561
+ if (e.key === 'Z') { e.preventDefault(); redo(); }
1562
+ return;
1563
+ }
1564
+
1565
+ if (e.key === 'Delete' || e.key === 'Backspace') {
1566
+ // No specific selection handling in v1 beyond sticky notes
1567
+ return;
1568
+ }
1569
+
1570
+ const keyMap = { v: 'select', p: 'pen', r: 'rect', c: 'ellipse', a: 'arrow', l: 'line', t: 'text', n: 'note', e: 'eraser' };
1571
+ if (keyMap[e.key]) {
1572
+ if (e.key === 'n') {
1573
+ noteColorPicker.classList.toggle('show');
1574
+ const btn = document.getElementById('note-tool-btn');
1575
+ const rect = btn.getBoundingClientRect();
1576
+ noteColorPicker.style.left = rect.left + 'px';
1577
+ } else {
1578
+ setTool(keyMap[e.key]);
1579
+ }
1580
+ }
1581
+ });
1582
+
1583
+ document.addEventListener('keyup', e => {
1584
+ if (e.key === ' ') {
1585
+ spaceHeld = false;
1586
+ if (!isPanning) container.classList.remove('panning');
1587
+ }
1588
+ });
1589
+
1590
+ // Shortcuts panel
1591
+ document.getElementById('close-shortcuts').addEventListener('click', () => {
1592
+ document.getElementById('shortcuts-panel').classList.remove('show');
1593
+ });
1594
+
1595
+ // Show shortcuts with ? key when not typing
1596
+ document.addEventListener('keydown', e => {
1597
+ if (e.target.isContentEditable || e.target.tagName === 'INPUT') return;
1598
+ if (e.key === '?') {
1599
+ document.getElementById('shortcuts-panel').classList.toggle('show');
1600
+ }
1601
+ });
1602
+
1603
+ // ── Sticky notes ─────────────────────────────────────────────────
1604
+ function createStickyNote(x, y) {
1605
+ const note = {
1606
+ id: uid(),
1607
+ text: '',
1608
+ x: x,
1609
+ y: y,
1610
+ w: 200,
1611
+ h: 160,
1612
+ color: noteColor
1613
+ };
1614
+ saveState();
1615
+ stickyNotes.push(note);
1616
+ renderStickyNote(note, true);
1617
+ scheduleAutoSave();
1618
+ }
1619
+
1620
+ function renderStickyNote(note, focusAfter) {
1621
+ const el = document.createElement('div');
1622
+ el.className = 'sticky-note sticky-' + note.color;
1623
+ el.dataset.noteId = note.id;
1624
+ el.style.left = (viewX + note.x * viewScale) + 'px';
1625
+ el.style.top = (viewY + note.y * viewScale) + 'px';
1626
+ el.style.width = (note.w * viewScale) + 'px';
1627
+ el.style.height = (note.h * viewScale) + 'px';
1628
+ el.style.fontSize = (14 * viewScale) + 'px';
1629
+
1630
+ const header = document.createElement('div');
1631
+ header.className = 'note-header';
1632
+
1633
+ const del = document.createElement('button');
1634
+ del.className = 'note-delete';
1635
+ del.textContent = '\u00d7';
1636
+ del.addEventListener('click', () => {
1637
+ saveState();
1638
+ stickyNotes = stickyNotes.filter(n => n.id !== note.id);
1639
+ el.remove();
1640
+ scheduleAutoSave();
1641
+ });
1642
+ header.appendChild(del);
1643
+
1644
+ const body = document.createElement('div');
1645
+ body.className = 'note-body';
1646
+ body.contentEditable = 'true';
1647
+ body.textContent = note.text;
1648
+ body.addEventListener('input', () => {
1649
+ note.text = body.textContent;
1650
+ scheduleAutoSave();
1651
+ });
1652
+ body.addEventListener('blur', () => {
1653
+ note.text = body.textContent;
1654
+ scheduleAutoSave();
1655
+ });
1656
+
1657
+ const resize = document.createElement('div');
1658
+ resize.className = 'note-resize';
1659
+
1660
+ el.appendChild(header);
1661
+ el.appendChild(body);
1662
+ el.appendChild(resize);
1663
+ container.appendChild(el);
1664
+
1665
+ // Drag header to move
1666
+ let dragOffX, dragOffY, isDragging = false;
1667
+ header.addEventListener('pointerdown', e => {
1668
+ isDragging = true;
1669
+ const rect = el.getBoundingClientRect();
1670
+ dragOffX = e.clientX - rect.left;
1671
+ dragOffY = e.clientY - rect.top;
1672
+ e.preventDefault();
1673
+ header.setPointerCapture(e.pointerId);
1674
+ });
1675
+ header.addEventListener('pointermove', e => {
1676
+ if (!isDragging) return;
1677
+ const cRect = container.getBoundingClientRect();
1678
+ const newLeft = e.clientX - cRect.left - dragOffX;
1679
+ const newTop = e.clientY - cRect.top - dragOffY;
1680
+ note.x = (newLeft - viewX) / viewScale;
1681
+ note.y = (newTop - viewY) / viewScale;
1682
+ el.style.left = newLeft + 'px';
1683
+ el.style.top = newTop + 'px';
1684
+ });
1685
+ header.addEventListener('pointerup', () => {
1686
+ if (isDragging) scheduleAutoSave();
1687
+ isDragging = false;
1688
+ });
1689
+
1690
+ // Resize handle
1691
+ let isResizing = false, resizeStartW, resizeStartH, resizeStartMx, resizeStartMy;
1692
+ resize.addEventListener('pointerdown', e => {
1693
+ isResizing = true;
1694
+ resizeStartW = note.w;
1695
+ resizeStartH = note.h;
1696
+ resizeStartMx = e.clientX;
1697
+ resizeStartMy = e.clientY;
1698
+ e.preventDefault();
1699
+ e.stopPropagation();
1700
+ resize.setPointerCapture(e.pointerId);
1701
+ });
1702
+ resize.addEventListener('pointermove', e => {
1703
+ if (!isResizing) return;
1704
+ const dw = (e.clientX - resizeStartMx) / viewScale;
1705
+ const dh = (e.clientY - resizeStartMy) / viewScale;
1706
+ note.w = Math.max(120, resizeStartW + dw);
1707
+ note.h = Math.max(80, resizeStartH + dh);
1708
+ el.style.width = (note.w * viewScale) + 'px';
1709
+ el.style.height = (note.h * viewScale) + 'px';
1710
+ });
1711
+ resize.addEventListener('pointerup', () => {
1712
+ if (isResizing) scheduleAutoSave();
1713
+ isResizing = false;
1714
+ });
1715
+
1716
+ if (focusAfter) {
1717
+ setTimeout(() => body.focus(), 50);
1718
+ }
1719
+ }
1720
+
1721
+ // ── Text labels ──────────────────────────────────────────────────
1722
+ function createTextLabel(x, y) {
1723
+ const lbl = {
1724
+ id: uid(),
1725
+ text: '',
1726
+ x: x,
1727
+ y: y,
1728
+ fontSize: 16
1729
+ };
1730
+ saveState();
1731
+ textLabels.push(lbl);
1732
+ renderTextLabel(lbl, true);
1733
+ setTool('select');
1734
+ scheduleAutoSave();
1735
+ }
1736
+
1737
+ function renderTextLabel(lbl, focusAfter) {
1738
+ const el = document.createElement('div');
1739
+ el.className = 'canvas-text-label';
1740
+ el.dataset.labelId = lbl.id;
1741
+ el.contentEditable = 'true';
1742
+ el.style.left = (viewX + lbl.x * viewScale) + 'px';
1743
+ el.style.top = (viewY + lbl.y * viewScale) + 'px';
1744
+ el.style.fontSize = (lbl.fontSize * viewScale) + 'px';
1745
+ el.textContent = lbl.text;
1746
+
1747
+ el.addEventListener('input', () => {
1748
+ lbl.text = el.textContent;
1749
+ scheduleAutoSave();
1750
+ });
1751
+ el.addEventListener('blur', () => {
1752
+ lbl.text = el.textContent;
1753
+ if (!lbl.text.trim()) {
1754
+ textLabels = textLabels.filter(l => l.id !== lbl.id);
1755
+ el.remove();
1756
+ }
1757
+ scheduleAutoSave();
1758
+ });
1759
+
1760
+ container.appendChild(el);
1761
+ if (focusAfter) {
1762
+ setTimeout(() => el.focus(), 50);
1763
+ }
1764
+ }
1765
+
1766
+ // ── Rebuild overlays from data (for undo/redo) ───────────────────
1767
+ function rebuildOverlays() {
1768
+ document.querySelectorAll('.sticky-note').forEach(el => el.remove());
1769
+ document.querySelectorAll('.canvas-text-label').forEach(el => el.remove());
1770
+ stickyNotes.forEach(n => renderStickyNote(n, false));
1771
+ textLabels.forEach(l => renderTextLabel(l, false));
1772
+ }
1773
+
1774
+ // ── Auto-save to localStorage ────────────────────────────────────
1775
+ let autoSaveTimer = null;
1776
+
1777
+ function scheduleAutoSave() {
1778
+ clearTimeout(autoSaveTimer);
1779
+ autoSaveTimer = setTimeout(autoSave, 2000);
1780
+ }
1781
+
1782
+ function autoSave() {
1783
+ try {
1784
+ const state = {
1785
+ objects: drawingObjects,
1786
+ notes: stickyNotes,
1787
+ labels: textLabels
1788
+ };
1789
+ localStorage.setItem('napkin_state', JSON.stringify(state));
1790
+ } catch (e) {
1791
+ // localStorage might be full; silently ignore
1792
+ }
1793
+ }
1794
+
1795
+ // Periodic save every 10 seconds
1796
+ setInterval(autoSave, 10000);
1797
+
1798
+ function loadState() {
1799
+ try {
1800
+ const raw = localStorage.getItem('napkin_state');
1801
+ if (!raw) return;
1802
+ const state = JSON.parse(raw);
1803
+ if (state.objects) drawingObjects = state.objects;
1804
+ if (state.notes) stickyNotes = state.notes;
1805
+ if (state.labels) textLabels = state.labels;
1806
+ rebuildOverlays();
1807
+ render();
1808
+ } catch (e) {
1809
+ // corrupted state, ignore
1810
+ }
1811
+ }
1812
+
1813
+ // ── Share with Copilot ───────────────────────────────────────────
1814
+ document.getElementById('share-btn').addEventListener('click', async () => {
1815
+ try {
1816
+ // Create an offscreen canvas for export
1817
+ const exportCanvas = document.createElement('canvas');
1818
+ exportCanvas.width = CANVAS_W;
1819
+ exportCanvas.height = CANVAS_H;
1820
+ const ectx = exportCanvas.getContext('2d');
1821
+
1822
+ // White background
1823
+ ectx.fillStyle = '#fff';
1824
+ ectx.fillRect(0, 0, CANVAS_W, CANVAS_H);
1825
+
1826
+ // Draw all drawing objects
1827
+ drawingObjects.forEach(obj => drawObject(ectx, obj));
1828
+
1829
+ // Draw sticky notes onto export canvas
1830
+ stickyNotes.forEach(note => {
1831
+ const colors = {
1832
+ yellow: { bg: '#fff9c4', header: '#fff176' },
1833
+ pink: { bg: '#fce4ec', header: '#f48fb1' },
1834
+ blue: { bg: '#e3f2fd', header: '#90caf9' },
1835
+ green: { bg: '#e8f5e9', header: '#a5d6a7' }
1836
+ };
1837
+ const c = colors[note.color] || colors.yellow;
1838
+
1839
+ // Shadow
1840
+ ectx.shadowColor = 'rgba(0,0,0,0.12)';
1841
+ ectx.shadowBlur = 12;
1842
+ ectx.shadowOffsetX = 2;
1843
+ ectx.shadowOffsetY = 3;
1844
+
1845
+ // Body
1846
+ ectx.fillStyle = c.bg;
1847
+ ectx.beginPath();
1848
+ safeRoundRect(ectx, note.x, note.y, note.w, note.h, 4);
1849
+ ectx.fill();
1850
+
1851
+ // Reset shadow
1852
+ ectx.shadowColor = 'transparent';
1853
+ ectx.shadowBlur = 0;
1854
+ ectx.shadowOffsetX = 0;
1855
+ ectx.shadowOffsetY = 0;
1856
+
1857
+ // Header
1858
+ ectx.fillStyle = c.header;
1859
+ ectx.beginPath();
1860
+ safeRoundRect(ectx, note.x, note.y, note.w, 24, [4, 4, 0, 0]);
1861
+ ectx.fill();
1862
+
1863
+ // Text
1864
+ if (note.text) {
1865
+ ectx.fillStyle = '#333';
1866
+ ectx.font = '14px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1867
+ const lines = wrapText(ectx, note.text, note.w - 24);
1868
+ lines.forEach((line, i) => {
1869
+ ectx.fillText(line, note.x + 12, note.y + 44 + i * 20);
1870
+ });
1871
+ }
1872
+ });
1873
+
1874
+ // Draw text labels
1875
+ textLabels.forEach(lbl => {
1876
+ if (!lbl.text) return;
1877
+ ectx.fillStyle = '#333';
1878
+ ectx.font = lbl.fontSize + 'px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1879
+ ectx.fillText(lbl.text, lbl.x, lbl.y + lbl.fontSize);
1880
+ });
1881
+
1882
+ // Export PNG
1883
+ const dataUrl = exportCanvas.toDataURL('image/png');
1884
+ const link = document.createElement('a');
1885
+ link.download = 'napkin-snapshot.png';
1886
+ link.href = dataUrl;
1887
+ document.body.appendChild(link);
1888
+ link.click();
1889
+ document.body.removeChild(link);
1890
+
1891
+ // Build JSON
1892
+ const json = {
1893
+ version: 1,
1894
+ timestamp: new Date().toISOString(),
1895
+ notes: stickyNotes.map(n => ({
1896
+ id: n.id, text: n.text, x: n.x, y: n.y, color: n.color, width: n.w, height: n.h
1897
+ })),
1898
+ textLabels: textLabels.map(l => ({
1899
+ id: l.id, text: l.text, x: l.x, y: l.y, fontSize: l.fontSize
1900
+ })),
1901
+ canvasSize: { width: CANVAS_W, height: CANVAS_H }
1902
+ };
1903
+
1904
+ // Copy JSON to clipboard
1905
+ try {
1906
+ await navigator.clipboard.writeText(JSON.stringify(json, null, 2));
1907
+ } catch (clipErr) {
1908
+ // Fallback for file:// protocol or older browsers
1909
+ const ta = document.createElement('textarea');
1910
+ ta.value = JSON.stringify(json, null, 2);
1911
+ ta.style.position = 'fixed';
1912
+ ta.style.left = '-9999px';
1913
+ document.body.appendChild(ta);
1914
+ ta.select();
1915
+ document.execCommand('copy');
1916
+ document.body.removeChild(ta);
1917
+ }
1918
+
1919
+ // Show confirmation
1920
+ shareOverlay.classList.remove('hidden');
1921
+
1922
+ } catch (err) {
1923
+ showToast('Export failed: ' + err.message, 4000);
1924
+ }
1925
+ });
1926
+
1927
+ document.getElementById('share-overlay-close').addEventListener('click', () => {
1928
+ shareOverlay.classList.add('hidden');
1929
+ });
1930
+
1931
+ function wrapText(c, text, maxWidth) {
1932
+ const words = text.split(/\s+/);
1933
+ const lines = [];
1934
+ let currentLine = '';
1935
+ words.forEach(word => {
1936
+ const test = currentLine ? currentLine + ' ' + word : word;
1937
+ if (c.measureText(test).width > maxWidth && currentLine) {
1938
+ lines.push(currentLine);
1939
+ currentLine = word;
1940
+ } else {
1941
+ currentLine = test;
1942
+ }
1943
+ });
1944
+ if (currentLine) lines.push(currentLine);
1945
+ return lines;
1946
+ }
1947
+
1948
+ // ── Touch support for pinch zoom ─────────────────────────────────
1949
+ let lastPinchDist = 0;
1950
+ let lastPinchCX = 0, lastPinchCY = 0;
1951
+
1952
+ container.addEventListener('touchstart', e => {
1953
+ if (e.touches.length === 2) {
1954
+ const dx = e.touches[0].clientX - e.touches[1].clientX;
1955
+ const dy = e.touches[0].clientY - e.touches[1].clientY;
1956
+ lastPinchDist = Math.hypot(dx, dy);
1957
+ lastPinchCX = (e.touches[0].clientX + e.touches[1].clientX) / 2;
1958
+ lastPinchCY = (e.touches[0].clientY + e.touches[1].clientY) / 2;
1959
+ }
1960
+ }, { passive: true });
1961
+
1962
+ container.addEventListener('touchmove', e => {
1963
+ if (e.touches.length === 2) {
1964
+ e.preventDefault();
1965
+ const dx = e.touches[0].clientX - e.touches[1].clientX;
1966
+ const dy = e.touches[0].clientY - e.touches[1].clientY;
1967
+ const dist = Math.hypot(dx, dy);
1968
+ const cx = (e.touches[0].clientX + e.touches[1].clientX) / 2;
1969
+ const cy = (e.touches[0].clientY + e.touches[1].clientY) / 2;
1970
+
1971
+ if (lastPinchDist > 0) {
1972
+ const factor = dist / lastPinchDist;
1973
+ zoomAt(cx, cy, factor);
1974
+ viewX += cx - lastPinchCX;
1975
+ viewY += cy - lastPinchCY;
1976
+ updateCanvasTransform();
1977
+ }
1978
+
1979
+ lastPinchDist = dist;
1980
+ lastPinchCX = cx;
1981
+ lastPinchCY = cy;
1982
+ }
1983
+ }, { passive: false });
1984
+
1985
+ container.addEventListener('touchend', () => {
1986
+ lastPinchDist = 0;
1987
+ }, { passive: true });
1988
+
1989
+ // ── Close overlays on escape ─────────────────────────────────────
1990
+ document.addEventListener('keydown', e => {
1991
+ if (e.key === 'Escape') {
1992
+ onboarding.classList.add('hidden');
1993
+ shareOverlay.classList.add('hidden');
1994
+ noteColorPicker.classList.remove('show');
1995
+ document.getElementById('shortcuts-panel').classList.remove('show');
1996
+ }
1997
+ });
1998
+
1999
+ // Close note color picker on outside click
2000
+ document.addEventListener('pointerdown', e => {
2001
+ if (!e.target.closest('#note-color-picker') && !e.target.closest('#note-tool-btn')) {
2002
+ noteColorPicker.classList.remove('show');
2003
+ }
2004
+ });
2005
+
2006
+ // ── Window resize ────────────────────────────────────────────────
2007
+ window.addEventListener('resize', () => {
2008
+ updateCanvasTransform();
2009
+ });
2010
+
2011
+ // ── Init ─────────────────────────────────────────────────────────
2012
+ initOnboarding();
2013
+ initCanvas();
2014
+ loadState();
2015
+
2016
+ })();
2017
+ </script>
2018
+ </body>
2019
+ </html>