@pylonsync/create-pylon 0.19.1 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (696) hide show
  1. package/bin/create-pylon.js +30 -7
  2. package/package.json +1 -1
  3. package/templates/_root/AGENTS.md +1 -1
  4. package/templates/agency/.env.example +7 -0
  5. package/templates/agency/AGENTS.md +1 -1
  6. package/templates/agency/README.md +28 -3
  7. package/templates/agency/app/(marketing)/contact-form.tsx +20 -18
  8. package/templates/agency/app/(marketing)/page.tsx +3 -3
  9. package/templates/agency/app/(marketing)/work/page.tsx +3 -3
  10. package/templates/agency/app/auth-form.tsx +4 -4
  11. package/templates/agency/app/dashboard/dashboard-client.tsx +110 -64
  12. package/templates/agency/app/dashboard/page.tsx +14 -16
  13. package/templates/agency/app/icon.svg +3 -0
  14. package/templates/agency/app/login/page.tsx +12 -14
  15. package/templates/agency/components/marketing.tsx +12 -5
  16. package/templates/agency/functions/seedStudioBackoffice.ts +42 -11
  17. package/templates/agency/lib/agency.ts +22 -0
  18. package/templates/agency/lib/demo.ts +118 -0
  19. package/templates/agency/lib/site.config.ts +19 -13
  20. package/templates/agency/public/favicon.ico +0 -0
  21. package/templates/agency/tests/agency.test.ts +57 -0
  22. package/templates/ai-chat/.env.example +13 -27
  23. package/templates/ai-chat/AGENTS.md +1 -1
  24. package/templates/ai-chat/README.md +53 -60
  25. package/templates/ai-chat/app/(chat)/c/[id]/page.tsx +19 -0
  26. package/templates/ai-chat/app/(chat)/chat-client.tsx +657 -622
  27. package/templates/ai-chat/app/(chat)/layout.tsx +6 -43
  28. package/templates/ai-chat/app/(chat)/not-found.tsx +6 -10
  29. package/templates/ai-chat/app/(chat)/page.tsx +7 -11
  30. package/templates/ai-chat/app/auth-form.tsx +45 -38
  31. package/templates/ai-chat/app/error.tsx +9 -12
  32. package/templates/ai-chat/app/globals.css +464 -102
  33. package/templates/ai-chat/app/layout.tsx +11 -19
  34. package/templates/ai-chat/app/login/page.tsx +39 -24
  35. package/templates/ai-chat/app.ts +118 -43
  36. package/templates/ai-chat/components/chat/composer.tsx +193 -0
  37. package/templates/ai-chat/components/chat/empty-state.tsx +65 -0
  38. package/templates/ai-chat/components/chat/icons.tsx +198 -0
  39. package/templates/ai-chat/components/chat/markdown.tsx +164 -0
  40. package/templates/ai-chat/components/chat/message.tsx +183 -0
  41. package/templates/ai-chat/components/chat/setup.tsx +71 -0
  42. package/templates/ai-chat/components/chat/sidebar.tsx +288 -0
  43. package/templates/ai-chat/functions/_beginTurn.ts +145 -0
  44. package/templates/ai-chat/functions/_finishTurn.ts +55 -0
  45. package/templates/ai-chat/functions/assistantStatus.ts +13 -0
  46. package/templates/ai-chat/functions/claimGuestHistory.ts +39 -0
  47. package/templates/ai-chat/functions/createConversation.ts +28 -0
  48. package/templates/ai-chat/functions/deleteConversation.ts +15 -20
  49. package/templates/ai-chat/functions/prepareGuestClaim.ts +32 -0
  50. package/templates/ai-chat/functions/renameConversation.ts +19 -0
  51. package/templates/ai-chat/functions/respond.ts +88 -0
  52. package/templates/ai-chat/functions/seedExamples.ts +46 -0
  53. package/templates/ai-chat/functions/stopResponse.ts +30 -0
  54. package/templates/ai-chat/lib/brand-icon.ts +7 -0
  55. package/templates/ai-chat/lib/chat.ts +277 -0
  56. package/templates/ai-chat/lib/claim.ts +15 -0
  57. package/templates/ai-chat/lib/examples.ts +179 -0
  58. package/templates/ai-chat/lib/highlight.ts +107 -0
  59. package/templates/ai-chat/lib/markdown.ts +317 -0
  60. package/templates/ai-chat/lib/provider.ts +38 -0
  61. package/templates/ai-chat/lib/site.config.ts +55 -39
  62. package/templates/ai-chat/tests/chat.test.ts +174 -0
  63. package/templates/ai-chat/tests/components.test.tsx +57 -0
  64. package/templates/ai-chat/tests/markdown.test.ts +88 -0
  65. package/templates/ai-chat/tests/provider.test.ts +32 -0
  66. package/templates/ai-studio/AGENTS.md +1 -1
  67. package/templates/backend/consumer/apps/api/app/layout.tsx +33 -0
  68. package/templates/backend/consumer/apps/api/app/page.tsx +54 -0
  69. package/templates/backend/consumer/apps/api/app.ts +166 -0
  70. package/templates/backend/consumer/apps/api/functions/addComment.ts +24 -0
  71. package/templates/backend/consumer/apps/api/functions/createPost.ts +19 -36
  72. package/templates/backend/consumer/apps/api/functions/deletePost.ts +15 -13
  73. package/templates/backend/consumer/apps/api/functions/myProfile.ts +5 -8
  74. package/templates/backend/consumer/apps/api/functions/seedDemo.ts +95 -0
  75. package/templates/backend/consumer/apps/api/functions/setFollow.ts +36 -0
  76. package/templates/backend/consumer/apps/api/functions/setLike.ts +36 -0
  77. package/templates/backend/consumer/apps/api/functions/upsertProfile.ts +43 -37
  78. package/templates/backend/consumer/apps/api/lib/seed.ts +89 -0
  79. package/templates/backend/consumer/apps/api/lib/social.ts +50 -0
  80. package/templates/backend/consumer/apps/api/package.json +8 -2
  81. package/templates/backend/consumer/apps/api/public/images/posts/arch.jpg +0 -0
  82. package/templates/backend/consumer/apps/api/public/images/posts/coffee.jpg +0 -0
  83. package/templates/backend/consumer/apps/api/public/images/posts/dog.jpg +0 -0
  84. package/templates/backend/consumer/apps/api/public/images/posts/lisbon.jpg +0 -0
  85. package/templates/backend/consumer/apps/api/public/images/posts/ramen.jpg +0 -0
  86. package/templates/backend/consumer/apps/api/public/images/posts/run.jpg +0 -0
  87. package/templates/backend/consumer/apps/api/public/images/posts/sunset.jpg +0 -0
  88. package/templates/backend/consumer/apps/api/tsconfig.json +12 -2
  89. package/templates/barebones/AGENTS.md +1 -1
  90. package/templates/chat/AGENTS.md +1 -1
  91. package/templates/chat/README.md +43 -21
  92. package/templates/chat/app/chat-client.tsx +495 -85
  93. package/templates/chat/app/error.tsx +1 -1
  94. package/templates/chat/app/globals.css +170 -54
  95. package/templates/chat/app/layout.tsx +12 -9
  96. package/templates/chat/app/not-found.tsx +4 -2
  97. package/templates/chat/app/page.tsx +9 -19
  98. package/templates/chat/app.ts +96 -17
  99. package/templates/chat/components/chat/avatar.tsx +45 -0
  100. package/templates/chat/components/chat/composer.tsx +110 -0
  101. package/templates/chat/components/chat/message-list.tsx +285 -0
  102. package/templates/chat/components/chat/sidebar.tsx +190 -0
  103. package/templates/chat/functions/joinChat.ts +83 -0
  104. package/templates/chat/functions/renameMember.ts +25 -0
  105. package/templates/chat/lib/chat.ts +188 -0
  106. package/templates/chat/lib/seed.ts +78 -0
  107. package/templates/chat/tests/chat.test.ts +159 -0
  108. package/templates/chat/tests/composer.test.tsx +54 -0
  109. package/templates/consumer/AGENTS.md +1 -1
  110. package/templates/consumer/README.md +3 -3
  111. package/templates/consumer/app/globals.css +10 -3
  112. package/templates/consumer/app/icon.svg +1 -0
  113. package/templates/consumer/components/social/avatar.tsx +25 -11
  114. package/templates/consumer/functions/seedFeed.ts +3 -3
  115. package/templates/consumer/lib/seed.ts +43 -85
  116. package/templates/consumer/public/favicon.ico +0 -0
  117. package/templates/consumer/public/images/posts/arch.jpg +0 -0
  118. package/templates/consumer/public/images/posts/coffee.jpg +0 -0
  119. package/templates/consumer/public/images/posts/dog.jpg +0 -0
  120. package/templates/consumer/public/images/posts/lisbon.jpg +0 -0
  121. package/templates/consumer/public/images/posts/ramen.jpg +0 -0
  122. package/templates/consumer/public/images/posts/run.jpg +0 -0
  123. package/templates/consumer/public/images/posts/sunset.jpg +0 -0
  124. package/templates/consumer/tests/seed.test.ts +39 -0
  125. package/templates/creator/.env.example +7 -0
  126. package/templates/creator/AGENTS.md +1 -1
  127. package/templates/creator/README.md +24 -5
  128. package/templates/creator/app/(marketing)/newsletter-signup.tsx +33 -12
  129. package/templates/creator/app/auth-form.tsx +7 -7
  130. package/templates/creator/app/dashboard/dashboard-client.tsx +137 -100
  131. package/templates/creator/app/dashboard/page.tsx +18 -18
  132. package/templates/creator/app/icon.svg +2 -0
  133. package/templates/creator/app/login/page.tsx +14 -14
  134. package/templates/creator/app.ts +4 -4
  135. package/templates/creator/functions/seedDemo.ts +32 -0
  136. package/templates/creator/functions/subscribe.ts +4 -15
  137. package/templates/creator/lib/demo.ts +94 -0
  138. package/templates/creator/lib/site.config.ts +15 -10
  139. package/templates/creator/lib/stats.ts +35 -0
  140. package/templates/creator/public/favicon.ico +0 -0
  141. package/templates/creator/tests/counter.test.ts +92 -0
  142. package/templates/creator/tests/live-count.test.tsx +45 -0
  143. package/templates/crm/AGENTS.md +1 -1
  144. package/templates/crm/README.md +22 -1
  145. package/templates/crm/app/apple-icon.png +0 -0
  146. package/templates/crm/app/companies/companies-view.tsx +32 -14
  147. package/templates/crm/app/companies/page.tsx +2 -1
  148. package/templates/crm/app/contacts/contacts-view.tsx +34 -10
  149. package/templates/crm/app/contacts/page.tsx +2 -1
  150. package/templates/crm/app/deals/[id]/deal-view.tsx +137 -98
  151. package/templates/crm/app/deals/[id]/page.tsx +2 -1
  152. package/templates/crm/app/globals.css +29 -14
  153. package/templates/crm/app/icon.svg +1 -0
  154. package/templates/crm/app/layout.tsx +7 -5
  155. package/templates/crm/app/page.tsx +2 -1
  156. package/templates/crm/app/pipeline-view.tsx +5 -5
  157. package/templates/crm/app/workspace.tsx +29 -17
  158. package/templates/crm/app.ts +5 -5
  159. package/templates/crm/components/activity-timeline.tsx +14 -4
  160. package/templates/crm/components/app-shell.tsx +94 -0
  161. package/templates/crm/components/auth-form.tsx +35 -5
  162. package/templates/crm/components/avatar.tsx +5 -1
  163. package/templates/crm/components/board-skeleton.tsx +5 -5
  164. package/templates/crm/components/brand-mark.tsx +25 -0
  165. package/templates/crm/components/command-palette.tsx +17 -17
  166. package/templates/crm/components/data-table.tsx +97 -36
  167. package/templates/crm/components/deal-card.tsx +23 -27
  168. package/templates/crm/components/filter-tabs.tsx +101 -0
  169. package/templates/crm/components/metrics-bar.tsx +6 -6
  170. package/templates/crm/components/nav.tsx +15 -0
  171. package/templates/crm/components/page-header.tsx +43 -7
  172. package/templates/crm/components/pipeline-board.tsx +16 -10
  173. package/templates/crm/components/require-auth.tsx +24 -26
  174. package/templates/crm/components/sidebar.tsx +54 -49
  175. package/templates/crm/components/stage-badge.tsx +4 -2
  176. package/templates/crm/components/ui/button.tsx +5 -4
  177. package/templates/crm/components/ui/dialog.tsx +1 -1
  178. package/templates/crm/components/ui/input.tsx +1 -1
  179. package/templates/crm/components/ui/select.tsx +1 -1
  180. package/templates/crm/components/ui/textarea.tsx +1 -1
  181. package/templates/crm/functions/seedWorkspace.ts +32 -17
  182. package/templates/crm/lib/brand.ts +9 -0
  183. package/templates/crm/lib/demo-team.ts +51 -0
  184. package/templates/crm/lib/pipeline.ts +37 -0
  185. package/templates/crm/lib/search.ts +4 -3
  186. package/templates/crm/lib/seed.ts +53 -8
  187. package/templates/crm/public/favicon.ico +0 -0
  188. package/templates/crm/tests/components.test.tsx +5 -5
  189. package/templates/crm/tests/demo-team.test.ts +18 -0
  190. package/templates/crm/tests/pipeline.test.ts +59 -3
  191. package/templates/directory/.env.example +7 -0
  192. package/templates/directory/AGENTS.md +1 -1
  193. package/templates/directory/README.md +22 -3
  194. package/templates/directory/app/(marketing)/directory-browse.tsx +30 -12
  195. package/templates/directory/app/(marketing)/page.tsx +6 -4
  196. package/templates/directory/app/auth-form.tsx +4 -4
  197. package/templates/directory/app/dashboard/dashboard-client.tsx +177 -90
  198. package/templates/directory/app/dashboard/page.tsx +16 -14
  199. package/templates/directory/app/icon.svg +4 -0
  200. package/templates/directory/app/login/page.tsx +16 -15
  201. package/templates/directory/functions/seedDemo.ts +43 -0
  202. package/templates/directory/lib/demo.ts +145 -0
  203. package/templates/directory/lib/directory.ts +27 -0
  204. package/templates/directory/lib/site.config.ts +21 -16
  205. package/templates/directory/public/favicon.ico +0 -0
  206. package/templates/directory/tests/directory.test.ts +46 -0
  207. package/templates/expo/consumer/apps/expo/App.tsx +360 -288
  208. package/templates/expo/consumer/apps/expo/app.json +9 -1
  209. package/templates/expo/consumer/apps/expo/package.json +2 -1
  210. package/templates/helpdesk/AGENTS.md +1 -1
  211. package/templates/helpdesk/README.md +21 -0
  212. package/templates/helpdesk/app/apple-icon.png +0 -0
  213. package/templates/helpdesk/app/customers/customers-view.tsx +23 -7
  214. package/templates/helpdesk/app/customers/page.tsx +2 -1
  215. package/templates/helpdesk/app/globals.css +29 -14
  216. package/templates/helpdesk/app/icon.svg +1 -0
  217. package/templates/helpdesk/app/inbox-view.tsx +66 -47
  218. package/templates/helpdesk/app/layout.tsx +7 -5
  219. package/templates/helpdesk/app/page.tsx +4 -7
  220. package/templates/helpdesk/app/tickets/[id]/page.tsx +2 -1
  221. package/templates/helpdesk/app/tickets/[id]/ticket-view.tsx +134 -97
  222. package/templates/helpdesk/app/workspace.tsx +33 -22
  223. package/templates/helpdesk/app.ts +2 -2
  224. package/templates/helpdesk/components/app-shell.tsx +94 -0
  225. package/templates/helpdesk/components/auth-form.tsx +35 -5
  226. package/templates/helpdesk/components/avatar.tsx +5 -1
  227. package/templates/helpdesk/components/brand-mark.tsx +28 -0
  228. package/templates/helpdesk/components/command-palette.tsx +17 -17
  229. package/templates/helpdesk/components/data-table.tsx +97 -36
  230. package/templates/helpdesk/components/filter-tabs.tsx +101 -0
  231. package/templates/helpdesk/components/nav.tsx +14 -0
  232. package/templates/helpdesk/components/page-header.tsx +43 -7
  233. package/templates/helpdesk/components/priority-badge.tsx +49 -6
  234. package/templates/helpdesk/components/require-auth.tsx +24 -26
  235. package/templates/helpdesk/components/sidebar.tsx +54 -48
  236. package/templates/helpdesk/components/sla-indicator.tsx +5 -8
  237. package/templates/helpdesk/components/thread.tsx +7 -7
  238. package/templates/helpdesk/components/ticket-list.tsx +79 -19
  239. package/templates/helpdesk/components/ui/button.tsx +5 -4
  240. package/templates/helpdesk/components/ui/dialog.tsx +1 -1
  241. package/templates/helpdesk/components/ui/input.tsx +1 -1
  242. package/templates/helpdesk/components/ui/select.tsx +1 -1
  243. package/templates/helpdesk/components/ui/textarea.tsx +1 -1
  244. package/templates/helpdesk/functions/seedWorkspace.ts +25 -15
  245. package/templates/helpdesk/lib/brand.ts +9 -0
  246. package/templates/helpdesk/lib/demo-team.ts +51 -0
  247. package/templates/helpdesk/lib/search.ts +4 -3
  248. package/templates/helpdesk/lib/seed.ts +43 -2
  249. package/templates/helpdesk/lib/tickets.ts +68 -20
  250. package/templates/helpdesk/public/favicon.ico +0 -0
  251. package/templates/helpdesk/tests/components.test.tsx +10 -0
  252. package/templates/helpdesk/tests/demo-team.test.ts +18 -0
  253. package/templates/helpdesk/tests/tickets.test.ts +70 -0
  254. package/templates/imessage/.env.example +49 -0
  255. package/templates/imessage/AGENTS.md +153 -0
  256. package/templates/imessage/CLAUDE.md +7 -0
  257. package/templates/imessage/README.md +187 -0
  258. package/templates/imessage/app/console.tsx +382 -0
  259. package/templates/imessage/app/contacts/page.tsx +13 -0
  260. package/templates/imessage/app/error.tsx +16 -0
  261. package/templates/imessage/app/gate.tsx +31 -0
  262. package/templates/imessage/app/globals.css +183 -0
  263. package/templates/imessage/app/layout.tsx +17 -0
  264. package/templates/imessage/app/login/login-form.tsx +115 -0
  265. package/templates/imessage/app/login/page.tsx +30 -0
  266. package/templates/imessage/app/not-found.tsx +13 -0
  267. package/templates/imessage/app/page.tsx +14 -0
  268. package/templates/imessage/app/robots.ts +6 -0
  269. package/templates/imessage/app/setup/page.tsx +13 -0
  270. package/templates/imessage/app/sign-out.tsx +20 -0
  271. package/templates/imessage/app.ts +299 -0
  272. package/templates/imessage/bunfig +4 -0
  273. package/templates/imessage/components/avatar.tsx +46 -0
  274. package/templates/imessage/components/contact-panel.tsx +263 -0
  275. package/templates/imessage/components/contacts-view.tsx +172 -0
  276. package/templates/imessage/components/conversation-list.tsx +129 -0
  277. package/templates/imessage/components/nav-rail.tsx +67 -0
  278. package/templates/imessage/components/setup-view.tsx +408 -0
  279. package/templates/imessage/components/thread.tsx +229 -0
  280. package/templates/imessage/components/ui/badge.tsx +37 -0
  281. package/templates/imessage/components/ui/button.tsx +56 -0
  282. package/templates/imessage/components/ui/card.tsx +90 -0
  283. package/templates/imessage/components/ui/dialog.tsx +110 -0
  284. package/templates/imessage/components/ui/input.tsx +30 -0
  285. package/templates/imessage/components/ui/label.tsx +21 -0
  286. package/templates/imessage/components/ui/select.tsx +39 -0
  287. package/templates/imessage/components/ui/table.tsx +124 -0
  288. package/templates/imessage/components/ui/textarea.tsx +24 -0
  289. package/templates/imessage/components.json +20 -0
  290. package/templates/imessage/functions/answerNow.ts +34 -0
  291. package/templates/imessage/functions/assistant.ts +96 -0
  292. package/templates/imessage/functions/beginTurn.ts +101 -0
  293. package/templates/imessage/functions/cancelReminder.ts +13 -0
  294. package/templates/imessage/functions/claimOutbound.ts +44 -0
  295. package/templates/imessage/functions/clearDemo.ts +18 -0
  296. package/templates/imessage/functions/deleteNote.ts +11 -0
  297. package/templates/imessage/functions/deliverOutbound.ts +55 -0
  298. package/templates/imessage/functions/finishTurn.ts +84 -0
  299. package/templates/imessage/functions/fireReminder.ts +42 -0
  300. package/templates/imessage/functions/ingestInbound.ts +22 -0
  301. package/templates/imessage/functions/ownerAccount.ts +13 -0
  302. package/templates/imessage/functions/processTurn.ts +74 -0
  303. package/templates/imessage/functions/relayApply.ts +102 -0
  304. package/templates/imessage/functions/relaySync.ts +63 -0
  305. package/templates/imessage/functions/releaseOutbound.ts +18 -0
  306. package/templates/imessage/functions/resolveTurn.ts +25 -0
  307. package/templates/imessage/functions/saveContact.ts +27 -0
  308. package/templates/imessage/functions/seedDemo.ts +70 -0
  309. package/templates/imessage/functions/sendOwnerMessage.ts +28 -0
  310. package/templates/imessage/functions/sendblueWebhook.ts +49 -0
  311. package/templates/imessage/functions/setContactStatus.ts +17 -0
  312. package/templates/imessage/functions/settleOutbound.ts +35 -0
  313. package/templates/imessage/functions/setupStatus.ts +33 -0
  314. package/templates/imessage/functions/sweep.ts +58 -0
  315. package/templates/imessage/functions/toolCancelReminder.ts +17 -0
  316. package/templates/imessage/functions/toolForgetNote.ts +15 -0
  317. package/templates/imessage/functions/toolListNotes.ts +16 -0
  318. package/templates/imessage/functions/toolListReminders.ts +17 -0
  319. package/templates/imessage/functions/toolSaveNote.ts +22 -0
  320. package/templates/imessage/functions/toolSetReminder.ts +55 -0
  321. package/templates/imessage/functions/updateSettings.ts +48 -0
  322. package/templates/imessage/gitignore +11 -0
  323. package/templates/imessage/lib/agent-call.ts +251 -0
  324. package/templates/imessage/lib/assistant.ts +74 -0
  325. package/templates/imessage/lib/chunk.ts +135 -0
  326. package/templates/imessage/lib/demo.ts +68 -0
  327. package/templates/imessage/lib/format.ts +170 -0
  328. package/templates/imessage/lib/gate.ts +104 -0
  329. package/templates/imessage/lib/handles.ts +67 -0
  330. package/templates/imessage/lib/provider.ts +38 -0
  331. package/templates/imessage/lib/relay-protocol.ts +95 -0
  332. package/templates/imessage/lib/reminders.ts +41 -0
  333. package/templates/imessage/lib/secrets.ts +59 -0
  334. package/templates/imessage/lib/sendblue.ts +173 -0
  335. package/templates/imessage/lib/store.ts +407 -0
  336. package/templates/imessage/lib/transport.ts +135 -0
  337. package/templates/imessage/lib/utils.ts +10 -0
  338. package/templates/imessage/package.json +40 -0
  339. package/templates/imessage/relay/.env.example +14 -0
  340. package/templates/imessage/relay/applescript.ts +70 -0
  341. package/templates/imessage/relay/chatdb.ts +165 -0
  342. package/templates/imessage/relay/client.ts +41 -0
  343. package/templates/imessage/relay/main.ts +137 -0
  344. package/templates/imessage/relay/state.ts +35 -0
  345. package/templates/imessage/tests/agent-call.test.ts +112 -0
  346. package/templates/imessage/tests/applescript.test.ts +88 -0
  347. package/templates/imessage/tests/chatdb.test.ts +139 -0
  348. package/templates/imessage/tests/chunk.test.ts +61 -0
  349. package/templates/imessage/tests/fake-ctx.ts +88 -0
  350. package/templates/imessage/tests/ingest.test.ts +141 -0
  351. package/templates/imessage/tests/lib.test.ts +99 -0
  352. package/templates/imessage/tests/review-fixes.test.ts +138 -0
  353. package/templates/imessage/tests/secrets.test.ts +36 -0
  354. package/templates/imessage/tests/sendblue.test.ts +143 -0
  355. package/templates/imessage/tests/setup.ts +5 -0
  356. package/templates/imessage/tsconfig.json +18 -0
  357. package/templates/inventory/AGENTS.md +1 -1
  358. package/templates/inventory/README.md +21 -0
  359. package/templates/inventory/app/apple-icon.png +0 -0
  360. package/templates/inventory/app/globals.css +29 -14
  361. package/templates/inventory/app/icon.svg +1 -0
  362. package/templates/inventory/app/layout.tsx +7 -5
  363. package/templates/inventory/app/movements/movements-view.tsx +32 -10
  364. package/templates/inventory/app/movements/page.tsx +2 -1
  365. package/templates/inventory/app/page.tsx +4 -6
  366. package/templates/inventory/app/products/[id]/page.tsx +2 -1
  367. package/templates/inventory/app/products/[id]/product-view.tsx +55 -25
  368. package/templates/inventory/app/products-view.tsx +74 -33
  369. package/templates/inventory/app/workspace.tsx +34 -16
  370. package/templates/inventory/app.ts +10 -2
  371. package/templates/inventory/components/app-shell.tsx +94 -0
  372. package/templates/inventory/components/auth-form.tsx +35 -5
  373. package/templates/inventory/components/avatar.tsx +5 -1
  374. package/templates/inventory/components/brand-mark.tsx +25 -0
  375. package/templates/inventory/components/category-tile.tsx +49 -0
  376. package/templates/inventory/components/command-palette.tsx +17 -17
  377. package/templates/inventory/components/data-table.tsx +97 -36
  378. package/templates/inventory/components/filter-tabs.tsx +101 -0
  379. package/templates/inventory/components/nav.tsx +14 -0
  380. package/templates/inventory/components/page-header.tsx +43 -7
  381. package/templates/inventory/components/require-auth.tsx +24 -26
  382. package/templates/inventory/components/sidebar.tsx +54 -48
  383. package/templates/inventory/components/stock-level.tsx +30 -14
  384. package/templates/inventory/components/summary-bar.tsx +8 -15
  385. package/templates/inventory/components/ui/button.tsx +5 -4
  386. package/templates/inventory/components/ui/dialog.tsx +1 -1
  387. package/templates/inventory/components/ui/input.tsx +1 -1
  388. package/templates/inventory/components/ui/select.tsx +1 -1
  389. package/templates/inventory/components/ui/textarea.tsx +1 -1
  390. package/templates/inventory/functions/seedWorkspace.ts +18 -8
  391. package/templates/inventory/lib/brand.ts +9 -0
  392. package/templates/inventory/lib/demo-team.ts +51 -0
  393. package/templates/inventory/lib/search.ts +4 -3
  394. package/templates/inventory/lib/seed.ts +29 -2
  395. package/templates/inventory/lib/stock.ts +32 -0
  396. package/templates/inventory/public/favicon.ico +0 -0
  397. package/templates/inventory/tests/demo-team.test.ts +18 -0
  398. package/templates/inventory/tests/stock.test.ts +29 -0
  399. package/templates/invoices/AGENTS.md +1 -1
  400. package/templates/invoices/README.md +16 -0
  401. package/templates/invoices/app/apple-icon.png +0 -0
  402. package/templates/invoices/app/clients/clients-view.tsx +18 -6
  403. package/templates/invoices/app/clients/page.tsx +2 -1
  404. package/templates/invoices/app/globals.css +29 -14
  405. package/templates/invoices/app/icon.svg +1 -0
  406. package/templates/invoices/app/invoices/[id]/invoice-view.tsx +72 -48
  407. package/templates/invoices/app/invoices/[id]/page.tsx +2 -1
  408. package/templates/invoices/app/invoices-view.tsx +81 -32
  409. package/templates/invoices/app/layout.tsx +7 -5
  410. package/templates/invoices/app/page.tsx +4 -6
  411. package/templates/invoices/app/workspace.tsx +26 -16
  412. package/templates/invoices/app.ts +2 -2
  413. package/templates/invoices/components/app-shell.tsx +94 -0
  414. package/templates/invoices/components/auth-form.tsx +35 -5
  415. package/templates/invoices/components/avatar.tsx +5 -1
  416. package/templates/invoices/components/brand-mark.tsx +26 -0
  417. package/templates/invoices/components/command-palette.tsx +17 -17
  418. package/templates/invoices/components/data-table.tsx +97 -36
  419. package/templates/invoices/components/filter-tabs.tsx +101 -0
  420. package/templates/invoices/components/line-items.tsx +19 -14
  421. package/templates/invoices/components/nav.tsx +14 -0
  422. package/templates/invoices/components/page-header.tsx +43 -7
  423. package/templates/invoices/components/require-auth.tsx +24 -26
  424. package/templates/invoices/components/sidebar.tsx +54 -48
  425. package/templates/invoices/components/status-badge.tsx +7 -7
  426. package/templates/invoices/components/summary-bar.tsx +5 -5
  427. package/templates/invoices/components/ui/button.tsx +5 -4
  428. package/templates/invoices/components/ui/dialog.tsx +1 -1
  429. package/templates/invoices/components/ui/input.tsx +1 -1
  430. package/templates/invoices/components/ui/select.tsx +1 -1
  431. package/templates/invoices/components/ui/textarea.tsx +1 -1
  432. package/templates/invoices/functions/recordPayment.ts +3 -0
  433. package/templates/invoices/lib/billing.ts +40 -0
  434. package/templates/invoices/lib/brand.ts +9 -0
  435. package/templates/invoices/lib/search.ts +4 -3
  436. package/templates/invoices/public/favicon.ico +0 -0
  437. package/templates/invoices/tests/billing.test.ts +27 -0
  438. package/templates/ios/consumer/apps/ios/Package.swift +4 -3
  439. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ActivityView.swift +107 -0
  440. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/AppModel.swift +171 -0
  441. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/AuthView.swift +182 -0
  442. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/CommentsView.swift +136 -0
  443. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ComposeView.swift +152 -0
  444. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ExploreView.swift +117 -0
  445. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/FeedView.swift +175 -159
  446. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/MainTabView.swift +54 -0
  447. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Media.swift +271 -0
  448. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Models.swift +101 -4
  449. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/PostCard.swift +245 -0
  450. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileEditorView.swift +208 -0
  451. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileView.swift +183 -0
  452. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/RootView.swift +25 -31
  453. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/SocialStore.swift +285 -0
  454. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/StoryViewer.swift +155 -0
  455. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Theme.swift +82 -0
  456. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/__APP_NAME_PASCAL__App.swift +4 -47
  457. package/templates/ios/consumer/apps/ios/project.yml +13 -9
  458. package/templates/local-service/.env.example +7 -0
  459. package/templates/local-service/AGENTS.md +1 -1
  460. package/templates/local-service/README.md +26 -2
  461. package/templates/local-service/app/(marketing)/booking-widget.tsx +48 -9
  462. package/templates/local-service/app/(marketing)/page.tsx +66 -42
  463. package/templates/local-service/app/auth-form.tsx +8 -8
  464. package/templates/local-service/app/dashboard/dashboard-client.tsx +119 -92
  465. package/templates/local-service/app/dashboard/page.tsx +14 -14
  466. package/templates/local-service/app/icon.svg +2 -0
  467. package/templates/local-service/app/login/page.tsx +15 -15
  468. package/templates/local-service/functions/seedDemo.ts +49 -0
  469. package/templates/local-service/lib/demo.ts +135 -0
  470. package/templates/local-service/lib/hours.ts +44 -0
  471. package/templates/local-service/lib/site.config.ts +8 -3
  472. package/templates/local-service/lib/slots.ts +3 -0
  473. package/templates/local-service/public/favicon.ico +0 -0
  474. package/templates/local-service/tests/booking.test.ts +104 -0
  475. package/templates/marketplace/AGENTS.md +1 -1
  476. package/templates/marketplace/README.md +23 -15
  477. package/templates/marketplace/app/globals.css +172 -114
  478. package/templates/marketplace/app/layout.tsx +75 -30
  479. package/templates/marketplace/app/listing/[id]/page.tsx +210 -123
  480. package/templates/marketplace/app/me/page.tsx +4 -4
  481. package/templates/marketplace/app/page.tsx +221 -298
  482. package/templates/marketplace/app/sell/page.tsx +8 -11
  483. package/templates/marketplace/app.ts +32 -7
  484. package/templates/marketplace/client/ActivityFeed.tsx +311 -0
  485. package/templates/marketplace/client/AuthNav.tsx +24 -16
  486. package/templates/marketplace/client/ListingCard.tsx +118 -0
  487. package/templates/marketplace/client/LiveGrid.tsx +92 -0
  488. package/templates/marketplace/client/LiveListingStatus.tsx +32 -24
  489. package/templates/marketplace/client/LoginCard.tsx +114 -136
  490. package/templates/marketplace/client/MarketProvider.tsx +3 -5
  491. package/templates/marketplace/client/MyMarket.tsx +371 -185
  492. package/templates/marketplace/client/OfferPanel.tsx +421 -287
  493. package/templates/marketplace/client/SellForm.tsx +271 -192
  494. package/templates/marketplace/client/ThemeToggle.tsx +1 -0
  495. package/templates/marketplace/client/WatchButton.tsx +16 -16
  496. package/templates/marketplace/client/market.ts +61 -14
  497. package/templates/marketplace/functions/seedMarket.ts +143 -36
  498. package/templates/marketplace/functions/seedOffers.ts +101 -0
  499. package/templates/marketplace/lib/catalog.ts +72 -1
  500. package/templates/marketplace/public/images/listings/ceramic-lamp-640.webp +0 -0
  501. package/templates/marketplace/public/images/listings/ceramic-lamp.webp +0 -0
  502. package/templates/marketplace/public/images/listings/duffel-640.webp +0 -0
  503. package/templates/marketplace/public/images/listings/duffel.webp +0 -0
  504. package/templates/marketplace/public/images/listings/film-camera-640.webp +0 -0
  505. package/templates/marketplace/public/images/listings/film-camera.webp +0 -0
  506. package/templates/marketplace/public/images/listings/lounge-chair-640.webp +0 -0
  507. package/templates/marketplace/public/images/listings/lounge-chair.webp +0 -0
  508. package/templates/marketplace/public/images/listings/road-bike-640.webp +0 -0
  509. package/templates/marketplace/public/images/listings/road-bike.webp +0 -0
  510. package/templates/marketplace/public/images/listings/slipper-chair-640.webp +0 -0
  511. package/templates/marketplace/public/images/listings/slipper-chair.webp +0 -0
  512. package/templates/marketplace/public/images/listings/turntable-640.webp +0 -0
  513. package/templates/marketplace/public/images/listings/turntable.webp +0 -0
  514. package/templates/marketplace/public/images/listings/wardrobe-640.webp +0 -0
  515. package/templates/marketplace/public/images/listings/wardrobe.webp +0 -0
  516. package/templates/marketplace/public/images/listings/watch-640.webp +0 -0
  517. package/templates/marketplace/public/images/listings/watch.webp +0 -0
  518. package/templates/marketplace/public/images/listings/weekender-bag-640.webp +0 -0
  519. package/templates/marketplace/public/images/listings/weekender-bag.webp +0 -0
  520. package/templates/marketplace/tests/example.test.ts +64 -2
  521. package/templates/marketplace/tests/listing-card.test.tsx +61 -0
  522. package/templates/projects/AGENTS.md +1 -1
  523. package/templates/projects/README.md +24 -3
  524. package/templates/projects/app/apple-icon.png +0 -0
  525. package/templates/projects/app/clients/clients-view.tsx +20 -6
  526. package/templates/projects/app/clients/page.tsx +2 -1
  527. package/templates/projects/app/globals.css +29 -14
  528. package/templates/projects/app/icon.svg +1 -0
  529. package/templates/projects/app/layout.tsx +7 -5
  530. package/templates/projects/app/page.tsx +3 -5
  531. package/templates/projects/app/projects/[id]/page.tsx +2 -1
  532. package/templates/projects/app/projects/[id]/project-view.tsx +45 -30
  533. package/templates/projects/app/projects-view.tsx +105 -52
  534. package/templates/projects/app/workspace.tsx +41 -20
  535. package/templates/projects/app.ts +2 -2
  536. package/templates/projects/components/app-shell.tsx +94 -0
  537. package/templates/projects/components/auth-form.tsx +35 -5
  538. package/templates/projects/components/avatar.tsx +5 -1
  539. package/templates/projects/components/board-skeleton.tsx +3 -3
  540. package/templates/projects/components/brand-mark.tsx +25 -0
  541. package/templates/projects/components/command-palette.tsx +17 -17
  542. package/templates/projects/components/data-table.tsx +97 -36
  543. package/templates/projects/components/filter-tabs.tsx +101 -0
  544. package/templates/projects/components/meter.tsx +48 -0
  545. package/templates/projects/components/nav.tsx +14 -0
  546. package/templates/projects/components/page-header.tsx +43 -7
  547. package/templates/projects/components/require-auth.tsx +24 -26
  548. package/templates/projects/components/sidebar.tsx +54 -48
  549. package/templates/projects/components/summary-bar.tsx +49 -0
  550. package/templates/projects/components/task-board.tsx +10 -9
  551. package/templates/projects/components/time-dialog.tsx +29 -5
  552. package/templates/projects/components/ui/button.tsx +5 -4
  553. package/templates/projects/components/ui/dialog.tsx +1 -1
  554. package/templates/projects/components/ui/input.tsx +1 -1
  555. package/templates/projects/components/ui/select.tsx +1 -1
  556. package/templates/projects/components/ui/textarea.tsx +1 -1
  557. package/templates/projects/functions/seedWorkspace.ts +26 -12
  558. package/templates/projects/lib/brand.ts +9 -0
  559. package/templates/projects/lib/demo-team.ts +51 -0
  560. package/templates/projects/lib/search.ts +4 -3
  561. package/templates/projects/lib/seed.ts +35 -1
  562. package/templates/projects/lib/work.ts +63 -0
  563. package/templates/projects/public/favicon.ico +0 -0
  564. package/templates/projects/tests/demo-team.test.ts +18 -0
  565. package/templates/projects/tests/work.test.ts +65 -0
  566. package/templates/restaurant/.env.example +7 -0
  567. package/templates/restaurant/AGENTS.md +1 -1
  568. package/templates/restaurant/README.md +29 -3
  569. package/templates/restaurant/app/(marketing)/layout.tsx +4 -2
  570. package/templates/restaurant/app/(marketing)/page.tsx +47 -23
  571. package/templates/restaurant/app/(marketing)/reservation-widget.tsx +37 -7
  572. package/templates/restaurant/app/auth-form.tsx +8 -8
  573. package/templates/restaurant/app/dashboard/dashboard-client.tsx +241 -109
  574. package/templates/restaurant/app/dashboard/page.tsx +14 -14
  575. package/templates/restaurant/app/icon.svg +4 -0
  576. package/templates/restaurant/app/login/page.tsx +15 -15
  577. package/templates/restaurant/functions/seedDemo.ts +44 -0
  578. package/templates/restaurant/lib/demo.ts +144 -0
  579. package/templates/restaurant/lib/hours.ts +45 -0
  580. package/templates/restaurant/lib/site.config.ts +3 -3
  581. package/templates/restaurant/public/favicon.ico +0 -0
  582. package/templates/restaurant/tests/reservations.test.ts +67 -0
  583. package/templates/saas/AGENTS.md +1 -1
  584. package/templates/saas/README.md +54 -35
  585. package/templates/saas/app/(auth)/auth-form.tsx +25 -23
  586. package/templates/saas/app/(auth)/forgot-password/page.tsx +1 -1
  587. package/templates/saas/app/(auth)/layout.tsx +27 -33
  588. package/templates/saas/app/(auth)/login/page.tsx +1 -1
  589. package/templates/saas/app/(auth)/reset-password/page.tsx +1 -1
  590. package/templates/saas/app/(auth)/signup/page.tsx +1 -1
  591. package/templates/saas/app/(marketing)/layout.tsx +127 -253
  592. package/templates/saas/app/(marketing)/page.tsx +133 -372
  593. package/templates/saas/app/(marketing)/pricing/page.tsx +21 -19
  594. package/templates/saas/app/(marketing)/products/[slug]/page.tsx +40 -95
  595. package/templates/saas/app/dashboard/board-client.tsx +416 -0
  596. package/templates/saas/app/dashboard/dashboard-client.tsx +30 -615
  597. package/templates/saas/app/dashboard/layout.tsx +27 -13
  598. package/templates/saas/app/dashboard/overview-client.tsx +332 -0
  599. package/templates/saas/app/dashboard/page.tsx +29 -35
  600. package/templates/saas/app/dashboard/projects/[id]/page.tsx +29 -0
  601. package/templates/saas/app/dashboard/projects/page.tsx +11 -7
  602. package/templates/saas/app/dashboard/projects-client.tsx +398 -0
  603. package/templates/saas/app/globals.css +5 -4
  604. package/templates/saas/app/icon.svg +1 -0
  605. package/templates/saas/app/onboarding/onboarding-client.tsx +93 -26
  606. package/templates/saas/app/onboarding/page.tsx +6 -2
  607. package/templates/saas/app.ts +68 -13
  608. package/templates/saas/components/dashboard-shell.tsx +212 -132
  609. package/templates/saas/components/marketing.tsx +137 -274
  610. package/templates/saas/components/pricing-table.tsx +12 -11
  611. package/templates/saas/components/setup-checklist.tsx +31 -29
  612. package/templates/saas/components/task-ui.tsx +199 -0
  613. package/templates/saas/functions/createProject.ts +7 -13
  614. package/templates/saas/functions/createTask.ts +67 -0
  615. package/templates/saas/functions/deleteProject.ts +17 -0
  616. package/templates/saas/functions/deleteTask.ts +14 -0
  617. package/templates/saas/functions/seedWorkspace.ts +46 -0
  618. package/templates/saas/functions/setProjectStatus.ts +41 -0
  619. package/templates/saas/functions/updateProfile.ts +13 -0
  620. package/templates/saas/functions/updateProject.ts +4 -5
  621. package/templates/saas/functions/updateTask.ts +88 -0
  622. package/templates/saas/lib/members.ts +53 -0
  623. package/templates/saas/lib/names.ts +53 -0
  624. package/templates/saas/lib/plans.ts +11 -0
  625. package/templates/saas/lib/sample-workspace.ts +117 -0
  626. package/templates/saas/lib/site.config.ts +200 -463
  627. package/templates/saas/lib/tasks.ts +101 -0
  628. package/templates/saas/lib/use-live.ts +25 -0
  629. package/templates/saas/public/favicon.ico +0 -0
  630. package/templates/saas/public/screenshots/board.png +0 -0
  631. package/templates/saas/public/screenshots/members.png +0 -0
  632. package/templates/saas/public/screenshots/overview.png +0 -0
  633. package/templates/saas/public/screenshots/projects.png +0 -0
  634. package/templates/saas/scripts/capture-screenshots.mjs +156 -0
  635. package/templates/saas/tests/names.test.ts +35 -0
  636. package/templates/saas/tests/plans.test.ts +12 -0
  637. package/templates/saas/tests/sample-workspace.test.ts +46 -0
  638. package/templates/saas/tests/tasks.test.ts +81 -0
  639. package/templates/shop/AGENTS.md +1 -1
  640. package/templates/shop/README.md +25 -13
  641. package/templates/shop/app/(marketing)/layout.tsx +94 -67
  642. package/templates/shop/app/(marketing)/not-found.tsx +13 -12
  643. package/templates/shop/app/(marketing)/page.tsx +120 -59
  644. package/templates/shop/app/(marketing)/shop-client.tsx +364 -237
  645. package/templates/shop/app/(marketing)/success/page.tsx +75 -22
  646. package/templates/shop/app/globals.css +94 -1
  647. package/templates/shop/app/layout.tsx +4 -4
  648. package/templates/shop/app/login/page.tsx +4 -4
  649. package/templates/shop/app.ts +18 -6
  650. package/templates/shop/components/cart-button.tsx +33 -0
  651. package/templates/shop/components/marketing.tsx +17 -87
  652. package/templates/shop/components/shelf-count.tsx +36 -0
  653. package/templates/shop/functions/checkout.ts +17 -1
  654. package/templates/shop/lib/cart-store.ts +57 -0
  655. package/templates/shop/lib/shelf-store.ts +35 -0
  656. package/templates/shop/lib/shop.ts +27 -0
  657. package/templates/shop/lib/site.config.ts +108 -98
  658. package/templates/shop/public/images/hero.jpg +0 -0
  659. package/templates/shop/public/images/products/cedar-smoke.jpg +0 -0
  660. package/templates/shop/public/images/products/fig-leaf.jpg +0 -0
  661. package/templates/shop/public/images/products/linen.jpg +0 -0
  662. package/templates/shop/public/images/products/sea-salt.jpg +0 -0
  663. package/templates/shop/public/images/products/tobacco-oak.jpg +0 -0
  664. package/templates/shop/tests/shop.test.ts +64 -0
  665. package/templates/todo/AGENTS.md +1 -1
  666. package/templates/waitlist/.env.example +7 -0
  667. package/templates/waitlist/AGENTS.md +1 -1
  668. package/templates/waitlist/README.md +29 -13
  669. package/templates/waitlist/app/(marketing)/page.tsx +9 -7
  670. package/templates/waitlist/app/(marketing)/waitlist-hero.tsx +64 -31
  671. package/templates/waitlist/app/auth-form.tsx +8 -8
  672. package/templates/waitlist/app/dashboard/dashboard-client.tsx +132 -95
  673. package/templates/waitlist/app/dashboard/page.tsx +17 -16
  674. package/templates/waitlist/app/icon.svg +2 -0
  675. package/templates/waitlist/app/login/page.tsx +14 -14
  676. package/templates/waitlist/app.ts +6 -6
  677. package/templates/waitlist/functions/joinWaitlist.ts +6 -18
  678. package/templates/waitlist/functions/seedDemo.ts +32 -0
  679. package/templates/waitlist/lib/demo.ts +94 -0
  680. package/templates/waitlist/lib/launch.ts +19 -0
  681. package/templates/waitlist/lib/site.config.ts +14 -9
  682. package/templates/waitlist/lib/stats.ts +35 -0
  683. package/templates/waitlist/public/favicon.ico +0 -0
  684. package/templates/waitlist/tests/counter.test.ts +107 -0
  685. package/templates/waitlist/tests/live-count.test.tsx +48 -0
  686. package/templates/ai-chat/tests/example.test.ts +0 -12
  687. package/templates/backend/consumer/apps/api/functions/feed.ts +0 -57
  688. package/templates/backend/consumer/apps/api/functions/profilePosts.ts +0 -17
  689. package/templates/backend/consumer/apps/api/functions/toggleLike.ts +0 -48
  690. package/templates/backend/consumer/apps/api/schema.ts +0 -143
  691. package/templates/chat/functions/_keep.ts +0 -13
  692. package/templates/chat/tests/example.test.ts +0 -12
  693. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileSetupView.swift +0 -68
  694. package/templates/marketplace/client/LiveTicker.tsx +0 -116
  695. package/templates/marketplace/client/ScrollToListingsLink.tsx +0 -29
  696. package/templates/marketplace/public/images/marketplace-hero.webp +0 -0
@@ -0,0 +1,107 @@
1
+ // A small syntax highlighter for code blocks in replies. It splits code into
2
+ // comment, string, number, keyword, and plain tokens with one pass per line
3
+ // set. It does not parse the language; it colors what most languages share.
4
+
5
+ export type TokenKind = "comment" | "string" | "number" | "keyword" | "fn" | "plain";
6
+
7
+ export interface Token {
8
+ kind: TokenKind;
9
+ text: string;
10
+ }
11
+
12
+ const KEYWORDS: Record<string, string[]> = {
13
+ js: "const let var function return if else for while do switch case break continue new class extends import export from default async await try catch finally throw typeof instanceof in of this null undefined true false void yield interface type enum implements public private protected readonly as satisfies keyof".split(" "),
14
+ py: "def return if elif else for while in not and or is import from as class try except finally raise with lambda yield pass break continue None True False async await global nonlocal self".split(" "),
15
+ sql: "select from where and or not insert into values update set delete create table index on join left right inner outer group by order having limit offset as distinct null is in exists primary key references unique default begin commit returning with case when then else end".split(" "),
16
+ rust: "fn let mut pub use mod struct enum impl trait for in if else match loop while return self Self crate super where as async await move ref const static true false Some None Ok Err".split(" "),
17
+ go: "func package import var const type struct interface map chan go defer return if else for range switch case default break continue nil true false".split(" "),
18
+ sh: "if then else elif fi for in do done while case esac function return export local echo cd set".split(" "),
19
+ };
20
+
21
+ const ALIASES: Record<string, string> = {
22
+ js: "js", jsx: "js", ts: "js", tsx: "js", javascript: "js", typescript: "js", json: "js",
23
+ py: "py", python: "py",
24
+ sql: "sql", postgres: "sql", postgresql: "sql", sqlite: "sql",
25
+ rs: "rust", rust: "rust",
26
+ go: "go", golang: "go",
27
+ sh: "sh", bash: "sh", shell: "sh", zsh: "sh", console: "sh",
28
+ };
29
+
30
+ function family(lang: string): string | null {
31
+ return ALIASES[lang.toLowerCase()] ?? null;
32
+ }
33
+
34
+ export function highlight(code: string, lang: string): Token[] {
35
+ const fam = family(lang);
36
+ if (!fam) return [{ kind: "plain", text: code }];
37
+ const caseInsensitive = fam === "sql";
38
+ const words = new Set(KEYWORDS[fam].map((w) => (caseInsensitive ? w.toLowerCase() : w)));
39
+ const lineComment = fam === "py" || fam === "sh" ? "#" : fam === "sql" ? "--" : "//";
40
+ const blockComments = fam === "js" || fam === "rust" || fam === "go" || fam === "sql";
41
+
42
+ const tokens: Token[] = [];
43
+ let plain = "";
44
+ const push = (kind: TokenKind, text: string) => {
45
+ if (plain) {
46
+ tokens.push({ kind: "plain", text: plain });
47
+ plain = "";
48
+ }
49
+ tokens.push({ kind, text });
50
+ };
51
+
52
+ let i = 0;
53
+ while (i < code.length) {
54
+ const rest = code.slice(i);
55
+
56
+ if (rest.startsWith(lineComment)) {
57
+ const end = code.indexOf("\n", i);
58
+ const stop = end === -1 ? code.length : end;
59
+ push("comment", code.slice(i, stop));
60
+ i = stop;
61
+ continue;
62
+ }
63
+ if (blockComments && rest.startsWith("/*")) {
64
+ const end = code.indexOf("*/", i + 2);
65
+ const stop = end === -1 ? code.length : end + 2;
66
+ push("comment", code.slice(i, stop));
67
+ i = stop;
68
+ continue;
69
+ }
70
+
71
+ const ch = code[i];
72
+ if (ch === '"' || ch === "'" || (ch === "`" && fam === "js")) {
73
+ let j = i + 1;
74
+ while (j < code.length && code[j] !== ch) {
75
+ if (code[j] === "\\") j++;
76
+ if (code[j] === "\n" && ch !== "`") break;
77
+ j++;
78
+ }
79
+ push("string", code.slice(i, Math.min(j + 1, code.length)));
80
+ i = Math.min(j + 1, code.length);
81
+ continue;
82
+ }
83
+
84
+ const num = rest.match(/^\d[\d_]*(\.\d+)?/);
85
+ if (num && (i === 0 || !/[\w$]/.test(code[i - 1]))) {
86
+ push("number", num[0]);
87
+ i += num[0].length;
88
+ continue;
89
+ }
90
+
91
+ const word = rest.match(/^[A-Za-z_$][\w$]*/);
92
+ if (word) {
93
+ const w = word[0];
94
+ const key = caseInsensitive ? w.toLowerCase() : w;
95
+ if (words.has(key)) push("keyword", w);
96
+ else if (code[i + w.length] === "(") push("fn", w);
97
+ else plain += w;
98
+ i += w.length;
99
+ continue;
100
+ }
101
+
102
+ plain += ch;
103
+ i++;
104
+ }
105
+ if (plain) tokens.push({ kind: "plain", text: plain });
106
+ return tokens;
107
+ }
@@ -0,0 +1,317 @@
1
+ // A small Markdown parser for assistant replies. It returns a plain tree that
2
+ // components/chat/markdown.tsx renders as React elements, so model output is
3
+ // never injected as HTML. It covers what models emit: headings, paragraphs,
4
+ // bullet and numbered lists (one nesting level), block quotes, fenced code,
5
+ // tables, horizontal rules, and inline code, bold, italic, strikethrough, and
6
+ // links. An unclosed code fence runs to the end of the text, which keeps a
7
+ // reply readable while it streams.
8
+
9
+ export type Inline =
10
+ | { type: "text"; text: string }
11
+ | { type: "code"; text: string }
12
+ | { type: "strong"; children: Inline[] }
13
+ | { type: "em"; children: Inline[] }
14
+ | { type: "del"; children: Inline[] }
15
+ | { type: "link"; href: string; children: Inline[] };
16
+
17
+ export interface ListItem {
18
+ children: Inline[];
19
+ sublist?: { ordered: boolean; start: number; items: ListItem[] };
20
+ }
21
+
22
+ export type Block =
23
+ | { type: "heading"; level: 1 | 2 | 3 | 4; children: Inline[] }
24
+ | { type: "paragraph"; children: Inline[] }
25
+ | { type: "code"; lang: string; code: string; closed: boolean }
26
+ | { type: "list"; ordered: boolean; start: number; items: ListItem[] }
27
+ | { type: "quote"; children: Block[] }
28
+ | { type: "table"; align: ("left" | "center" | "right" | null)[]; head: Inline[][]; rows: Inline[][][] }
29
+ | { type: "hr" };
30
+
31
+ const FENCE = /^\s{0,3}(`{3,}|~{3,})\s*([\w+#.-]*)/;
32
+ const HEADING = /^\s{0,3}(#{1,6})\s+(.*?)\s*#*\s*$/;
33
+ const BULLET = /^(\s*)[-*+]\s+(.*)$/;
34
+ const ORDERED = /^(\s*)(\d{1,9})[.)]\s+(.*)$/;
35
+ const HR = /^\s{0,3}([-*_])(\s*\1){2,}\s*$/;
36
+ const QUOTE = /^\s{0,3}>\s?(.*)$/;
37
+ const TABLE_SEP = /^\s*\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)*\|?\s*$/;
38
+
39
+ function isBlockStart(line: string): boolean {
40
+ return (
41
+ FENCE.test(line) ||
42
+ HEADING.test(line) ||
43
+ BULLET.test(line) ||
44
+ ORDERED.test(line) ||
45
+ HR.test(line) ||
46
+ QUOTE.test(line)
47
+ );
48
+ }
49
+
50
+ function splitRow(line: string): string[] {
51
+ let s = line.trim();
52
+ if (s.startsWith("|")) s = s.slice(1);
53
+ if (s.endsWith("|") && !s.endsWith("\\|")) s = s.slice(0, -1);
54
+ return s.split(/(?<!\\)\|/).map((c) => c.trim().replace(/\\\|/g, "|"));
55
+ }
56
+
57
+ export function parseMarkdown(src: string): Block[] {
58
+ const lines = src.replace(/\r\n?/g, "\n").split("\n");
59
+ const blocks: Block[] = [];
60
+ let i = 0;
61
+
62
+ while (i < lines.length) {
63
+ const line = lines[i];
64
+
65
+ if (line.trim() === "") {
66
+ i++;
67
+ continue;
68
+ }
69
+
70
+ const fence = line.match(FENCE);
71
+ if (fence) {
72
+ const marker = fence[1];
73
+ const code: string[] = [];
74
+ let closed = false;
75
+ i++;
76
+ while (i < lines.length) {
77
+ const l = lines[i];
78
+ if (l.trim().startsWith(marker[0].repeat(marker.length)) && l.trim().replace(/[`~]/g, "") === "") {
79
+ closed = true;
80
+ i++;
81
+ break;
82
+ }
83
+ code.push(l);
84
+ i++;
85
+ }
86
+ blocks.push({ type: "code", lang: fence[2] ?? "", code: code.join("\n"), closed });
87
+ continue;
88
+ }
89
+
90
+ const heading = line.match(HEADING);
91
+ if (heading) {
92
+ const level = Math.min(heading[1].length, 4) as 1 | 2 | 3 | 4;
93
+ blocks.push({ type: "heading", level, children: parseInline(heading[2]) });
94
+ i++;
95
+ continue;
96
+ }
97
+
98
+ if (HR.test(line)) {
99
+ blocks.push({ type: "hr" });
100
+ i++;
101
+ continue;
102
+ }
103
+
104
+ if (QUOTE.test(line)) {
105
+ const inner: string[] = [];
106
+ while (i < lines.length && QUOTE.test(lines[i])) {
107
+ inner.push(lines[i].match(QUOTE)![1]);
108
+ i++;
109
+ }
110
+ blocks.push({ type: "quote", children: parseMarkdown(inner.join("\n")) });
111
+ continue;
112
+ }
113
+
114
+ if (BULLET.test(line) || ORDERED.test(line)) {
115
+ const { block, next } = parseList(lines, i);
116
+ blocks.push(block);
117
+ i = next;
118
+ continue;
119
+ }
120
+
121
+ if (line.includes("|") && i + 1 < lines.length && TABLE_SEP.test(lines[i + 1])) {
122
+ const head = splitRow(line);
123
+ const align = splitRow(lines[i + 1]).map((c) => {
124
+ const left = c.startsWith(":");
125
+ const right = c.endsWith(":");
126
+ return left && right ? "center" : right ? "right" : left ? "left" : null;
127
+ });
128
+ i += 2;
129
+ const rows: Inline[][][] = [];
130
+ while (i < lines.length && lines[i].includes("|") && lines[i].trim() !== "") {
131
+ const cells = splitRow(lines[i]);
132
+ rows.push(head.map((_, c) => parseInline(cells[c] ?? "")));
133
+ i++;
134
+ }
135
+ blocks.push({ type: "table", align, head: head.map(parseInline), rows });
136
+ continue;
137
+ }
138
+
139
+ const para: string[] = [];
140
+ while (i < lines.length && lines[i].trim() !== "" && !(para.length > 0 && isBlockStart(lines[i]))) {
141
+ para.push(lines[i].trim());
142
+ i++;
143
+ }
144
+ blocks.push({ type: "paragraph", children: parseInline(para.join("\n")) });
145
+ }
146
+
147
+ return blocks;
148
+ }
149
+
150
+ function parseList(lines: string[], start: number): { block: Block; next: number } {
151
+ const first = lines[start];
152
+ const ordered = ORDERED.test(first) && !BULLET.test(first);
153
+ const baseIndent = (first.match(/^(\s*)/)?.[1] ?? "").length;
154
+ const startNum = ordered ? Number(first.match(ORDERED)![2]) : 1;
155
+ const items: ListItem[] = [];
156
+ let i = start;
157
+
158
+ while (i < lines.length) {
159
+ const line = lines[i];
160
+ if (line.trim() === "") {
161
+ // A blank line inside a list continues it only when the next line is
162
+ // another item at the same level or deeper.
163
+ const nxt = lines[i + 1];
164
+ if (nxt !== undefined && (BULLET.test(nxt) || ORDERED.test(nxt))) {
165
+ i++;
166
+ continue;
167
+ }
168
+ break;
169
+ }
170
+ const m = ordered ? line.match(ORDERED) : line.match(BULLET);
171
+ const other = ordered ? line.match(BULLET) : line.match(ORDERED);
172
+ const indent = (line.match(/^(\s*)/)?.[1] ?? "").length;
173
+
174
+ if (indent > baseIndent && (m || other) && items.length > 0) {
175
+ const { block, next } = parseList(lines, i);
176
+ if (block.type === "list") {
177
+ items[items.length - 1].sublist = { ordered: block.ordered, start: block.start, items: block.items };
178
+ }
179
+ i = next;
180
+ continue;
181
+ }
182
+ if (indent < baseIndent) break;
183
+ if (m && indent === baseIndent) {
184
+ const text = ordered ? m[3] : m[2];
185
+ items.push({ children: parseInline(text) });
186
+ i++;
187
+ continue;
188
+ }
189
+ if (other && indent === baseIndent) break;
190
+ if (isBlockStart(line) && indent <= baseIndent) break;
191
+ // Lazy continuation of the previous item's text.
192
+ if (items.length > 0) {
193
+ items[items.length - 1].children.push({ type: "text", text: "\n" }, ...parseInline(line.trim()));
194
+ }
195
+ i++;
196
+ }
197
+ return { block: { type: "list", ordered, start: startNum, items }, next: i };
198
+ }
199
+
200
+ /* -------------------------------- inline -------------------------------- */
201
+
202
+ // Links render only for these schemes. Anything else (javascript:, data:,
203
+ // vbscript:) renders as plain text.
204
+ export function safeHref(href: string): string | null {
205
+ const h = href.trim();
206
+ if (/^(https?:|mailto:)/i.test(h)) return h;
207
+ if (h.startsWith("/") && !h.startsWith("//")) return h;
208
+ if (h.startsWith("#")) return h;
209
+ return null;
210
+ }
211
+
212
+ export function parseInline(text: string): Inline[] {
213
+ const out: Inline[] = [];
214
+ let buf = "";
215
+ let i = 0;
216
+
217
+ const flush = () => {
218
+ if (buf) {
219
+ out.push({ type: "text", text: buf });
220
+ buf = "";
221
+ }
222
+ };
223
+
224
+ while (i < text.length) {
225
+ const ch = text[i];
226
+
227
+ if (ch === "\\" && i + 1 < text.length && /[\\`*_~[\]()#|>-]/.test(text[i + 1])) {
228
+ buf += text[i + 1];
229
+ i += 2;
230
+ continue;
231
+ }
232
+
233
+ if (ch === "`") {
234
+ let ticks = 1;
235
+ while (text[i + ticks] === "`") ticks++;
236
+ const marker = "`".repeat(ticks);
237
+ const end = text.indexOf(marker, i + ticks);
238
+ if (end !== -1) {
239
+ flush();
240
+ out.push({ type: "code", text: text.slice(i + ticks, end).replace(/^ (.*) $/, "$1") });
241
+ i = end + ticks;
242
+ continue;
243
+ }
244
+ }
245
+
246
+ if ((ch === "*" || ch === "_") && text[i + 1] === ch) {
247
+ const marker = ch + ch;
248
+ const end = text.indexOf(marker, i + 2);
249
+ if (end > i + 2) {
250
+ flush();
251
+ out.push({ type: "strong", children: parseInline(text.slice(i + 2, end)) });
252
+ i = end + 2;
253
+ continue;
254
+ }
255
+ }
256
+
257
+ if (ch === "~" && text[i + 1] === "~") {
258
+ const end = text.indexOf("~~", i + 2);
259
+ if (end > i + 2) {
260
+ flush();
261
+ out.push({ type: "del", children: parseInline(text.slice(i + 2, end)) });
262
+ i = end + 2;
263
+ continue;
264
+ }
265
+ }
266
+
267
+ if ((ch === "*" || ch === "_") && text[i + 1] !== " " && text[i + 1] !== undefined) {
268
+ // `_` only opens emphasis at a word boundary, so snake_case stays text.
269
+ const boundary = ch === "*" || i === 0 || /[\s(]/.test(text[i - 1]);
270
+ let end = text.indexOf(ch, i + 1);
271
+ while (end !== -1 && text[end + 1] === ch) end = text.indexOf(ch, end + 2);
272
+ if (boundary && end > i + 1 && text[end - 1] !== " ") {
273
+ flush();
274
+ out.push({ type: "em", children: parseInline(text.slice(i + 1, end)) });
275
+ i = end + 1;
276
+ continue;
277
+ }
278
+ }
279
+
280
+ if (ch === "[") {
281
+ const close = text.indexOf("]", i + 1);
282
+ if (close !== -1 && text[close + 1] === "(") {
283
+ const end = text.indexOf(")", close + 2);
284
+ if (end !== -1) {
285
+ const label = text.slice(i + 1, close);
286
+ const href = safeHref(text.slice(close + 2, end));
287
+ flush();
288
+ if (href) out.push({ type: "link", href, children: parseInline(label) });
289
+ else out.push(...parseInline(label));
290
+ i = end + 1;
291
+ continue;
292
+ }
293
+ }
294
+ }
295
+
296
+ if ((ch === "h" || ch === "H") && /^https?:\/\/[^\s<]+/i.test(text.slice(i)) && (i === 0 || /[\s(]/.test(text[i - 1]))) {
297
+ const m = text.slice(i).match(/^https?:\/\/[^\s<]+/i)!;
298
+ let url = m[0];
299
+ while (/[.,;:!?)]$/.test(url)) url = url.slice(0, -1);
300
+ flush();
301
+ out.push({ type: "link", href: url, children: [{ type: "text", text: url }] });
302
+ i += url.length;
303
+ continue;
304
+ }
305
+
306
+ buf += ch;
307
+ i++;
308
+ }
309
+ flush();
310
+ return out;
311
+ }
312
+
313
+ export function inlineText(nodes: Inline[]): string {
314
+ return nodes
315
+ .map((n) => (n.type === "text" || n.type === "code" ? n.text : inlineText(n.children)))
316
+ .join("");
317
+ }
@@ -0,0 +1,38 @@
1
+ // Whether the server has a model provider configured, derived from the same
2
+ // environment variables Pylon reads for `ctx.llm`:
3
+ //
4
+ // PYLON_LLM_PROVIDER (or PYLON_AI_PROVIDER) = "anthropic" | "openai"
5
+ // ANTHROPIC_API_KEY / OPENAI_API_KEY (or PYLON_AI_API_KEY)
6
+ //
7
+ // With no provider set, an ANTHROPIC_API_KEY selects Anthropic and an
8
+ // OPENAI_API_KEY selects OpenAI. The result carries no key material.
9
+
10
+ export type ProviderName = "anthropic" | "openai";
11
+
12
+ export interface ProviderStatus {
13
+ configured: boolean;
14
+ provider: ProviderName | null;
15
+ }
16
+
17
+ type Env = Record<string, string | undefined>;
18
+
19
+ function present(env: Env, key: string): boolean {
20
+ const v = env[key];
21
+ return typeof v === "string" && v.trim().length > 0;
22
+ }
23
+
24
+ export function providerStatus(env: Env): ProviderStatus {
25
+ const explicit = (env.PYLON_LLM_PROVIDER || env.PYLON_AI_PROVIDER || "").trim();
26
+ if (explicit === "anthropic") {
27
+ const ok = present(env, "ANTHROPIC_API_KEY") || present(env, "PYLON_AI_API_KEY");
28
+ return { configured: ok, provider: "anthropic" };
29
+ }
30
+ if (explicit === "openai") {
31
+ const ok = present(env, "OPENAI_API_KEY") || present(env, "PYLON_AI_API_KEY");
32
+ return { configured: ok, provider: "openai" };
33
+ }
34
+ if (explicit !== "") return { configured: false, provider: null };
35
+ if (present(env, "ANTHROPIC_API_KEY")) return { configured: true, provider: "anthropic" };
36
+ if (present(env, "OPENAI_API_KEY")) return { configured: true, provider: "openai" };
37
+ return { configured: false, provider: null };
38
+ }
@@ -1,8 +1,8 @@
1
- // Brand-specific copy and settings live here. The layout, chat UI,
2
- // create-pylon scaffolder, and Mast all read this file.
1
+ // Brand-specific copy and settings. The layout, the chat UI, the server
2
+ // functions (system prompt, model allowlist, limits), and the scaffolder read
3
+ // this file. Replace the values and keep the shape.
3
4
  //
4
- // Colors live here (applied as CSS variables on <html> in app/layout.tsx).
5
- // Fictional demo copy. Replace the values and keep the shape.
5
+ // Colors are applied as CSS variables on <html> in app/layout.tsx.
6
6
 
7
7
  /* ----------------------------- types ----------------------------- */
8
8
 
@@ -22,27 +22,33 @@ export type BaseConfig = {
22
22
  seo: { title: string; description: string };
23
23
  };
24
24
 
25
- // A selectable model. `id` is what's sent to /api/ai/stream; `provider` is just
26
- // a label for the picker. Which models are actually accepted is gated server-side
27
- // by PYLON_AI_MODELS_ALLOWED (+ the configured provider / gateway) — see README.
28
- export type ChatModel = { id: string; label: string; provider: string };
25
+ // A selectable model. `id` is sent to the provider; `label` and `note` are
26
+ // shown in the picker. Only ids listed here are accepted by the `respond`
27
+ // function, and app.ts passes the same list to `llm({ allowedModels })`.
28
+ export type ChatModel = { id: string; label: string; note: string };
29
+
30
+ export type Suggestion = { title: string; prompt: string };
29
31
 
30
32
  export type ChatConfig = BaseConfig & {
31
33
  chat: {
32
- assistantName: string;
33
- // Prepended as a system message on every request — sets the assistant's
34
- // persona. Edit to retune the assistant without touching code.
34
+ // Sent as the system prompt on every request.
35
35
  systemPrompt: string;
36
36
  emptyHeadline: string;
37
- emptySubcopy: string;
38
37
  inputPlaceholder: string;
39
- // Starter prompts shown on the empty state; clicking one sends it.
40
- suggestions: string[];
41
- // The model picker. Curate to your setup: a single provider's models, or —
42
- // with an OpenRouter-style gateway (PYLON_AI_PROVIDER=custom) — models across
43
- // providers in one list. The selected id is sent as `model` per request.
38
+ // Starter prompts on the empty state. Picking one sends `prompt`.
39
+ suggestions: Suggestion[];
44
40
  models: ChatModel[];
45
41
  defaultModel: string;
42
+ // Upper bound on tokens per reply.
43
+ maxOutputTokens: number;
44
+ // Messages longer than this are refused by the server.
45
+ maxInputChars: number;
46
+ // Replies per rolling hour. `guest` and `user` are per person;
47
+ // `allGuests` caps every guest session together, since anyone can start a
48
+ // new guest session.
49
+ repliesPerHour: { guest: number; user: number; allGuests: number };
50
+ // Model ids a guest session may use. Accounts may use every model.
51
+ guestModels: string[];
46
52
  };
47
53
  };
48
54
 
@@ -54,7 +60,7 @@ export const siteConfig: ChatConfig = {
54
60
  letter: "L",
55
61
  domain: "lumen.chat",
56
62
  email: "hello@lumen.example",
57
- footerBlurb: "A fast, streaming AI assistant built on Pylon.",
63
+ footerBlurb: "A streaming AI assistant built on Pylon.",
58
64
  copyrightName: "Lumen",
59
65
  socials: [
60
66
  {
@@ -65,38 +71,48 @@ export const siteConfig: ChatConfig = {
65
71
  ],
66
72
  },
67
73
 
68
- colors: { brand: "#6d28d9", brandSoft: "#ede9fe", paper: "#faf9fc" },
74
+ colors: { brand: "#1d5c4d", brandSoft: "#e3eeea", paper: "#f4f1ea" },
69
75
 
70
76
  seo: {
71
- title: "Lumen — a fast streaming AI assistant.",
77
+ title: "Lumen, a streaming AI assistant",
72
78
  description:
73
- "A streaming AI chat app built on Pylon. Conversations sync across your tabs and devices in realtime; your API key never leaves the server.",
79
+ "Ask questions and read answers as they stream. Conversations sync across your tabs and devices, and your API key stays on the server.",
74
80
  },
75
81
 
76
82
  chat: {
77
- assistantName: "Lumen",
78
83
  systemPrompt:
79
- "You are Lumen, a friendly, concise AI assistant. Answer clearly and get to the point. Use Markdown when it helps.",
80
- emptyHeadline: "How can I help?",
81
- emptySubcopy: "Ask anything. Your conversations are saved and stay in sync across your tabs.",
82
- inputPlaceholder: "Message Lumen…",
84
+ "You are Lumen, a helpful AI assistant. Answer clearly and get to the point. Use Markdown: short paragraphs, lists where they help, and fenced code blocks with a language tag for code.",
85
+ emptyHeadline: "What can I help with?",
86
+ inputPlaceholder: "Message Lumen",
83
87
  suggestions: [
84
- "Explain WebSockets like I'm five.",
85
- "Draft a friendly out-of-office reply.",
86
- "Give me 5 dinner ideas using chicken and rice.",
87
- "What's the difference between SSR and SSG?",
88
+ {
89
+ title: "Explain a concept",
90
+ prompt: "Explain how WebSockets differ from Server-Sent Events, and when to pick each.",
91
+ },
92
+ {
93
+ title: "Write code",
94
+ prompt: "Write a TypeScript function that retries a fetch with exponential backoff and jitter.",
95
+ },
96
+ {
97
+ title: "Edit my writing",
98
+ prompt: "Rewrite this to be shorter and clearer: \"We are reaching out to let you know that we have made some changes to our pricing.\"",
99
+ },
100
+ {
101
+ title: "Plan something",
102
+ prompt: "Plan a 3-day trip to Lisbon for someone who likes food markets and walking.",
103
+ },
88
104
  ],
89
- // Current Claude models (verify the ids for your provider before shipping —
90
- // model names move fast). Whichever you keep here must be in
91
- // PYLON_AI_MODELS_ALLOWED for switching to work (see .env.example). To offer
92
- // models from OTHER providers (OpenAI, Google, …) in the same list, route
93
- // through an OpenRouter-style gateway (PYLON_AI_PROVIDER=custom +
94
- // PYLON_AI_BASE_URL) and use that gateway's slugs here.
105
+ // Verify the ids for your provider before shipping. Every id here is
106
+ // accepted by the server; remove the ones you do not want to pay for.
95
107
  models: [
96
- { id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", provider: "Anthropic" },
97
- { id: "claude-opus-4-8", label: "Claude Opus 4.8", provider: "Anthropic" },
98
- { id: "claude-haiku-4-5", label: "Claude Haiku 4.5", provider: "Anthropic" },
108
+ { id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", note: "Balanced speed and quality" },
109
+ { id: "claude-opus-4-8", label: "Claude Opus 4.8", note: "Best for hard problems" },
110
+ { id: "claude-haiku-4-5", label: "Claude Haiku 4.5", note: "Fastest replies" },
99
111
  ],
100
112
  defaultModel: "claude-sonnet-4-6",
113
+ maxOutputTokens: 4096,
114
+ maxInputChars: 12000,
115
+ repliesPerHour: { guest: 20, user: 100, allGuests: 300 },
116
+ guestModels: ["claude-sonnet-4-6", "claude-haiku-4-5"],
101
117
  },
102
118
  };