@dsalazardev/ai-hub-cli 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1296) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +34 -0
  3. package/README.md +64 -2
  4. package/agents/cpp-build-resolver.md +25 -0
  5. package/agents/cpp-reviewer.md +28 -0
  6. package/agents/csharp-reviewer.md +28 -0
  7. package/agents/django-build-resolver.md +25 -0
  8. package/agents/django-reviewer.md +28 -0
  9. package/agents/explorer-domain.md +28 -0
  10. package/agents/fastapi-reviewer.md +28 -0
  11. package/agents/flutter-build-resolver.md +25 -0
  12. package/agents/flutter-reviewer.md +28 -0
  13. package/agents/go-build-resolver.md +25 -0
  14. package/agents/go-reviewer.md +28 -0
  15. package/agents/implementer-backend.md +30 -0
  16. package/agents/implementer-frontend.md +30 -0
  17. package/agents/java-build-resolver.md +26 -0
  18. package/agents/java-reviewer.md +29 -0
  19. package/agents/kotlin-build-resolver.md +25 -0
  20. package/agents/kotlin-reviewer.md +28 -0
  21. package/agents/mle-reviewer.md +28 -0
  22. package/agents/php-reviewer.md +29 -0
  23. package/agents/postgres-reviewer.md +28 -0
  24. package/agents/python-reviewer.md +28 -0
  25. package/agents/pytorch-build-resolver.md +25 -0
  26. package/agents/rag-reviewer.md +28 -0
  27. package/agents/react-build-resolver.md +26 -0
  28. package/agents/react-reviewer.md +29 -0
  29. package/agents/reviewer-architecture.md +32 -0
  30. package/agents/reviewer-tests.md +31 -0
  31. package/agents/rust-build-resolver.md +25 -0
  32. package/agents/rust-reviewer.md +28 -0
  33. package/agents/spec-author.md +36 -0
  34. package/agents/spec-miner.md +14 -0
  35. package/agents/swift-build-resolver.md +25 -0
  36. package/agents/swift-reviewer.md +28 -0
  37. package/agents/typescript-reviewer.md +28 -0
  38. package/agents/vue-reviewer.md +28 -0
  39. package/dist/backup/snapshots.d.ts +24 -0
  40. package/dist/backup/snapshots.js +171 -0
  41. package/dist/bin/ai-hub.d.ts +2 -0
  42. package/dist/bin/ai-hub.js +11 -0
  43. package/dist/catalog.d.ts +76 -0
  44. package/dist/catalog.js +321 -0
  45. package/dist/cli/args.d.ts +4 -0
  46. package/dist/cli/args.js +63 -0
  47. package/dist/cli/context.d.ts +7 -0
  48. package/dist/cli/context.js +79 -0
  49. package/dist/cli/doctor.d.ts +14 -0
  50. package/dist/cli/doctor.js +282 -0
  51. package/dist/cli/drift.d.ts +2 -0
  52. package/dist/cli/drift.js +34 -0
  53. package/dist/cli/items.d.ts +5 -0
  54. package/dist/cli/items.js +10 -0
  55. package/dist/cli/legacy.d.ts +3 -0
  56. package/dist/cli/legacy.js +18 -0
  57. package/dist/cli/maintenance.d.ts +8 -0
  58. package/dist/cli/maintenance.js +334 -0
  59. package/dist/cli/memory.d.ts +2 -0
  60. package/dist/cli/memory.js +89 -0
  61. package/dist/cli/onboarding.d.ts +36 -0
  62. package/dist/cli/onboarding.js +516 -0
  63. package/dist/cli/run.d.ts +15 -0
  64. package/dist/cli/run.js +185 -0
  65. package/dist/cli/source.d.ts +5 -0
  66. package/dist/cli/source.js +22 -0
  67. package/dist/cli/trunk.d.ts +8 -0
  68. package/dist/cli/trunk.js +54 -0
  69. package/dist/cli/types.d.ts +17 -0
  70. package/dist/cli/types.js +4 -0
  71. package/dist/cli/worktrees.d.ts +11 -0
  72. package/dist/cli/worktrees.js +141 -0
  73. package/dist/concurrency.d.ts +5 -0
  74. package/dist/concurrency.js +23 -0
  75. package/dist/engine/engine.d.ts +48 -0
  76. package/dist/engine/engine.js +114 -0
  77. package/dist/engine/gates.d.ts +2 -0
  78. package/dist/engine/gates.js +131 -0
  79. package/dist/frontmatter.d.ts +11 -0
  80. package/dist/frontmatter.js +30 -0
  81. package/dist/harness/guards/adapters/context.d.ts +19 -0
  82. package/dist/harness/guards/adapters/context.js +153 -0
  83. package/dist/harness/guards/adapters/hermes.d.ts +13 -0
  84. package/dist/harness/guards/adapters/hermes.js +18 -0
  85. package/dist/harness/guards/adapters/hooks.d.ts +25 -0
  86. package/dist/harness/guards/adapters/hooks.js +52 -0
  87. package/dist/harness/guards/branch.d.ts +5 -0
  88. package/dist/harness/guards/branch.js +43 -0
  89. package/dist/harness/guards/danger.d.ts +13 -0
  90. package/dist/harness/guards/danger.js +157 -0
  91. package/dist/harness/guards/index.d.ts +6 -0
  92. package/dist/harness/guards/index.js +6 -0
  93. package/dist/harness/guards/preflight.d.ts +14 -0
  94. package/dist/harness/guards/preflight.js +37 -0
  95. package/dist/harness/guards/ship.d.ts +2 -0
  96. package/dist/harness/guards/ship.js +35 -0
  97. package/dist/harness/guards/trunk.d.ts +5 -0
  98. package/dist/harness/guards/trunk.js +41 -0
  99. package/dist/harness/guards/types.d.ts +50 -0
  100. package/dist/harness/guards/types.js +1 -0
  101. package/dist/harness/memory/ledger.d.ts +53 -0
  102. package/dist/harness/memory/ledger.js +136 -0
  103. package/dist/harness/memory/state.d.ts +35 -0
  104. package/dist/harness/memory/state.js +121 -0
  105. package/dist/harness/worktree/reaper.d.ts +32 -0
  106. package/dist/harness/worktree/reaper.js +54 -0
  107. package/dist/manifest/build.d.ts +1 -0
  108. package/dist/manifest/build.js +1 -0
  109. package/dist/manifest/cli.d.ts +2 -0
  110. package/dist/manifest/cli.js +44 -0
  111. package/dist/manifest/dispatch.d.ts +13 -0
  112. package/dist/manifest/dispatch.js +36 -0
  113. package/dist/manifest/labels.d.ts +15 -0
  114. package/dist/manifest/labels.js +70 -0
  115. package/dist/manifest/manifest.d.ts +130 -0
  116. package/dist/manifest/manifest.js +220 -0
  117. package/dist/package-info.d.ts +4 -0
  118. package/dist/package-info.js +7 -0
  119. package/dist/paths.d.ts +33 -0
  120. package/dist/paths.js +123 -0
  121. package/dist/presets/detect.d.ts +24 -0
  122. package/dist/presets/detect.js +116 -0
  123. package/dist/presets/materialize.d.ts +26 -0
  124. package/dist/presets/materialize.js +192 -0
  125. package/dist/presets/resolve.d.ts +37 -0
  126. package/dist/presets/resolve.js +83 -0
  127. package/dist/presets/schema.d.ts +57 -0
  128. package/dist/presets/schema.js +68 -0
  129. package/dist/source-checkout.d.ts +8 -0
  130. package/dist/source-checkout.js +19 -0
  131. package/dist/sync/config.d.ts +47 -0
  132. package/dist/sync/config.js +85 -0
  133. package/dist/sync/lock.d.ts +16 -0
  134. package/dist/sync/lock.js +43 -0
  135. package/dist/sync/render.d.ts +18 -0
  136. package/dist/sync/render.js +259 -0
  137. package/dist/sync/sync.d.ts +38 -0
  138. package/dist/sync/sync.js +288 -0
  139. package/dist/sync/targets.d.ts +24 -0
  140. package/dist/sync/targets.js +78 -0
  141. package/engine/coupling.json +4 -0
  142. package/engine/engine.yaml +250 -0
  143. package/engine/legacy-paths.json +4 -0
  144. package/engine/preflight.md +11 -0
  145. package/manifest.json +402 -0
  146. package/package.json +62 -4
  147. package/presets/angular-express/harness/rules/01-zero-any.sh +25 -0
  148. package/presets/angular-express/harness/rules/02-no-ng-module.sh +21 -0
  149. package/presets/angular-express/harness/rules/03-no-constructor-injection.sh +21 -0
  150. package/presets/angular-express/harness/rules/04-no-legacy-directives.sh +21 -0
  151. package/presets/angular-express/harness/rules/05-no-dolibarrdal-inheritance.sh +25 -0
  152. package/presets/angular-express/harness/rules/06-no-todos.sh +22 -0
  153. package/presets/angular-express/harness/run-all.sh +13 -0
  154. package/presets/angular-express/preset.yaml +53 -0
  155. package/presets/angular-express/references/common-imports-catalog.md +146 -0
  156. package/presets/angular-express/references/fichajes-migration-notes.md +57 -0
  157. package/presets/angular-express/references/module-implementation-flow.md +260 -0
  158. package/presets/angular-express/references/products-coding-standard.md +143 -0
  159. package/presets/angular-express/references/products-module-blueprint.md +860 -0
  160. package/presets/angular-express/references/replicate-module-checklist.md +72 -0
  161. package/presets/angular-express/references/users-migration-notes.md +172 -0
  162. package/presets/angular-express/rules/architecture.md +8 -0
  163. package/presets/angular-express/rules/backend.md +4 -0
  164. package/presets/angular-express/rules/frontend.md +53 -0
  165. package/presets/angular-express/skills/angular-developer/SKILL.md +130 -0
  166. package/presets/angular-express/skills/angular-developer/references/angular-animations.md +160 -0
  167. package/presets/angular-express/skills/angular-developer/references/angular-aria.md +410 -0
  168. package/presets/angular-express/skills/angular-developer/references/cli.md +86 -0
  169. package/presets/angular-express/skills/angular-developer/references/component-harnesses.md +59 -0
  170. package/presets/angular-express/skills/angular-developer/references/component-styling.md +91 -0
  171. package/presets/angular-express/skills/angular-developer/references/components.md +117 -0
  172. package/presets/angular-express/skills/angular-developer/references/creating-services.md +97 -0
  173. package/presets/angular-express/skills/angular-developer/references/data-resolvers.md +69 -0
  174. package/presets/angular-express/skills/angular-developer/references/define-routes.md +67 -0
  175. package/presets/angular-express/skills/angular-developer/references/defining-providers.md +72 -0
  176. package/presets/angular-express/skills/angular-developer/references/di-fundamentals.md +120 -0
  177. package/presets/angular-express/skills/angular-developer/references/e2e-testing.md +66 -0
  178. package/presets/angular-express/skills/angular-developer/references/effects.md +83 -0
  179. package/presets/angular-express/skills/angular-developer/references/hierarchical-injectors.md +43 -0
  180. package/presets/angular-express/skills/angular-developer/references/host-elements.md +80 -0
  181. package/presets/angular-express/skills/angular-developer/references/injection-context.md +63 -0
  182. package/presets/angular-express/skills/angular-developer/references/inputs.md +101 -0
  183. package/presets/angular-express/skills/angular-developer/references/linked-signal.md +59 -0
  184. package/presets/angular-express/skills/angular-developer/references/loading-strategies.md +61 -0
  185. package/presets/angular-express/skills/angular-developer/references/mcp.md +106 -0
  186. package/presets/angular-express/skills/angular-developer/references/migrations.md +30 -0
  187. package/presets/angular-express/skills/angular-developer/references/navigate-to-routes.md +69 -0
  188. package/presets/angular-express/skills/angular-developer/references/outputs.md +86 -0
  189. package/presets/angular-express/skills/angular-developer/references/reactive-forms.md +122 -0
  190. package/presets/angular-express/skills/angular-developer/references/rendering-strategies.md +44 -0
  191. package/presets/angular-express/skills/angular-developer/references/resource.md +74 -0
  192. package/presets/angular-express/skills/angular-developer/references/route-animations.md +56 -0
  193. package/presets/angular-express/skills/angular-developer/references/route-guards.md +52 -0
  194. package/presets/angular-express/skills/angular-developer/references/router-lifecycle.md +45 -0
  195. package/presets/angular-express/skills/angular-developer/references/router-testing.md +87 -0
  196. package/presets/angular-express/skills/angular-developer/references/show-routes-with-outlets.md +68 -0
  197. package/presets/angular-express/skills/angular-developer/references/signal-forms.md +897 -0
  198. package/presets/angular-express/skills/angular-developer/references/signals-overview.md +94 -0
  199. package/presets/angular-express/skills/angular-developer/references/tailwind-css.md +69 -0
  200. package/presets/angular-express/skills/angular-developer/references/template-driven-forms.md +114 -0
  201. package/presets/angular-express/skills/angular-developer/references/testing-fundamentals.md +66 -0
  202. package/presets/angular-express/skills/angular-new-app/SKILL.md +62 -0
  203. package/presets/angular-express/skills/frontend-design/LICENSE.txt +177 -0
  204. package/presets/angular-express/skills/frontend-design/SKILL.md +55 -0
  205. package/presets/angular-express/skills/onna-architecture-angular/SKILL.md +229 -0
  206. package/presets/angular-express/skills/onna-architecture-bff/SKILL.md +446 -0
  207. package/presets/angular-express/skills/onna-architecture-common/SKILL.md +313 -0
  208. package/presets/angular-express/skills/onna-design-system/SKILL.md +615 -0
  209. package/presets/base/preset.yaml +25 -0
  210. package/presets/base/rules/core.md +35 -0
  211. package/presets/generic-ts/preset.yaml +44 -0
  212. package/presets/python/preset.yaml +45 -0
  213. package/presets/python/rules/python.md +10 -0
  214. package/rules/skill-quality/skill-behavior-rubric.md +63 -0
  215. package/rules/skill-quality/skill-harden-rubric.md +102 -0
  216. package/rules/skill-quality/skill-migration-brief.md +200 -0
  217. package/rules/skill-quality/skill-rubric.md +40 -0
  218. package/schema/engine.schema.json +73 -0
  219. package/schema/manifest.schema.json +152 -0
  220. package/schema/preset.schema.json +98 -0
  221. package/schema/state.schema.json +27 -0
  222. package/skills/shared/ab-testing/SKILL.md +159 -0
  223. package/skills/shared/ab-testing/evals/README.md +8 -0
  224. package/skills/shared/ab-testing/evals/cases.yaml +49 -0
  225. package/skills/shared/ab-testing/references/pitfalls.md +74 -0
  226. package/skills/shared/ab-testing/references/sample-size-and-cuped.md +128 -0
  227. package/skills/shared/ab-testing/scripts/verify.sh +89 -0
  228. package/skills/shared/accessibility/SKILL.md +216 -0
  229. package/skills/shared/accessibility/evals/README.md +3 -0
  230. package/skills/shared/accessibility/evals/cases.yaml +47 -0
  231. package/skills/shared/accessibility/references/aria-patterns.md +113 -0
  232. package/skills/shared/accessibility/references/wcag22-checklist.md +83 -0
  233. package/skills/shared/accessibility/scripts/verify.sh +103 -0
  234. package/skills/shared/agent-eval/SKILL.md +187 -0
  235. package/skills/shared/agent-eval/evals/README.md +12 -0
  236. package/skills/shared/agent-eval/evals/cases.yaml +45 -0
  237. package/skills/shared/agent-eval/references/judge-design.md +118 -0
  238. package/skills/shared/agent-eval/references/runner-and-gate.md +183 -0
  239. package/skills/shared/agent-eval/scripts/verify.sh +161 -0
  240. package/skills/shared/agent-safety/SKILL.md +169 -0
  241. package/skills/shared/agent-safety/evals/README.md +12 -0
  242. package/skills/shared/agent-safety/evals/cases.yaml +46 -0
  243. package/skills/shared/agent-safety/references/threat-model.md +51 -0
  244. package/skills/shared/analyze/SKILL.md +123 -0
  245. package/skills/shared/analyze/evals/README.md +72 -0
  246. package/skills/shared/analyze/evals/cases.yaml +74 -0
  247. package/skills/shared/angular/SKILL.md +275 -0
  248. package/skills/shared/angular/evals/README.md +3 -0
  249. package/skills/shared/angular/evals/cases.yaml +38 -0
  250. package/skills/shared/angular/references/migration.md +81 -0
  251. package/skills/shared/angular/references/signals-rxjs.md +92 -0
  252. package/skills/shared/angular/scripts/verify.sh +122 -0
  253. package/skills/shared/api-connector-builder/SKILL.md +268 -0
  254. package/skills/shared/api-connector-builder/evals/README.md +11 -0
  255. package/skills/shared/api-connector-builder/evals/cases.yaml +47 -0
  256. package/skills/shared/api-connector-builder/references/auth-flows.md +132 -0
  257. package/skills/shared/api-connector-builder/references/pagination.md +144 -0
  258. package/skills/shared/api-connector-builder/scripts/verify.sh +172 -0
  259. package/skills/shared/api-design/SKILL.md +182 -0
  260. package/skills/shared/api-design/evals/README.md +3 -0
  261. package/skills/shared/api-design/evals/cases.yaml +45 -0
  262. package/skills/shared/api-design/references/graphql-design.md +70 -0
  263. package/skills/shared/api-design/references/openapi-contract.md +86 -0
  264. package/skills/shared/api-design/references/rest-conventions.md +63 -0
  265. package/skills/shared/api-design/references/versioning-and-evolution.md +49 -0
  266. package/skills/shared/api-design/scripts/verify.sh +138 -0
  267. package/skills/shared/astro/SKILL.md +257 -0
  268. package/skills/shared/astro/evals/README.md +3 -0
  269. package/skills/shared/astro/evals/cases.yaml +41 -0
  270. package/skills/shared/astro/references/content-layer.md +118 -0
  271. package/skills/shared/astro/references/deploy-and-integrations.md +163 -0
  272. package/skills/shared/astro/scripts/verify.sh +137 -0
  273. package/skills/shared/author-skill/SKILL.md +194 -0
  274. package/skills/shared/author-skill/evals/README.md +66 -0
  275. package/skills/shared/author-skill/evals/cases.yaml +75 -0
  276. package/skills/shared/author-skill/references/description-recipe.md +85 -0
  277. package/skills/shared/author-skill/references/eval-authoring.md +108 -0
  278. package/skills/shared/author-skill/references/skill-conventions.md +95 -0
  279. package/skills/shared/automation-flows/SKILL.md +122 -0
  280. package/skills/shared/automation-flows/evals/README.md +5 -0
  281. package/skills/shared/automation-flows/evals/cases.yaml +44 -0
  282. package/skills/shared/automation-flows/references/error-handling.md +58 -0
  283. package/skills/shared/automation-flows/references/n8n-workflow-json.md +63 -0
  284. package/skills/shared/automation-flows/scripts/verify.sh +78 -0
  285. package/skills/shared/aws-essentials/SKILL.md +206 -0
  286. package/skills/shared/aws-essentials/evals/README.md +10 -0
  287. package/skills/shared/aws-essentials/evals/cases.yaml +44 -0
  288. package/skills/shared/aws-essentials/references/iam-least-privilege.md +134 -0
  289. package/skills/shared/aws-essentials/references/rds-cloudfront-recipes.md +127 -0
  290. package/skills/shared/aws-essentials/scripts/verify.sh +99 -0
  291. package/skills/shared/backups/SKILL.md +131 -0
  292. package/skills/shared/backups/evals/README.md +3 -0
  293. package/skills/shared/backups/evals/cases.yaml +42 -0
  294. package/skills/shared/backups/references/engine-recipes.md +121 -0
  295. package/skills/shared/backups/references/restore-runbook.md +65 -0
  296. package/skills/shared/backups/scripts/verify.sh +80 -0
  297. package/skills/shared/bash-scripting/SKILL.md +227 -0
  298. package/skills/shared/bash-scripting/evals/README.md +3 -0
  299. package/skills/shared/bash-scripting/evals/cases.yaml +45 -0
  300. package/skills/shared/bash-scripting/references/portability.md +97 -0
  301. package/skills/shared/bash-scripting/scripts/verify.sh +140 -0
  302. package/skills/shared/building-agents/SKILL.md +386 -0
  303. package/skills/shared/building-agents/evals/README.md +68 -0
  304. package/skills/shared/building-agents/evals/cases.yaml +60 -0
  305. package/skills/shared/building-agents/references/agent-loops-and-harness.md +371 -0
  306. package/skills/shared/building-agents/references/evals-and-observability.md +420 -0
  307. package/skills/shared/building-agents/references/mcp-servers.md +294 -0
  308. package/skills/shared/building-agents/references/provider-abstraction.md +489 -0
  309. package/skills/shared/building-agents/references/tools-and-rag.md +417 -0
  310. package/skills/shared/building-agents/scripts/verify.sh +121 -0
  311. package/skills/shared/chatbot/SKILL.md +151 -0
  312. package/skills/shared/chatbot/evals/README.md +13 -0
  313. package/skills/shared/chatbot/evals/cases.yaml +43 -0
  314. package/skills/shared/chatbot/references/handoff-and-sales.md +71 -0
  315. package/skills/shared/chatbot/references/system-prompt-and-guardrails.md +78 -0
  316. package/skills/shared/chatbot/scripts/verify.sh +162 -0
  317. package/skills/shared/chrome-extension/SKILL.md +169 -0
  318. package/skills/shared/chrome-extension/evals/README.md +12 -0
  319. package/skills/shared/chrome-extension/evals/cases.yaml +40 -0
  320. package/skills/shared/chrome-extension/references/store-and-migration.md +84 -0
  321. package/skills/shared/chrome-extension/scripts/verify.sh +62 -0
  322. package/skills/shared/clarify/SKILL.md +161 -0
  323. package/skills/shared/clarify/evals/README.md +70 -0
  324. package/skills/shared/clarify/evals/cases.yaml +71 -0
  325. package/skills/shared/clickhouse-analytics/SKILL.md +159 -0
  326. package/skills/shared/clickhouse-analytics/evals/README.md +3 -0
  327. package/skills/shared/clickhouse-analytics/evals/cases.yaml +45 -0
  328. package/skills/shared/clickhouse-analytics/references/ingestion-and-mvs.md +109 -0
  329. package/skills/shared/clickhouse-analytics/references/query-optimization.md +76 -0
  330. package/skills/shared/clickhouse-analytics/references/schema-and-engines.md +63 -0
  331. package/skills/shared/clickhouse-analytics/scripts/verify.sh +109 -0
  332. package/skills/shared/cloudflare/SKILL.md +186 -0
  333. package/skills/shared/cloudflare/evals/README.md +15 -0
  334. package/skills/shared/cloudflare/evals/cases.yaml +46 -0
  335. package/skills/shared/cloudflare/references/storage-primitives.md +104 -0
  336. package/skills/shared/cloudflare/references/wrangler-config.md +91 -0
  337. package/skills/shared/cloudflare/scripts/verify.sh +133 -0
  338. package/skills/shared/code-review/SKILL.md +132 -0
  339. package/skills/shared/code-review/evals/README.md +3 -0
  340. package/skills/shared/code-review/evals/cases.yaml +55 -0
  341. package/skills/shared/code-review/references/pr-workflow.md +67 -0
  342. package/skills/shared/codebase-onboarding/SKILL.md +128 -0
  343. package/skills/shared/codebase-onboarding/evals/README.md +3 -0
  344. package/skills/shared/codebase-onboarding/evals/cases.yaml +69 -0
  345. package/skills/shared/codebase-onboarding/references/recon-playbook.md +57 -0
  346. package/skills/shared/codebase-onboarding/scripts/verify.sh +54 -0
  347. package/skills/shared/compose-multiplatform/SKILL.md +198 -0
  348. package/skills/shared/compose-multiplatform/evals/README.md +3 -0
  349. package/skills/shared/compose-multiplatform/evals/cases.yaml +40 -0
  350. package/skills/shared/compose-multiplatform/references/ios-interop.md +91 -0
  351. package/skills/shared/compose-multiplatform/references/project-setup.md +96 -0
  352. package/skills/shared/compose-multiplatform/scripts/verify.sh +123 -0
  353. package/skills/shared/connect-tool/SKILL.md +163 -0
  354. package/skills/shared/connect-tool/evals/cases.yaml +58 -0
  355. package/skills/shared/constitution/SKILL.md +158 -0
  356. package/skills/shared/constitution/evals/README.md +68 -0
  357. package/skills/shared/constitution/evals/cases.yaml +72 -0
  358. package/skills/shared/constitution/references/constitution-template.md +100 -0
  359. package/skills/shared/context-budget/SKILL.md +114 -0
  360. package/skills/shared/context-budget/evals/README.md +11 -0
  361. package/skills/shared/context-budget/evals/cases.yaml +40 -0
  362. package/skills/shared/context-budget/references/handoff-and-compaction.md +96 -0
  363. package/skills/shared/continuous-learning/SKILL.md +106 -0
  364. package/skills/shared/continuous-learning/evals/README.md +16 -0
  365. package/skills/shared/continuous-learning/evals/cases.yaml +39 -0
  366. package/skills/shared/continuous-learning/references/lesson-routing.md +106 -0
  367. package/skills/shared/coolify/SKILL.md +194 -0
  368. package/skills/shared/coolify/evals/README.md +21 -0
  369. package/skills/shared/coolify/evals/cases.yaml +46 -0
  370. package/skills/shared/coolify/references/databases-and-backups.md +99 -0
  371. package/skills/shared/coolify/references/deploy-recipes.md +105 -0
  372. package/skills/shared/coolify/references/install-and-proxy.md +80 -0
  373. package/skills/shared/coolify/scripts/verify.sh +123 -0
  374. package/skills/shared/cost-tracking/SKILL.md +176 -0
  375. package/skills/shared/cost-tracking/evals/README.md +3 -0
  376. package/skills/shared/cost-tracking/evals/cases.yaml +45 -0
  377. package/skills/shared/cost-tracking/references/cloud-caps.md +52 -0
  378. package/skills/shared/cost-tracking/references/pricing-tables.md +51 -0
  379. package/skills/shared/cost-tracking/scripts/verify.sh +135 -0
  380. package/skills/shared/cpp/SKILL.md +302 -0
  381. package/skills/shared/cpp/evals/README.md +14 -0
  382. package/skills/shared/cpp/evals/cases.yaml +44 -0
  383. package/skills/shared/cpp/references/cmake.md +167 -0
  384. package/skills/shared/cpp/references/move-and-templates.md +130 -0
  385. package/skills/shared/cpp/references/undefined-behavior.md +86 -0
  386. package/skills/shared/cpp/scripts/verify.sh +165 -0
  387. package/skills/shared/csharp-dotnet/SKILL.md +272 -0
  388. package/skills/shared/csharp-dotnet/evals/README.md +3 -0
  389. package/skills/shared/csharp-dotnet/evals/cases.yaml +48 -0
  390. package/skills/shared/csharp-dotnet/references/aspnetcore.md +99 -0
  391. package/skills/shared/csharp-dotnet/references/async.md +82 -0
  392. package/skills/shared/csharp-dotnet/references/efcore.md +96 -0
  393. package/skills/shared/csharp-dotnet/scripts/verify.sh +90 -0
  394. package/skills/shared/data-cleaning/SKILL.md +259 -0
  395. package/skills/shared/data-cleaning/evals/README.md +16 -0
  396. package/skills/shared/data-cleaning/evals/cases.yaml +57 -0
  397. package/skills/shared/data-cleaning/references/normalization-recipes.md +136 -0
  398. package/skills/shared/data-cleaning/references/validation-patterns.md +134 -0
  399. package/skills/shared/data-cleaning/scripts/verify.sh +115 -0
  400. package/skills/shared/data-scraper/SKILL.md +130 -0
  401. package/skills/shared/data-scraper/evals/README.md +3 -0
  402. package/skills/shared/data-scraper/evals/cases.yaml +46 -0
  403. package/skills/shared/data-scraper/references/anti-bot.md +85 -0
  404. package/skills/shared/data-scraper/references/frameworks.md +116 -0
  405. package/skills/shared/data-scraper/references/legal-compliance.md +64 -0
  406. package/skills/shared/data-scraper/scripts/verify.sh +166 -0
  407. package/skills/shared/db-migrations/SKILL.md +237 -0
  408. package/skills/shared/db-migrations/evals/README.md +10 -0
  409. package/skills/shared/db-migrations/evals/cases.yaml +46 -0
  410. package/skills/shared/db-migrations/references/backfill-and-batching.md +105 -0
  411. package/skills/shared/db-migrations/references/expand-contract-playbook.md +152 -0
  412. package/skills/shared/db-migrations/references/tools-and-runners.md +88 -0
  413. package/skills/shared/db-migrations/scripts/verify.sh +112 -0
  414. package/skills/shared/debug/SKILL.md +188 -0
  415. package/skills/shared/debug/evals/README.md +88 -0
  416. package/skills/shared/debug/evals/cases.yaml +74 -0
  417. package/skills/shared/decision-challenge/SKILL.md +113 -0
  418. package/skills/shared/decision-challenge/evals/README.md +3 -0
  419. package/skills/shared/decision-challenge/evals/cases.yaml +42 -0
  420. package/skills/shared/decision-records/SKILL.md +202 -0
  421. package/skills/shared/decision-records/evals/README.md +3 -0
  422. package/skills/shared/decision-records/evals/cases.yaml +43 -0
  423. package/skills/shared/decision-records/references/templates.md +252 -0
  424. package/skills/shared/decision-records/scripts/verify.sh +105 -0
  425. package/skills/shared/deep-learning/SKILL.md +226 -0
  426. package/skills/shared/deep-learning/evals/README.md +11 -0
  427. package/skills/shared/deep-learning/evals/cases.yaml +48 -0
  428. package/skills/shared/deep-learning/references/distributed.md +105 -0
  429. package/skills/shared/deep-learning/references/training-recipes.md +135 -0
  430. package/skills/shared/deployment/SKILL.md +374 -0
  431. package/skills/shared/deployment/evals/README.md +50 -0
  432. package/skills/shared/deployment/evals/cases.yaml +53 -0
  433. package/skills/shared/deployment/references/coolify.md +216 -0
  434. package/skills/shared/deployment/references/dockerfiles-by-stack.md +319 -0
  435. package/skills/shared/deployment/references/github-actions.md +295 -0
  436. package/skills/shared/deployment/references/hosting-targets.md +272 -0
  437. package/skills/shared/deployment/scripts/verify.sh +134 -0
  438. package/skills/shared/deprecation/SKILL.md +123 -0
  439. package/skills/shared/deprecation/evals/README.md +3 -0
  440. package/skills/shared/deprecation/evals/cases.yaml +42 -0
  441. package/skills/shared/design/IMPECCABLE-LICENSE.txt +191 -0
  442. package/skills/shared/design/SKILL.md +111 -0
  443. package/skills/shared/design/THIRD_PARTY.md +26 -0
  444. package/skills/shared/design/engine/LICENSE +21 -0
  445. package/skills/shared/design/engine/RUN.md +515 -0
  446. package/skills/shared/design/engine/UPSTREAM.json +4 -0
  447. package/skills/shared/design/engine/assets/app.css +216 -0
  448. package/skills/shared/design/engine/assets/base.css +105 -0
  449. package/skills/shared/design/engine/assets/base.js +37 -0
  450. package/skills/shared/design/engine/assets/charts.js +617 -0
  451. package/skills/shared/design/engine/assets/scenes/stage.css +28 -0
  452. package/skills/shared/design/engine/assets/scenes/stage.js +133 -0
  453. package/skills/shared/design/engine/library/app.json +1327 -0
  454. package/skills/shared/design/engine/library/directions.json +1078 -0
  455. package/skills/shared/design/engine/library/heroes.json +1086 -0
  456. package/skills/shared/design/engine/library/motions.json +92 -0
  457. package/skills/shared/design/engine/library/palettes.json +1485 -0
  458. package/skills/shared/design/engine/library/photos.json +7240 -0
  459. package/skills/shared/design/engine/library/sections.json +4429 -0
  460. package/skills/shared/design/engine/library/sites.json +8350 -0
  461. package/skills/shared/design/engine/library/type.json +2024 -0
  462. package/skills/shared/design/engine/references/app-screens.md +1199 -0
  463. package/skills/shared/design/engine/references/colour.md +141 -0
  464. package/skills/shared/design/engine/references/copy.md +177 -0
  465. package/skills/shared/design/engine/references/critique.md +182 -0
  466. package/skills/shared/design/engine/references/imagery.md +791 -0
  467. package/skills/shared/design/engine/references/layout.md +292 -0
  468. package/skills/shared/design/engine/references/motion.md +980 -0
  469. package/skills/shared/design/engine/references/research.md +356 -0
  470. package/skills/shared/design/engine/references/scenes.md +174 -0
  471. package/skills/shared/design/engine/references/tells.md +115 -0
  472. package/skills/shared/design/engine/references/type.md +170 -0
  473. package/skills/shared/design/engine/scripts/assets.mjs +865 -0
  474. package/skills/shared/design/engine/scripts/draw.mjs +584 -0
  475. package/skills/shared/design/engine/scripts/inspect.mjs +303 -0
  476. package/skills/shared/design/engine/scripts/lib/app-draw.mjs +203 -0
  477. package/skills/shared/design/engine/scripts/lib/cdp.mjs +248 -0
  478. package/skills/shared/design/engine/scripts/lib/probe.mjs +909 -0
  479. package/skills/shared/design/engine/scripts/lib/rules.mjs +243 -0
  480. package/skills/shared/design/engine/scripts/lint.mjs +119 -0
  481. package/skills/shared/design/engine/scripts/scenes.mjs +124 -0
  482. package/skills/shared/design/evals/cases.yaml +45 -0
  483. package/skills/shared/design/references/design-md.md +49 -0
  484. package/skills/shared/design/references/finish-review.md +46 -0
  485. package/skills/shared/design/references/modes.md +51 -0
  486. package/skills/shared/digitalocean/SKILL.md +227 -0
  487. package/skills/shared/digitalocean/evals/README.md +10 -0
  488. package/skills/shared/digitalocean/evals/cases.yaml +37 -0
  489. package/skills/shared/digitalocean/references/app-spec.md +126 -0
  490. package/skills/shared/digitalocean/references/droplet-ops.md +95 -0
  491. package/skills/shared/digitalocean/scripts/verify.sh +102 -0
  492. package/skills/shared/django/SKILL.md +263 -0
  493. package/skills/shared/django/evals/README.md +11 -0
  494. package/skills/shared/django/evals/cases.yaml +47 -0
  495. package/skills/shared/django/references/drf.md +109 -0
  496. package/skills/shared/django/references/orm-performance.md +91 -0
  497. package/skills/shared/django/references/security.md +81 -0
  498. package/skills/shared/django/references/testing.md +86 -0
  499. package/skills/shared/django/scripts/verify.sh +115 -0
  500. package/skills/shared/docker/SKILL.md +251 -0
  501. package/skills/shared/docker/evals/README.md +10 -0
  502. package/skills/shared/docker/evals/cases.yaml +44 -0
  503. package/skills/shared/docker/references/base-images-and-stages.md +104 -0
  504. package/skills/shared/docker/references/compose-recipes.md +109 -0
  505. package/skills/shared/docker/scripts/verify.sh +149 -0
  506. package/skills/shared/domains-dns/SKILL.md +131 -0
  507. package/skills/shared/domains-dns/evals/README.md +16 -0
  508. package/skills/shared/domains-dns/evals/cases.yaml +47 -0
  509. package/skills/shared/domains-dns/references/record-cookbook.md +94 -0
  510. package/skills/shared/domains-dns/references/tls-and-acme.md +90 -0
  511. package/skills/shared/domains-dns/references/verify-and-debug.md +64 -0
  512. package/skills/shared/domains-dns/scripts/verify.sh +163 -0
  513. package/skills/shared/drizzle-orm/SKILL.md +231 -0
  514. package/skills/shared/drizzle-orm/evals/README.md +12 -0
  515. package/skills/shared/drizzle-orm/evals/cases.yaml +47 -0
  516. package/skills/shared/drizzle-orm/references/relations-and-drivers.md +118 -0
  517. package/skills/shared/drizzle-orm/scripts/verify.sh +155 -0
  518. package/skills/shared/duckdb/SKILL.md +202 -0
  519. package/skills/shared/duckdb/evals/README.md +31 -0
  520. package/skills/shared/duckdb/evals/cases.yaml +41 -0
  521. package/skills/shared/duckdb/references/python-and-interop.md +105 -0
  522. package/skills/shared/duckdb/references/remote-and-lakehouse.md +101 -0
  523. package/skills/shared/duckdb/scripts/verify.sh +71 -0
  524. package/skills/shared/dynamodb/SKILL.md +204 -0
  525. package/skills/shared/dynamodb/evals/README.md +8 -0
  526. package/skills/shared/dynamodb/evals/cases.yaml +46 -0
  527. package/skills/shared/dynamodb/references/access-patterns.md +127 -0
  528. package/skills/shared/dynamodb/references/capacity-and-limits.md +78 -0
  529. package/skills/shared/dynamodb/scripts/verify.sh +108 -0
  530. package/skills/shared/e2e-testing/SKILL.md +233 -0
  531. package/skills/shared/e2e-testing/evals/README.md +10 -0
  532. package/skills/shared/e2e-testing/evals/cases.yaml +64 -0
  533. package/skills/shared/e2e-testing/references/config-and-ci.md +156 -0
  534. package/skills/shared/e2e-testing/references/flakiness-playbook.md +124 -0
  535. package/skills/shared/e2e-testing/scripts/verify.sh +117 -0
  536. package/skills/shared/electron/SKILL.md +209 -0
  537. package/skills/shared/electron/evals/README.md +13 -0
  538. package/skills/shared/electron/evals/cases.yaml +38 -0
  539. package/skills/shared/electron/references/packaging-and-updates.md +122 -0
  540. package/skills/shared/electron/references/security-and-ipc.md +158 -0
  541. package/skills/shared/electron/scripts/verify.sh +143 -0
  542. package/skills/shared/elixir/SKILL.md +209 -0
  543. package/skills/shared/elixir/evals/README.md +3 -0
  544. package/skills/shared/elixir/evals/cases.yaml +41 -0
  545. package/skills/shared/elixir/references/mix-and-releases.md +91 -0
  546. package/skills/shared/elixir/references/otp-patterns.md +96 -0
  547. package/skills/shared/elixir/scripts/verify.sh +76 -0
  548. package/skills/shared/email-deliverability/SKILL.md +148 -0
  549. package/skills/shared/email-deliverability/evals/README.md +21 -0
  550. package/skills/shared/email-deliverability/evals/cases.yaml +45 -0
  551. package/skills/shared/email-deliverability/scripts/verify.sh +98 -0
  552. package/skills/shared/embeddings-search/SKILL.md +184 -0
  553. package/skills/shared/embeddings-search/evals/README.md +10 -0
  554. package/skills/shared/embeddings-search/evals/cases.yaml +44 -0
  555. package/skills/shared/embeddings-search/references/evaluation.md +86 -0
  556. package/skills/shared/embeddings-search/references/models.md +73 -0
  557. package/skills/shared/embeddings-search/scripts/verify.sh +103 -0
  558. package/skills/shared/error-handling/SKILL.md +273 -0
  559. package/skills/shared/error-handling/evals/README.md +12 -0
  560. package/skills/shared/error-handling/evals/cases.yaml +46 -0
  561. package/skills/shared/error-handling/references/boundaries-and-messaging.md +120 -0
  562. package/skills/shared/error-handling/references/retry-and-resilience.md +154 -0
  563. package/skills/shared/error-handling/scripts/verify.sh +110 -0
  564. package/skills/shared/expo/SKILL.md +243 -0
  565. package/skills/shared/expo/evals/README.md +13 -0
  566. package/skills/shared/expo/evals/cases.yaml +44 -0
  567. package/skills/shared/expo/references/config-plugins.md +117 -0
  568. package/skills/shared/expo/references/eas-update.md +118 -0
  569. package/skills/shared/expo/scripts/verify.sh +132 -0
  570. package/skills/shared/fal/SKILL.md +196 -0
  571. package/skills/shared/fal/evals/README.md +3 -0
  572. package/skills/shared/fal/evals/cases.yaml +42 -0
  573. package/skills/shared/fal/references/models-and-cost.md +53 -0
  574. package/skills/shared/fal/references/queue-and-webhooks.md +153 -0
  575. package/skills/shared/fal/scripts/verify.sh +72 -0
  576. package/skills/shared/fastapi/SKILL.md +469 -0
  577. package/skills/shared/fastapi/evals/README.md +50 -0
  578. package/skills/shared/fastapi/evals/cases.yaml +55 -0
  579. package/skills/shared/fastapi/references/database.md +347 -0
  580. package/skills/shared/fastapi/references/production.md +338 -0
  581. package/skills/shared/fastapi/references/security.md +330 -0
  582. package/skills/shared/fastapi/references/testing.md +349 -0
  583. package/skills/shared/fastapi/scripts/verify.sh +157 -0
  584. package/skills/shared/finetuning/SKILL.md +232 -0
  585. package/skills/shared/finetuning/evals/README.md +13 -0
  586. package/skills/shared/finetuning/evals/cases.yaml +50 -0
  587. package/skills/shared/finetuning/references/hyperparameters-and-eval.md +74 -0
  588. package/skills/shared/finetuning/references/methods.md +189 -0
  589. package/skills/shared/firebase/SKILL.md +237 -0
  590. package/skills/shared/firebase/evals/README.md +12 -0
  591. package/skills/shared/firebase/evals/cases.yaml +45 -0
  592. package/skills/shared/firebase/references/cloud-functions.md +102 -0
  593. package/skills/shared/firebase/references/data-modeling.md +108 -0
  594. package/skills/shared/firebase/references/security-rules.md +137 -0
  595. package/skills/shared/firebase/scripts/verify.sh +98 -0
  596. package/skills/shared/flutter/SKILL.md +400 -0
  597. package/skills/shared/flutter/evals/README.md +54 -0
  598. package/skills/shared/flutter/evals/cases.yaml +69 -0
  599. package/skills/shared/flutter/references/architecture-and-state.md +499 -0
  600. package/skills/shared/flutter/references/i18n-and-dependencies.md +197 -0
  601. package/skills/shared/flutter/references/performance.md +299 -0
  602. package/skills/shared/flutter/references/testing.md +385 -0
  603. package/skills/shared/flutter/references/ui-and-navigation.md +378 -0
  604. package/skills/shared/flutter/scripts/verify.sh +104 -0
  605. package/skills/shared/fly-io/SKILL.md +197 -0
  606. package/skills/shared/fly-io/evals/README.md +3 -0
  607. package/skills/shared/fly-io/evals/cases.yaml +42 -0
  608. package/skills/shared/fly-io/references/fly-toml.md +155 -0
  609. package/skills/shared/fly-io/references/multi-region.md +66 -0
  610. package/skills/shared/fly-io/scripts/verify.sh +90 -0
  611. package/skills/shared/ftd/SKILL.md +111 -0
  612. package/skills/shared/ftd/evals/cases.yaml +66 -0
  613. package/skills/shared/ftd/evals/routing.json +24 -0
  614. package/skills/shared/game-design/SKILL.md +146 -0
  615. package/skills/shared/game-design/evals/README.md +13 -0
  616. package/skills/shared/game-design/evals/cases.yaml +47 -0
  617. package/skills/shared/game-design/references/mechanics-and-loops.md +78 -0
  618. package/skills/shared/game-design/references/playtesting-and-scope.md +58 -0
  619. package/skills/shared/game-design/references/progression-and-economy.md +70 -0
  620. package/skills/shared/game-storytelling/SKILL.md +134 -0
  621. package/skills/shared/game-storytelling/evals/README.md +28 -0
  622. package/skills/shared/game-storytelling/evals/cases.yaml +51 -0
  623. package/skills/shared/game-storytelling/references/branching-and-state.md +134 -0
  624. package/skills/shared/game-storytelling/references/dialogue-tools.md +117 -0
  625. package/skills/shared/game-storytelling/references/environmental-storytelling.md +71 -0
  626. package/skills/shared/gamedev-multiplayer/SKILL.md +237 -0
  627. package/skills/shared/gamedev-multiplayer/evals/README.md +12 -0
  628. package/skills/shared/gamedev-multiplayer/evals/cases.yaml +44 -0
  629. package/skills/shared/gamedev-multiplayer/references/godot-high-level-multiplayer.md +133 -0
  630. package/skills/shared/gamedev-multiplayer/references/prediction-and-latency.md +104 -0
  631. package/skills/shared/gamedev-multiplayer/references/unity-and-unreal-netcode.md +166 -0
  632. package/skills/shared/gamedev-pathing/SKILL.md +233 -0
  633. package/skills/shared/gamedev-pathing/evals/README.md +14 -0
  634. package/skills/shared/gamedev-pathing/evals/cases.yaml +49 -0
  635. package/skills/shared/gamedev-pathing/references/navmesh-workflow.md +110 -0
  636. package/skills/shared/gamedev-pathing/references/search-algorithms.md +135 -0
  637. package/skills/shared/gamedev-pathing/references/steering-and-avoidance.md +120 -0
  638. package/skills/shared/gamedev-physics/SKILL.md +225 -0
  639. package/skills/shared/gamedev-physics/evals/README.md +12 -0
  640. package/skills/shared/gamedev-physics/evals/cases.yaml +54 -0
  641. package/skills/shared/gamedev-physics/references/character-controllers.md +120 -0
  642. package/skills/shared/gamedev-physics/references/determinism-and-queries.md +124 -0
  643. package/skills/shared/gamedev-physics/references/layers-and-masks.md +115 -0
  644. package/skills/shared/gamedev-shaders/SKILL.md +232 -0
  645. package/skills/shared/gamedev-shaders/evals/README.md +14 -0
  646. package/skills/shared/gamedev-shaders/evals/cases.yaml +45 -0
  647. package/skills/shared/gamedev-shaders/references/effect-recipes.md +205 -0
  648. package/skills/shared/gamedev-shaders/references/godot-shading-language.md +133 -0
  649. package/skills/shared/gamedev-shaders/references/unity-and-unreal-shaders.md +169 -0
  650. package/skills/shared/gamedev-shipping/SKILL.md +220 -0
  651. package/skills/shared/gamedev-shipping/evals/README.md +9 -0
  652. package/skills/shared/gamedev-shipping/evals/cases.yaml +55 -0
  653. package/skills/shared/gamedev-shipping/references/mobile-and-desktop.md +127 -0
  654. package/skills/shared/gamedev-shipping/references/stores-and-ci.md +162 -0
  655. package/skills/shared/gamedev-shipping/references/web-export-headers.md +140 -0
  656. package/skills/shared/gcp-essentials/SKILL.md +324 -0
  657. package/skills/shared/gcp-essentials/evals/README.md +12 -0
  658. package/skills/shared/gcp-essentials/evals/cases.yaml +38 -0
  659. package/skills/shared/gcp-essentials/references/deploy-recipes.md +81 -0
  660. package/skills/shared/gcp-essentials/references/iam-and-auth.md +94 -0
  661. package/skills/shared/gcp-essentials/references/networking-and-sql.md +74 -0
  662. package/skills/shared/gcp-essentials/scripts/verify.sh +158 -0
  663. package/skills/shared/git-workflow/SKILL.md +214 -0
  664. package/skills/shared/git-workflow/evals/README.md +10 -0
  665. package/skills/shared/git-workflow/evals/cases.yaml +52 -0
  666. package/skills/shared/git-workflow/references/gitmoji.md +157 -0
  667. package/skills/shared/git-workflow/references/interactive-rebase.md +89 -0
  668. package/skills/shared/github-actions/SKILL.md +244 -0
  669. package/skills/shared/github-actions/evals/README.md +3 -0
  670. package/skills/shared/github-actions/evals/cases.yaml +45 -0
  671. package/skills/shared/github-actions/references/caching-and-matrix.md +92 -0
  672. package/skills/shared/github-actions/references/oidc-deploys.md +130 -0
  673. package/skills/shared/github-actions/scripts/verify.sh +105 -0
  674. package/skills/shared/gitlab-auth/SKILL.md +99 -0
  675. package/skills/shared/gitlab-workflow/SKILL.md +138 -0
  676. package/skills/shared/go/SKILL.md +390 -0
  677. package/skills/shared/go/evals/README.md +56 -0
  678. package/skills/shared/go/evals/cases.yaml +55 -0
  679. package/skills/shared/go/references/concurrency.md +557 -0
  680. package/skills/shared/go/references/http-services.md +529 -0
  681. package/skills/shared/go/references/testing.md +338 -0
  682. package/skills/shared/go/scripts/verify.sh +134 -0
  683. package/skills/shared/godot/SKILL.md +300 -0
  684. package/skills/shared/godot/evals/README.md +13 -0
  685. package/skills/shared/godot/evals/cases.yaml +50 -0
  686. package/skills/shared/godot/references/export-and-testing.md +102 -0
  687. package/skills/shared/godot/references/gdscript-style.md +84 -0
  688. package/skills/shared/godot/references/godot3-to-4-traps.md +89 -0
  689. package/skills/shared/godot/references/nodes-scenes-resources.md +109 -0
  690. package/skills/shared/harness/SKILL.md +316 -0
  691. package/skills/shared/harness/assets/_TEMPLATE/.env.example +8 -0
  692. package/skills/shared/harness/assets/_TEMPLATE/CREDENTIALS.md +25 -0
  693. package/skills/shared/harness/assets/_TEMPLATE/README.md +25 -0
  694. package/skills/shared/harness/assets/_TEMPLATE/gitignore +10 -0
  695. package/skills/shared/harness/assets/_TEMPLATE/test_connection.sh +30 -0
  696. package/skills/shared/harness/evals/README.md +54 -0
  697. package/skills/shared/harness/evals/cases.yaml +72 -0
  698. package/skills/shared/harness/examples/audit-example.md +120 -0
  699. package/skills/shared/harness/references/agents-md-template.md +41 -0
  700. package/skills/shared/harness/references/audit-report-template.html +140 -0
  701. package/skills/shared/harness/references/audit-report-template.md +116 -0
  702. package/skills/shared/harness/references/claude-md-template.md +85 -0
  703. package/skills/shared/harness/references/daily-curation-automation.md +68 -0
  704. package/skills/shared/harness/references/inbox-readme-template.md +51 -0
  705. package/skills/shared/harness/references/ingest-formats.md +185 -0
  706. package/skills/shared/harness/references/ingest-ignore-defaults.md +48 -0
  707. package/skills/shared/harness/references/obsidian-scaffolding.md +103 -0
  708. package/skills/shared/harness/references/providers.yaml +3546 -0
  709. package/skills/shared/harness/references/tools-readme-template.md +88 -0
  710. package/skills/shared/harness/references/wiki-archive-template.html +81 -0
  711. package/skills/shared/harness/references/wiki-article-template.md +60 -0
  712. package/skills/shared/harness/references/wiki-dashboard-template.html +136 -0
  713. package/skills/shared/harness/references/wiki-deep-improve-report-template.html +126 -0
  714. package/skills/shared/harness/references/wiki-gaps-template.md +22 -0
  715. package/skills/shared/harness/references/wiki-index-template.md +32 -0
  716. package/skills/shared/harness/references/wiki-protocol.md +926 -0
  717. package/skills/shared/harness/references/wiki-raw-template.md +7 -0
  718. package/skills/shared/harness/references/wiki-worklog-template.md +60 -0
  719. package/skills/shared/hetzner/SKILL.md +203 -0
  720. package/skills/shared/hetzner/evals/README.md +35 -0
  721. package/skills/shared/hetzner/evals/cases.yaml +46 -0
  722. package/skills/shared/hetzner/references/cloud-init.md +120 -0
  723. package/skills/shared/hetzner/references/plans-and-locations.md +56 -0
  724. package/skills/shared/hetzner/scripts/verify.sh +122 -0
  725. package/skills/shared/htmx/SKILL.md +261 -0
  726. package/skills/shared/htmx/evals/README.md +3 -0
  727. package/skills/shared/htmx/evals/cases.yaml +38 -0
  728. package/skills/shared/htmx/references/patterns.md +113 -0
  729. package/skills/shared/htmx/references/server-contract.md +91 -0
  730. package/skills/shared/htmx/scripts/verify.sh +93 -0
  731. package/skills/shared/huggingface/SKILL.md +191 -0
  732. package/skills/shared/huggingface/evals/README.md +11 -0
  733. package/skills/shared/huggingface/evals/cases.yaml +41 -0
  734. package/skills/shared/huggingface/references/endpoints-and-spaces.md +99 -0
  735. package/skills/shared/huggingface/references/hub-and-cli.md +85 -0
  736. package/skills/shared/huggingface/references/inference-providers.md +115 -0
  737. package/skills/shared/huggingface/scripts/verify.sh +123 -0
  738. package/skills/shared/idea-refinement/SKILL.md +121 -0
  739. package/skills/shared/idea-refinement/evals/README.md +3 -0
  740. package/skills/shared/idea-refinement/evals/cases.yaml +42 -0
  741. package/skills/shared/implement/SKILL.md +383 -0
  742. package/skills/shared/implement/evals/README.md +56 -0
  743. package/skills/shared/implement/evals/cases.yaml +43 -0
  744. package/skills/shared/implement/references/per-task-review.md +46 -0
  745. package/skills/shared/implement/scripts/review-package +59 -0
  746. package/skills/shared/implement/scripts/sdd-workspace +47 -0
  747. package/skills/shared/implement/scripts/task-brief +77 -0
  748. package/skills/shared/init/SKILL.md +209 -0
  749. package/skills/shared/init/evals/README.md +49 -0
  750. package/skills/shared/init/evals/cases.yaml +74 -0
  751. package/skills/shared/init/references/accompaniment-and-profile.md +122 -0
  752. package/skills/shared/init/references/discovery.md +90 -0
  753. package/skills/shared/init/references/recommend-skills.md +115 -0
  754. package/skills/shared/init/scripts/verify.sh +118 -0
  755. package/skills/shared/java/SKILL.md +341 -0
  756. package/skills/shared/java/evals/README.md +23 -0
  757. package/skills/shared/java/evals/cases.yaml +43 -0
  758. package/skills/shared/java/references/builds.md +133 -0
  759. package/skills/shared/java/references/concurrency.md +108 -0
  760. package/skills/shared/java/references/streams.md +102 -0
  761. package/skills/shared/java/scripts/verify.sh +107 -0
  762. package/skills/shared/knowledge-ops/SKILL.md +122 -0
  763. package/skills/shared/knowledge-ops/evals/README.md +16 -0
  764. package/skills/shared/knowledge-ops/evals/cases.yaml +50 -0
  765. package/skills/shared/knowledge-ops/references/gardening-playbook.md +126 -0
  766. package/skills/shared/kotlin-android/SKILL.md +245 -0
  767. package/skills/shared/kotlin-android/evals/README.md +13 -0
  768. package/skills/shared/kotlin-android/evals/cases.yaml +56 -0
  769. package/skills/shared/kotlin-android/references/architecture.md +200 -0
  770. package/skills/shared/kotlin-android/references/gradle-setup.md +125 -0
  771. package/skills/shared/kotlin-android/scripts/verify.sh +109 -0
  772. package/skills/shared/laravel/SKILL.md +301 -0
  773. package/skills/shared/laravel/evals/README.md +10 -0
  774. package/skills/shared/laravel/evals/cases.yaml +45 -0
  775. package/skills/shared/laravel/references/eloquent-patterns.md +126 -0
  776. package/skills/shared/laravel/references/queues-and-scheduling.md +153 -0
  777. package/skills/shared/laravel/scripts/verify.sh +128 -0
  778. package/skills/shared/level-design/SKILL.md +143 -0
  779. package/skills/shared/level-design/evals/README.md +35 -0
  780. package/skills/shared/level-design/evals/cases.yaml +58 -0
  781. package/skills/shared/level-design/references/blockout-to-art.md +118 -0
  782. package/skills/shared/level-design/references/guidance-and-readability.md +152 -0
  783. package/skills/shared/level-design/references/pacing-and-encounters.md +142 -0
  784. package/skills/shared/llm-pipeline/SKILL.md +150 -0
  785. package/skills/shared/llm-pipeline/evals/README.md +3 -0
  786. package/skills/shared/llm-pipeline/evals/cases.yaml +44 -0
  787. package/skills/shared/llm-pipeline/references/caching-layers.md +60 -0
  788. package/skills/shared/llm-pipeline/references/litellm-router.md +101 -0
  789. package/skills/shared/llm-pipeline/scripts/verify.sh +169 -0
  790. package/skills/shared/machine-learning/SKILL.md +228 -0
  791. package/skills/shared/machine-learning/evals/README.md +15 -0
  792. package/skills/shared/machine-learning/evals/cases.yaml +54 -0
  793. package/skills/shared/machine-learning/references/gbdt-and-tuning.md +83 -0
  794. package/skills/shared/machine-learning/references/metrics-and-imbalance.md +82 -0
  795. package/skills/shared/machine-learning/references/pipelines-and-cv.md +135 -0
  796. package/skills/shared/modal/SKILL.md +290 -0
  797. package/skills/shared/modal/evals/README.md +29 -0
  798. package/skills/shared/modal/evals/cases.yaml +50 -0
  799. package/skills/shared/modal/references/images-gpu-cookbook.md +160 -0
  800. package/skills/shared/modal/references/web-and-scaling.md +138 -0
  801. package/skills/shared/modal/scripts/verify.sh +127 -0
  802. package/skills/shared/mongodb/SKILL.md +342 -0
  803. package/skills/shared/mongodb/evals/README.md +29 -0
  804. package/skills/shared/mongodb/evals/cases.yaml +41 -0
  805. package/skills/shared/mongodb/references/aggregation.md +115 -0
  806. package/skills/shared/mongodb/references/data-modeling.md +135 -0
  807. package/skills/shared/mongodb/references/transactions-and-ops.md +128 -0
  808. package/skills/shared/mongodb/scripts/verify.sh +151 -0
  809. package/skills/shared/monitoring/SKILL.md +155 -0
  810. package/skills/shared/monitoring/evals/README.md +3 -0
  811. package/skills/shared/monitoring/evals/cases.yaml +47 -0
  812. package/skills/shared/monitoring/references/burn-rate-and-oncall.md +128 -0
  813. package/skills/shared/monitoring/references/tool-setup.md +154 -0
  814. package/skills/shared/monitoring/scripts/verify.sh +145 -0
  815. package/skills/shared/mysql/SKILL.md +249 -0
  816. package/skills/shared/mysql/evals/README.md +12 -0
  817. package/skills/shared/mysql/evals/cases.yaml +49 -0
  818. package/skills/shared/mysql/references/indexing-and-explain.md +161 -0
  819. package/skills/shared/mysql/references/mysql-vs-mariadb.md +78 -0
  820. package/skills/shared/mysql/references/online-ddl-and-migrations.md +120 -0
  821. package/skills/shared/mysql/references/replication-and-ha.md +115 -0
  822. package/skills/shared/mysql/scripts/verify.sh +141 -0
  823. package/skills/shared/neon/SKILL.md +218 -0
  824. package/skills/shared/neon/evals/README.md +11 -0
  825. package/skills/shared/neon/evals/cases.yaml +45 -0
  826. package/skills/shared/neon/references/branching-ci.md +86 -0
  827. package/skills/shared/neon/scripts/verify.sh +78 -0
  828. package/skills/shared/nestjs/SKILL.md +217 -0
  829. package/skills/shared/nestjs/evals/README.md +3 -0
  830. package/skills/shared/nestjs/evals/cases.yaml +38 -0
  831. package/skills/shared/nestjs/references/cross-cutting.md +135 -0
  832. package/skills/shared/nestjs/references/testing-recipes.md +105 -0
  833. package/skills/shared/nestjs/scripts/verify.sh +98 -0
  834. package/skills/shared/netlify/SKILL.md +208 -0
  835. package/skills/shared/netlify/evals/README.md +13 -0
  836. package/skills/shared/netlify/evals/cases.yaml +43 -0
  837. package/skills/shared/netlify/references/functions.md +97 -0
  838. package/skills/shared/netlify/references/netlify-toml.md +115 -0
  839. package/skills/shared/netlify/scripts/verify.sh +95 -0
  840. package/skills/shared/nextjs/SKILL.md +400 -0
  841. package/skills/shared/nextjs/evals/README.md +59 -0
  842. package/skills/shared/nextjs/evals/cases.yaml +56 -0
  843. package/skills/shared/nextjs/references/data-and-caching.md +309 -0
  844. package/skills/shared/nextjs/references/metadata.md +208 -0
  845. package/skills/shared/nextjs/references/performance.md +325 -0
  846. package/skills/shared/nextjs/references/react.md +383 -0
  847. package/skills/shared/nextjs/references/security.md +239 -0
  848. package/skills/shared/nextjs/references/testing.md +290 -0
  849. package/skills/shared/nextjs/scripts/verify.sh +141 -0
  850. package/skills/shared/nlp/SKILL.md +225 -0
  851. package/skills/shared/nlp/evals/README.md +10 -0
  852. package/skills/shared/nlp/evals/cases.yaml +45 -0
  853. package/skills/shared/nlp/references/evaluation.md +107 -0
  854. package/skills/shared/nlp/references/tokenization.md +95 -0
  855. package/skills/shared/no-code-app/SKILL.md +145 -0
  856. package/skills/shared/no-code-app/evals/README.md +3 -0
  857. package/skills/shared/no-code-app/evals/cases.yaml +43 -0
  858. package/skills/shared/no-code-app/references/platform-limits.md +100 -0
  859. package/skills/shared/nodejs/SKILL.md +229 -0
  860. package/skills/shared/nodejs/evals/README.md +3 -0
  861. package/skills/shared/nodejs/evals/cases.yaml +39 -0
  862. package/skills/shared/nodejs/references/express5-migration.md +53 -0
  863. package/skills/shared/nodejs/references/graceful-shutdown.md +73 -0
  864. package/skills/shared/nodejs/scripts/verify.sh +122 -0
  865. package/skills/shared/observability/SKILL.md +235 -0
  866. package/skills/shared/observability/evals/README.md +3 -0
  867. package/skills/shared/observability/evals/cases.yaml +51 -0
  868. package/skills/shared/observability/references/collector-config.md +98 -0
  869. package/skills/shared/observability/references/instrumentation-recipes.md +115 -0
  870. package/skills/shared/observability/scripts/verify.sh +156 -0
  871. package/skills/shared/ollama/SKILL.md +213 -0
  872. package/skills/shared/ollama/evals/README.md +9 -0
  873. package/skills/shared/ollama/evals/cases.yaml +43 -0
  874. package/skills/shared/ollama/references/api.md +148 -0
  875. package/skills/shared/ollama/references/hardware-sizing.md +87 -0
  876. package/skills/shared/ollama/scripts/verify.sh +116 -0
  877. package/skills/shared/open-weights/SKILL.md +239 -0
  878. package/skills/shared/open-weights/evals/README.md +14 -0
  879. package/skills/shared/open-weights/evals/cases.yaml +42 -0
  880. package/skills/shared/open-weights/references/licenses.md +123 -0
  881. package/skills/shared/open-weights/references/model-families.md +83 -0
  882. package/skills/shared/open-weights/references/sizing-and-quant.md +89 -0
  883. package/skills/shared/orient/SKILL.md +92 -0
  884. package/skills/shared/orient/evals/README.md +18 -0
  885. package/skills/shared/orient/evals/cases.yaml +67 -0
  886. package/skills/shared/orient/references/explain-ladder.md +93 -0
  887. package/skills/shared/orient/references/orientation-contract.md +86 -0
  888. package/skills/shared/parallel/SKILL.md +168 -0
  889. package/skills/shared/parallel/evals/README.md +62 -0
  890. package/skills/shared/parallel/evals/cases.yaml +44 -0
  891. package/skills/shared/performance/SKILL.md +229 -0
  892. package/skills/shared/performance/evals/README.md +3 -0
  893. package/skills/shared/performance/evals/cases.yaml +49 -0
  894. package/skills/shared/performance/references/profiling-playbook.md +54 -0
  895. package/skills/shared/performance/scripts/verify.sh +94 -0
  896. package/skills/shared/phoenix/SKILL.md +169 -0
  897. package/skills/shared/phoenix/evals/README.md +3 -0
  898. package/skills/shared/phoenix/evals/cases.yaml +40 -0
  899. package/skills/shared/phoenix/references/auth-and-scopes.md +82 -0
  900. package/skills/shared/phoenix/references/ecto-patterns.md +93 -0
  901. package/skills/shared/phoenix/references/liveview.md +134 -0
  902. package/skills/shared/phoenix/scripts/verify.sh +73 -0
  903. package/skills/shared/php/SKILL.md +397 -0
  904. package/skills/shared/php/evals/README.md +12 -0
  905. package/skills/shared/php/evals/cases.yaml +45 -0
  906. package/skills/shared/php/references/tooling.md +170 -0
  907. package/skills/shared/php/references/type-system.md +220 -0
  908. package/skills/shared/php/scripts/verify.sh +155 -0
  909. package/skills/shared/plan/SKILL.md +166 -0
  910. package/skills/shared/plan/evals/README.md +62 -0
  911. package/skills/shared/plan/evals/cases.yaml +49 -0
  912. package/skills/shared/plan/references/plan-template.md +153 -0
  913. package/skills/shared/planetscale/SKILL.md +198 -0
  914. package/skills/shared/planetscale/evals/README.md +11 -0
  915. package/skills/shared/planetscale/evals/cases.yaml +46 -0
  916. package/skills/shared/planetscale/references/deploy-requests.md +75 -0
  917. package/skills/shared/planetscale/references/no-foreign-keys.md +88 -0
  918. package/skills/shared/planetscale/scripts/verify.sh +115 -0
  919. package/skills/shared/planning-with-files/SKILL.md +278 -0
  920. package/skills/shared/planning-with-files/examples.md +202 -0
  921. package/skills/shared/planning-with-files/reference.md +218 -0
  922. package/skills/shared/planning-with-files/scripts/attest-plan.ps1 +118 -0
  923. package/skills/shared/planning-with-files/scripts/attest-plan.sh +110 -0
  924. package/skills/shared/planning-with-files/scripts/check-complete.ps1 +44 -0
  925. package/skills/shared/planning-with-files/scripts/check-complete.sh +46 -0
  926. package/skills/shared/planning-with-files/scripts/init-session.ps1 +166 -0
  927. package/skills/shared/planning-with-files/scripts/init-session.sh +284 -0
  928. package/skills/shared/planning-with-files/scripts/resolve-plan-dir.ps1 +44 -0
  929. package/skills/shared/planning-with-files/scripts/resolve-plan-dir.sh +76 -0
  930. package/skills/shared/planning-with-files/scripts/session-catchup.py +438 -0
  931. package/skills/shared/planning-with-files/scripts/set-active-plan.ps1 +50 -0
  932. package/skills/shared/planning-with-files/scripts/set-active-plan.sh +50 -0
  933. package/skills/shared/planning-with-files/templates/findings.md +95 -0
  934. package/skills/shared/planning-with-files/templates/progress.md +114 -0
  935. package/skills/shared/planning-with-files/templates/task_plan.md +132 -0
  936. package/skills/shared/postgresdb/SKILL.md +354 -0
  937. package/skills/shared/postgresdb/evals/README.md +55 -0
  938. package/skills/shared/postgresdb/evals/cases.yaml +57 -0
  939. package/skills/shared/postgresdb/references/migrations.md +279 -0
  940. package/skills/shared/postgresdb/references/operations-and-security.md +267 -0
  941. package/skills/shared/postgresdb/references/query-optimization.md +374 -0
  942. package/skills/shared/postgresdb/references/schema-and-indexing.md +379 -0
  943. package/skills/shared/postgresdb/scripts/verify.sh +191 -0
  944. package/skills/shared/prisma-orm/SKILL.md +313 -0
  945. package/skills/shared/prisma-orm/evals/README.md +12 -0
  946. package/skills/shared/prisma-orm/evals/cases.yaml +56 -0
  947. package/skills/shared/prisma-orm/references/migrations-and-v7-upgrade.md +197 -0
  948. package/skills/shared/prisma-orm/references/queries-and-performance.md +169 -0
  949. package/skills/shared/prisma-orm/scripts/verify.sh +137 -0
  950. package/skills/shared/prompt-engineering/SKILL.md +127 -0
  951. package/skills/shared/prompt-engineering/evals/README.md +11 -0
  952. package/skills/shared/prompt-engineering/evals/cases.yaml +46 -0
  953. package/skills/shared/prompt-engineering/references/eval-templates.md +94 -0
  954. package/skills/shared/prompt-engineering/references/output-contracts.md +120 -0
  955. package/skills/shared/prompt-engineering/scripts/verify.sh +84 -0
  956. package/skills/shared/python/SKILL.md +320 -0
  957. package/skills/shared/python/evals/README.md +19 -0
  958. package/skills/shared/python/evals/cases.yaml +46 -0
  959. package/skills/shared/python/references/async.md +136 -0
  960. package/skills/shared/python/references/stdlib.md +162 -0
  961. package/skills/shared/python/references/typing.md +160 -0
  962. package/skills/shared/python/scripts/verify.sh +125 -0
  963. package/skills/shared/rag/SKILL.md +209 -0
  964. package/skills/shared/rag/evals/README.md +13 -0
  965. package/skills/shared/rag/evals/cases.yaml +45 -0
  966. package/skills/shared/rag/references/evaluation.md +99 -0
  967. package/skills/shared/rag/references/pipeline.md +151 -0
  968. package/skills/shared/rag/scripts/verify.sh +99 -0
  969. package/skills/shared/rails/SKILL.md +264 -0
  970. package/skills/shared/rails/evals/README.md +12 -0
  971. package/skills/shared/rails/evals/cases.yaml +47 -0
  972. package/skills/shared/rails/references/activerecord.md +148 -0
  973. package/skills/shared/rails/references/hotwire.md +139 -0
  974. package/skills/shared/rails/references/testing.md +110 -0
  975. package/skills/shared/rails/scripts/verify.sh +128 -0
  976. package/skills/shared/railway/SKILL.md +245 -0
  977. package/skills/shared/railway/evals/README.md +14 -0
  978. package/skills/shared/railway/evals/cases.yaml +44 -0
  979. package/skills/shared/railway/references/cli-cookbook.md +137 -0
  980. package/skills/shared/railway/references/config-as-code.md +120 -0
  981. package/skills/shared/railway/scripts/verify.sh +162 -0
  982. package/skills/shared/react/SKILL.md +182 -0
  983. package/skills/shared/react/evals/README.md +3 -0
  984. package/skills/shared/react/evals/cases.yaml +43 -0
  985. package/skills/shared/react/references/data-and-state.md +152 -0
  986. package/skills/shared/react/references/performance.md +75 -0
  987. package/skills/shared/react/references/routing.md +99 -0
  988. package/skills/shared/react/scripts/verify.sh +123 -0
  989. package/skills/shared/react-native/SKILL.md +215 -0
  990. package/skills/shared/react-native/evals/README.md +3 -0
  991. package/skills/shared/react-native/evals/cases.yaml +42 -0
  992. package/skills/shared/react-native/references/native-modules.md +123 -0
  993. package/skills/shared/react-native/references/performance-debugging.md +46 -0
  994. package/skills/shared/react-native/scripts/verify.sh +120 -0
  995. package/skills/shared/redis/SKILL.md +298 -0
  996. package/skills/shared/redis/evals/README.md +10 -0
  997. package/skills/shared/redis/evals/cases.yaml +43 -0
  998. package/skills/shared/redis/references/caching.md +116 -0
  999. package/skills/shared/redis/references/locks-and-rate-limiting.md +140 -0
  1000. package/skills/shared/redis/references/queues.md +102 -0
  1001. package/skills/shared/redis/scripts/verify.sh +164 -0
  1002. package/skills/shared/render/SKILL.md +256 -0
  1003. package/skills/shared/render/evals/README.md +12 -0
  1004. package/skills/shared/render/evals/cases.yaml +45 -0
  1005. package/skills/shared/render/references/blueprint-reference.md +203 -0
  1006. package/skills/shared/render/scripts/verify.sh +167 -0
  1007. package/skills/shared/replicate/SKILL.md +210 -0
  1008. package/skills/shared/replicate/evals/README.md +9 -0
  1009. package/skills/shared/replicate/evals/cases.yaml +45 -0
  1010. package/skills/shared/replicate/references/cog-packaging.md +89 -0
  1011. package/skills/shared/replicate/references/deployments-api.md +87 -0
  1012. package/skills/shared/replicate/references/webhooks-and-async.md +110 -0
  1013. package/skills/shared/replicate/scripts/verify.sh +162 -0
  1014. package/skills/shared/research-ops/SKILL.md +200 -0
  1015. package/skills/shared/research-ops/evals/README.md +13 -0
  1016. package/skills/shared/research-ops/evals/cases.yaml +38 -0
  1017. package/skills/shared/research-ops/references/credibility-rubric.md +78 -0
  1018. package/skills/shared/research-ops/references/memo-template.md +63 -0
  1019. package/skills/shared/research-ops/scripts/verify.sh +181 -0
  1020. package/skills/shared/review/SKILL.md +314 -0
  1021. package/skills/shared/review/evals/README.md +84 -0
  1022. package/skills/shared/review/evals/cases.yaml +55 -0
  1023. package/skills/shared/ruby/SKILL.md +295 -0
  1024. package/skills/shared/ruby/evals/README.md +12 -0
  1025. package/skills/shared/ruby/evals/cases.yaml +41 -0
  1026. package/skills/shared/ruby/references/gems-and-testing.md +208 -0
  1027. package/skills/shared/ruby/references/metaprogramming.md +161 -0
  1028. package/skills/shared/ruby/scripts/verify.sh +83 -0
  1029. package/skills/shared/runpod/SKILL.md +238 -0
  1030. package/skills/shared/runpod/evals/README.md +11 -0
  1031. package/skills/shared/runpod/evals/cases.yaml +47 -0
  1032. package/skills/shared/runpod/references/cost-and-scaling.md +85 -0
  1033. package/skills/shared/runpod/references/serverless-workers.md +101 -0
  1034. package/skills/shared/runpod/scripts/verify.sh +126 -0
  1035. package/skills/shared/rust/SKILL.md +320 -0
  1036. package/skills/shared/rust/evals/README.md +12 -0
  1037. package/skills/shared/rust/evals/cases.yaml +42 -0
  1038. package/skills/shared/rust/references/async-tokio.md +141 -0
  1039. package/skills/shared/rust/references/axum-service.md +132 -0
  1040. package/skills/shared/rust/references/ownership.md +86 -0
  1041. package/skills/shared/rust/references/testing.md +108 -0
  1042. package/skills/shared/rust/scripts/verify.sh +91 -0
  1043. package/skills/shared/scaling/SKILL.md +137 -0
  1044. package/skills/shared/scaling/evals/README.md +3 -0
  1045. package/skills/shared/scaling/evals/cases.yaml +42 -0
  1046. package/skills/shared/scaling/references/load-testing-k6.md +127 -0
  1047. package/skills/shared/scaling/scripts/example.load.js +24 -0
  1048. package/skills/shared/scaling/scripts/verify.sh +70 -0
  1049. package/skills/shared/sdd/SKILL.md +250 -0
  1050. package/skills/shared/sdd/evals/README.md +60 -0
  1051. package/skills/shared/sdd/evals/cases.yaml +90 -0
  1052. package/skills/shared/sdd/references/model-routing.md +194 -0
  1053. package/skills/shared/sdd-init/SKILL.md +189 -0
  1054. package/skills/shared/sdd-init/evals/README.md +3 -0
  1055. package/skills/shared/sdd-init/evals/cases.yaml +43 -0
  1056. package/skills/shared/secure-coding/SKILL.md +336 -0
  1057. package/skills/shared/secure-coding/evals/README.md +68 -0
  1058. package/skills/shared/secure-coding/evals/cases.yaml +55 -0
  1059. package/skills/shared/secure-coding/references/authn-authz.md +249 -0
  1060. package/skills/shared/secure-coding/references/owasp-by-stack.md +574 -0
  1061. package/skills/shared/secure-coding/references/secrets-and-supply-chain.md +205 -0
  1062. package/skills/shared/secure-coding/references/threat-modeling.md +213 -0
  1063. package/skills/shared/secure-coding/scripts/verify.sh +208 -0
  1064. package/skills/shared/security-scan/SKILL.md +219 -0
  1065. package/skills/shared/security-scan/evals/README.md +14 -0
  1066. package/skills/shared/security-scan/evals/cases.yaml +50 -0
  1067. package/skills/shared/security-scan/references/tools.md +97 -0
  1068. package/skills/shared/security-scan/references/triage.md +92 -0
  1069. package/skills/shared/security-scan/scripts/verify.sh +108 -0
  1070. package/skills/shared/ship/SKILL.md +272 -0
  1071. package/skills/shared/ship/evals/README.md +89 -0
  1072. package/skills/shared/ship/evals/cases.yaml +44 -0
  1073. package/skills/shared/shopify/SKILL.md +229 -0
  1074. package/skills/shared/shopify/evals/README.md +14 -0
  1075. package/skills/shared/shopify/evals/cases.yaml +41 -0
  1076. package/skills/shared/shopify/references/apps-graphql.md +103 -0
  1077. package/skills/shared/shopify/references/checkout-extensibility.md +71 -0
  1078. package/skills/shared/shopify/references/liquid-themes.md +89 -0
  1079. package/skills/shared/shopify/scripts/verify.sh +120 -0
  1080. package/skills/shared/simplify-code/SKILL.md +101 -0
  1081. package/skills/shared/simplify-code/evals/README.md +3 -0
  1082. package/skills/shared/simplify-code/evals/cases.yaml +42 -0
  1083. package/skills/shared/skill-scout/SKILL.md +169 -0
  1084. package/skills/shared/skill-scout/evals/README.md +12 -0
  1085. package/skills/shared/skill-scout/evals/cases.yaml +56 -0
  1086. package/skills/shared/skill-scout/references/install-commands.md +76 -0
  1087. package/skills/shared/skill-scout/scripts/verify.sh +154 -0
  1088. package/skills/shared/solid-js/SKILL.md +260 -0
  1089. package/skills/shared/solid-js/evals/README.md +3 -0
  1090. package/skills/shared/solid-js/evals/cases.yaml +38 -0
  1091. package/skills/shared/solid-js/references/reactivity-deep-dive.md +89 -0
  1092. package/skills/shared/solid-js/references/router-and-start.md +93 -0
  1093. package/skills/shared/solid-js/scripts/verify.sh +130 -0
  1094. package/skills/shared/source-grounded-development/SKILL.md +108 -0
  1095. package/skills/shared/source-grounded-development/evals/README.md +3 -0
  1096. package/skills/shared/source-grounded-development/evals/cases.yaml +42 -0
  1097. package/skills/shared/specify/SKILL.md +391 -0
  1098. package/skills/shared/specify/evals/README.md +73 -0
  1099. package/skills/shared/specify/evals/cases.yaml +93 -0
  1100. package/skills/shared/specify/references/eliciting-requirements.md +117 -0
  1101. package/skills/shared/specify/references/spec-template.md +101 -0
  1102. package/skills/shared/speckit-analyze/SKILL.md +35 -0
  1103. package/skills/shared/speckit-assess-decide/SKILL.md +36 -0
  1104. package/skills/shared/speckit-assess-define/SKILL.md +36 -0
  1105. package/skills/shared/speckit-assess-intake/SKILL.md +38 -0
  1106. package/skills/shared/speckit-assess-research/SKILL.md +36 -0
  1107. package/skills/shared/speckit-assess-shape/SKILL.md +36 -0
  1108. package/skills/shared/speckit-bug-assess/SKILL.md +38 -0
  1109. package/skills/shared/speckit-bug-fix/SKILL.md +37 -0
  1110. package/skills/shared/speckit-bug-test/SKILL.md +37 -0
  1111. package/skills/shared/speckit-checklist/SKILL.md +35 -0
  1112. package/skills/shared/speckit-clarify/SKILL.md +32 -0
  1113. package/skills/shared/speckit-constitution/SKILL.md +35 -0
  1114. package/skills/shared/speckit-converge/SKILL.md +36 -0
  1115. package/skills/shared/speckit-implement/SKILL.md +32 -0
  1116. package/skills/shared/speckit-plan/SKILL.md +37 -0
  1117. package/skills/shared/speckit-specify/SKILL.md +36 -0
  1118. package/skills/shared/speckit-tasks/SKILL.md +34 -0
  1119. package/skills/shared/spreadsheet-ops/SKILL.md +180 -0
  1120. package/skills/shared/spreadsheet-ops/evals/README.md +33 -0
  1121. package/skills/shared/spreadsheet-ops/evals/cases.yaml +42 -0
  1122. package/skills/shared/spreadsheet-ops/references/formula-cookbook.md +70 -0
  1123. package/skills/shared/spreadsheet-ops/references/python-excel.md +87 -0
  1124. package/skills/shared/spreadsheet-ops/references/sheets-api-appsscript.md +118 -0
  1125. package/skills/shared/spreadsheet-ops/scripts/verify.sh +152 -0
  1126. package/skills/shared/spring-boot/SKILL.md +350 -0
  1127. package/skills/shared/spring-boot/evals/README.md +11 -0
  1128. package/skills/shared/spring-boot/evals/cases.yaml +49 -0
  1129. package/skills/shared/spring-boot/references/jpa.md +94 -0
  1130. package/skills/shared/spring-boot/references/security.md +92 -0
  1131. package/skills/shared/spring-boot/references/testing.md +95 -0
  1132. package/skills/shared/spring-boot/scripts/verify.sh +115 -0
  1133. package/skills/shared/sql/SKILL.md +286 -0
  1134. package/skills/shared/sql/evals/README.md +9 -0
  1135. package/skills/shared/sql/evals/cases.yaml +49 -0
  1136. package/skills/shared/sql/references/ctes-and-recursion.md +63 -0
  1137. package/skills/shared/sql/references/joins-and-sets.md +71 -0
  1138. package/skills/shared/sql/references/portability.md +38 -0
  1139. package/skills/shared/sql/references/window-functions.md +72 -0
  1140. package/skills/shared/sql/scripts/verify.sh +139 -0
  1141. package/skills/shared/sqlite-turso/SKILL.md +214 -0
  1142. package/skills/shared/sqlite-turso/evals/README.md +24 -0
  1143. package/skills/shared/sqlite-turso/evals/cases.yaml +45 -0
  1144. package/skills/shared/sqlite-turso/references/embedded-replicas.md +96 -0
  1145. package/skills/shared/sqlite-turso/scripts/verify.sh +95 -0
  1146. package/skills/shared/structured-extraction/SKILL.md +230 -0
  1147. package/skills/shared/structured-extraction/evals/README.md +13 -0
  1148. package/skills/shared/structured-extraction/evals/cases.yaml +70 -0
  1149. package/skills/shared/structured-extraction/references/providers.md +152 -0
  1150. package/skills/shared/structured-extraction/scripts/verify.sh +160 -0
  1151. package/skills/shared/suggest/SKILL.md +123 -0
  1152. package/skills/shared/suggest/evals/README.md +17 -0
  1153. package/skills/shared/suggest/evals/cases.yaml +78 -0
  1154. package/skills/shared/supabase/SKILL.md +268 -0
  1155. package/skills/shared/supabase/evals/README.md +12 -0
  1156. package/skills/shared/supabase/evals/cases.yaml +42 -0
  1157. package/skills/shared/supabase/references/auth-ssr.md +173 -0
  1158. package/skills/shared/supabase/references/rls-cookbook.md +122 -0
  1159. package/skills/shared/supabase/scripts/verify.sh +149 -0
  1160. package/skills/shared/svelte/SKILL.md +238 -0
  1161. package/skills/shared/svelte/evals/README.md +3 -0
  1162. package/skills/shared/svelte/evals/cases.yaml +41 -0
  1163. package/skills/shared/svelte/references/runes.md +97 -0
  1164. package/skills/shared/svelte/references/sveltekit-data.md +156 -0
  1165. package/skills/shared/svelte/scripts/verify.sh +128 -0
  1166. package/skills/shared/swift-ios/SKILL.md +224 -0
  1167. package/skills/shared/swift-ios/evals/README.md +3 -0
  1168. package/skills/shared/swift-ios/evals/cases.yaml +46 -0
  1169. package/skills/shared/swift-ios/references/concurrency.md +132 -0
  1170. package/skills/shared/swift-ios/references/testing.md +112 -0
  1171. package/skills/shared/swift-ios/scripts/verify.sh +98 -0
  1172. package/skills/shared/tasks/SKILL.md +265 -0
  1173. package/skills/shared/tasks/evals/README.md +70 -0
  1174. package/skills/shared/tasks/evals/cases.yaml +75 -0
  1175. package/skills/shared/tauri/SKILL.md +219 -0
  1176. package/skills/shared/tauri/evals/README.md +12 -0
  1177. package/skills/shared/tauri/evals/cases.yaml +46 -0
  1178. package/skills/shared/tauri/references/bundling-distribution.md +129 -0
  1179. package/skills/shared/tauri/references/security.md +143 -0
  1180. package/skills/shared/tauri/scripts/verify.sh +178 -0
  1181. package/skills/shared/technical-writing/SKILL.md +230 -0
  1182. package/skills/shared/technical-writing/evals/README.md +12 -0
  1183. package/skills/shared/technical-writing/evals/cases.yaml +53 -0
  1184. package/skills/shared/technical-writing/references/diataxis-modes.md +131 -0
  1185. package/skills/shared/technical-writing/references/vale-starter.md +90 -0
  1186. package/skills/shared/technical-writing/scripts/verify.sh +83 -0
  1187. package/skills/shared/testing-go/SKILL.md +263 -0
  1188. package/skills/shared/testing-go/evals/README.md +3 -0
  1189. package/skills/shared/testing-go/evals/cases.yaml +46 -0
  1190. package/skills/shared/testing-go/references/coverage-and-benchmarks.md +85 -0
  1191. package/skills/shared/testing-go/references/mocks-and-fakes.md +140 -0
  1192. package/skills/shared/testing-go/references/synctest-and-concurrency.md +82 -0
  1193. package/skills/shared/testing-go/scripts/verify.sh +72 -0
  1194. package/skills/shared/testing-py/SKILL.md +197 -0
  1195. package/skills/shared/testing-py/evals/README.md +5 -0
  1196. package/skills/shared/testing-py/evals/cases.yaml +44 -0
  1197. package/skills/shared/testing-py/references/mocking.md +141 -0
  1198. package/skills/shared/testing-py/references/property-testing.md +99 -0
  1199. package/skills/shared/testing-py/scripts/verify.sh +117 -0
  1200. package/skills/shared/testing-web/SKILL.md +244 -0
  1201. package/skills/shared/testing-web/evals/README.md +11 -0
  1202. package/skills/shared/testing-web/evals/cases.yaml +52 -0
  1203. package/skills/shared/testing-web/references/jest-setup.md +88 -0
  1204. package/skills/shared/testing-web/references/recipes.md +116 -0
  1205. package/skills/shared/testing-web/scripts/verify.sh +111 -0
  1206. package/skills/shared/together-fireworks/SKILL.md +176 -0
  1207. package/skills/shared/together-fireworks/evals/README.md +3 -0
  1208. package/skills/shared/together-fireworks/evals/cases.yaml +50 -0
  1209. package/skills/shared/together-fireworks/references/batch-and-tuning.md +59 -0
  1210. package/skills/shared/together-fireworks/references/models-and-pricing.md +79 -0
  1211. package/skills/shared/together-fireworks/scripts/verify.sh +165 -0
  1212. package/skills/shared/training-data/SKILL.md +226 -0
  1213. package/skills/shared/training-data/evals/README.md +13 -0
  1214. package/skills/shared/training-data/evals/cases.yaml +41 -0
  1215. package/skills/shared/training-data/references/formats.md +118 -0
  1216. package/skills/shared/training-data/references/synthesis-dedup-quality.md +134 -0
  1217. package/skills/shared/translation-l10n/SKILL.md +229 -0
  1218. package/skills/shared/translation-l10n/evals/README.md +3 -0
  1219. package/skills/shared/translation-l10n/evals/cases.yaml +39 -0
  1220. package/skills/shared/translation-l10n/references/icu-cookbook.md +82 -0
  1221. package/skills/shared/translation-l10n/references/rtl-and-bidi.md +60 -0
  1222. package/skills/shared/typescript/SKILL.md +225 -0
  1223. package/skills/shared/typescript/evals/README.md +15 -0
  1224. package/skills/shared/typescript/evals/cases.yaml +46 -0
  1225. package/skills/shared/typescript/references/build-and-monorepo.md +141 -0
  1226. package/skills/shared/typescript/references/type-system.md +162 -0
  1227. package/skills/shared/typescript/scripts/verify.sh +52 -0
  1228. package/skills/shared/ui-engineering/SKILL.md +113 -0
  1229. package/skills/shared/ui-engineering/evals/cases.yaml +38 -0
  1230. package/skills/shared/unity/SKILL.md +282 -0
  1231. package/skills/shared/unity/evals/README.md +8 -0
  1232. package/skills/shared/unity/evals/cases.yaml +43 -0
  1233. package/skills/shared/unity/references/build-and-platforms.md +65 -0
  1234. package/skills/shared/unity/references/input-system.md +102 -0
  1235. package/skills/shared/unity/references/lifecycle-deep-dive.md +75 -0
  1236. package/skills/shared/unreal/SKILL.md +270 -0
  1237. package/skills/shared/unreal/evals/README.md +12 -0
  1238. package/skills/shared/unreal/evals/cases.yaml +45 -0
  1239. package/skills/shared/unreal/references/blueprint-cpp-parity.md +109 -0
  1240. package/skills/shared/unreal/references/gameplay-framework.md +95 -0
  1241. package/skills/shared/unreal/references/packaging.md +83 -0
  1242. package/skills/shared/unslop/SKILL.md +143 -0
  1243. package/skills/shared/unslop/evals/README.md +25 -0
  1244. package/skills/shared/unslop/evals/cases.yaml +61 -0
  1245. package/skills/shared/unsloth/SKILL.md +254 -0
  1246. package/skills/shared/unsloth/evals/README.md +10 -0
  1247. package/skills/shared/unsloth/evals/cases.yaml +42 -0
  1248. package/skills/shared/unsloth/references/export.md +75 -0
  1249. package/skills/shared/unsloth/references/grpo.md +91 -0
  1250. package/skills/shared/unsloth/references/masking-and-templates.md +91 -0
  1251. package/skills/shared/variant-explorer/SKILL.md +93 -0
  1252. package/skills/shared/variant-explorer/evals/cases.yaml +38 -0
  1253. package/skills/shared/vector-db/SKILL.md +189 -0
  1254. package/skills/shared/vector-db/evals/README.md +10 -0
  1255. package/skills/shared/vector-db/evals/cases.yaml +45 -0
  1256. package/skills/shared/vector-db/references/engines.md +175 -0
  1257. package/skills/shared/vector-db/references/tuning.md +62 -0
  1258. package/skills/shared/vector-db/scripts/verify.sh +110 -0
  1259. package/skills/shared/vercel/SKILL.md +242 -0
  1260. package/skills/shared/vercel/evals/README.md +23 -0
  1261. package/skills/shared/vercel/evals/cases.yaml +45 -0
  1262. package/skills/shared/vercel/references/cli-cookbook.md +98 -0
  1263. package/skills/shared/vercel/references/vercel-json.md +120 -0
  1264. package/skills/shared/vercel/scripts/verify.sh +168 -0
  1265. package/skills/shared/verify/SKILL.md +230 -0
  1266. package/skills/shared/verify/evals/README.md +78 -0
  1267. package/skills/shared/verify/evals/cases.yaml +104 -0
  1268. package/skills/shared/vllm/SKILL.md +235 -0
  1269. package/skills/shared/vllm/evals/README.md +9 -0
  1270. package/skills/shared/vllm/evals/cases.yaml +47 -0
  1271. package/skills/shared/vllm/references/flags-and-endpoints.md +105 -0
  1272. package/skills/shared/vllm/references/memory-and-throughput.md +78 -0
  1273. package/skills/shared/vue-nuxt/SKILL.md +323 -0
  1274. package/skills/shared/vue-nuxt/evals/README.md +11 -0
  1275. package/skills/shared/vue-nuxt/evals/cases.yaml +49 -0
  1276. package/skills/shared/vue-nuxt/references/data-and-state.md +127 -0
  1277. package/skills/shared/vue-nuxt/references/migration-nuxt4.md +79 -0
  1278. package/skills/shared/vue-nuxt/references/nitro-and-rendering.md +117 -0
  1279. package/skills/shared/vue-nuxt/references/reactivity.md +135 -0
  1280. package/skills/shared/vue-nuxt/scripts/verify.sh +148 -0
  1281. package/skills/shared/webhooks/SKILL.md +229 -0
  1282. package/skills/shared/webhooks/evals/README.md +15 -0
  1283. package/skills/shared/webhooks/evals/cases.yaml +46 -0
  1284. package/skills/shared/webhooks/references/framework-raw-body.md +97 -0
  1285. package/skills/shared/webhooks/references/signature-schemes.md +66 -0
  1286. package/skills/shared/webhooks/scripts/verify.sh +142 -0
  1287. package/skills/shared/wordpress/SKILL.md +224 -0
  1288. package/skills/shared/wordpress/evals/README.md +3 -0
  1289. package/skills/shared/wordpress/evals/cases.yaml +50 -0
  1290. package/skills/shared/wordpress/references/hardening.md +108 -0
  1291. package/skills/shared/wordpress/references/performance.md +80 -0
  1292. package/skills/shared/wordpress/references/woocommerce.md +65 -0
  1293. package/skills/shared/wordpress/scripts/verify.sh +96 -0
  1294. package/skills/shared/worktrees/SKILL.md +204 -0
  1295. package/skills/shared/worktrees/evals/README.md +78 -0
  1296. package/skills/shared/worktrees/evals/cases.yaml +47 -0
@@ -0,0 +1,617 @@
1
+ // tasteskill / charts.js — small, dependency-free charts for app screens, drawn in SVG from your data.
2
+ // They follow references/app-screens.md: one question per chart, one series that matters, 3–5 quiet
3
+ // horizontal gridlines, round ticks that top out above the largest value, 2px straight lines with no
4
+ // markers, square bars, no gradients, a bare tooltip, tabular figures. Colours come from CSS variables:
5
+ // --chart-1 … --chart-4 (series), --chart-muted (other series), --chart-mark (a marked period; ink by default),
6
+ // --chart-span (the opacity of a shaded span: about .06 on light, .12 on dark), --chart-track (a time strip's track),
7
+ // --grid, --axis-ink, --ink, --surface, --raised, --rule, --negative
8
+ // Usage (after this file loads):
9
+ // Charts.line(el, { labels: ['1 Oct', …], series: [{ name: 'Requests', values: [...] }], format: Charts.fmt.compact })
10
+ // Charts.bars(el, { labels, values, highlight: 6, format }) one bar (or [indices]) may carry the accent; dim: [indices]
11
+ // Charts.diverging(el, { labels, up, down, above: 'Sold', below: 'Bought', mark: [3, 9], markLabel: 'Car charged' })
12
+ // Charts.ring(el, { value: 0.72, label: '72%', sub: 'of capacity' }) a progress ring with its total inside
13
+ // Charts.barList(el, [{ label: 'Berlin', value: 412 }, …], { format, thin }) a ranked list where the row is the bar
14
+ // Charts.plan(el, [{ label: 'Groceries', planned: 600, spent: 412, committed: 60 }, …], { scale: 'row' | 'plan' }) planned against spent
15
+ // Charts.bullet(el, [{ label: 'Bonds', value: 0.31, target: 0.25 }, …]) share against a target
16
+ // Charts.timeline(el, rows, kinds, { days, today, weekends }) who is away when, each kind of booking its own mark
17
+ // Charts.matrix(el, rows, { cols, comfort: 2, today }) slack against a minimum, team by day
18
+ // Charts.timeStrip(el, rows, { open: '08:00', close: '15:00', compareLabel: 'Last Sunday' }) when, within the day
19
+ // line, bars and diverging take annotations: [{ at: index, label: 'Deploy a3f09c1', short: 'a3f09c1' }] or spans
20
+ // [{ from, to, label: 'Cloud' }]. Their labels sit in rows above the plot, measured once the fonts have loaded, and no
21
+ // leader line crosses another label; the rows are reserved only when a label exists. reference: { value, label }, its
22
+ // label set where no series passes.
23
+ // line takes step: true for a balance that only changes on given days; today: index (the forecast after it is dashed)
24
+ // with todayLabel: 'Now 20:34' (set clear of the line); endLabel: true (the last value at the line's end); max: caps a
25
+ // flat series with one spike (the peak is labelled); yTicks: fixed ticks for a bounded quantity (0–100%); tickFormat:
26
+ // axis labels apart from the tooltip format; xAt: the indices to label. Without xAt the x labels keep one step.
27
+ // diverging, timeline, matrix and timeStrip return { svg, legend }, and line returns { legend } for two series or more:
28
+ // the legend is drawn from the same style objects as the marks, so a swatch is always the mark scaled down. Put it in
29
+ // the card's header, or pass legend: element (or a selector) to have it filled.
30
+ // Numbers follow the page's language (<html lang>). Every chart gets role="img" and an aria-label that states what it shows.
31
+ (() => {
32
+ const NS = 'http://www.w3.org/2000/svg', MINUS = '\u2212', ROW = 14, LANE = (rows) => 8 + rows * ROW + (rows ? 4 : 0);
33
+ const css = (el, name, fb) => getComputedStyle(el).getPropertyValue(name).trim() || fb;
34
+ const cssNum = (el, name, fb) => { const v = parseFloat(css(el, name, '')); return Number.isFinite(v) ? v : fb; };
35
+ const svg = (tag, attrs = {}, parent) => { const n = document.createElementNS(NS, tag); for (const [k, v] of Object.entries(attrs)) if (v != null) n.setAttribute(k, v); if (parent) parent.appendChild(n); return n; };
36
+ const text = (parent, str, attrs) => { const t = svg('text', attrs, parent); t.textContent = str; return t; };
37
+ const titled = (parent, str) => { svg('title', {}, parent).textContent = str; return parent; };
38
+ // numbers follow the page's language (<html lang>), so separators match the rest of the screen
39
+ const nf = (o) => new Intl.NumberFormat(document.documentElement.lang || 'en', o);
40
+ const fmt = {
41
+ int: (v) => nf({ maximumFractionDigits: 0 }).format(v),
42
+ dec: (d) => (v) => nf({ minimumFractionDigits: d, maximumFractionDigits: d }).format(v),
43
+ pct: (d = 1) => (v) => nf({ style: 'percent', minimumFractionDigits: d, maximumFractionDigits: d }).format(v),
44
+ money: (cur = 'EUR', d = 0) => (v) => nf({ style: 'currency', currency: cur, minimumFractionDigits: d, maximumFractionDigits: d }).format(v),
45
+ compact: (v) => nf({ notation: 'compact', maximumFractionDigits: 1 }).format(v),
46
+ ms: (v) => `${nf({ maximumFractionDigits: 0 }).format(v)} ms`,
47
+ // a sign on every change, with a true minus: fmt.signed() → '+2', '0', '−1'; fmt.signed(fmt.dec(1)) → '+0.4'
48
+ signed: (f = (v) => nf({ maximumFractionDigits: 0 }).format(v)) => (v) => (v > 0 ? '+' : v < 0 ? MINUS : '') + f(Math.abs(v)),
49
+ // minutes since midnight as a 24-hour time: 680 → '11:20'
50
+ clock: (m) => `${String(Math.floor(m / 60) % 24).padStart(2, '0')}:${String(Math.round(m % 60)).padStart(2, '0')}`, // taste-skill-ignore: a clock, not a counter
51
+ };
52
+ const minutes = (t) => (t == null || t === '' ? null : typeof t === 'number' ? t : (([hh, mm]) => hh * 60 + (mm || 0))(String(t).split(':').map(Number)));
53
+ // Round ticks (steps of 1, 2, 2.5 or 5 × 10^n) whose top sits above the largest value.
54
+ function ticks(min, max, count = 4) {
55
+ if (max === min) max = min + 1;
56
+ const raw = (max - min) / count, mag = 10 ** Math.floor(Math.log10(raw));
57
+ const step = [1, 2, 2.5, 5, 10].map((m) => m * mag).find((s) => s >= raw) || 10 * mag;
58
+ const lo = Math.floor(min / step) * step; let hi = Math.ceil(max / step) * step; if (hi <= max) hi += step;
59
+ const out = []; for (let v = lo; v <= hi + step / 2; v += step) out.push(+v.toFixed(10));
60
+ return out;
61
+ }
62
+ // x labels keep one step all the way: every k-th label, with k chosen so the labels fit the width, and a step that
63
+ // lands on the last label when one gives enough labels. Never a forced end label that breaks the step. Clock labels
64
+ // ('08:30') step in whole hours (or halves and quarters) from a round time, so a half-hourly axis reads 06:00, 09:00.
65
+ function xPicks(labels, span, at) {
66
+ const n = labels.length;
67
+ if (at) return at.filter((i) => i >= 0 && i < n);
68
+ if (n <= 1) return n ? [0] : [];
69
+ const longest = Math.max(...labels.map((l) => String(l).length));
70
+ const cap = Math.max(2, Math.min(8, Math.floor(span / (longest * 7 + 18))));
71
+ if (n <= cap) return [...Array(n).keys()];
72
+ const mins = labels.every((l) => /^\d{1,2}:\d{2}$/.test(String(l))) ? labels.map(minutes) : null;
73
+ const d = mins ? mins[1] - mins[0] : 0;
74
+ let first = null, land = null;
75
+ for (let k = 1; k < n; k++) {
76
+ const stepM = k * d, clock = mins && d > 0;
77
+ if (clock && (stepM >= 60 ? ![1, 2, 3, 4, 6, 12].includes(stepM / 60) : 60 % stepM !== 0)) continue;
78
+ // start on a round time: a multiple of the step (09:00 for three hours), or a whole hour for shorter steps
79
+ let s = clock ? mins.findIndex((m) => m % Math.max(60, stepM) === 0) : 0;
80
+ if (s < 0) s = Math.max(0, mins.findIndex((m) => m % 60 === 0));
81
+ const count = Math.floor((n - 1 - s) / k) + 1;
82
+ if (count > cap) continue;
83
+ if (first == null) first = { k, s };
84
+ if ((n - 1 - s) % k === 0) { land = { k, s, count }; break; }
85
+ }
86
+ const pick = land && land.count >= Math.max(3, Math.ceil(cap * 0.6)) ? land : first || { k: n - 1, s: 0 };
87
+ const out = []; for (let i = pick.s; i < n; i += pick.k) out.push(i);
88
+ return out;
89
+ }
90
+ // colours: tokens resolved to rgb, so a mark can be mixed with the surface (a pale fill, a darker step)
91
+ const swatchProbe = document.createElement('span'); swatchProbe.style.display = 'none';
92
+ const rgb = (el, value) => {
93
+ el.appendChild(swatchProbe); swatchProbe.style.color = ''; swatchProbe.style.color = value;
94
+ const c = getComputedStyle(swatchProbe).color; swatchProbe.remove();
95
+ const m = c.match(/-?[\d.]+/g); if (!m || m.length < 3) return null;
96
+ return c.startsWith('color(') ? m.slice(0, 3).map((v) => Math.round(+v * 255)) : m.slice(0, 3).map(Number);
97
+ };
98
+ const mix = (el, a, b, t) => { const p = rgb(el, a), q = rgb(el, b); return p && q ? `rgb(${p.map((v, i) => Math.round(v * t + q[i] * (1 - t))).join(',')})` : a; };
99
+ // text width, measured in the chart's own face (falls back to an estimate when the chart is hidden)
100
+ const measure = (s, str, size = 11, weight = 400) => { const t = text(s, str, { x: -999, y: -999, 'font-size': size, 'font-weight': weight, visibility: 'hidden' }); let wd = 0; try { wd = t.getComputedTextLength(); } catch {} t.remove(); return wd > 0 ? wd : String(str).length * size * 0.56; };
101
+ const fit = (s, str, max, size, weight) => { str = String(str); if (measure(s, str, size, weight) <= max) return str; while (str.length > 1 && measure(s, str + '\u2026', size, weight) > max) str = str.slice(0, -1); return str.trimEnd() + '\u2026'; };
102
+ function frame(el, h) {
103
+ el.innerHTML = '';
104
+ const w = Math.max(240, el.clientWidth || 600);
105
+ const s = svg('svg', { viewBox: `0 0 ${w} ${h}`, width: '100%', height: h, role: 'img', style: 'display:block;overflow:visible;font-variant-numeric:tabular-nums' }, el);
106
+ return { s, w, h };
107
+ }
108
+ function tooltip(el) {
109
+ let t = el.querySelector('.chart-tip');
110
+ if (!t) { t = document.createElement('div'); t.className = 'chart-tip'; t.style.cssText = 'position:absolute;pointer-events:none;padding:6px 8px;font:inherit;font-size:12px;line-height:1.35;border-radius:6px;white-space:nowrap;opacity:0;transition:opacity 120ms ease;background:var(--surface,#fff);color:var(--ink,#111);border:1px solid var(--grid,#e5e7eb)'; if (getComputedStyle(el).position === 'static') el.style.position = 'relative'; el.appendChild(t); }
111
+ return t;
112
+ }
113
+ function axes(g, el, { w, h, padL, padB, yt, y, labels, x, band = false, at = null, tick, avoid = null }) {
114
+ const grid = css(el, '--grid', '#e8e8e8'), ink = css(el, '--axis-ink', '#6b6b6b'), s = g.ownerSVGElement;
115
+ for (const v of yt) {
116
+ const yy = y(v);
117
+ svg('line', { x1: padL, x2: w, y1: yy, y2: yy, stroke: grid, 'stroke-width': 1, 'shape-rendering': 'crispEdges' }, g);
118
+ text(g, tick(v), { x: padL - 8, y: yy + 4, 'text-anchor': 'end', 'font-size': 12, fill: ink });
119
+ }
120
+ const n = labels.length;
121
+ for (const i of xPicks(labels, w - padL, at)) {
122
+ const lab = String(labels[i]), tw = measure(s, lab, 12), xx = x(i);
123
+ // the first and last labels are pulled inside the plot; none runs past either edge
124
+ let left = band ? xx - tw / 2 : i === 0 ? xx : i === n - 1 ? xx - tw : xx - tw / 2;
125
+ left = Math.max(band ? 0 : padL, Math.min(w - tw, left));
126
+ if (avoid && left < avoid[1] + 8 && left + tw > avoid[0] - 8) continue;
127
+ text(g, lab, { x: left, y: h - padB + 18, 'font-size': 12, fill: ink });
128
+ }
129
+ }
130
+ // Annotation labels sit in rows above the plot, never on the data. A label sits beside the top of its own leader
131
+ // line, right of it or left of it, in one of three rows. A place is free when no other label in that row overlaps
132
+ // it, no leader line passes through it, and its own leader passes through no label below it. The layout is searched
133
+ // (close markers often need the first label on the left so the next leader runs clear): full labels first, then
134
+ // short forms (`short`), and only then is a label dropped to its marker's tooltip, with a note in the console.
135
+ function lane(s, items, w, maxRows = 3) {
136
+ const gap = 6, rank = (it) => (it.fixed != null ? 0 : it.span ? 1 : 2);
137
+ // fixed captions first, then spans, then markers from left to right
138
+ const order = [...items].sort((a, b) => rank(a) - rank(b) || (a.x ?? a.x0) - (b.x ?? b.x0));
139
+ const opts = order.map((it) => {
140
+ const out = [];
141
+ for (const str of [it.label, it.short].filter(Boolean)) {
142
+ const tw = measure(s, str, 11) + (it.glyph ? 9 : 0), mid = it.span ? (it.x0 + it.x1) / 2 : 0;
143
+ const cands = it.fixed != null ? [[it.fixed, it.fixed + tw]] : it.span ? [[mid - tw / 2, mid + tw / 2], [it.x0, it.x0 + tw], [it.x1 - tw, it.x1]] : [[it.x + 4, it.x + 4 + tw], [it.x - 4 - tw, it.x - 4]];
144
+ for (let row = 0; row < maxRows; row++) for (const [x0, x1] of cands) if (x0 >= 0 && x1 <= w) out.push({ ...it, text: str, isShort: str !== it.label, row, x0, x1 });
145
+ }
146
+ return out;
147
+ });
148
+ const free = (c, placed) => placed.every((p) => p.dropped || (!(p.row === c.row && c.x0 < p.x1 + gap && c.x1 > p.x0 - gap)
149
+ && !(p.leader != null && p.row >= c.row && p.leader > c.x0 - 3 && p.leader < c.x1 + 3)
150
+ && !(c.leader != null && p.row <= c.row && c.leader > p.x0 - 3 && c.leader < p.x1 + 3)));
151
+ let best = null, steps = 0;
152
+ const solve = (i, placed, allowShort, allowDrop) => {
153
+ if (++steps > 20000) return false;
154
+ if (i === order.length) { best = placed.slice(); return true; }
155
+ for (const c of opts[i]) { if ((c.isShort && !allowShort) || !free(c, placed)) continue; placed.push(c); if (solve(i + 1, placed, allowShort, allowDrop)) return true; placed.pop(); }
156
+ if (allowDrop) { placed.push({ ...order[i], dropped: true }); if (solve(i + 1, placed, allowShort, allowDrop)) return true; placed.pop(); }
157
+ return false;
158
+ };
159
+ for (const [sh, dr] of [[false, false], [true, false], [true, true]]) { steps = 0; if (solve(0, [], sh, dr)) break; }
160
+ const placed = (best || []).filter((p) => !p.dropped), dropped = (best || order.map((it) => ({ ...it, dropped: true }))).filter((p) => p.dropped);
161
+ return { placed, dropped, rows: placed.length ? Math.max(...placed.map((p) => p.row)) + 1 : 0 };
162
+ }
163
+ function prepNotes(s, annotations = [], x, w, extra = []) {
164
+ const items = [];
165
+ for (const a of annotations || []) {
166
+ if (a.from != null) items.push({ span: true, x0: Math.min(x(a.from), x(a.to)), x1: Math.max(x(a.from), x(a.to)), label: a.label, short: a.short, colour: a.colour });
167
+ else if (a.at != null) items.push({ x: x(a.at), at: a.at, leader: x(a.at), label: a.label, short: a.short, colour: a.colour });
168
+ }
169
+ items.push(...extra);
170
+ return { items, ...lane(s, items.filter((it) => it.label), w) };
171
+ }
172
+ // shaded spans go under the data; marker lines and the label rows over it
173
+ function notesUnder(g, el, N, { padT, h, padB }) {
174
+ const ink = css(el, '--axis-ink', '#6b6b6b'), op = cssNum(el, '--chart-span', 0.07);
175
+ for (const it of N.items) if (it.span) svg('rect', { x: it.x0, y: padT, width: it.x1 - it.x0, height: h - padT - padB, fill: ink, opacity: op }, g);
176
+ }
177
+ function notesOver(g, el, N, { padT, h, padB }) {
178
+ const ink = css(el, '--axis-ink', '#6b6b6b');
179
+ // a marker line runs to the plot's foot, or stops above the bar it points at (it.end)
180
+ for (const it of N.items) if (it.leader != null && !it.drawn) svg('line', { x1: it.leader, x2: it.leader, y1: padT, y2: Math.max(padT, it.end ?? h - padB), stroke: ink, 'stroke-width': 1, opacity: 0.45, 'shape-rendering': 'crispEdges' }, g);
181
+ for (const p of N.placed) {
182
+ const base = padT - 9 - p.row * ROW;
183
+ if (p.leader != null) svg('line', { x1: p.leader, x2: p.leader, y1: base - 8, y2: padT, stroke: ink, 'stroke-width': 1, opacity: 0.45, 'shape-rendering': 'crispEdges' }, g);
184
+ if (p.glyph) svg('path', { d: p.glyph === 'up' ? `M${p.x0} ${base - 1}l3 -6l3 6z` : `M${p.x0} ${base - 7}l3 6l3 -6z`, fill: ink }, g);
185
+ text(g, p.text, { x: p.x0 + (p.glyph ? 9 : 0), y: base, 'font-size': 11, fill: p.colour || ink });
186
+ }
187
+ const el2 = g.ownerSVGElement.parentNode; el2._warned = el2._warned || new Set();
188
+ for (const d of N.dropped) {
189
+ if (d.leader != null) { const hit = svg('line', { x1: d.leader, x2: d.leader, y1: padT, y2: h - padB, stroke: 'transparent', 'stroke-width': 8 }, g); titled(hit, d.label, {}); }
190
+ if (!el2._warned.has(d.label)) { el2._warned.add(d.label); console.warn(`Charts: no room above the plot for "${d.label}". Give it a short form (short) or label fewer markers.`); }
191
+ }
192
+ }
193
+ // does a label box touch a drawn line? polylines are [[x, y], …]; a box is { x0, x1, y0, y1 }
194
+ function hits(b, lines) {
195
+ for (const pts of lines) for (let k = 1; k < pts.length; k++) {
196
+ const a = pts[k - 1], c = pts[k]; if (!a || !c) continue;
197
+ if (a[0] === c[0]) { if (a[0] >= b.x0 - 3 && a[0] <= b.x1 + 3 && Math.max(a[1], c[1]) >= b.y0 - 3 && Math.min(a[1], c[1]) <= b.y1 + 3) return true; continue; }
198
+ const lo = Math.max(b.x0 - 3, Math.min(a[0], c[0])), hi = Math.min(b.x1 + 3, Math.max(a[0], c[0]));
199
+ for (let xx = lo; xx <= hi; xx += 2) { const yy = a[1] + ((xx - a[0]) / (c[0] - a[0])) * (c[1] - a[1]); if (yy >= b.y0 - 3 && yy <= b.y1 + 3) return true; }
200
+ }
201
+ return false;
202
+ }
203
+ const boxHits = (b, boxes) => boxes.some((r) => b.x0 < r.x1 + 3 && b.x1 > r.x0 - 3 && b.y0 < r.y1 + 3 && b.y1 > r.y0 - 3);
204
+ // a reference line (a budget, an SLO) with its label at an end where no series passes
205
+ function references(g, el, refs, { y, padL, w, lines = [], boxes = [] }) {
206
+ const ink = css(el, '--axis-ink', '#6b6b6b'), s = g.ownerSVGElement;
207
+ for (const r of [].concat(refs || [])) {
208
+ const yy = y(r.value);
209
+ svg('line', { x1: padL, x2: w, y1: yy, y2: yy, stroke: ink, 'stroke-width': 1, 'stroke-dasharray': '4 4', opacity: 0.7 }, g);
210
+ if (!r.label) continue;
211
+ const tw = measure(s, r.label, 11), right = r.at !== 'left';
212
+ const cand = [[right, -5], [right, 13], [!right, -5], [!right, 13]].map(([rt, dy]) => ({ x0: rt ? w - tw : padL + 4, x1: rt ? w : padL + 4 + tw, y0: yy + dy - 9, y1: yy + dy + 2, base: yy + dy }));
213
+ const b = cand.find((c) => !hits(c, lines) && !boxHits(c, boxes)) || cand[0];
214
+ text(g, r.label, { x: b.x0, y: b.base, 'font-size': 11, fill: ink });
215
+ }
216
+ }
217
+ // One style object per kind of mark draws both the mark and its legend swatch, so the two cannot drift apart.
218
+ function paintRect(parent, st, x, y, w, h, r = 0) {
219
+ let fill = st.fill || 'none';
220
+ if (st.hatch) {
221
+ const s = parent.ownerSVGElement || parent, id = 'h' + Math.random().toString(36).slice(2, 8);
222
+ const p = svg('pattern', { id, width: 5, height: 5, patternUnits: 'userSpaceOnUse', patternTransform: 'rotate(45)' }, svg('defs', {}, s));
223
+ svg('rect', { width: 5, height: 5, fill: st.fill }, p); svg('line', { x1: 0, y1: 0, x2: 0, y2: 5, stroke: st.hatch, 'stroke-width': 1.2 }, p);
224
+ fill = `url(#${id})`;
225
+ }
226
+ const inset = st.stroke ? (st.width || 1) / 2 : 0;
227
+ const n = svg('rect', { x: x + inset, y: y + inset, width: Math.max(0, w - inset * 2), height: Math.max(0, h - inset * 2), rx: r, fill, stroke: st.stroke, 'stroke-width': st.stroke ? st.width || 1 : null, 'stroke-dasharray': st.dash, opacity: st.opacity, 'shape-rendering': r ? null : 'crispEdges' }, parent);
228
+ if (st.edge) svg('rect', { x, y, width: 3, height: h, rx: Math.min(r, 1.5), fill: st.edge }, parent);
229
+ return n;
230
+ }
231
+ const legendCss = ':where(.chart-legend){list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:4px 14px;font-size:12px;line-height:16px;color:var(--muted,#5f6368)}:where(.chart-legend li){display:inline-flex;align-items:center;gap:6px;white-space:nowrap}:where(.chart-legend svg){flex:none;overflow:visible}@media (max-width:480px){:where(.chart-legend){display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}}';
232
+ function legendEl(items, target) {
233
+ if (!document.getElementById('charts-legend-css')) { const st = document.createElement('style'); st.id = 'charts-legend-css'; st.textContent = legendCss; document.head.appendChild(st); }
234
+ const ul = document.createElement('ul'); ul.className = 'chart-legend';
235
+ for (const it of items) {
236
+ const li = document.createElement('li'), sw = svg('svg', { width: it.w || 14, height: 12, 'aria-hidden': 'true' });
237
+ it.draw(sw); li.append(sw, document.createTextNode(it.label)); ul.appendChild(li);
238
+ }
239
+ const t = typeof target === 'string' ? document.querySelector(target) : target;
240
+ if (t) t.replaceChildren(ul);
241
+ return ul;
242
+ }
243
+ const rectSwatch = (st, w = 14, h = 10, r = 2) => (sw) => paintRect(sw, st, 0, (12 - h) / 2, w, h, r);
244
+ // charts are laid out with measured text: draw again once the page's fonts have arrived
245
+ function settle(draw) { if (document.fonts) { document.fonts.ready.then(draw); document.fonts.addEventListener?.('loadingdone', draw, { once: true }); } }
246
+ const heightOf = (h) => (typeof h === 'function' ? h() : h);
247
+
248
+ function line(el, { labels, series, format = fmt.int, tickFormat = null, height = 220, fill = false, min, max, step = false, annotations, reference, today = null, todayLabel = 'Today', endLabel = false, yTicks = null, xAt = null, legend = null }) {
249
+ el._fmt = format;
250
+ const colourOf = (sr, k) => sr.colour || (k === 0 ? css(el, '--chart-1', '#2f6fdf') : css(el, `--chart-${k + 1}`, css(el, '--chart-muted', '#a3a3a3')));
251
+ const draw = () => {
252
+ const { s, w, h } = frame(el, heightOf(height));
253
+ const all = series.flatMap((x) => x.values.filter((v) => v != null)).concat([].concat(reference || []).map((r) => r.value));
254
+ // max caps the range (a flat series with one spike): values above it are clipped and their peak labelled
255
+ const top = max ?? Math.max(...all);
256
+ const yt = yTicks || ticks(min ?? Math.min(0, ...all), top, 4);
257
+ const tick = tickFormat || format;
258
+ const lastVal = series[0].values.filter((v) => v != null).at(-1);
259
+ const padL = 12 + Math.max(...yt.map((v) => measure(s, tick(v), 12))), padB = 26, padR = endLabel ? 10 + measure(s, format(lastVal), 12, 600) : 0;
260
+ const x = (i) => padL + (i * (w - padL - padR)) / Math.max(1, labels.length - 1);
261
+ // the peaks clipped by max are labelled in the rows above the plot, where the line leaves it
262
+ const peaks = [];
263
+ series.forEach((sr, k) => sr.values.forEach((v, i) => { if (v != null && v > yt.at(-1) && (i === 0 || sr.values[i - 1] == null || sr.values[i - 1] <= yt.at(-1))) { let j = i, peak = v; while (j < sr.values.length && sr.values[j] != null && sr.values[j] > yt.at(-1)) { peak = Math.max(peak, sr.values[j]); j++; } peaks.push({ x: x(i), label: format(peak) + ' at ' + labels[i], colour: colourOf(sr, k) }); } }));
264
+ const scale = (N) => { const padT = LANE(N.rows); return { padT, y: (v) => padT + (h - padT - padB) * (1 - (v - yt[0]) / (yt.at(-1) - yt[0])) }; };
265
+ const linesAt = (y) => series.map((sr) => { const out = []; sr.values.forEach((v, i) => { if (v == null) { out.push(null); return; } const p = [x(i), y(Math.min(v, yt.at(-1)))]; const prev = out.at(-1); if (step && prev) out.push([p[0], prev[1]]); out.push(p); }); return out; }).concat([].concat(reference || []).map((r) => [[padL, y(r.value)], [w, y(r.value)]]));
266
+ let N = prepNotes(s, annotations, x, w, peaks), { padT, y } = scale(N), todayBox = null;
267
+ // the today label goes inside the plot on whichever side of its line no series crosses; failing that, above
268
+ if (today != null && todayLabel) {
269
+ const cut = x(today), tw = measure(s, todayLabel, 11), lines = linesAt(y);
270
+ const cand = [[cut + 4, h - padB - 6], [cut - 4 - tw, h - padB - 6], [cut + 4, padT + 11], [cut - 4 - tw, padT + 11]].map(([x0, b]) => ({ x0, x1: x0 + tw, y0: b - 9, y1: b + 2, base: b }));
271
+ todayBox = cand.find((b) => b.x0 >= padL && b.x1 <= w && !hits(b, lines)) || null;
272
+ if (!todayBox) { N = prepNotes(s, annotations, x, w, [...peaks, { x: cut, leader: cut, drawn: true, label: todayLabel }]); ({ padT, y } = scale(N)); }
273
+ }
274
+ const g = svg('g', {}, s);
275
+ axes(g, el, { w, h, padL, padB, yt, y, labels, x, at: xAt, tick });
276
+ notesUnder(g, el, N, { padT, h, padB });
277
+ series.forEach((sr, k) => {
278
+ const col = colourOf(sr, k);
279
+ const pts = sr.values.map((v, i) => (v == null ? null : [x(i), y(Math.min(v, yt.at(-1)))]));
280
+ // step: a balance that only changes on given days holds its value until the next one
281
+ const d = pts.reduce((acc, p, i) => (p ? acc + (acc && pts[i - 1] ? (step ? `L${p[0].toFixed(1)} ${pts[i - 1][1].toFixed(1)}L` : 'L') : 'M') + p[0].toFixed(1) + ' ' + p[1].toFixed(1) : acc), '');
282
+ if (fill && k === 0) { const first = pts.find(Boolean), last = [...pts].reverse().find(Boolean); svg('path', { d: `${d}L${last[0]} ${y(yt[0])}L${first[0]} ${y(yt[0])}Z`, fill: col, opacity: 0.12 }, g); }
283
+ if (today == null) svg('path', { d, fill: 'none', stroke: col, 'stroke-width': 2, 'stroke-linejoin': 'round', 'stroke-linecap': 'round' }, g);
284
+ else {
285
+ // a forecast: the line after today is dashed, so a projection never reads as a fact
286
+ const cut = x(today), id = 'c' + k + Math.random().toString(36).slice(2, 8);
287
+ const defs = svg('defs', {}, g);
288
+ const a = svg('clipPath', { id: id + 'a' }, defs); svg('rect', { x: 0, y: 0, width: cut, height: h }, a);
289
+ const b = svg('clipPath', { id: id + 'b' }, defs); svg('rect', { x: cut, y: 0, width: w, height: h }, b);
290
+ svg('path', { d, fill: 'none', stroke: col, 'stroke-width': 2, 'stroke-linejoin': 'round', 'clip-path': 'url(#' + id + 'a)' }, g);
291
+ svg('path', { d, fill: 'none', stroke: col, 'stroke-width': 2, 'stroke-dasharray': '5 4', opacity: 0.8, 'clip-path': 'url(#' + id + 'b)' }, g);
292
+ if (k === 0) { svg('line', { x1: cut, x2: cut, y1: padT, y2: h - padB, stroke: css(el, '--axis-ink', '#6b6b6b'), 'stroke-width': 1, opacity: 0.4 }, g); if (todayBox) text(g, todayLabel, { x: todayBox.x0, y: todayBox.base, 'font-size': 11, fill: css(el, '--axis-ink', '#6b6b6b') }); }
293
+ }
294
+ if (endLabel && k === 0) { const li = sr.values.map((v, i) => (v == null ? -1 : i)).filter((i) => i >= 0).at(-1); text(g, format(sr.values[li]), { x: x(li) + 6, y: y(Math.min(sr.values[li], yt.at(-1))) + 4, 'font-size': 12, 'font-weight': 600, fill: css(el, '--ink', '#111') }); }
295
+ });
296
+ references(g, el, reference, { y, padL, w, lines: linesAt(y).slice(0, series.length) });
297
+ notesOver(g, el, N, { padT, h, padB });
298
+ // hover: a rule, a dot per series and a bare tooltip
299
+ const tip = tooltip(el), rule = svg('line', { y1: padT, y2: h - padB, stroke: css(el, '--axis-ink', '#6b6b6b'), 'stroke-width': 1, opacity: 0 }, g);
300
+ const dots = series.map((sr, k) => svg('circle', { r: 3.5, fill: css(el, '--surface', '#fff'), stroke: colourOf(sr, k), 'stroke-width': 2, opacity: 0 }, g));
301
+ const hit = svg('rect', { x: padL, y: padT, width: w - padL, height: h - padT - padB, fill: 'transparent' }, s);
302
+ const move = (ev) => { const r = s.getBoundingClientRect(); const px = ((ev.clientX - r.left) / r.width) * w; const i = Math.max(0, Math.min(labels.length - 1, Math.round(((px - padL) / (w - padL - padR)) * (labels.length - 1)))); rule.setAttribute('x1', x(i)); rule.setAttribute('x2', x(i)); rule.setAttribute('opacity', 0.35); series.forEach((sr, k) => { const v = sr.values[i]; dots[k].setAttribute('cx', x(i)); dots[k].setAttribute('cy', v == null ? -99 : y(Math.min(v, yt.at(-1)))); dots[k].setAttribute('opacity', v == null ? 0 : 1); }); tip.innerHTML = `<div style="opacity:.7">${labels[i]}</div>` + series.map((sr) => `<div><b style="font-weight:600">${sr.values[i] == null ? '–' : format(sr.values[i])}</b> ${series.length > 1 ? sr.name : ''}</div>`).join(''); const left = Math.min((x(i) / w) * r.width + 12, r.width - tip.offsetWidth - 4); tip.style.left = `${Math.max(0, left)}px`; tip.style.top = '0px'; tip.style.opacity = 1; };
303
+ hit.addEventListener('pointermove', move); hit.addEventListener('pointerleave', () => { tip.style.opacity = 0; rule.setAttribute('opacity', 0); dots.forEach((d) => d.setAttribute('opacity', 0)); });
304
+ const last = series[0].values.filter((v) => v != null).at(-1);
305
+ s.setAttribute('aria-label', `${series.map((x) => x.name).join(', ')}, ${labels[0]} to ${labels.at(-1)}; latest ${last == null ? 'no data' : format(last)}`);
306
+ };
307
+ draw(); watch(el, draw); settle(draw);
308
+ const lg = series.length > 1 ? legendEl(series.map((sr, k) => ({ label: sr.name, w: 16, draw: (sw) => svg('line', { x1: 0, x2: 16, y1: 6, y2: 6, stroke: colourOf(sr, k), 'stroke-width': 2, 'stroke-dasharray': sr.dash ? '4 3' : null }, sw) })), legend) : null;
309
+ return { legend: lg };
310
+ }
311
+ function bars(el, { labels, values, format = fmt.int, tickFormat = null, height = 200, highlight = null, dim = [], colour, mutedColour, annotations, reference, xAt = null }) {
312
+ el._fmt = format;
313
+ const lit = (i) => highlight == null || (Array.isArray(highlight) ? highlight.includes(i) : highlight === i);
314
+ const draw = () => {
315
+ const { s, w, h } = frame(el, heightOf(height));
316
+ const yt = ticks(0, Math.max(...values, ...[].concat(reference || []).map((r) => r.value)), 4), tick = tickFormat || format;
317
+ const padL = 12 + Math.max(...yt.map((v) => measure(s, tick(v), 12))), padB = 26;
318
+ const band = (w - padL) / values.length, bw = Math.max(2, band * 0.62);
319
+ const x = (i) => padL + band * i + band / 2;
320
+ const N = prepNotes(s, annotations, x, w), padT = LANE(N.rows);
321
+ const y = (v) => padT + (h - padT - padB) * (1 - v / yt.at(-1));
322
+ const g = svg('g', {}, s);
323
+ axes(g, el, { w, h, padL, padB, yt, y, labels, x, band: true, at: xAt, tick });
324
+ notesUnder(g, el, N, { padT, h, padB });
325
+ for (const it of N.items) if (it.at != null && values[it.at] != null) it.end = y(values[it.at]) - 4;
326
+ const main = colour || css(el, '--chart-1', '#2f6fdf'), muted = mutedColour || css(el, '--chart-muted', '#c9c9c9');
327
+ values.forEach((v, i) => { const r = svg('rect', { x: x(i) - bw / 2, y: y(v), width: bw, height: Math.max(0, y(0) - y(v)), fill: lit(i) ? main : muted, opacity: dim.includes(i) ? 0.45 : null, 'shape-rendering': 'crispEdges' }, g); titled(r, `${labels[i]}: ${format(v)}`, {}); });
328
+ references(g, el, reference, { y, padL, w, boxes: values.map((v, i) => ({ x0: x(i) - bw / 2, x1: x(i) + bw / 2, y0: y(v), y1: y(0) })) });
329
+ notesOver(g, el, N, { padT, h, padB });
330
+ s.setAttribute('aria-label', `${labels.length} bars from ${labels[0]} to ${labels.at(-1)}; highest ${format(Math.max(...values))}`);
331
+ };
332
+ draw(); watch(el, draw); settle(draw);
333
+ }
334
+ // Two directions on one scale: what went out above the zero line and what came in below it (sold and bought,
335
+ // income and spend). The axis says which is which, with signed ticks and a caption on each side of zero.
336
+ // mark: [indices] draws those periods in a second tone with their own legend entry (the nights the car charged).
337
+ function diverging(el, { labels, up, down, values, above = 'Above', below = 'Below', mark = [], markLabel = null, markSide = 'below', partial = null, format = fmt.int, tickFormat = null, height = 200, annotations, reference, xAt = null, legend = null }) {
338
+ if (values) { up = values.map((v) => Math.max(0, v || 0)); down = values.map((v) => Math.max(0, -(v || 0))); }
339
+ up = up || labels.map(() => 0); down = down || labels.map(() => 0);
340
+ const st = { above: { fill: css(el, '--chart-1', '#2f6fdf') }, below: { fill: css(el, '--chart-muted', '#c9c9c9') }, mark: { fill: css(el, '--chart-mark', css(el, '--ink', '#111')) } };
341
+ const marked = (i, side) => mark.includes(i) && (markSide === 'both' || markSide === side);
342
+ const tick = (v) => (v > 0 ? '+' : v < 0 ? MINUS : '') + (tickFormat || format)(Math.abs(v));
343
+ const draw = () => {
344
+ const { s, w, h } = frame(el, heightOf(height));
345
+ const hiUp = Math.max(0, ...up), hiDown = Math.max(0, ...down);
346
+ const yt = ticks(-hiDown, hiUp || 1, 4); const stp = yt[1] - yt[0]; if (hiDown > 0 && yt[0] >= -hiDown) yt.unshift(+(yt[0] - stp).toFixed(10));
347
+ const padL = 12 + Math.max(...yt.map((v) => measure(s, tick(v), 12))), padB = 26;
348
+ const band = (w - padL) / labels.length, bw = Math.max(2, band * 0.62);
349
+ const x = (i) => padL + band * i + band / 2;
350
+ // the caption for the upper side opens the label rows above the plot; the lower one sits under the plot, at left
351
+ const N = prepNotes(s, annotations, x, w, [{ fixed: padL, glyph: 'up', label: above }]), padT = LANE(N.rows);
352
+ const y = (v) => padT + (h - padT - padB) * (1 - (v - yt[0]) / (yt.at(-1) - yt[0]));
353
+ const g = svg('g', {}, s), ink = css(el, '--axis-ink', '#6b6b6b');
354
+ const bwid = measure(s, below, 11) + 9;
355
+ axes(g, el, { w, h, padL, padB, yt, y, labels, x, band: true, at: xAt, tick, avoid: [padL, padL + bwid] });
356
+ svg('path', { d: `M${padL} ${h - padB + 11}l3 6l3 -6z`, fill: ink }, g); text(g, below, { x: padL + 9, y: h - padB + 18, 'font-size': 11, fill: ink });
357
+ notesUnder(g, el, N, { padT, h, padB });
358
+ for (const it of N.items) if (it.at != null) it.end = y(up[it.at] || 0) - 4;
359
+ labels.forEach((lab, i) => {
360
+ const o = partial === i ? 0.5 : null;
361
+ if (up[i] > 0) { const r = paintRect(g, { ...(marked(i, 'above') ? st.mark : st.above), opacity: o }, x(i) - bw / 2, y(up[i]), bw, Math.max(0, y(0) - y(up[i]) - 1)); titled(r, `${lab}: ${above} ${format(up[i])}`, {}); }
362
+ if (down[i] > 0) { const r = paintRect(g, { ...(marked(i, 'below') ? st.mark : st.below), opacity: o }, x(i) - bw / 2, y(0) + 1, bw, Math.max(0, y(-down[i]) - y(0) - 1)); titled(r, `${lab}: ${below} ${format(down[i])}`, {}); }
363
+ });
364
+ svg('line', { x1: padL, x2: w, y1: y(0), y2: y(0), stroke: ink, 'stroke-width': 1, opacity: 0.8, 'shape-rendering': 'crispEdges' }, g);
365
+ references(g, el, reference, { y, padL, w, boxes: labels.map((_, i) => ({ x0: x(i) - bw / 2, x1: x(i) + bw / 2, y0: y(up[i]), y1: y(-down[i]) })) });
366
+ notesOver(g, el, N, { padT, h, padB });
367
+ s.setAttribute('aria-label', `${above} above the line and ${below} below it, ${labels[0]} to ${labels.at(-1)}`);
368
+ };
369
+ draw(); watch(el, draw); settle(draw);
370
+ const items = [];
371
+ if (up.some((v) => v > 0)) items.push({ label: above, draw: rectSwatch(st.above) });
372
+ if (down.some((v) => v > 0)) items.push({ label: below, draw: rectSwatch(st.below) });
373
+ if (mark.length && markLabel) items.push({ label: markLabel, draw: rectSwatch(st.mark) });
374
+ return { get svg() { return el.querySelector(':scope > svg'); }, legend: legendEl(items, legend) };
375
+ }
376
+ function ring(el, { value, label, sub, size = 132, stroke = 8, colour }) {
377
+ el.innerHTML = '';
378
+ const r = (size - stroke) / 2, c = 2 * Math.PI * r, v = Math.max(0, Math.min(1, value));
379
+ const wrap = document.createElement('div'); wrap.style.cssText = `position:relative;width:${size}px;height:${size}px`;
380
+ const s = svg('svg', { viewBox: `0 0 ${size} ${size}`, width: size, height: size, role: 'img', 'aria-label': `${label}${sub ? ' ' + sub : ''}` }, wrap);
381
+ svg('circle', { cx: size / 2, cy: size / 2, r, fill: 'none', stroke: css(el, '--grid', '#e8e8e8'), 'stroke-width': stroke }, s);
382
+ svg('circle', { cx: size / 2, cy: size / 2, r, fill: 'none', stroke: colour || css(el, '--chart-1', '#2f6fdf'), 'stroke-width': stroke, 'stroke-dasharray': `${c * v} ${c}`, transform: `rotate(-90 ${size / 2} ${size / 2})` }, s);
383
+ const t = document.createElement('div'); t.style.cssText = 'position:absolute;inset:0;display:grid;place-content:center;text-align:center;font-variant-numeric:tabular-nums';
384
+ t.innerHTML = `<div style="font-size:${Math.round(size / 5.5)}px;font-weight:600;line-height:1">${label}</div>${sub ? `<div style="font-size:12px;opacity:.7;margin-top:4px">${sub}</div>` : ''}`;
385
+ wrap.appendChild(t); el.appendChild(wrap);
386
+ }
387
+ // A ranked list. By default the row's fill is the bar (a one-figure list); thin: true puts a 2px grey bar under each
388
+ // label instead, ink for the top item, for a ranked list of money in a narrow card.
389
+ function barList(el, rows, { format = fmt.int, colour, thin = false } = {}) {
390
+ el.innerHTML = '';
391
+ const max = Math.max(...rows.map((r) => r.value)) || 1;
392
+ const list = document.createElement('ol'); list.style.cssText = `list-style:none;margin:0;padding:0;display:grid;gap:${thin ? 10 : 2}px;font-variant-numeric:tabular-nums`;
393
+ const valueCol = Math.max(...rows.map((r) => String(format(r.value)).length)) + 1;
394
+ rows.forEach((r, k) => {
395
+ const li = document.createElement('li'); li.style.cssText = 'display:grid;grid-template-columns:minmax(0,1fr) ' + valueCol + 'ch;align-items:center;column-gap:12px';
396
+ const a = document.createElement('span'); a.textContent = r.label; a.style.cssText = 'position:relative;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis';
397
+ const b = document.createElement('span'); b.textContent = format(r.value); b.style.cssText = 'font-weight:500;text-align:right';
398
+ if (thin) {
399
+ const bar = document.createElement('span'); bar.style.cssText = `grid-column:1 / -1;height:2px;margin-top:4px;width:${(r.value / max) * 100}%;background:${k === 0 ? colour || 'var(--ink,#111)' : 'var(--chart-muted,#c9c9c9)'}`;
400
+ li.append(a, b, bar);
401
+ } else {
402
+ const track = document.createElement('span'); track.style.cssText = 'position:relative;padding:10px 12px;border-radius:6px;isolation:isolate;min-width:0';
403
+ const bar = document.createElement('span'); bar.style.cssText = `position:absolute;inset:0 auto 0 0;width:${(r.value / max) * 100}%;background:${colour || 'var(--bar-fill, color-mix(in srgb, var(--chart-1, #2f6fdf) 12%, transparent))'};border-radius:inherit;z-index:-1`;
404
+ track.append(bar, a); li.append(track, b);
405
+ }
406
+ list.appendChild(li);
407
+ });
408
+ el.appendChild(list);
409
+ }
410
+ // Planned against spent: the track is the plan, the fill what is spent, a lighter segment what is
411
+ // already committed (bills to come), and an overrun past the track's end in the negative colour.
412
+ // One row per category: label and figures on one line, the 8px track under them.
413
+ function plan(el, rows, { format = fmt.money('EUR', 0), scale = 'row', note = (r) => r.spent > r.planned ? `${format(r.spent - r.planned)} over` : `${format(r.planned - r.spent - (r.committed || 0))} left` } = {}) {
414
+ el.innerHTML = '';
415
+ const list = document.createElement('ul'); list.style.cssText = 'list-style:none;margin:0;padding:0;display:grid;gap:14px;font-variant-numeric:tabular-nums';
416
+ const max = Math.max(...rows.map((r) => Math.max(r.planned, r.spent + (r.committed || 0))));
417
+ for (const r of rows) {
418
+ const over = r.spent > r.planned;
419
+ const li = document.createElement('li');
420
+ const top = document.createElement('div'); top.style.cssText = 'display:flex;justify-content:space-between;gap:12px;margin-bottom:6px';
421
+ top.innerHTML = `<span>${r.label}</span><span><b style="font-weight:500">${format(r.spent)}</b> <span style="color:var(--muted,#5f6368)">of ${format(r.planned)} · </span><span style="color:${over ? 'var(--negative,#c4242a)' : 'var(--muted,#5f6368)'}">${note(r)}</span></span>`;
422
+ // scale 'row': each track is full width and shows the share used (rows in a grid compare); 'plan': as long as its plan
423
+ const room = over ? 100 / (1 + Math.max(0.06, (r.spent - r.planned) / r.planned)) : 100;
424
+ const track = document.createElement('div'); track.style.cssText = 'position:relative;height:8px;border-radius:999px;background:var(--rule,#eceeef);overflow:visible;width:' + (scale === 'plan' ? (r.planned / max) * room : room) + '%';
425
+ const pct = (v) => (v / r.planned) * 100;
426
+ const spent = Math.min(r.spent, r.planned);
427
+ track.innerHTML = `<span style="position:absolute;inset:0 auto 0 0;width:${pct(spent)}%;border-radius:999px;background:var(--chart-1,#2f6fdf)"></span>`
428
+ + (r.committed ? `<span style="position:absolute;top:0;bottom:0;left:${pct(spent)}%;width:${Math.min(pct(r.committed), 100 - pct(spent))}%;background:var(--chart-1,#2f6fdf);opacity:.35"></span>` : '')
429
+ + (over ? `<span style="position:absolute;top:-3px;bottom:-3px;left:100%;width:1px;background:var(--text,#111)"></span><span style="position:absolute;top:0;bottom:0;left:calc(100% + 2px);width:max(12px, ${pct(r.spent - r.planned)}%);border-radius:0 999px 999px 0;background:var(--negative,#c4242a)"></span>` : '');
430
+ track.setAttribute('role', 'img'); track.setAttribute('aria-label', `${r.label}: ${format(r.spent)} of ${format(r.planned)}${r.committed ? `, ${format(r.committed)} committed` : ''}${over ? ', over plan' : ''}`);
431
+ li.append(top, track); list.appendChild(li);
432
+ }
433
+ el.appendChild(list);
434
+ }
435
+ // Share against a target: one row per part, the current share as a bar and a 1px tick at the target,
436
+ // so drift reads at a glance (never two stacked bars to compare).
437
+ function bullet(el, rows, { format = fmt.pct(1), max = Math.max(...rows.map((r) => Math.max(r.value, r.target))) * 1.15 } = {}) {
438
+ el.innerHTML = '';
439
+ const list = document.createElement('ul'); list.style.cssText = 'list-style:none;margin:0;padding:0;display:grid;gap:12px;font-variant-numeric:tabular-nums';
440
+ for (const r of rows) {
441
+ const drift = r.value - r.target;
442
+ const li = document.createElement('li'); li.style.cssText = 'display:grid;grid-template-columns:minmax(90px,30%) 1fr auto;align-items:center;gap:12px';
443
+ li.innerHTML = `<span>${r.label}</span><span style="position:relative;height:10px;background:var(--rule,#eceeef);border-radius:2px"><span style="position:absolute;inset:0 auto 0 0;width:${(r.value / max) * 100}%;background:var(--chart-1,#2f6fdf);border-radius:2px"></span><span style="position:absolute;top:-4px;bottom:-4px;left:${(r.target / max) * 100}%;width:2px;margin-left:-1px;background:var(--text,#111)"></span></span><span><b style="font-weight:500">${format(r.value)}</b> <span style="color:${Math.abs(drift) >= (r.tolerance ?? 0.02) ? 'var(--negative,#c4242a)' : 'var(--muted,#5f6368)'}">${drift >= 0 ? '+' : '−'}${format(Math.abs(drift))} vs ${format(r.target)}</span></span>`;
444
+ li.setAttribute('aria-label', `${r.label}: ${format(r.value)}, target ${format(r.target)}`);
445
+ list.appendChild(li);
446
+ }
447
+ el.appendChild(list);
448
+ }
449
+ // shared by the row charts (timeline, matrix, time strip): a label column with an optional grey subline.
450
+ // A subline needs a 40-44px row pitch; one-line labels sit on 32px.
451
+ function rowLabel(g, s, el, r, { y0, pitch, lw }) {
452
+ const ink = css(el, '--ink', '#111'), muted = css(el, '--axis-ink', '#6b6b6b');
453
+ if (r.sub) { text(g, fit(s, r.label, lw - 12, 14), { x: 0, y: y0 + pitch / 2 - 3, 'font-size': 14, fill: ink }); text(g, fit(s, r.sub, lw - 12, 12), { x: 0, y: y0 + pitch / 2 + 13, 'font-size': 12, fill: muted }); }
454
+ else text(g, fit(s, r.label, lw - 12, 14), { x: 0, y: y0 + pitch / 2 + 5, 'font-size': 14, fill: ink });
455
+ }
456
+ const dayText = (d) => (typeof d === 'object' && d ? d.label : String(d));
457
+ // day headers: the full label when every one fits its column, else the short form ('19'), else every k-th short
458
+ // label with today always shown and its neighbours left out, so no two headers ever touch
459
+ function dayHeads(g, s, el, days, { x0, cw, y, today }) {
460
+ const ink = css(el, '--ink', '#111'), muted = css(el, '--axis-ink', '#6b6b6b');
461
+ const full = days.map(dayText), short = days.map((d) => (typeof d === 'object' && d ? d.short || dayText(d) : dayText(d).split(' ').at(-1)));
462
+ const wide = (labs) => Math.max(...labs.map((t) => measure(s, t, 12))) + 6;
463
+ const labs = wide(full) <= cw ? full : short, k = Math.max(1, Math.ceil(wide(labs) / cw));
464
+ labs.forEach((t, i) => {
465
+ if (i !== today && (i % k || (today != null && k > 1 && Math.abs(i - today) < k))) return;
466
+ text(g, t, { x: x0 + i * cw + cw / 2, y, 'text-anchor': 'middle', 'font-size': 12, 'font-weight': i === today ? 600 : 400, fill: i === today ? ink : muted });
467
+ });
468
+ }
469
+ // The style of each kind of booking: a pale fill, a 1px diagonal hatch, a darker grey step, an outline, or the one
470
+ // chart hue for the screen's main data element. tone: 'negative' turns the edge and the label red (it needs a decision).
471
+ function kindStyle(el, k = {}) {
472
+ const ink = css(el, '--ink', '#111'), surface = css(el, '--surface', '#fff'), neg = css(el, '--negative', '#c4242a'), hue = k.colour || css(el, '--chart-1', '#2f6fdf');
473
+ const tone = k.tone === 'negative' ? { stroke: neg, width: 1.5 } : {};
474
+ const dash = k.dash ? { dash: '3 2' } : {};
475
+ if (k.mark === 'hatch') return { fill: mix(el, ink, surface, 0.04), hatch: mix(el, ink, surface, 0.32), ...tone, ...dash };
476
+ if (k.mark === 'step') return { fill: mix(el, ink, surface, 0.24), ...tone, ...dash };
477
+ if (k.mark === 'outline') return { fill: surface, stroke: mix(el, ink, surface, 0.55), width: 1, ...tone, ...dash };
478
+ if (k.mark === 'hue') return { fill: mix(el, hue, surface, 0.18), edge: hue, ...tone, ...dash };
479
+ return { fill: mix(el, ink, surface, 0.12), ...tone, ...dash };
480
+ }
481
+ // Who is away when: people (or rooms, vans) down the left, days across, a bar per booking told apart by its kind.
482
+ // rows: [{ label: 'Lena Hoffmann', sub: 'Product design · Berlin', bars: [{ from: 3, to: 7, kind: 'holiday', label, note }] }]
483
+ // and { group: 'Brand' } rows for a team subheader
484
+ // kinds: { holiday: { label: 'Holiday', mark: 'fill' | 'hatch' | 'step' | 'outline' | 'hue', code: 'H', tone, dash } }
485
+ // days: ['Mon 19', …] or [{ label: 'Mon 19', short: '19' }]; weekends: [indices]; today: index;
486
+ // holidays: [{ day: index, label: 'All Saints’ Day (Lisbon)' }]; onSelect(bar, row) makes the bars buttons.
487
+ // A label that does not fit its bar becomes the kind's code inside it, then goes after the bar's end (never into the
488
+ // days before it), and is always in the bar's tooltip.
489
+ function timeline(el, rows, kinds = {}, { days = [], weekends = [], today = null, holidays = [], labelWidth = null, rowHeight = null, barHeight = 22, onSelect = null, legend = null, extras = true } = {}) {
490
+ const draw = () => {
491
+ const pitch = rowHeight || (rows.some((r) => r.sub) ? 44 : 32), head = 30, groupH = 30;
492
+ const height = head + rows.reduce((a, r) => a + (r.group ? groupH : pitch), 0) + 2;
493
+ const { s, w, h } = frame(el, height);
494
+ const lw = labelWidth || Math.round(Math.min(220, Math.max(w < 480 ? 96 : 120, w * 0.2)));
495
+ const cw = (w - lw) / Math.max(1, days.length), col = (i) => lw + i * cw;
496
+ const ink = css(el, '--ink', '#111'), muted = css(el, '--axis-ink', '#6b6b6b'), rule = css(el, '--rule', '#f0f0f0'), raised = css(el, '--raised', '#f4f5f6'), hue = css(el, '--chart-1', '#2f6fdf');
497
+ const g = svg('g', {}, s);
498
+ // weekends one tone step darker, faint day lines, the day header (today in ink)
499
+ for (const i of weekends) svg('rect', { x: col(i), y: head, width: cw, height: h - head, fill: raised }, g);
500
+ for (let i = 0; i <= days.length; i++) svg('line', { x1: col(i), x2: col(i), y1: head, y2: h, stroke: rule, 'stroke-width': 1, 'shape-rendering': 'crispEdges' }, g);
501
+ dayHeads(g, s, el, days, { x0: lw, cw, y: head - 10, today });
502
+ for (const hd of holidays) { const c = svg('circle', { cx: col(hd.day) + cw / 2, cy: head - 3, r: 2, fill: muted }, g); titled(c, hd.label, {}); }
503
+ if (today != null) svg('line', { x1: col(today) + cw / 2, x2: col(today) + cw / 2, y1: head, y2: h, stroke: hue, 'stroke-width': 1, 'shape-rendering': 'crispEdges' }, g);
504
+ let y0 = head;
505
+ for (const r of rows) {
506
+ if (r.group) { svg('line', { x1: 0, x2: w, y1: y0 + 0.5, y2: y0 + 0.5, stroke: rule, 'stroke-width': 1 }, g); text(g, r.group, { x: 0, y: y0 + 20, 'font-size': 12, 'font-weight': 500, fill: muted }); y0 += groupH; continue; }
507
+ rowLabel(g, s, el, r, { y0, pitch, lw });
508
+ const bs = (r.bars || []).filter((b) => b.to >= 0 && b.from < days.length).sort((a, b) => a.from - b.from);
509
+ bs.forEach((b, k) => {
510
+ const kind = kinds[b.kind] || {}, st = kindStyle(el, kind);
511
+ const x0 = col(Math.max(0, b.from)) + 2, x1 = col(Math.min(days.length - 1, b.to) + 1) - 2, by = y0 + (pitch - barHeight) / 2;
512
+ const grp = svg('g', onSelect ? { tabindex: 0, role: 'button', style: 'cursor:pointer' } : {}, g);
513
+ paintRect(grp, st, x0, by, x1 - x0, barHeight, 4);
514
+ const label = b.label ?? kind.label ?? '', code = b.code ?? kind.code, tw = measure(s, label, 12), labInk = kind.tone === 'negative' ? css(el, '--negative', '#c4242a') : ink;
515
+ const next = bs[k + 1] ? col(Math.max(0, bs[k + 1].from)) : w;
516
+ // over a hatch the label keeps a halo of the bar's own fill, so the lines never run through the words
517
+ const halo = st.hatch ? { stroke: st.fill, 'stroke-width': 4, 'stroke-linejoin': 'round', 'paint-order': 'stroke' } : {};
518
+ if (label && tw + 16 <= x1 - x0) text(grp, label, { x: x0 + 8 + (st.edge ? 2 : 0), y: by + barHeight / 2 + 4, 'font-size': 12, fill: labInk, ...halo });
519
+ else if (code && measure(s, code, 12) + 8 <= x1 - x0) text(grp, code, { x: (x0 + x1) / 2, y: by + barHeight / 2 + 4, 'text-anchor': 'middle', 'font-size': 12, fill: labInk, ...halo });
520
+ else if (label && x1 + 6 + tw <= Math.min(next - 6, w)) text(grp, label, { x: x1 + 6, y: by + barHeight / 2 + 4, 'font-size': 12, fill: kind.tone === 'negative' ? labInk : muted });
521
+ titled(grp, `${r.label}: ${label}${b.note ? ' \u00b7 ' + b.note : ''}`, {});
522
+ if (onSelect) { grp.addEventListener('click', () => onSelect(b, r)); grp.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onSelect(b, r); } }); }
523
+ });
524
+ y0 += pitch;
525
+ }
526
+ s.setAttribute('aria-label', `${rows.filter((r) => !r.group).length} rows across ${days.length} days, ${dayText(days[0])} to ${dayText(days.at(-1))}`);
527
+ };
528
+ draw(); watch(el, draw); settle(draw);
529
+ const used = new Set(rows.flatMap((r) => (r.bars || []).map((b) => b.kind)));
530
+ const items = Object.entries(kinds).filter(([id]) => used.has(id)).map(([, k]) => ({ label: k.label, w: 22, draw: (sw) => { const st = kindStyle(el, k); paintRect(sw, st, 0, 0, 22, 12, 3); } }));
531
+ if (extras && today != null) items.push({ label: 'Today', w: 8, draw: (sw) => svg('line', { x1: 4, x2: 4, y1: 0, y2: 12, stroke: css(el, '--chart-1', '#2f6fdf'), 'stroke-width': 1.5 }, sw) });
532
+ return { get svg() { return el.querySelector(':scope > svg'); }, legend: legendEl(items, legend) };
533
+ }
534
+ // Is there enough cover? A team-by-day grid of slack against the minimum (+2, +1, 0, −1). Cells with room to spare
535
+ // stay plain, and one hue ramps toward the negative colour as the slack runs out; the headcount is in the tooltip.
536
+ // rows: [{ label: 'Product design', sub: 'needs 7 of 10', values: [2, 1, 0, -1, null, …], titles: ['8 in', …] }]
537
+ // cols: ['Mon 19', …]; comfort: the slack that needs no attention (2); null is a day with no cover to count (a dash)
538
+ function matrix(el, rows, { cols = [], comfort = 2, today = null, format = fmt.signed(), labelWidth = null, rowHeight = null, levels = ['Room to spare', 'Tight', 'At the minimum', 'Short'], legend = null } = {}) {
539
+ const level = (v) => (v >= comfort ? 0 : v > 0 ? 1 : v === 0 ? 2 : 3);
540
+ const styles = () => { const neg = css(el, '--negative', '#c4242a'), surface = css(el, '--surface', '#fff'), ink = css(el, '--ink', '#111'); return [{ fill: surface, ink: css(el, '--axis-ink', '#6b6b6b'), stroke: css(el, '--grid', '#e5e5e5') }, { fill: mix(el, neg, surface, 0.1), ink }, { fill: mix(el, neg, surface, 0.26), ink }, { fill: neg, ink: surface }]; };
541
+ const draw = () => {
542
+ const pitch = rowHeight || (rows.some((r) => r.sub) ? 44 : 32), head = 26;
543
+ const { s, w, h } = frame(el, head + rows.length * pitch);
544
+ const lw = labelWidth || Math.round(Math.min(220, Math.max(w < 480 ? 96 : 120, w * 0.22)));
545
+ const cw = (w - lw) / Math.max(1, cols.length), ST = styles(), muted = css(el, '--axis-ink', '#6b6b6b'), ink = css(el, '--ink', '#111');
546
+ const g = svg('g', {}, s);
547
+ dayHeads(g, s, el, cols, { x0: lw, cw, y: head - 10, today });
548
+ rows.forEach((r, k) => {
549
+ const y0 = head + k * pitch; rowLabel(g, s, el, r, { y0, pitch, lw });
550
+ const ch = Math.min(pitch - 6, 28), cy = y0 + (pitch - ch) / 2;
551
+ r.values.forEach((v, i) => {
552
+ const cx = lw + i * cw + 1;
553
+ if (v == null) { svg('rect', { x: cx + cw / 2 - 4, y: cy + ch / 2 - 1, width: 6, height: 2, fill: muted }, g); return; }
554
+ const st = ST[level(v)], cell = paintRect(g, { fill: st.fill }, cx, cy, cw - 2, ch, 3);
555
+ text(g, format(v), { x: cx + (cw - 2) / 2, y: cy + ch / 2 + 4, 'text-anchor': 'middle', 'font-size': 12, 'font-weight': level(v) === 3 ? 600 : 400, fill: st.ink });
556
+ titled(cell, `${r.label}, ${dayText(cols[i])}: ${r.titles?.[i] || format(v) + ' against the minimum'}`, {});
557
+ });
558
+ });
559
+ s.setAttribute('aria-label', `Cover against the minimum for ${rows.length} rows across ${cols.length} days`);
560
+ };
561
+ draw(); watch(el, draw); settle(draw);
562
+ const seen = new Set(rows.flatMap((r) => r.values.filter((v) => v != null).map(level)));
563
+ const ST = styles();
564
+ const items = [0, 1, 2, 3].filter((l) => seen.has(l)).map((l) => ({ label: levels[l], w: 14, draw: rectSwatch(l === 0 ? { fill: ST[0].fill, stroke: ST[0].stroke } : { fill: ST[l].fill }, 14, 12, 3) }));
565
+ return { get svg() { return el.querySelector(':scope > svg'); }, legend: legendEl(items, legend) };
566
+ }
567
+ // When, within the day: one row per item on a shared open–close axis. A 2px grey track, an ink dot at today's time and
568
+ // a hollow tick at the comparison day's, so "earlier than last Sunday" is drawn and not only written.
569
+ // rows: [{ label: 'White sourdough', sub: 'Headingley', at: '11:20', compare: '12:05', value: '11:20', note: '3 h 40 m before close' }]
570
+ // at or compare may be null (it did not sell out); step: minutes between axis labels (60).
571
+ function timeStrip(el, rows, { open = '08:00', close = '18:00', step = 60, todayLabel = 'Today', compareLabel = null, labelWidth = null, valueWidth = null, rowHeight = null, legend = null } = {}) {
572
+ const o = minutes(open), c = minutes(close);
573
+ const st = { today: { r: 4.5 }, compare: { w: 5, h: 12 } };
574
+ const dot = (parent, cx, cy) => svg('circle', { cx, cy, r: st.today.r, fill: css(el, '--ink', '#111') }, parent);
575
+ const tick = (parent, cx, cy) => svg('rect', { x: cx - st.compare.w / 2, y: cy - st.compare.h / 2, width: st.compare.w, height: st.compare.h, rx: 2.5, fill: css(el, '--surface', '#fff'), stroke: css(el, '--axis-ink', '#6b6b6b'), 'stroke-width': 1.5 }, parent);
576
+ const draw = () => {
577
+ const narrow = (el.clientWidth || 600) < 560, axisH = 24;
578
+ const pitch = rowHeight || (narrow ? 62 : rows.some((r) => r.sub || r.note) ? 44 : 32);
579
+ const { s, w, h } = frame(el, rows.length * pitch + axisH);
580
+ const lw = narrow ? 0 : labelWidth || Math.round(Math.min(200, Math.max(110, w * 0.26)));
581
+ const vw = narrow ? 0 : valueWidth ?? Math.min(w * 0.32, Math.max(0, ...rows.map((r) => Math.max(r.value ? measure(s, r.value, 13, 500) : 0, r.note ? measure(s, r.note, 12) : 0))) + (rows.some((r) => r.value || r.note) ? 16 : 0));
582
+ const x0 = narrow ? 18 : lw + 6, x1 = narrow ? w - 18 : w - vw - 6, tx = (m) => x0 + ((m - o) / Math.max(1, c - o)) * (x1 - x0);
583
+ const ink = css(el, '--ink', '#111'), muted = css(el, '--axis-ink', '#6b6b6b'), rule = css(el, '--rule', '#f0f0f0');
584
+ const track = css(el, '--chart-track', mix(el, ink, css(el, '--surface', '#fff'), 0.16));
585
+ const g = svg('g', {}, s), plotH = rows.length * pitch;
586
+ // the axis: one step from the opening, the labels thinned by the same rule as the charts
587
+ const marks = []; for (let m = Math.ceil(o / step) * step; m <= c; m += step) marks.push(m);
588
+ const picks = xPicks(marks.map(fmt.clock), x1 - x0);
589
+ for (const i of picks) { const xx = tx(marks[i]); if (!narrow) svg('line', { x1: xx, x2: xx, y1: 0, y2: plotH, stroke: rule, 'stroke-width': 1, 'shape-rendering': 'crispEdges' }, g); const lab = fmt.clock(marks[i]), tw = measure(s, lab, 12); text(g, lab, { x: Math.max(x0 - 2, Math.min(x1 + 6 - tw, xx - tw / 2)), y: plotH + 17, 'font-size': 12, fill: muted }); }
590
+ rows.forEach((r, k) => {
591
+ const y0 = k * pitch, cy = narrow ? y0 + pitch - 12 : y0 + pitch / 2;
592
+ if (narrow) {
593
+ const vwid = r.value ? measure(s, r.value, 13, 500) + 12 : 0;
594
+ text(g, fit(s, r.label, w - vwid, 14), { x: 0, y: y0 + 16, 'font-size': 14, fill: ink });
595
+ if (r.value) text(g, r.value, { x: w, y: y0 + 16, 'text-anchor': 'end', 'font-size': 13, 'font-weight': 500, fill: ink });
596
+ const second = [r.sub, r.note].filter(Boolean).join(' \u00b7 ');
597
+ if (second) text(g, fit(s, second, w, 12), { x: 0, y: y0 + 33, 'font-size': 12, fill: muted });
598
+ } else rowLabel(g, s, el, r, { y0, pitch, lw });
599
+ svg('line', { x1: x0, x2: x1, y1: cy, y2: cy, stroke: track, 'stroke-width': 2, 'stroke-linecap': 'round' }, g);
600
+ const cm = minutes(r.compare), am = minutes(r.at);
601
+ if (cm != null) titled(tick(g, tx(cm), cy), `${compareLabel || 'Comparison'}: ${fmt.clock(cm)}`, {});
602
+ if (am != null) titled(dot(g, tx(am), cy), `${todayLabel}: ${fmt.clock(am)}`, {});
603
+ if (narrow) return;
604
+ if (r.note) { if (r.value) text(g, r.value, { x: w, y: cy - 3, 'text-anchor': 'end', 'font-size': 13, 'font-weight': 500, fill: ink }); text(g, fit(s, r.note, vw - 8, 12), { x: w, y: r.value ? cy + 13 : cy + 4, 'text-anchor': 'end', 'font-size': 12, fill: muted }); }
605
+ else if (r.value) text(g, r.value, { x: w, y: cy + 5, 'text-anchor': 'end', 'font-size': 13, 'font-weight': 500, fill: ink });
606
+ });
607
+ s.setAttribute('aria-label', `${rows.length} rows between ${fmt.clock(o)} and ${fmt.clock(c)}`);
608
+ };
609
+ draw(); watch(el, draw); settle(draw);
610
+ const items = [];
611
+ if (rows.some((r) => minutes(r.at) != null)) items.push({ label: todayLabel, w: 10, draw: (sw) => dot(sw, 5, 6) });
612
+ if (compareLabel && rows.some((r) => minutes(r.compare) != null)) items.push({ label: compareLabel, w: 8, draw: (sw) => tick(sw, 4, 6) });
613
+ return { get svg() { return el.querySelector(':scope > svg'); }, legend: legendEl(items, legend) };
614
+ }
615
+ function watch(el, draw) { if (!('ResizeObserver' in window)) return; let w = el.clientWidth; new ResizeObserver(() => { if (Math.abs(el.clientWidth - w) > 4) { w = el.clientWidth; draw(); } }).observe(el); }
616
+ window.Charts = { line, bars, diverging, ring, barList, plan, bullet, timeline, matrix, timeStrip, ticks, fmt };
617
+ })();