@supersoniks/concorde 5.1.1 → 5.1.3-immutable.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (459) hide show
  1. package/.agents/skills/concorde-docs/SKILL.md +153 -0
  2. package/.agents/skills/{concorde-component-docs/template.md → concorde-docs/templates/component.md} +6 -2
  3. package/.agents/skills/concorde-docs/templates/decorator.md +43 -0
  4. package/.agents/skills/concorde-docs/templates/guide.md +25 -0
  5. package/.claude/skills +1 -0
  6. package/.github/workflows/ci.yml +21 -0
  7. package/.github-export-ignore +30 -0
  8. package/CONTRIBUTING.md +59 -0
  9. package/DEV.md +54 -0
  10. package/LICENSE +21 -0
  11. package/OPEN_SOURCE_CHECKPOINT.md +133 -0
  12. package/README.md +4 -4
  13. package/ai/README.md +29 -41
  14. package/ai/skills/concorde/SKILL.md +54 -324
  15. package/ai/skills/concorde/rules/composition.md +32 -0
  16. package/ai/skills/concorde/rules/data.md +47 -0
  17. package/ai/skills/concorde/rules/http.md +25 -0
  18. package/ai/skills/concorde/rules/lists-forms.md +35 -0
  19. package/ai/skills/concorde/rules/styling.md +46 -0
  20. package/ai/skills/concorde/rules/troubleshooting.md +45 -0
  21. package/build-infos.json +1 -1
  22. package/concorde-core.bundle.js +177 -177
  23. package/concorde-core.es.js +4993 -4833
  24. package/custom-elements-manifest.public.config.mjs +8 -0
  25. package/{.tmp-cem/custom-elements.json → custom-elements.json} +11758 -8904
  26. package/dist/concorde-core.bundle.js +177 -177
  27. package/dist/concorde-core.es.js +4993 -4833
  28. package/dist/docs-mock-api-sw.js +58 -223
  29. package/dist/docs-mock-api-sw.js.map +4 -4
  30. package/dist/img/concorde/plane_01.jpg +0 -0
  31. package/dist/img/concorde/plane_02.jpg +0 -0
  32. package/dist/img/concorde/plane_03.jpg +0 -0
  33. package/dist/img/concorde/plane_04.jpg +0 -0
  34. package/dist/img/concorde/plane_05.jpg +0 -0
  35. package/dist/img/concorde/plane_06.jpg +0 -0
  36. package/dist/img/concorde/plane_07.jpg +0 -0
  37. package/dist/img/concorde/plane_08.jpg +0 -0
  38. package/dist/img/concorde/plane_09.jpg +0 -0
  39. package/dist/img/concorde/plane_10.jpg +0 -0
  40. package/dist/img/concorde/plane_11.jpg +0 -0
  41. package/dist/img/concorde/plane_12.jpg +0 -0
  42. package/dist/img/concorde/plane_13.jpg +0 -0
  43. package/dist/img/og-concorde.jpg +0 -0
  44. package/dist/robots.txt +11 -10
  45. package/docs/assets/index-D_alEsng.js +12122 -0
  46. package/docs/crawl/core/components/functional/date/date.html +190 -0
  47. package/docs/crawl/core/components/functional/fetch/fetch.html +109 -0
  48. package/docs/crawl/core/components/functional/if/if.html +27 -0
  49. package/docs/crawl/core/components/functional/jsonata/jsonata.html +79 -0
  50. package/docs/crawl/core/components/functional/list/list.html +70 -0
  51. package/docs/crawl/core/components/functional/mix/mix.html +45 -0
  52. package/docs/crawl/core/components/functional/queue/queue.html +96 -0
  53. package/docs/crawl/core/components/functional/router/router.html +106 -0
  54. package/docs/crawl/core/components/functional/sdui/sdui-extension-points.html +126 -0
  55. package/docs/crawl/core/components/functional/sdui/sdui.html +368 -0
  56. package/docs/crawl/core/components/functional/states/states.html +66 -0
  57. package/docs/crawl/core/components/functional/submit/submit.html +160 -0
  58. package/docs/crawl/core/components/functional/subscriber/subscriber.html +67 -0
  59. package/docs/crawl/core/components/functional/value/value.html +51 -0
  60. package/docs/crawl/core/components/ui/alert/alert.html +211 -0
  61. package/docs/crawl/core/components/ui/alert-messages/alert-messages.html +131 -0
  62. package/docs/crawl/core/components/ui/badge/badge.html +197 -0
  63. package/docs/crawl/core/components/ui/button/button.html +150 -0
  64. package/docs/crawl/core/components/ui/captcha/captcha.html +112 -0
  65. package/docs/crawl/core/components/ui/card/card.html +253 -0
  66. package/docs/crawl/core/components/ui/divider/divider.html +144 -0
  67. package/docs/crawl/core/components/ui/form/checkbox/checkbox.html +73 -0
  68. package/docs/crawl/core/components/ui/form/fieldset/fieldset.html +266 -0
  69. package/docs/crawl/core/components/ui/form/form-actions/form-actions.html +122 -0
  70. package/docs/crawl/core/components/ui/form/form-layout/form-layout.html +121 -0
  71. package/docs/crawl/core/components/ui/form/input/input.html +109 -0
  72. package/docs/crawl/core/components/ui/form/input-autocomplete/input-autocomplete.html +38 -0
  73. package/docs/crawl/core/components/ui/form/radio/radio.html +56 -0
  74. package/docs/crawl/core/components/ui/form/select/select.html +73 -0
  75. package/docs/crawl/core/components/ui/form/switch/switch.html +56 -0
  76. package/docs/crawl/core/components/ui/form/textarea/textarea.html +59 -0
  77. package/docs/crawl/core/components/ui/group/group.html +104 -0
  78. package/docs/crawl/core/components/ui/icon/icon.html +222 -0
  79. package/docs/crawl/core/components/ui/image/image.html +298 -0
  80. package/docs/crawl/core/components/ui/link/link.html +100 -0
  81. package/docs/crawl/core/components/ui/loader/loader.html +124 -0
  82. package/docs/crawl/core/components/ui/menu/menu.html +394 -0
  83. package/docs/crawl/core/components/ui/modal/modal.html +342 -0
  84. package/docs/crawl/core/components/ui/pop/pop.html +296 -0
  85. package/docs/crawl/core/components/ui/progress/progress.html +131 -0
  86. package/docs/crawl/core/components/ui/table/table.html +545 -0
  87. package/docs/crawl/core/components/ui/theme/theme.html +131 -0
  88. package/docs/crawl/core/components/ui/toast/toast.html +233 -0
  89. package/docs/crawl/core/components/ui/tooltip/tooltip.html +140 -0
  90. package/docs/crawl/docs/_core-concept/dataFlow.html +177 -0
  91. package/docs/crawl/docs/_core-concept/overview.html +66 -0
  92. package/docs/crawl/docs/_core-concept/subscriber.html +75 -0
  93. package/docs/crawl/docs/_decorators/ancestor-attribute.html +117 -0
  94. package/docs/crawl/docs/_decorators/auto-subscribe.html +202 -0
  95. package/docs/crawl/docs/_decorators/bind.html +141 -0
  96. package/docs/crawl/docs/_decorators/get.html +149 -0
  97. package/docs/crawl/docs/_decorators/handle.html +165 -0
  98. package/docs/crawl/docs/_decorators/on-assign.html +355 -0
  99. package/docs/crawl/docs/_decorators/patch.html +78 -0
  100. package/docs/crawl/docs/_decorators/post.html +139 -0
  101. package/docs/crawl/docs/_decorators/publish.html +61 -0
  102. package/docs/crawl/docs/_decorators/put.html +78 -0
  103. package/docs/crawl/docs/_decorators/subscribe.html +109 -0
  104. package/docs/crawl/docs/_decorators/wait-for-ancestors.html +137 -0
  105. package/docs/crawl/docs/_directives/sub.html +93 -0
  106. package/docs/crawl/docs/_getting-started/ai-agents.html +173 -0
  107. package/docs/crawl/docs/_getting-started/concorde-manual-install.html +100 -0
  108. package/docs/crawl/docs/_getting-started/concorde-outside.html +58 -0
  109. package/docs/crawl/docs/_getting-started/create-a-component.html +111 -0
  110. package/docs/crawl/docs/_getting-started/my-first-component.html +189 -0
  111. package/docs/crawl/docs/_getting-started/my-first-subscriber.html +110 -0
  112. package/docs/crawl/docs/_getting-started/pubsub.html +62 -0
  113. package/docs/crawl/docs/_getting-started/start.html +76 -0
  114. package/docs/crawl/docs/_getting-started/theming.html +333 -0
  115. package/docs/crawl/docs/_misc/api-configuration.html +149 -0
  116. package/docs/crawl/docs/_misc/dataProviderKey.html +135 -0
  117. package/docs/crawl/docs/_misc/docs-mock-api.html +158 -0
  118. package/docs/crawl/docs/_misc/dynamic-path.html +180 -0
  119. package/docs/crawl/docs/_misc/endpoint.html +50 -0
  120. package/docs/crawl/docs/_misc/formelement-subscriber-removal.html +138 -0
  121. package/docs/crawl/docs/_misc/html-integration.html +48 -0
  122. package/docs/crawl/hubs/decorators.html +547 -0
  123. package/docs/crawl/hubs/form-components.html +381 -0
  124. package/docs/crawl/hubs/remote-data.html +452 -0
  125. package/docs/crawl/index.html +103 -0
  126. package/docs/index.html +1 -1
  127. package/docs/llms-full.txt +7174 -0
  128. package/docs/llms.txt +98 -0
  129. package/docs/sitemap.xml +243 -0
  130. package/docs/src/core/components/functional/date/date.md +290 -0
  131. package/docs/src/core/components/functional/fetch/fetch.md +125 -0
  132. package/docs/src/core/components/functional/if/if.md +9 -0
  133. package/docs/src/core/components/functional/jsonata/jsonata.md +56 -0
  134. package/docs/src/core/components/functional/list/list.md +65 -0
  135. package/docs/src/core/components/functional/mix/mix.md +41 -0
  136. package/docs/src/core/components/functional/queue/queue.md +72 -0
  137. package/docs/src/core/components/functional/router/router.md +94 -0
  138. package/docs/src/core/components/functional/sdui/component-catalog.gaps.json +511 -0
  139. package/docs/src/core/components/functional/sdui/component-catalog.json +3103 -0
  140. package/docs/src/core/components/functional/sdui/default-library.json +108 -0
  141. package/docs/src/core/components/functional/sdui/example.json +99 -0
  142. package/docs/src/core/components/functional/sdui/sdui-extension-points.md +94 -0
  143. package/docs/src/core/components/functional/sdui/sdui.md +478 -0
  144. package/docs/src/core/components/functional/states/states.md +87 -0
  145. package/docs/src/core/components/functional/submit/submit.md +114 -0
  146. package/docs/src/core/components/functional/subscriber/subscriber.md +91 -0
  147. package/docs/src/core/components/functional/value/value.md +35 -0
  148. package/docs/src/core/components/ui/alert/alert.md +196 -0
  149. package/docs/src/core/components/ui/alert-messages/alert-messages.md +85 -0
  150. package/docs/src/core/components/ui/badge/badge.md +188 -0
  151. package/docs/src/core/components/ui/button/button.md +183 -0
  152. package/docs/src/core/components/ui/captcha/captcha.md +71 -0
  153. package/docs/src/core/components/ui/card/card.md +215 -0
  154. package/docs/src/core/components/ui/divider/divider.md +129 -0
  155. package/docs/src/core/components/ui/form/checkbox/checkbox.md +77 -0
  156. package/docs/src/core/components/ui/form/fieldset/fieldset.md +205 -0
  157. package/docs/src/core/components/ui/form/form-actions/form-actions.md +100 -0
  158. package/docs/src/core/components/ui/form/form-layout/form-layout.md +119 -0
  159. package/docs/src/core/components/ui/form/input/input.md +142 -0
  160. package/docs/src/core/components/ui/form/radio/radio.md +57 -0
  161. package/docs/src/core/components/ui/form/select/select.md +71 -0
  162. package/docs/src/core/components/ui/form/switch/switch.md +57 -0
  163. package/docs/src/core/components/ui/form/textarea/textarea.md +65 -0
  164. package/docs/src/core/components/ui/group/group.md +75 -0
  165. package/docs/src/core/components/ui/icon/icon.md +214 -0
  166. package/docs/src/core/components/ui/icon/icons.json +1 -0
  167. package/docs/src/core/components/ui/image/image.md +233 -0
  168. package/docs/src/core/components/ui/link/link.md +81 -0
  169. package/docs/src/core/components/ui/loader/loader.md +112 -0
  170. package/docs/src/core/components/ui/menu/menu.md +370 -0
  171. package/docs/src/core/components/ui/modal/modal.md +235 -0
  172. package/docs/src/core/components/ui/pop/pop.md +294 -0
  173. package/docs/src/core/components/ui/progress/progress.md +109 -0
  174. package/docs/src/core/components/ui/table/table.md +431 -0
  175. package/docs/src/core/components/ui/theme/theme.md +122 -0
  176. package/docs/src/core/components/ui/toast/toast.md +216 -0
  177. package/docs/src/core/components/ui/tooltip/tooltip.md +124 -0
  178. package/{src → docs/src}/docs/_core-concept/subscriber.md +0 -0
  179. package/{src → docs/src}/docs/_getting-started/my-first-subscriber.md +0 -0
  180. package/{src → docs/src}/docs/_getting-started/pubsub.md +0 -0
  181. package/docs/src/docs/_getting-started/theming.md +253 -0
  182. package/docs/src/docs/search/docs-search.json +12242 -0
  183. package/docs/src/tag-list.json +1 -0
  184. package/docs/src/tsconfig-model.json +23 -0
  185. package/docs/src/tsconfig.declarations.json +22 -0
  186. package/docs/src/tsconfig.emit.json +23 -0
  187. package/docs/src/tsconfig.json +1332 -0
  188. package/gitlab/job_github_mirror.sh +39 -0
  189. package/index.html +157 -5
  190. package/package.json +22 -4
  191. package/public/docs-mock-api-sw.js +58 -223
  192. package/public/docs-mock-api-sw.js.map +4 -4
  193. package/public/img/concorde/plane_01.jpg +0 -0
  194. package/public/img/concorde/plane_02.jpg +0 -0
  195. package/public/img/concorde/plane_03.jpg +0 -0
  196. package/public/img/concorde/plane_04.jpg +0 -0
  197. package/public/img/concorde/plane_05.jpg +0 -0
  198. package/public/img/concorde/plane_06.jpg +0 -0
  199. package/public/img/concorde/plane_07.jpg +0 -0
  200. package/public/img/concorde/plane_08.jpg +0 -0
  201. package/public/img/concorde/plane_09.jpg +0 -0
  202. package/public/img/concorde/plane_10.jpg +0 -0
  203. package/public/img/concorde/plane_11.jpg +0 -0
  204. package/public/img/concorde/plane_12.jpg +0 -0
  205. package/public/img/concorde/plane_13.jpg +0 -0
  206. package/public/img/og-concorde.jpg +0 -0
  207. package/public/robots.txt +11 -10
  208. package/scripts/ai-init.mjs +104 -379
  209. package/scripts/ai-init.test.mjs +81 -239
  210. package/scripts/docs-markdown-vite-plugin.ts +43 -0
  211. package/scripts/docs-public-url.mjs +56 -0
  212. package/scripts/docs.htaccess +82 -0
  213. package/scripts/generate-cem.mjs +244 -0
  214. package/scripts/generate-cem.test.mjs +122 -0
  215. package/scripts/generate-crawl-docs.mjs +233 -118
  216. package/scripts/generate-crawl-docs.test.mjs +124 -0
  217. package/scripts/generate-sdui-catalog.mjs +11 -10
  218. package/scripts/github-export.mjs +150 -0
  219. package/scripts/post-build-docs.js +37 -50
  220. package/scripts/post-build.mjs +0 -0
  221. package/scripts/pre-publish.mjs +2 -1
  222. package/scripts/site-pages.mjs +212 -0
  223. package/scripts/site-pages.test.mjs +116 -0
  224. package/site-pages/about.md +22 -0
  225. package/site-pages/privacy.md +32 -0
  226. package/src/core/components/functional/date/date.md +91 -231
  227. package/src/core/components/functional/example/example.ts +3 -1
  228. package/src/core/components/functional/fetch/fetch.md +66 -83
  229. package/src/core/components/functional/if/if.md +28 -3
  230. package/src/core/components/functional/if/if.ts +0 -0
  231. package/src/core/components/functional/jsonata/jsonata.md +42 -37
  232. package/src/core/components/functional/list/list.demo.ts +0 -0
  233. package/src/core/components/functional/list/list.md +103 -43
  234. package/src/core/components/functional/list/list.ts +17 -4
  235. package/src/core/components/functional/mix/mix.md +31 -26
  236. package/src/core/components/functional/queue/queue.demo.ts +10 -7
  237. package/src/core/components/functional/queue/queue.md +40 -61
  238. package/src/core/components/functional/router/router.demo.ts +16 -16
  239. package/src/core/components/functional/router/router.md +64 -65
  240. package/src/core/components/functional/router/router.ts +0 -0
  241. package/src/core/components/functional/sdui/SDUIDescriptorTransformer.ts +0 -0
  242. package/src/core/components/functional/sdui/component-catalog.gaps.json +1 -1
  243. package/src/core/components/functional/sdui/component-catalog.json +2 -2
  244. package/src/core/components/functional/sdui/example.json +19 -86
  245. package/src/core/components/functional/sdui/sdui-extension-points.md +1 -1
  246. package/src/core/components/functional/sdui/sdui-immutable.spec.ts +74 -0
  247. package/src/core/components/functional/sdui/sdui.md +187 -358
  248. package/src/core/components/functional/sdui/sdui.ts +33 -8
  249. package/src/core/components/functional/sdui/types.ts +0 -0
  250. package/src/core/components/functional/states/states.demo.ts +21 -22
  251. package/src/core/components/functional/states/states.md +86 -61
  252. package/src/core/components/functional/states/states.ts +1 -1
  253. package/src/core/components/functional/submit/submit.md +64 -72
  254. package/src/core/components/functional/submit/submit.spec.ts +60 -0
  255. package/src/core/components/functional/submit/submit.ts +6 -3
  256. package/src/core/components/functional/subscriber/subscriber.ts +0 -0
  257. package/src/core/components/functional/translation/translation.md +38 -0
  258. package/src/core/components/functional/value/value.md +34 -22
  259. package/src/core/components/functional/value/value.ts +0 -0
  260. package/src/core/components/ui/_css/size.ts +0 -0
  261. package/src/core/components/ui/alert/alert.md +48 -58
  262. package/src/core/components/ui/badge/badge.md +27 -34
  263. package/src/core/components/ui/button/button.md +139 -106
  264. package/src/core/components/ui/captcha/altchaStyles.ts +0 -0
  265. package/src/core/components/ui/captcha/captcha.md +17 -32
  266. package/src/core/components/ui/card/card.md +6 -6
  267. package/src/core/components/ui/divider/divider.md +8 -11
  268. package/src/core/components/ui/form/checkbox/checkbox.md +90 -42
  269. package/src/core/components/ui/form/fieldset/fieldset.md +31 -75
  270. package/src/core/components/ui/form/form-actions/form-actions.md +14 -16
  271. package/src/core/components/ui/form/form-layout/form-layout.md +19 -29
  272. package/src/core/components/ui/form/input/input.md +108 -90
  273. package/src/core/components/ui/form/input/input.ts +8 -2
  274. package/src/core/components/ui/form/radio/radio.md +65 -30
  275. package/src/core/components/ui/form/select/select.md +60 -45
  276. package/src/core/components/ui/form/switch/switch.md +57 -34
  277. package/src/core/components/ui/form/textarea/textarea.md +55 -38
  278. package/src/core/components/ui/group/group.md +35 -33
  279. package/src/core/components/ui/icon/icon.md +4 -4
  280. package/src/core/components/ui/image/image.md +41 -107
  281. package/src/core/components/ui/link/link.md +6 -6
  282. package/src/core/components/ui/loader/loader.md +30 -55
  283. package/src/core/components/ui/menu/menu.md +27 -27
  284. package/src/core/components/ui/modal/modal.md +72 -96
  285. package/src/core/components/ui/pop/pop.md +80 -158
  286. package/src/core/components/ui/progress/progress.md +2 -2
  287. package/src/core/components/ui/table/table.md +91 -255
  288. package/src/core/components/ui/theme/theme.md +11 -36
  289. package/src/core/components/ui/toast/toast.md +48 -117
  290. package/src/core/components/ui/tooltip/tooltip.md +27 -62
  291. package/src/core/decorators/subscriber/bind.ts +9 -14
  292. package/src/core/decorators/subscriber/subscribe.ts +15 -9
  293. package/src/core/decorators/subscriber/subscribe.type-test.ts +14 -5
  294. package/src/core/mixins/Subscriber.ts +0 -0
  295. package/src/core/utils/DataBindObserver.ts +0 -0
  296. package/src/core/utils/LocationHandler.spec.ts +80 -0
  297. package/src/core/utils/LocationHandler.ts +5 -9
  298. package/src/core/utils/Objects.ts +0 -0
  299. package/src/core/utils/PublisherProxy.ts +166 -125
  300. package/src/core/utils/deepReadonly.spec.ts +66 -0
  301. package/src/core/utils/deepReadonly.ts +71 -0
  302. package/src/core/utils/immutableValue.spec.ts +54 -0
  303. package/src/core/utils/immutableValue.ts +102 -0
  304. package/src/core/utils/nestedDotForm.spec.ts +88 -0
  305. package/src/core/utils/publisherImmutable.spec.ts +76 -0
  306. package/src/core/utils/route.ts +0 -0
  307. package/src/core/utils/strictGet.spec.ts +61 -0
  308. package/src/core/utils/strictGet.ts +102 -0
  309. package/src/css.d.ts +19 -0
  310. package/src/docs/components/docs-demo-sources.ts +55 -140
  311. package/src/docs/components/docs-lit-demo.ts +1 -3
  312. package/src/docs/components/docs-source-link.ts +0 -82
  313. package/src/docs/decorators/ancestor-attribute.md +59 -0
  314. package/src/docs/decorators/auto-subscribe.md +40 -0
  315. package/src/docs/decorators/bind.md +76 -0
  316. package/src/docs/decorators/get.md +160 -0
  317. package/src/docs/decorators/handle.md +119 -0
  318. package/src/docs/decorators/on-assign.md +63 -0
  319. package/src/docs/decorators/patch.md +44 -0
  320. package/src/docs/decorators/post.md +134 -0
  321. package/src/docs/decorators/publish.md +56 -0
  322. package/src/docs/decorators/put.md +51 -0
  323. package/src/docs/decorators/subscribe.md +87 -0
  324. package/src/docs/decorators/wait-for-ancestors.md +76 -0
  325. package/src/docs/directives/sub.md +75 -0
  326. package/src/docs/directives/t.md +73 -0
  327. package/src/docs/docs-location.spec.ts +56 -0
  328. package/src/docs/docs-location.ts +133 -32
  329. package/src/docs/docs.ts +1 -2
  330. package/src/docs/example/decorators-demo-bind-demos.ts +83 -135
  331. package/src/docs/example/decorators-demo-geo.ts +30 -19
  332. package/src/docs/example/decorators-demo-post.ts +88 -186
  333. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +165 -268
  334. package/src/docs/example/decorators-demo.ts +85 -98
  335. package/src/docs/example/docs-api-config-demos.ts +19 -20
  336. package/src/docs/example/docs-flight-demos.ts +147 -0
  337. package/src/docs/example/docs-jsonata-demos.ts +52 -52
  338. package/src/docs/example/docs-list-demos.ts +43 -123
  339. package/src/docs/example/docs-provider-keys.ts +21 -28
  340. package/src/docs/example/docs-queue-demos.ts +37 -77
  341. package/src/docs/example/docs-router-demos.ts +20 -25
  342. package/src/docs/example/docs-submit-demos.ts +48 -48
  343. package/src/docs/example/docs-toggle-demos.ts +4 -3
  344. package/src/docs/example/users.ts +0 -0
  345. package/src/docs/getting-started/ai-agents.md +50 -0
  346. package/src/docs/getting-started/create-a-component.md +136 -0
  347. package/src/docs/getting-started/dataFlow.md +87 -0
  348. package/src/docs/getting-started/installation.md +36 -0
  349. package/src/docs/getting-started/my-first-component.md +227 -0
  350. package/src/docs/getting-started/start.md +35 -0
  351. package/src/docs/header/header.ts +11 -6
  352. package/src/docs/home/catalog.ts +1 -1
  353. package/src/docs/home/home.ts +20 -11
  354. package/src/docs/layout.ts +12 -13
  355. package/src/docs/misc/api-configuration.md +79 -0
  356. package/src/docs/misc/dataProviderKey.md +168 -0
  357. package/src/docs/misc/docs-mock-api.md +62 -0
  358. package/src/docs/misc/dynamic-path.md +71 -0
  359. package/src/docs/misc/endpoint.md +45 -0
  360. package/src/docs/misc/html-integration.md +14 -0
  361. package/src/docs/misc/publisher-get-immutability-docs-crawl.json +902 -0
  362. package/src/docs/misc/publisher-get-immutability-docs-recheck.json +13 -0
  363. package/src/docs/misc/publisher-get-immutability-study.md +229 -0
  364. package/src/docs/mock-api/api-config-mock.ts +5 -0
  365. package/src/docs/mock-api/fixtures.ts +0 -278
  366. package/src/docs/mock-api/flights.ts +89 -0
  367. package/src/docs/mock-api/router.ts +3 -4
  368. package/src/docs/mock-api/urls.ts +1 -2
  369. package/src/docs/navigation/navigation.ts +84 -101
  370. package/src/docs/navigation/toc.ts +7 -4
  371. package/src/docs/search/docs-search.json +3188 -5153
  372. package/src/docs/search/markdown-renderer.ts +31 -8
  373. package/src/docs/search/page.ts +9 -6
  374. package/src/docs/search/search.ts +154 -122
  375. package/src/docs/tailwind/css/docs/content.css +4 -5
  376. package/src/tsconfig.declarations.json +22 -0
  377. package/src/tsconfig.emit.json +23 -0
  378. package/src/tsconfig.json +53 -5
  379. package/src/tsconfig.tsbuildinfo +1 -1
  380. package/vite.config.mts +11 -2
  381. package/.agents/skills/concorde-component-docs/SKILL.md +0 -194
  382. package/.taste-skill/after/desktop-fold.jpg +0 -0
  383. package/.taste-skill/after/desktop-page-01.jpg +0 -0
  384. package/.taste-skill/after/desktop-page-02.jpg +0 -0
  385. package/.taste-skill/after/desktop-page-03.jpg +0 -0
  386. package/.taste-skill/after/mobile-fold.jpg +0 -0
  387. package/.taste-skill/after/mobile-page-01.jpg +0 -0
  388. package/.taste-skill/after/report.json +0 -4103
  389. package/.taste-skill/after/tablet-fold.jpg +0 -0
  390. package/.taste-skill/after/tablet-page-01.jpg +0 -0
  391. package/.taste-skill/after/tablet-page-02.jpg +0 -0
  392. package/.taste-skill/before/desktop-fold.jpg +0 -0
  393. package/.taste-skill/before/desktop-page-01.jpg +0 -0
  394. package/.taste-skill/before/desktop-page-02.jpg +0 -0
  395. package/.taste-skill/before/mobile-fold.jpg +0 -0
  396. package/.taste-skill/before/mobile-page-01.jpg +0 -0
  397. package/.taste-skill/before/report.json +0 -2556
  398. package/.taste-skill/before/tablet-fold.jpg +0 -0
  399. package/.taste-skill/before/tablet-page-01.jpg +0 -0
  400. package/.taste-skill/direction.json +0 -510
  401. package/.taste-skill/notes.md +0 -84
  402. package/.taste-skill/prod/desktop-fold.jpg +0 -0
  403. package/.taste-skill/prod/desktop-page-01.jpg +0 -0
  404. package/.taste-skill/prod/desktop-page-02.jpg +0 -0
  405. package/.taste-skill/prod/desktop-page-03.jpg +0 -0
  406. package/.taste-skill/prod/mobile-fold.jpg +0 -0
  407. package/.taste-skill/prod/mobile-page-01.jpg +0 -0
  408. package/.taste-skill/prod/mobile-page-02.jpg +0 -0
  409. package/.taste-skill/prod/report.json +0 -1973
  410. package/.taste-skill/prod/tablet-fold.jpg +0 -0
  411. package/.taste-skill/prod/tablet-page-01.jpg +0 -0
  412. package/.taste-skill/prod/tablet-page-02.jpg +0 -0
  413. package/AUDIT.md +0 -228
  414. package/PLAN-AMELIORATION.md +0 -220
  415. package/ai/AGENTS.md +0 -56
  416. package/ai/cursor/rules/concorde-menu.mdc +0 -15
  417. package/ai/cursor/rules/concorde-scope.mdc +0 -14
  418. package/ai/cursor/rules/concorde-theme.mdc +0 -13
  419. package/ai/cursor/rules/concorde.mdc +0 -66
  420. package/ai/jetbrains/rules/concorde.md +0 -53
  421. package/ai/skills/concorde-get-set-dp/SKILL.md +0 -194
  422. package/ai/skills/concorde-imports/SKILL.md +0 -78
  423. package/ai/skills/concorde-menu/SKILL.md +0 -74
  424. package/ai/skills/concorde-scope/SKILL.md +0 -70
  425. package/ai/skills/concorde-theme/SKILL.md +0 -57
  426. package/docs/assets/index-Bb-_LRyY.js +0 -12280
  427. package/src/docs/example/docs-input-autocomplete-demos.ts +0 -110
  428. package/src/docs/example/docs-joke-demos.ts +0 -297
  429. /package/{src → docs/src}/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -0
  430. /package/{src → docs/src}/docs/_core-concept/dataFlow.md +0 -0
  431. /package/{src → docs/src}/docs/_core-concept/overview.md +0 -0
  432. /package/{src → docs/src}/docs/_decorators/ancestor-attribute.md +0 -0
  433. /package/{src → docs/src}/docs/_decorators/auto-subscribe.md +0 -0
  434. /package/{src → docs/src}/docs/_decorators/bind.md +0 -0
  435. /package/{src → docs/src}/docs/_decorators/get.md +0 -0
  436. /package/{src → docs/src}/docs/_decorators/handle.md +0 -0
  437. /package/{src → docs/src}/docs/_decorators/on-assign.md +0 -0
  438. /package/{src → docs/src}/docs/_decorators/patch.md +0 -0
  439. /package/{src → docs/src}/docs/_decorators/post.md +0 -0
  440. /package/{src → docs/src}/docs/_decorators/publish.md +0 -0
  441. /package/{src → docs/src}/docs/_decorators/put.md +0 -0
  442. /package/{src → docs/src}/docs/_decorators/subscribe.md +0 -0
  443. /package/{src → docs/src}/docs/_decorators/wait-for-ancestors.md +0 -0
  444. /package/{src → docs/src}/docs/_directives/sub.md +0 -0
  445. /package/{src → docs/src}/docs/_getting-started/ai-agents.md +0 -0
  446. /package/{src → docs/src}/docs/_getting-started/concorde-manual-install.md +0 -0
  447. /package/{src → docs/src}/docs/_getting-started/concorde-outside.md +0 -0
  448. /package/{src → docs/src}/docs/_getting-started/create-a-component.md +0 -0
  449. /package/{src → docs/src}/docs/_getting-started/my-first-component.md +0 -0
  450. /package/{src → docs/src}/docs/_getting-started/start.md +0 -0
  451. /package/{src → docs/src}/docs/_misc/api-configuration.md +0 -0
  452. /package/{src → docs/src}/docs/_misc/dataProviderKey.md +0 -0
  453. /package/{src → docs/src}/docs/_misc/docs-mock-api.md +0 -0
  454. /package/{src → docs/src}/docs/_misc/dynamic-path.md +0 -0
  455. /package/{src → docs/src}/docs/_misc/endpoint.md +0 -0
  456. /package/{src → docs/src}/docs/_misc/formelement-subscriber-removal.md +0 -0
  457. /package/{src → docs/src}/docs/_misc/html-integration.md +0 -0
  458. /package/src/docs/{_getting-started → getting-started}/components.md +0 -0
  459. /package/src/docs/{_getting-started → getting-started}/theming.md +0 -0
@@ -3,257 +3,99 @@ import fs from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
5
  import test from "node:test";
6
- import {
7
- buildAgentsFile,
8
- decideAgentsAction,
9
- preambleDuplicatesBase,
10
- readOverlayAgents,
11
- slimPreamble,
12
- } from "./ai-init.mjs";
6
+ import {SKILLS_DIR, linkSkills, syncSkills} from "./ai-init.mjs";
13
7
 
14
- const base = `# Agents — Concorde
8
+ async function makeSkill(dir, name, body = "x") {
9
+ await fs.mkdir(path.join(dir, name), {recursive: true});
10
+ await fs.writeFile(path.join(dir, name, "SKILL.md"), `---\nname: ${name}\n---\n${body}\n`);
11
+ }
15
12
 
16
- Guide for Concorde.
17
-
18
- ## Skills / rules
19
-
20
- | File | Role |
21
- |------|------|
22
- | \`.cursor/skills/concorde/SKILL.md\` | Patterns |
23
-
24
- ## Conventions impératives
25
-
26
- - Always **DataProvider**
27
- - No **sonic-fetch**, no **PublisherManager**
28
- - Forms: **formDataProvider**
29
- - Skill **concorde-get-set-dp**
30
- `;
31
-
32
- const overlay = `## Conventions (project)
33
-
34
- - HTTP routes: \`endpoints.*\`
35
- `;
36
-
37
- test("decideAgentsAction: missing file → create", () => {
38
- assert.equal(decideAgentsAction({existingText: ""}), "create");
39
- });
40
-
41
- test("decideAgentsAction: project-owned AGENTS.md → skip by default", () => {
42
- assert.equal(
43
- decideAgentsAction({existingText: "# Billetterie\n\nProject notes.\n"}),
44
- "skip",
45
- );
46
- });
47
-
48
- test("decideAgentsAction: --skip-agents always skips", () => {
49
- assert.equal(
50
- decideAgentsAction({existingText: "", skipAgents: true}),
51
- "skip",
52
- );
53
- });
54
-
55
- test("decideAgentsAction: --merge-agents on project-owned → merge", () => {
56
- assert.equal(
57
- decideAgentsAction({
58
- existingText: "# Billetterie\n\nNotes.\n",
59
- mergeAgents: true,
60
- }),
61
- "merge",
62
- );
63
- });
64
-
65
- test("decideAgentsAction: --force-agents on project-owned → force", () => {
66
- assert.equal(
67
- decideAgentsAction({
68
- existingText: "# Billetterie\n\nNotes.\n",
69
- forceAgents: true,
70
- }),
71
- "force",
72
- );
73
- });
74
-
75
- test("decideAgentsAction: marked file → refresh", () => {
76
- assert.equal(
77
- decideAgentsAction({
78
- existingText: "# App\n\n<!-- concorde-ai -->\n\nold\n",
79
- }),
80
- "refresh",
81
- );
82
- });
83
-
84
- test("forceAgents replaces project-owned content", () => {
85
- const {markdown} = buildAgentsFile({
86
- existing: "# Old project notes\n\nkeep me",
87
- baseContent: base,
88
- overlayContent: "",
89
- forceAgents: true,
13
+ async function withProject(fn) {
14
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), "concorde-skills-"));
15
+ try {
16
+ await fn(root);
17
+ } finally {
18
+ await fs.rm(root, {recursive: true, force: true});
19
+ }
20
+ }
21
+
22
+ test("syncSkills copies a skill with its rules/ folder into .agents/skills", async () => {
23
+ await withProject(async (root) => {
24
+ const pkg = path.join(root, "pkg");
25
+ await makeSkill(pkg, "concorde");
26
+ await fs.mkdir(path.join(pkg, "concorde", "rules"));
27
+ await fs.writeFile(path.join(pkg, "concorde", "rules", "data.md"), "# Data\n");
28
+ assert.deepEqual(syncSkills(path.join(root, "app"), [pkg]), ["concorde"]);
29
+ const rule = path.join(root, "app", SKILLS_DIR, "concorde", "rules", "data.md");
30
+ assert.equal(await fs.readFile(rule, "utf8"), "# Data\n");
90
31
  });
91
- assert.equal(markdown.includes("keep me"), false);
92
- assert.equal(markdown.includes("<!-- concorde-ai -->"), false);
93
- assert.match(markdown, /^# Agents — Concorde/m);
94
32
  });
95
33
 
96
- test("without force/merge, buildAgentsFile still builds content (caller decides skip)", () => {
97
- const {markdown} = buildAgentsFile({
98
- existing: "",
99
- baseContent: base,
100
- overlayContent: "",
34
+ test("syncSkills replaces its own skill and keeps project skills", async () => {
35
+ await withProject(async (root) => {
36
+ const pkg = path.join(root, "pkg");
37
+ const app = path.join(root, "app");
38
+ const installed = path.join(app, SKILLS_DIR);
39
+ await makeSkill(pkg, "concorde");
40
+ await makeSkill(installed, "concorde", "old copy");
41
+ await makeSkill(installed, "concorde-docs", "project");
42
+ syncSkills(app, [pkg]);
43
+ assert.deepEqual((await fs.readdir(installed)).sort(), ["concorde", "concorde-docs"]);
44
+ assert.doesNotMatch(
45
+ await fs.readFile(path.join(installed, "concorde", "SKILL.md"), "utf8"),
46
+ /old copy/,
47
+ );
48
+ assert.match(
49
+ await fs.readFile(path.join(installed, "concorde-docs", "SKILL.md"), "utf8"),
50
+ /project/,
51
+ );
101
52
  });
102
- assert.match(markdown, /^# Agents — Concorde/m);
103
53
  });
104
54
 
105
- test("merge without marker keeps short unique preamble", () => {
106
- const {markdown, warnings} = buildAgentsFile({
107
- existing: "# My app\n\nOnly project notes here.\n",
108
- baseContent: base,
109
- overlayContent: "",
110
- mergeAgents: true,
55
+ test("linkSkills links each skill from .claude and .junie", async () => {
56
+ await withProject(async (root) => {
57
+ await makeSkill(path.join(root, SKILLS_DIR), "concorde");
58
+ const results = linkSkills(root, ["concorde"]);
59
+ assert.deepEqual(
60
+ results.map((r) => r.mode),
61
+ ["linked", "linked"],
62
+ );
63
+ for (const dir of [".claude/skills", ".junie/skills"]) {
64
+ const link = path.join(root, dir, "concorde");
65
+ assert.ok((await fs.lstat(link)).isSymbolicLink(), `${dir} not a symlink`);
66
+ assert.equal(await fs.readlink(link), path.join("..", "..", SKILLS_DIR, "concorde"));
67
+ assert.match(await fs.readFile(path.join(link, "SKILL.md"), "utf8"), /concorde/);
68
+ }
111
69
  });
112
- assert.match(markdown, /# My app/);
113
- assert.match(markdown, /<!-- concorde-ai -->/);
114
- assert.match(markdown, /# Agents — Concorde/);
115
- assert.equal(warnings.length, 0);
116
70
  });
117
71
 
118
- test("re-run with marker replaces managed zone only (idempotent)", () => {
119
- const first = buildAgentsFile({
120
- existing: "# My app\n\nNote.\n",
121
- baseContent: base,
122
- overlayContent: "v1 overlay",
123
- mergeAgents: true,
124
- }).markdown;
125
-
126
- const second = buildAgentsFile({
127
- existing: first.replace("v1 overlay", "STALE"),
128
- baseContent: base,
129
- overlayContent: "v2 overlay",
130
- mergeAgents: true,
131
- }).markdown;
132
-
133
- assert.equal(second.includes("STALE"), false);
134
- assert.match(second, /v2 overlay/);
135
- assert.equal(second.split("<!-- concorde-ai -->").length, 2);
136
- });
137
-
138
- test("duplicate Concorde preamble is dropped", () => {
139
- const fork = `${base}\n\nExtra copy of the same guide.\n`;
140
- assert.equal(preambleDuplicatesBase(fork, base), true);
141
-
142
- const {markdown, warnings} = buildAgentsFile({
143
- existing: `${fork}\n\n<!-- concorde-ai -->\n\nold managed\n`,
144
- baseContent: base,
145
- overlayContent: overlay,
146
- mergeAgents: true,
72
+ test("linkSkills keeps project skills and whole-folder links", async () => {
73
+ await withProject(async (root) => {
74
+ await makeSkill(path.join(root, SKILLS_DIR), "concorde");
75
+ await makeSkill(path.join(root, SKILLS_DIR), "my-skill");
76
+ // .claude/skills is already a symlink to .agents/skills (this repo's layout)
77
+ await fs.mkdir(path.join(root, ".claude"), {recursive: true});
78
+ await fs.symlink(path.join("..", SKILLS_DIR), path.join(root, ".claude/skills"));
79
+ // .junie has its own skill with the same name as an overlay skill
80
+ await makeSkill(path.join(root, ".junie/skills"), "my-skill", "junie own");
81
+
82
+ const results = linkSkills(root, ["concorde", "my-skill"], {packageNames: ["concorde"]});
83
+ assert.equal(results.find((r) => r.dir === ".claude/skills").mode, "shared");
84
+ assert.ok((await fs.lstat(path.join(root, ".claude/skills"))).isSymbolicLink());
85
+ const own = path.join(root, ".junie/skills/my-skill");
86
+ assert.ok(!(await fs.lstat(own)).isSymbolicLink());
87
+ assert.match(await fs.readFile(path.join(own, "SKILL.md"), "utf8"), /junie own/);
88
+ assert.ok((await fs.lstat(path.join(root, ".junie/skills/concorde"))).isSymbolicLink());
147
89
  });
148
-
149
- assert.equal(markdown.split("<!-- concorde-ai -->").length, 2);
150
- assert.equal(
151
- markdown.indexOf("# Agents — Concorde"),
152
- markdown.lastIndexOf("# Agents — Concorde"),
153
- );
154
- assert.match(markdown, /Conventions \(project\)/);
155
- assert.ok(warnings.some((w) => /duplicated|slimmed/i.test(w)));
156
- });
157
-
158
- test("slimPreamble keeps unique ## sections", () => {
159
- const preamble = `# Agents — Concorde (my-app)
160
-
161
- Guide.
162
-
163
- ## Skills / rules
164
-
165
- dup
166
-
167
- ## Project only
168
-
169
- - use endpoints.ts
170
- `;
171
- const slim = slimPreamble(preamble, base);
172
- assert.match(slim, /Project only/);
173
- assert.equal(slim.includes("## Skills / rules"), false);
174
- assert.match(slim, /Concorde \(my-app\)/);
175
- });
176
-
177
- test("slimPreamble drops Skills even when package title has suffix", () => {
178
- const packageBase = `# Agents — Concorde
179
-
180
- ## Skills / rules (après installation)
181
-
182
- table
183
-
184
- ## Conventions impératives
185
-
186
- - sonic-fetch
187
- - PublisherManager
188
- - formDataProvider
189
- - concorde-get-set-dp
190
- `;
191
- const preamble = `# Agents — Concorde (app)
192
-
193
- ## Skills / rules
194
-
195
- dup table
196
-
197
- ## Installation / réinstallation
198
-
199
- custom install cmd
200
-
201
- ## Project endpoints
202
-
203
- - endpoints.ts
204
- `;
205
- const slim = slimPreamble(preamble, packageBase);
206
- assert.equal(slim.includes("## Skills / rules"), false);
207
- assert.match(slim, /Project endpoints/);
208
- // Installation may stay if not in package — package has no Installation ##
209
- assert.match(slim, /Installation \/ réinstallation|Project endpoints/);
210
- });
211
-
212
- test("readOverlayAgents: prefers AGENTS.concorde.md", async () => {
213
- const dir = await fs.mkdtemp(path.join(os.tmpdir(), "concorde-overlay-"));
214
- try {
215
- await fs.writeFile(
216
- path.join(dir, "AGENTS.concorde.md"),
217
- "# overlay preferred\n",
218
- );
219
- await fs.writeFile(
220
- path.join(dir, "AGENTS.starter.md"),
221
- "# overlay legacy\n",
222
- );
223
- const {content, warnings} = readOverlayAgents(dir);
224
- assert.match(content, /overlay preferred/);
225
- assert.equal(warnings.length, 0);
226
- } finally {
227
- await fs.rm(dir, {recursive: true, force: true});
228
- }
229
90
  });
230
91
 
231
- test("readOverlayAgents: falls back to AGENTS.starter.md with warning", async () => {
232
- const dir = await fs.mkdtemp(path.join(os.tmpdir(), "concorde-overlay-"));
233
- try {
234
- await fs.writeFile(
235
- path.join(dir, "AGENTS.starter.md"),
236
- "# overlay legacy\n",
237
- );
238
- const {content, warnings} = readOverlayAgents(dir);
239
- assert.match(content, /overlay legacy/);
240
- assert.match(warnings[0] ?? "", /deprecated AGENTS\.starter\.md/);
241
- } finally {
242
- await fs.rm(dir, {recursive: true, force: true});
243
- }
244
- });
245
-
246
- test("readOverlayAgents: falls back to AGENTS.overlay.md with warning", async () => {
247
- const dir = await fs.mkdtemp(path.join(os.tmpdir(), "concorde-overlay-"));
248
- try {
249
- await fs.writeFile(
250
- path.join(dir, "AGENTS.overlay.md"),
251
- "# overlay mid legacy\n",
252
- );
253
- const {content, warnings} = readOverlayAgents(dir);
254
- assert.match(content, /overlay mid legacy/);
255
- assert.match(warnings[0] ?? "", /deprecated AGENTS\.overlay\.md/);
256
- } finally {
257
- await fs.rm(dir, {recursive: true, force: true});
258
- }
92
+ test("linkSkills replaces an earlier copy of a package skill", async () => {
93
+ await withProject(async (root) => {
94
+ await makeSkill(path.join(root, SKILLS_DIR), "concorde", "new");
95
+ await makeSkill(path.join(root, ".junie/skills"), "concorde", "copied before");
96
+ linkSkills(root, ["concorde"], {packageNames: ["concorde"]});
97
+ const link = path.join(root, ".junie/skills/concorde");
98
+ assert.ok((await fs.lstat(link)).isSymbolicLink());
99
+ assert.match(await fs.readFile(path.join(link, "SKILL.md"), "utf8"), /new/);
100
+ });
259
101
  });
@@ -0,0 +1,43 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ import type { Connect, Plugin } from "vite";
5
+ import { SITE_PAGE_SLUGS, toSourceId } from "./docs-public-url.mjs";
6
+
7
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
8
+ const MD_PATH_RE = /^\/((?:docs|core)\/.+\.mdx?)(?:\?|$)/i;
9
+ const SITE_PAGE_MD_RE = new RegExp(
10
+ `^/(${SITE_PAGE_SLUGS.join("|")})\\.md(?:\\?|$)`,
11
+ );
12
+
13
+ /**
14
+ * Dev: serve public `/docs|core/…/*.md` from `src/…` (including underscore
15
+ * sections and `name/name.md` component pages), and `/about.md` & co. from
16
+ * `site-pages/`.
17
+ */
18
+ export function docsMarkdownVitePlugin(): Plugin {
19
+ return {
20
+ name: "concorde-docs-markdown",
21
+ configureServer(server) {
22
+ server.middlewares.use(((req, res, next) => {
23
+ const raw = req.url || "";
24
+ const sitePage = SITE_PAGE_MD_RE.exec(raw);
25
+ const match = MD_PATH_RE.exec(raw);
26
+ if (!match && !sitePage) {
27
+ next();
28
+ return;
29
+ }
30
+ const filePath = sitePage
31
+ ? path.join(root, "site-pages", `${sitePage[1]}.md`)
32
+ : path.join(root, "src", `${toSourceId(match![1])}.md`);
33
+ if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
34
+ next();
35
+ return;
36
+ }
37
+ res.statusCode = 200;
38
+ res.setHeader("Content-Type", "text/markdown; charset=utf-8");
39
+ fs.createReadStream(filePath).pipe(res);
40
+ }) as Connect.NextHandleFunction);
41
+ },
42
+ };
43
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Public doc URL ↔ source markdown path (under src/).
3
+ *
4
+ * Docs sections are 1:1 with the public path:
5
+ * /docs/getting-started/start ↔ docs/getting-started/start.md
6
+ *
7
+ * Components collapse the trailing duplicate folder/file name:
8
+ * /core/components/ui/button ↔ core/components/ui/button/button.md
9
+ */
10
+
11
+ /**
12
+ * Component markdown whose basename ≠ parent folder (not collapsed in public URLs).
13
+ * Keep in sync with `find src/core/components -name '*.md'` where dirname ≠ basename.
14
+ */
15
+ export const COMPONENT_MD_EXCEPTIONS = new Set([
16
+ "core/components/functional/sdui/sdui-extension-points",
17
+ ]);
18
+
19
+ /**
20
+ * Root-level site pages (`/about` ↔ `site-pages/about.md`, published as
21
+ * `/about.md`). Kept outside src/ so they stay out of doc nav and search.
22
+ */
23
+ export const SITE_PAGE_SLUGS = ["about", "privacy"];
24
+
25
+ /** Strip leading slash and optional .md/.mdx */
26
+ export function stripMd(rel) {
27
+ return rel.replace(/^\//, "").replace(/\.mdx?$/i, "");
28
+ }
29
+
30
+ /** Source-relative id (may include …/name/name for components). */
31
+ export function toSourceId(relOrPublic) {
32
+ let p = stripMd(relOrPublic);
33
+
34
+ if (p.startsWith("core/components/") && !COMPONENT_MD_EXCEPTIONS.has(p)) {
35
+ const parts = p.split("/");
36
+ const last = parts[parts.length - 1];
37
+ if (parts.length >= 2 && parts[parts.length - 2] !== last) {
38
+ p = `${p}/${last}`;
39
+ }
40
+ }
41
+
42
+ return p;
43
+ }
44
+
45
+ /** Public pathname (leading slash, no .md). */
46
+ export function toPublicPath(mdRel) {
47
+ let p = stripMd(mdRel);
48
+ // …/name/name → …/name (component index pages)
49
+ p = p.replace(/\/([^/]+)\/\1$/, "/$1");
50
+ return `/${p}`;
51
+ }
52
+
53
+ /** Public path + .md for agent / SPA fetch URL path (no leading slash). */
54
+ export function toPublicMdRel(mdRel) {
55
+ return `${toPublicPath(mdRel).slice(1)}.md`;
56
+ }
@@ -0,0 +1,82 @@
1
+ # Concorde docs — pathname SPA + agent Markdown/HTML
2
+ # Public paths match on-disk docs/… ; components collapse …/name → …/name/name.(md|html)
3
+ # See https://acceptmarkdown.com/recipes/apache (Option A, pragmatic)
4
+
5
+ DirectoryIndex index.html
6
+ # Component folders exist on disk (…/button/button.md); do not force a trailing
7
+ # slash on the pretty URL /…/button (that would break SPA + Accept negotiation).
8
+ DirectorySlash Off
9
+
10
+ RewriteEngine On
11
+
12
+ # Pretty component URLs: drop a trailing slash if the client added one
13
+ RewriteRule ^(core/components/.+)/$ /$1 [R=301,L]
14
+
15
+ # Homepage: Accept: text/markdown → index.md
16
+ RewriteCond %{HTTP:Accept} "text/markdown" [NC]
17
+ RewriteCond %{HTTP:Accept} !"text/markdown\s*;\s*q\s*=\s*0(\.0+)?(\s*,|$)" [NC]
18
+ RewriteRule ^/?$ index.md [END]
19
+
20
+ # --- Site pages: /about, /privacy (SPA shell with inline content + .md) ---
21
+ RewriteRule ^(about|privacy)/$ /$1 [R=301,L]
22
+ RewriteCond %{HTTP:Accept} "text/markdown" [NC]
23
+ RewriteCond %{HTTP:Accept} !"text/markdown\s*;\s*q\s*=\s*0(\.0+)?(\s*,|$)" [NC]
24
+ RewriteRule ^(about|privacy)$ /$1.md [END]
25
+ RewriteRule ^(about|privacy)$ /$1.html [END]
26
+
27
+ # --- Components: /…/button(.md|.html) → /…/button/button.(md|html) ---
28
+ RewriteCond %{DOCUMENT_ROOT}/$1/$2/$2.md -f
29
+ RewriteRule ^(core/components/.+)/([^/]+)\.md$ /$1/$2/$2.md [END]
30
+ RewriteCond %{DOCUMENT_ROOT}/$1/$2/$2.html -f
31
+ RewriteRule ^(core/components/.+)/([^/]+)\.html$ /$1/$2/$2.html [END]
32
+
33
+ # --- Accept: text/markdown → sibling .md (docs paths are 1:1; components collapse) ---
34
+ RewriteCond %{REQUEST_URI} !\.(mdx?|html)$ [NC]
35
+ RewriteCond %{HTTP:Accept} "text/markdown" [NC]
36
+ RewriteCond %{HTTP:Accept} !"text/markdown\s*;\s*q\s*=\s*0(\.0+)?(\s*,|$)" [NC]
37
+ RewriteCond %{DOCUMENT_ROOT}/$1/$2/$2.md -f
38
+ RewriteRule ^(core/components/.+)/([^/]+)$ /$1/$2/$2.md [END]
39
+
40
+ RewriteCond %{REQUEST_URI} !\.(mdx?|html)$ [NC]
41
+ RewriteCond %{HTTP:Accept} "text/markdown" [NC]
42
+ RewriteCond %{HTTP:Accept} !"text/markdown\s*;\s*q\s*=\s*0(\.0+)?(\s*,|$)" [NC]
43
+ RewriteCond %{DOCUMENT_ROOT}/$1.md -f
44
+ RewriteRule ^((?:docs|core)/.+)$ /$1.md [END]
45
+
46
+ # --- Known crawlers → static HTML ---
47
+ RewriteCond %{REQUEST_URI} !\.(mdx?|html)$ [NC]
48
+ RewriteCond %{HTTP_USER_AGENT} (bot|crawler|spider|slurp|GPTBot|Claude|anthropic|Bytespider|Applebot|bingbot|Googlebot|DuckDuckBot|YandexBot|Baiduspider|facebookexternalhit|LinkedInBot|Twitterbot|SemrushBot|AhrefsBot|PetalBot|CCBot|meta-externalagent|OAI-SearchBot|Perplexity|Diffbot|ia_archiver) [NC]
49
+ RewriteCond %{DOCUMENT_ROOT}/$1/$2/$2.html -f
50
+ RewriteRule ^(core/components/.+)/([^/]+)$ /$1/$2/$2.html [END]
51
+
52
+ RewriteCond %{REQUEST_URI} !\.(mdx?|html)$ [NC]
53
+ RewriteCond %{HTTP_USER_AGENT} (bot|crawler|spider|slurp|GPTBot|Claude|anthropic|Bytespider|Applebot|bingbot|Googlebot|DuckDuckBot|YandexBot|Baiduspider|facebookexternalhit|LinkedInBot|Twitterbot|SemrushBot|AhrefsBot|PetalBot|CCBot|meta-externalagent|OAI-SearchBot|Perplexity|Diffbot|ia_archiver) [NC]
54
+ RewriteCond %{DOCUMENT_ROOT}/$1.html -f
55
+ RewriteRule ^((?:docs|core)/.+)$ /$1.html [END]
56
+
57
+ # Hubs are static files only
58
+ RewriteCond %{DOCUMENT_ROOT}/hubs/$1.html -f
59
+ RewriteRule ^hubs/([^/]+)/?$ /hubs/$1.html [END]
60
+
61
+ # SPA pushState (allow when path matches an on-disk dir such as …/button/)
62
+ RewriteCond %{REQUEST_FILENAME} !-f
63
+ RewriteRule ^(?:docs|core)/ index.html [END]
64
+
65
+ RewriteCond %{REQUEST_FILENAME} !-f
66
+ RewriteCond %{HTTP:Accept} "text/markdown" [NC]
67
+ RewriteCond %{HTTP:Accept} !"text/markdown\s*;\s*q\s*=\s*0(\.0+)?(\s*,|$)" [NC]
68
+ RewriteRule ^ - [R=404,L]
69
+
70
+ ErrorDocument 404 /404.md
71
+
72
+ <IfModule mod_headers.c>
73
+ Header merge Vary Accept
74
+ </IfModule>
75
+
76
+ <FilesMatch "\.md$">
77
+ ForceType text/markdown
78
+ <IfModule mod_headers.c>
79
+ Header set Content-Type "text/markdown; charset=utf-8"
80
+ Header merge Vary Accept
81
+ </IfModule>
82
+ </FilesMatch>