makersclaw 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (401) hide show
  1. package/README.md +9 -3
  2. package/package.json +1 -1
  3. package/r/activity-log.json +52 -0
  4. package/r/agent-changes.json +51 -0
  5. package/r/agent-chat.json +53 -0
  6. package/r/agent-column.json +85 -0
  7. package/r/agent-dock.json +57 -0
  8. package/r/agent-kit.json +49 -0
  9. package/r/agent-marks.json +49 -0
  10. package/r/agent-pane.json +93 -0
  11. package/r/ai-action.json +56 -0
  12. package/r/annotate.json +3 -3
  13. package/r/approval-request.json +2 -2
  14. package/r/approval.json +54 -0
  15. package/r/ask-bar.json +50 -0
  16. package/r/audio-player.json +2 -2
  17. package/r/auth-form.json +2 -2
  18. package/r/automation-editor.json +66 -0
  19. package/r/automation-list.json +57 -0
  20. package/r/automation-model.json +118 -0
  21. package/r/automations-screen.json +71 -0
  22. package/r/board.json +2 -2
  23. package/r/calendar-view.json +3 -3
  24. package/r/cart.json +2 -2
  25. package/r/chart.json +2 -2
  26. package/r/chat-pane.json +84 -0
  27. package/r/chat.json +2 -2
  28. package/r/code-editor.json +2 -2
  29. package/r/comment-box.json +3 -3
  30. package/r/connect-card.json +51 -0
  31. package/r/contact-section.json +2 -2
  32. package/r/core.json +13 -7
  33. package/r/cost.json +51 -0
  34. package/r/csv-import.json +3 -3
  35. package/r/data-picker.json +60 -0
  36. package/r/data-table.json +2 -2
  37. package/r/diagram.json +2 -2
  38. package/r/doc-editor.json +2 -2
  39. package/r/doc-page.json +3 -3
  40. package/r/email-render.json +2 -2
  41. package/r/faq.json +2 -2
  42. package/r/file-upload.json +2 -2
  43. package/r/first-run.json +63 -0
  44. package/r/fix-note.json +57 -0
  45. package/r/flow-canvas.json +2 -2
  46. package/r/flow-editor.json +79 -0
  47. package/r/footer.json +2 -2
  48. package/r/gantt.json +3 -3
  49. package/r/job-panel.json +2 -2
  50. package/r/json-editor.json +3 -3
  51. package/r/library-shelf.json +56 -0
  52. package/r/map.json +2 -2
  53. package/r/margin-notes.json +67 -0
  54. package/r/menubar.json +2 -2
  55. package/r/mind-map.json +3 -3
  56. package/r/navigation-menu.json +2 -2
  57. package/r/needs-you.json +55 -0
  58. package/r/order-detail.json +2 -2
  59. package/r/org-chart.json +3 -3
  60. package/r/pace-bar.json +69 -0
  61. package/r/page-builder.json +2 -2
  62. package/r/payment-methods.json +2 -2
  63. package/r/pdf-document.json +2 -2
  64. package/r/pdf-viewer.json +2 -2
  65. package/r/product-detail.json +2 -2
  66. package/r/product-grid.json +3 -3
  67. package/r/record-form.json +2 -2
  68. package/r/record-grid.json +52 -0
  69. package/r/record-notes.json +4 -4
  70. package/r/registry.json +4086 -1512
  71. package/r/run-history.json +52 -0
  72. package/r/run-view.json +80 -0
  73. package/r/schedule-card.json +54 -0
  74. package/r/schedule-engine.json +79 -0
  75. package/r/schedule-gantt.json +83 -0
  76. package/r/schedule-ruler.json +64 -0
  77. package/r/search-dialog.json +2 -2
  78. package/r/settings-list.json +2 -2
  79. package/r/setup-checklist.json +2 -2
  80. package/r/share-dialog.json +2 -2
  81. package/r/sidebar.json +2 -2
  82. package/r/signature-pad.json +2 -2
  83. package/r/sketch-canvas.json +2 -2
  84. package/r/source-receipt.json +52 -0
  85. package/r/spreadsheet.json +3 -3
  86. package/r/stat-cards.json +3 -3
  87. package/r/step-picker.json +53 -0
  88. package/r/step-settings.json +72 -0
  89. package/r/suggestion.json +58 -0
  90. package/r/sum-bar.json +64 -0
  91. package/r/task-list.json +3 -3
  92. package/r/task-model.json +2 -2
  93. package/r/testimonials.json +2 -2
  94. package/r/tier-map.json +67 -0
  95. package/r/time-grid.json +73 -0
  96. package/r/time-strip.json +64 -0
  97. package/r/top-bar.json +66 -0
  98. package/r/transaction-list.json +2 -2
  99. package/r/trigger-picker.json +61 -0
  100. package/r/whiteboard.json +3 -3
  101. package/r/workflow-view.json +55 -0
  102. package/registry/blocks/activity-log/README.md +112 -0
  103. package/registry/blocks/activity-log/activity-log.jsx +351 -0
  104. package/registry/blocks/activity-log/block.json +33 -0
  105. package/registry/blocks/activity-log/demo.jsx +48 -0
  106. package/registry/blocks/activity-log/index.js +4 -0
  107. package/registry/blocks/agent-changes/README.md +94 -0
  108. package/registry/blocks/agent-changes/agent-changes.jsx +118 -0
  109. package/registry/blocks/agent-changes/block.json +28 -0
  110. package/registry/blocks/agent-changes/demo.jsx +39 -0
  111. package/registry/blocks/agent-changes/index.js +3 -0
  112. package/registry/blocks/agent-chat/README.md +145 -0
  113. package/registry/blocks/agent-chat/agent-chat.jsx +415 -0
  114. package/registry/blocks/agent-chat/block.json +30 -0
  115. package/registry/blocks/agent-chat/demo.jsx +165 -0
  116. package/registry/blocks/agent-chat/index.js +3 -0
  117. package/registry/blocks/agent-column/README.md +197 -0
  118. package/registry/blocks/agent-column/agent-column.jsx +492 -0
  119. package/registry/blocks/agent-column/block.json +67 -0
  120. package/registry/blocks/agent-column/column-picker.jsx +163 -0
  121. package/registry/blocks/agent-column/demo.jsx +50 -0
  122. package/registry/blocks/agent-column/index.js +7 -0
  123. package/registry/blocks/agent-column/model.js +164 -0
  124. package/registry/blocks/agent-column/receipt.jsx +483 -0
  125. package/registry/blocks/agent-column/spreadsheet-type.jsx +24 -0
  126. package/registry/blocks/agent-dock/README.md +210 -0
  127. package/registry/blocks/agent-dock/agent-dock.jsx +356 -0
  128. package/registry/blocks/agent-dock/block.json +47 -0
  129. package/registry/blocks/agent-dock/demo.jsx +153 -0
  130. package/registry/blocks/agent-dock/dock-model.js +118 -0
  131. package/registry/blocks/agent-dock/index.js +5 -0
  132. package/registry/blocks/agent-kit/README.md +73 -0
  133. package/registry/blocks/agent-kit/agent-kit.jsx +86 -0
  134. package/registry/blocks/agent-kit/block.json +10 -0
  135. package/registry/blocks/agent-kit/demo.jsx +35 -0
  136. package/registry/blocks/agent-kit/index.js +3 -0
  137. package/registry/blocks/agent-marks/README.md +80 -0
  138. package/registry/blocks/agent-marks/agent-marks.jsx +133 -0
  139. package/registry/blocks/agent-marks/block.json +27 -0
  140. package/registry/blocks/agent-marks/demo.jsx +49 -0
  141. package/registry/blocks/agent-marks/index.js +3 -0
  142. package/registry/blocks/agent-pane/README.md +225 -0
  143. package/registry/blocks/agent-pane/agent-pane.jsx +244 -0
  144. package/registry/blocks/agent-pane/block.json +41 -0
  145. package/registry/blocks/agent-pane/composer.jsx +6 -0
  146. package/registry/blocks/agent-pane/demo.jsx +233 -0
  147. package/registry/blocks/agent-pane/dock-context.js +10 -0
  148. package/registry/blocks/agent-pane/index.js +4 -0
  149. package/registry/blocks/agent-pane/prose.jsx +84 -0
  150. package/registry/blocks/agent-pane/questions.jsx +134 -0
  151. package/registry/blocks/agent-pane/transcript.jsx +268 -0
  152. package/registry/blocks/agent-pane/work.jsx +368 -0
  153. package/registry/blocks/ai-action/README.md +94 -0
  154. package/registry/blocks/ai-action/ai-action.jsx +188 -0
  155. package/registry/blocks/ai-action/block.json +34 -0
  156. package/registry/blocks/ai-action/demo.jsx +93 -0
  157. package/registry/blocks/ai-action/index.js +3 -0
  158. package/registry/blocks/approval/README.md +145 -0
  159. package/registry/blocks/approval/approval.jsx +163 -0
  160. package/registry/blocks/approval/block.json +31 -0
  161. package/registry/blocks/approval/demo.jsx +121 -0
  162. package/registry/blocks/approval/index.js +3 -0
  163. package/registry/blocks/ask-bar/README.md +105 -0
  164. package/registry/blocks/ask-bar/ask-bar.jsx +166 -0
  165. package/registry/blocks/ask-bar/block.json +26 -0
  166. package/registry/blocks/ask-bar/demo.jsx +78 -0
  167. package/registry/blocks/ask-bar/index.js +3 -0
  168. package/registry/blocks/automation-editor/README.md +291 -0
  169. package/registry/blocks/automation-editor/automation-editor.jsx +656 -0
  170. package/registry/blocks/automation-editor/block.json +39 -0
  171. package/registry/blocks/automation-editor/demo.jsx +284 -0
  172. package/registry/blocks/automation-editor/index.js +4 -0
  173. package/registry/blocks/automation-editor/run-inputs.jsx +82 -0
  174. package/registry/blocks/automation-list/README.md +129 -0
  175. package/registry/blocks/automation-list/automation-list.jsx +476 -0
  176. package/registry/blocks/automation-list/block.json +35 -0
  177. package/registry/blocks/automation-list/demo.jsx +67 -0
  178. package/registry/blocks/automation-list/index.js +3 -0
  179. package/registry/blocks/automation-model/README.md +109 -0
  180. package/registry/blocks/automation-model/block.json +135 -0
  181. package/registry/blocks/automation-model/catalog.js +256 -0
  182. package/registry/blocks/automation-model/check.js +161 -0
  183. package/registry/blocks/automation-model/demo.jsx +42 -0
  184. package/registry/blocks/automation-model/edit.js +262 -0
  185. package/registry/blocks/automation-model/fixes.js +287 -0
  186. package/registry/blocks/automation-model/glyph.jsx +13 -0
  187. package/registry/blocks/automation-model/graph.js +410 -0
  188. package/registry/blocks/automation-model/index.js +33 -0
  189. package/registry/blocks/automation-model/overlay.js +175 -0
  190. package/registry/blocks/automation-model/parts.jsx +94 -0
  191. package/registry/blocks/automation-model/schedule.js +53 -0
  192. package/registry/blocks/automation-model/templates.js +128 -0
  193. package/registry/blocks/automation-model/values.js +29 -0
  194. package/registry/blocks/automation-model/words.js +439 -0
  195. package/registry/blocks/automations-screen/README.md +207 -0
  196. package/registry/blocks/automations-screen/automations-screen.jsx +452 -0
  197. package/registry/blocks/automations-screen/block.json +47 -0
  198. package/registry/blocks/automations-screen/demo.jsx +364 -0
  199. package/registry/blocks/automations-screen/index.js +4 -0
  200. package/registry/blocks/automations-screen/screen-model.js +129 -0
  201. package/registry/blocks/chat-pane/README.md +143 -0
  202. package/registry/blocks/chat-pane/block.json +48 -0
  203. package/registry/blocks/chat-pane/chat-attach.js +166 -0
  204. package/registry/blocks/chat-pane/chat-composer.jsx +195 -0
  205. package/registry/blocks/chat-pane/chat-context.js +17 -0
  206. package/registry/blocks/chat-pane/chat-model.js +43 -0
  207. package/registry/blocks/chat-pane/chat-pane.jsx +398 -0
  208. package/registry/blocks/chat-pane/chats-list.jsx +52 -0
  209. package/registry/blocks/chat-pane/demo.jsx +103 -0
  210. package/registry/blocks/chat-pane/index.js +9 -0
  211. package/registry/blocks/connect-card/README.md +99 -0
  212. package/registry/blocks/connect-card/block.json +10 -0
  213. package/registry/blocks/connect-card/connect-card.jsx +103 -0
  214. package/registry/blocks/connect-card/demo.jsx +49 -0
  215. package/registry/blocks/connect-card/index.js +3 -0
  216. package/registry/blocks/cost/README.md +115 -0
  217. package/registry/blocks/cost/block.json +10 -0
  218. package/registry/blocks/cost/cost.jsx +176 -0
  219. package/registry/blocks/cost/demo.jsx +66 -0
  220. package/registry/blocks/cost/index.js +3 -0
  221. package/registry/blocks/data-picker/README.md +81 -0
  222. package/registry/blocks/data-picker/block.json +38 -0
  223. package/registry/blocks/data-picker/data-picker.jsx +210 -0
  224. package/registry/blocks/data-picker/demo.jsx +34 -0
  225. package/registry/blocks/data-picker/fields.js +89 -0
  226. package/registry/blocks/data-picker/index.js +4 -0
  227. package/registry/blocks/data-table/demo.jsx +1 -1
  228. package/registry/blocks/first-run/README.md +118 -0
  229. package/registry/blocks/first-run/block.json +11 -0
  230. package/registry/blocks/first-run/demo.jsx +88 -0
  231. package/registry/blocks/first-run/first-run-model.js +51 -0
  232. package/registry/blocks/first-run/first-run.jsx +156 -0
  233. package/registry/blocks/first-run/index.js +5 -0
  234. package/registry/blocks/first-run/probe-rules.js +26 -0
  235. package/registry/blocks/fix-note/README.md +79 -0
  236. package/registry/blocks/fix-note/block.json +35 -0
  237. package/registry/blocks/fix-note/demo.jsx +30 -0
  238. package/registry/blocks/fix-note/fix-note.jsx +235 -0
  239. package/registry/blocks/fix-note/index.js +3 -0
  240. package/registry/blocks/flow-editor/README.md +108 -0
  241. package/registry/blocks/flow-editor/block.json +44 -0
  242. package/registry/blocks/flow-editor/demo.jsx +115 -0
  243. package/registry/blocks/flow-editor/flow-canvas.jsx +568 -0
  244. package/registry/blocks/flow-editor/flow-editor.jsx +154 -0
  245. package/registry/blocks/flow-editor/index.js +6 -0
  246. package/registry/blocks/flow-editor/minimap.jsx +78 -0
  247. package/registry/blocks/flow-editor/outline.jsx +134 -0
  248. package/registry/blocks/library-shelf/README.md +117 -0
  249. package/registry/blocks/library-shelf/block.json +28 -0
  250. package/registry/blocks/library-shelf/demo.jsx +68 -0
  251. package/registry/blocks/library-shelf/index.js +3 -0
  252. package/registry/blocks/library-shelf/library-shelf.jsx +211 -0
  253. package/registry/blocks/library-shelf/probe-rules.js +15 -0
  254. package/registry/blocks/margin-notes/README.md +222 -0
  255. package/registry/blocks/margin-notes/block.json +10 -0
  256. package/registry/blocks/margin-notes/demo.jsx +144 -0
  257. package/registry/blocks/margin-notes/index.js +20 -0
  258. package/registry/blocks/margin-notes/margin-model.js +224 -0
  259. package/registry/blocks/margin-notes/margin-notes.jsx +465 -0
  260. package/registry/blocks/needs-you/README.md +177 -0
  261. package/registry/blocks/needs-you/block.json +34 -0
  262. package/registry/blocks/needs-you/demo.jsx +143 -0
  263. package/registry/blocks/needs-you/index.js +3 -0
  264. package/registry/blocks/needs-you/needs-you.jsx +441 -0
  265. package/registry/blocks/pace-bar/README.md +230 -0
  266. package/registry/blocks/pace-bar/block.json +10 -0
  267. package/registry/blocks/pace-bar/demo.jsx +255 -0
  268. package/registry/blocks/pace-bar/index.js +22 -0
  269. package/registry/blocks/pace-bar/pace-bar.jsx +461 -0
  270. package/registry/blocks/pace-bar/pace-model.js +288 -0
  271. package/registry/blocks/record-grid/README.md +100 -0
  272. package/registry/blocks/record-grid/block.json +28 -0
  273. package/registry/blocks/record-grid/demo.jsx +43 -0
  274. package/registry/blocks/record-grid/index.js +3 -0
  275. package/registry/blocks/record-grid/record-grid.jsx +251 -0
  276. package/registry/blocks/run-history/README.md +138 -0
  277. package/registry/blocks/run-history/block.json +10 -0
  278. package/registry/blocks/run-history/demo.jsx +74 -0
  279. package/registry/blocks/run-history/index.js +3 -0
  280. package/registry/blocks/run-history/run-history.jsx +218 -0
  281. package/registry/blocks/run-view/README.md +174 -0
  282. package/registry/blocks/run-view/block.json +50 -0
  283. package/registry/blocks/run-view/demo.jsx +286 -0
  284. package/registry/blocks/run-view/index.js +5 -0
  285. package/registry/blocks/run-view/run-controls.jsx +266 -0
  286. package/registry/blocks/run-view/run-view.jsx +236 -0
  287. package/registry/blocks/run-view/runs-list.jsx +99 -0
  288. package/registry/blocks/schedule-card/README.md +121 -0
  289. package/registry/blocks/schedule-card/block.json +10 -0
  290. package/registry/blocks/schedule-card/demo.jsx +82 -0
  291. package/registry/blocks/schedule-card/index.js +3 -0
  292. package/registry/blocks/schedule-card/schedule-card.jsx +136 -0
  293. package/registry/blocks/schedule-engine/README.md +137 -0
  294. package/registry/blocks/schedule-engine/block.json +10 -0
  295. package/registry/blocks/schedule-engine/demo.jsx +82 -0
  296. package/registry/blocks/schedule-engine/engine.js +769 -0
  297. package/registry/blocks/schedule-engine/index.js +9 -0
  298. package/registry/blocks/schedule-engine/ops.js +71 -0
  299. package/registry/blocks/schedule-engine/place.js +294 -0
  300. package/registry/blocks/schedule-engine/tree.js +79 -0
  301. package/registry/blocks/schedule-engine/waits.js +80 -0
  302. package/registry/blocks/schedule-gantt/README.md +159 -0
  303. package/registry/blocks/schedule-gantt/block.json +10 -0
  304. package/registry/blocks/schedule-gantt/demo.jsx +223 -0
  305. package/registry/blocks/schedule-gantt/gantt-model.js +219 -0
  306. package/registry/blocks/schedule-gantt/geometry.js +176 -0
  307. package/registry/blocks/schedule-gantt/index.js +26 -0
  308. package/registry/blocks/schedule-gantt/schedule-gantt.jsx +882 -0
  309. package/registry/blocks/schedule-gantt/sheet.jsx +372 -0
  310. package/registry/blocks/schedule-gantt/track.jsx +190 -0
  311. package/registry/blocks/schedule-ruler/README.md +148 -0
  312. package/registry/blocks/schedule-ruler/block.json +10 -0
  313. package/registry/blocks/schedule-ruler/demo.jsx +181 -0
  314. package/registry/blocks/schedule-ruler/index.js +21 -0
  315. package/registry/blocks/schedule-ruler/ruler-model.js +239 -0
  316. package/registry/blocks/schedule-ruler/schedule-ruler.jsx +548 -0
  317. package/registry/blocks/source-receipt/README.md +97 -0
  318. package/registry/blocks/source-receipt/block.json +30 -0
  319. package/registry/blocks/source-receipt/demo.jsx +71 -0
  320. package/registry/blocks/source-receipt/index.js +3 -0
  321. package/registry/blocks/source-receipt/source-receipt.jsx +107 -0
  322. package/registry/blocks/spreadsheet/spreadsheet.jsx +15 -1
  323. package/registry/blocks/step-picker/README.md +78 -0
  324. package/registry/blocks/step-picker/block.json +31 -0
  325. package/registry/blocks/step-picker/demo.jsx +23 -0
  326. package/registry/blocks/step-picker/index.js +3 -0
  327. package/registry/blocks/step-picker/step-picker.jsx +144 -0
  328. package/registry/blocks/step-settings/README.md +100 -0
  329. package/registry/blocks/step-settings/block.json +44 -0
  330. package/registry/blocks/step-settings/demo.jsx +93 -0
  331. package/registry/blocks/step-settings/fields.jsx +58 -0
  332. package/registry/blocks/step-settings/flow-settings.jsx +115 -0
  333. package/registry/blocks/step-settings/index.js +5 -0
  334. package/registry/blocks/step-settings/step-settings.jsx +290 -0
  335. package/registry/blocks/suggestion/README.md +171 -0
  336. package/registry/blocks/suggestion/block.json +40 -0
  337. package/registry/blocks/suggestion/demo.jsx +91 -0
  338. package/registry/blocks/suggestion/index.js +3 -0
  339. package/registry/blocks/suggestion/suggestion.jsx +436 -0
  340. package/registry/blocks/sum-bar/README.md +122 -0
  341. package/registry/blocks/sum-bar/block.json +10 -0
  342. package/registry/blocks/sum-bar/demo.jsx +110 -0
  343. package/registry/blocks/sum-bar/index.js +5 -0
  344. package/registry/blocks/sum-bar/sum-bar.jsx +209 -0
  345. package/registry/blocks/sum-bar/sum-model.js +126 -0
  346. package/registry/blocks/tier-map/README.md +217 -0
  347. package/registry/blocks/tier-map/block.json +10 -0
  348. package/registry/blocks/tier-map/demo.jsx +222 -0
  349. package/registry/blocks/tier-map/index.js +24 -0
  350. package/registry/blocks/tier-map/tier-map.jsx +574 -0
  351. package/registry/blocks/tier-map/tier-model.js +318 -0
  352. package/registry/blocks/time-grid/README.md +305 -0
  353. package/registry/blocks/time-grid/block.json +10 -0
  354. package/registry/blocks/time-grid/demo.jsx +279 -0
  355. package/registry/blocks/time-grid/grid-model.js +322 -0
  356. package/registry/blocks/time-grid/index.js +25 -0
  357. package/registry/blocks/time-grid/time-grid.jsx +1325 -0
  358. package/registry/blocks/time-strip/README.md +141 -0
  359. package/registry/blocks/time-strip/block.json +10 -0
  360. package/registry/blocks/time-strip/demo.jsx +129 -0
  361. package/registry/blocks/time-strip/index.js +19 -0
  362. package/registry/blocks/time-strip/strip-model.js +178 -0
  363. package/registry/blocks/time-strip/time-strip.jsx +260 -0
  364. package/registry/blocks/top-bar/README.md +149 -0
  365. package/registry/blocks/top-bar/block.json +35 -0
  366. package/registry/blocks/top-bar/demo.jsx +78 -0
  367. package/registry/blocks/top-bar/index.js +5 -0
  368. package/registry/blocks/top-bar/probe-rules.js +74 -0
  369. package/registry/blocks/top-bar/top-bar-model.js +152 -0
  370. package/registry/blocks/top-bar/top-bar.jsx +244 -0
  371. package/registry/blocks/trigger-picker/README.md +98 -0
  372. package/registry/blocks/trigger-picker/block.json +38 -0
  373. package/registry/blocks/trigger-picker/demo.jsx +59 -0
  374. package/registry/blocks/trigger-picker/index.js +3 -0
  375. package/registry/blocks/trigger-picker/trigger-picker.jsx +374 -0
  376. package/registry/blocks/workflow-view/README.md +123 -0
  377. package/registry/blocks/workflow-view/block.json +10 -0
  378. package/registry/blocks/workflow-view/demo.jsx +90 -0
  379. package/registry/blocks/workflow-view/index.js +3 -0
  380. package/registry/blocks/workflow-view/workflow-view.jsx +203 -0
  381. package/src/install.mjs +77 -16
  382. package/src/registry.mjs +3 -0
  383. package/templates/next/browser/lib/data.js +6 -1
  384. package/templates/next/files/README.md +627 -24
  385. package/templates/next/files/check/automation-format.ts +2103 -0
  386. package/templates/next/files/check/automation-package.ts +142 -0
  387. package/templates/next/files/check/run.mjs +968 -9
  388. package/templates/next/files/components/ui/field.jsx +17 -4
  389. package/templates/next/files/components/ui/icon.jsx +13 -0
  390. package/templates/next/files/components/ui/index.js +2 -1
  391. package/templates/next/files/components/ui/layout.jsx +77 -2
  392. package/templates/next/files/components/ui/notice.jsx +70 -0
  393. package/templates/next/files/components/ui/page.jsx +124 -0
  394. package/templates/next/files/components/ui/stat.jsx +22 -7
  395. package/templates/next/files/components/ui/toast.jsx +6 -3
  396. package/templates/next/files/lib/automations.js +660 -0
  397. package/templates/next/files/lib/claw.js +241 -5
  398. package/templates/next/files/lib/door.js +92 -0
  399. package/templates/next/files/lib/hooks.js +1627 -8
  400. package/templates/next/files/lib/platform.js +529 -21
  401. package/templates/next/template.json +13 -3
@@ -0,0 +1,152 @@
1
+ // The top bar's rules, as plain functions and one table: what the bar draws
2
+ // at a given width, in what order things give way, and whether Ask is drawn.
3
+ // No React here, so a test can walk every width and the server can use it.
4
+ //
5
+ // Why a table (2026-10-12, the UI review): fourteen apps drew their own top
6
+ // bar, and in Newsletter the week's allowance ran into Find. A bar that is
7
+ // told only "hide this under 56rem" overlaps the day an app adds a longer
8
+ // button. So every piece has a width it is allowed to take (`rem`) and the
9
+ // bar width it appears from (`from`, a Tailwind container size), and a test
10
+ // walks the widths from a phone to a wide desk and checks that what is drawn
11
+ // always fits. The CSS classes in `SHOW` are written from the same table.
12
+
13
+ /** Container sizes, in rem, as Tailwind v4 names them (@lg = 32rem…). */
14
+ export const SIZES = { xs: 20, sm: 24, md: 28, lg: 32, xl: 36, "2xl": 42, "3xl": 48, "4xl": 56, "5xl": 64, "6xl": 72 };
15
+
16
+ /** The width the bar has to give each piece, in rem, and where it appears.
17
+ * `from: null` is always drawn. The crumb's last label is the floor: it
18
+ * truncates, but never gives up the room it is counted here. `extra` and
19
+ * the action's label are the app's: they are held to these widths (the
20
+ * README says how; `BarText` hides a label under `lg`). */
21
+ export const PIECES = [
22
+ { key: "lead", rem: 2.5, from: null },
23
+ { key: "crumb", rem: 5, from: null },
24
+ { key: "find", rem: 2.5, from: null },
25
+ { key: "ask", rem: 2.5, from: null },
26
+ { key: "action", rem: 2.5, from: null },
27
+ { key: "findLabel", rem: 3.5, from: "lg" },
28
+ { key: "askLabel", rem: 2.5, from: "lg" },
29
+ { key: "actionLabel", rem: 7, from: "lg" },
30
+ { key: "trail", rem: 0, from: "xl" }, // earlier crumbs and the note: they truncate, so they take what is left and no more
31
+ { key: "findKey", rem: 3.2, from: "2xl" },
32
+ { key: "extra", rem: 12, from: "3xl" },
33
+ { key: "allowance", rem: 5, from: "4xl" },
34
+ { key: "allowanceWords", rem: 8, from: "5xl" },
35
+ ];
36
+
37
+ /** Space between neighbours, in rem (gap-1.5). */
38
+ export const GAP = 0.375;
39
+
40
+ /** The classes that show a piece from its size and hide it under, written
41
+ * whole so Tailwind reads them. */
42
+ export const SHOW = {
43
+ findLabel: "hidden @lg/bar:inline",
44
+ askLabel: "hidden @lg/bar:inline",
45
+ // The action's words stay for a screen reader under 32rem (a button that is
46
+ // only its icon still has its name): sr-only there, drawn from 32rem.
47
+ actionLabel: "sr-only @lg/bar:not-sr-only",
48
+ trailFlex: "hidden @xl/bar:flex",
49
+ trailInline: "hidden @xl/bar:inline",
50
+ findKey: "hidden @2xl/bar:inline-flex",
51
+ extra: "hidden @3xl/bar:flex",
52
+ allowance: "hidden @4xl/bar:flex",
53
+ allowanceWords: "hidden @5xl/bar:inline",
54
+ };
55
+
56
+ const has = (piece, present) => (piece.key.startsWith("find") ? present.find : piece.key.startsWith("ask") ? present.ask : true);
57
+
58
+ /** The pieces drawn in a bar `rem` wide. `present`: { find, ask } say whether
59
+ * those are drawn at all (an app can leave Find out; it can never leave
60
+ * Ask out when it has a dock). */
61
+ export function visibleAt(rem, present = { find: true, ask: true }) {
62
+ return PIECES.filter((p) => has(p, present) && (p.from === null || rem >= SIZES[p.from])).map((p) => p.key);
63
+ }
64
+
65
+ /** The room the drawn pieces take at `rem`, gaps included. A label rides
66
+ * inside its button, so only these items have a gap between them. */
67
+ const ITEMS = ["lead", "crumb", "find", "ask", "action", "extra", "allowance"];
68
+ export function usedAt(rem, present = { find: true, ask: true }) {
69
+ const keys = new Set(visibleAt(rem, present));
70
+ const sum = PIECES.filter((p) => keys.has(p.key)).reduce((n, p) => n + p.rem, 0);
71
+ const items = ITEMS.filter((k) => keys.has(k)).length;
72
+ return sum + Math.max(0, items - 1) * GAP;
73
+ }
74
+
75
+ /** True when what is drawn at `rem` fits with nothing over it. */
76
+ export function fitsAt(rem, present) {
77
+ return usedAt(rem, present) <= rem;
78
+ }
79
+
80
+ /** The narrowest bar the table is true for: what is always drawn. */
81
+ export function floorRem(present) {
82
+ return usedAt(0, present);
83
+ }
84
+
85
+ /** Is Ask drawn? Whenever the app has an agent to ask: a dock handed over,
86
+ * an `onAsk`, or an AskProvider above the bar. There is no prop that turns
87
+ * it off, and that is the point: an app with a dock cannot have an agent
88
+ * nobody can open. */
89
+ export function askDrawn({ dock, onAsk, context } = {}) {
90
+ return Boolean(dock || onAsk || context);
91
+ }
92
+
93
+ /** What pressing Ask does: an `onAsk` the app gave wins, then the dock's
94
+ * toggle, then the provider's. Null when there is nothing to open. */
95
+ export function askAction({ dock, onAsk, context } = {}) {
96
+ if (typeof onAsk === "function") return onAsk;
97
+ if (dock && typeof dock.toggle === "function") return dock.toggle;
98
+ if (context && typeof context.toggle === "function") return context.toggle;
99
+ return null;
100
+ }
101
+
102
+ /** Whether the agent is open, for aria-pressed. */
103
+ export function askOpen({ dock, asking, context } = {}) {
104
+ if (typeof asking === "boolean") return asking;
105
+ if (dock && typeof dock.open === "boolean") return dock.open;
106
+ if (context && typeof context.open === "boolean") return context.open;
107
+ return false;
108
+ }
109
+
110
+ /** The props a screen's TopBar may leave to the shell: the week's allowance
111
+ * and how Find is reached are the same on every screen of an app, so the
112
+ * shell says them once on its AskProvider and a bar uses them unless it
113
+ * passes its own. */
114
+ export const BAR_DEFAULTS = ["allowance", "allowanceLabel", "allowanceUnit", "allowancePeriod", "onFind", "findEvent", "findLabel", "findWord", "askLabel"];
115
+
116
+ /** The shell's defaults, from the props it gave AskProvider: only the keys it
117
+ * set, `undefined` ones left out. */
118
+ export function barDefaultsOf(props = {}) {
119
+ const out = {};
120
+ for (const key of BAR_DEFAULTS) if (props[key] !== undefined) out[key] = props[key];
121
+ return out;
122
+ }
123
+
124
+ /** One screen's bar props over the shell's defaults. A prop the screen passes
125
+ * (even `null`, which leaves the allowance out for that screen) wins; one it
126
+ * leaves `undefined` takes the shell's; else the built-in ("cr", "this
127
+ * week"). */
128
+ export function resolveBar(own = {}, defaults = {}) {
129
+ const out = {};
130
+ for (const key of BAR_DEFAULTS) out[key] = own[key] !== undefined ? own[key] : defaults[key];
131
+ out.allowanceUnit ??= "cr";
132
+ out.allowancePeriod ??= "this week";
133
+ return out;
134
+ }
135
+
136
+ /** The allowance as { left, used, cap, pct } from the platform's budget
137
+ * ({ used, cap }); null when there is no cap to count against. */
138
+ export function allowanceOf(allowance) {
139
+ const cap = Number(allowance?.cap);
140
+ if (!allowance || !Number.isFinite(cap) || cap <= 0) return null;
141
+ const used = Math.max(0, Number(allowance.used) || 0);
142
+ return { used, cap, left: Math.max(0, cap - used), pct: Math.min(100, Math.round((used / cap) * 100)) };
143
+ }
144
+
145
+ const num = (n) => Math.round(Number(n)).toLocaleString("en-US");
146
+
147
+ /** The allowance in words: "15,000 cr left" and, from 64rem, " this week". */
148
+ export function allowanceWords(allowance, { unit = "cr", period = "this week" } = {}) {
149
+ const a = allowanceOf(allowance);
150
+ if (!a) return null;
151
+ return { short: `${num(a.left)} ${unit} left`, long: `${num(a.left)} ${unit} left ${period}`, period, left: a.left, cap: a.cap };
152
+ }
@@ -0,0 +1,244 @@
1
+ "use client";
2
+
3
+ import { createContext, useCallback, useContext, useMemo } from "react";
4
+ import { createPortal } from "react-dom";
5
+ import { Button, Icon, IconButton, Kbd, Meter, cx } from "../../ui";
6
+ import { SHOW, allowanceOf, allowanceWords, askAction, askDrawn, askOpen, barDefaultsOf, resolveBar } from "./top-bar-model";
7
+
8
+ // TopBar — the one bar every app draws over its work (2026-10-12). It holds
9
+ // where you are, the week's allowance, Find, Ask and the page's action, and
10
+ // it gives way in a set order as the app's window narrows, so nothing runs
11
+ // into anything:
12
+ //
13
+ // always the menu/lead, the last crumb, Find and Ask as icons, the action
14
+ // from 32rem the words on Find, Ask and the action (BarText)
15
+ // from 36rem the earlier crumbs and the note
16
+ // from 42rem the ⌘K key on Find
17
+ // from 48rem `extra` (a switch, a chip)
18
+ // from 56rem the allowance, as a bar
19
+ // from 64rem the allowance in words
20
+ //
21
+ // The sizes are measures of the BAR, not the window: the app lives in a frame
22
+ // on the desk, and an open agent dock takes a quarter of it. top-bar-model.js
23
+ // holds the table; a test walks every width and checks what is drawn fits.
24
+ //
25
+ // Ask is never optional. If the app has an agent to ask (a `dock` from
26
+ // useAgentDock, an `onAsk`, or an AskProvider above the bar) the bar draws
27
+ // Ask and it opens the agent. There is no prop that leaves it out, so an app
28
+ // that mounts an AgentDock cannot have an agent nobody can reach (Gantt
29
+ // Planner, 2026-10-12: the dock was mounted and no button opened it).
30
+ // `npm run check` (rule 19, ask) refuses the app that mounts a dock without
31
+ // one.
32
+
33
+ /** Where a screen's bar goes: the shell's header slot (an element). Leave it
34
+ * unprovided and the bar draws where it is rendered (as an AppLayout's
35
+ * `header`); provide null until the slot has mounted and it draws nothing. */
36
+ export const TopBarSlot = createContext(undefined);
37
+
38
+ const AskContext = createContext(null);
39
+ const BarContext = createContext({});
40
+
41
+ /** Put the app's agent within reach of every bar below, and say the bar's
42
+ * defaults once: the shell wraps its layout in it, with the dock
43
+ * useAgentDock() returned, and no screen has to pass anything to its TopBar.
44
+ * dock what useAgentDock() returned ({ open, toggle })
45
+ * onAsk or your own opener, when there is no dock yet
46
+ * open with onAsk: whether the agent is open (aria-pressed)
47
+ * and the props every screen's bar repeats, which a bar uses unless it passes
48
+ * its own (pass `allowance={null}` on a screen to leave it out there):
49
+ * allowance, allowanceLabel, allowanceUnit, allowancePeriod
50
+ * findEvent, onFind, findLabel, findWord
51
+ * askLabel */
52
+ export function AskProvider({ dock, onAsk, open, children, ...bar }) {
53
+ const toggle = askAction({ dock, onAsk });
54
+ const isOpen = askOpen({ dock, asking: open });
55
+ const value = useMemo(() => (toggle ? { toggle, open: isOpen } : null), [toggle, isOpen]);
56
+ const d = barDefaultsOf(bar);
57
+ // The allowance is a fresh object each render; what matters is its numbers.
58
+ const key = JSON.stringify([d.allowance?.used ?? null, d.allowance?.cap ?? null, d.allowanceLabel, d.allowanceUnit, d.allowancePeriod, d.findEvent, d.findLabel, d.findWord, d.askLabel]);
59
+ const defaults = useMemo(() => d, [key, d.onFind]); // eslint-disable-line react-hooks/exhaustive-deps
60
+ return (
61
+ <AskContext.Provider value={value}>
62
+ <BarContext.Provider value={defaults}>{children}</BarContext.Provider>
63
+ </AskContext.Provider>
64
+ );
65
+ }
66
+
67
+ /** { toggle, open } from the nearest AskProvider, or null. */
68
+ export function useAsk() {
69
+ return useContext(AskContext);
70
+ }
71
+
72
+ /** A label for the bar's buttons that gives way under 32rem, leaving the
73
+ * icon; a screen reader still hears it (it is sr-only there, so an icon-only
74
+ * button keeps its name). Use it for the action's words: `<Button
75
+ * icon="plus"><BarText>New issue</BarText></Button>`. The button needs an
76
+ * icon, or under 32rem there is nothing to see (npm run check, rule
77
+ * barlabel). Keep the words to about 12 characters. */
78
+ export function BarText({ children, className }) {
79
+ return <span className={cx(SHOW.actionLabel, className)}>{children}</span>;
80
+ }
81
+
82
+ /** The Ask button. TopBar draws it; use it on its own only in a bar of your
83
+ * own that cannot be a TopBar (the check accepts it as the way in).
84
+ * dock, onAsk, asking as AskProvider; the provider's is the default
85
+ * label the words from 32rem. Default "Ask" */
86
+ export function AskButton({ dock, onAsk, asking, label = "Ask", className }) {
87
+ const context = useContext(AskContext);
88
+ const act = askAction({ dock, onAsk, context });
89
+ const on = useCallback(() => act?.(), [act]);
90
+ if (!askDrawn({ dock, onAsk, context })) return null;
91
+ return (
92
+ <Button size="sm" onClick={on} data-bar-piece="ask" aria-label="Ask the agent" aria-pressed={askOpen({ dock, asking, context })} className={className}>
93
+ <Icon name="sparkles" size={14} />
94
+ <span className={SHOW.askLabel}>{label}</span>
95
+ </Button>
96
+ );
97
+ }
98
+
99
+ /** The Find button. `onFind`, or else a window event named `event` (the
100
+ * app's finder listens for it).
101
+ * label what a screen reader hears ("Find an issue, a change or a post")
102
+ * word the visible word from 32rem. Default "Find" */
103
+ export function FindButton({ onFind, event = "app:find", label = "Find", word = "Find", className }) {
104
+ const on = () => (onFind ? onFind() : window.dispatchEvent(new CustomEvent(event)));
105
+ return (
106
+ <Button size="sm" onClick={on} data-bar-piece="find" aria-label={label} className={className}>
107
+ <Icon name="search" size={14} />
108
+ <span className={SHOW.findLabel}>{word}</span>
109
+ <Kbd className={SHOW.findKey}>⌘K</Kbd>
110
+ </Button>
111
+ );
112
+ }
113
+
114
+ // The allowance: its words, then the kit's Meter in its compact form (the bar
115
+ // alone; the label and the numbers go to a screen reader and the tooltip).
116
+ function AllowanceBar({ allowance, unit, period, label }) {
117
+ const a = allowanceOf(allowance);
118
+ const words = allowanceWords(allowance, { unit, period });
119
+ if (!a) return null;
120
+ return (
121
+ <span data-bar-piece="allowance" className={cx(SHOW.allowance, "shrink-0 items-center gap-2 whitespace-nowrap text-xs text-muted-foreground")}>
122
+ <span className="tabular-nums">
123
+ {words.short}
124
+ <span className={SHOW.allowanceWords}> {period}</span>
125
+ </span>
126
+ <Meter value={a.used} max={a.cap} label={label ?? "Allowance"} unit={unit} valueText={null} size="thin" compact className="w-14" />
127
+ </span>
128
+ );
129
+ }
130
+
131
+ function Crumb({ items, back }) {
132
+ const last = items[items.length - 1];
133
+ return (
134
+ <nav aria-label="Where you are" data-bar-piece="crumb" className="flex min-w-0 shrink items-center gap-1.5 overflow-hidden whitespace-nowrap font-medium">
135
+ {back ? <IconButton icon="chevron-left" label="Back" size="sm" href={back} /> : null}
136
+ {items.map((c, i) => {
137
+ const here = c === last;
138
+ return (
139
+ <span key={`${c.label}-${i}`} className={cx("flex min-w-0 items-center gap-1.5", here ? "shrink" : cx(SHOW.trailFlex, "shrink-[4]"))}>
140
+ {i ? (
141
+ <span aria-hidden="true" className={SHOW.trailInline}>
142
+ <Icon name="chevron-right" size={12} className="shrink-0 text-muted-foreground" />
143
+ </span>
144
+ ) : null}
145
+ {c.href && !here ? (
146
+ <span className="min-w-0 truncate font-normal">
147
+ <Button variant="link" tone="muted" size="inherit" href={c.href}>
148
+ {c.label}
149
+ </Button>
150
+ </span>
151
+ ) : (
152
+ <span className={cx("min-w-0 truncate", c.muted && "font-normal text-muted-foreground")} aria-current={here ? "page" : undefined}>
153
+ {c.label}
154
+ </span>
155
+ )}
156
+ </span>
157
+ );
158
+ })}
159
+ </nav>
160
+ );
161
+ }
162
+
163
+ /**
164
+ * One screen's top bar.
165
+ *
166
+ * lead a node before everything (the sidebar trigger, a period picker)
167
+ * back a path: a back button before the crumb
168
+ * crumb [{ label, href?, muted? }]: where you are; the last is this screen
169
+ * note muted words after the crumb (from 36rem)
170
+ * extra nodes before the allowance (from 48rem)
171
+ * allowance { used, cap } of the week's credits, from the platform's budget
172
+ * (null: nothing drawn). `allowanceLabel`, `allowanceUnit` ("cr"),
173
+ * `allowancePeriod` ("this week"). Left out, the shell's
174
+ * AskProvider says them once; null leaves it out on this screen
175
+ * find false leaves Find out. `onFind`, or `findEvent` (a window event;
176
+ * default "app:find"), `findLabel` (for a screen reader), `findWord`.
177
+ * Left out, the AskProvider's are used
178
+ * dock what useAgentDock() returns: Ask opens it
179
+ * onAsk or your own opener. Neither: the nearest AskProvider's. If none,
180
+ * the app has no agent and no Ask is drawn
181
+ * asking whether the agent is open, when you pass onAsk
182
+ * askLabel the word on Ask. Default "Ask"
183
+ * action the screen's main action, last in the bar: a Button whose words
184
+ * are <BarText>
185
+ * className spacing only
186
+ *
187
+ * It draws where it is rendered (as an AppLayout `header`), or into the
188
+ * shell's header slot when a TopBarSlot is provided.
189
+ */
190
+ export function TopBar({
191
+ lead,
192
+ back,
193
+ crumb = [],
194
+ note,
195
+ extra,
196
+ allowance: allowanceOwn,
197
+ allowanceLabel: allowanceLabelOwn,
198
+ allowanceUnit: allowanceUnitOwn,
199
+ allowancePeriod: allowancePeriodOwn,
200
+ find = true,
201
+ onFind: onFindOwn,
202
+ findEvent: findEventOwn,
203
+ findLabel: findLabelOwn,
204
+ findWord: findWordOwn,
205
+ dock,
206
+ onAsk,
207
+ asking,
208
+ askLabel: askLabelOwn,
209
+ action,
210
+ className,
211
+ }) {
212
+ const slot = useContext(TopBarSlot);
213
+ const defaults = useContext(BarContext);
214
+ if (slot === null) return null;
215
+ // What this screen did not pass, the shell's AskProvider said once.
216
+ const { allowance, allowanceLabel, allowanceUnit, allowancePeriod, onFind, findEvent, findLabel, findWord, askLabel } = resolveBar(
217
+ {
218
+ allowance: allowanceOwn,
219
+ allowanceLabel: allowanceLabelOwn,
220
+ allowanceUnit: allowanceUnitOwn,
221
+ allowancePeriod: allowancePeriodOwn,
222
+ onFind: onFindOwn,
223
+ findEvent: findEventOwn,
224
+ findLabel: findLabelOwn,
225
+ findWord: findWordOwn,
226
+ askLabel: askLabelOwn,
227
+ },
228
+ defaults,
229
+ );
230
+ const bar = (
231
+ <div data-top-bar className={cx("@container/bar flex h-10 min-w-0 items-center gap-1.5", slot === undefined && "px-2 sm:px-3", className)}>
232
+ {lead ? <span className="flex shrink-0 items-center">{lead}</span> : null}
233
+ <Crumb items={crumb} back={back} />
234
+ {note ? <span data-bar-piece="note" className={cx(SHOW.trailInline, "min-w-0 shrink-[4] truncate whitespace-nowrap text-muted-foreground")}>{note}</span> : null}
235
+ <span className="min-w-0 flex-1" />
236
+ {extra ? <span data-bar-piece="extra" className={cx(SHOW.extra, "shrink-0 items-center gap-1.5")}>{extra}</span> : null}
237
+ <AllowanceBar allowance={allowance} unit={allowanceUnit} period={allowancePeriod} label={allowanceLabel} />
238
+ {find ? <FindButton onFind={onFind} event={findEvent} label={findLabel} word={findWord} className="shrink-0" /> : null}
239
+ <AskButton dock={dock} onAsk={onAsk} asking={asking} label={askLabel} className="shrink-0" />
240
+ {action ? <span data-bar-piece="action" className="flex shrink-0 items-center">{action}</span> : null}
241
+ </div>
242
+ );
243
+ return slot === undefined ? bar : createPortal(bar, slot);
244
+ }
@@ -0,0 +1,98 @@
1
+ # TriggerPicker
2
+
3
+ What starts an automation, as a panel. Seven ways, and the platform says
4
+ which of them it runs:
5
+
6
+ - **By hand**: someone presses Run, or the agent runs it.
7
+ - **On a schedule**: every day, every weekday, every week, every hour, or
8
+ another schedule written as a five-field cron, with a time of day (or the
9
+ minute past the hour, or the weekday) and a sentence that says it back:
10
+ "Runs weekdays at 07:00, team time." **The team's time zone** is the
11
+ default, and it is the point: 07:00 stays 07:00 through daylight saving,
12
+ whoever is looking. A schedule the picker cannot read back stays the
13
+ custom cron it was.
14
+ - **When an app sends an event**: a topic like `rows.imported`. A team
15
+ automation may name the app it hears. Events that carry a `key` run once
16
+ per item; events without one run at most once in five minutes.
17
+ - **When an app action finishes**: one of the app's declared actions, done
18
+ by a person or by the app's agent. An action another automation ran does
19
+ not start it (that would loop); "after another automation" is for that.
20
+ - **When a record is added or changed**: in the company brain, for the
21
+ kinds picked (none picked: every kind the owner can read), added and/or
22
+ changed. One run for each record, looked at once a minute. Changes the
23
+ app's own jobs make do not start it.
24
+ - **When its web address is called**: the automation's own address, which
25
+ any system can post JSON to. The panel makes the secret, shows it once,
26
+ and replaces it on request (the old one stops at once). The sender signs
27
+ the body with it, or adds `?token=<secret>` to the address when it cannot
28
+ sign.
29
+ - **When another automation finishes**: done, failed, or either. The
30
+ platform refuses a loop when the automation is saved.
31
+
32
+ A connection's own events (a new mail, a new row in a sheet) are listed as
33
+ **soon**, with what to use until then.
34
+
35
+ ```jsx
36
+ import { TriggerPicker } from "../components/blocks/trigger-picker"; // a Makersclaw app
37
+ import { TriggerPicker } from "@/components/makersclaw/blocks/trigger-picker"; // a shadcn project
38
+ ```
39
+
40
+ `makersclaw add trigger-picker` lays `automation-model` with it. A client
41
+ component. It is a panel (a head, a body): place it beside or over the
42
+ canvas. `automation-editor` does that when the trigger card is pressed, and
43
+ passes it what the hooks give it.
44
+
45
+ ## Props
46
+
47
+ - `trigger`: `{ type: "manual" }`, `{ type: "schedule", cron, tz }`,
48
+ `{ type: "event", topic, app? }`, `{ type: "action", action, app? }`,
49
+ `{ type: "record", kinds?, ops?, app? }`, `{ type: "webhook" }` or
50
+ `{ type: "automation", key, when }` (`tz` is `"team"` or an IANA zone).
51
+ - `onChange(trigger)`: a whole new trigger, ready to put into the
52
+ definition.
53
+ - `catalog`: what the platform offers, `useAutomations().triggers`:
54
+ `{ choices: [{ type, label, hint, available, why? }], apps: [{ name,
55
+ actions: [{ name, description }], kinds, topics }], automations: [{ key,
56
+ name }] }`. Without it the panel offers by hand and a schedule and lists
57
+ `later` as "soon" (a platform from before the other triggers).
58
+ - `ownedByApp`: the automation belongs to an app, so its actions, kinds and
59
+ topics are that app's (the first of `catalog.apps`); a team automation
60
+ picks an app.
61
+ - `selfKey`: this automation's key, which it cannot follow.
62
+ - `hook`: a webhook trigger's address once the automation is saved,
63
+ `useAutomation(id).hook`: `{ path, has_secret, rotated_at, last_received_at }`.
64
+ - `onRotateHook()`: makes or replaces the secret; resolves `{ ok: true,
65
+ hook: { secret } }` (`useAutomation(id).rotateHook`).
66
+ - `origin`: where the address lives (default: this page's origin).
67
+ - `readOnly`: shown, not editable.
68
+ - `onClose`: draws the close button.
69
+ - `later`: without a `catalog`, the ways to start that are not built yet,
70
+ `[{ id, label, hint }]`.
71
+
72
+ ## Never
73
+
74
+ - Never show a schedule in the viewer's time zone: say it in the
75
+ automation's.
76
+ - Never offer a trigger the platform does not run without saying "soon".
77
+ - Never keep the webhook's secret anywhere after it has been shown: the
78
+ platform does not send it again.
79
+
80
+ ## Example
81
+
82
+ ```jsx
83
+ "use client";
84
+ import { useState } from "react";
85
+ import { useAutomation, useAutomations } from "../lib/hooks";
86
+ import { TriggerPicker } from "../components/blocks/trigger-picker";
87
+
88
+ export default function WhenItRuns({ id }) {
89
+ const { triggers } = useAutomations();
90
+ const { automation, definition, hook, rotateHook } = useAutomation(id);
91
+ const [trigger, setTrigger] = useState(definition?.trigger ?? { type: "manual" });
92
+ return (
93
+ <div className="max-w-sm overflow-hidden rounded-lg border border-border">
94
+ <TriggerPicker trigger={trigger} onChange={setTrigger} catalog={triggers} ownedByApp selfKey={automation?.key} hook={hook} onRotateHook={rotateHook} />
95
+ </div>
96
+ );
97
+ }
98
+ ```
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "trigger-picker",
3
+ "title": "TriggerPicker",
4
+ "description": "What starts an automation, as a panel: by hand, on a schedule in the team's time zone, when an app sends an event, when one of an app's actions finishes, when a record is added or changed, when the automation's own web address is called (its secret made and replaced here, shown once), or when another automation finishes. The platform says which of these it runs (the list door's triggers); a connection's own events are listed as \"soon\" with what to use meanwhile. The schedule is offered in the shapes people ask for (every day, every weekday, every week, every hour, another schedule as five-field cron) with a time of day, a weekday, the team's zone or another, and a sentence saying it back (\"Runs weekdays at 07:00, team time\").",
5
+ "useWhen": "An automation's trigger is edited in your own screen. automation-editor opens it when the trigger card is pressed; pass it the platform's triggers (useAutomations().triggers) so it offers what the platform runs.",
6
+ "tags": [
7
+ "automation",
8
+ "workflow",
9
+ "trigger",
10
+ "schedule",
11
+ "cron",
12
+ "time",
13
+ "when",
14
+ "every day",
15
+ "weekday",
16
+ "time zone",
17
+ "manual",
18
+ "n8n",
19
+ "make",
20
+ "event",
21
+ "webhook",
22
+ "record",
23
+ "action",
24
+ "web address",
25
+ "secret",
26
+ "follow"
27
+ ],
28
+ "exports": [
29
+ "TriggerPicker"
30
+ ],
31
+ "files": [
32
+ "index.js",
33
+ "trigger-picker.jsx"
34
+ ],
35
+ "requires": [
36
+ "automation-model"
37
+ ]
38
+ }
@@ -0,0 +1,59 @@
1
+ "use client";
2
+
3
+ // TriggerPicker — the gallery's and the smoke test's surface. Not
4
+ // installed into apps. Switch between the ways to start (by hand, a
5
+ // schedule, an event, an action, a record, a web address, after another
6
+ // automation): the sentence under the title says it back. The second panel
7
+ // is a platform from before the other triggers (by hand and a schedule,
8
+ // the rest listed as soon); the third is read-only.
9
+ import { useState } from "react";
10
+ import { TriggerPicker } from "../components/blocks/trigger-picker";
11
+
12
+ const CATALOG = {
13
+ choices: [
14
+ { type: "manual", label: "By hand", hint: "Someone presses Run, or the agent runs it.", available: true },
15
+ { type: "schedule", label: "On a schedule", hint: "Every day, every weekday, every hour.", available: true },
16
+ { type: "event", label: "When an app sends an event", hint: "An app announces something, like rows.imported.", available: true },
17
+ { type: "action", label: "When an app action finishes", hint: "A person or the app's agent ran one of its actions.", available: true },
18
+ { type: "record", label: "When a record is added or changed", hint: "A new person, a changed deal, in the company brain.", available: true },
19
+ { type: "webhook", label: "When its web address is called", hint: "Another system posts to a secret address of its own.", available: true },
20
+ { type: "automation", label: "When another automation finishes", hint: "One flow starts the next.", available: true },
21
+ { type: "connection", label: "When something happens in a connected account", hint: "A new mail, a new row in a sheet.", available: false, why: "Not offered yet. Use a schedule with a step that reads the account, or the web address trigger." },
22
+ ],
23
+ apps: [{ name: "CRM", actions: [{ name: "add_people", description: "Add people" }, { name: "suggest", description: "Suggest" }], kinds: ["contact", "deal", "company"], topics: ["rows.imported", "reply.received"] }],
24
+ automations: [{ key: "morning-read", name: "Morning read" }, { key: "weekly-look", name: "Weekly look back" }],
25
+ };
26
+
27
+ export default function TriggerPickerDemo() {
28
+ const [trigger, setTrigger] = useState({ type: "schedule", cron: "0 7 * * 1-5", tz: "team" });
29
+ const [hook, setHook] = useState({ path: "/hooks/automation/0b9f3c1a-5d2e-4c70-8a11-93e5f2a6b7d4", has_secret: false, rotated_at: null, last_received_at: null });
30
+ return (
31
+ <div className="grid gap-4 p-4 sm:grid-cols-2">
32
+ <div className="max-w-sm overflow-hidden rounded-lg border border-border">
33
+ <TriggerPicker
34
+ trigger={trigger}
35
+ onChange={setTrigger}
36
+ catalog={CATALOG}
37
+ ownedByApp
38
+ selfKey="reply-tidy"
39
+ hook={hook}
40
+ origin="https://app.makersclaw.com"
41
+ onRotateHook={async () => {
42
+ setHook((h) => ({ ...h, has_secret: true, rotated_at: new Date().toISOString() }));
43
+ return { ok: true, hook: { secret: "9f2c41a7e0b35d68c1a4f7203be96d85a1c0f3e7b2d49586" } };
44
+ }}
45
+ />
46
+ </div>
47
+ <div className="max-w-sm overflow-hidden rounded-lg border border-border">
48
+ <TriggerPicker trigger={{ type: "manual" }} onChange={() => {}} />
49
+ </div>
50
+ <div className="max-w-sm overflow-hidden rounded-lg border border-border">
51
+ <TriggerPicker trigger={{ type: "schedule", cron: "0 13,21 * * 1-5", tz: "Europe/Paris" }} onChange={() => {}} readOnly later={[]} />
52
+ </div>
53
+ <div className="max-w-sm overflow-hidden rounded-lg border border-border">
54
+ <TriggerPicker trigger={{ type: "record", kinds: ["contact"], ops: ["create"], app: "CRM" }} onChange={() => {}} catalog={CATALOG} selfKey="reply-tidy" readOnly />
55
+ </div>
56
+ <pre className="m-0 overflow-auto rounded-md bg-muted p-2 font-mono text-xs sm:col-span-2">{JSON.stringify(trigger)}</pre>
57
+ </div>
58
+ );
59
+ }
@@ -0,0 +1,3 @@
1
+ // The TriggerPicker block — `makersclaw add trigger-picker`. Fixed:
2
+ // compose it through its props (README.md beside this file).
3
+ export { TriggerPicker } from "./trigger-picker";