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,364 @@
1
+ "use client";
2
+
3
+ // AutomationsScreen over a pretend platform — the gallery's and the smoke
4
+ // test's surface. Not installed into apps. The platform's hooks are written
5
+ // here, in memory, and handed to the block as `hooks`, exactly as an app hands
6
+ // its lib/hooks. A scenario picker draws each state: many automations, one,
7
+ // none (the first-run screen), still loading, the list failing to load, an
8
+ // older platform without the engine, an app whose job is still its old
9
+ // schedule (read-only), and an automation that will not open. A width picker
10
+ // shows the page at 1280, 800, 368 and 320 px of the block's own width.
11
+ //
12
+ // Try: open a row (Back returns to the list with its search kept), Test run
13
+ // then Back from the run, Runs then a run then Back (it returns to Runs),
14
+ // the app's own tab on Morning read, Delete a row (a toast with Undo),
15
+ // New automation from a starting point, the switch on a row. The line under
16
+ // the pickers is the page address the place would travel in.
17
+ import { useMemo, useState, useSyncExternalStore } from "react";
18
+ import { AppLayout, Button, ButtonGroup, Notice } from "../components/ui";
19
+ import { AutomationsScreen, paramsOfPlace, placeFromParams } from "../components/blocks/automations-screen";
20
+
21
+ const MORNING = {
22
+ format: 1,
23
+ key: "morning-read",
24
+ name: "Morning read",
25
+ does: "Reads your mail, saves who wrote, drafts the follow-ups that are owed.",
26
+ trigger: { type: "schedule", cron: "0 7 * * 1-5", tz: "team" },
27
+ inputs: {},
28
+ settings: { overlap: "skip", on_failure: "retry_then_agent", only_if_changed: false },
29
+ steps: [
30
+ { id: "mail", kind: "tool", label: "Read the mail since the last read", needs: { category: "mail" }, tool: "list_messages", input: { since: "{{ trigger.at }}", limit: 200 } },
31
+ { id: "touches", kind: "action", label: "Save who wrote", action: "record_touches", input: { touches: "{{ steps.mail.output.messages }}" } },
32
+ { id: "write", kind: "llm", label: "Write the follow-up", tier: "smart", prompt: "Write a short follow-up to the last person who wrote." },
33
+ { id: "tell", kind: "notify", message: "Morning read done." },
34
+ ],
35
+ };
36
+ const simple = (key, name, trigger, message = "Done.") => ({ format: 1, key, name, trigger, inputs: {}, settings: { overlap: "skip", on_failure: "retry_then_agent", only_if_changed: false }, steps: [{ id: "tell", kind: "notify", message }] });
37
+ const FRIDAY = simple("friday-review", "Friday review", { type: "schedule", cron: "0 16 * * 5", tz: "team" }, "Friday review is ready.");
38
+ const LONG = simple("long", "Every Monday morning, collect every deal that has gone quiet for more than three weeks, draft a short note to each owner and leave all of it for the team lead to read before the stand-up", { type: "schedule", cron: "0 9 * * 1", tz: "team" });
39
+
40
+ const ACTIONS = [
41
+ { name: "record_touches", description: "Save who wrote to whom" },
42
+ { name: "suggest", description: "Leave a suggestion on Today" },
43
+ ];
44
+
45
+ const T0 = "2026-10-09T11:00:00.000Z";
46
+ const auto = (id, def, over = {}) => ({ id, def, liveDef: def, status: "off", live: 1, draft: 1, source: "member", versions: [{ version: 1, kind: "member", created_at: T0 }], runs: [], suggestions: [], passed: null, ...over });
47
+ const SCENARIOS = {
48
+ many: () => ({
49
+ a1: auto("a1", MORNING, { status: "on", source: "package", versions: [{ version: 1, kind: "shipped", created_at: T0 }], runs: ["r1"], passed: 1 }),
50
+ a2: auto("a2", FRIDAY, { status: "on", runs: ["r2"], passed: 1 }),
51
+ a3: auto("a3", simple("weekly-signups", "Weekly signups", { type: "schedule", cron: "0 9 * * 1", tz: "team" })),
52
+ a4: auto("a4", simple("a-draft", "A draft I started", { type: "manual" }), { status: "draft", live: null }),
53
+ a5: auto("a5", LONG, { status: "on", passed: 1 }),
54
+ }),
55
+ one: () => ({ a1: auto("a1", MORNING, { status: "on", source: "package", versions: [{ version: 1, kind: "shipped", created_at: T0 }], runs: ["r1"], passed: 1 }) }),
56
+ none: () => ({}),
57
+ loading: () => ({}),
58
+ failed: () => ({}),
59
+ unavailable: () => ({}),
60
+ readonly: () => ({ a1: auto("a1", simple("morning", "Morning read", { type: "schedule", cron: "0 7 * * 1-5", tz: "team" }), { status: "on", source: "legacy" }), a2: auto("a2", simple("weekly-review", "Weekly look back", { type: "schedule", cron: "0 16 * * 5", tz: "team" }), { source: "legacy" }) }),
61
+ unopenable: () => ({ a1: auto("a1", MORNING, { status: "on" }), a2: auto("a2", FRIDAY) }),
62
+ };
63
+ const SCENARIO_LABELS = { many: "Many", one: "One", none: "None", loading: "Loading", failed: "Failed to load", unavailable: "No engine", readonly: "Read-only", unopenable: "Will not open" };
64
+
65
+ const row = (step_id, over = {}) => ({ path: step_id, step_id, kind: "notify", attempt: 1, status: "done", started_at: T0, ended_at: T0, credits: 0, error: null, ...over });
66
+ const PAST = {
67
+ r1: { id: "r1", status: "done", version: 1, trigger_type: "schedule", is_test: false, created_at: T0, started_at: T0, ended_at: "2026-10-09T11:01:00.000Z", credits: 4.2, cap_credits: 900, result: null, error: null, steps: [row("mail", { kind: "tool" }), row("touches", { kind: "action" }), row("write", { kind: "llm", credits: 4.2 }), row("tell")] },
68
+ r2: { id: "r2", status: "failed", version: 1, trigger_type: "schedule", is_test: false, created_at: T0, started_at: T0, ended_at: T0, credits: 0.8, result: null, error: { words: "The note could not be left." }, steps: [row("tell", { status: "failed", error: { code: "x", words: "The note could not be left." } })] },
69
+ };
70
+ const flat = (steps) => steps.flatMap((s) => [s, ...(s.then ?? []).flatMap((x) => flat([x])), ...(s.else ?? []).flatMap((x) => flat([x])), ...flat(s.steps ?? [])]);
71
+
72
+ /** A platform in memory: the three hooks and two doors the block asks for. */
73
+ function createPlatform(scenario) {
74
+ const state = { autos: SCENARIOS[scenario](), runs: { ...(scenario === "many" || scenario === "one" ? PAST : {}) }, deleted: {}, n: 0, tick: 0 };
75
+ const subs = new Set();
76
+ const bump = () => {
77
+ state.tick += 1;
78
+ subs.forEach((f) => f());
79
+ };
80
+ const useTick = () => useSyncExternalStore((f) => (subs.add(f), () => subs.delete(f)), () => state.tick, () => state.tick);
81
+ const rowOf = (a) => {
82
+ const last = a.runs.map((id) => state.runs[id]).filter(Boolean)[0];
83
+ return {
84
+ id: a.id,
85
+ key: a.def.key,
86
+ name: a.def.name,
87
+ status: a.status,
88
+ live_version: a.live,
89
+ draft_version: a.draft,
90
+ trigger: a.def.trigger,
91
+ tz: "America/New_York",
92
+ next_run_at: a.status === "on" && a.def.trigger.type === "schedule" ? "2026-10-12T11:00:00.000Z" : null,
93
+ last_run: last ? { status: last.status, started_at: last.created_at, credits: last.credits } : null,
94
+ active_runs: 0,
95
+ owner_kind: "app",
96
+ app_id: "crm",
97
+ edited: a.versions.some((v) => v.kind === "member"),
98
+ source: a.source,
99
+ };
100
+ };
101
+ const testView = (a, version) => (version === null || version === undefined ? null : { version, exempt: a.versions.some((v) => v.version === version && v.kind === "shipped"), passed: a.passed === version, last: null });
102
+ const needsTest = (a, version, opts) => !opts?.skipTest && !testView(a, version)?.exempt && a.passed !== version;
103
+ const REFUSED = { ok: false, status: 409, code: "needs_test", error: "Run a test of this version first. It reads your real data and changes nothing." };
104
+ const wait = (ms = 250) => new Promise((r) => setTimeout(r, ms));
105
+
106
+ const useAutomations = () => {
107
+ useTick();
108
+ if (scenario === "unavailable") return { automations: [], triggers: null, starts: [], describe: async () => ({ ok: false, code: "unavailable" }), loading: false, error: null, unavailable: true, reload() {}, setStatus: async () => ({ ok: false }), create: async () => ({ ok: false }) };
109
+ const loading = scenario === "loading";
110
+ const error = scenario === "failed" ? "not reachable" : null;
111
+ return {
112
+ automations: loading || error ? [] : Object.values(state.autos).map(rowOf),
113
+ triggers: null,
114
+ starts: [],
115
+ describe: async (ask) => {
116
+ await wait(600);
117
+ return ask.length < 24 ? { ok: false, code: "needs_answer", error: "I need a little more.", questions: ["Who should it tell?", "How often should it run?"] } : { ok: true, id: "a1" };
118
+ },
119
+ describing: false,
120
+ loading,
121
+ error,
122
+ code: undefined,
123
+ unavailable: false,
124
+ reload: bump,
125
+ setStatus: async (id, on) => {
126
+ await wait(150);
127
+ state.autos[id] = { ...state.autos[id], status: on ? "on" : "off" };
128
+ bump();
129
+ return { ok: true, status: 200, data: {} };
130
+ },
131
+ create: async (def) => {
132
+ const id = `n${++state.n}`;
133
+ state.autos[id] = auto(id, def, { status: "draft", live: null });
134
+ bump();
135
+ return { ok: true, status: 200, data: { id } };
136
+ },
137
+ };
138
+ };
139
+
140
+ const useAutomation = (id) => {
141
+ useTick();
142
+ const a = state.autos[id];
143
+ if (scenario === "loading") return { automation: null, definition: null, versions: [], runs: [], suggestions: [], tests: null, hook: null, loading: true, error: null, unavailable: false, busy: null, reload: bump };
144
+ const dead = scenario === "unopenable" || !a;
145
+ if (dead) return { automation: null, definition: null, versions: [], runs: [], suggestions: [], tests: null, hook: null, loading: false, error: "That did not open.", code: a ? undefined : "not_found", unavailable: false, busy: null, reload: bump };
146
+ const set = (patch) => {
147
+ state.autos[id] = { ...state.autos[id], ...patch };
148
+ bump();
149
+ };
150
+ return {
151
+ automation: { ...rowOf(a), tz: "America/New_York" },
152
+ live: a.live ? { version: a.live, definition: a.liveDef } : null,
153
+ draft: a.draft !== a.live ? { version: a.draft, definition: a.def } : null,
154
+ definition: a.def,
155
+ versions: [...a.versions].reverse(),
156
+ estimate: { credits: 3, credits_max: 12, steps: [] },
157
+ tests: { live: testView(a, a.live), draft: a.draft !== a.live ? testView(a, a.draft) : null },
158
+ runs: a.runs.map((r) => state.runs[r]).filter(Boolean),
159
+ suggestions: a.suggestions,
160
+ keepSuggestion: async () => ({ ok: true }),
161
+ dropSuggestion: async () => ({ ok: true }),
162
+ hook: null,
163
+ rotateHook: async () => ({ ok: true, hook: null }),
164
+ busy: null,
165
+ save: async (def, how) => {
166
+ await wait(150);
167
+ const latest = a.versions.length;
168
+ const base = how && typeof how === "object" ? how.baseVersion : latest;
169
+ if (base !== latest) return { ok: false, status: 409, code: "changed", latest, error: "Someone saved a newer version while you were editing." };
170
+ set({ def, draft: latest + 1, versions: [...a.versions, { version: latest + 1, kind: "member", created_at: new Date().toISOString() }] });
171
+ return { ok: true, status: 200, data: { version: latest + 1 } };
172
+ },
173
+ keep: async (o) => {
174
+ if (needsTest(a, a.draft, o)) return REFUSED;
175
+ set({ live: a.draft, liveDef: a.def });
176
+ return { ok: true, status: 200, data: {} };
177
+ },
178
+ setLive: async (on, o) => {
179
+ if (on && needsTest(a, a.live ?? a.draft, o)) return REFUSED;
180
+ set({ status: on ? "on" : "off" });
181
+ return { ok: true, status: 200, data: {} };
182
+ },
183
+ test: async (given = {}) => {
184
+ await wait(300);
185
+ const dry = !(given && given.dry === false);
186
+ const id2 = `t${++state.n}`;
187
+ const t = new Date().toISOString();
188
+ const standIn = new Set(["action", "notify"]);
189
+ const steps = flat(a.def.steps).map((s) => {
190
+ const would = dry && standIn.has(s.kind);
191
+ return row(s.id, { kind: s.kind, started_at: t, ended_at: t, credits: s.kind === "llm" ? 3 : 0, ...(would ? { simulated: true, output: { simulated: true, would: { kind: s.kind, effect: s.kind === "notify" ? "note" : "write", words: s.kind === "notify" ? "Would leave a note." : `Would run ${s.action}.` } } } : { output: { ok: true } }) });
192
+ });
193
+ const woulds = steps.filter((x) => x.simulated);
194
+ state.runs[id2] = { id: id2, status: "done", dry, version: a.draft, trigger_type: "manual", is_test: dry, created_at: t, started_at: t, ended_at: t, credits: 3, result: dry ? { dry: { simulated: woulds.length, would: woulds.map((x) => ({ step: x.step_id, path: x.path, kind: x.kind, effect: x.output.would.effect, words: x.output.would.words })), unchecked: [], sampled: [] } } : null, error: null, steps, automation_id: id };
195
+ set({ runs: [id2, ...a.runs], passed: a.draft });
196
+ return { ok: true, status: 200, data: { run_id: id2, test: dry, dry, version: a.draft } };
197
+ },
198
+ loading: false,
199
+ error: null,
200
+ code: undefined,
201
+ unavailable: false,
202
+ reload: bump,
203
+ };
204
+ };
205
+
206
+ const useAutomationRun = (runId) => {
207
+ useTick();
208
+ const r = runId ? state.runs[runId] : null;
209
+ const none = { run: null, steps: [], stepsVisible: false, automation: null, definition: null, fixes: [], detail: null, control: async () => ({ ok: true }), keepFix: async () => ({ ok: true }), dropFix: async () => ({ ok: true }), busy: null, loading: false, error: null, unavailable: false, reload: bump };
210
+ if (!r) return runId ? { ...none, error: "gone" } : none;
211
+ return { ...none, run: r, steps: r.steps, stepsVisible: true, detail: { run: r, automation: { name: "" }, steps: r.steps, steps_visible: true, fixes: [] } };
212
+ };
213
+
214
+ const deleteAutomation = async (id) => {
215
+ await wait(200);
216
+ const a = state.autos[id];
217
+ if (!a) return { ok: false, status: 404, code: "not_found", error: "That automation is not there any more." };
218
+ if (a.source === "package" || a.source === "legacy") return { ok: false, status: 409, code: a.source, error: "This one came with the app. Switch it off in the app's settings instead." };
219
+ state.deleted[id] = a;
220
+ delete state.autos[id];
221
+ bump();
222
+ return { ok: true, status: 200, data: { ok: true, id, name: a.def.name, was_status: a.status, followers: id === "a2" ? [{ id: "a3", key: "weekly-signups", name: "Weekly signups" }] : [], undo: true } };
223
+ };
224
+ const restoreAutomation = async (id) => {
225
+ await wait(150);
226
+ if (!state.deleted[id]) return { ok: false, status: 404, code: "not_found", error: "It could not be brought back." };
227
+ state.autos[id] = state.deleted[id];
228
+ delete state.deleted[id];
229
+ bump();
230
+ return { ok: true, status: 200, data: { ok: true, id } };
231
+ };
232
+
233
+ return { useAutomations, useAutomation, useAutomationRun, deleteAutomation, restoreAutomation };
234
+ }
235
+
236
+ const WIDTHS = [1280, 800, 368, 320];
237
+ const CHARGE = { many: { used: 4180, of: 10000 }, one: { used: 0, of: 10000 } };
238
+
239
+ function Page({ scenario }) {
240
+ const hooks = useMemo(() => createPlatform(scenario), [scenario]);
241
+ const [place, setPlace] = useState(() => placeFromParams(null));
242
+ const [asked, setAsked] = useState(null);
243
+ return (
244
+ <div className="flex h-full min-h-0 flex-col">
245
+ <p className="m-0 shrink-0 border-b border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground" role="status">
246
+ Page address: <b className="font-semibold text-foreground">{`?${new URLSearchParams({ view: "automations", ...paramsOfPlace(place) })}`}</b>
247
+ {asked ? ` · Describe it handed on: “${asked}”` : ""}
248
+ </p>
249
+ <div className="flex min-h-0 flex-1 flex-col">
250
+ <AutomationsScreen
251
+ key={scenario}
252
+ hooks={hooks}
253
+ place={place}
254
+ onPlace={setPlace}
255
+ actions={ACTIONS}
256
+ title="Automations"
257
+ intro="What the CRM does on its own. Open one to see its steps, change them, test it and switch it on."
258
+ allowance={CHARGE[scenario] ? { ...CHARGE[scenario], words: CHARGE[scenario].used > 0 ? "4,180 of 10,000 credits this week" : "10,000 credits a week" } : null}
259
+ starts={[
260
+ {
261
+ id: "quiet-monday",
262
+ name: "Look at who has gone quiet every Monday",
263
+ blurb: "The agent drafts a short follow-up for the people on open deals who have gone quiet. Nothing is sent.",
264
+ glyph: "agent",
265
+ needs: null,
266
+ build: (taken) => ({ ...simple(taken.has("quiet-monday") ? "quiet-monday-2" : "quiet-monday", "Who has gone quiet", { type: "schedule", cron: "30 8 * * 1", tz: "team" }, "Drafted the follow-ups."), does: "Drafts follow-ups for people who have gone quiet." }),
267
+ },
268
+ ]}
269
+ onDescribe={scenario === "one" ? (ask) => (setAsked(ask), Promise.resolve({ ok: true })) : "platform"}
270
+ describePrice=""
271
+ onRequest={
272
+ <section aria-labelledby="demo-on-request" className="grid gap-2">
273
+ <h2 id="demo-on-request" className="m-0 text-[13px] font-semibold">
274
+ On request
275
+ </h2>
276
+ <ul className="m-0 grid list-none rounded-md border border-border p-0">
277
+ {[
278
+ ["The first read", "Once, when a mailbox connects: the last 30 days of mail and meetings."],
279
+ ["Fill in", "When someone presses Fill in on a person, a company or a list's column."],
280
+ ].map(([name, when]) => (
281
+ <li key={name} className="grid gap-0.5 border-b border-border px-3.5 py-2.5 text-[13px] last:border-b-0">
282
+ <b className="font-semibold">{name}</b>
283
+ <span className="text-muted-foreground">{when}</span>
284
+ </li>
285
+ ))}
286
+ </ul>
287
+ </section>
288
+ }
289
+ extras={({ automations }) => <p className="m-0 text-xs text-muted-foreground">{automations.length} of the app's own automations are drawn above.</p>}
290
+ extraTabs={[
291
+ {
292
+ key: "reads",
293
+ label: "What it reads",
294
+ when: (a) => a.key === "morning-read",
295
+ render: () => (
296
+ <div className="grid max-w-3xl gap-1.5 p-5 text-[13px]">
297
+ <b className="font-semibold">Mail</b>
298
+ <p className="m-0 text-muted-foreground">For each email: who wrote to whom, when, the subject and one line. Never the full text.</p>
299
+ </div>
300
+ ),
301
+ },
302
+ ]}
303
+ aboveOne={({ automation, runId }) => (automation.key === "morning-read" && !runId ? <Notice tone="info">It needs a mailbox. Connect one on the desk.</Notice> : null)}
304
+ afterRun={() => <p className="m-0 shrink-0 border-t border-border px-4 py-2 text-xs text-muted-foreground">The app's own account of this run sits here.</p>}
305
+ frame={({ crumb, label, fill, children }) => (
306
+ <AppLayout
307
+ height="parent"
308
+ contentLabel={label}
309
+ contentMode={fill ? "fill" : "scroll"}
310
+ header={
311
+ <nav aria-label="Where you are" className="flex min-h-11 min-w-0 items-center gap-1 px-3 text-sm">
312
+ {crumb.map((c, i) =>
313
+ c.onPress ? (
314
+ <span key={c.label} className="flex items-center gap-1">
315
+ <Button size="sm" variant="quiet" onClick={c.onPress}>
316
+ {c.label}
317
+ </Button>
318
+ <span aria-hidden="true" className="text-muted-foreground">
319
+ ›
320
+ </span>
321
+ </span>
322
+ ) : (
323
+ <b key={`${c.label}-${i}`} className="min-w-0 truncate font-semibold">
324
+ {c.label}
325
+ </b>
326
+ ),
327
+ )}
328
+ </nav>
329
+ }
330
+ >
331
+ {children}
332
+ </AppLayout>
333
+ )}
334
+ />
335
+ </div>
336
+ </div>
337
+ );
338
+ }
339
+
340
+ export default function AutomationsScreenDemo() {
341
+ const [width, setWidth] = useState(1280);
342
+ const [scenario, setScenario] = useState("many");
343
+ return (
344
+ <div className="grid gap-4 p-4">
345
+ <ButtonGroup aria-label="The state">
346
+ {Object.entries(SCENARIO_LABELS).map(([key, label]) => (
347
+ <Button key={key} size="sm" variant={key === scenario ? "primary" : "secondary"} onClick={() => setScenario(key)}>
348
+ {label}
349
+ </Button>
350
+ ))}
351
+ </ButtonGroup>
352
+ <ButtonGroup aria-label="The block's width">
353
+ {WIDTHS.map((w) => (
354
+ <Button key={w} size="sm" variant={w === width ? "primary" : "secondary"} onClick={() => setWidth(w)}>
355
+ {w} px
356
+ </Button>
357
+ ))}
358
+ </ButtonGroup>
359
+ <div className="flex h-[720px] w-full flex-col overflow-hidden rounded-lg border border-border" style={{ maxWidth: width }}>
360
+ <Page key={scenario} scenario={scenario} />
361
+ </div>
362
+ </div>
363
+ );
364
+ }
@@ -0,0 +1,4 @@
1
+ // The AutomationsScreen block — `makersclaw add automations-screen`. Fixed:
2
+ // compose it through its props (README.md beside this file).
3
+ export { AutomationsScreen } from "./automations-screen";
4
+ export { deletedWords, normalizePlace, paramsOfPlace, placeFromParams } from "./screen-model";
@@ -0,0 +1,129 @@
1
+ // The pure part of AutomationsScreen: where the member is (the place), how
2
+ // the place travels in a URL, where Back goes, what a delete says, which
3
+ // starting points are offered, which tabs an automation has. No React, no
4
+ // network: a test runs every function here.
5
+
6
+ /** The `automation` value of a screen that makes a new one. */
7
+ export const NEW = "new";
8
+ /** The two places inside one automation that every automation has. */
9
+ export const FLOW = "flow";
10
+ export const RUNS = "runs";
11
+
12
+ const text = (v) => (typeof v === "string" && v.trim() ? v.trim() : null);
13
+ const list = (v) => (Array.isArray(v) ? v : []);
14
+
15
+ /**
16
+ * A place, made well-formed. The list is `{ automation: null }`. One
17
+ * automation is `{ automation: <id>, tab, run }`: `tab` is `flow` (default),
18
+ * `runs`, or the key of an extra tab; `run` is a run's id. A new one is
19
+ * `{ automation: "new", start }`, `start` being the starting point's id.
20
+ */
21
+ export function normalizePlace(p) {
22
+ const o = p && typeof p === "object" ? p : {};
23
+ const automation = text(o.automation);
24
+ if (!automation) return { automation: null, tab: FLOW, run: null, start: null };
25
+ if (automation === NEW) return { automation: NEW, tab: FLOW, run: null, start: text(o.start) };
26
+ return { automation, tab: text(o.tab) ?? FLOW, run: text(o.run), start: null };
27
+ }
28
+
29
+ /** Which screen a place is: list · new · one · run. */
30
+ export function whereOf(place) {
31
+ const p = normalizePlace(place);
32
+ if (!p.automation) return "list";
33
+ if (p.automation === NEW) return "new";
34
+ return p.run ? "run" : "one";
35
+ }
36
+
37
+ export const samePlace = (a, b) => JSON.stringify(normalizePlace(a)) === JSON.stringify(normalizePlace(b));
38
+
39
+ /** A place from the page's query string: `placeFromParams(useSearchParams())`,
40
+ * a URLSearchParams, or a function name → value. The names are `automation`,
41
+ * `tab`, `run`, `start`. */
42
+ export function placeFromParams(params) {
43
+ const get = typeof params === "function" ? params : (name) => (params && typeof params.get === "function" ? params.get(name) : null);
44
+ return normalizePlace({ automation: get("automation"), tab: get("tab"), run: get("run"), start: get("start") });
45
+ }
46
+
47
+ /** The query parameters of a place, only what is set: the list is `{}`. Spread
48
+ * them into your own (`{ view: "automations", ...paramsOfPlace(place) }`). */
49
+ export function paramsOfPlace(place) {
50
+ const p = normalizePlace(place);
51
+ if (!p.automation) return {};
52
+ return {
53
+ automation: p.automation,
54
+ ...(p.tab !== FLOW && !p.run ? { tab: p.tab } : {}),
55
+ ...(p.run ? { run: p.run } : {}),
56
+ ...(p.start ? { start: p.start } : {}),
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Where the member came from when a run opened: remembered so that Back from
62
+ * a run returns to the tab it was opened from (the Runs list), not always to
63
+ * the flow. `from` and `to` are the places before and after a move; `origin`
64
+ * is what was remembered. Choosing another run from inside a run keeps it.
65
+ */
66
+ export function originAfter(from, to, origin = null) {
67
+ const a = normalizePlace(from);
68
+ const b = normalizePlace(to);
69
+ if (!b.run) return null;
70
+ if (a.run) return origin;
71
+ return a.automation === b.automation ? a : null;
72
+ }
73
+
74
+ /** The place Back from a run goes to: the tab the run was opened from, else the flow. */
75
+ export function backFrom(place, origin = null) {
76
+ const p = normalizePlace(place);
77
+ const o = origin ? normalizePlace(origin) : null;
78
+ if (o && o.automation === p.automation && !o.run && o.tab !== FLOW) return { automation: p.automation, tab: o.tab, run: null, start: null };
79
+ return { automation: p.automation, tab: FLOW, run: null, start: null };
80
+ }
81
+
82
+ /**
83
+ * The words after a delete: a title, what followed it (the automations that
84
+ * started when it finished and now never will), and whether Undo is offered.
85
+ * `done` is the platform's answer `{ id, name, followers, undo }`.
86
+ */
87
+ export function deletedWords(done, fallbackName = "") {
88
+ const name = text(done?.name) ?? text(fallbackName);
89
+ const followers = list(done?.followers).filter((f) => f && text(f.name));
90
+ return {
91
+ title: name ? `Deleted “${name}”.` : "Deleted.",
92
+ detail: followers.length
93
+ ? `${followers.length} ${followers.length === 1 ? "automation" : "automations"} followed it and will no longer start: ${followers.map((f) => f.name).join(", ")}.`
94
+ : "",
95
+ undo: Boolean(done?.undo) && Boolean(text(done?.id)),
96
+ };
97
+ }
98
+
99
+ /** The starting points offered under New: the app's own first, then the platform's
100
+ * (already turned into the list's shape), else the built-in ones. One of each id. */
101
+ export function combineStarts(app, platform, builtIn) {
102
+ const seen = new Set();
103
+ const out = [];
104
+ for (const s of [...list(app), ...(list(platform).length ? list(platform) : list(builtIn))]) {
105
+ if (!s || typeof s.id !== "string" || seen.has(s.id)) continue;
106
+ seen.add(s.id);
107
+ out.push(s);
108
+ }
109
+ return out;
110
+ }
111
+
112
+ /** The tabs of one automation: Flow, Runs, then the app's own that apply to it. */
113
+ export function tabsOf(extras, automation) {
114
+ const more = [];
115
+ for (const t of list(extras)) {
116
+ if (!t || typeof t.key !== "string" || t.key === FLOW || t.key === RUNS || typeof t.label !== "string") continue;
117
+ if (more.some((x) => x.key === t.key)) continue;
118
+ if (typeof t.when === "function" && !t.when(automation)) continue;
119
+ more.push(t);
120
+ }
121
+ return [{ key: FLOW, label: "Flow" }, { key: RUNS, label: "Runs" }, ...more.map((t) => ({ key: t.key, label: t.label }))];
122
+ }
123
+
124
+ /** What `hooks` must hold. A string naming what is missing, else null. */
125
+ export function hooksProblem(hooks) {
126
+ if (!hooks || typeof hooks !== "object") return "AutomationsScreen needs hooks={{ useAutomations, useAutomation, useAutomationRun }} (from lib/hooks).";
127
+ const missing = ["useAutomations", "useAutomation", "useAutomationRun"].filter((k) => typeof hooks[k] !== "function");
128
+ return missing.length ? `AutomationsScreen: hooks is missing ${missing.join(", ")}.` : null;
129
+ }
@@ -0,0 +1,143 @@
1
+ # ChatPane
2
+
3
+ The desk's chat pane, as the app's own, in the app's theme (0.8.1). The
4
+ founder, after reviewing the app agent's message box next to the
5
+ Automations window's: "add claw's ChatPane as a block in the makersclaw
6
+ template". This is that port: claw's `web/src/os/windows/artifact/ChatPane`
7
+ and the composer of its `EveChat`, in JSX, with the kit's `Icon` and
8
+ `Button` and the app's tokens, talking to the agent through the app's own
9
+ hook (`useAgentPane`, `lib/hooks.js`) instead of `eve/client`.
10
+
11
+ It is the **chrome around a conversation**:
12
+
13
+ - **The head**: the title, **New chat**, **Chats** (the past chats drop over
14
+ the conversation, newest first, with a dot on one that needs you or is
15
+ working), and a close.
16
+ - **The empty state**: before the first ask, one line, the recent chats
17
+ ("No chats yet. Your first message starts one." when there are none), and
18
+ the app's suggestions.
19
+ - **The conversation**: its lines are the children. It stays at the newest
20
+ words until the member scrolls up, then offers a jump to latest.
21
+ - **The bar** between the conversation and the box: what waits on the member,
22
+ or that the agent is working.
23
+ - **The message box**: the desk's composer. **One rounded box.** The words
24
+ on top, full width, growing with what is typed. Under them a row: **+**
25
+ (attach) at the left, and at the right the **microphone** and a **round
26
+ arrow** to send. **While a turn runs, a round stop takes the arrow's
27
+ place** (once the member types, the arrow comes back: a message sent then
28
+ waits its turn, as before). A quiet `hint` can sit under the box.
29
+ - **Files** by the + button, by paste and by a drop anywhere on the pane (up
30
+ to 4 files and 3 MB together); **dictation** where the browser has speech
31
+ recognition; the box **closed** while something waits on the member, with
32
+ the reason in its placeholder.
33
+ - **A starting line** from the dock: `openAgent({ ask })` (blocks/agent-dock).
34
+ The pane sends it as the member's first words in a new chat, or puts it
35
+ in the box. See "Have the agent do it" below.
36
+
37
+ ```jsx
38
+ import { ChatPane } from "../components/blocks/chat-pane"; // a Makersclaw app ("./blocks/chat-pane" from components/)
39
+ import { ChatPane } from "@/components/makersclaw/blocks/chat-pane"; // a shadcn project
40
+ ```
41
+
42
+ A client component. It needs the kit and nothing else; it is not tied to the
43
+ agent's lines. **For the agent's conversation use `agent-pane`**, which
44
+ draws the plan, the work folded into "Worked through N steps", the
45
+ questions, the yes and what the agent made, inside this pane. Use `ChatPane`
46
+ itself for lines of your own in the desk's frame.
47
+
48
+ ## What was ported, and what was not
49
+
50
+ Ported: the head (New chat, Chats), the past chats list and its marks, the
51
+ empty state, the scroll that follows, the composer (its layout, the
52
+ attachments, the dictation, the send and stop), the closed box, and the
53
+ hand-off seam in a form the app needs (the starting line).
54
+
55
+ Not ported, because the app has no such thing: the desk's **rail** beside the
56
+ chat (an app's agent lives in the dock, a column; the Chats overlay is the
57
+ column mode's), the **binding** (headers, scope, the session pointer: the
58
+ app's `useAgentPane` holds those), **`openSession`/`pendingLine`** (the desk's
59
+ hand-off of a request into the agent's chat; the app's starting line does
60
+ that job), **`chatMarks` "In Makersclaw"** (an ask made in Makersclaw shows
61
+ as a pointer in the conversation instead) and the wallet gate (the platform
62
+ refuses a turn with no credits and says so).
63
+
64
+ ## Props
65
+
66
+ - `chat` — what `useAgentPane()` returns. Required. The pane calls its
67
+ `send(text, { files })`, `stop()`, `newChat()` and `openSession(id)` and
68
+ reads `sessionId`, `request`, `chats`, `view`/`turns`/`pending`/`state`
69
+ (to follow the newest words), `sameConversation`, `sending`, `loading`,
70
+ `error`, `notice`, `unavailable`.
71
+ - `title` — the head's words, and the box's label. Default `"Ask the agent"`.
72
+ - `suggestions` — asks that fit the moment, as chips before the first ask.
73
+ - `empty` — one line before the first ask.
74
+ - `placeholder` — the box's words before the first ask. Once there is a
75
+ conversation it says "Ask a follow-up…" unless `chat.sameConversation` is
76
+ false.
77
+ - `closedWords` — the box's words while `blocked` ("Answer above first").
78
+ - `hint` — a quiet line under the box ("Enter sends · Shift+Enter is a new
79
+ line").
80
+ - `recent` — past chats listed before the first ask. Default `5`; `0` none.
81
+ - `bare` — no head, inside a `Sheet` or a `Card` that has its own.
82
+ - `fill` — default `true`: the pane takes its container's height and the
83
+ conversation scrolls inside it. `false`: compact, a capped height.
84
+ - `onClose` — a close in the head. Inside an `agent-dock` it is the dock's.
85
+ - `started` — there is a conversation to draw (else the empty state).
86
+ - `busy` — a turn runs: the arrow is a stop while the box is empty.
87
+ - `blocked` — something waits on the member: the whole box is closed.
88
+ - `bar` — a node between the conversation and the box.
89
+ - `children` — the conversation's lines.
90
+ - `className` — layout around it. Never colour.
91
+
92
+ `ChatComposer` is also exported, for a box of your own around the same
93
+ frame: `value`, `onChange`, `onSubmit`, `onStop`, `onAttach`, `files`,
94
+ `onRemoveFile`, `busy`, `canStop`, `stopping`, `blocked`, `sending`,
95
+ `encoding`, `dictation` (`useDictation()`), `placeholder`, `label`, `hint`,
96
+ `textareaRef`, `fileInputRef`. `ChatsList` draws the past chats.
97
+
98
+ ## Have the agent do it
99
+
100
+ A button that says the agent will do the work does not open a form. It calls
101
+ `openAgent("Draft a project plan for me")` (blocks/agent-dock). The dock
102
+ opens, tells this pane the line through `ChatDockContext`, and the pane:
103
+
104
+ 1. starts a new chat (if one is open; `fresh: false` carries on in it),
105
+ 2. sends the line as the member's first words, once,
106
+ 3. and tells the dock it took it.
107
+
108
+ With `send: false` it puts the line in the box instead, with the cursor at
109
+ its end (words the member already typed stay, and the line goes under them). A closed box (something waits on the member) always takes the line
110
+ as a prefill. The pure rule is `startStep(...)` in `chat-model.js`.
111
+
112
+ ## The model (plain functions)
113
+
114
+ `ago(iso)`, `startStep({ start, handled, sessionId, blocked, canNew, newed })`,
115
+ and the composer's parts: `addFiles`, `filesFromTransfer`, `readFile`,
116
+ `formatBytes`, `MAX_FILES`, `MAX_BYTES`, `useDictation`.
117
+
118
+ ## Example
119
+
120
+ ```jsx
121
+ "use client";
122
+ import { useAgentPane } from "../lib/hooks";
123
+ import { ChatPane } from "../components/blocks/chat-pane";
124
+
125
+ export default function Notes() {
126
+ const chat = useAgentPane({ key: "notes" });
127
+ const messages = chat.view?.messages ?? [];
128
+ return (
129
+ <ChatPane
130
+ chat={chat}
131
+ title="Ask about your notes"
132
+ suggestions={["Summarise this week"]}
133
+ hint="Enter sends · Shift+Enter is a new line"
134
+ started={messages.length > 0}
135
+ busy={chat.state === "working"}
136
+ >
137
+ {messages.map((m) => (
138
+ <p key={m.id}>{m.text}</p>
139
+ ))}
140
+ </ChatPane>
141
+ );
142
+ }
143
+ ```