@pylonsync/create-pylon 0.19.0 → 0.20.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 (675) hide show
  1. package/bin/create-pylon.js +30 -7
  2. package/package.json +1 -1
  3. package/templates/agency/.env.example +7 -0
  4. package/templates/agency/README.md +28 -3
  5. package/templates/agency/app/(marketing)/contact-form.tsx +20 -18
  6. package/templates/agency/app/(marketing)/page.tsx +3 -3
  7. package/templates/agency/app/(marketing)/work/page.tsx +3 -3
  8. package/templates/agency/app/auth-form.tsx +4 -4
  9. package/templates/agency/app/dashboard/dashboard-client.tsx +110 -64
  10. package/templates/agency/app/dashboard/page.tsx +14 -16
  11. package/templates/agency/app/icon.svg +3 -0
  12. package/templates/agency/app/login/page.tsx +12 -14
  13. package/templates/agency/components/marketing.tsx +12 -5
  14. package/templates/agency/functions/seedStudioBackoffice.ts +42 -11
  15. package/templates/agency/lib/agency.ts +22 -0
  16. package/templates/agency/lib/demo.ts +118 -0
  17. package/templates/agency/lib/site.config.ts +19 -13
  18. package/templates/agency/public/favicon.ico +0 -0
  19. package/templates/agency/tests/agency.test.ts +57 -0
  20. package/templates/ai-chat/.env.example +13 -27
  21. package/templates/ai-chat/README.md +53 -60
  22. package/templates/ai-chat/app/(chat)/c/[id]/page.tsx +19 -0
  23. package/templates/ai-chat/app/(chat)/chat-client.tsx +657 -622
  24. package/templates/ai-chat/app/(chat)/layout.tsx +6 -43
  25. package/templates/ai-chat/app/(chat)/not-found.tsx +6 -10
  26. package/templates/ai-chat/app/(chat)/page.tsx +7 -11
  27. package/templates/ai-chat/app/auth-form.tsx +45 -38
  28. package/templates/ai-chat/app/error.tsx +9 -12
  29. package/templates/ai-chat/app/globals.css +464 -102
  30. package/templates/ai-chat/app/layout.tsx +11 -19
  31. package/templates/ai-chat/app/login/page.tsx +39 -24
  32. package/templates/ai-chat/app.ts +118 -43
  33. package/templates/ai-chat/components/chat/composer.tsx +193 -0
  34. package/templates/ai-chat/components/chat/empty-state.tsx +65 -0
  35. package/templates/ai-chat/components/chat/icons.tsx +198 -0
  36. package/templates/ai-chat/components/chat/markdown.tsx +164 -0
  37. package/templates/ai-chat/components/chat/message.tsx +183 -0
  38. package/templates/ai-chat/components/chat/setup.tsx +71 -0
  39. package/templates/ai-chat/components/chat/sidebar.tsx +288 -0
  40. package/templates/ai-chat/functions/_beginTurn.ts +145 -0
  41. package/templates/ai-chat/functions/_finishTurn.ts +55 -0
  42. package/templates/ai-chat/functions/assistantStatus.ts +13 -0
  43. package/templates/ai-chat/functions/claimGuestHistory.ts +39 -0
  44. package/templates/ai-chat/functions/createConversation.ts +28 -0
  45. package/templates/ai-chat/functions/deleteConversation.ts +15 -20
  46. package/templates/ai-chat/functions/prepareGuestClaim.ts +32 -0
  47. package/templates/ai-chat/functions/renameConversation.ts +19 -0
  48. package/templates/ai-chat/functions/respond.ts +88 -0
  49. package/templates/ai-chat/functions/seedExamples.ts +46 -0
  50. package/templates/ai-chat/functions/stopResponse.ts +30 -0
  51. package/templates/ai-chat/lib/brand-icon.ts +7 -0
  52. package/templates/ai-chat/lib/chat.ts +277 -0
  53. package/templates/ai-chat/lib/claim.ts +15 -0
  54. package/templates/ai-chat/lib/examples.ts +179 -0
  55. package/templates/ai-chat/lib/highlight.ts +107 -0
  56. package/templates/ai-chat/lib/markdown.ts +317 -0
  57. package/templates/ai-chat/lib/provider.ts +38 -0
  58. package/templates/ai-chat/lib/site.config.ts +55 -39
  59. package/templates/ai-chat/tests/chat.test.ts +174 -0
  60. package/templates/ai-chat/tests/components.test.tsx +57 -0
  61. package/templates/ai-chat/tests/markdown.test.ts +88 -0
  62. package/templates/ai-chat/tests/provider.test.ts +32 -0
  63. package/templates/backend/consumer/apps/api/app/layout.tsx +33 -0
  64. package/templates/backend/consumer/apps/api/app/page.tsx +54 -0
  65. package/templates/backend/consumer/apps/api/app.ts +166 -0
  66. package/templates/backend/consumer/apps/api/functions/addComment.ts +24 -0
  67. package/templates/backend/consumer/apps/api/functions/createPost.ts +19 -36
  68. package/templates/backend/consumer/apps/api/functions/deletePost.ts +15 -13
  69. package/templates/backend/consumer/apps/api/functions/myProfile.ts +5 -8
  70. package/templates/backend/consumer/apps/api/functions/seedDemo.ts +95 -0
  71. package/templates/backend/consumer/apps/api/functions/setFollow.ts +36 -0
  72. package/templates/backend/consumer/apps/api/functions/setLike.ts +36 -0
  73. package/templates/backend/consumer/apps/api/functions/upsertProfile.ts +43 -37
  74. package/templates/backend/consumer/apps/api/lib/seed.ts +89 -0
  75. package/templates/backend/consumer/apps/api/lib/social.ts +50 -0
  76. package/templates/backend/consumer/apps/api/package.json +8 -2
  77. package/templates/backend/consumer/apps/api/public/images/posts/arch.jpg +0 -0
  78. package/templates/backend/consumer/apps/api/public/images/posts/coffee.jpg +0 -0
  79. package/templates/backend/consumer/apps/api/public/images/posts/dog.jpg +0 -0
  80. package/templates/backend/consumer/apps/api/public/images/posts/lisbon.jpg +0 -0
  81. package/templates/backend/consumer/apps/api/public/images/posts/ramen.jpg +0 -0
  82. package/templates/backend/consumer/apps/api/public/images/posts/run.jpg +0 -0
  83. package/templates/backend/consumer/apps/api/public/images/posts/sunset.jpg +0 -0
  84. package/templates/backend/consumer/apps/api/tsconfig.json +12 -2
  85. package/templates/chat/README.md +43 -21
  86. package/templates/chat/app/chat-client.tsx +495 -85
  87. package/templates/chat/app/error.tsx +1 -1
  88. package/templates/chat/app/globals.css +170 -54
  89. package/templates/chat/app/layout.tsx +12 -9
  90. package/templates/chat/app/not-found.tsx +4 -2
  91. package/templates/chat/app/page.tsx +9 -19
  92. package/templates/chat/app.ts +96 -17
  93. package/templates/chat/components/chat/avatar.tsx +45 -0
  94. package/templates/chat/components/chat/composer.tsx +110 -0
  95. package/templates/chat/components/chat/message-list.tsx +285 -0
  96. package/templates/chat/components/chat/sidebar.tsx +190 -0
  97. package/templates/chat/functions/joinChat.ts +83 -0
  98. package/templates/chat/functions/renameMember.ts +25 -0
  99. package/templates/chat/lib/chat.ts +188 -0
  100. package/templates/chat/lib/seed.ts +78 -0
  101. package/templates/chat/tests/chat.test.ts +159 -0
  102. package/templates/chat/tests/composer.test.tsx +54 -0
  103. package/templates/consumer/README.md +3 -3
  104. package/templates/consumer/app/globals.css +10 -3
  105. package/templates/consumer/app/icon.svg +1 -0
  106. package/templates/consumer/components/social/avatar.tsx +25 -11
  107. package/templates/consumer/functions/seedFeed.ts +3 -3
  108. package/templates/consumer/lib/seed.ts +43 -85
  109. package/templates/consumer/public/favicon.ico +0 -0
  110. package/templates/consumer/public/images/posts/arch.jpg +0 -0
  111. package/templates/consumer/public/images/posts/coffee.jpg +0 -0
  112. package/templates/consumer/public/images/posts/dog.jpg +0 -0
  113. package/templates/consumer/public/images/posts/lisbon.jpg +0 -0
  114. package/templates/consumer/public/images/posts/ramen.jpg +0 -0
  115. package/templates/consumer/public/images/posts/run.jpg +0 -0
  116. package/templates/consumer/public/images/posts/sunset.jpg +0 -0
  117. package/templates/consumer/tests/seed.test.ts +39 -0
  118. package/templates/creator/.env.example +7 -0
  119. package/templates/creator/README.md +24 -5
  120. package/templates/creator/app/(marketing)/newsletter-signup.tsx +33 -12
  121. package/templates/creator/app/auth-form.tsx +7 -7
  122. package/templates/creator/app/dashboard/dashboard-client.tsx +137 -100
  123. package/templates/creator/app/dashboard/page.tsx +18 -18
  124. package/templates/creator/app/icon.svg +2 -0
  125. package/templates/creator/app/login/page.tsx +14 -14
  126. package/templates/creator/app.ts +4 -4
  127. package/templates/creator/functions/seedDemo.ts +32 -0
  128. package/templates/creator/functions/subscribe.ts +4 -15
  129. package/templates/creator/lib/demo.ts +94 -0
  130. package/templates/creator/lib/site.config.ts +15 -10
  131. package/templates/creator/lib/stats.ts +35 -0
  132. package/templates/creator/public/favicon.ico +0 -0
  133. package/templates/creator/tests/counter.test.ts +92 -0
  134. package/templates/creator/tests/live-count.test.tsx +45 -0
  135. package/templates/crm/README.md +22 -1
  136. package/templates/crm/app/apple-icon.png +0 -0
  137. package/templates/crm/app/companies/companies-view.tsx +32 -14
  138. package/templates/crm/app/companies/page.tsx +2 -1
  139. package/templates/crm/app/contacts/contacts-view.tsx +34 -10
  140. package/templates/crm/app/contacts/page.tsx +2 -1
  141. package/templates/crm/app/deals/[id]/deal-view.tsx +137 -98
  142. package/templates/crm/app/deals/[id]/page.tsx +2 -1
  143. package/templates/crm/app/globals.css +29 -14
  144. package/templates/crm/app/icon.svg +1 -0
  145. package/templates/crm/app/layout.tsx +7 -5
  146. package/templates/crm/app/page.tsx +2 -1
  147. package/templates/crm/app/pipeline-view.tsx +5 -5
  148. package/templates/crm/app/workspace.tsx +29 -17
  149. package/templates/crm/app.ts +5 -5
  150. package/templates/crm/components/activity-timeline.tsx +14 -4
  151. package/templates/crm/components/app-shell.tsx +94 -0
  152. package/templates/crm/components/auth-form.tsx +35 -5
  153. package/templates/crm/components/avatar.tsx +5 -1
  154. package/templates/crm/components/board-skeleton.tsx +5 -5
  155. package/templates/crm/components/brand-mark.tsx +25 -0
  156. package/templates/crm/components/command-palette.tsx +17 -17
  157. package/templates/crm/components/data-table.tsx +97 -36
  158. package/templates/crm/components/deal-card.tsx +23 -27
  159. package/templates/crm/components/filter-tabs.tsx +101 -0
  160. package/templates/crm/components/metrics-bar.tsx +6 -6
  161. package/templates/crm/components/nav.tsx +15 -0
  162. package/templates/crm/components/page-header.tsx +43 -7
  163. package/templates/crm/components/pipeline-board.tsx +16 -10
  164. package/templates/crm/components/require-auth.tsx +24 -26
  165. package/templates/crm/components/sidebar.tsx +54 -49
  166. package/templates/crm/components/stage-badge.tsx +4 -2
  167. package/templates/crm/components/ui/button.tsx +5 -4
  168. package/templates/crm/components/ui/dialog.tsx +1 -1
  169. package/templates/crm/components/ui/input.tsx +1 -1
  170. package/templates/crm/components/ui/select.tsx +1 -1
  171. package/templates/crm/components/ui/textarea.tsx +1 -1
  172. package/templates/crm/functions/seedWorkspace.ts +32 -17
  173. package/templates/crm/lib/brand.ts +9 -0
  174. package/templates/crm/lib/demo-team.ts +51 -0
  175. package/templates/crm/lib/pipeline.ts +37 -0
  176. package/templates/crm/lib/search.ts +4 -3
  177. package/templates/crm/lib/seed.ts +53 -8
  178. package/templates/crm/public/favicon.ico +0 -0
  179. package/templates/crm/tests/components.test.tsx +5 -5
  180. package/templates/crm/tests/demo-team.test.ts +18 -0
  181. package/templates/crm/tests/pipeline.test.ts +59 -3
  182. package/templates/directory/.env.example +7 -0
  183. package/templates/directory/README.md +22 -3
  184. package/templates/directory/app/(marketing)/directory-browse.tsx +30 -12
  185. package/templates/directory/app/(marketing)/page.tsx +6 -4
  186. package/templates/directory/app/auth-form.tsx +4 -4
  187. package/templates/directory/app/dashboard/dashboard-client.tsx +177 -90
  188. package/templates/directory/app/dashboard/page.tsx +16 -14
  189. package/templates/directory/app/icon.svg +4 -0
  190. package/templates/directory/app/login/page.tsx +16 -15
  191. package/templates/directory/functions/seedDemo.ts +43 -0
  192. package/templates/directory/lib/demo.ts +145 -0
  193. package/templates/directory/lib/directory.ts +27 -0
  194. package/templates/directory/lib/site.config.ts +21 -16
  195. package/templates/directory/public/favicon.ico +0 -0
  196. package/templates/directory/tests/directory.test.ts +46 -0
  197. package/templates/expo/consumer/apps/expo/App.tsx +360 -288
  198. package/templates/expo/consumer/apps/expo/app.json +9 -1
  199. package/templates/expo/consumer/apps/expo/package.json +2 -1
  200. package/templates/helpdesk/README.md +21 -0
  201. package/templates/helpdesk/app/apple-icon.png +0 -0
  202. package/templates/helpdesk/app/customers/customers-view.tsx +23 -7
  203. package/templates/helpdesk/app/customers/page.tsx +2 -1
  204. package/templates/helpdesk/app/globals.css +29 -14
  205. package/templates/helpdesk/app/icon.svg +1 -0
  206. package/templates/helpdesk/app/inbox-view.tsx +66 -47
  207. package/templates/helpdesk/app/layout.tsx +7 -5
  208. package/templates/helpdesk/app/page.tsx +4 -7
  209. package/templates/helpdesk/app/tickets/[id]/page.tsx +2 -1
  210. package/templates/helpdesk/app/tickets/[id]/ticket-view.tsx +134 -97
  211. package/templates/helpdesk/app/workspace.tsx +33 -22
  212. package/templates/helpdesk/app.ts +2 -2
  213. package/templates/helpdesk/components/app-shell.tsx +94 -0
  214. package/templates/helpdesk/components/auth-form.tsx +35 -5
  215. package/templates/helpdesk/components/avatar.tsx +5 -1
  216. package/templates/helpdesk/components/brand-mark.tsx +28 -0
  217. package/templates/helpdesk/components/command-palette.tsx +17 -17
  218. package/templates/helpdesk/components/data-table.tsx +97 -36
  219. package/templates/helpdesk/components/filter-tabs.tsx +101 -0
  220. package/templates/helpdesk/components/nav.tsx +14 -0
  221. package/templates/helpdesk/components/page-header.tsx +43 -7
  222. package/templates/helpdesk/components/priority-badge.tsx +49 -6
  223. package/templates/helpdesk/components/require-auth.tsx +24 -26
  224. package/templates/helpdesk/components/sidebar.tsx +54 -48
  225. package/templates/helpdesk/components/sla-indicator.tsx +5 -8
  226. package/templates/helpdesk/components/thread.tsx +7 -7
  227. package/templates/helpdesk/components/ticket-list.tsx +79 -19
  228. package/templates/helpdesk/components/ui/button.tsx +5 -4
  229. package/templates/helpdesk/components/ui/dialog.tsx +1 -1
  230. package/templates/helpdesk/components/ui/input.tsx +1 -1
  231. package/templates/helpdesk/components/ui/select.tsx +1 -1
  232. package/templates/helpdesk/components/ui/textarea.tsx +1 -1
  233. package/templates/helpdesk/functions/seedWorkspace.ts +25 -15
  234. package/templates/helpdesk/lib/brand.ts +9 -0
  235. package/templates/helpdesk/lib/demo-team.ts +51 -0
  236. package/templates/helpdesk/lib/search.ts +4 -3
  237. package/templates/helpdesk/lib/seed.ts +43 -2
  238. package/templates/helpdesk/lib/tickets.ts +68 -20
  239. package/templates/helpdesk/public/favicon.ico +0 -0
  240. package/templates/helpdesk/tests/components.test.tsx +10 -0
  241. package/templates/helpdesk/tests/demo-team.test.ts +18 -0
  242. package/templates/helpdesk/tests/tickets.test.ts +70 -0
  243. package/templates/imessage/.env.example +49 -0
  244. package/templates/imessage/AGENTS.md +153 -0
  245. package/templates/imessage/CLAUDE.md +7 -0
  246. package/templates/imessage/README.md +187 -0
  247. package/templates/imessage/app/console.tsx +382 -0
  248. package/templates/imessage/app/contacts/page.tsx +13 -0
  249. package/templates/imessage/app/error.tsx +16 -0
  250. package/templates/imessage/app/gate.tsx +31 -0
  251. package/templates/imessage/app/globals.css +183 -0
  252. package/templates/imessage/app/layout.tsx +17 -0
  253. package/templates/imessage/app/login/login-form.tsx +115 -0
  254. package/templates/imessage/app/login/page.tsx +30 -0
  255. package/templates/imessage/app/not-found.tsx +13 -0
  256. package/templates/imessage/app/page.tsx +14 -0
  257. package/templates/imessage/app/robots.ts +6 -0
  258. package/templates/imessage/app/setup/page.tsx +13 -0
  259. package/templates/imessage/app/sign-out.tsx +20 -0
  260. package/templates/imessage/app.ts +299 -0
  261. package/templates/imessage/bunfig +4 -0
  262. package/templates/imessage/components/avatar.tsx +46 -0
  263. package/templates/imessage/components/contact-panel.tsx +263 -0
  264. package/templates/imessage/components/contacts-view.tsx +172 -0
  265. package/templates/imessage/components/conversation-list.tsx +129 -0
  266. package/templates/imessage/components/nav-rail.tsx +67 -0
  267. package/templates/imessage/components/setup-view.tsx +408 -0
  268. package/templates/imessage/components/thread.tsx +229 -0
  269. package/templates/imessage/components/ui/badge.tsx +37 -0
  270. package/templates/imessage/components/ui/button.tsx +56 -0
  271. package/templates/imessage/components/ui/card.tsx +90 -0
  272. package/templates/imessage/components/ui/dialog.tsx +110 -0
  273. package/templates/imessage/components/ui/input.tsx +30 -0
  274. package/templates/imessage/components/ui/label.tsx +21 -0
  275. package/templates/imessage/components/ui/select.tsx +39 -0
  276. package/templates/imessage/components/ui/table.tsx +124 -0
  277. package/templates/imessage/components/ui/textarea.tsx +24 -0
  278. package/templates/imessage/components.json +20 -0
  279. package/templates/imessage/functions/answerNow.ts +34 -0
  280. package/templates/imessage/functions/assistant.ts +96 -0
  281. package/templates/imessage/functions/beginTurn.ts +101 -0
  282. package/templates/imessage/functions/cancelReminder.ts +13 -0
  283. package/templates/imessage/functions/claimOutbound.ts +44 -0
  284. package/templates/imessage/functions/clearDemo.ts +18 -0
  285. package/templates/imessage/functions/deleteNote.ts +11 -0
  286. package/templates/imessage/functions/deliverOutbound.ts +55 -0
  287. package/templates/imessage/functions/finishTurn.ts +84 -0
  288. package/templates/imessage/functions/fireReminder.ts +42 -0
  289. package/templates/imessage/functions/ingestInbound.ts +22 -0
  290. package/templates/imessage/functions/ownerAccount.ts +13 -0
  291. package/templates/imessage/functions/processTurn.ts +74 -0
  292. package/templates/imessage/functions/relayApply.ts +102 -0
  293. package/templates/imessage/functions/relaySync.ts +63 -0
  294. package/templates/imessage/functions/releaseOutbound.ts +18 -0
  295. package/templates/imessage/functions/resolveTurn.ts +25 -0
  296. package/templates/imessage/functions/saveContact.ts +27 -0
  297. package/templates/imessage/functions/seedDemo.ts +70 -0
  298. package/templates/imessage/functions/sendOwnerMessage.ts +28 -0
  299. package/templates/imessage/functions/sendblueWebhook.ts +49 -0
  300. package/templates/imessage/functions/setContactStatus.ts +17 -0
  301. package/templates/imessage/functions/settleOutbound.ts +35 -0
  302. package/templates/imessage/functions/setupStatus.ts +33 -0
  303. package/templates/imessage/functions/sweep.ts +58 -0
  304. package/templates/imessage/functions/toolCancelReminder.ts +17 -0
  305. package/templates/imessage/functions/toolForgetNote.ts +15 -0
  306. package/templates/imessage/functions/toolListNotes.ts +16 -0
  307. package/templates/imessage/functions/toolListReminders.ts +17 -0
  308. package/templates/imessage/functions/toolSaveNote.ts +22 -0
  309. package/templates/imessage/functions/toolSetReminder.ts +55 -0
  310. package/templates/imessage/functions/updateSettings.ts +48 -0
  311. package/templates/imessage/gitignore +11 -0
  312. package/templates/imessage/lib/agent-call.ts +251 -0
  313. package/templates/imessage/lib/assistant.ts +74 -0
  314. package/templates/imessage/lib/chunk.ts +135 -0
  315. package/templates/imessage/lib/demo.ts +68 -0
  316. package/templates/imessage/lib/format.ts +170 -0
  317. package/templates/imessage/lib/gate.ts +104 -0
  318. package/templates/imessage/lib/handles.ts +67 -0
  319. package/templates/imessage/lib/provider.ts +38 -0
  320. package/templates/imessage/lib/relay-protocol.ts +95 -0
  321. package/templates/imessage/lib/reminders.ts +41 -0
  322. package/templates/imessage/lib/secrets.ts +59 -0
  323. package/templates/imessage/lib/sendblue.ts +173 -0
  324. package/templates/imessage/lib/store.ts +407 -0
  325. package/templates/imessage/lib/transport.ts +135 -0
  326. package/templates/imessage/lib/utils.ts +10 -0
  327. package/templates/imessage/package.json +40 -0
  328. package/templates/imessage/relay/.env.example +14 -0
  329. package/templates/imessage/relay/applescript.ts +70 -0
  330. package/templates/imessage/relay/chatdb.ts +165 -0
  331. package/templates/imessage/relay/client.ts +41 -0
  332. package/templates/imessage/relay/main.ts +137 -0
  333. package/templates/imessage/relay/state.ts +35 -0
  334. package/templates/imessage/tests/agent-call.test.ts +112 -0
  335. package/templates/imessage/tests/applescript.test.ts +88 -0
  336. package/templates/imessage/tests/chatdb.test.ts +139 -0
  337. package/templates/imessage/tests/chunk.test.ts +61 -0
  338. package/templates/imessage/tests/fake-ctx.ts +88 -0
  339. package/templates/imessage/tests/ingest.test.ts +141 -0
  340. package/templates/imessage/tests/lib.test.ts +99 -0
  341. package/templates/imessage/tests/review-fixes.test.ts +138 -0
  342. package/templates/imessage/tests/secrets.test.ts +36 -0
  343. package/templates/imessage/tests/sendblue.test.ts +143 -0
  344. package/templates/imessage/tests/setup.ts +5 -0
  345. package/templates/imessage/tsconfig.json +18 -0
  346. package/templates/inventory/README.md +21 -0
  347. package/templates/inventory/app/apple-icon.png +0 -0
  348. package/templates/inventory/app/globals.css +29 -14
  349. package/templates/inventory/app/icon.svg +1 -0
  350. package/templates/inventory/app/layout.tsx +7 -5
  351. package/templates/inventory/app/movements/movements-view.tsx +32 -10
  352. package/templates/inventory/app/movements/page.tsx +2 -1
  353. package/templates/inventory/app/page.tsx +4 -6
  354. package/templates/inventory/app/products/[id]/page.tsx +2 -1
  355. package/templates/inventory/app/products/[id]/product-view.tsx +55 -25
  356. package/templates/inventory/app/products-view.tsx +74 -33
  357. package/templates/inventory/app/workspace.tsx +34 -16
  358. package/templates/inventory/app.ts +10 -2
  359. package/templates/inventory/components/app-shell.tsx +94 -0
  360. package/templates/inventory/components/auth-form.tsx +35 -5
  361. package/templates/inventory/components/avatar.tsx +5 -1
  362. package/templates/inventory/components/brand-mark.tsx +25 -0
  363. package/templates/inventory/components/category-tile.tsx +49 -0
  364. package/templates/inventory/components/command-palette.tsx +17 -17
  365. package/templates/inventory/components/data-table.tsx +97 -36
  366. package/templates/inventory/components/filter-tabs.tsx +101 -0
  367. package/templates/inventory/components/nav.tsx +14 -0
  368. package/templates/inventory/components/page-header.tsx +43 -7
  369. package/templates/inventory/components/require-auth.tsx +24 -26
  370. package/templates/inventory/components/sidebar.tsx +54 -48
  371. package/templates/inventory/components/stock-level.tsx +30 -14
  372. package/templates/inventory/components/summary-bar.tsx +8 -15
  373. package/templates/inventory/components/ui/button.tsx +5 -4
  374. package/templates/inventory/components/ui/dialog.tsx +1 -1
  375. package/templates/inventory/components/ui/input.tsx +1 -1
  376. package/templates/inventory/components/ui/select.tsx +1 -1
  377. package/templates/inventory/components/ui/textarea.tsx +1 -1
  378. package/templates/inventory/functions/seedWorkspace.ts +18 -8
  379. package/templates/inventory/lib/brand.ts +9 -0
  380. package/templates/inventory/lib/demo-team.ts +51 -0
  381. package/templates/inventory/lib/search.ts +4 -3
  382. package/templates/inventory/lib/seed.ts +29 -2
  383. package/templates/inventory/lib/stock.ts +32 -0
  384. package/templates/inventory/public/favicon.ico +0 -0
  385. package/templates/inventory/tests/demo-team.test.ts +18 -0
  386. package/templates/inventory/tests/stock.test.ts +29 -0
  387. package/templates/invoices/README.md +16 -0
  388. package/templates/invoices/app/apple-icon.png +0 -0
  389. package/templates/invoices/app/clients/clients-view.tsx +18 -6
  390. package/templates/invoices/app/clients/page.tsx +2 -1
  391. package/templates/invoices/app/globals.css +29 -14
  392. package/templates/invoices/app/icon.svg +1 -0
  393. package/templates/invoices/app/invoices/[id]/invoice-view.tsx +72 -48
  394. package/templates/invoices/app/invoices/[id]/page.tsx +2 -1
  395. package/templates/invoices/app/invoices-view.tsx +81 -32
  396. package/templates/invoices/app/layout.tsx +7 -5
  397. package/templates/invoices/app/page.tsx +4 -6
  398. package/templates/invoices/app/workspace.tsx +26 -16
  399. package/templates/invoices/app.ts +2 -2
  400. package/templates/invoices/components/app-shell.tsx +94 -0
  401. package/templates/invoices/components/auth-form.tsx +35 -5
  402. package/templates/invoices/components/avatar.tsx +5 -1
  403. package/templates/invoices/components/brand-mark.tsx +26 -0
  404. package/templates/invoices/components/command-palette.tsx +17 -17
  405. package/templates/invoices/components/data-table.tsx +97 -36
  406. package/templates/invoices/components/filter-tabs.tsx +101 -0
  407. package/templates/invoices/components/line-items.tsx +19 -14
  408. package/templates/invoices/components/nav.tsx +14 -0
  409. package/templates/invoices/components/page-header.tsx +43 -7
  410. package/templates/invoices/components/require-auth.tsx +24 -26
  411. package/templates/invoices/components/sidebar.tsx +54 -48
  412. package/templates/invoices/components/status-badge.tsx +7 -7
  413. package/templates/invoices/components/summary-bar.tsx +5 -5
  414. package/templates/invoices/components/ui/button.tsx +5 -4
  415. package/templates/invoices/components/ui/dialog.tsx +1 -1
  416. package/templates/invoices/components/ui/input.tsx +1 -1
  417. package/templates/invoices/components/ui/select.tsx +1 -1
  418. package/templates/invoices/components/ui/textarea.tsx +1 -1
  419. package/templates/invoices/functions/recordPayment.ts +3 -0
  420. package/templates/invoices/lib/billing.ts +40 -0
  421. package/templates/invoices/lib/brand.ts +9 -0
  422. package/templates/invoices/lib/search.ts +4 -3
  423. package/templates/invoices/public/favicon.ico +0 -0
  424. package/templates/invoices/tests/billing.test.ts +27 -0
  425. package/templates/ios/consumer/apps/ios/Package.swift +4 -3
  426. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ActivityView.swift +107 -0
  427. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/AppModel.swift +171 -0
  428. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/AuthView.swift +182 -0
  429. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/CommentsView.swift +136 -0
  430. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ComposeView.swift +152 -0
  431. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ExploreView.swift +117 -0
  432. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/FeedView.swift +175 -159
  433. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/MainTabView.swift +54 -0
  434. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Media.swift +271 -0
  435. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Models.swift +101 -4
  436. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/PostCard.swift +245 -0
  437. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileEditorView.swift +208 -0
  438. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileView.swift +183 -0
  439. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/RootView.swift +25 -31
  440. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/SocialStore.swift +285 -0
  441. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/StoryViewer.swift +155 -0
  442. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/Theme.swift +82 -0
  443. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/__APP_NAME_PASCAL__App.swift +4 -47
  444. package/templates/ios/consumer/apps/ios/project.yml +13 -9
  445. package/templates/local-service/.env.example +7 -0
  446. package/templates/local-service/README.md +26 -2
  447. package/templates/local-service/app/(marketing)/booking-widget.tsx +48 -9
  448. package/templates/local-service/app/(marketing)/page.tsx +66 -42
  449. package/templates/local-service/app/auth-form.tsx +8 -8
  450. package/templates/local-service/app/dashboard/dashboard-client.tsx +119 -92
  451. package/templates/local-service/app/dashboard/page.tsx +14 -14
  452. package/templates/local-service/app/icon.svg +2 -0
  453. package/templates/local-service/app/login/page.tsx +15 -15
  454. package/templates/local-service/functions/seedDemo.ts +49 -0
  455. package/templates/local-service/lib/demo.ts +135 -0
  456. package/templates/local-service/lib/hours.ts +44 -0
  457. package/templates/local-service/lib/site.config.ts +8 -3
  458. package/templates/local-service/lib/slots.ts +3 -0
  459. package/templates/local-service/public/favicon.ico +0 -0
  460. package/templates/local-service/tests/booking.test.ts +104 -0
  461. package/templates/marketplace/README.md +23 -15
  462. package/templates/marketplace/app/globals.css +172 -114
  463. package/templates/marketplace/app/layout.tsx +75 -30
  464. package/templates/marketplace/app/listing/[id]/page.tsx +210 -123
  465. package/templates/marketplace/app/me/page.tsx +4 -4
  466. package/templates/marketplace/app/page.tsx +221 -298
  467. package/templates/marketplace/app/sell/page.tsx +8 -11
  468. package/templates/marketplace/app.ts +32 -7
  469. package/templates/marketplace/client/ActivityFeed.tsx +311 -0
  470. package/templates/marketplace/client/AuthNav.tsx +24 -16
  471. package/templates/marketplace/client/ListingCard.tsx +118 -0
  472. package/templates/marketplace/client/LiveGrid.tsx +92 -0
  473. package/templates/marketplace/client/LiveListingStatus.tsx +32 -24
  474. package/templates/marketplace/client/LoginCard.tsx +114 -136
  475. package/templates/marketplace/client/MarketProvider.tsx +3 -5
  476. package/templates/marketplace/client/MyMarket.tsx +371 -185
  477. package/templates/marketplace/client/OfferPanel.tsx +421 -287
  478. package/templates/marketplace/client/SellForm.tsx +271 -192
  479. package/templates/marketplace/client/ThemeToggle.tsx +1 -0
  480. package/templates/marketplace/client/WatchButton.tsx +16 -16
  481. package/templates/marketplace/client/market.ts +61 -14
  482. package/templates/marketplace/functions/seedMarket.ts +143 -36
  483. package/templates/marketplace/functions/seedOffers.ts +101 -0
  484. package/templates/marketplace/lib/catalog.ts +72 -1
  485. package/templates/marketplace/public/images/listings/ceramic-lamp-640.webp +0 -0
  486. package/templates/marketplace/public/images/listings/ceramic-lamp.webp +0 -0
  487. package/templates/marketplace/public/images/listings/duffel-640.webp +0 -0
  488. package/templates/marketplace/public/images/listings/duffel.webp +0 -0
  489. package/templates/marketplace/public/images/listings/film-camera-640.webp +0 -0
  490. package/templates/marketplace/public/images/listings/film-camera.webp +0 -0
  491. package/templates/marketplace/public/images/listings/lounge-chair-640.webp +0 -0
  492. package/templates/marketplace/public/images/listings/lounge-chair.webp +0 -0
  493. package/templates/marketplace/public/images/listings/road-bike-640.webp +0 -0
  494. package/templates/marketplace/public/images/listings/road-bike.webp +0 -0
  495. package/templates/marketplace/public/images/listings/slipper-chair-640.webp +0 -0
  496. package/templates/marketplace/public/images/listings/slipper-chair.webp +0 -0
  497. package/templates/marketplace/public/images/listings/turntable-640.webp +0 -0
  498. package/templates/marketplace/public/images/listings/turntable.webp +0 -0
  499. package/templates/marketplace/public/images/listings/wardrobe-640.webp +0 -0
  500. package/templates/marketplace/public/images/listings/wardrobe.webp +0 -0
  501. package/templates/marketplace/public/images/listings/watch-640.webp +0 -0
  502. package/templates/marketplace/public/images/listings/watch.webp +0 -0
  503. package/templates/marketplace/public/images/listings/weekender-bag-640.webp +0 -0
  504. package/templates/marketplace/public/images/listings/weekender-bag.webp +0 -0
  505. package/templates/marketplace/tests/example.test.ts +64 -2
  506. package/templates/marketplace/tests/listing-card.test.tsx +61 -0
  507. package/templates/projects/README.md +24 -3
  508. package/templates/projects/app/apple-icon.png +0 -0
  509. package/templates/projects/app/clients/clients-view.tsx +20 -6
  510. package/templates/projects/app/clients/page.tsx +2 -1
  511. package/templates/projects/app/globals.css +29 -14
  512. package/templates/projects/app/icon.svg +1 -0
  513. package/templates/projects/app/layout.tsx +7 -5
  514. package/templates/projects/app/page.tsx +3 -5
  515. package/templates/projects/app/projects/[id]/page.tsx +2 -1
  516. package/templates/projects/app/projects/[id]/project-view.tsx +45 -30
  517. package/templates/projects/app/projects-view.tsx +105 -52
  518. package/templates/projects/app/workspace.tsx +41 -20
  519. package/templates/projects/app.ts +2 -2
  520. package/templates/projects/components/app-shell.tsx +94 -0
  521. package/templates/projects/components/auth-form.tsx +35 -5
  522. package/templates/projects/components/avatar.tsx +5 -1
  523. package/templates/projects/components/board-skeleton.tsx +3 -3
  524. package/templates/projects/components/brand-mark.tsx +25 -0
  525. package/templates/projects/components/command-palette.tsx +17 -17
  526. package/templates/projects/components/data-table.tsx +97 -36
  527. package/templates/projects/components/filter-tabs.tsx +101 -0
  528. package/templates/projects/components/meter.tsx +48 -0
  529. package/templates/projects/components/nav.tsx +14 -0
  530. package/templates/projects/components/page-header.tsx +43 -7
  531. package/templates/projects/components/require-auth.tsx +24 -26
  532. package/templates/projects/components/sidebar.tsx +54 -48
  533. package/templates/projects/components/summary-bar.tsx +49 -0
  534. package/templates/projects/components/task-board.tsx +10 -9
  535. package/templates/projects/components/time-dialog.tsx +29 -5
  536. package/templates/projects/components/ui/button.tsx +5 -4
  537. package/templates/projects/components/ui/dialog.tsx +1 -1
  538. package/templates/projects/components/ui/input.tsx +1 -1
  539. package/templates/projects/components/ui/select.tsx +1 -1
  540. package/templates/projects/components/ui/textarea.tsx +1 -1
  541. package/templates/projects/functions/seedWorkspace.ts +26 -12
  542. package/templates/projects/lib/brand.ts +9 -0
  543. package/templates/projects/lib/demo-team.ts +51 -0
  544. package/templates/projects/lib/search.ts +4 -3
  545. package/templates/projects/lib/seed.ts +35 -1
  546. package/templates/projects/lib/work.ts +63 -0
  547. package/templates/projects/public/favicon.ico +0 -0
  548. package/templates/projects/tests/demo-team.test.ts +18 -0
  549. package/templates/projects/tests/work.test.ts +65 -0
  550. package/templates/restaurant/.env.example +7 -0
  551. package/templates/restaurant/README.md +29 -3
  552. package/templates/restaurant/app/(marketing)/layout.tsx +4 -2
  553. package/templates/restaurant/app/(marketing)/page.tsx +47 -23
  554. package/templates/restaurant/app/(marketing)/reservation-widget.tsx +37 -7
  555. package/templates/restaurant/app/auth-form.tsx +8 -8
  556. package/templates/restaurant/app/dashboard/dashboard-client.tsx +241 -109
  557. package/templates/restaurant/app/dashboard/page.tsx +14 -14
  558. package/templates/restaurant/app/icon.svg +4 -0
  559. package/templates/restaurant/app/login/page.tsx +15 -15
  560. package/templates/restaurant/functions/seedDemo.ts +44 -0
  561. package/templates/restaurant/lib/demo.ts +144 -0
  562. package/templates/restaurant/lib/hours.ts +45 -0
  563. package/templates/restaurant/lib/site.config.ts +3 -3
  564. package/templates/restaurant/public/favicon.ico +0 -0
  565. package/templates/restaurant/tests/reservations.test.ts +67 -0
  566. package/templates/saas/README.md +54 -35
  567. package/templates/saas/app/(auth)/auth-form.tsx +25 -23
  568. package/templates/saas/app/(auth)/forgot-password/page.tsx +1 -1
  569. package/templates/saas/app/(auth)/layout.tsx +27 -33
  570. package/templates/saas/app/(auth)/login/page.tsx +1 -1
  571. package/templates/saas/app/(auth)/reset-password/page.tsx +1 -1
  572. package/templates/saas/app/(auth)/signup/page.tsx +1 -1
  573. package/templates/saas/app/(marketing)/layout.tsx +127 -253
  574. package/templates/saas/app/(marketing)/page.tsx +133 -372
  575. package/templates/saas/app/(marketing)/pricing/page.tsx +21 -19
  576. package/templates/saas/app/(marketing)/products/[slug]/page.tsx +40 -95
  577. package/templates/saas/app/dashboard/board-client.tsx +416 -0
  578. package/templates/saas/app/dashboard/dashboard-client.tsx +30 -615
  579. package/templates/saas/app/dashboard/layout.tsx +27 -13
  580. package/templates/saas/app/dashboard/overview-client.tsx +332 -0
  581. package/templates/saas/app/dashboard/page.tsx +29 -35
  582. package/templates/saas/app/dashboard/projects/[id]/page.tsx +29 -0
  583. package/templates/saas/app/dashboard/projects/page.tsx +11 -7
  584. package/templates/saas/app/dashboard/projects-client.tsx +398 -0
  585. package/templates/saas/app/globals.css +5 -4
  586. package/templates/saas/app/icon.svg +1 -0
  587. package/templates/saas/app/onboarding/onboarding-client.tsx +93 -26
  588. package/templates/saas/app/onboarding/page.tsx +6 -2
  589. package/templates/saas/app.ts +68 -13
  590. package/templates/saas/components/dashboard-shell.tsx +212 -132
  591. package/templates/saas/components/marketing.tsx +137 -274
  592. package/templates/saas/components/pricing-table.tsx +12 -11
  593. package/templates/saas/components/setup-checklist.tsx +31 -29
  594. package/templates/saas/components/task-ui.tsx +199 -0
  595. package/templates/saas/functions/createProject.ts +7 -13
  596. package/templates/saas/functions/createTask.ts +67 -0
  597. package/templates/saas/functions/deleteProject.ts +17 -0
  598. package/templates/saas/functions/deleteTask.ts +14 -0
  599. package/templates/saas/functions/seedWorkspace.ts +46 -0
  600. package/templates/saas/functions/setProjectStatus.ts +41 -0
  601. package/templates/saas/functions/updateProfile.ts +13 -0
  602. package/templates/saas/functions/updateProject.ts +4 -5
  603. package/templates/saas/functions/updateTask.ts +88 -0
  604. package/templates/saas/lib/members.ts +53 -0
  605. package/templates/saas/lib/names.ts +53 -0
  606. package/templates/saas/lib/plans.ts +11 -0
  607. package/templates/saas/lib/sample-workspace.ts +117 -0
  608. package/templates/saas/lib/site.config.ts +200 -463
  609. package/templates/saas/lib/tasks.ts +101 -0
  610. package/templates/saas/lib/use-live.ts +25 -0
  611. package/templates/saas/public/favicon.ico +0 -0
  612. package/templates/saas/public/screenshots/board.png +0 -0
  613. package/templates/saas/public/screenshots/members.png +0 -0
  614. package/templates/saas/public/screenshots/overview.png +0 -0
  615. package/templates/saas/public/screenshots/projects.png +0 -0
  616. package/templates/saas/scripts/capture-screenshots.mjs +156 -0
  617. package/templates/saas/tests/names.test.ts +35 -0
  618. package/templates/saas/tests/plans.test.ts +12 -0
  619. package/templates/saas/tests/sample-workspace.test.ts +46 -0
  620. package/templates/saas/tests/tasks.test.ts +81 -0
  621. package/templates/shop/README.md +25 -13
  622. package/templates/shop/app/(marketing)/layout.tsx +94 -67
  623. package/templates/shop/app/(marketing)/not-found.tsx +13 -12
  624. package/templates/shop/app/(marketing)/page.tsx +120 -59
  625. package/templates/shop/app/(marketing)/shop-client.tsx +364 -237
  626. package/templates/shop/app/(marketing)/success/page.tsx +75 -22
  627. package/templates/shop/app/globals.css +94 -1
  628. package/templates/shop/app/layout.tsx +4 -4
  629. package/templates/shop/app/login/page.tsx +4 -4
  630. package/templates/shop/app.ts +18 -6
  631. package/templates/shop/components/cart-button.tsx +33 -0
  632. package/templates/shop/components/marketing.tsx +17 -87
  633. package/templates/shop/components/shelf-count.tsx +36 -0
  634. package/templates/shop/functions/checkout.ts +17 -1
  635. package/templates/shop/lib/cart-store.ts +57 -0
  636. package/templates/shop/lib/shelf-store.ts +35 -0
  637. package/templates/shop/lib/shop.ts +27 -0
  638. package/templates/shop/lib/site.config.ts +108 -98
  639. package/templates/shop/public/images/hero.jpg +0 -0
  640. package/templates/shop/public/images/products/cedar-smoke.jpg +0 -0
  641. package/templates/shop/public/images/products/fig-leaf.jpg +0 -0
  642. package/templates/shop/public/images/products/linen.jpg +0 -0
  643. package/templates/shop/public/images/products/sea-salt.jpg +0 -0
  644. package/templates/shop/public/images/products/tobacco-oak.jpg +0 -0
  645. package/templates/shop/tests/shop.test.ts +64 -0
  646. package/templates/waitlist/.env.example +7 -0
  647. package/templates/waitlist/README.md +29 -13
  648. package/templates/waitlist/app/(marketing)/page.tsx +9 -7
  649. package/templates/waitlist/app/(marketing)/waitlist-hero.tsx +64 -31
  650. package/templates/waitlist/app/auth-form.tsx +8 -8
  651. package/templates/waitlist/app/dashboard/dashboard-client.tsx +132 -95
  652. package/templates/waitlist/app/dashboard/page.tsx +17 -16
  653. package/templates/waitlist/app/icon.svg +2 -0
  654. package/templates/waitlist/app/login/page.tsx +14 -14
  655. package/templates/waitlist/app.ts +6 -6
  656. package/templates/waitlist/functions/joinWaitlist.ts +6 -18
  657. package/templates/waitlist/functions/seedDemo.ts +32 -0
  658. package/templates/waitlist/lib/demo.ts +94 -0
  659. package/templates/waitlist/lib/launch.ts +19 -0
  660. package/templates/waitlist/lib/site.config.ts +14 -9
  661. package/templates/waitlist/lib/stats.ts +35 -0
  662. package/templates/waitlist/public/favicon.ico +0 -0
  663. package/templates/waitlist/tests/counter.test.ts +107 -0
  664. package/templates/waitlist/tests/live-count.test.tsx +48 -0
  665. package/templates/ai-chat/tests/example.test.ts +0 -12
  666. package/templates/backend/consumer/apps/api/functions/feed.ts +0 -57
  667. package/templates/backend/consumer/apps/api/functions/profilePosts.ts +0 -17
  668. package/templates/backend/consumer/apps/api/functions/toggleLike.ts +0 -48
  669. package/templates/backend/consumer/apps/api/schema.ts +0 -143
  670. package/templates/chat/functions/_keep.ts +0 -13
  671. package/templates/chat/tests/example.test.ts +0 -12
  672. package/templates/ios/consumer/apps/ios/Sources/__APP_NAME_PASCAL__/ProfileSetupView.swift +0 -68
  673. package/templates/marketplace/client/LiveTicker.tsx +0 -116
  674. package/templates/marketplace/client/ScrollToListingsLink.tsx +0 -29
  675. 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
  };