@askrjs/cli 0.0.2

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 (460) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +140 -0
  3. package/dist/add-DqhqRzBQ.js +555 -0
  4. package/dist/add-DqhqRzBQ.js.map +1 -0
  5. package/dist/add.js +3 -0
  6. package/dist/cli.js +91 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/create.js +923 -0
  9. package/dist/create.js.map +1 -0
  10. package/dist/is-direct-execution-Cdlr-ZUl.js +20 -0
  11. package/dist/is-direct-execution-Cdlr-ZUl.js.map +1 -0
  12. package/dist/openapi.js +127 -0
  13. package/dist/openapi.js.map +1 -0
  14. package/dist/skills/askr-accessibility/SKILL.md +68 -0
  15. package/dist/skills/askr-accessibility/agents/openai.yaml +4 -0
  16. package/dist/skills/askr-agent-execution/SKILL.md +85 -0
  17. package/dist/skills/askr-agent-execution/agents/openai.yaml +4 -0
  18. package/dist/skills/askr-agent-workflows/SKILL.md +57 -0
  19. package/dist/skills/askr-agent-workflows/agents/openai.yaml +4 -0
  20. package/dist/skills/askr-api-integration/SKILL.md +79 -0
  21. package/dist/skills/askr-api-integration/agents/openai.yaml +4 -0
  22. package/dist/skills/askr-app-builder/SKILL.md +99 -0
  23. package/dist/skills/askr-app-builder/agents/openai.yaml +4 -0
  24. package/dist/skills/askr-auth-access/SKILL.md +74 -0
  25. package/dist/skills/askr-auth-access/agents/openai.yaml +4 -0
  26. package/dist/skills/askr-cli-vite/SKILL.md +76 -0
  27. package/dist/skills/askr-cli-vite/agents/openai.yaml +4 -0
  28. package/dist/skills/askr-dashboard-charts/SKILL.md +82 -0
  29. package/dist/skills/askr-dashboard-charts/agents/openai.yaml +4 -0
  30. package/dist/skills/askr-design-system/SKILL.md +86 -0
  31. package/dist/skills/askr-design-system/agents/openai.yaml +4 -0
  32. package/dist/skills/askr-env-config/SKILL.md +74 -0
  33. package/dist/skills/askr-env-config/agents/openai.yaml +4 -0
  34. package/dist/skills/askr-error-loading-empty/SKILL.md +89 -0
  35. package/dist/skills/askr-error-loading-empty/agents/openai.yaml +4 -0
  36. package/dist/skills/askr-file-upload-artifacts/SKILL.md +77 -0
  37. package/dist/skills/askr-file-upload-artifacts/agents/openai.yaml +4 -0
  38. package/dist/skills/askr-forms-tables-crud/SKILL.md +98 -0
  39. package/dist/skills/askr-forms-tables-crud/agents/openai.yaml +4 -0
  40. package/dist/skills/askr-mental-model/SKILL.md +109 -0
  41. package/dist/skills/askr-mental-model/agents/openai.yaml +4 -0
  42. package/dist/skills/askr-migration-react/SKILL.md +81 -0
  43. package/dist/skills/askr-migration-react/agents/openai.yaml +4 -0
  44. package/dist/skills/askr-observability-debugging/SKILL.md +83 -0
  45. package/dist/skills/askr-observability-debugging/agents/openai.yaml +4 -0
  46. package/dist/skills/askr-project-structure/SKILL.md +79 -0
  47. package/dist/skills/askr-project-structure/agents/openai.yaml +4 -0
  48. package/dist/skills/askr-query-mutation/SKILL.md +115 -0
  49. package/dist/skills/askr-query-mutation/agents/openai.yaml +4 -0
  50. package/dist/skills/askr-realtime-streaming/SKILL.md +76 -0
  51. package/dist/skills/askr-realtime-streaming/agents/openai.yaml +4 -0
  52. package/dist/skills/askr-resources-data/SKILL.md +100 -0
  53. package/dist/skills/askr-resources-data/agents/openai.yaml +4 -0
  54. package/dist/skills/askr-routing-layouts/SKILL.md +107 -0
  55. package/dist/skills/askr-routing-layouts/agents/openai.yaml +4 -0
  56. package/dist/skills/askr-runtime-reactivity/SKILL.md +92 -0
  57. package/dist/skills/askr-runtime-reactivity/agents/openai.yaml +4 -0
  58. package/dist/skills/askr-ssr-ssg/SKILL.md +76 -0
  59. package/dist/skills/askr-ssr-ssg/agents/openai.yaml +4 -0
  60. package/dist/skills/askr-testing-determinism/SKILL.md +75 -0
  61. package/dist/skills/askr-testing-determinism/agents/openai.yaml +4 -0
  62. package/dist/skills/askr-theming/SKILL.md +86 -0
  63. package/dist/skills/askr-theming/agents/openai.yaml +4 -0
  64. package/dist/skills/askr-ui-composition/SKILL.md +92 -0
  65. package/dist/skills/askr-ui-composition/agents/openai.yaml +4 -0
  66. package/dist/skills-Bh0mEhIx.js +682 -0
  67. package/dist/skills-Bh0mEhIx.js.map +1 -0
  68. package/dist/skills.js +3 -0
  69. package/dist/ssg.js +188 -0
  70. package/dist/ssg.js.map +1 -0
  71. package/dist/templates/full-stack/AGENTS.md +12 -0
  72. package/dist/templates/full-stack/README.md +18 -0
  73. package/dist/templates/full-stack/gitignore.template +4 -0
  74. package/dist/templates/full-stack/index.html +14 -0
  75. package/dist/templates/full-stack/package.json +37 -0
  76. package/dist/templates/full-stack/server.ts +13 -0
  77. package/dist/templates/full-stack/src/action-authorizations.ts +10 -0
  78. package/dist/templates/full-stack/src/actions/create-message.ts +10 -0
  79. package/dist/templates/full-stack/src/i18n.ts +8 -0
  80. package/dist/templates/full-stack/src/main.tsx +12 -0
  81. package/dist/templates/full-stack/src/pages/home.tsx +25 -0
  82. package/dist/templates/full-stack/src/pages/layout.tsx +33 -0
  83. package/dist/templates/full-stack/src/pages/not-found.tsx +4 -0
  84. package/dist/templates/full-stack/src/routes.tsx +20 -0
  85. package/dist/templates/full-stack/src/schemas.ts +11 -0
  86. package/dist/templates/full-stack/src/server/action-registry.ts +12 -0
  87. package/dist/templates/full-stack/src/server/actions/create-message.ts +14 -0
  88. package/dist/templates/full-stack/src/server/app.ts +66 -0
  89. package/dist/templates/full-stack/src/server/dependencies.ts +55 -0
  90. package/dist/templates/full-stack/src/server/entry-server.ts +8 -0
  91. package/dist/templates/full-stack/src/telemetry.ts +4 -0
  92. package/dist/templates/full-stack/src/vite-server.d.ts +6 -0
  93. package/dist/templates/full-stack/tests/actions/create-message.test.ts +13 -0
  94. package/dist/templates/full-stack/tsconfig.json +16 -0
  95. package/dist/templates/full-stack/vite.config.ts +11 -0
  96. package/dist/templates/spa/AGENTS.md +60 -0
  97. package/dist/templates/spa/README.md +96 -0
  98. package/dist/templates/spa/gitignore.template +16 -0
  99. package/dist/templates/spa/index.html +13 -0
  100. package/dist/templates/spa/package.json +35 -0
  101. package/dist/templates/spa/src/adapters/operations-client.ts +90 -0
  102. package/dist/templates/spa/src/components/shared/metric-card.tsx +27 -0
  103. package/dist/templates/spa/src/components/shared/status-badge.tsx +24 -0
  104. package/dist/templates/spa/src/features/operations/operations.query.ts +9 -0
  105. package/dist/templates/spa/src/main.tsx +10 -0
  106. package/dist/templates/spa/src/pages/_layout.tsx +9 -0
  107. package/dist/templates/spa/src/pages/_routes.tsx +27 -0
  108. package/dist/templates/spa/src/pages/app/_layout.tsx +94 -0
  109. package/dist/templates/spa/src/pages/app/_routes.tsx +10 -0
  110. package/dist/templates/spa/src/pages/app/admin-home.tsx +152 -0
  111. package/dist/templates/spa/src/pages/app/agent-runs.tsx +93 -0
  112. package/dist/templates/spa/src/pages/app/settings.tsx +91 -0
  113. package/dist/templates/spa/src/pages/auth/_layout.tsx +38 -0
  114. package/dist/templates/spa/src/pages/auth/_routes.tsx +6 -0
  115. package/dist/templates/spa/src/pages/auth/login.tsx +63 -0
  116. package/dist/templates/spa/src/pages/not-found.tsx +22 -0
  117. package/dist/templates/spa/src/pages/public/_layout.tsx +47 -0
  118. package/dist/templates/spa/src/pages/public/_routes.tsx +6 -0
  119. package/dist/templates/spa/src/pages/public/home.tsx +143 -0
  120. package/dist/templates/spa/src/shared/format.ts +12 -0
  121. package/dist/templates/spa/src/shared/navigation.ts +15 -0
  122. package/dist/templates/spa/src/styles/components.css +49 -0
  123. package/dist/templates/spa/src/styles/layout.css +192 -0
  124. package/dist/templates/spa/src/styles/reset.css +44 -0
  125. package/dist/templates/spa/src/styles/theme.css +57 -0
  126. package/dist/templates/spa/src/styles/tokens.css +20 -0
  127. package/dist/templates/spa/src/styles.css +7 -0
  128. package/dist/templates/spa/src/styles.d.ts +1 -0
  129. package/dist/templates/spa/tests/app.test.tsx +37 -0
  130. package/dist/templates/spa/tests/components/shared.test.tsx +12 -0
  131. package/dist/templates/spa/tests/resources.test.ts +22 -0
  132. package/dist/templates/spa/tsconfig.json +20 -0
  133. package/dist/templates/spa/tsconfig.node.json +10 -0
  134. package/dist/templates/spa/vite.config.ts +24 -0
  135. package/dist/templates/spa/vitest.config.ts +17 -0
  136. package/dist/templates/ssg/AGENTS.md +55 -0
  137. package/dist/templates/ssg/README.md +39 -0
  138. package/dist/templates/ssg/gitignore.template +17 -0
  139. package/dist/templates/ssg/index.html +13 -0
  140. package/dist/templates/ssg/package.json +35 -0
  141. package/dist/templates/ssg/src/app.tsx +14 -0
  142. package/dist/templates/ssg/src/components/badge.tsx +3 -0
  143. package/dist/templates/ssg/src/components/counter.tsx +30 -0
  144. package/dist/templates/ssg/src/components/site-shell.tsx +111 -0
  145. package/dist/templates/ssg/src/jsx.d.ts +23 -0
  146. package/dist/templates/ssg/src/main.tsx +8 -0
  147. package/dist/templates/ssg/src/pages/about.tsx +82 -0
  148. package/dist/templates/ssg/src/pages/content.tsx +63 -0
  149. package/dist/templates/ssg/src/pages/example.tsx +97 -0
  150. package/dist/templates/ssg/src/pages/home.tsx +51 -0
  151. package/dist/templates/ssg/src/resources/user.ts +15 -0
  152. package/dist/templates/ssg/src/routes.tsx +15 -0
  153. package/dist/templates/ssg/src/styles.css +89 -0
  154. package/dist/templates/ssg/src/vite-env.d.ts +5 -0
  155. package/dist/templates/ssg/ssg.config.ts +34 -0
  156. package/dist/templates/ssg/tests/app.test.tsx +19 -0
  157. package/dist/templates/ssg/tests/components/counter.test.tsx +18 -0
  158. package/dist/templates/ssg/tests/resources.test.ts +11 -0
  159. package/dist/templates/ssg/tests/ssg-config.test.ts +11 -0
  160. package/dist/templates/ssg/tsconfig.json +20 -0
  161. package/dist/templates/ssg/tsconfig.node.json +10 -0
  162. package/dist/templates/ssg/vite.config.ts +24 -0
  163. package/dist/templates/ssg/vitest.config.ts +17 -0
  164. package/dist/templates/ssr/AGENTS.md +28 -0
  165. package/dist/templates/ssr/README.md +38 -0
  166. package/dist/templates/ssr/gitignore.template +16 -0
  167. package/dist/templates/ssr/index.html +13 -0
  168. package/dist/templates/ssr/package.json +34 -0
  169. package/dist/templates/ssr/server.ts +16 -0
  170. package/dist/templates/ssr/src/app.tsx +21 -0
  171. package/dist/templates/ssr/src/components/counter.tsx +26 -0
  172. package/dist/templates/ssr/src/entry-server.tsx +10 -0
  173. package/dist/templates/ssr/src/main.tsx +11 -0
  174. package/dist/templates/ssr/src/pages/about.tsx +75 -0
  175. package/dist/templates/ssr/src/pages/example.tsx +113 -0
  176. package/dist/templates/ssr/src/pages/home.tsx +56 -0
  177. package/dist/templates/ssr/src/resources/user.ts +15 -0
  178. package/dist/templates/ssr/src/routes.tsx +13 -0
  179. package/dist/templates/ssr/src/styles.css +148 -0
  180. package/dist/templates/ssr/src/vite-server.d.ts +7 -0
  181. package/dist/templates/ssr/tests/app.test.tsx +24 -0
  182. package/dist/templates/ssr/tests/components/counter.test.tsx +13 -0
  183. package/dist/templates/ssr/tests/resources.test.ts +11 -0
  184. package/dist/templates/ssr/tsconfig.json +22 -0
  185. package/dist/templates/ssr/tsconfig.node.json +10 -0
  186. package/dist/templates/ssr/tsconfig.server.json +15 -0
  187. package/dist/templates/ssr/vite.config.ts +25 -0
  188. package/dist/templates/ssr/vitest.config.ts +13 -0
  189. package/dist/templates/startkit/AGENTS.md +77 -0
  190. package/dist/templates/startkit/README.md +192 -0
  191. package/dist/templates/startkit/gitignore.template +16 -0
  192. package/dist/templates/startkit/index.html +13 -0
  193. package/dist/templates/startkit/package.json +35 -0
  194. package/dist/templates/startkit/src/components/app-header.tsx +93 -0
  195. package/dist/templates/startkit/src/components/app-sidebar.tsx +95 -0
  196. package/dist/templates/startkit/src/components/data-table.tsx +80 -0
  197. package/dist/templates/startkit/src/components/empty-state.tsx +13 -0
  198. package/dist/templates/startkit/src/components/page-header.tsx +23 -0
  199. package/dist/templates/startkit/src/components/stat-card.tsx +24 -0
  200. package/dist/templates/startkit/src/features/accounts/account-filters.tsx +61 -0
  201. package/dist/templates/startkit/src/features/accounts/account-table.tsx +79 -0
  202. package/dist/templates/startkit/src/lib/format.ts +31 -0
  203. package/dist/templates/startkit/src/lib/mock-data.ts +441 -0
  204. package/dist/templates/startkit/src/lib/routes.ts +116 -0
  205. package/dist/templates/startkit/src/main.tsx +12 -0
  206. package/dist/templates/startkit/src/pages/_layout.tsx +56 -0
  207. package/dist/templates/startkit/src/pages/auth/_layout.tsx +7 -0
  208. package/dist/templates/startkit/src/pages/auth/login.tsx +129 -0
  209. package/dist/templates/startkit/src/pages/home.tsx +83 -0
  210. package/dist/templates/startkit/src/pages/not-found.tsx +24 -0
  211. package/dist/templates/startkit/src/pages/workspace/_layout.tsx +17 -0
  212. package/dist/templates/startkit/src/pages/workspace/accounts/index.tsx +217 -0
  213. package/dist/templates/startkit/src/pages/workspace/dashboard.tsx +118 -0
  214. package/dist/templates/startkit/src/pages/workspace/settings.tsx +218 -0
  215. package/dist/templates/startkit/src/router.tsx +7 -0
  216. package/dist/templates/startkit/src/routes/auth-config.ts +38 -0
  217. package/dist/templates/startkit/src/routes/auth.ts +8 -0
  218. package/dist/templates/startkit/src/routes/index.ts +28 -0
  219. package/dist/templates/startkit/src/routes/public.ts +8 -0
  220. package/dist/templates/startkit/src/routes/workspace/accounts.ts +8 -0
  221. package/dist/templates/startkit/src/routes/workspace/index.ts +14 -0
  222. package/dist/templates/startkit/src/styles/components.css +396 -0
  223. package/dist/templates/startkit/src/styles/layout.css +192 -0
  224. package/dist/templates/startkit/src/styles/reset.css +38 -0
  225. package/dist/templates/startkit/src/styles/theme.css +76 -0
  226. package/dist/templates/startkit/src/styles/tokens.css +67 -0
  227. package/dist/templates/startkit/src/styles.css +7 -0
  228. package/dist/templates/startkit/src/toast.ts +55 -0
  229. package/dist/templates/startkit/src/utils/join-classes.ts +4 -0
  230. package/dist/templates/startkit/src/vite-env.d.ts +5 -0
  231. package/dist/templates/startkit/tests/app.test.tsx +32 -0
  232. package/dist/templates/startkit/tests/preferences.test.ts +43 -0
  233. package/dist/templates/startkit/tests/resources.test.ts +82 -0
  234. package/dist/templates/startkit/tsconfig.json +20 -0
  235. package/dist/templates/startkit/tsconfig.node.json +10 -0
  236. package/dist/templates/startkit/vite.config.ts +32 -0
  237. package/dist/templates/startkit/vitest.config.ts +13 -0
  238. package/dist/update-DyW1na5V.js +1140 -0
  239. package/dist/update-DyW1na5V.js.map +1 -0
  240. package/dist/update.js +3 -0
  241. package/package.json +84 -0
  242. package/skills/askr-accessibility/SKILL.md +68 -0
  243. package/skills/askr-accessibility/agents/openai.yaml +4 -0
  244. package/skills/askr-agent-execution/SKILL.md +85 -0
  245. package/skills/askr-agent-execution/agents/openai.yaml +4 -0
  246. package/skills/askr-agent-workflows/SKILL.md +57 -0
  247. package/skills/askr-agent-workflows/agents/openai.yaml +4 -0
  248. package/skills/askr-api-integration/SKILL.md +79 -0
  249. package/skills/askr-api-integration/agents/openai.yaml +4 -0
  250. package/skills/askr-app-builder/SKILL.md +99 -0
  251. package/skills/askr-app-builder/agents/openai.yaml +4 -0
  252. package/skills/askr-auth-access/SKILL.md +74 -0
  253. package/skills/askr-auth-access/agents/openai.yaml +4 -0
  254. package/skills/askr-cli-vite/SKILL.md +76 -0
  255. package/skills/askr-cli-vite/agents/openai.yaml +4 -0
  256. package/skills/askr-dashboard-charts/SKILL.md +82 -0
  257. package/skills/askr-dashboard-charts/agents/openai.yaml +4 -0
  258. package/skills/askr-design-system/SKILL.md +86 -0
  259. package/skills/askr-design-system/agents/openai.yaml +4 -0
  260. package/skills/askr-env-config/SKILL.md +74 -0
  261. package/skills/askr-env-config/agents/openai.yaml +4 -0
  262. package/skills/askr-error-loading-empty/SKILL.md +89 -0
  263. package/skills/askr-error-loading-empty/agents/openai.yaml +4 -0
  264. package/skills/askr-file-upload-artifacts/SKILL.md +77 -0
  265. package/skills/askr-file-upload-artifacts/agents/openai.yaml +4 -0
  266. package/skills/askr-forms-tables-crud/SKILL.md +98 -0
  267. package/skills/askr-forms-tables-crud/agents/openai.yaml +4 -0
  268. package/skills/askr-mental-model/SKILL.md +109 -0
  269. package/skills/askr-mental-model/agents/openai.yaml +4 -0
  270. package/skills/askr-migration-react/SKILL.md +81 -0
  271. package/skills/askr-migration-react/agents/openai.yaml +4 -0
  272. package/skills/askr-observability-debugging/SKILL.md +83 -0
  273. package/skills/askr-observability-debugging/agents/openai.yaml +4 -0
  274. package/skills/askr-project-structure/SKILL.md +79 -0
  275. package/skills/askr-project-structure/agents/openai.yaml +4 -0
  276. package/skills/askr-query-mutation/SKILL.md +115 -0
  277. package/skills/askr-query-mutation/agents/openai.yaml +4 -0
  278. package/skills/askr-realtime-streaming/SKILL.md +76 -0
  279. package/skills/askr-realtime-streaming/agents/openai.yaml +4 -0
  280. package/skills/askr-resources-data/SKILL.md +100 -0
  281. package/skills/askr-resources-data/agents/openai.yaml +4 -0
  282. package/skills/askr-routing-layouts/SKILL.md +107 -0
  283. package/skills/askr-routing-layouts/agents/openai.yaml +4 -0
  284. package/skills/askr-runtime-reactivity/SKILL.md +92 -0
  285. package/skills/askr-runtime-reactivity/agents/openai.yaml +4 -0
  286. package/skills/askr-ssr-ssg/SKILL.md +76 -0
  287. package/skills/askr-ssr-ssg/agents/openai.yaml +4 -0
  288. package/skills/askr-testing-determinism/SKILL.md +75 -0
  289. package/skills/askr-testing-determinism/agents/openai.yaml +4 -0
  290. package/skills/askr-theming/SKILL.md +86 -0
  291. package/skills/askr-theming/agents/openai.yaml +4 -0
  292. package/skills/askr-ui-composition/SKILL.md +92 -0
  293. package/skills/askr-ui-composition/agents/openai.yaml +4 -0
  294. package/templates/full-stack/AGENTS.md +12 -0
  295. package/templates/full-stack/README.md +18 -0
  296. package/templates/full-stack/gitignore.template +4 -0
  297. package/templates/full-stack/index.html +14 -0
  298. package/templates/full-stack/package.json +37 -0
  299. package/templates/full-stack/server.ts +13 -0
  300. package/templates/full-stack/src/action-authorizations.ts +10 -0
  301. package/templates/full-stack/src/actions/create-message.ts +10 -0
  302. package/templates/full-stack/src/i18n.ts +8 -0
  303. package/templates/full-stack/src/main.tsx +12 -0
  304. package/templates/full-stack/src/pages/home.tsx +25 -0
  305. package/templates/full-stack/src/pages/layout.tsx +33 -0
  306. package/templates/full-stack/src/pages/not-found.tsx +4 -0
  307. package/templates/full-stack/src/routes.tsx +20 -0
  308. package/templates/full-stack/src/schemas.ts +11 -0
  309. package/templates/full-stack/src/server/action-registry.ts +12 -0
  310. package/templates/full-stack/src/server/actions/create-message.ts +14 -0
  311. package/templates/full-stack/src/server/app.ts +66 -0
  312. package/templates/full-stack/src/server/dependencies.ts +55 -0
  313. package/templates/full-stack/src/server/entry-server.ts +8 -0
  314. package/templates/full-stack/src/telemetry.ts +4 -0
  315. package/templates/full-stack/src/vite-server.d.ts +6 -0
  316. package/templates/full-stack/tests/actions/create-message.test.ts +13 -0
  317. package/templates/full-stack/tsconfig.json +16 -0
  318. package/templates/full-stack/vite.config.ts +11 -0
  319. package/templates/spa/AGENTS.md +60 -0
  320. package/templates/spa/README.md +96 -0
  321. package/templates/spa/gitignore.template +16 -0
  322. package/templates/spa/index.html +13 -0
  323. package/templates/spa/package.json +35 -0
  324. package/templates/spa/src/adapters/operations-client.ts +90 -0
  325. package/templates/spa/src/components/shared/metric-card.tsx +27 -0
  326. package/templates/spa/src/components/shared/status-badge.tsx +24 -0
  327. package/templates/spa/src/features/operations/operations.query.ts +9 -0
  328. package/templates/spa/src/main.tsx +10 -0
  329. package/templates/spa/src/pages/_layout.tsx +9 -0
  330. package/templates/spa/src/pages/_routes.tsx +27 -0
  331. package/templates/spa/src/pages/app/_layout.tsx +94 -0
  332. package/templates/spa/src/pages/app/_routes.tsx +10 -0
  333. package/templates/spa/src/pages/app/admin-home.tsx +152 -0
  334. package/templates/spa/src/pages/app/agent-runs.tsx +93 -0
  335. package/templates/spa/src/pages/app/settings.tsx +91 -0
  336. package/templates/spa/src/pages/auth/_layout.tsx +38 -0
  337. package/templates/spa/src/pages/auth/_routes.tsx +6 -0
  338. package/templates/spa/src/pages/auth/login.tsx +63 -0
  339. package/templates/spa/src/pages/not-found.tsx +22 -0
  340. package/templates/spa/src/pages/public/_layout.tsx +47 -0
  341. package/templates/spa/src/pages/public/_routes.tsx +6 -0
  342. package/templates/spa/src/pages/public/home.tsx +143 -0
  343. package/templates/spa/src/shared/format.ts +12 -0
  344. package/templates/spa/src/shared/navigation.ts +15 -0
  345. package/templates/spa/src/styles/components.css +49 -0
  346. package/templates/spa/src/styles/layout.css +192 -0
  347. package/templates/spa/src/styles/reset.css +44 -0
  348. package/templates/spa/src/styles/theme.css +57 -0
  349. package/templates/spa/src/styles/tokens.css +20 -0
  350. package/templates/spa/src/styles.css +7 -0
  351. package/templates/spa/src/styles.d.ts +1 -0
  352. package/templates/spa/tests/app.test.tsx +37 -0
  353. package/templates/spa/tests/components/shared.test.tsx +12 -0
  354. package/templates/spa/tests/resources.test.ts +22 -0
  355. package/templates/spa/tsconfig.json +20 -0
  356. package/templates/spa/tsconfig.node.json +10 -0
  357. package/templates/spa/vite.config.ts +24 -0
  358. package/templates/spa/vitest.config.ts +17 -0
  359. package/templates/ssg/AGENTS.md +55 -0
  360. package/templates/ssg/README.md +39 -0
  361. package/templates/ssg/gitignore.template +17 -0
  362. package/templates/ssg/index.html +13 -0
  363. package/templates/ssg/package.json +35 -0
  364. package/templates/ssg/src/app.tsx +14 -0
  365. package/templates/ssg/src/components/badge.tsx +3 -0
  366. package/templates/ssg/src/components/counter.tsx +30 -0
  367. package/templates/ssg/src/components/site-shell.tsx +111 -0
  368. package/templates/ssg/src/jsx.d.ts +23 -0
  369. package/templates/ssg/src/main.tsx +8 -0
  370. package/templates/ssg/src/pages/about.tsx +82 -0
  371. package/templates/ssg/src/pages/content.tsx +63 -0
  372. package/templates/ssg/src/pages/example.tsx +97 -0
  373. package/templates/ssg/src/pages/home.tsx +51 -0
  374. package/templates/ssg/src/resources/user.ts +15 -0
  375. package/templates/ssg/src/routes.tsx +15 -0
  376. package/templates/ssg/src/styles.css +89 -0
  377. package/templates/ssg/src/vite-env.d.ts +5 -0
  378. package/templates/ssg/ssg.config.ts +34 -0
  379. package/templates/ssg/tests/app.test.tsx +19 -0
  380. package/templates/ssg/tests/components/counter.test.tsx +18 -0
  381. package/templates/ssg/tests/resources.test.ts +11 -0
  382. package/templates/ssg/tests/ssg-config.test.ts +11 -0
  383. package/templates/ssg/tsconfig.json +20 -0
  384. package/templates/ssg/tsconfig.node.json +10 -0
  385. package/templates/ssg/vite.config.ts +24 -0
  386. package/templates/ssg/vitest.config.ts +17 -0
  387. package/templates/ssr/AGENTS.md +28 -0
  388. package/templates/ssr/README.md +38 -0
  389. package/templates/ssr/gitignore.template +16 -0
  390. package/templates/ssr/index.html +13 -0
  391. package/templates/ssr/package.json +34 -0
  392. package/templates/ssr/server.ts +16 -0
  393. package/templates/ssr/src/app.tsx +21 -0
  394. package/templates/ssr/src/components/counter.tsx +26 -0
  395. package/templates/ssr/src/entry-server.tsx +10 -0
  396. package/templates/ssr/src/main.tsx +11 -0
  397. package/templates/ssr/src/pages/about.tsx +75 -0
  398. package/templates/ssr/src/pages/example.tsx +113 -0
  399. package/templates/ssr/src/pages/home.tsx +56 -0
  400. package/templates/ssr/src/resources/user.ts +15 -0
  401. package/templates/ssr/src/routes.tsx +13 -0
  402. package/templates/ssr/src/styles.css +148 -0
  403. package/templates/ssr/src/vite-server.d.ts +7 -0
  404. package/templates/ssr/tests/app.test.tsx +24 -0
  405. package/templates/ssr/tests/components/counter.test.tsx +13 -0
  406. package/templates/ssr/tests/resources.test.ts +11 -0
  407. package/templates/ssr/tsconfig.json +22 -0
  408. package/templates/ssr/tsconfig.node.json +10 -0
  409. package/templates/ssr/tsconfig.server.json +15 -0
  410. package/templates/ssr/vite.config.ts +25 -0
  411. package/templates/ssr/vitest.config.ts +13 -0
  412. package/templates/startkit/AGENTS.md +77 -0
  413. package/templates/startkit/README.md +192 -0
  414. package/templates/startkit/gitignore.template +16 -0
  415. package/templates/startkit/index.html +13 -0
  416. package/templates/startkit/package.json +35 -0
  417. package/templates/startkit/src/components/app-header.tsx +93 -0
  418. package/templates/startkit/src/components/app-sidebar.tsx +95 -0
  419. package/templates/startkit/src/components/data-table.tsx +80 -0
  420. package/templates/startkit/src/components/empty-state.tsx +13 -0
  421. package/templates/startkit/src/components/page-header.tsx +23 -0
  422. package/templates/startkit/src/components/stat-card.tsx +24 -0
  423. package/templates/startkit/src/features/accounts/account-filters.tsx +61 -0
  424. package/templates/startkit/src/features/accounts/account-table.tsx +79 -0
  425. package/templates/startkit/src/lib/format.ts +31 -0
  426. package/templates/startkit/src/lib/mock-data.ts +441 -0
  427. package/templates/startkit/src/lib/routes.ts +116 -0
  428. package/templates/startkit/src/main.tsx +12 -0
  429. package/templates/startkit/src/pages/_layout.tsx +56 -0
  430. package/templates/startkit/src/pages/auth/_layout.tsx +7 -0
  431. package/templates/startkit/src/pages/auth/login.tsx +129 -0
  432. package/templates/startkit/src/pages/home.tsx +83 -0
  433. package/templates/startkit/src/pages/not-found.tsx +24 -0
  434. package/templates/startkit/src/pages/workspace/_layout.tsx +17 -0
  435. package/templates/startkit/src/pages/workspace/accounts/index.tsx +217 -0
  436. package/templates/startkit/src/pages/workspace/dashboard.tsx +118 -0
  437. package/templates/startkit/src/pages/workspace/settings.tsx +218 -0
  438. package/templates/startkit/src/router.tsx +7 -0
  439. package/templates/startkit/src/routes/auth-config.ts +38 -0
  440. package/templates/startkit/src/routes/auth.ts +8 -0
  441. package/templates/startkit/src/routes/index.ts +28 -0
  442. package/templates/startkit/src/routes/public.ts +8 -0
  443. package/templates/startkit/src/routes/workspace/accounts.ts +8 -0
  444. package/templates/startkit/src/routes/workspace/index.ts +14 -0
  445. package/templates/startkit/src/styles/components.css +396 -0
  446. package/templates/startkit/src/styles/layout.css +192 -0
  447. package/templates/startkit/src/styles/reset.css +38 -0
  448. package/templates/startkit/src/styles/theme.css +76 -0
  449. package/templates/startkit/src/styles/tokens.css +67 -0
  450. package/templates/startkit/src/styles.css +7 -0
  451. package/templates/startkit/src/toast.ts +55 -0
  452. package/templates/startkit/src/utils/join-classes.ts +4 -0
  453. package/templates/startkit/src/vite-env.d.ts +5 -0
  454. package/templates/startkit/tests/app.test.tsx +32 -0
  455. package/templates/startkit/tests/preferences.test.ts +43 -0
  456. package/templates/startkit/tests/resources.test.ts +82 -0
  457. package/templates/startkit/tsconfig.json +20 -0
  458. package/templates/startkit/tsconfig.node.json +10 -0
  459. package/templates/startkit/vite.config.ts +32 -0
  460. package/templates/startkit/vitest.config.ts +13 -0
@@ -0,0 +1,555 @@
1
+ import { t as isDirectExecution } from "./is-direct-execution-Cdlr-ZUl.js";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { randomUUID } from "node:crypto";
5
+ //#region src/file-changes.ts
6
+ async function remove(paths) {
7
+ await Promise.all(paths.map((filePath) => fs.rm(filePath, { force: true }).catch(() => void 0)));
8
+ }
9
+ async function restore(changes) {
10
+ let complete = true;
11
+ for (const change of [...changes].reverse()) try {
12
+ if (change.original === null) {
13
+ await fs.rm(change.filePath, { force: true });
14
+ continue;
15
+ }
16
+ const rollbackPath = path.join(path.dirname(change.filePath), `.${path.basename(change.filePath)}.askr-rollback-${randomUUID()}`);
17
+ await fs.writeFile(rollbackPath, change.original, {
18
+ flag: "wx",
19
+ mode: change.mode
20
+ });
21
+ await fs.rename(rollbackPath, change.filePath);
22
+ } catch {
23
+ complete = false;
24
+ }
25
+ return complete;
26
+ }
27
+ async function writeFileChanges(changes, options = {}) {
28
+ const ordered = [...changes].sort((left, right) => left.filePath.localeCompare(right.filePath));
29
+ if (new Set(ordered.map((change) => change.filePath)).size !== ordered.length) throw new Error("File changes contain duplicate target paths.");
30
+ const replace = options.replace ?? fs.rename;
31
+ const staged = [];
32
+ try {
33
+ for (const change of ordered) {
34
+ await fs.mkdir(path.dirname(change.filePath), { recursive: true });
35
+ const stat = await fs.stat(change.filePath).catch(() => null);
36
+ const original = stat ? await fs.readFile(change.filePath) : null;
37
+ const temporaryPath = path.join(path.dirname(change.filePath), `.${path.basename(change.filePath)}.askr-change-${randomUUID()}`);
38
+ const mode = stat?.mode ?? 420;
39
+ await fs.writeFile(temporaryPath, change.content, {
40
+ flag: "wx",
41
+ mode
42
+ });
43
+ staged.push({
44
+ ...change,
45
+ original,
46
+ mode,
47
+ temporaryPath
48
+ });
49
+ }
50
+ } catch (error) {
51
+ await remove(staged.map((change) => change.temporaryPath));
52
+ throw error;
53
+ }
54
+ const replaced = [];
55
+ try {
56
+ for (const change of staged) {
57
+ await replace(change.temporaryPath, change.filePath);
58
+ replaced.push(change);
59
+ }
60
+ } catch {
61
+ const complete = await restore(replaced);
62
+ await remove(staged.map((change) => change.temporaryPath));
63
+ throw new Error(complete ? "File replacement failed; completed changes were rolled back." : "File replacement failed and rollback was incomplete.");
64
+ }
65
+ }
66
+ //#endregion
67
+ //#region src/bin/add.ts
68
+ const BRANCH_CONFIG = {
69
+ app: {
70
+ badge: "app route",
71
+ pagesDir: [
72
+ "src",
73
+ "pages",
74
+ "app"
75
+ ],
76
+ routesFile: [
77
+ "src",
78
+ "pages",
79
+ "app",
80
+ "_routes.tsx"
81
+ ]
82
+ },
83
+ public: {
84
+ badge: "public route",
85
+ pagesDir: [
86
+ "src",
87
+ "pages",
88
+ "public"
89
+ ],
90
+ routesFile: [
91
+ "src",
92
+ "pages",
93
+ "public",
94
+ "_routes.tsx"
95
+ ]
96
+ }
97
+ };
98
+ function helpText() {
99
+ return [
100
+ "askr add - Generate code into an existing Askr project",
101
+ "",
102
+ "Usage:",
103
+ " askr add page <name> [--branch app|public] [--cwd <dir>] [--title <title>] [--route <path>] [--force]",
104
+ " askr add action <name> --route <path> [--cwd <dir>] [--force]",
105
+ "",
106
+ "Commands:",
107
+ " page Scaffold a route page and register it in a route-first SPA branch",
108
+ " action Scaffold a browser descriptor, server handler, registration, authorization, and test",
109
+ "",
110
+ "Options:",
111
+ " --branch <name> Route branch to target (default: app)",
112
+ " --cwd <dir> Project directory (default: current directory)",
113
+ " --title <text> Override the generated page title",
114
+ " --route <path> Override the generated route path",
115
+ " --force Overwrite an existing page file",
116
+ " --help Show this help message",
117
+ "",
118
+ "Examples:",
119
+ " askr add page audit-log",
120
+ " askr add page ops/audit-log --branch public",
121
+ " askr add page approvals --title \"Human approvals\" --route /app/approvals",
122
+ " askr add action approve-request --route /requests/{id}",
123
+ "",
124
+ "Notes:",
125
+ " Page generation supports route-first SPA projects created from `askr create spa`.",
126
+ " Action generation supports projects created from `askr create full-stack`."
127
+ ].join("\n");
128
+ }
129
+ function parseArgs(args) {
130
+ const positional = [];
131
+ const parsed = {
132
+ branch: "app",
133
+ cwd: process.cwd(),
134
+ force: false,
135
+ help: false,
136
+ routePath: "",
137
+ title: "",
138
+ errors: []
139
+ };
140
+ for (let index = 0; index < args.length; index += 1) {
141
+ const arg = args[index];
142
+ if (arg === "--help" || arg === "-h") parsed.help = true;
143
+ else if (arg === "--force") parsed.force = true;
144
+ else if (arg === "--branch") if (index + 1 >= args.length) parsed.errors.push("Missing value for --branch");
145
+ else {
146
+ parsed.branch = args[index + 1];
147
+ index += 1;
148
+ }
149
+ else if (arg === "--cwd") if (index + 1 >= args.length) parsed.errors.push("Missing value for --cwd");
150
+ else {
151
+ parsed.cwd = args[index + 1];
152
+ index += 1;
153
+ }
154
+ else if (arg === "--title") if (index + 1 >= args.length) parsed.errors.push("Missing value for --title");
155
+ else {
156
+ parsed.title = args[index + 1].trim();
157
+ index += 1;
158
+ }
159
+ else if (arg === "--route") if (index + 1 >= args.length) parsed.errors.push("Missing value for --route");
160
+ else {
161
+ parsed.routePath = args[index + 1].trim();
162
+ index += 1;
163
+ }
164
+ else positional.push(arg);
165
+ }
166
+ return {
167
+ ...parsed,
168
+ command: positional[0] || "",
169
+ name: positional[1] || ""
170
+ };
171
+ }
172
+ async function pathExists(filePath) {
173
+ return Boolean(await fs.stat(filePath).catch(() => null));
174
+ }
175
+ function slugifySegment(value) {
176
+ return value.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
177
+ }
178
+ function normalizePageSegments(input) {
179
+ const segments = input.replace(/^\/+|\/+$/g, "").split("/").map((segment) => slugifySegment(segment.trim())).filter(Boolean);
180
+ if (segments.length === 0 || segments.some((segment) => segment.startsWith("_"))) return [];
181
+ return segments;
182
+ }
183
+ function toWords(segments) {
184
+ return segments.flatMap((segment) => segment.split("-").filter(Boolean));
185
+ }
186
+ function toTitleCase(words) {
187
+ return words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
188
+ }
189
+ function buildComponentName(segments) {
190
+ return `${toWords(segments).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("")}Page`;
191
+ }
192
+ function buildIdentifier(segments) {
193
+ const [first = "action", ...rest] = toWords(segments);
194
+ return [first.toLowerCase(), ...rest.map((word) => word.charAt(0).toUpperCase() + word.slice(1))].join("").replace(/^[^a-z_$]/i, "action");
195
+ }
196
+ function renderAuthorizationRegistry(actions) {
197
+ const imports = actions.map((action) => `import { ${action.descriptorName} } from './actions/${action.slug}.js';`);
198
+ const routes = /* @__PURE__ */ new Map();
199
+ for (const action of actions) {
200
+ const entries = routes.get(action.routePath) ?? [];
201
+ entries.push(action);
202
+ routes.set(action.routePath, entries);
203
+ }
204
+ const routeLines = [...routes].sort(([left], [right]) => left.localeCompare(right)).map(([routePath, entries]) => ` ${JSON.stringify(routePath)}: [${entries.map((entry) => entry.descriptorName).join(", ")}],`);
205
+ return [
206
+ "import type { ActionDescriptor } from '@askrjs/askr/actions';",
207
+ ...imports,
208
+ "",
209
+ "const actionsByRoute: Readonly<Record<string, readonly ActionDescriptor[]>> = Object.freeze({",
210
+ ...routeLines,
211
+ "});",
212
+ "",
213
+ "export function actionsFor(path: string): readonly ActionDescriptor[] {",
214
+ " return actionsByRoute[path] ?? [];",
215
+ "}",
216
+ ""
217
+ ].join("\n");
218
+ }
219
+ function renderServerActionRegistry(actions) {
220
+ return [
221
+ "import { createActionRegistry } from '@askrjs/server/askr';",
222
+ ...actions.map((action) => `import { ${action.descriptorName} } from '../actions/${action.slug}.js';`),
223
+ ...actions.map((action) => `import { ${action.handlerName} } from './actions/${action.slug}.js';`),
224
+ "import type { AppDependencies } from './dependencies.js';",
225
+ "",
226
+ "export function createActions(deps: AppDependencies) {",
227
+ " const registry = createActionRegistry(deps, {",
228
+ " csrf: { secret: process.env.CSRF_SECRET ?? 'development-only-secret' },",
229
+ " });",
230
+ ...actions.map((action) => ` registry.register(${action.descriptorName}, ${action.handlerName});`),
231
+ " return registry;",
232
+ "}",
233
+ ""
234
+ ].join("\n");
235
+ }
236
+ async function discoverDeclaredActions(projectRoot, replacement) {
237
+ const actionsDir = path.join(projectRoot, "src", "actions");
238
+ const names = await fs.readdir(actionsDir).catch(() => []);
239
+ const files = new Set(names.filter((name) => name.endsWith(".ts")).map((name) => path.join(actionsDir, name)));
240
+ files.add(replacement.filePath);
241
+ const actions = [];
242
+ for (const filePath of [...files].sort()) {
243
+ const content = filePath === replacement.filePath ? replacement.content : await fs.readFile(filePath, "utf8");
244
+ const descriptor = /export const (\w+Action) = defineAction\(/.exec(content)?.[1];
245
+ if (!descriptor) continue;
246
+ const routeName = `${descriptor}Route`;
247
+ const routeMatch = new RegExp(`export const ${routeName} = (['"])(.*?)\\1;`).exec(content);
248
+ if (!routeMatch) throw new Error(`Action descriptor ${path.basename(filePath)} must declare ${routeName}.`);
249
+ const slug = path.basename(filePath, ".ts");
250
+ actions.push({
251
+ slug,
252
+ descriptorName: descriptor,
253
+ handlerName: buildIdentifier([slug]),
254
+ routePath: routeMatch[2]
255
+ });
256
+ }
257
+ return actions.sort((left, right) => left.slug.localeCompare(right.slug));
258
+ }
259
+ function renderActionDescriptor(options) {
260
+ return [
261
+ "import { defineAction } from '@askrjs/askr/actions';",
262
+ "import { schema } from '@askrjs/schema';",
263
+ "",
264
+ `export const ${options.descriptorName}Route = ${JSON.stringify(options.routePath)};`,
265
+ "",
266
+ `export const ${options.descriptorName} = defineAction({`,
267
+ ` id: '${options.slug}',`,
268
+ " input: schema.object({ value: schema.string({ minLength: 1 }) }),",
269
+ " invalidates: [],",
270
+ "});",
271
+ ""
272
+ ].join("\n");
273
+ }
274
+ function renderActionHandler(options) {
275
+ return [
276
+ "import type { InferSchema } from '@askrjs/schema';",
277
+ `import { ${options.descriptorName} } from '../../actions/${options.slug}.js';`,
278
+ "import type { AppDependencies } from '../dependencies.js';",
279
+ "",
280
+ `type Input = InferSchema<typeof ${options.descriptorName}.input>;`,
281
+ "",
282
+ `export async function ${options.handlerName}(`,
283
+ " _context: unknown,",
284
+ " input: Input,",
285
+ " deps: Pick<AppDependencies, 'actions'>,",
286
+ ") {",
287
+ " await deps.actions.record({ action: " + JSON.stringify(options.slug) + ", value: input.value });",
288
+ " return { result: { accepted: true } };",
289
+ "}",
290
+ ""
291
+ ].join("\n");
292
+ }
293
+ function renderActionTest(options) {
294
+ return [
295
+ "import { describe, expect, it } from 'vitest';",
296
+ `import { ${options.descriptorName} } from '../../src/actions/${options.slug}.js';`,
297
+ "",
298
+ `describe('${options.slug} action', () => {`,
299
+ " it('should expose a browser-safe executable input contract', () => {",
300
+ ` expect(${options.descriptorName}.id).toBe('${options.slug}');`,
301
+ ` expect(${options.descriptorName}.input.safeParse({ value: 'example' }).success).toBe(true);`,
302
+ ` expect(${options.descriptorName}.input.safeParse({ value: '' }).success).toBe(false);`,
303
+ " });",
304
+ "});",
305
+ ""
306
+ ].join("\n");
307
+ }
308
+ function buildRoutePath(branch, segments, overridePath = "") {
309
+ if (!overridePath) {
310
+ const suffix = segments.join("/");
311
+ return branch === "app" ? `/app/${suffix}` : `/${suffix}`;
312
+ }
313
+ const normalized = overridePath.startsWith("/") ? overridePath : `/${overridePath}`;
314
+ if (branch === "app") return normalized === "/app" || normalized.startsWith("/app/") ? normalized : `/app${normalized}`;
315
+ if (normalized === "/app" || normalized.startsWith("/app/")) throw new Error("Public branch routes cannot live under /app.");
316
+ return normalized;
317
+ }
318
+ function toImportSpecifier(fromFile, toFile) {
319
+ const withoutExtension = path.relative(path.dirname(fromFile), toFile).replace(/\\/g, "/").replace(/\.tsx$/i, "");
320
+ return withoutExtension.startsWith(".") ? withoutExtension : `./${withoutExtension}`;
321
+ }
322
+ function createUpdatedRouteFile(routeFileContent, options) {
323
+ const normalized = routeFileContent.replace(/\r\n/g, "\n");
324
+ const lines = normalized.split("\n");
325
+ const lastImportIndex = lines.reduce((currentIndex, line, index) => line.startsWith("import ") ? index : currentIndex, -1);
326
+ if (lastImportIndex === -1) throw new Error("Unsupported route file: could not find import block.");
327
+ const importLine = `import ${options.componentName} from '${options.importSpecifier}';`;
328
+ if (normalized.includes(importLine) || normalized.includes(`route('${options.routePath}',`) || normalized.includes(`route("${options.routePath}",`)) throw new Error(`Route '${options.routePath}' is already registered.`);
329
+ lines.splice(lastImportIndex + 1, 0, importLine);
330
+ const closingIndex = lines.map((line) => line.trim()).lastIndexOf("}");
331
+ if (closingIndex === -1) throw new Error("Unsupported route file: could not find registration function body.");
332
+ lines.splice(closingIndex, 0, ` route('${options.routePath}', ${options.componentName});`);
333
+ return `${lines.join("\n")}\n`;
334
+ }
335
+ function renderPageFile(options) {
336
+ return [
337
+ "import {",
338
+ " Badge,",
339
+ " Card,",
340
+ " CardContent,",
341
+ " CardDescription,",
342
+ " CardHeader,",
343
+ " CardTitle,",
344
+ "} from '@askrjs/themes/components';",
345
+ "import { Stack } from '@askrjs/themes/components';",
346
+ "",
347
+ `export default function ${options.componentName}() {`,
348
+ " return (",
349
+ " <Stack gap=\"5\">",
350
+ " <section class=\"page-heading\">",
351
+ " <Stack gap=\"2\">",
352
+ ` <Badge>${options.badge}</Badge>`,
353
+ ` <h1>${options.title}</h1>`,
354
+ " <p class=\"lead\">",
355
+ ` Route-first scaffold for ${options.routePath}. Keep adapters, queries, and mutations outside the page as this surface grows.`,
356
+ " </p>",
357
+ " </Stack>",
358
+ " </section>",
359
+ "",
360
+ " <Card>",
361
+ " <CardHeader>",
362
+ " <CardTitle>Next step</CardTitle>",
363
+ " <CardDescription>",
364
+ " Move view logic into feature folders and keep loading, empty, error, and success states explicit.",
365
+ " </CardDescription>",
366
+ " </CardHeader>",
367
+ " <CardContent>",
368
+ " <Stack gap=\"3\">",
369
+ " <p>Start with a focused feature boundary instead of inline data fetching.</p>",
370
+ " <p>Prefer resource(), derive(), and For once the page takes on real state.</p>",
371
+ " </Stack>",
372
+ " </CardContent>",
373
+ " </Card>",
374
+ " </Stack>",
375
+ " );",
376
+ "}",
377
+ ""
378
+ ].join("\n");
379
+ }
380
+ async function addPage(parsed, io) {
381
+ if (!parsed.name) {
382
+ io.error("Page name is required.");
383
+ return 1;
384
+ }
385
+ const branch = parsed.branch.toLowerCase();
386
+ const branchConfig = BRANCH_CONFIG[branch];
387
+ if (!branchConfig) {
388
+ io.error(`Unsupported branch '${parsed.branch}'. Use app or public.`);
389
+ return 1;
390
+ }
391
+ const segments = normalizePageSegments(parsed.name);
392
+ if (segments.length === 0) {
393
+ io.error("Page name must contain at least one non-empty path segment.");
394
+ return 1;
395
+ }
396
+ const projectRoot = path.resolve(parsed.cwd);
397
+ const routesFile = path.join(projectRoot, ...branchConfig.routesFile);
398
+ if (!await pathExists(routesFile)) {
399
+ io.error(`Unsupported project layout. Expected route file: ${routesFile}`);
400
+ io.error("askr add page currently supports route-first SPA projects created by `askr create spa`.");
401
+ return 1;
402
+ }
403
+ const pageFile = path.join(projectRoot, ...branchConfig.pagesDir, ...segments).concat(".tsx");
404
+ if (await pathExists(pageFile) && !parsed.force) {
405
+ io.error(`Page file already exists: ${pageFile}`);
406
+ io.error("Pass --force to overwrite the existing file.");
407
+ return 1;
408
+ }
409
+ const title = parsed.title || toTitleCase(toWords(segments));
410
+ const componentName = buildComponentName(segments);
411
+ let routePath = "";
412
+ try {
413
+ routePath = buildRoutePath(branch, segments, parsed.routePath);
414
+ } catch (error) {
415
+ io.error(error instanceof Error ? error.message : String(error));
416
+ return 1;
417
+ }
418
+ const importSpecifier = toImportSpecifier(routesFile, pageFile);
419
+ let updatedRoutes = "";
420
+ try {
421
+ updatedRoutes = createUpdatedRouteFile(await fs.readFile(routesFile, "utf8"), {
422
+ componentName,
423
+ importSpecifier,
424
+ routePath
425
+ });
426
+ } catch (error) {
427
+ io.error(error instanceof Error ? error.message : String(error));
428
+ return 1;
429
+ }
430
+ try {
431
+ await fs.mkdir(path.dirname(pageFile), { recursive: true });
432
+ await fs.writeFile(pageFile, renderPageFile({
433
+ badge: branchConfig.badge,
434
+ componentName,
435
+ routePath,
436
+ title
437
+ }), "utf8");
438
+ await fs.writeFile(routesFile, updatedRoutes, "utf8");
439
+ } catch (error) {
440
+ io.error("Failed to write generated page artifacts.");
441
+ io.error(error instanceof Error ? error.message : String(error));
442
+ return 1;
443
+ }
444
+ io.log(`Added ${branch} page '${title}'.`);
445
+ io.log(` File: ${path.relative(projectRoot, pageFile).replace(/\\/g, "/")}`);
446
+ io.log(` Route: ${routePath}`);
447
+ io.log(` Router: ${path.relative(projectRoot, routesFile).replace(/\\/g, "/")}`);
448
+ return 0;
449
+ }
450
+ async function addAction(parsed, io) {
451
+ if (!parsed.name) {
452
+ io.error("Action name is required.");
453
+ return 1;
454
+ }
455
+ if (!parsed.routePath || !parsed.routePath.startsWith("/")) {
456
+ io.error("Action generation requires an absolute --route path.");
457
+ return 1;
458
+ }
459
+ const segments = normalizePageSegments(parsed.name);
460
+ if (segments.length === 0) {
461
+ io.error("Action name must contain at least one non-empty path segment.");
462
+ return 1;
463
+ }
464
+ const projectRoot = path.resolve(parsed.cwd);
465
+ const slug = segments.join("-");
466
+ const handlerName = buildIdentifier(segments);
467
+ const descriptorName = `${handlerName}Action`;
468
+ const descriptorFile = path.join(projectRoot, "src", "actions", `${slug}.ts`);
469
+ const handlerFile = path.join(projectRoot, "src", "server", "actions", `${slug}.ts`);
470
+ const registryFile = path.join(projectRoot, "src", "server", "action-registry.ts");
471
+ const authorizationFile = path.join(projectRoot, "src", "action-authorizations.ts");
472
+ const testFile = path.join(projectRoot, "tests", "actions", `${slug}.test.ts`);
473
+ if (!await pathExists(registryFile) || !await pathExists(authorizationFile)) {
474
+ io.error("Unsupported project layout. Expected an `askr create full-stack` project.");
475
+ return 1;
476
+ }
477
+ if (!parsed.force && (await pathExists(descriptorFile) || await pathExists(handlerFile))) {
478
+ io.error(`Action '${slug}' already exists. Pass --force to replace its generated files.`);
479
+ return 1;
480
+ }
481
+ try {
482
+ const descriptor = renderActionDescriptor({
483
+ descriptorName,
484
+ routePath: parsed.routePath,
485
+ slug
486
+ });
487
+ const actions = await discoverDeclaredActions(projectRoot, {
488
+ filePath: descriptorFile,
489
+ content: descriptor
490
+ });
491
+ await writeFileChanges([
492
+ {
493
+ filePath: descriptorFile,
494
+ content: descriptor
495
+ },
496
+ {
497
+ filePath: handlerFile,
498
+ content: renderActionHandler({
499
+ descriptorName,
500
+ handlerName,
501
+ slug
502
+ })
503
+ },
504
+ {
505
+ filePath: testFile,
506
+ content: renderActionTest({
507
+ descriptorName,
508
+ slug
509
+ })
510
+ },
511
+ {
512
+ filePath: registryFile,
513
+ content: renderServerActionRegistry(actions)
514
+ },
515
+ {
516
+ filePath: authorizationFile,
517
+ content: renderAuthorizationRegistry(actions)
518
+ }
519
+ ]);
520
+ } catch (error) {
521
+ io.error("Failed to write generated action artifacts.");
522
+ io.error(error instanceof Error ? error.message : String(error));
523
+ return 1;
524
+ }
525
+ io.log(`Added action '${slug}' for ${parsed.routePath}.`);
526
+ io.log(` Descriptor: ${path.relative(projectRoot, descriptorFile).replace(/\\/g, "/")}`);
527
+ io.log(` Handler: ${path.relative(projectRoot, handlerFile).replace(/\\/g, "/")}`);
528
+ io.log(` Test: ${path.relative(projectRoot, testFile).replace(/\\/g, "/")}`);
529
+ return 0;
530
+ }
531
+ async function runAddCli(args = process.argv.slice(2), io = console) {
532
+ const parsed = parseArgs(args);
533
+ if (parsed.errors.length > 0) {
534
+ for (const message of parsed.errors) io.error(message);
535
+ return 1;
536
+ }
537
+ if (!parsed.command || parsed.help) {
538
+ io.log(helpText());
539
+ return 0;
540
+ }
541
+ if (parsed.command === "page") return addPage(parsed, io);
542
+ if (parsed.command === "action") return addAction(parsed, io);
543
+ io.error(`Unknown add command: ${parsed.command}`);
544
+ io.error("Run `askr add --help` to see available commands.");
545
+ return 1;
546
+ }
547
+ async function main() {
548
+ const code = await runAddCli(process.argv.slice(2));
549
+ process.exit(code);
550
+ }
551
+ if (isDirectExecution(import.meta.url)) main();
552
+ //#endregion
553
+ export { runAddCli as t };
554
+
555
+ //# sourceMappingURL=add-DqhqRzBQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-DqhqRzBQ.js","names":[],"sources":["../src/file-changes.ts","../src/bin/add.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\nexport interface FileChange {\n readonly filePath: string;\n readonly content: string;\n}\n\ninterface StagedChange extends FileChange {\n readonly original: Buffer | null;\n readonly mode: number;\n readonly temporaryPath: string;\n}\n\nexport interface FileChangeWriterOptions {\n readonly replace?: (temporaryPath: string, filePath: string) => Promise<void>;\n}\n\nasync function remove(paths: readonly string[]): Promise<void> {\n await Promise.all(\n paths.map((filePath) => fs.rm(filePath, { force: true }).catch(() => undefined)),\n );\n}\n\nasync function restore(changes: readonly StagedChange[]): Promise<boolean> {\n let complete = true;\n for (const change of [...changes].reverse()) {\n try {\n if (change.original === null) {\n await fs.rm(change.filePath, { force: true });\n continue;\n }\n const rollbackPath = path.join(\n path.dirname(change.filePath),\n `.${path.basename(change.filePath)}.askr-rollback-${randomUUID()}`,\n );\n await fs.writeFile(rollbackPath, change.original, { flag: \"wx\", mode: change.mode });\n await fs.rename(rollbackPath, change.filePath);\n } catch {\n complete = false;\n }\n }\n return complete;\n}\n\nexport async function writeFileChanges(\n changes: readonly FileChange[],\n options: FileChangeWriterOptions = {},\n): Promise<void> {\n const ordered = [...changes].sort((left, right) => left.filePath.localeCompare(right.filePath));\n if (new Set(ordered.map((change) => change.filePath)).size !== ordered.length) {\n throw new Error(\"File changes contain duplicate target paths.\");\n }\n const replace = options.replace ?? fs.rename;\n const staged: StagedChange[] = [];\n try {\n for (const change of ordered) {\n await fs.mkdir(path.dirname(change.filePath), { recursive: true });\n const stat = await fs.stat(change.filePath).catch(() => null);\n const original = stat ? await fs.readFile(change.filePath) : null;\n const temporaryPath = path.join(\n path.dirname(change.filePath),\n `.${path.basename(change.filePath)}.askr-change-${randomUUID()}`,\n );\n const mode = stat?.mode ?? 0o644;\n await fs.writeFile(temporaryPath, change.content, { flag: \"wx\", mode });\n staged.push({ ...change, original, mode, temporaryPath });\n }\n } catch (error) {\n await remove(staged.map((change) => change.temporaryPath));\n throw error;\n }\n\n const replaced: StagedChange[] = [];\n try {\n for (const change of staged) {\n await replace(change.temporaryPath, change.filePath);\n replaced.push(change);\n }\n } catch {\n const complete = await restore(replaced);\n await remove(staged.map((change) => change.temporaryPath));\n throw new Error(\n complete\n ? \"File replacement failed; completed changes were rolled back.\"\n : \"File replacement failed and rollback was incomplete.\",\n );\n }\n}\n","#!/usr/bin/env node\n\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { isDirectExecution } from \"./is-direct-execution\";\nimport { writeFileChanges } from \"../file-changes\";\n\ntype CliIo = Pick<Console, \"error\" | \"log\">;\n\nconst BRANCH_CONFIG = {\n app: {\n badge: \"app route\",\n pagesDir: [\"src\", \"pages\", \"app\"],\n routesFile: [\"src\", \"pages\", \"app\", \"_routes.tsx\"],\n },\n public: {\n badge: \"public route\",\n pagesDir: [\"src\", \"pages\", \"public\"],\n routesFile: [\"src\", \"pages\", \"public\", \"_routes.tsx\"],\n },\n} as const;\n\ntype BranchName = keyof typeof BRANCH_CONFIG;\n\ninterface ParsedArgs {\n branch: string;\n cwd: string;\n force: boolean;\n help: boolean;\n routePath: string;\n title: string;\n errors: string[];\n command: string;\n name: string;\n}\n\nfunction helpText(): string {\n return [\n \"askr add - Generate code into an existing Askr project\",\n \"\",\n \"Usage:\",\n \" askr add page <name> [--branch app|public] [--cwd <dir>] [--title <title>] [--route <path>] [--force]\",\n \" askr add action <name> --route <path> [--cwd <dir>] [--force]\",\n \"\",\n \"Commands:\",\n \" page Scaffold a route page and register it in a route-first SPA branch\",\n \" action Scaffold a browser descriptor, server handler, registration, authorization, and test\",\n \"\",\n \"Options:\",\n \" --branch <name> Route branch to target (default: app)\",\n \" --cwd <dir> Project directory (default: current directory)\",\n \" --title <text> Override the generated page title\",\n \" --route <path> Override the generated route path\",\n \" --force Overwrite an existing page file\",\n \" --help Show this help message\",\n \"\",\n \"Examples:\",\n \" askr add page audit-log\",\n \" askr add page ops/audit-log --branch public\",\n ' askr add page approvals --title \"Human approvals\" --route /app/approvals',\n \" askr add action approve-request --route /requests/{id}\",\n \"\",\n \"Notes:\",\n \" Page generation supports route-first SPA projects created from `askr create spa`.\",\n \" Action generation supports projects created from `askr create full-stack`.\",\n ].join(\"\\n\");\n}\n\nfunction parseArgs(args: string[]): ParsedArgs {\n const positional: string[] = [];\n const parsed = {\n branch: \"app\",\n cwd: process.cwd(),\n force: false,\n help: false,\n routePath: \"\",\n title: \"\",\n errors: [] as string[],\n };\n\n for (let index = 0; index < args.length; index += 1) {\n const arg = args[index];\n\n if (arg === \"--help\" || arg === \"-h\") {\n parsed.help = true;\n } else if (arg === \"--force\") {\n parsed.force = true;\n } else if (arg === \"--branch\") {\n if (index + 1 >= args.length) {\n parsed.errors.push(\"Missing value for --branch\");\n } else {\n parsed.branch = args[index + 1];\n index += 1;\n }\n } else if (arg === \"--cwd\") {\n if (index + 1 >= args.length) {\n parsed.errors.push(\"Missing value for --cwd\");\n } else {\n parsed.cwd = args[index + 1];\n index += 1;\n }\n } else if (arg === \"--title\") {\n if (index + 1 >= args.length) {\n parsed.errors.push(\"Missing value for --title\");\n } else {\n parsed.title = args[index + 1].trim();\n index += 1;\n }\n } else if (arg === \"--route\") {\n if (index + 1 >= args.length) {\n parsed.errors.push(\"Missing value for --route\");\n } else {\n parsed.routePath = args[index + 1].trim();\n index += 1;\n }\n } else {\n positional.push(arg);\n }\n }\n\n return {\n ...parsed,\n command: positional[0] || \"\",\n name: positional[1] || \"\",\n };\n}\n\nasync function pathExists(filePath: string): Promise<boolean> {\n return Boolean(await fs.stat(filePath).catch(() => null));\n}\n\nfunction slugifySegment(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nfunction normalizePageSegments(input: string): string[] {\n const segments = input\n .replace(/^\\/+|\\/+$/g, \"\")\n .split(\"/\")\n .map((segment) => slugifySegment(segment.trim()))\n .filter(Boolean);\n\n if (segments.length === 0 || segments.some((segment) => segment.startsWith(\"_\"))) {\n return [];\n }\n\n return segments;\n}\n\nfunction toWords(segments: string[]): string[] {\n return segments.flatMap((segment) => segment.split(\"-\").filter(Boolean));\n}\n\nfunction toTitleCase(words: string[]): string {\n return words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(\" \");\n}\n\nfunction buildComponentName(segments: string[]): string {\n return `${toWords(segments)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\"\")}Page`;\n}\n\nfunction buildIdentifier(segments: string[]): string {\n const [first = \"action\", ...rest] = toWords(segments);\n return [first.toLowerCase(), ...rest.map((word) => word.charAt(0).toUpperCase() + word.slice(1))]\n .join(\"\")\n .replace(/^[^a-z_$]/i, \"action\");\n}\n\ninterface DeclaredAction {\n readonly slug: string;\n readonly descriptorName: string;\n readonly handlerName: string;\n readonly routePath: string;\n}\n\nfunction renderAuthorizationRegistry(actions: readonly DeclaredAction[]): string {\n const imports = actions.map(\n (action) => `import { ${action.descriptorName} } from './actions/${action.slug}.js';`,\n );\n const routes = new Map<string, DeclaredAction[]>();\n for (const action of actions) {\n const entries = routes.get(action.routePath) ?? [];\n entries.push(action);\n routes.set(action.routePath, entries);\n }\n const routeLines = [...routes]\n .sort(([left], [right]) => left.localeCompare(right))\n .map(\n ([routePath, entries]) =>\n ` ${JSON.stringify(routePath)}: [${entries.map((entry) => entry.descriptorName).join(\", \")}],`,\n );\n return [\n \"import type { ActionDescriptor } from '@askrjs/askr/actions';\",\n ...imports,\n \"\",\n \"const actionsByRoute: Readonly<Record<string, readonly ActionDescriptor[]>> = Object.freeze({\",\n ...routeLines,\n \"});\",\n \"\",\n \"export function actionsFor(path: string): readonly ActionDescriptor[] {\",\n \" return actionsByRoute[path] ?? [];\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction renderServerActionRegistry(actions: readonly DeclaredAction[]): string {\n return [\n \"import { createActionRegistry } from '@askrjs/server/askr';\",\n ...actions.map(\n (action) => `import { ${action.descriptorName} } from '../actions/${action.slug}.js';`,\n ),\n ...actions.map(\n (action) => `import { ${action.handlerName} } from './actions/${action.slug}.js';`,\n ),\n \"import type { AppDependencies } from './dependencies.js';\",\n \"\",\n \"export function createActions(deps: AppDependencies) {\",\n \" const registry = createActionRegistry(deps, {\",\n \" csrf: { secret: process.env.CSRF_SECRET ?? 'development-only-secret' },\",\n \" });\",\n ...actions.map(\n (action) => ` registry.register(${action.descriptorName}, ${action.handlerName});`,\n ),\n \" return registry;\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n\nasync function discoverDeclaredActions(\n projectRoot: string,\n replacement: { readonly filePath: string; readonly content: string },\n): Promise<DeclaredAction[]> {\n const actionsDir = path.join(projectRoot, \"src\", \"actions\");\n const names = await fs.readdir(actionsDir).catch(() => []);\n const files = new Set(\n names.filter((name) => name.endsWith(\".ts\")).map((name) => path.join(actionsDir, name)),\n );\n files.add(replacement.filePath);\n const actions: DeclaredAction[] = [];\n for (const filePath of [...files].sort()) {\n const content =\n filePath === replacement.filePath ? replacement.content : await fs.readFile(filePath, \"utf8\");\n const descriptor = /export const (\\w+Action) = defineAction\\(/.exec(content)?.[1];\n if (!descriptor) continue;\n const routeName = `${descriptor}Route`;\n const routeMatch = new RegExp(`export const ${routeName} = (['\"])(.*?)\\\\1;`).exec(content);\n if (!routeMatch)\n throw new Error(`Action descriptor ${path.basename(filePath)} must declare ${routeName}.`);\n const slug = path.basename(filePath, \".ts\");\n actions.push({\n slug,\n descriptorName: descriptor,\n handlerName: buildIdentifier([slug]),\n routePath: routeMatch[2]!,\n });\n }\n return actions.sort((left, right) => left.slug.localeCompare(right.slug));\n}\n\nfunction renderActionDescriptor(options: {\n descriptorName: string;\n routePath: string;\n slug: string;\n}): string {\n return [\n \"import { defineAction } from '@askrjs/askr/actions';\",\n \"import { schema } from '@askrjs/schema';\",\n \"\",\n `export const ${options.descriptorName}Route = ${JSON.stringify(options.routePath)};`,\n \"\",\n `export const ${options.descriptorName} = defineAction({`,\n ` id: '${options.slug}',`,\n \" input: schema.object({ value: schema.string({ minLength: 1 }) }),\",\n \" invalidates: [],\",\n \"});\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction renderActionHandler(options: {\n descriptorName: string;\n handlerName: string;\n slug: string;\n}): string {\n return [\n \"import type { InferSchema } from '@askrjs/schema';\",\n `import { ${options.descriptorName} } from '../../actions/${options.slug}.js';`,\n \"import type { AppDependencies } from '../dependencies.js';\",\n \"\",\n `type Input = InferSchema<typeof ${options.descriptorName}.input>;`,\n \"\",\n `export async function ${options.handlerName}(`,\n \" _context: unknown,\",\n \" input: Input,\",\n \" deps: Pick<AppDependencies, 'actions'>,\",\n \") {\",\n \" await deps.actions.record({ action: \" +\n JSON.stringify(options.slug) +\n \", value: input.value });\",\n \" return { result: { accepted: true } };\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction renderActionTest(options: { descriptorName: string; slug: string }): string {\n return [\n \"import { describe, expect, it } from 'vitest';\",\n `import { ${options.descriptorName} } from '../../src/actions/${options.slug}.js';`,\n \"\",\n `describe('${options.slug} action', () => {`,\n \" it('should expose a browser-safe executable input contract', () => {\",\n ` expect(${options.descriptorName}.id).toBe('${options.slug}');`,\n ` expect(${options.descriptorName}.input.safeParse({ value: 'example' }).success).toBe(true);`,\n ` expect(${options.descriptorName}.input.safeParse({ value: '' }).success).toBe(false);`,\n \" });\",\n \"});\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction buildRoutePath(branch: BranchName, segments: string[], overridePath = \"\"): string {\n if (!overridePath) {\n const suffix = segments.join(\"/\");\n return branch === \"app\" ? `/app/${suffix}` : `/${suffix}`;\n }\n\n const normalized = overridePath.startsWith(\"/\") ? overridePath : `/${overridePath}`;\n if (branch === \"app\") {\n return normalized === \"/app\" || normalized.startsWith(\"/app/\")\n ? normalized\n : `/app${normalized}`;\n }\n\n if (normalized === \"/app\" || normalized.startsWith(\"/app/\")) {\n throw new Error(\"Public branch routes cannot live under /app.\");\n }\n\n return normalized;\n}\n\nfunction toImportSpecifier(fromFile: string, toFile: string): string {\n const relativePath = path.relative(path.dirname(fromFile), toFile).replace(/\\\\/g, \"/\");\n const withoutExtension = relativePath.replace(/\\.tsx$/i, \"\");\n return withoutExtension.startsWith(\".\") ? withoutExtension : `./${withoutExtension}`;\n}\n\nfunction createUpdatedRouteFile(\n routeFileContent: string,\n options: { componentName: string; importSpecifier: string; routePath: string },\n): string {\n const normalized = routeFileContent.replace(/\\r\\n/g, \"\\n\");\n const lines = normalized.split(\"\\n\");\n const lastImportIndex = lines.reduce(\n (currentIndex, line, index) => (line.startsWith(\"import \") ? index : currentIndex),\n -1,\n );\n\n if (lastImportIndex === -1) {\n throw new Error(\"Unsupported route file: could not find import block.\");\n }\n\n const importLine = `import ${options.componentName} from '${options.importSpecifier}';`;\n if (\n normalized.includes(importLine) ||\n normalized.includes(`route('${options.routePath}',`) ||\n normalized.includes(`route(\"${options.routePath}\",`)\n ) {\n throw new Error(`Route '${options.routePath}' is already registered.`);\n }\n\n lines.splice(lastImportIndex + 1, 0, importLine);\n\n const closingIndex = lines.map((line) => line.trim()).lastIndexOf(\"}\");\n if (closingIndex === -1) {\n throw new Error(\"Unsupported route file: could not find registration function body.\");\n }\n\n lines.splice(closingIndex, 0, ` route('${options.routePath}', ${options.componentName});`);\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction renderPageFile(options: {\n badge: string;\n componentName: string;\n routePath: string;\n title: string;\n}): string {\n return [\n \"import {\",\n \" Badge,\",\n \" Card,\",\n \" CardContent,\",\n \" CardDescription,\",\n \" CardHeader,\",\n \" CardTitle,\",\n \"} from '@askrjs/themes/components';\",\n \"import { Stack } from '@askrjs/themes/components';\",\n \"\",\n `export default function ${options.componentName}() {`,\n \" return (\",\n ' <Stack gap=\"5\">',\n ' <section class=\"page-heading\">',\n ' <Stack gap=\"2\">',\n ` <Badge>${options.badge}</Badge>`,\n ` <h1>${options.title}</h1>`,\n ' <p class=\"lead\">',\n ` Route-first scaffold for ${options.routePath}. Keep adapters, queries, and mutations outside the page as this surface grows.`,\n \" </p>\",\n \" </Stack>\",\n \" </section>\",\n \"\",\n \" <Card>\",\n \" <CardHeader>\",\n \" <CardTitle>Next step</CardTitle>\",\n \" <CardDescription>\",\n \" Move view logic into feature folders and keep loading, empty, error, and success states explicit.\",\n \" </CardDescription>\",\n \" </CardHeader>\",\n \" <CardContent>\",\n ' <Stack gap=\"3\">',\n \" <p>Start with a focused feature boundary instead of inline data fetching.</p>\",\n \" <p>Prefer resource(), derive(), and For once the page takes on real state.</p>\",\n \" </Stack>\",\n \" </CardContent>\",\n \" </Card>\",\n \" </Stack>\",\n \" );\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n\nasync function addPage(parsed: ParsedArgs, io: CliIo): Promise<number> {\n if (!parsed.name) {\n io.error(\"Page name is required.\");\n return 1;\n }\n\n const branch = parsed.branch.toLowerCase() as BranchName;\n const branchConfig = BRANCH_CONFIG[branch];\n if (!branchConfig) {\n io.error(`Unsupported branch '${parsed.branch}'. Use app or public.`);\n return 1;\n }\n\n const segments = normalizePageSegments(parsed.name);\n if (segments.length === 0) {\n io.error(\"Page name must contain at least one non-empty path segment.\");\n return 1;\n }\n\n const projectRoot = path.resolve(parsed.cwd);\n const routesFile = path.join(projectRoot, ...branchConfig.routesFile);\n if (!(await pathExists(routesFile))) {\n io.error(`Unsupported project layout. Expected route file: ${routesFile}`);\n io.error(\n \"askr add page currently supports route-first SPA projects created by `askr create spa`.\",\n );\n return 1;\n }\n\n const pageFile = path.join(projectRoot, ...branchConfig.pagesDir, ...segments).concat(\".tsx\");\n if ((await pathExists(pageFile)) && !parsed.force) {\n io.error(`Page file already exists: ${pageFile}`);\n io.error(\"Pass --force to overwrite the existing file.\");\n return 1;\n }\n\n const title = parsed.title || toTitleCase(toWords(segments));\n const componentName = buildComponentName(segments);\n let routePath = \"\";\n try {\n routePath = buildRoutePath(branch, segments, parsed.routePath);\n } catch (error) {\n io.error(error instanceof Error ? error.message : String(error));\n return 1;\n }\n\n const importSpecifier = toImportSpecifier(routesFile, pageFile);\n let updatedRoutes = \"\";\n try {\n const routeFileContent = await fs.readFile(routesFile, \"utf8\");\n updatedRoutes = createUpdatedRouteFile(routeFileContent, {\n componentName,\n importSpecifier,\n routePath,\n });\n } catch (error) {\n io.error(error instanceof Error ? error.message : String(error));\n return 1;\n }\n\n try {\n await fs.mkdir(path.dirname(pageFile), { recursive: true });\n await fs.writeFile(\n pageFile,\n renderPageFile({\n badge: branchConfig.badge,\n componentName,\n routePath,\n title,\n }),\n \"utf8\",\n );\n await fs.writeFile(routesFile, updatedRoutes, \"utf8\");\n } catch (error) {\n io.error(\"Failed to write generated page artifacts.\");\n io.error(error instanceof Error ? error.message : String(error));\n return 1;\n }\n\n io.log(`Added ${branch} page '${title}'.`);\n io.log(` File: ${path.relative(projectRoot, pageFile).replace(/\\\\/g, \"/\")}`);\n io.log(` Route: ${routePath}`);\n io.log(` Router: ${path.relative(projectRoot, routesFile).replace(/\\\\/g, \"/\")}`);\n return 0;\n}\n\nasync function addAction(parsed: ParsedArgs, io: CliIo): Promise<number> {\n if (!parsed.name) {\n io.error(\"Action name is required.\");\n return 1;\n }\n if (!parsed.routePath || !parsed.routePath.startsWith(\"/\")) {\n io.error(\"Action generation requires an absolute --route path.\");\n return 1;\n }\n\n const segments = normalizePageSegments(parsed.name);\n if (segments.length === 0) {\n io.error(\"Action name must contain at least one non-empty path segment.\");\n return 1;\n }\n\n const projectRoot = path.resolve(parsed.cwd);\n const slug = segments.join(\"-\");\n const handlerName = buildIdentifier(segments);\n const descriptorName = `${handlerName}Action`;\n const descriptorFile = path.join(projectRoot, \"src\", \"actions\", `${slug}.ts`);\n const handlerFile = path.join(projectRoot, \"src\", \"server\", \"actions\", `${slug}.ts`);\n const registryFile = path.join(projectRoot, \"src\", \"server\", \"action-registry.ts\");\n const authorizationFile = path.join(projectRoot, \"src\", \"action-authorizations.ts\");\n const testFile = path.join(projectRoot, \"tests\", \"actions\", `${slug}.test.ts`);\n\n if (!(await pathExists(registryFile)) || !(await pathExists(authorizationFile))) {\n io.error(\"Unsupported project layout. Expected an `askr create full-stack` project.\");\n return 1;\n }\n if (!parsed.force && ((await pathExists(descriptorFile)) || (await pathExists(handlerFile)))) {\n io.error(`Action '${slug}' already exists. Pass --force to replace its generated files.`);\n return 1;\n }\n\n try {\n const descriptor = renderActionDescriptor({\n descriptorName,\n routePath: parsed.routePath,\n slug,\n });\n const actions = await discoverDeclaredActions(projectRoot, {\n filePath: descriptorFile,\n content: descriptor,\n });\n await writeFileChanges([\n { filePath: descriptorFile, content: descriptor },\n {\n filePath: handlerFile,\n content: renderActionHandler({ descriptorName, handlerName, slug }),\n },\n { filePath: testFile, content: renderActionTest({ descriptorName, slug }) },\n { filePath: registryFile, content: renderServerActionRegistry(actions) },\n { filePath: authorizationFile, content: renderAuthorizationRegistry(actions) },\n ]);\n } catch (error) {\n io.error(\"Failed to write generated action artifacts.\");\n io.error(error instanceof Error ? error.message : String(error));\n return 1;\n }\n\n io.log(`Added action '${slug}' for ${parsed.routePath}.`);\n io.log(` Descriptor: ${path.relative(projectRoot, descriptorFile).replace(/\\\\/g, \"/\")}`);\n io.log(` Handler: ${path.relative(projectRoot, handlerFile).replace(/\\\\/g, \"/\")}`);\n io.log(` Test: ${path.relative(projectRoot, testFile).replace(/\\\\/g, \"/\")}`);\n return 0;\n}\n\nexport async function runAddCli(\n args: string[] = process.argv.slice(2),\n io: CliIo = console,\n): Promise<number> {\n const parsed = parseArgs(args);\n\n if (parsed.errors.length > 0) {\n for (const message of parsed.errors) {\n io.error(message);\n }\n return 1;\n }\n\n if (!parsed.command || parsed.help) {\n io.log(helpText());\n return 0;\n }\n\n if (parsed.command === \"page\") {\n return addPage(parsed, io);\n }\n\n if (parsed.command === \"action\") {\n return addAction(parsed, io);\n }\n\n io.error(`Unknown add command: ${parsed.command}`);\n io.error(\"Run `askr add --help` to see available commands.\");\n return 1;\n}\n\nasync function main(): Promise<void> {\n const code = await runAddCli(process.argv.slice(2));\n process.exit(code);\n}\n\nif (isDirectExecution(import.meta.url)) {\n void main();\n}\n"],"mappings":";;;;;AAmBA,eAAe,OAAO,OAAyC;CAC7D,MAAM,QAAQ,IACZ,MAAM,KAAK,aAAa,GAAG,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS,CAAC,CACjF;AACF;AAEA,eAAe,QAAQ,SAAoD;CACzE,IAAI,WAAW;CACf,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,CAAC,CAAC,QAAQ,GACxC,IAAI;EACF,IAAI,OAAO,aAAa,MAAM;GAC5B,MAAM,GAAG,GAAG,OAAO,UAAU,EAAE,OAAO,KAAK,CAAC;GAC5C;EACF;EACA,MAAM,eAAe,KAAK,KACxB,KAAK,QAAQ,OAAO,QAAQ,GAC5B,IAAI,KAAK,SAAS,OAAO,QAAQ,EAAE,iBAAiB,WAAW,GACjE;EACA,MAAM,GAAG,UAAU,cAAc,OAAO,UAAU;GAAE,MAAM;GAAM,MAAM,OAAO;EAAK,CAAC;EACnF,MAAM,GAAG,OAAO,cAAc,OAAO,QAAQ;CAC/C,QAAQ;EACN,WAAW;CACb;CAEF,OAAO;AACT;AAEA,eAAsB,iBACpB,SACA,UAAmC,CAAC,GACrB;CACf,MAAM,UAAU,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,MAAM,UAAU,KAAK,SAAS,cAAc,MAAM,QAAQ,CAAC;CAC9F,IAAI,IAAI,IAAI,QAAQ,KAAK,WAAW,OAAO,QAAQ,CAAC,CAAC,CAAC,SAAS,QAAQ,QACrE,MAAM,IAAI,MAAM,8CAA8C;CAEhE,MAAM,UAAU,QAAQ,WAAW,GAAG;CACtC,MAAM,SAAyB,CAAC;CAChC,IAAI;EACF,KAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,GAAG,MAAM,KAAK,QAAQ,OAAO,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;GACjE,MAAM,OAAO,MAAM,GAAG,KAAK,OAAO,QAAQ,CAAC,CAAC,YAAY,IAAI;GAC5D,MAAM,WAAW,OAAO,MAAM,GAAG,SAAS,OAAO,QAAQ,IAAI;GAC7D,MAAM,gBAAgB,KAAK,KACzB,KAAK,QAAQ,OAAO,QAAQ,GAC5B,IAAI,KAAK,SAAS,OAAO,QAAQ,EAAE,eAAe,WAAW,GAC/D;GACA,MAAM,OAAO,MAAM,QAAQ;GAC3B,MAAM,GAAG,UAAU,eAAe,OAAO,SAAS;IAAE,MAAM;IAAM;GAAK,CAAC;GACtE,OAAO,KAAK;IAAE,GAAG;IAAQ;IAAU;IAAM;GAAc,CAAC;EAC1D;CACF,SAAS,OAAO;EACd,MAAM,OAAO,OAAO,KAAK,WAAW,OAAO,aAAa,CAAC;EACzD,MAAM;CACR;CAEA,MAAM,WAA2B,CAAC;CAClC,IAAI;EACF,KAAK,MAAM,UAAU,QAAQ;GAC3B,MAAM,QAAQ,OAAO,eAAe,OAAO,QAAQ;GACnD,SAAS,KAAK,MAAM;EACtB;CACF,QAAQ;EACN,MAAM,WAAW,MAAM,QAAQ,QAAQ;EACvC,MAAM,OAAO,OAAO,KAAK,WAAW,OAAO,aAAa,CAAC;EACzD,MAAM,IAAI,MACR,WACI,iEACA,sDACN;CACF;AACF;;;AChFA,MAAM,gBAAgB;CACpB,KAAK;EACH,OAAO;EACP,UAAU;GAAC;GAAO;GAAS;EAAK;EAChC,YAAY;GAAC;GAAO;GAAS;GAAO;EAAa;CACnD;CACA,QAAQ;EACN,OAAO;EACP,UAAU;GAAC;GAAO;GAAS;EAAQ;EACnC,YAAY;GAAC;GAAO;GAAS;GAAU;EAAa;CACtD;AACF;AAgBA,SAAS,WAAmB;CAC1B,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAS,UAAU,MAA4B;CAC7C,MAAM,aAAuB,CAAC;CAC9B,MAAM,SAAS;EACb,QAAQ;EACR,KAAK,QAAQ,IAAI;EACjB,OAAO;EACP,MAAM;EACN,WAAW;EACX,OAAO;EACP,QAAQ,CAAC;CACX;CAEA,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;EACnD,MAAM,MAAM,KAAK;EAEjB,IAAI,QAAQ,YAAY,QAAQ,MAC9B,OAAO,OAAO;OACT,IAAI,QAAQ,WACjB,OAAO,QAAQ;OACV,IAAI,QAAQ,YACjB,IAAI,QAAQ,KAAK,KAAK,QACpB,OAAO,OAAO,KAAK,4BAA4B;OAC1C;GACL,OAAO,SAAS,KAAK,QAAQ;GAC7B,SAAS;EACX;OACK,IAAI,QAAQ,SACjB,IAAI,QAAQ,KAAK,KAAK,QACpB,OAAO,OAAO,KAAK,yBAAyB;OACvC;GACL,OAAO,MAAM,KAAK,QAAQ;GAC1B,SAAS;EACX;OACK,IAAI,QAAQ,WACjB,IAAI,QAAQ,KAAK,KAAK,QACpB,OAAO,OAAO,KAAK,2BAA2B;OACzC;GACL,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC,KAAK;GACpC,SAAS;EACX;OACK,IAAI,QAAQ,WACjB,IAAI,QAAQ,KAAK,KAAK,QACpB,OAAO,OAAO,KAAK,2BAA2B;OACzC;GACL,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC,KAAK;GACxC,SAAS;EACX;OAEA,WAAW,KAAK,GAAG;CAEvB;CAEA,OAAO;EACL,GAAG;EACH,SAAS,WAAW,MAAM;EAC1B,MAAM,WAAW,MAAM;CACzB;AACF;AAEA,eAAe,WAAW,UAAoC;CAC5D,OAAO,QAAQ,MAAM,GAAG,KAAK,QAAQ,CAAC,CAAC,YAAY,IAAI,CAAC;AAC1D;AAEA,SAAS,eAAe,OAAuB;CAC7C,OAAO,MACJ,QAAQ,sBAAsB,OAAO,CAAC,CACtC,YAAY,CAAC,CACb,QAAQ,eAAe,GAAG,CAAC,CAC3B,QAAQ,YAAY,EAAE;AAC3B;AAEA,SAAS,sBAAsB,OAAyB;CACtD,MAAM,WAAW,MACd,QAAQ,cAAc,EAAE,CAAC,CACzB,MAAM,GAAG,CAAC,CACV,KAAK,YAAY,eAAe,QAAQ,KAAK,CAAC,CAAC,CAAC,CAChD,OAAO,OAAO;CAEjB,IAAI,SAAS,WAAW,KAAK,SAAS,MAAM,YAAY,QAAQ,WAAW,GAAG,CAAC,GAC7E,OAAO,CAAC;CAGV,OAAO;AACT;AAEA,SAAS,QAAQ,UAA8B;CAC7C,OAAO,SAAS,SAAS,YAAY,QAAQ,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CAAC;AACzE;AAEA,SAAS,YAAY,OAAyB;CAC5C,OAAO,MAAM,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG;AACnF;AAEA,SAAS,mBAAmB,UAA4B;CACtD,OAAO,GAAG,QAAQ,QAAQ,CAAC,CACxB,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAC3D,KAAK,EAAE,EAAE;AACd;AAEA,SAAS,gBAAgB,UAA4B;CACnD,MAAM,CAAC,QAAQ,UAAU,GAAG,QAAQ,QAAQ,QAAQ;CACpD,OAAO,CAAC,MAAM,YAAY,GAAG,GAAG,KAAK,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAC9F,KAAK,EAAE,CAAC,CACR,QAAQ,cAAc,QAAQ;AACnC;AASA,SAAS,4BAA4B,SAA4C;CAC/E,MAAM,UAAU,QAAQ,KACrB,WAAW,YAAY,OAAO,eAAe,qBAAqB,OAAO,KAAK,MACjF;CACA,MAAM,yBAAS,IAAI,IAA8B;CACjD,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,UAAU,OAAO,IAAI,OAAO,SAAS,KAAK,CAAC;EACjD,QAAQ,KAAK,MAAM;EACnB,OAAO,IAAI,OAAO,WAAW,OAAO;CACtC;CACA,MAAM,aAAa,CAAC,GAAG,MAAM,CAAC,CAC3B,MAAM,CAAC,OAAO,CAAC,WAAW,KAAK,cAAc,KAAK,CAAC,CAAC,CACpD,KACE,CAAC,WAAW,aACX,KAAK,KAAK,UAAU,SAAS,EAAE,KAAK,QAAQ,KAAK,UAAU,MAAM,cAAc,CAAC,CAAC,KAAK,IAAI,EAAE,GAChG;CACF,OAAO;EACL;EACA,GAAG;EACH;EACA;EACA,GAAG;EACH;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAS,2BAA2B,SAA4C;CAC9E,OAAO;EACL;EACA,GAAG,QAAQ,KACR,WAAW,YAAY,OAAO,eAAe,sBAAsB,OAAO,KAAK,MAClF;EACA,GAAG,QAAQ,KACR,WAAW,YAAY,OAAO,YAAY,qBAAqB,OAAO,KAAK,MAC9E;EACA;EACA;EACA;EACA;EACA;EACA;EACA,GAAG,QAAQ,KACR,WAAW,uBAAuB,OAAO,eAAe,IAAI,OAAO,YAAY,GAClF;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,eAAe,wBACb,aACA,aAC2B;CAC3B,MAAM,aAAa,KAAK,KAAK,aAAa,OAAO,SAAS;CAC1D,MAAM,QAAQ,MAAM,GAAG,QAAQ,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC;CACzD,MAAM,QAAQ,IAAI,IAChB,MAAM,QAAQ,SAAS,KAAK,SAAS,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,KAAK,KAAK,YAAY,IAAI,CAAC,CACxF;CACA,MAAM,IAAI,YAAY,QAAQ;CAC9B,MAAM,UAA4B,CAAC;CACnC,KAAK,MAAM,YAAY,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,GAAG;EACxC,MAAM,UACJ,aAAa,YAAY,WAAW,YAAY,UAAU,MAAM,GAAG,SAAS,UAAU,MAAM;EAC9F,MAAM,aAAa,4CAA4C,KAAK,OAAO,CAAC,GAAG;EAC/E,IAAI,CAAC,YAAY;EACjB,MAAM,YAAY,GAAG,WAAW;EAChC,MAAM,aAAa,IAAI,OAAO,gBAAgB,UAAU,mBAAmB,CAAC,CAAC,KAAK,OAAO;EACzF,IAAI,CAAC,YACH,MAAM,IAAI,MAAM,qBAAqB,KAAK,SAAS,QAAQ,EAAE,gBAAgB,UAAU,EAAE;EAC3F,MAAM,OAAO,KAAK,SAAS,UAAU,KAAK;EAC1C,QAAQ,KAAK;GACX;GACA,gBAAgB;GAChB,aAAa,gBAAgB,CAAC,IAAI,CAAC;GACnC,WAAW,WAAW;EACxB,CAAC;CACH;CACA,OAAO,QAAQ,MAAM,MAAM,UAAU,KAAK,KAAK,cAAc,MAAM,IAAI,CAAC;AAC1E;AAEA,SAAS,uBAAuB,SAIrB;CACT,OAAO;EACL;EACA;EACA;EACA,gBAAgB,QAAQ,eAAe,UAAU,KAAK,UAAU,QAAQ,SAAS,EAAE;EACnF;EACA,gBAAgB,QAAQ,eAAe;EACvC,UAAU,QAAQ,KAAK;EACvB;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAS,oBAAoB,SAIlB;CACT,OAAO;EACL;EACA,YAAY,QAAQ,eAAe,yBAAyB,QAAQ,KAAK;EACzE;EACA;EACA,mCAAmC,QAAQ,eAAe;EAC1D;EACA,yBAAyB,QAAQ,YAAY;EAC7C;EACA;EACA;EACA;EACA,2CACE,KAAK,UAAU,QAAQ,IAAI,IAC3B;EACF;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAS,iBAAiB,SAA2D;CACnF,OAAO;EACL;EACA,YAAY,QAAQ,eAAe,6BAA6B,QAAQ,KAAK;EAC7E;EACA,aAAa,QAAQ,KAAK;EAC1B;EACA,cAAc,QAAQ,eAAe,aAAa,QAAQ,KAAK;EAC/D,cAAc,QAAQ,eAAe;EACrC,cAAc,QAAQ,eAAe;EACrC;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAS,eAAe,QAAoB,UAAoB,eAAe,IAAY;CACzF,IAAI,CAAC,cAAc;EACjB,MAAM,SAAS,SAAS,KAAK,GAAG;EAChC,OAAO,WAAW,QAAQ,QAAQ,WAAW,IAAI;CACnD;CAEA,MAAM,aAAa,aAAa,WAAW,GAAG,IAAI,eAAe,IAAI;CACrE,IAAI,WAAW,OACb,OAAO,eAAe,UAAU,WAAW,WAAW,OAAO,IACzD,aACA,OAAO;CAGb,IAAI,eAAe,UAAU,WAAW,WAAW,OAAO,GACxD,MAAM,IAAI,MAAM,8CAA8C;CAGhE,OAAO;AACT;AAEA,SAAS,kBAAkB,UAAkB,QAAwB;CAEnE,MAAM,mBADe,KAAK,SAAS,KAAK,QAAQ,QAAQ,GAAG,MAAM,CAAC,CAAC,QAAQ,OAAO,GAC9C,CAAC,CAAC,QAAQ,WAAW,EAAE;CAC3D,OAAO,iBAAiB,WAAW,GAAG,IAAI,mBAAmB,KAAK;AACpE;AAEA,SAAS,uBACP,kBACA,SACQ;CACR,MAAM,aAAa,iBAAiB,QAAQ,SAAS,IAAI;CACzD,MAAM,QAAQ,WAAW,MAAM,IAAI;CACnC,MAAM,kBAAkB,MAAM,QAC3B,cAAc,MAAM,UAAW,KAAK,WAAW,SAAS,IAAI,QAAQ,cACrE,EACF;CAEA,IAAI,oBAAoB,IACtB,MAAM,IAAI,MAAM,sDAAsD;CAGxE,MAAM,aAAa,UAAU,QAAQ,cAAc,SAAS,QAAQ,gBAAgB;CACpF,IACE,WAAW,SAAS,UAAU,KAC9B,WAAW,SAAS,UAAU,QAAQ,UAAU,GAAG,KACnD,WAAW,SAAS,UAAU,QAAQ,UAAU,GAAG,GAEnD,MAAM,IAAI,MAAM,UAAU,QAAQ,UAAU,yBAAyB;CAGvE,MAAM,OAAO,kBAAkB,GAAG,GAAG,UAAU;CAE/C,MAAM,eAAe,MAAM,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,GAAG;CACrE,IAAI,iBAAiB,IACnB,MAAM,IAAI,MAAM,oEAAoE;CAGtF,MAAM,OAAO,cAAc,GAAG,YAAY,QAAQ,UAAU,KAAK,QAAQ,cAAc,GAAG;CAC1F,OAAO,GAAG,MAAM,KAAK,IAAI,EAAE;AAC7B;AAEA,SAAS,eAAe,SAKb;CACT,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,2BAA2B,QAAQ,cAAc;EACjD;EACA;EACA;EACA;EACA,oBAAoB,QAAQ,MAAM;EAClC,iBAAiB,QAAQ,MAAM;EAC/B;EACA,wCAAwC,QAAQ,UAAU;EAC1D;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,eAAe,QAAQ,QAAoB,IAA4B;CACrE,IAAI,CAAC,OAAO,MAAM;EAChB,GAAG,MAAM,wBAAwB;EACjC,OAAO;CACT;CAEA,MAAM,SAAS,OAAO,OAAO,YAAY;CACzC,MAAM,eAAe,cAAc;CACnC,IAAI,CAAC,cAAc;EACjB,GAAG,MAAM,uBAAuB,OAAO,OAAO,sBAAsB;EACpE,OAAO;CACT;CAEA,MAAM,WAAW,sBAAsB,OAAO,IAAI;CAClD,IAAI,SAAS,WAAW,GAAG;EACzB,GAAG,MAAM,6DAA6D;EACtE,OAAO;CACT;CAEA,MAAM,cAAc,KAAK,QAAQ,OAAO,GAAG;CAC3C,MAAM,aAAa,KAAK,KAAK,aAAa,GAAG,aAAa,UAAU;CACpE,IAAI,CAAE,MAAM,WAAW,UAAU,GAAI;EACnC,GAAG,MAAM,oDAAoD,YAAY;EACzE,GAAG,MACD,yFACF;EACA,OAAO;CACT;CAEA,MAAM,WAAW,KAAK,KAAK,aAAa,GAAG,aAAa,UAAU,GAAG,QAAQ,CAAC,CAAC,OAAO,MAAM;CAC5F,IAAK,MAAM,WAAW,QAAQ,KAAM,CAAC,OAAO,OAAO;EACjD,GAAG,MAAM,6BAA6B,UAAU;EAChD,GAAG,MAAM,8CAA8C;EACvD,OAAO;CACT;CAEA,MAAM,QAAQ,OAAO,SAAS,YAAY,QAAQ,QAAQ,CAAC;CAC3D,MAAM,gBAAgB,mBAAmB,QAAQ;CACjD,IAAI,YAAY;CAChB,IAAI;EACF,YAAY,eAAe,QAAQ,UAAU,OAAO,SAAS;CAC/D,SAAS,OAAO;EACd,GAAG,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EAC/D,OAAO;CACT;CAEA,MAAM,kBAAkB,kBAAkB,YAAY,QAAQ;CAC9D,IAAI,gBAAgB;CACpB,IAAI;EAEF,gBAAgB,uBAAuB,MADR,GAAG,SAAS,YAAY,MAAM,GACJ;GACvD;GACA;GACA;EACF,CAAC;CACH,SAAS,OAAO;EACd,GAAG,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EAC/D,OAAO;CACT;CAEA,IAAI;EACF,MAAM,GAAG,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;EAC1D,MAAM,GAAG,UACP,UACA,eAAe;GACb,OAAO,aAAa;GACpB;GACA;GACA;EACF,CAAC,GACD,MACF;EACA,MAAM,GAAG,UAAU,YAAY,eAAe,MAAM;CACtD,SAAS,OAAO;EACd,GAAG,MAAM,2CAA2C;EACpD,GAAG,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EAC/D,OAAO;CACT;CAEA,GAAG,IAAI,SAAS,OAAO,SAAS,MAAM,GAAG;CACzC,GAAG,IAAI,WAAW,KAAK,SAAS,aAAa,QAAQ,CAAC,CAAC,QAAQ,OAAO,GAAG,GAAG;CAC5E,GAAG,IAAI,YAAY,WAAW;CAC9B,GAAG,IAAI,aAAa,KAAK,SAAS,aAAa,UAAU,CAAC,CAAC,QAAQ,OAAO,GAAG,GAAG;CAChF,OAAO;AACT;AAEA,eAAe,UAAU,QAAoB,IAA4B;CACvE,IAAI,CAAC,OAAO,MAAM;EAChB,GAAG,MAAM,0BAA0B;EACnC,OAAO;CACT;CACA,IAAI,CAAC,OAAO,aAAa,CAAC,OAAO,UAAU,WAAW,GAAG,GAAG;EAC1D,GAAG,MAAM,sDAAsD;EAC/D,OAAO;CACT;CAEA,MAAM,WAAW,sBAAsB,OAAO,IAAI;CAClD,IAAI,SAAS,WAAW,GAAG;EACzB,GAAG,MAAM,+DAA+D;EACxE,OAAO;CACT;CAEA,MAAM,cAAc,KAAK,QAAQ,OAAO,GAAG;CAC3C,MAAM,OAAO,SAAS,KAAK,GAAG;CAC9B,MAAM,cAAc,gBAAgB,QAAQ;CAC5C,MAAM,iBAAiB,GAAG,YAAY;CACtC,MAAM,iBAAiB,KAAK,KAAK,aAAa,OAAO,WAAW,GAAG,KAAK,IAAI;CAC5E,MAAM,cAAc,KAAK,KAAK,aAAa,OAAO,UAAU,WAAW,GAAG,KAAK,IAAI;CACnF,MAAM,eAAe,KAAK,KAAK,aAAa,OAAO,UAAU,oBAAoB;CACjF,MAAM,oBAAoB,KAAK,KAAK,aAAa,OAAO,0BAA0B;CAClF,MAAM,WAAW,KAAK,KAAK,aAAa,SAAS,WAAW,GAAG,KAAK,SAAS;CAE7E,IAAI,CAAE,MAAM,WAAW,YAAY,KAAM,CAAE,MAAM,WAAW,iBAAiB,GAAI;EAC/E,GAAG,MAAM,2EAA2E;EACpF,OAAO;CACT;CACA,IAAI,CAAC,OAAO,UAAW,MAAM,WAAW,cAAc,KAAO,MAAM,WAAW,WAAW,IAAK;EAC5F,GAAG,MAAM,WAAW,KAAK,+DAA+D;EACxF,OAAO;CACT;CAEA,IAAI;EACF,MAAM,aAAa,uBAAuB;GACxC;GACA,WAAW,OAAO;GAClB;EACF,CAAC;EACD,MAAM,UAAU,MAAM,wBAAwB,aAAa;GACzD,UAAU;GACV,SAAS;EACX,CAAC;EACD,MAAM,iBAAiB;GACrB;IAAE,UAAU;IAAgB,SAAS;GAAW;GAChD;IACE,UAAU;IACV,SAAS,oBAAoB;KAAE;KAAgB;KAAa;IAAK,CAAC;GACpE;GACA;IAAE,UAAU;IAAU,SAAS,iBAAiB;KAAE;KAAgB;IAAK,CAAC;GAAE;GAC1E;IAAE,UAAU;IAAc,SAAS,2BAA2B,OAAO;GAAE;GACvE;IAAE,UAAU;IAAmB,SAAS,4BAA4B,OAAO;GAAE;EAC/E,CAAC;CACH,SAAS,OAAO;EACd,GAAG,MAAM,6CAA6C;EACtD,GAAG,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EAC/D,OAAO;CACT;CAEA,GAAG,IAAI,iBAAiB,KAAK,QAAQ,OAAO,UAAU,EAAE;CACxD,GAAG,IAAI,iBAAiB,KAAK,SAAS,aAAa,cAAc,CAAC,CAAC,QAAQ,OAAO,GAAG,GAAG;CACxF,GAAG,IAAI,cAAc,KAAK,SAAS,aAAa,WAAW,CAAC,CAAC,QAAQ,OAAO,GAAG,GAAG;CAClF,GAAG,IAAI,WAAW,KAAK,SAAS,aAAa,QAAQ,CAAC,CAAC,QAAQ,OAAO,GAAG,GAAG;CAC5E,OAAO;AACT;AAEA,eAAsB,UACpB,OAAiB,QAAQ,KAAK,MAAM,CAAC,GACrC,KAAY,SACK;CACjB,MAAM,SAAS,UAAU,IAAI;CAE7B,IAAI,OAAO,OAAO,SAAS,GAAG;EAC5B,KAAK,MAAM,WAAW,OAAO,QAC3B,GAAG,MAAM,OAAO;EAElB,OAAO;CACT;CAEA,IAAI,CAAC,OAAO,WAAW,OAAO,MAAM;EAClC,GAAG,IAAI,SAAS,CAAC;EACjB,OAAO;CACT;CAEA,IAAI,OAAO,YAAY,QACrB,OAAO,QAAQ,QAAQ,EAAE;CAG3B,IAAI,OAAO,YAAY,UACrB,OAAO,UAAU,QAAQ,EAAE;CAG7B,GAAG,MAAM,wBAAwB,OAAO,SAAS;CACjD,GAAG,MAAM,kDAAkD;CAC3D,OAAO;AACT;AAEA,eAAe,OAAsB;CACnC,MAAM,OAAO,MAAM,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC;CAClD,QAAQ,KAAK,IAAI;AACnB;AAEA,IAAI,kBAAkB,OAAO,KAAK,GAAG,GACnC,KAAU"}
package/dist/add.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { t as runAddCli } from "./add-DqhqRzBQ.js";
3
+ export { runAddCli };