makersclaw 0.7.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 (419) hide show
  1. package/README.md +17 -4
  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 +4 -4
  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 +5 -5
  26. package/r/chat-pane.json +84 -0
  27. package/r/chat.json +3 -3
  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 +18 -6
  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 +3 -3
  46. package/r/flow-editor.json +79 -0
  47. package/r/footer.json +3 -3
  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 +4 -4
  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 +4 -4
  60. package/r/pace-bar.json +69 -0
  61. package/r/page-builder.json +3 -3
  62. package/r/payment-methods.json +2 -2
  63. package/r/pdf-document.json +2 -2
  64. package/r/pdf-viewer.json +3 -3
  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 +4089 -1510
  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 +3 -3
  82. package/r/signature-pad.json +2 -2
  83. package/r/sketch-canvas.json +3 -3
  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 +4 -4
  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/annotate/README.md +14 -11
  159. package/registry/blocks/approval/README.md +145 -0
  160. package/registry/blocks/approval/approval.jsx +163 -0
  161. package/registry/blocks/approval/block.json +31 -0
  162. package/registry/blocks/approval/demo.jsx +121 -0
  163. package/registry/blocks/approval/index.js +3 -0
  164. package/registry/blocks/ask-bar/README.md +105 -0
  165. package/registry/blocks/ask-bar/ask-bar.jsx +166 -0
  166. package/registry/blocks/ask-bar/block.json +26 -0
  167. package/registry/blocks/ask-bar/demo.jsx +78 -0
  168. package/registry/blocks/ask-bar/index.js +3 -0
  169. package/registry/blocks/automation-editor/README.md +291 -0
  170. package/registry/blocks/automation-editor/automation-editor.jsx +656 -0
  171. package/registry/blocks/automation-editor/block.json +39 -0
  172. package/registry/blocks/automation-editor/demo.jsx +284 -0
  173. package/registry/blocks/automation-editor/index.js +4 -0
  174. package/registry/blocks/automation-editor/run-inputs.jsx +82 -0
  175. package/registry/blocks/automation-list/README.md +129 -0
  176. package/registry/blocks/automation-list/automation-list.jsx +476 -0
  177. package/registry/blocks/automation-list/block.json +35 -0
  178. package/registry/blocks/automation-list/demo.jsx +67 -0
  179. package/registry/blocks/automation-list/index.js +3 -0
  180. package/registry/blocks/automation-model/README.md +109 -0
  181. package/registry/blocks/automation-model/block.json +135 -0
  182. package/registry/blocks/automation-model/catalog.js +256 -0
  183. package/registry/blocks/automation-model/check.js +161 -0
  184. package/registry/blocks/automation-model/demo.jsx +42 -0
  185. package/registry/blocks/automation-model/edit.js +262 -0
  186. package/registry/blocks/automation-model/fixes.js +287 -0
  187. package/registry/blocks/automation-model/glyph.jsx +13 -0
  188. package/registry/blocks/automation-model/graph.js +410 -0
  189. package/registry/blocks/automation-model/index.js +33 -0
  190. package/registry/blocks/automation-model/overlay.js +175 -0
  191. package/registry/blocks/automation-model/parts.jsx +94 -0
  192. package/registry/blocks/automation-model/schedule.js +53 -0
  193. package/registry/blocks/automation-model/templates.js +128 -0
  194. package/registry/blocks/automation-model/values.js +29 -0
  195. package/registry/blocks/automation-model/words.js +439 -0
  196. package/registry/blocks/automations-screen/README.md +207 -0
  197. package/registry/blocks/automations-screen/automations-screen.jsx +452 -0
  198. package/registry/blocks/automations-screen/block.json +47 -0
  199. package/registry/blocks/automations-screen/demo.jsx +364 -0
  200. package/registry/blocks/automations-screen/index.js +4 -0
  201. package/registry/blocks/automations-screen/screen-model.js +129 -0
  202. package/registry/blocks/chart/cartesian.jsx +1 -1
  203. package/registry/blocks/chart/core.jsx +33 -23
  204. package/registry/blocks/chart/pie.jsx +1 -1
  205. package/registry/blocks/chat/README.md +4 -1
  206. package/registry/blocks/chat/demo.jsx +2 -2
  207. package/registry/blocks/chat-pane/README.md +143 -0
  208. package/registry/blocks/chat-pane/block.json +48 -0
  209. package/registry/blocks/chat-pane/chat-attach.js +166 -0
  210. package/registry/blocks/chat-pane/chat-composer.jsx +195 -0
  211. package/registry/blocks/chat-pane/chat-context.js +17 -0
  212. package/registry/blocks/chat-pane/chat-model.js +43 -0
  213. package/registry/blocks/chat-pane/chat-pane.jsx +398 -0
  214. package/registry/blocks/chat-pane/chats-list.jsx +52 -0
  215. package/registry/blocks/chat-pane/demo.jsx +103 -0
  216. package/registry/blocks/chat-pane/index.js +9 -0
  217. package/registry/blocks/connect-card/README.md +99 -0
  218. package/registry/blocks/connect-card/block.json +10 -0
  219. package/registry/blocks/connect-card/connect-card.jsx +103 -0
  220. package/registry/blocks/connect-card/demo.jsx +49 -0
  221. package/registry/blocks/connect-card/index.js +3 -0
  222. package/registry/blocks/cost/README.md +115 -0
  223. package/registry/blocks/cost/block.json +10 -0
  224. package/registry/blocks/cost/cost.jsx +176 -0
  225. package/registry/blocks/cost/demo.jsx +66 -0
  226. package/registry/blocks/cost/index.js +3 -0
  227. package/registry/blocks/data-picker/README.md +81 -0
  228. package/registry/blocks/data-picker/block.json +38 -0
  229. package/registry/blocks/data-picker/data-picker.jsx +210 -0
  230. package/registry/blocks/data-picker/demo.jsx +34 -0
  231. package/registry/blocks/data-picker/fields.js +89 -0
  232. package/registry/blocks/data-picker/index.js +4 -0
  233. package/registry/blocks/data-table/demo.jsx +1 -1
  234. package/registry/blocks/first-run/README.md +118 -0
  235. package/registry/blocks/first-run/block.json +11 -0
  236. package/registry/blocks/first-run/demo.jsx +88 -0
  237. package/registry/blocks/first-run/first-run-model.js +51 -0
  238. package/registry/blocks/first-run/first-run.jsx +156 -0
  239. package/registry/blocks/first-run/index.js +5 -0
  240. package/registry/blocks/first-run/probe-rules.js +26 -0
  241. package/registry/blocks/fix-note/README.md +79 -0
  242. package/registry/blocks/fix-note/block.json +35 -0
  243. package/registry/blocks/fix-note/demo.jsx +30 -0
  244. package/registry/blocks/fix-note/fix-note.jsx +235 -0
  245. package/registry/blocks/fix-note/index.js +3 -0
  246. package/registry/blocks/flow-canvas/README.md +15 -8
  247. package/registry/blocks/flow-editor/README.md +108 -0
  248. package/registry/blocks/flow-editor/block.json +44 -0
  249. package/registry/blocks/flow-editor/demo.jsx +115 -0
  250. package/registry/blocks/flow-editor/flow-canvas.jsx +568 -0
  251. package/registry/blocks/flow-editor/flow-editor.jsx +154 -0
  252. package/registry/blocks/flow-editor/index.js +6 -0
  253. package/registry/blocks/flow-editor/minimap.jsx +78 -0
  254. package/registry/blocks/flow-editor/outline.jsx +134 -0
  255. package/registry/blocks/footer/README.md +3 -2
  256. package/registry/blocks/library-shelf/README.md +117 -0
  257. package/registry/blocks/library-shelf/block.json +28 -0
  258. package/registry/blocks/library-shelf/demo.jsx +68 -0
  259. package/registry/blocks/library-shelf/index.js +3 -0
  260. package/registry/blocks/library-shelf/library-shelf.jsx +211 -0
  261. package/registry/blocks/library-shelf/probe-rules.js +15 -0
  262. package/registry/blocks/margin-notes/README.md +222 -0
  263. package/registry/blocks/margin-notes/block.json +10 -0
  264. package/registry/blocks/margin-notes/demo.jsx +144 -0
  265. package/registry/blocks/margin-notes/index.js +20 -0
  266. package/registry/blocks/margin-notes/margin-model.js +224 -0
  267. package/registry/blocks/margin-notes/margin-notes.jsx +465 -0
  268. package/registry/blocks/mind-map/README.md +4 -2
  269. package/registry/blocks/needs-you/README.md +177 -0
  270. package/registry/blocks/needs-you/block.json +34 -0
  271. package/registry/blocks/needs-you/demo.jsx +143 -0
  272. package/registry/blocks/needs-you/index.js +3 -0
  273. package/registry/blocks/needs-you/needs-you.jsx +441 -0
  274. package/registry/blocks/org-chart/README.md +4 -2
  275. package/registry/blocks/pace-bar/README.md +230 -0
  276. package/registry/blocks/pace-bar/block.json +10 -0
  277. package/registry/blocks/pace-bar/demo.jsx +255 -0
  278. package/registry/blocks/pace-bar/index.js +22 -0
  279. package/registry/blocks/pace-bar/pace-bar.jsx +461 -0
  280. package/registry/blocks/pace-bar/pace-model.js +288 -0
  281. package/registry/blocks/page-builder/README.md +1 -1
  282. package/registry/blocks/page-builder/demo.jsx +3 -3
  283. package/registry/blocks/pdf-viewer/README.md +4 -1
  284. package/registry/blocks/record-grid/README.md +100 -0
  285. package/registry/blocks/record-grid/block.json +28 -0
  286. package/registry/blocks/record-grid/demo.jsx +43 -0
  287. package/registry/blocks/record-grid/index.js +3 -0
  288. package/registry/blocks/record-grid/record-grid.jsx +251 -0
  289. package/registry/blocks/run-history/README.md +138 -0
  290. package/registry/blocks/run-history/block.json +10 -0
  291. package/registry/blocks/run-history/demo.jsx +74 -0
  292. package/registry/blocks/run-history/index.js +3 -0
  293. package/registry/blocks/run-history/run-history.jsx +218 -0
  294. package/registry/blocks/run-view/README.md +174 -0
  295. package/registry/blocks/run-view/block.json +50 -0
  296. package/registry/blocks/run-view/demo.jsx +286 -0
  297. package/registry/blocks/run-view/index.js +5 -0
  298. package/registry/blocks/run-view/run-controls.jsx +266 -0
  299. package/registry/blocks/run-view/run-view.jsx +236 -0
  300. package/registry/blocks/run-view/runs-list.jsx +99 -0
  301. package/registry/blocks/schedule-card/README.md +121 -0
  302. package/registry/blocks/schedule-card/block.json +10 -0
  303. package/registry/blocks/schedule-card/demo.jsx +82 -0
  304. package/registry/blocks/schedule-card/index.js +3 -0
  305. package/registry/blocks/schedule-card/schedule-card.jsx +136 -0
  306. package/registry/blocks/schedule-engine/README.md +137 -0
  307. package/registry/blocks/schedule-engine/block.json +10 -0
  308. package/registry/blocks/schedule-engine/demo.jsx +82 -0
  309. package/registry/blocks/schedule-engine/engine.js +769 -0
  310. package/registry/blocks/schedule-engine/index.js +9 -0
  311. package/registry/blocks/schedule-engine/ops.js +71 -0
  312. package/registry/blocks/schedule-engine/place.js +294 -0
  313. package/registry/blocks/schedule-engine/tree.js +79 -0
  314. package/registry/blocks/schedule-engine/waits.js +80 -0
  315. package/registry/blocks/schedule-gantt/README.md +159 -0
  316. package/registry/blocks/schedule-gantt/block.json +10 -0
  317. package/registry/blocks/schedule-gantt/demo.jsx +223 -0
  318. package/registry/blocks/schedule-gantt/gantt-model.js +219 -0
  319. package/registry/blocks/schedule-gantt/geometry.js +176 -0
  320. package/registry/blocks/schedule-gantt/index.js +26 -0
  321. package/registry/blocks/schedule-gantt/schedule-gantt.jsx +882 -0
  322. package/registry/blocks/schedule-gantt/sheet.jsx +372 -0
  323. package/registry/blocks/schedule-gantt/track.jsx +190 -0
  324. package/registry/blocks/schedule-ruler/README.md +148 -0
  325. package/registry/blocks/schedule-ruler/block.json +10 -0
  326. package/registry/blocks/schedule-ruler/demo.jsx +181 -0
  327. package/registry/blocks/schedule-ruler/index.js +21 -0
  328. package/registry/blocks/schedule-ruler/ruler-model.js +239 -0
  329. package/registry/blocks/schedule-ruler/schedule-ruler.jsx +548 -0
  330. package/registry/blocks/sidebar/README.md +23 -13
  331. package/registry/blocks/sketch-canvas/README.md +15 -9
  332. package/registry/blocks/source-receipt/README.md +97 -0
  333. package/registry/blocks/source-receipt/block.json +30 -0
  334. package/registry/blocks/source-receipt/demo.jsx +71 -0
  335. package/registry/blocks/source-receipt/index.js +3 -0
  336. package/registry/blocks/source-receipt/source-receipt.jsx +107 -0
  337. package/registry/blocks/spreadsheet/spreadsheet.jsx +15 -1
  338. package/registry/blocks/step-picker/README.md +78 -0
  339. package/registry/blocks/step-picker/block.json +31 -0
  340. package/registry/blocks/step-picker/demo.jsx +23 -0
  341. package/registry/blocks/step-picker/index.js +3 -0
  342. package/registry/blocks/step-picker/step-picker.jsx +144 -0
  343. package/registry/blocks/step-settings/README.md +100 -0
  344. package/registry/blocks/step-settings/block.json +44 -0
  345. package/registry/blocks/step-settings/demo.jsx +93 -0
  346. package/registry/blocks/step-settings/fields.jsx +58 -0
  347. package/registry/blocks/step-settings/flow-settings.jsx +115 -0
  348. package/registry/blocks/step-settings/index.js +5 -0
  349. package/registry/blocks/step-settings/step-settings.jsx +290 -0
  350. package/registry/blocks/suggestion/README.md +171 -0
  351. package/registry/blocks/suggestion/block.json +40 -0
  352. package/registry/blocks/suggestion/demo.jsx +91 -0
  353. package/registry/blocks/suggestion/index.js +3 -0
  354. package/registry/blocks/suggestion/suggestion.jsx +436 -0
  355. package/registry/blocks/sum-bar/README.md +122 -0
  356. package/registry/blocks/sum-bar/block.json +10 -0
  357. package/registry/blocks/sum-bar/demo.jsx +110 -0
  358. package/registry/blocks/sum-bar/index.js +5 -0
  359. package/registry/blocks/sum-bar/sum-bar.jsx +209 -0
  360. package/registry/blocks/sum-bar/sum-model.js +126 -0
  361. package/registry/blocks/tier-map/README.md +217 -0
  362. package/registry/blocks/tier-map/block.json +10 -0
  363. package/registry/blocks/tier-map/demo.jsx +222 -0
  364. package/registry/blocks/tier-map/index.js +24 -0
  365. package/registry/blocks/tier-map/tier-map.jsx +574 -0
  366. package/registry/blocks/tier-map/tier-model.js +318 -0
  367. package/registry/blocks/time-grid/README.md +305 -0
  368. package/registry/blocks/time-grid/block.json +10 -0
  369. package/registry/blocks/time-grid/demo.jsx +279 -0
  370. package/registry/blocks/time-grid/grid-model.js +322 -0
  371. package/registry/blocks/time-grid/index.js +25 -0
  372. package/registry/blocks/time-grid/time-grid.jsx +1325 -0
  373. package/registry/blocks/time-strip/README.md +141 -0
  374. package/registry/blocks/time-strip/block.json +10 -0
  375. package/registry/blocks/time-strip/demo.jsx +129 -0
  376. package/registry/blocks/time-strip/index.js +19 -0
  377. package/registry/blocks/time-strip/strip-model.js +178 -0
  378. package/registry/blocks/time-strip/time-strip.jsx +260 -0
  379. package/registry/blocks/top-bar/README.md +149 -0
  380. package/registry/blocks/top-bar/block.json +35 -0
  381. package/registry/blocks/top-bar/demo.jsx +78 -0
  382. package/registry/blocks/top-bar/index.js +5 -0
  383. package/registry/blocks/top-bar/probe-rules.js +74 -0
  384. package/registry/blocks/top-bar/top-bar-model.js +152 -0
  385. package/registry/blocks/top-bar/top-bar.jsx +244 -0
  386. package/registry/blocks/trigger-picker/README.md +98 -0
  387. package/registry/blocks/trigger-picker/block.json +38 -0
  388. package/registry/blocks/trigger-picker/demo.jsx +59 -0
  389. package/registry/blocks/trigger-picker/index.js +3 -0
  390. package/registry/blocks/trigger-picker/trigger-picker.jsx +374 -0
  391. package/registry/blocks/whiteboard/README.md +20 -14
  392. package/registry/blocks/workflow-view/README.md +123 -0
  393. package/registry/blocks/workflow-view/block.json +10 -0
  394. package/registry/blocks/workflow-view/demo.jsx +90 -0
  395. package/registry/blocks/workflow-view/index.js +3 -0
  396. package/registry/blocks/workflow-view/workflow-view.jsx +203 -0
  397. package/src/cli.mjs +2 -2
  398. package/src/install.mjs +100 -22
  399. package/src/registry.mjs +37 -3
  400. package/templates/next/browser/lib/data.js +6 -1
  401. package/templates/next/files/README.md +909 -26
  402. package/templates/next/files/app/shell.jsx +54 -37
  403. package/templates/next/files/check/automation-format.ts +2103 -0
  404. package/templates/next/files/check/automation-package.ts +142 -0
  405. package/templates/next/files/check/run.mjs +1043 -12
  406. package/templates/next/files/components/ui/field.jsx +17 -4
  407. package/templates/next/files/components/ui/icon.jsx +13 -0
  408. package/templates/next/files/components/ui/index.js +3 -1
  409. package/templates/next/files/components/ui/layout.jsx +382 -0
  410. package/templates/next/files/components/ui/notice.jsx +70 -0
  411. package/templates/next/files/components/ui/page.jsx +124 -0
  412. package/templates/next/files/components/ui/stat.jsx +22 -7
  413. package/templates/next/files/components/ui/toast.jsx +6 -3
  414. package/templates/next/files/lib/automations.js +660 -0
  415. package/templates/next/files/lib/claw.js +244 -5
  416. package/templates/next/files/lib/door.js +92 -0
  417. package/templates/next/files/lib/hooks.js +1694 -6
  418. package/templates/next/files/lib/platform.js +611 -14
  419. package/templates/next/template.json +22 -3
@@ -0,0 +1,72 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "step-settings",
4
+ "type": "registry:block",
5
+ "title": "StepSettings",
6
+ "description": "The panel for one step of an automation, made for its kind: a name; an app action picked from the app's declared actions with what to give it; a connected tool by kind of account; a condition; a for-each's list and limit; a model call's question and tier; an agent step's instructions and credit limit; a paid-data step's service, address and price ceiling; a wait; a stop; a note for the owner; and, for every step, what happens if it fails (stop or carry on, how many tries) and a plain list of what is wrong with it. Every text field takes data from earlier steps (data-picker). In a run the same panel is read-only and shows how the step went, what went in and what came out, and what the agent changed (fix-note). FlowSettings is the panel for the automation as a whole: name, what it does, overlap, what happens when a step fails, the most a run may spend, what a manual run asks first, and its versions.",
7
+ "registryDependencies": [
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/core.json",
9
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/automation-model.json",
10
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/data-picker.json",
11
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/fix-note.json"
12
+ ],
13
+ "dependencies": [],
14
+ "files": [
15
+ {
16
+ "path": "registry/blocks/step-settings/index.js",
17
+ "type": "registry:component",
18
+ "target": "@components/makersclaw/blocks/step-settings/index.js",
19
+ "content": "// The StepSettings block — `makersclaw add step-settings`. Fixed: compose\n// it through its props (README.md beside this file).\nexport { FlowSettings } from \"./flow-settings\";\nexport { NumberField, SelectField, SwitchField, TextField } from \"./fields\";\nexport { StepSettings } from \"./step-settings\";\n"
20
+ },
21
+ {
22
+ "path": "registry/blocks/step-settings/step-settings.jsx",
23
+ "type": "registry:component",
24
+ "target": "@components/makersclaw/blocks/step-settings/step-settings.jsx",
25
+ "content": "\"use client\";\n\n// The panel for one step: its name, what it does (a form made for its\n// kind), what happens if it fails, and the plain list of what is wrong\n// with it. In a run the same panel is read-only and adds how the step went,\n// what went in and what came out, and, when the agent fixed the step,\n// what it changed (fix-note).\n//\n// Fields are written in a person's words; the definition's own keys stay\n// out of sight (the step id is shown small, because it is what a run's rows\n// and an app update match steps by). Props in, callbacks out: every change\n// is `onChange(patch)`, applied by the screen with automation-model's\n// updateStep.\n\nimport { useState } from \"react\";\nimport { Button, Confirm, Icon, cx } from \"../../ui\";\nimport { Glyph, KINDS, SidePanel, creditsWords, innerCount, nodeStateWords, stepTitle } from \"../automation-model\";\nimport { DataInput, DataPairs } from \"../data-picker\";\nimport { FixNote } from \"../fix-note\";\nimport { NumberField, SelectField, TextField } from \"./fields\";\n\nconst FAIL_OPTIONS = [\n { value: \"stop\", label: \"Stop the run\" },\n { value: \"continue\", label: \"Carry on without it\" },\n];\nconst OP_OPTIONS = [\n { value: \"search\", label: \"Search\" },\n { value: \"get\", label: \"Get one\" },\n { value: \"list\", label: \"List\" },\n];\nconst METHOD_OPTIONS = [\n { value: \"GET\", label: \"Ask (GET)\" },\n { value: \"POST\", label: \"Send (POST)\" },\n { value: \"PUT\", label: \"Replace (PUT)\" },\n { value: \"PATCH\", label: \"Change (PATCH)\" },\n];\nconst TIER_OPTIONS = [\n { value: \"fast\", label: \"Quick\" },\n { value: \"smart\", label: \"Careful\" },\n];\n\nconst show = (v) => JSON.stringify(v, null, 2) ?? \"\";\n\nfunction Data({ label, value }) {\n if (value === undefined || value === null) return null;\n const text = show(value);\n return (\n <details open={text.length < 240} className=\"rounded-md border border-border bg-muted\">\n <summary className=\"cursor-pointer px-2 py-1 text-xs font-medium\">{label}</summary>\n <pre className=\"m-0 max-h-64 overflow-auto px-2 pb-2 font-mono text-xs\">{text.length > 4000 ? `${text.slice(0, 4000)}\\n…` : text}</pre>\n </details>\n );\n}\n\n/** A run's own account of the step: how it went, what went in and out. */\nfunction RunBlock({ summary, dataVisible, title, fixProps }) {\n const last = summary.rows[summary.rows.length - 1];\n return (\n <section aria-label=\"How it went\" className=\"grid gap-2 rounded-lg border border-border bg-background p-3\">\n <h4 className={cx(\"m-0 text-sm font-semibold\", summary.state === \"failed\" && \"text-destructive\", summary.state === \"done\" && \"text-success\", summary.state === \"would\" && \"text-primary\")}>{nodeStateWords(summary.state)}</h4>\n <p className=\"m-0 text-xs text-muted-foreground\">\n {summary.passes > 1 ? `${summary.passes} times · ` : \"\"}\n {creditsWords(summary.credits)}\n </p>\n {summary.words ? <p className=\"m-0 text-[13px] text-destructive\">{summary.words}</p> : null}\n {summary.state === \"would\" && summary.would ? <p className=\"m-0 text-[13px] text-primary\">{summary.would}</p> : null}\n {summary.unchecked ? <p className=\"m-0 text-[13px] text-muted-foreground\">Not checked: it needs what an earlier step would have made.</p> : null}\n {summary.fix ? <FixNote fix={summary.fix} stepTitle={title} {...fixProps} /> : null}\n {dataVisible && last ? (\n <>\n <Data label=\"Went in\" value={last.input} />\n <Data label=\"Came out\" value={last.output} />\n </>\n ) : (\n <p className=\"m-0 text-xs text-muted-foreground\">What went in and came out is shown to the automation's owner and the admins.</p>\n )}\n </section>\n );\n}\n\n/**\n * step the step shown\n * available automation-model's availableBefore(def, id, stepTitle), plus\n * optionally `inputs: [{ name, label }]` (what a manual run asks)\n * samples { [stepId]: a real output } for the data picker, or null\n * apps the workspace's apps, [{ id, name }], for an action in a team automation\n * actions the app's declared actions, [{ name, description? }]: an action\n * step picks from them instead of typing a name\n * ownedByApp the automation belongs to an app (its actions need no app)\n * problems lines about this step to fix\n * readOnly shown, not editable (a run)\n * onChange(patch), onRemove(), onDuplicate(), onClose()\n * summary a run: automation-model's summarizeSteps() entry for this step\n * dataVisible the member may read what went in and out\n * fixProps what FixNote needs for a step the agent fixed: { draft, onKeep, onDrop, onUndo }\n * onKeepFix() keep a fix the agent made, for next time (shorthand for fixProps.onKeep)\n * runActions a run: what the member can do with this step (a node), drawn under how it went\n */\nexport function StepSettings({ step, available, samples = null, apps = [], actions, ownedByApp = false, problems = [], readOnly = false, onChange, onRemove, onDuplicate, onClose, summary = null, dataVisible = false, fixProps, onKeepFix, runActions = null }) {\n const info = KINDS[step.kind] ?? KINDS.action;\n const dis = readOnly;\n const set = (patch) => onChange?.(patch);\n const inner = innerCount(step);\n const [confirming, setConfirming] = useState(false);\n const title = stepTitle(step);\n\n const remove = () => {\n if (inner > 0) setConfirming(true);\n else onRemove?.();\n };\n\n return (\n <SidePanel\n glyph={<Glyph name={info.glyph} size={20} />}\n tone={info.tone === \"plain\" ? \"plain\" : \"ai\"}\n title={title}\n subtitle={`${info.name}${info.paid ? \" · costs credits\" : \" · free\"}`}\n label={`${info.name} settings`}\n onClose={onClose}\n footer={\n readOnly ? null : (\n <>\n <Button size=\"sm\" variant=\"secondary\" icon=\"copy\" onClick={onDuplicate}>\n Duplicate\n </Button>\n <Button size=\"sm\" variant=\"danger\" icon=\"trash\" onClick={remove}>\n Remove\n </Button>\n </>\n )\n }\n >\n {summary ? <RunBlock summary={summary} dataVisible={dataVisible} title={title} fixProps={fixProps ?? (onKeepFix ? { onKeep: onKeepFix } : undefined)} /> : null}\n {summary && runActions ? runActions : null}\n\n <TextField label=\"Name\" value={step.label ?? \"\"} placeholder={stepTitle({ ...step, label: undefined })} disabled={dis} onChange={(v) => set({ label: v.trim() ? v : undefined })} help=\"What this step is called on the canvas.\" />\n\n {step.kind === \"action\" ? (\n <>\n {!ownedByApp ? (\n <SelectField label=\"App\" value={step.app ?? \"\"} disabled={dis} onChange={(v) => set({ app: v || undefined })} options={[{ value: \"\", label: \"Pick an app\" }, ...apps.map((a) => ({ value: a.id, label: a.name }))]} help=\"Which of your apps this action belongs to.\" />\n ) : null}\n {actions?.length ? (\n <SelectField\n label=\"Action\"\n value={step.action}\n disabled={dis}\n onChange={(v) => set({ action: v })}\n options={[{ value: \"\", label: \"Pick an action\" }, ...actions.map((a) => ({ value: a.name, label: a.description ? `${a.name}: ${a.description}` : a.name })), ...(step.action && !actions.some((a) => a.name === step.action) ? [{ value: step.action, label: step.action }] : [])]}\n help=\"The actions this app declares.\"\n />\n ) : (\n <TextField label=\"Action\" value={step.action} mono disabled={dis} placeholder=\"add_people\" onChange={(v) => set({ action: v })} help=\"The name of the action the app declares.\" />\n )}\n <DataPairs label=\"What to give it\" value={step.input} available={available} samples={samples} disabled={dis} onChange={(v) => set({ input: v })} />\n </>\n ) : null}\n\n {step.kind === \"tool\" ? (\n <>\n <TextField label=\"Kind of account\" value={step.needs?.category ?? \"\"} mono disabled={dis} placeholder=\"mail\" onChange={(v) => set({ needs: { category: v } })} help=\"The account is chosen by kind (mail, calendar, chat), never by product.\" />\n <TextField label=\"Tool\" value={step.tool} mono disabled={dis} placeholder=\"list_messages\" onChange={(v) => set({ tool: v })} />\n <TextField label=\"Which account\" value={step.account ?? \"\"} disabled={dis} placeholder=\"you@company.com\" onChange={(v) => set({ account: v || undefined })} help=\"Only when you have several of that kind.\" />\n <DataPairs label=\"What to give it\" value={step.input} available={available} samples={samples} disabled={dis} onChange={(v) => set({ input: v })} />\n </>\n ) : null}\n\n {step.kind === \"brain.read\" ? (\n <>\n <SelectField label=\"How\" value={step.op} options={OP_OPTIONS} disabled={dis} onChange={(v) => set({ op: v })} />\n <DataPairs label=\"What to look for\" value={step.input} available={available} samples={samples} disabled={dis} onChange={(v) => set({ input: v })} />\n </>\n ) : null}\n\n {step.kind === \"condition\" ? (\n <DataInput label=\"Go the Yes way when\" value={step.if} mono multiline rows={3} disabled={dis} available={available} samples={samples} onChange={(v) => set({ if: v })} help=\"Anything else goes the No way. Branches are drawn on the canvas; add steps to each with +.\" />\n ) : null}\n\n {step.kind === \"loop\" ? (\n <>\n <DataInput label=\"Go through\" value={step.over} mono disabled={dis} available={available} samples={samples} onChange={(v) => set({ over: v })} help=\"A list from an earlier step.\" />\n <NumberField label=\"At most\" value={step.max} min={1} max={500} disabled={dis} onChange={(v) => set({ max: v })} help=\"How many items it will go through.\" />\n <DataInput label=\"Collect from each pass\" value={step.collect ?? \"\"} mono disabled={dis} available={available} samples={samples} onChange={(v) => set({ collect: v || undefined })} help=\"Optional: what to keep from every pass, as a list.\" />\n </>\n ) : null}\n\n {step.kind === \"set\" ? <DataPairs label=\"Values\" value={step.values} available={available} samples={samples} disabled={dis} keyLabel=\"Name\" onChange={(v) => set({ values: v })} /> : null}\n\n {step.kind === \"wait\" ? (\n <>\n <TextField label=\"Wait for\" value={step.for ?? \"\"} mono disabled={dis} placeholder=\"10m\" onChange={(v) => set({ for: v || undefined, ...(v ? { until: undefined } : {}) })} help=\"A number and a unit: 30s, 10m, 2h, 3d. Nothing runs while it waits.\" />\n <DataInput label=\"Or wait until\" value={step.until ?? \"\"} mono disabled={dis} available={available} samples={samples} onChange={(v) => set({ until: v || undefined, ...(v ? { for: undefined } : {}) })} help=\"A time, as data.\" />\n </>\n ) : null}\n\n {step.kind === \"stop\" ? (\n <>\n <DataInput label=\"Message\" value={step.message} multiline rows={3} disabled={dis} available={available} samples={samples} onChange={(v) => set({ message: v })} />\n <SelectField\n label=\"Ends as\"\n value={step.as ?? \"done\"}\n disabled={dis}\n onChange={(v) => set({ as: v === \"done\" ? undefined : v })}\n options={[\n { value: \"done\", label: \"Done\" },\n { value: \"failed\", label: \"Failed\" },\n ]}\n />\n </>\n ) : null}\n\n {step.kind === \"notify\" ? <DataInput label=\"Message\" value={step.message} multiline rows={3} disabled={dis} available={available} samples={samples} onChange={(v) => set({ message: v })} help=\"A line for the owner, in their Needs you.\" /> : null}\n\n {step.kind === \"search\" ? (\n <>\n <DataInput label=\"Search for\" value={step.query} multiline rows={2} disabled={dis} available={available} samples={samples} onChange={(v) => set({ query: v })} />\n <NumberField label=\"How many results\" value={step.limit} min={1} max={20} disabled={dis} onChange={(v) => set({ limit: v })} />\n </>\n ) : null}\n\n {step.kind === \"llm\" ? (\n <>\n <DataInput label=\"What to ask\" value={step.prompt} multiline rows={6} disabled={dis} available={available} samples={samples} onChange={(v) => set({ prompt: v })} />\n <SelectField label=\"Which model\" value={step.tier ?? \"fast\"} options={TIER_OPTIONS} disabled={dis} onChange={(v) => set({ tier: v })} help=\"Quick is cheaper. Careful thinks longer.\" />\n <TextField label=\"Standing instructions\" value={step.system ?? \"\"} multiline rows={2} disabled={dis} onChange={(v) => set({ system: v || undefined })} help=\"Optional instructions that frame every answer.\" />\n </>\n ) : null}\n\n {step.kind === \"agent\" ? (\n <>\n <DataInput label=\"What the agent should do\" value={step.instructions} multiline rows={7} disabled={dis} available={available} samples={samples} onChange={(v) => set({ instructions: v })} help=\"Plain words. The agent may use your apps and connected accounts, within what you can reach.\" />\n <NumberField label=\"Most it may spend\" value={step.cap_credits} min={1} disabled={dis} onChange={(v) => set({ cap_credits: v })} help=\"In credits. The run stops the agent there.\" />\n </>\n ) : null}\n\n {step.kind === \"zero\" ? (\n <>\n <TextField label=\"Paid service\" value={step.capability ?? \"\"} mono disabled={dis} placeholder=\"the service's name\" onChange={(v) => set({ capability: v })} help=\"The name the platform's catalog of paid services gave it.\" />\n <DataInput label=\"Address\" value={step.url ?? \"\"} mono disabled={dis} available={available} samples={samples} onChange={(v) => set({ url: v })} help=\"The service's own web address, starting with https://.\" />\n <SelectField label=\"How it is called\" value={step.method ?? \"GET\"} options={METHOD_OPTIONS} disabled={dis} onChange={(v) => set({ method: v === \"GET\" ? undefined : v })} help=\"Ask puts what you give it on the address; the others send it as a body.\" />\n <DataPairs label=\"What to give it\" value={step.input} available={available} samples={samples} disabled={dis} onChange={(v) => set({ input: v })} />\n <NumberField label=\"Most one call may cost, in dollars\" value={step.max_pay_usd} min={0.01} max={2} step={0.01} disabled={dis} onChange={(v) => set({ max_pay_usd: v })} help=\"The step never pays more than this, and the same call is not paid for twice. It comes out of your credits.\" />\n </>\n ) : null}\n\n {step.kind === \"automation\" ? (\n <>\n <TextField label=\"Which automation\" value={step.key} mono disabled={dis} placeholder=\"morning-read\" onChange={(v) => set({ key: v })} />\n <DataPairs label=\"What to give it\" value={step.input} available={available} samples={samples} disabled={dis} onChange={(v) => set({ input: v })} />\n </>\n ) : null}\n\n <section className=\"grid gap-3 border-t border-border pt-3\">\n <h4 className=\"m-0 text-2xs font-semibold uppercase tracking-wide text-muted-foreground\">If it fails</h4>\n <SelectField label=\"After the tries are used up\" value={step.on_error ?? \"stop\"} options={FAIL_OPTIONS} disabled={dis} onChange={(v) => set({ on_error: v === \"stop\" ? undefined : v })} help=\"The agent steps in first, if the flow lets it.\" />\n <NumberField label=\"Tries after the first\" value={step.retry?.max} min={0} max={5} disabled={dis} placeholder=\"3\" onChange={(v) => set({ retry: v === undefined ? undefined : { max: v } })} help=\"For a slow or busy service. Leave empty for the usual three.\" />\n </section>\n\n {problems.length > 0 ? (\n <div role=\"alert\" className=\"grid gap-1 rounded-lg border border-destructive/50 bg-destructive/10 p-3\">\n <h4 className=\"m-0 flex items-center gap-1.5 text-sm font-semibold text-destructive\">\n <Icon name=\"warning\" size={14} /> To fix\n </h4>\n <ul className=\"m-0 grid list-disc gap-0.5 pl-5 text-[13px]\">\n {problems.map((x) => (\n <li key={x}>{x}</li>\n ))}\n </ul>\n </div>\n ) : null}\n\n <p className=\"m-0 text-xs text-muted-foreground\">\n Step id <span className=\"font-mono\">{step.id}</span>\n </p>\n\n <Confirm\n open={confirming}\n onClose={() => setConfirming(false)}\n onConfirm={() => {\n setConfirming(false);\n onRemove?.();\n }}\n title=\"Remove this step?\"\n body={`This also removes the ${inner} step${inner === 1 ? \"\" : \"s\"} inside it.`}\n confirmLabel=\"Remove\"\n tone=\"danger\"\n />\n </SidePanel>\n );\n}\n"
26
+ },
27
+ {
28
+ "path": "registry/blocks/step-settings/flow-settings.jsx",
29
+ "type": "registry:component",
30
+ "target": "@components/makersclaw/blocks/step-settings/flow-settings.jsx",
31
+ "content": "\"use client\";\n\n// The panel for the automation as a whole: its name, what it does, what\n// happens when a step fails, what one run may spend, what a manual run\n// asks for first, and its versions. Props in; every change is\n// `onChange(nextDefinition)`.\n\nimport { Button, Select, Input, cx } from \"../../ui\";\nimport { Chip, Glyph, PanelSection, SidePanel, agoWords } from \"../automation-model\";\nimport { NumberField, SelectField, SwitchField, TextField } from \"./fields\";\n\nconst OVERLAP = [\n { value: \"skip\", label: \"Skip the new run\" },\n { value: \"queue\", label: \"Queue it behind\" },\n { value: \"allow\", label: \"Run both at once\" },\n];\nconst FAILURE = [\n { value: \"retry_then_agent\", label: \"Retry, then ask the agent to fix it\" },\n { value: \"agent_first\", label: \"Ask the agent to fix it straight away\" },\n { value: \"stop\", label: \"Stop the run\" },\n];\nconst INPUT_TYPES = [\n { value: \"string\", label: \"Text\" },\n { value: \"number\", label: \"Number\" },\n { value: \"boolean\", label: \"Yes or no\" },\n { value: \"date\", label: \"Date\" },\n];\n\n/**\n * def the automation: { name, does, settings, inputs, … }\n * readOnly shown, not editable\n * versions [{ version, kind: shipped|member|agent, note, created_at }]\n * liveVersion the version that runs\n * onChange(def)\n * onClose draws the close button\n * onReset draws \"Reset to the app's version\" when the automation\n * was edited from a shipped one\n */\nexport function FlowSettings({ def, readOnly = false, versions = [], liveVersion = null, onChange, onClose, onReset }) {\n const set = (patch) => onChange({ ...def, ...patch });\n const setSettings = (patch) => onChange({ ...def, settings: { ...def.settings, ...patch } });\n const inputs = Object.entries(def.inputs ?? {});\n const setInputs = (next) => onChange({ ...def, inputs: Object.fromEntries(next) });\n\n return (\n <SidePanel glyph={<Glyph name=\"automation\" size={20} />} title=\"This automation\" subtitle=\"How it behaves as a whole\" label=\"Flow settings\" onClose={onClose}>\n <TextField label=\"Name\" value={def.name} disabled={readOnly} onChange={(v) => set({ name: v })} />\n <TextField label=\"What it does\" value={def.does ?? \"\"} multiline rows={3} disabled={readOnly} onChange={(v) => set({ does: v || undefined })} help=\"One sentence, for the list.\" />\n\n <PanelSection title=\"When it runs\">\n <SelectField label=\"If it is still running when the next one is due\" value={def.settings.overlap} options={OVERLAP} disabled={readOnly} onChange={(v) => setSettings({ overlap: v })} />\n <SwitchField label=\"Only when something changed\" checked={Boolean(def.settings.only_if_changed)} disabled={readOnly} onChange={(v) => setSettings({ only_if_changed: v })} help=\"Skip a scheduled run when nothing it reads has changed since the last one.\" />\n </PanelSection>\n\n <PanelSection title=\"When a step fails\">\n <SelectField label=\"What happens\" value={def.settings.on_failure} options={FAILURE} disabled={readOnly} onChange={(v) => setSettings({ on_failure: v })} help=\"The agent changes only this run: a date format, a missing field. Never who gets what.\" />\n <NumberField label=\"Most one run may spend\" value={def.settings.run_cap_credits} min={1} disabled={readOnly} placeholder=\"No limit\" onChange={(v) => setSettings({ run_cap_credits: v })} help=\"In credits. A run that reaches it stops.\" />\n </PanelSection>\n\n <PanelSection title=\"What a manual run asks for\">\n {inputs.length === 0 ? <p className=\"m-0 text-xs text-muted-foreground\">Nothing. Add a question if a run needs an answer first.</p> : null}\n {inputs.map(([name, spec], i) => (\n <div key={i} className=\"flex min-w-0 items-center gap-1.5\">\n <Input\n className=\"min-w-0 flex-1 font-mono text-[13px]\"\n aria-label={`Question name ${i + 1}`}\n value={name}\n disabled={readOnly}\n onChange={(e) => setInputs(inputs.map((x, j) => (j === i ? [e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, \"_\"), x[1]] : x)))}\n />\n <span className=\"w-28 shrink-0\">\n <Select aria-label={`Question type ${i + 1}`} value={spec.type} disabled={readOnly} options={INPUT_TYPES} onChange={(e) => setInputs(inputs.map((x, j) => (j === i ? [x[0], { ...x[1], type: e.target.value }] : x)))} />\n </span>\n {!readOnly ? (\n <button type=\"button\" aria-label={`Remove ${name}`} onClick={() => setInputs(inputs.filter((_, j) => j !== i))} className=\"inline-flex size-9 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\">\n ×\n </button>\n ) : null}\n </div>\n ))}\n {!readOnly && inputs.length < 20 ? (\n <Button size=\"sm\" variant=\"secondary\" className=\"justify-self-start\" onClick={() => setInputs([...inputs, [`question_${inputs.length + 1}`, { type: \"string\", label: \"\" }]])}>\n + Add a question\n </Button>\n ) : null}\n </PanelSection>\n\n {versions.length > 0 ? (\n <PanelSection title=\"Versions\">\n <ol className=\"m-0 grid list-none gap-1.5 p-0\">\n {versions.map((v) => (\n <li key={v.version} className={cx(\"grid gap-0.5 rounded-lg border px-2.5 py-1.5\", v.version === liveVersion ? \"border-success/50\" : \"border-border\")}>\n <span className=\"flex items-center gap-2\">\n <b className=\"text-[13px] font-semibold\">Version {v.version}</b>\n {v.version === liveVersion ? <Chip tone=\"green\">Live</Chip> : null}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n {v.kind === \"shipped\" ? \"From the app\" : v.kind === \"agent\" ? \"By the agent\" : \"Edited\"}\n {\" · \"}\n {agoWords(v.created_at) ?? \"\"}\n </span>\n {v.note ? <p className=\"m-0 text-xs\">{v.note}</p> : null}\n </li>\n ))}\n </ol>\n {onReset && !readOnly ? (\n <Button size=\"sm\" variant=\"secondary\" className=\"justify-self-start\" onClick={onReset}>\n Reset to the app's version\n </Button>\n ) : null}\n </PanelSection>\n ) : null}\n </SidePanel>\n );\n}\n"
32
+ },
33
+ {
34
+ "path": "registry/blocks/step-settings/fields.jsx",
35
+ "type": "registry:component",
36
+ "target": "@components/makersclaw/blocks/step-settings/fields.jsx",
37
+ "content": "\"use client\";\n\n// The plain form rows the settings panels share, on the kit's parts: a\n// labelled text, number, select or switch. Each is a real label over a\n// real control, so it works by keyboard and with a screen reader.\n\nimport { useId } from \"react\";\nimport { Field, Input, Select, Switch, Textarea } from \"../../ui\";\n\nexport function TextField({ label, value, onChange, help, placeholder, mono = false, multiline = false, rows = 3, disabled = false }) {\n const id = useId();\n const common = { id, value, disabled, placeholder, className: mono ? \"font-mono text-[13px]\" : undefined, onChange: (e) => onChange(e.target.value) };\n return (\n <Field id={id} label={label} hint={help}>\n {multiline ? <Textarea {...common} rows={rows} /> : <Input {...common} type=\"text\" />}\n </Field>\n );\n}\n\nexport function NumberField({ label, value, onChange, min, max, step, help, placeholder, disabled = false }) {\n const id = useId();\n return (\n <Field id={id} label={label} hint={help}>\n <Input\n id={id}\n type=\"number\"\n inputMode={step !== undefined && step < 1 ? \"decimal\" : \"numeric\"}\n className=\"font-mono text-[13px]\"\n min={min}\n max={max}\n step={step}\n value={value ?? \"\"}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? undefined : Number(e.target.value))}\n />\n </Field>\n );\n}\n\nexport function SelectField({ label, value, onChange, options, help, disabled = false }) {\n const id = useId();\n return (\n <Field id={id} label={label} hint={help}>\n <Select id={id} value={value} disabled={disabled} options={options} onChange={(e) => onChange(e.target.value)} />\n </Field>\n );\n}\n\nexport function SwitchField({ label, checked, onChange, help, disabled = false }) {\n const id = useId();\n return (\n <div className=\"grid gap-0.5\">\n <Switch id={id} checked={checked} disabled={disabled} label={label} onChange={(e) => onChange(e.target.checked)} />\n {help ? <p className=\"m-0 text-xs text-muted-foreground\">{help}</p> : null}\n </div>\n );\n}\n"
38
+ },
39
+ {
40
+ "path": "registry/blocks/step-settings/README.md",
41
+ "type": "registry:file",
42
+ "target": "@components/makersclaw/blocks/step-settings/README.md",
43
+ "content": "# StepSettings\n\nThe panel for one step of an automation, made for its kind, and the panel\nfor the automation as a whole. In a run the same panel is read-only and\nadds how the step went.\n\n**StepSettings** — a name; then what the kind needs, in a person's words:\n\n- **App action** — picked from the app's declared actions (`actions`),\n with what to give it; in a team automation, which app.\n- **Connected tool** — the kind of account (mail, calendar, chat — never a\n product), the tool, which account when there are several, what to give it.\n- **Condition** — \"Go the Yes way when …\"; anything else goes No.\n- **For each** — the list, at most how many, what to collect.\n- **Ask the model** — what to ask, Quick or Careful, standing instructions.\n- **Agent** — what it should do, and the most it may spend.\n- **Buy paid data** (a Zero step) — the paid service, its address, how it is\n called (Ask, Send, Replace, Change), what to give it, and the most one call\n may cost in dollars. Plain code: no model, and the same call is never paid\n for twice.\n- **Set, Wait, Stop, Tell someone, Search, Another automation, Company\n brain** — their own few fields.\n\nEvery text field takes data from earlier steps (`data-picker`). For every\nstep: **If it fails** (stop or carry on without it; how many tries) and a\nplain **To fix** list of what is wrong with it. In a run (`readOnly` and a\n`summary`): how it went, how many times, what it cost, what went in and\nwhat came out (for those who may read it), and the agent's fix (`fix-note`).\n\n**FlowSettings** — name; what it does; if it is still running when the next\nis due (skip, queue, run both); only when something changed; what happens\nwhen a step fails (retry, then the agent; the agent first; stop); the most\none run may spend; what a manual run asks for first; its versions.\n\n```jsx\nimport { StepSettings, FlowSettings } from \"../components/blocks/step-settings\"; // a Makersclaw app\nimport { StepSettings, FlowSettings } from \"@/components/makersclaw/blocks/step-settings\"; // a shadcn project\n```\n\n`makersclaw add step-settings` lays `data-picker`, `fix-note` and\n`automation-model` with it. Client components. Each is a panel (a head, a\nscrolling body, a foot): place it beside or over the canvas.\n\n## Props\n\n### StepSettings\n\n- `step` — the step shown.\n- `available` — `availableBefore(def, step.id, stepTitle)`, plus\n `inputs: [{ name, label }]` for a manual run's questions. `samples` —\n `{ [stepId]: a real output }`, or null.\n- `apps` — `[{ id, name }]`; `ownedByApp` — an app's own automation needs\n no app on an action. `actions` — `[{ name, description }]`.\n- `problems` — lines about this step (`issuesFor(issues, step.id)`).\n- `readOnly`, `summary` (a run's `summarizeSteps(rows).get(step.id)`),\n `dataVisible` (the member may read what went in and out), `onKeepFix()`,\n `runActions` (a node drawn under how the step went: run-view puts its\n \"Retry from this step\" there).\n- `onChange(patch)` — fields to change, for `updateStep(def, id, patch)`.\n `onRemove()` (asks first when the step holds others), `onDuplicate()`,\n `onClose()`.\n\n### FlowSettings\n\n- `def`, `readOnly`, `versions` (`[{ version, kind, note, created_at }]`),\n `liveVersion`, `onChange(def)`, `onClose`, `onReset` (\"Reset to the app's\n version\", when it was edited from a shipped one).\n\n### The rows\n\n`TextField`, `NumberField`, `SelectField` and `SwitchField`: a labelled\ncontrol each, on the kit's parts.\n\n## Never\n\n- Never show the definition's own keys: a step's words are a person's.\n (The step id is shown small, because a run's rows and an app update\n match steps by it.)\n- Never let the panel save: it only says what changed. The screen saves.\n\n## Example\n\n```jsx\n\"use client\";\nimport { useState } from \"react\";\nimport { availableBefore, stepTitle, updateStep } from \"../components/blocks/automation-model\";\nimport { StepSettings } from \"../components/blocks/step-settings\";\n\nconst START = { format: 1, key: \"t\", name: \"T\", trigger: { type: \"manual\" }, inputs: {}, settings: {}, steps: [{ id: \"tell\", kind: \"notify\", message: \"Hello\" }] };\n\nexport default function Panel() {\n const [def, setDef] = useState(START);\n const step = def.steps[0];\n return (\n <div className=\"h-[520px] max-w-sm overflow-hidden rounded-lg border border-border\">\n <StepSettings step={step} available={availableBefore(def, step.id, stepTitle)} onChange={(patch) => setDef(updateStep(def, step.id, patch))} onClose={() => {}} />\n </div>\n );\n}\n```\n"
44
+ }
45
+ ],
46
+ "categories": [
47
+ "automation",
48
+ "workflow",
49
+ "step",
50
+ "settings",
51
+ "form",
52
+ "panel",
53
+ "inspector",
54
+ "action",
55
+ "condition",
56
+ "loop",
57
+ "llm",
58
+ "agent",
59
+ "retry",
60
+ "failure",
61
+ "versions",
62
+ "n8n",
63
+ "make"
64
+ ],
65
+ "docs": "Installed to components/makersclaw/blocks/step-settings. Import: import { FlowSettings, NumberField, SelectField, StepSettings, SwitchField, TextField } from \"@/components/makersclaw/blocks/step-settings\". Props and an example: components/makersclaw/blocks/step-settings/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
66
+ "meta": {
67
+ "makersclaw": {
68
+ "version": "0.8.1",
69
+ "useWhen": "A step or an automation is edited or read in your own screen. automation-editor and run-view place these for you."
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "suggestion",
4
+ "type": "registry:block",
5
+ "title": "Suggestion",
6
+ "description": "A value the agent proposes, drawn in pencil — dashed while it is a proposal, solid once kept — with its source always shown and a keep or a drop. Five shapes: FieldSuggestion under a field (\"empty now\", the proposed value, where it came from, Keep and Drop); InlineSuggestion found in place, a small dashed chip inside the cell it would fill with a tick and a cross; TextSuggestion, a span of text struck with its replacement beside it, the reason and the source; Pencil, the dashed frame for a whole proposed record (\"pencil to ink\"); SuggestionGroup, the head over several (\"Keep all 6\", \"Drop all\"); and Looking while a value is still being found. The verbs are props (Keep/Drop, Apply/Dismiss, Accept/Decline). Keeps and drops go out through async callbacks that answer { ok }; a failure says why in place.",
7
+ "registryDependencies": [
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/core.json"
9
+ ],
10
+ "dependencies": [],
11
+ "files": [
12
+ {
13
+ "path": "registry/blocks/suggestion/index.js",
14
+ "type": "registry:component",
15
+ "target": "@components/makersclaw/blocks/suggestion/index.js",
16
+ "content": "// The Suggestion block — `makersclaw add suggestion`. Fixed: compose it\n// through its props (README.md beside this file).\nexport { FieldSuggestion, InlineSuggestion, TextSuggestion, Pencil, SuggestionGroup, Looking, suggestionSource } from \"./suggestion\";\n"
17
+ },
18
+ {
19
+ "path": "registry/blocks/suggestion/suggestion.jsx",
20
+ "type": "registry:component",
21
+ "target": "@components/makersclaw/blocks/suggestion/suggestion.jsx",
22
+ "content": "\"use client\";\n\n// A value the agent proposes, drawn in pencil: dashed while it is a\n// proposal, solid once kept (the app kit, D15; grown in the CRM as\n// field-suggestion, 0.7.0). Five shapes, one idea — the source is always\n// shown, and a person keeps or drops it:\n//\n// FieldSuggestion under a field, with what it holds now\n// InlineSuggestion found in place: a dashed chip in the cell it would fill\n// TextSuggestion a span of text struck, its replacement beside it\n// Pencil the dashed frame for a whole record (\"pencil to ink\")\n// SuggestionGroup the head over several: Keep all, Drop all\n//\n// The verbs are props (Keep/Drop, Apply/Dismiss, Accept/Decline). A keep\n// calls your callback, which runs the app's own declared action, so a\n// keep is the same write the agent would make. Props in, callbacks out;\n// the block never reads a database. Tokens only.\n\nimport { useState } from \"react\";\nimport { Button, Icon, IconButton, cx } from \"../../ui\";\n\n/** \"her email signature, Sat 12 Sep\" from { from, at }. `at` is a\n * \"YYYY-MM-DD\" day (or anything Date reads); `format(date)` words it,\n * default \"Sat 12 Sep\". */\nexport function suggestionSource({ from, at } = {}, format) {\n if (!from && !at) return \"\";\n let when = \"\";\n if (at) {\n const d = typeof at === \"string\" && /^\\d{4}-\\d{2}-\\d{2}$/.test(at) ? new Date(`${at}T12:00:00Z`) : new Date(at);\n if (!Number.isNaN(d.getTime())) {\n when = format ? format(d) : d.toLocaleDateString(\"en-GB\", { weekday: \"short\", day: \"numeric\", month: \"short\", timeZone: \"UTC\" }).replace(\",\", \"\");\n }\n }\n return [from, when].filter(Boolean).join(\", \");\n}\n\nconst FRAME = {\n pencil: \"border-[1.5px] border-dashed border-foreground/35 bg-card\",\n kept: \"border-[1.5px] border-solid border-success/60 bg-card\",\n failed: \"border-[1.5px] border-dashed border-destructive/60 bg-card\",\n};\n\n/** The dashed frame for any proposal: a kicker (\"A NEW DEAL\"), a title,\n * the reason, your content, your actions. `state` \"pencil\" (default),\n * \"kept\" (solid) or \"failed\" (with `error`). */\nexport function Pencil({ kicker, title, reason, state = \"pencil\", error, actions, label, className, children }) {\n return (\n <section\n aria-label={label ?? (typeof title === \"string\" ? `Suggested: ${title}` : \"A suggestion\")}\n className={cx(\"grid grid-cols-1 min-w-0 gap-2 rounded-lg p-3\", FRAME[state] ?? FRAME.pencil, className)}\n >\n {kicker ? <p className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">{kicker}</p> : null}\n {title ? <div className=\"min-w-0 text-[15px] font-semibold leading-snug\">{title}</div> : null}\n {children}\n {reason ? <p className=\"text-sm text-muted-foreground\">{reason}</p> : null}\n {state === \"failed\" && error ? (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {error}\n </p>\n ) : null}\n {actions ? <div className=\"flex flex-wrap items-center gap-2\">{actions}</div> : null}\n </section>\n );\n}\n\n/**\n * One proposed value for one field.\n *\n * label the field's name (\"Job title\")\n * current what it holds now; empty → \"empty now\"\n * value the proposed value (text or a node)\n * source { from, at } or a string: where it came from\n * onKeep() async → { ok } | { ok: false, error }\n * onDrop() async → { ok } | { ok: false, error }\n * compact icon Keep/Drop at the row's end (a list of several)\n * showLabel false when the field's label is drawn by you above it\n * keepLabel · dropLabel · keptLabel the verbs (\"Apply\", \"Dismiss\", \"Applied\")\n */\nexport function FieldSuggestion({\n label,\n current,\n value,\n source,\n onKeep,\n onDrop,\n compact = false,\n showLabel = true,\n keepLabel = \"Keep\",\n dropLabel = \"Drop\",\n keptLabel = \"Kept\",\n formatDate,\n className,\n}) {\n const [busy, setBusy] = useState(null);\n const [state, setState] = useState(\"pencil\");\n const [error, setError] = useState(null);\n const from = typeof source === \"string\" ? source : suggestionSource(source, formatDate);\n const empty = current == null || current === \"\";\n\n async function run(which, fn) {\n if (!fn || busy) return;\n setBusy(which);\n setError(null);\n let r;\n try {\n r = await fn();\n } catch (e) {\n r = { ok: false, error: e?.message ?? String(e) };\n }\n setBusy(null);\n if (r && r.ok === false) {\n setState(\"failed\");\n setError(r.error || `Couldn't ${(which === \"keep\" ? keepLabel : dropLabel).toLowerCase()} it. Try again.`);\n return;\n }\n setState(which === \"keep\" ? \"kept\" : \"dropped\");\n }\n\n if (state === \"dropped\") return null;\n const name = typeof label === \"string\" ? label.toLowerCase() : \"this\";\n return (\n <div className={cx(\"@container grid grid-cols-1 min-w-0 gap-1\", className)}>\n {showLabel && label ? (\n <p className=\"text-xs text-muted-foreground\">\n {label}\n {state === \"kept\" ? ` · ${keptLabel.toLowerCase()}` : empty ? \" · empty now\" : ` · now ${typeof current === \"string\" ? current : \"\"}`}\n </p>\n ) : null}\n <div\n role=\"group\"\n aria-label={`Suggested ${name}`}\n className={cx(\n \"grid min-w-0 gap-2 rounded-md px-3 py-2\",\n // Side by side from 22rem of its own width; under it the\n // buttons go below the value. Compact icons always fit beside.\n compact ? \"grid-cols-[minmax(0,1fr)_auto] items-center gap-3\" : \"grid-cols-1 @[22rem]:grid-cols-[minmax(0,1fr)_auto] @[22rem]:items-center @[22rem]:gap-3\",\n FRAME[state] ?? FRAME.pencil,\n )}\n >\n <div className=\"grid grid-cols-1 min-w-0 gap-0.5\">\n {compact && label ? <span className=\"text-xs text-muted-foreground\">{label}</span> : null}\n <span className=\"min-w-0 break-words text-sm font-semibold\">{value}</span>\n {from ? <span className=\"text-xs text-muted-foreground\">{from}</span> : null}\n {state === \"failed\" && error ? (\n <span role=\"alert\" className=\"text-xs text-destructive\">\n {error}\n </span>\n ) : null}\n </div>\n {state === \"kept\" ? (\n <span className=\"inline-flex items-center gap-1 text-xs font-medium text-success\">\n <Icon name=\"check\" size={14} />\n {keptLabel}\n </span>\n ) : compact ? (\n <span className=\"flex items-center gap-1\">\n <IconButton icon=\"check\" size=\"sm\" variant=\"secondary\" label={`${keepLabel} ${name}`} disabled={Boolean(busy)} onClick={() => run(\"keep\", onKeep)} />\n <IconButton icon=\"x\" size=\"sm\" label={`${dropLabel} ${name}`} disabled={Boolean(busy)} onClick={() => run(\"drop\", onDrop)} />\n </span>\n ) : (\n <span className=\"flex flex-wrap items-center gap-1\">\n <Button size=\"sm\" variant=\"primary\" loading={busy === \"keep\"} disabled={Boolean(busy)} onClick={() => run(\"keep\", onKeep)} aria-label={`${keepLabel} ${name}`}>\n {keepLabel}\n </Button>\n <Button size=\"sm\" variant=\"quiet\" loading={busy === \"drop\"} disabled={Boolean(busy)} onClick={() => run(\"drop\", onDrop)} aria-label={`${dropLabel} ${name}`}>\n {dropLabel}\n </Button>\n </span>\n )}\n </div>\n </div>\n );\n}\n\n/** The header for several suggestions on one record: what was found and\n * where from, Keep all and Drop all. */\nexport function SuggestionGroup({ title, description, count, onKeepAll, onDropAll, keepAllLabel, dropAllLabel = \"Drop all\", className, children }) {\n const [busy, setBusy] = useState(null);\n const [error, setError] = useState(null);\n async function run(which, fn) {\n if (!fn || busy) return;\n setBusy(which);\n setError(null);\n let r;\n try {\n r = await fn();\n } catch (e) {\n r = { ok: false, error: e?.message ?? String(e) };\n }\n setBusy(null);\n if (r && r.ok === false) setError(r.error || \"That didn't work. Try again.\");\n }\n return (\n <div className={cx(\"grid grid-cols-1 min-w-0 gap-3\", className)}>\n <div role=\"status\" className={cx(\"flex min-w-0 flex-wrap items-center gap-3 rounded-lg px-4 py-3\", FRAME.pencil)}>\n <Icon name=\"sparkles\" className=\"text-muted-foreground\" />\n <div className=\"grid min-w-0 flex-1 basis-56 grid-cols-1 gap-0.5\">\n <p className=\"text-sm font-semibold\">{title}</p>\n {description ? <p className=\"text-sm text-muted-foreground\">{description}</p> : null}\n {error ? (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {error}\n </p>\n ) : null}\n </div>\n <span className=\"flex flex-wrap items-center gap-2\">\n {onKeepAll ? (\n <Button size=\"sm\" variant=\"primary\" loading={busy === \"keep\"} disabled={Boolean(busy)} onClick={() => run(\"keep\", onKeepAll)}>\n {keepAllLabel ?? (count ? `Keep all ${count}` : \"Keep all\")}\n </Button>\n ) : null}\n {onDropAll ? (\n <Button size=\"sm\" variant=\"quiet\" loading={busy === \"drop\"} disabled={Boolean(busy)} onClick={() => run(\"drop\", onDropAll)}>\n {dropAllLabel}\n </Button>\n ) : null}\n </span>\n </div>\n {children}\n </div>\n );\n}\n\n/**\n * Found in place: the proposed value inside the cell or field it would\n * fill, as a small dashed chip in the agent's tone, with where it came\n * from and a tick to keep and a cross to drop (0.7.0, the CRM's v2\n * signature). Same callbacks as FieldSuggestion.\n *\n * value the proposed value\n * source { from, at } or a string (\"her email signature, Sat 12 Sep\")\n * label the field's name, for the buttons (\"Keep job title\")\n * onKeep() · onDrop() async → { ok } | { ok: false, error }\n * keepLabel · dropLabel the verbs the buttons say to a reader\n */\nexport function InlineSuggestion({ value, source, label, onKeep, onDrop, keepLabel = \"Keep\", dropLabel = \"Drop\", formatDate, className }) {\n const [busy, setBusy] = useState(null);\n const [state, setState] = useState(\"pencil\");\n const [error, setError] = useState(null);\n const from = typeof source === \"string\" ? source : suggestionSource(source, formatDate);\n const name = typeof label === \"string\" ? label.toLowerCase() : \"this\";\n async function run(which, fn) {\n if (!fn || busy) return;\n setBusy(which);\n setError(null);\n let r;\n try {\n r = await fn();\n } catch (e) {\n r = { ok: false, error: e?.message ?? String(e) };\n }\n setBusy(null);\n if (r && r.ok === false) {\n setState(\"failed\");\n setError(r.error || \"That didn't work. Try again.\");\n return;\n }\n setState(which === \"keep\" ? \"kept\" : \"dropped\");\n }\n if (state === \"dropped\") return null;\n return (\n <span\n role=\"group\"\n aria-label={`Suggested ${name}: ${typeof value === \"string\" ? value : \"\"}`}\n title={error ?? (from ? `Found by the agent: ${from}` : undefined)}\n className={cx(\n \"inline-flex h-[22px] min-w-0 max-w-full items-center gap-1.5 whitespace-nowrap rounded-[4px] border border-dashed pl-[7px] pr-[3px] align-middle text-[13px] text-foreground\",\n state === \"kept\" ? \"border-solid border-success\" : state === \"failed\" ? \"border-destructive\" : \"border-info\",\n className,\n )}\n >\n <span className=\"min-w-0 truncate\">{value}</span>\n {from ? <span className=\"min-w-0 truncate text-[11.5px] text-muted-foreground\">{from}</span> : null}\n {state === \"kept\" ? (\n <Icon name=\"check\" size={12} className=\"shrink-0 text-success\" label=\"Kept\" />\n ) : (\n <>\n <button\n type=\"button\"\n aria-label={`${keepLabel} ${name}`}\n disabled={Boolean(busy)}\n onClick={(e) => {\n e.stopPropagation();\n run(\"keep\", onKeep);\n }}\n className=\"grid grid-cols-1 size-[18px] shrink-0 place-items-center rounded-[3px] text-success outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50\"\n >\n <Icon name=\"check\" size={12} />\n </button>\n <button\n type=\"button\"\n aria-label={`${dropLabel} ${name}`}\n disabled={Boolean(busy)}\n onClick={(e) => {\n e.stopPropagation();\n run(\"drop\", onDrop);\n }}\n className=\"grid grid-cols-1 size-[18px] shrink-0 place-items-center rounded-[3px] text-muted-foreground outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50\"\n >\n <Icon name=\"x\" size={12} />\n </button>\n </>\n )}\n {state === \"failed\" && error ? <span className=\"sr-only\" role=\"alert\">{error}</span> : null}\n </span>\n );\n}\n\n/** \"Looking…\" in the agent's tone, where a value is still being found. */\nexport function Looking({ children = \"Looking…\", className }) {\n return (\n <span className={cx(\"inline-flex items-center gap-[5px] text-[13px] text-info motion-safe:animate-pulse\", className)}>\n <Icon name=\"sparkles\" size={12} />\n {children}\n </span>\n );\n}\n\n/**\n * A change to a span of text, as an editor's proof mark: the old words\n * struck, the new beside them, why, and where from (Writing Review's proof\n * marks; Notes, Landing Page Reviewer). Kept, the new words stand alone in\n * a solid frame; dropped, it goes.\n *\n * before the words now (struck); empty for an insertion\n * after the words proposed; empty for a cut\n * lead · tail a few words around the span, muted, so it reads in place\n * reason why, one line (\"“your” is the owner's, “you're” is “you are”\")\n * source { from, at } or a string: what it leans on (a style guide, a page)\n * onKeep() · onDrop() async → { ok } | { ok: false, error }\n * keepLabel · dropLabel · keptLabel default \"Keep\", \"Drop\", \"Kept\"\n */\nexport function TextSuggestion({\n before,\n after,\n lead,\n tail,\n reason,\n source,\n onKeep,\n onDrop,\n keepLabel = \"Keep\",\n dropLabel = \"Drop\",\n keptLabel = \"Kept\",\n formatDate,\n className,\n}) {\n const [busy, setBusy] = useState(null);\n const [state, setState] = useState(\"pencil\");\n const [error, setError] = useState(null);\n const from = typeof source === \"string\" ? source : suggestionSource(source, formatDate);\n const cut = after == null || after === \"\";\n const insert = before == null || before === \"\";\n\n async function run(which, fn) {\n if (!fn || busy) return;\n setBusy(which);\n setError(null);\n let r;\n try {\n r = await fn();\n } catch (e) {\n r = { ok: false, error: e?.message ?? String(e) };\n }\n setBusy(null);\n if (r && r.ok === false) {\n setState(\"failed\");\n setError(r.error || `Couldn't ${(which === \"keep\" ? keepLabel : dropLabel).toLowerCase()} it. Try again.`);\n return;\n }\n setState(which === \"keep\" ? \"kept\" : \"dropped\");\n }\n\n if (state === \"dropped\") return null;\n const kept = state === \"kept\";\n const what = cut ? \"Cut\" : insert ? \"Add\" : \"Change\";\n return (\n <div\n role=\"group\"\n aria-label={`Suggested ${what.toLowerCase()}${typeof after === \"string\" && after ? `: ${after}` : \"\"}`}\n className={cx(\"@container grid grid-cols-1 min-w-0 gap-2 rounded-md px-3 py-2 text-sm\", FRAME[state] ?? FRAME.pencil, className)}\n >\n <p className=\"min-w-0 break-words leading-relaxed\">\n {lead ? <span className=\"text-muted-foreground\">{lead}</span> : null}\n {kept ? (\n cut ? null : <span className=\"font-semibold\">{after}</span>\n ) : (\n <>\n {insert ? null : (\n <del className=\"text-muted-foreground decoration-foreground decoration-[1.5px]\">\n <span className=\"sr-only\">Remove: </span>\n {before}\n </del>\n )}\n {!insert && !cut ? (\n <Icon name=\"arrow-right\" size={12} className=\"mx-1 inline-block align-[-0.1em] text-muted-foreground\" />\n ) : null}\n {cut ? null : (\n <ins className=\"font-semibold no-underline\">\n <span className=\"sr-only\">Add: </span>\n {after}\n </ins>\n )}\n </>\n )}\n {tail ? <span className=\"text-muted-foreground\">{tail}</span> : null}\n </p>\n {reason && !kept ? <p className=\"text-xs text-muted-foreground\">{reason}</p> : null}\n {from && !kept ? <p className=\"text-xs text-muted-foreground\">{from}</p> : null}\n {state === \"failed\" && error ? (\n <p role=\"alert\" className=\"text-xs text-destructive\">\n {error}\n </p>\n ) : null}\n {kept ? (\n <span className=\"inline-flex items-center gap-1 text-xs font-medium text-success\">\n <Icon name=\"check\" size={14} />\n {keptLabel}\n </span>\n ) : onKeep || onDrop ? (\n <span className=\"flex flex-wrap items-center gap-1\">\n {onKeep ? (\n <Button size=\"sm\" variant=\"primary\" loading={busy === \"keep\"} disabled={Boolean(busy)} onClick={() => run(\"keep\", onKeep)}>\n {keepLabel}\n </Button>\n ) : null}\n {onDrop ? (\n <Button size=\"sm\" variant=\"quiet\" loading={busy === \"drop\"} disabled={Boolean(busy)} onClick={() => run(\"drop\", onDrop)}>\n {dropLabel}\n </Button>\n ) : null}\n </span>\n ) : null}\n </div>\n );\n}\n"
23
+ },
24
+ {
25
+ "path": "registry/blocks/suggestion/README.md",
26
+ "type": "registry:file",
27
+ "target": "@components/makersclaw/blocks/suggestion/README.md",
28
+ "content": "# Suggestion\n\nA value the agent proposes, drawn in pencil: **dashed** while it is a\nproposal, **solid** once kept. Its source is always shown, and a person\nkeeps or drops it. A proposal differs from a fact in shape, never colour\nalone.\n\nFive shapes, one idea:\n\n- **FieldSuggestion** — under a field: what it holds now (\"empty now\"),\n the proposed value, where it came from, Keep and Drop.\n- **InlineSuggestion** — found in place: a small dashed chip inside the\n cell or field it would fill, its source, a tick and a cross (CRM v2).\n- **TextSuggestion** — a span of text: the old words struck, the new\n beside them, the reason, the source (Writing Review's proof marks).\n- **Pencil** — the dashed frame for a whole proposed record: a drafted\n email, a deal, a week's plan (\"pencil to ink\", Weekly Planner).\n- **SuggestionGroup** — the head over several: \"Keep all 6\", \"Drop all\".\n\nAnd **Looking**: \"✦ Looking…\" where a value is still being found.\n\nGrown in the CRM (0.7.0) as `field-suggestion`; every export kept its\nprops. One change: a FieldSuggestion that was dropped now goes, as an\nInlineSuggestion always did.\n\n```jsx\nimport { FieldSuggestion, InlineSuggestion, TextSuggestion, Pencil, SuggestionGroup, Looking } from \"../components/blocks/suggestion\"; // a Makersclaw app (\"./blocks/suggestion\" from components/)\nimport { FieldSuggestion } from \"@/components/makersclaw/blocks/suggestion\"; // a shadcn project\n```\n\nClient components; `suggestionSource` is a plain function.\n\n## Which hook feeds it\n\nNone of its own. The proposals are app data the agent wrote (a\n`suggestions` table, a column of proposed values). **A keep runs the\napp's own declared action** (`runAction`, lib/actions), so a keep is the\nsame write the agent would make, and the door's rules hold for it.\n\n## The verbs are props\n\nEach app says it its way: Keep/Drop (CRM), Apply/Dismiss (Data Tables),\nAccept/Decline (Writing Review). Every shape takes `keepLabel` and\n`dropLabel`; FieldSuggestion and TextSuggestion also take `keptLabel`\n(\"Applied\").\n\n## Props\n\n### FieldSuggestion\n\n- `label` — the field's name (\"Job title\"). It also names the group for a\n reader (\"Suggested job title\") and the buttons (\"Keep job title\").\n- `current` — what the field holds now; empty → \"empty now\".\n- `value` — the proposed value (text or a node).\n- `source` — `{ from, at }` (\"her email signature\", \"2026-09-12\") or a\n string.\n- `onKeep()` · `onDrop()` — async, answer `{ ok: true }` or `{ ok: false,\n error }` (a throw counts as failed). The frame spins while it runs,\n turns solid when kept, goes when dropped, and says why when it fails.\n- `compact` — icon buttons at the row's end, the label inside the frame:\n for a list of several.\n- `showLabel` — `false` when you draw the field's label above it.\n- `keepLabel` · `dropLabel` · `keptLabel` — default \"Keep\", \"Drop\", \"Kept\".\n- `formatDate(date)` — how `source.at` is worded (default \"Sat 12 Sep\").\n\nUnder 22rem of its own width the buttons go below the value.\n\n### InlineSuggestion\n\n- `value`, `source`, `label` (names the buttons for a reader),\n `onKeep()` · `onDrop()`, `keepLabel` · `dropLabel`, `formatDate`.\n\nA dashed chip in the agent's tone (`border-info`); kept, solid with a\ntick; dropped, gone. For a table cell or a record's field list.\n\n### TextSuggestion\n\n- `before` — the words now, struck. Empty for an insertion.\n- `after` — the words proposed. Empty for a cut.\n- `lead` · `tail` — a few words around the span, muted, so it reads in\n place (\"…sorry about \", \" order\").\n- `reason` — why, one line.\n- `source` — `{ from, at }` or a string: what it leans on (the style\n guide, a page).\n- `onKeep()` · `onDrop()` — async `{ ok }`.\n- `keepLabel` · `dropLabel` · `keptLabel`.\n\nA reader hears \"Remove: … Add: …\" for the struck and new words.\n\n### Pencil\n\n- `kicker` — the small line above (\"A NEW DEAL\").\n- `title` — what it is (\"Crumb & Co: 22 shops\").\n- `reason` — why the agent proposes it.\n- `children` — your content between the title and the reason.\n- `actions` — your buttons, with your verbs (\"Make the deal\", \"Drop\").\n- `state` — `pencil` (default) · `kept` (solid) · `failed` (with\n `error`).\n- `label` — the region's name for a reader.\n\n### SuggestionGroup\n\n- `title` — \"3 details found for Sofia: job title, LinkedIn and city\".\n- `description` — where they came from; that nothing changes until kept.\n- `count` — for \"Keep all 3\" (or `keepAllLabel`). `dropAllLabel` —\n default \"Drop all\".\n- `onKeepAll()` · `onDropAll()` — async `{ ok }`; a failure shows under\n the title.\n- `children` — the suggestions under it.\n\n### Looking\n\n`children` replaces \"Looking…\". Pulses, and stays still under reduced\nmotion.\n\n### suggestionSource({ from, at }, format?)\n\n\"her email signature, Sat 12 Sep\".\n\n## Who may do what\n\nThe block shows the buttons it is given. Give `onKeep`/`onDrop` only to a\nmember who may make that write; the declared action's door refuses anyone\nelse anyway.\n\n## Never\n\n- Never write the value yourself on render: nothing changes until a\n person keeps it.\n- Never draw a proposal solid, or a kept value dashed.\n- Never hide the source.\n\n## Example\n\nA contact's found details, kept through the app's declared actions.\n\n```jsx\n\"use client\";\nimport { runAction } from \"../lib/actions\";\nimport { FieldSuggestion, SuggestionGroup } from \"../components/blocks/suggestion\";\n\nexport function FoundDetails({ person, suggestions, reload }) {\n const done = (r) => {\n if (r.ok) reload();\n return r;\n };\n return (\n <SuggestionGroup\n title={`${suggestions.length} details found for ${person.first_name}`}\n description=\"From her email signature and a web search. Nothing changes until you keep them.\"\n count={suggestions.length}\n onKeepAll={async () => done(await runAction({ name: \"keep_details\", args: { person: person.id } }))}\n onDropAll={async () => done(await runAction({ name: \"drop_details\", args: { person: person.id } }))}\n >\n {suggestions.map((s) => (\n <FieldSuggestion\n key={s.id}\n label={s.label}\n current={person[s.column]}\n value={s.value}\n source={{ from: s.from, at: s.at }}\n onKeep={async () => done(await runAction({ name: \"keep_detail\", args: { id: s.id } }))}\n onDrop={async () => done(await runAction({ name: \"drop_detail\", args: { id: s.id } }))}\n />\n ))}\n </SuggestionGroup>\n );\n}\n```\n\nIn a server-mode app the same calls are `loadRows` in a server surface and the Server Actions of `lib/actions`.\n"
29
+ }
30
+ ],
31
+ "categories": [
32
+ "suggestion",
33
+ "proposal",
34
+ "keep",
35
+ "drop",
36
+ "accept",
37
+ "decline",
38
+ "apply",
39
+ "dismiss",
40
+ "pencil",
41
+ "field",
42
+ "inline",
43
+ "found in place",
44
+ "proofread",
45
+ "redline",
46
+ "diff",
47
+ "enrichment",
48
+ "source",
49
+ "review"
50
+ ],
51
+ "docs": "Installed to components/makersclaw/blocks/suggestion. Import: import { FieldSuggestion, InlineSuggestion, TextSuggestion, Pencil, SuggestionGroup, Looking, suggestionSource } from \"@/components/makersclaw/blocks/suggestion\". Props and an example: components/makersclaw/blocks/suggestion/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
52
+ "meta": {
53
+ "makersclaw": {
54
+ "version": "0.8.1",
55
+ "useWhen": "The agent proposes values or changes a person keeps or drops: a CRM filling in a contact, a cleaner value in a table cell, a priority on an issue, a proofread sentence, a drafted plan for the week, a batch of moves on a board. For a whole column of answers across many records use agent-column; for one ask's finished changes with an undo use agent-changes."
56
+ }
57
+ }
58
+ }
package/r/sum-bar.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "sum-bar",
4
+ "type": "registry:block",
5
+ "title": "SumBar",
6
+ "description": "A total with its parts cut out of it, drawn to scale. The bar runs from 0 to the total (100 by default); what is left is solid with its number, each part's cost is a hatched block cut from the top end downward in the tone of its part (warning, danger, info, neutral) with its cost written in it and its name under it, and a part can be pressed. When a rule holds the result below the sum, the stretch between them is dotted and says so. Posts stand on the bar where a rule applies (a cap at 74, a cap at 49), each with a flag above. Coloured bands under the bar name the ranges (off track under 50, at risk to 75, on track). Under it the sum is written out so no number is taken on trust: \"100 − 22 − 25 − 5 − 8 − 0 − 5 = 35\", or \"100 − 44 = 56, held at 49\". Positions are percentages, so it draws the same on the server; a screen reader hears the whole bar as one sentence; loading, failed and nothing-taken-off are drawn; the sums (resultOf, cutsOf, postsOf, bandsOf, receiptOf, sumWords) are exported as plain functions.",
7
+ "registryDependencies": [
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/core.json"
9
+ ],
10
+ "dependencies": [],
11
+ "files": [
12
+ {
13
+ "path": "registry/blocks/sum-bar/index.js",
14
+ "type": "registry:component",
15
+ "target": "@components/makersclaw/blocks/sum-bar/index.js",
16
+ "content": "// The SumBar block — `makersclaw add sum-bar`. Fixed: compose it through its\n// props (README.md beside this file). The model's helpers are plain\n// functions; they work on the server too.\nexport { SumBar } from \"./sum-bar\";\nexport { bandsOf, costOf, cutsOf, labelledCuts, lostOf, postsOf, receiptOf, resultOf, sumWords, totalOf } from \"./sum-model\";\n"
17
+ },
18
+ {
19
+ "path": "registry/blocks/sum-bar/sum-bar.jsx",
20
+ "type": "registry:component",
21
+ "target": "@components/makersclaw/blocks/sum-bar/sum-bar.jsx",
22
+ "content": "\"use client\";\n\nimport { Button, Notice, Skeleton, cx } from \"../../ui\";\nimport { bandsOf, cutsOf, labelledCuts, postsOf, receiptOf, resultOf, sumWords } from \"./sum-model\";\n\n// A total with its parts cut out of it. The bar runs from 0 to the total;\n// what is left is solid, each part's cost is a hatched block cut from the\n// top end downward, and a post stands where a rule holds the result down (a\n// cap). Under it, the sum written out so no number is taken on trust.\n//\n// Props in, one callback out (`onSelect`); the block imports only React and\n// the kit, reads no data and works nothing out beyond placing what it is\n// given. Positions are percentages, so the server draws what the browser\n// draws. README.md beside this file lists every prop.\n\n// Literal class names, so Tailwind sees every one of them.\nconst CUT = {\n neutral: \"border-border text-muted-foreground bg-muted\",\n info: \"border-info text-info bg-info/10\",\n warning: \"border-warning text-warning bg-warning/10\",\n danger: \"border-destructive text-destructive bg-destructive/10\",\n};\nconst BAND = { success: \"bg-success\", warning: \"bg-warning\", danger: \"bg-destructive\", info: \"bg-info\", neutral: \"bg-muted-foreground\" };\nconst SIZE = { sm: \"h-6\", md: \"h-9\", lg: \"h-12\" };\n\nconst HATCH = { backgroundImage: \"repeating-linear-gradient(135deg, currentColor 0 1px, transparent 1px 5px)\" };\nconst DOTS = { backgroundImage: \"repeating-linear-gradient(90deg, currentColor 0 2px, transparent 2px 6px)\" };\n\nconst say = (n) => (Number.isInteger(n) ? String(n) : String(Math.round(n * 1000) / 1000));\n\n/**\n * The bar.\n *\n * Props: `total` (100), `parts` `[{ id, label, cost, tone?, note? }]` (taken\n * off in the order given, from the top end), `result` (the number after a\n * rule held it down; default total minus the costs), `posts` `[{ at, label,\n * tone? }]`, `bands` `[{ from, to, tone, label? }]`, `selected`, `onSelect(part)`,\n * `size` (sm | md | lg), `names` (the names under the cuts, default true),\n * `legend` (a list of the parts under the bar), `receipt` (the written sum,\n * default true), `unit`, `noun`, `label`, `status`, `error`, `onRetry`,\n * `className`.\n */\nexport function SumBar({\n total = 100,\n parts,\n result,\n posts,\n bands,\n selected,\n onSelect,\n size = \"md\",\n names = true,\n legend = false,\n receipt = true,\n unit = \"\",\n noun = \"point\",\n label = \"Score sheet\",\n status = \"ready\",\n error,\n onRetry,\n className,\n}) {\n if (status === \"loading\") {\n return (\n <div role=\"status\" aria-label={`${label}, loading`} className={cx(\"grid gap-2\", className)}>\n <Skeleton className={cx(\"w-full\", SIZE[size] ?? SIZE.md)} />\n <Skeleton className=\"h-3 w-2/3\" />\n </div>\n );\n }\n if (status === \"failed\") {\n return (\n <Notice\n tone=\"danger\"\n className={className}\n action={\n onRetry ? (\n <Button size=\"sm\" onClick={onRetry}>\n Try again\n </Button>\n ) : undefined\n }\n >\n {error || \"The sum could not be read.\"}\n </Notice>\n );\n }\n\n const r = resultOf({ total, parts, result });\n const cuts = cutsOf({ total, parts });\n const pins = postsOf({ total: r.total, posts });\n const strips = bandsOf({ total: r.total, bands });\n const named = names ? labelledCuts(cuts) : [];\n const keptPct = Math.round((Math.min(r.kept, r.result) / r.total) * 100000) / 1000;\n const resultPct = Math.round((r.result / r.total) * 100000) / 1000;\n const sum = receiptOf({ total, parts, result, unit });\n const inside = resultPct >= 12;\n const words = sumWords({ total, parts, result, posts, noun });\n\n return (\n <div role=\"group\" aria-label={label} className={cx(\"@container grid min-w-0 gap-2\", className)}>\n <div className=\"relative min-w-0 pt-6\">\n {pins.map((p) => (\n <span\n key={`post-label-${p.index}`}\n aria-hidden=\"true\"\n className={cx(\"absolute top-0 left-(--at) -translate-x-1/2 whitespace-nowrap text-[11px] font-semibold leading-none\", p.tone === \"danger\" ? \"text-destructive\" : \"text-muted-foreground\")}\n style={{ \"--at\": `${p.pct}%` }}\n >\n {p.label}\n </span>\n ))}\n <div className={cx(\"relative overflow-hidden rounded-[4px] border border-border bg-muted\", SIZE[size] ?? SIZE.md)} role=\"img\" aria-label={words}>\n {resultPct > 0 ? (\n <span aria-hidden=\"true\" className=\"absolute inset-y-0 left-0 w-(--w) bg-foreground\" style={{ \"--w\": `${Math.min(keptPct, resultPct)}%` }} />\n ) : null}\n {r.held > 0 ? (\n <span\n aria-hidden=\"true\"\n title={`Held down by a rule: ${say(r.kept)} on the sum, ${say(r.result)} after it`}\n className=\"absolute inset-y-0 left-(--at) w-(--width) text-muted-foreground\"\n style={{ ...DOTS, \"--at\": `${resultPct}%`, \"--width\": `${Math.round((r.held / r.total) * 100000) / 1000}%` }}\n />\n ) : null}\n {inside ? (\n <span aria-hidden=\"true\" className=\"absolute inset-y-0 left-2 flex items-center text-sm font-semibold tabular-nums text-background\">\n {say(r.result)}\n </span>\n ) : null}\n {cuts\n .filter((c) => c.cut)\n .map((c) => {\n const tone = CUT[c.tone] ?? CUT.neutral;\n const on = selected != null && c.id === selected;\n const className = cx(\"absolute inset-y-0 left-(--at) w-(--width) overflow-hidden border-x outline-none focus-visible:ring-2 focus-visible:ring-ring\", tone, on && \"ring-2 ring-ring\");\n const style = { \"--at\": `${c.leftPct}%`, \"--width\": `${c.widthPct}%` };\n const inner = (\n <>\n <span aria-hidden=\"true\" className=\"absolute inset-0 opacity-60\" style={HATCH} />\n {c.widthPct >= 5 ? <span className=\"relative flex h-full items-center justify-center text-[11px] font-semibold tabular-nums text-foreground\">−{say(c.cost)}</span> : null}\n </>\n );\n return onSelect ? (\n <button key={c.id ?? c.index} type=\"button\" aria-label={`${c.label ?? \"Part\"}, took ${say(c.cost)}`} aria-pressed={on} title={`${c.label ?? \"Part\"} took ${say(c.cost)}`} className={className} style={style} onClick={() => onSelect(c)}>\n {inner}\n </button>\n ) : (\n <span key={c.id ?? c.index} title={`${c.label ?? \"Part\"} took ${say(c.cost)}`} className={className} style={style}>\n {inner}\n </span>\n );\n })}\n {pins.map((p) => (\n <span key={`post-${p.index}`} aria-hidden=\"true\" className={cx(\"absolute inset-y-0 left-(--at) w-0 border-l-2 border-dashed\", p.tone === \"danger\" ? \"border-destructive\" : \"border-muted-foreground\")} style={{ \"--at\": `${p.pct}%` }} />\n ))}\n {!inside && resultPct > 0 ? (\n <span aria-hidden=\"true\" className=\"absolute inset-y-0 left-(--at) ml-1.5 flex items-center text-sm font-semibold tabular-nums\" style={{ \"--at\": `${resultPct}%` }}>\n {say(r.result)}\n </span>\n ) : null}\n </div>\n {strips.length ? (\n <div className=\"relative mt-1 h-1.5 overflow-hidden rounded-[2px]\" aria-hidden=\"true\">\n {strips.map((b) => (\n <span key={b.index} className={cx(\"absolute inset-y-0 left-(--at) w-(--width)\", BAND[b.tone] ?? BAND.neutral)} style={{ \"--at\": `${b.leftPct}%`, \"--width\": `${b.widthPct}%` }} />\n ))}\n </div>\n ) : null}\n {strips.some((b) => b.label) ? (\n <div className=\"relative mt-1 h-4 text-[11px] text-muted-foreground\" aria-hidden=\"true\">\n {strips.map((b) =>\n b.label ? (\n <span key={b.index} className=\"absolute top-0 left-(--at) -translate-x-1/2 whitespace-nowrap\" style={{ \"--at\": `${b.leftPct + b.widthPct / 2}%` }}>\n {b.label}\n </span>\n ) : null,\n )}\n </div>\n ) : null}\n {named.length ? (\n <div className=\"relative mt-1 hidden h-4 text-[11px] text-muted-foreground @lg:block\" aria-hidden=\"true\">\n {named.map((c) => (\n <span key={c.id ?? c.index} className=\"absolute top-0 left-(--at) -translate-x-1/2 whitespace-nowrap\" style={{ \"--at\": `${c.leftPct + c.widthPct / 2}%` }}>\n {c.label}\n </span>\n ))}\n </div>\n ) : null}\n </div>\n {legend && cuts.length ? (\n <ul className=\"m-0 grid list-none gap-1 p-0 text-xs @md:grid-cols-2\">\n {cuts.map((c) => (\n <li key={c.id ?? c.index} className=\"flex min-w-0 items-baseline gap-2\">\n <span className=\"truncate\">{c.label}</span>\n <span className=\"ml-auto shrink-0 tabular-nums text-muted-foreground\">{c.cost > 0 ? `−${say(c.cost)}` : \"0\"}</span>\n </li>\n ))}\n </ul>\n ) : null}\n {receipt ? (\n <p className=\"m-0 text-xs tabular-nums text-muted-foreground\">\n <span className=\"font-medium text-foreground\">{sum.text}</span>\n {sum.held > 0 ? <span> · a rule holds it down by {say(sum.held)}</span> : null}\n {sum.raised > 0 ? <span> · a rule lifts it by {say(sum.raised)}</span> : null}\n </p>\n ) : null}\n </div>\n );\n}\n"
23
+ },
24
+ {
25
+ "path": "registry/blocks/sum-bar/sum-model.js",
26
+ "type": "registry:component",
27
+ "target": "@components/makersclaw/blocks/sum-bar/sum-model.js",
28
+ "content": "// sum-bar: the arithmetic. Plain functions, no React, no clock: they work on\n// the server and in a test.\n//\n// A SUM starts at a total (100) and takes costs off it, one per part. What is\n// left is the result. A rule may hold the result down (a cap): then the result\n// is lower than total minus the costs, and the stretch between the two is\n// \"held\". The block draws what the app has already worked out; these helpers\n// only place it and say it.\n\n/** A cost: a finite number, never below 0. Anything else counts as 0. */\nexport function costOf(value) {\n const n = typeof value === \"number\" ? value : typeof value === \"string\" && value.trim() !== \"\" ? Number(value) : NaN;\n return Number.isFinite(n) && n > 0 ? n : 0;\n}\n\nconst round = (n) => Math.round(n * 1000) / 1000;\nconst clampPct = (n) => Math.min(100, Math.max(0, n));\n\n/** The total as a positive number (default 100). */\nexport function totalOf(total) {\n const n = Number(total);\n return Number.isFinite(n) && n > 0 ? n : 100;\n}\n\n/** Everything the parts cost, together. */\nexport function lostOf(parts) {\n return round((parts ?? []).reduce((sum, p) => sum + costOf(p?.cost), 0));\n}\n\n/**\n * What is left once the costs are off, and what the result is:\n * `kept` = total minus the costs (never below 0), `result` = the app's own\n * number when it gives one (a cap held it down), else `kept`.\n * `held` is how far a rule pushed the result below `kept`.\n */\nexport function resultOf({ total, parts, result }) {\n const whole = totalOf(total);\n const lost = lostOf(parts);\n const kept = Math.max(0, round(whole - lost));\n const given = typeof result === \"number\" && Number.isFinite(result) ? Math.min(Math.max(result, 0), whole) : null;\n const final = given == null ? kept : round(given);\n return { total: whole, lost, kept, result: final, held: final < kept ? round(kept - final) : 0, raised: final > kept ? round(final - kept) : 0 };\n}\n\n/**\n * Each part's place on the bar. The costs are cut out from the total\n * downward, in the order the parts are given: the first part sits at the top\n * end. A part that would run below 0 is cut short there. Percentages of the\n * total.\n */\nexport function cutsOf({ total, parts }) {\n const whole = totalOf(total);\n let top = whole;\n const out = [];\n for (const [index, p] of (parts ?? []).entries()) {\n const cost = costOf(p?.cost);\n const low = Math.max(0, top - cost);\n out.push({\n ...p,\n index,\n cost,\n from: round(low),\n to: round(top),\n leftPct: round(clampPct((low / whole) * 100)),\n widthPct: round(clampPct(((top - low) / whole) * 100)),\n cut: cost > 0,\n });\n top = low;\n }\n return out;\n}\n\n/** A post's place (a cap, a threshold) as a percentage. Posts out of range are dropped. */\nexport function postsOf({ total, posts }) {\n const whole = totalOf(total);\n return (posts ?? [])\n .map((p, index) => ({ ...p, index, at: Number(p?.at) }))\n .filter((p) => Number.isFinite(p.at) && p.at >= 0 && p.at <= whole)\n .map((p) => ({ ...p, pct: round(clampPct((p.at / whole) * 100)) }));\n}\n\n/** The coloured bands under the bar (off track, at risk, on track), as percentages. */\nexport function bandsOf({ total, bands }) {\n const whole = totalOf(total);\n return (bands ?? [])\n .map((b, index) => ({ ...b, index, from: Number(b?.from), to: Number(b?.to) }))\n .filter((b) => Number.isFinite(b.from) && Number.isFinite(b.to) && b.to > b.from)\n .map((b) => {\n const from = Math.max(0, b.from);\n const to = Math.min(whole, b.to);\n return { ...b, leftPct: round(clampPct((from / whole) * 100)), widthPct: round(clampPct(((to - from) / whole) * 100)) };\n })\n .filter((b) => b.widthPct > 0);\n}\n\nconst num = (n) => (Number.isInteger(n) ? String(n) : String(round(n)));\n\n/**\n * The receipt, as a sum anyone can check: \"100 − 22 − 25 − 5 − 8 − 0 − 5 = 35\".\n * Every part is a term, a part that cost nothing included. When a rule held\n * the result down: \"100 − 44 = 56, held at 49\".\n */\nexport function receiptOf({ total, parts, result, unit = \"\" }) {\n const r = resultOf({ total, parts, result });\n const list = parts ?? [];\n const terms = list.map((p) => ({ id: p?.id ?? p?.label, label: p?.label ?? \"\", cost: costOf(p?.cost) }));\n const sum = [num(r.total), ...terms.map((t) => `− ${num(t.cost)}`)].join(\" \");\n const text = r.held > 0 ? `${r.total} − ${num(r.lost)} = ${num(r.kept)}, held at ${num(r.result)}` : list.length ? `${sum} = ${num(r.result)}` : `${num(r.total)} = ${num(r.result)}`;\n return { ...r, terms, text: unit ? `${text} ${unit}` : text };\n}\n\n/** The whole bar in a sentence for a screen reader. */\nexport function sumWords({ total, parts, result, posts, noun = \"point\" }) {\n const r = resultOf({ total, parts, result });\n const list = (parts ?? []).filter((p) => costOf(p?.cost) > 0);\n const plural = (n) => (n === 1 ? noun : `${noun}s`);\n const took = list.length ? ` ${list.map((p) => `${p.label ?? \"A part\"} took ${num(costOf(p.cost))}`).join(\", \")}.` : \" Nothing was taken off.\";\n const held = r.held > 0 ? ` A rule holds it at ${num(r.result)} where the sum is ${num(r.kept)}.` : \"\";\n const pins = (posts ?? []).filter((p) => p?.label).map((p) => `${p.label} at ${num(Number(p.at))}`);\n return `${num(r.result)} of ${num(r.total)} ${plural(r.total)}.${took}${held}${pins.length ? ` Posts: ${pins.join(\", \")}.` : \"\"}`;\n}\n\n/** Which of the parts to show a name under, when the bar is too short for all of them. */\nexport function labelledCuts(cuts, minPct = 7) {\n return cuts.filter((c) => c.cut && c.widthPct >= minPct);\n}\n"
29
+ },
30
+ {
31
+ "path": "registry/blocks/sum-bar/README.md",
32
+ "type": "registry:file",
33
+ "target": "@components/makersclaw/blocks/sum-bar/README.md",
34
+ "content": "# SumBar\n\nA total with its parts cut out of it, so a number can be checked, not trusted.\n\nA health score of 35 says little. \"100, less 22 for the schedule, 25 for the\nbudget, 5 late, 8 blocked, 5 quiet client\" says everything. This block draws\nthat sum to scale:\n\n- **The bar** runs from 0 to the total (100). What is left is solid, with its\n number in it.\n- **Each part is a hatched block cut from the top end downward**, in the tone\n of its part (`warning`, `danger`, `info`, `neutral`), its cost written in it\n and its name under it. A part can be pressed.\n- **A rule that holds the result down** (a cap) is a **post** standing on the\n bar with a flag above it. When the cap bites, the stretch between the sum\n and the result is dotted and the receipt says so.\n- **Bands** under the bar name the ranges (off track, at risk, on track).\n- **The receipt** writes the sum out: `100 − 22 − 25 − 5 − 8 − 0 − 5 = 35`,\n or `100 − 44 = 56, held at 49`.\n\nIt draws a result the app has already worked out. It scores nothing and\nchanges no number. For a total split into shares use the kit's `Distribution`;\nfor progress against a clock use `pace-bar`.\n\nBorn in a project monitor's score sheet (\"57% done, 88% of the time gone\" is\n`pace-bar`; the 35 it costs is this). Fits any app that scores out of 100 and\nmust show its working.\n\n```jsx\nimport { SumBar, receiptOf, resultOf, sumWords } from \"../components/blocks/sum-bar\"; // a Makersclaw app (\"./blocks/sum-bar\" from components/)\nimport { SumBar } from \"@/components/makersclaw/blocks/sum-bar\"; // a shadcn project\n```\n\nA client component. No other block, no npm package. Positions are percentages\nof the total, so a server render and a browser render agree.\n\n## Props\n\n- `total`: the whole (default `100`).\n- `parts`: `[{ id, label, cost, tone, note }]`, taken off in the order given,\n from the top end of the bar. `cost` is a number (0 or more; anything else\n counts as 0). A part that costs nothing is no block on the bar but is a term\n in the receipt. `tone`: `neutral` (default), `info`, `warning`, `danger`.\n- `result`: the number after a rule held it down. Left out, it is the total\n less the costs. Lower than that, the difference is \"held\" (dotted).\n- `posts`: `[{ at, label, tone }]`: a dashed post at `at` (0 to the total),\n with a flag above. `tone: \"danger\"` draws it in the danger colour.\n- `bands`: `[{ from, to, tone, label }]`: a thin coloured strip under the bar\n and a label centred under each band. `tone`: `success`, `warning`, `danger`,\n `info`, `neutral`.\n- `selected`, `onSelect(part)`: with `onSelect` every cut is a button; the\n selected one is ringed. Without it the cuts are read-only.\n- `size`: `sm` (24 px), `md` (36 px, default), `lg` (48 px).\n- `names`: the names under the cuts (default `true`). They show from 32rem of\n the block's own width, and only under cuts wide enough to hold a name.\n- `legend`: a list of every part and its cost under the bar (default `false`).\n- `receipt`: the written sum (default `true`).\n- `unit`: appended to the receipt (`\"points\"`). `noun`: what a screen reader\n calls one unit (default `\"point\"`).\n- `label`: what a screen reader calls the whole (default \"Score sheet\").\n- `status`: `ready` (default), `loading` (a skeleton), `failed` (a danger\n notice with `error` and a Try again when `onRetry` is given).\n- `className`: layout around it. Never colour.\n\n## The sums (plain functions, no React)\n\n- `resultOf({ total, parts, result })` → `{ total, lost, kept, result, held, raised }`\n- `cutsOf({ total, parts })` → each part with `from`, `to`, `leftPct`, `widthPct`, `cut`\n- `postsOf({ total, posts })`, `bandsOf({ total, bands })`: placed, out-of-range ones dropped\n- `receiptOf({ total, parts, result, unit })` → `{ …resultOf, terms, text }`\n- `sumWords({ total, parts, result, posts, noun })`: the whole bar in a sentence\n- `costOf(value)`, `totalOf(total)`, `lostOf(parts)`, `labelledCuts(cuts, minPct)`\n\n## Example\n\n```jsx\n// A project's score: 100 less what each signal cost, held at 49 by two reds.\n<SumBar\n label=\"Website rebuild, score sheet\"\n parts={[\n { id: \"schedule\", label: \"Schedule\", cost: 22, tone: \"danger\" },\n { id: \"budget\", label: \"Budget\", cost: 25, tone: \"danger\" },\n { id: \"late\", label: \"Late work\", cost: 5, tone: \"warning\" },\n { id: \"blocked\", label: \"Blocked\", cost: 8, tone: \"warning\" },\n { id: \"activity\", label: \"Activity\", cost: 0 },\n { id: \"client\", label: \"Client\", cost: 5, tone: \"warning\" },\n ]}\n result={35}\n posts={[{ at: 74, label: \"cap 74 · one red\" }, { at: 49, label: \"cap 49 · two reds\" }]}\n bands={[\n { from: 0, to: 50, tone: \"danger\", label: \"off track\" },\n { from: 50, to: 75, tone: \"warning\", label: \"at risk\" },\n { from: 75, to: 100, tone: \"success\", label: \"on track\" },\n ]}\n unit=\"points\"\n onSelect={(part) => scrollToSignal(part.id)}\n/>\n```\n\n## States drawn in the demo\n\n- **Nothing taken off**: a full solid bar, the receipt `100 = 100`.\n- **One part, many parts**, a part that costs nothing (in the receipt, not on\n the bar).\n- **Held by a rule**: the sum above the result, the dotted stretch, the receipt\n \"held at 49\".\n- **Posts and bands**; **pressable** (a selected part, arrow keys by Tab).\n- **Very small cuts** (under 5% wide: no cost written in the block, still in the\n tooltip and the receipt).\n- **Odd input**: a negative cost, a cost past the total, text for a cost, a\n zero total.\n- **Narrow** (a 320 px container: names under the cuts give way to the legend\n you ask for), **wide**, **loading**, **failed**.\n\n## Notes for the app that places it\n\n- Colour is a signal. Tone a cut `danger` or `warning` only when its signal is\n in the red or a warning; a neutral cut is a cost that is not a problem.\n- Never rely on tone alone: the cost is written in the cut, in the tooltip and\n in the receipt.\n- Put the same numbers in words beside it (the rows of the sum). The bar is a\n picture of them.\n"
35
+ }
36
+ ],
37
+ "categories": [
38
+ "sum",
39
+ "score",
40
+ "total",
41
+ "points",
42
+ "cost",
43
+ "deduction",
44
+ "receipt",
45
+ "arithmetic",
46
+ "cap",
47
+ "ceiling",
48
+ "threshold",
49
+ "health",
50
+ "risk",
51
+ "budget",
52
+ "breakdown",
53
+ "waterfall",
54
+ "bar",
55
+ "hatched"
56
+ ],
57
+ "docs": "Installed to components/makersclaw/blocks/sum-bar. Import: import { SumBar, bandsOf, costOf, cutsOf, labelledCuts, lostOf, postsOf, receiptOf, resultOf, sumWords, totalOf } from \"@/components/makersclaw/blocks/sum-bar\". Props and an example: components/makersclaw/blocks/sum-bar/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
58
+ "meta": {
59
+ "makersclaw": {
60
+ "version": "0.8.1",
61
+ "useWhen": "Any screen where a number is a total with things taken off it and the member should be able to check the arithmetic: a health score of 100 points less what each signal cost, a risk score, a quote's price less its discounts, a budget less what each line spent, a credit balance less each charge, a grade out of 100 less each lost mark. It draws a result the app has already worked out and changes no number. Not a total split into shares (Distribution, breakdown), progress against a clock (pace-bar), a meter against a limit (Meter), or a time series (chart)."
62
+ }
63
+ }
64
+ }
package/r/task-list.json CHANGED
@@ -5,8 +5,8 @@
5
5
  "title": "Task list",
6
6
  "description": "The List view of work, like ClickUp's or Linear's: tasks under headings that fold (group by status, assignee, priority, project, due date or any field), a round check to complete each, the title edited in place, subtasks indented under their parent with their own fold, the fields you choose (assignees, due date, priority, tags, project, estimate) as inline pickers, a quick-add row at the end of every group, drag to reorder and to move between groups (saving the new status, assignee or due date), multi-select with a bulk bar (status, assign, due, priority, delete with undo), a toolbar with search, filter chips, group by, sort and fields, and friendly empty states with starter templates. One async onChange saves every change; failures roll back with a notice.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.7.0/r/core.json",
9
- "https://cdn.jsdelivr.net/npm/makersclaw@0.7.0/r/task-model.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/core.json",
9
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/task-model.json"
10
10
  ],
11
11
  "dependencies": [],
12
12
  "files": [
@@ -56,7 +56,7 @@
56
56
  "docs": "Installed to components/makersclaw/blocks/task-list. Import: import { TaskList } from \"@/components/makersclaw/blocks/task-list\". Props and an example: components/makersclaw/blocks/task-list/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
57
57
  "meta": {
58
58
  "makersclaw": {
59
- "version": "0.7.0",
59
+ "version": "0.8.1",
60
60
  "useWhen": "A screen that lists work to get done and moves it along: a team's tasks, a launch checklist, a sprint, a personal to-do list, onboarding steps, content to publish. Not for records that are not work (data-table), for stage columns side by side (board), or for dates on a grid (calendar)."
61
61
  }
62
62
  }
package/r/task-model.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "title": "Task model",
6
6
  "description": "The shared work-item model every task view reads: one task shape (status, assignees, start/due, estimate, progress, priority, parent, dependencies, location, tags, project, extra fields) with statuses, people and projects; pure helpers to search, filter, group by any field, sort, nest subtasks, do date math (week and month grids, working days, overlaps, time scales), sum capacity per person, follow dependencies and the critical path, and apply, undo and persist changes; the shared parts (StatusPill, AssigneeStack, DueLabel, PriorityFlag, TaskChip, CompleteToggle), the ViewToolbar (search, filter chips, group by, sort, show fields), drag primitives on @dnd-kit, a hook for optimistic saves with rollback and undo, and adapters that drive the Board and DataTable blocks from tasks.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.7.0/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/core.json"
9
9
  ],
10
10
  "dependencies": [
11
11
  "@dnd-kit/core@6.3.1",
@@ -91,7 +91,7 @@
91
91
  "docs": "Installed to components/makersclaw/blocks/task-model. Import: import { NONE, PRIORITIES, DEFAULT_STATUSES, TASK_FIELDS, DEFAULT_VIEW, normalizeTask, normalizeTasks, createTaskContext, fieldOf, isDone, doneStatusId, openStatusId, toggleDoneChange, newTaskId, draftTask, valuesOf, optionsOf, labelOf, searchText, searchTasks, filterTasks, orderOf, sortTasks, sortOptions, groupTasks, groupOptions, movePatch, applyView, activeFilterCount, rankBetween, placeChange, childrenMap, buildTree, flattenTree, descendantIds, ancestorIds, subtaskCounts, rollup, progressOf, dependencyEdges, blockersOf, wouldCycle, dateConflicts, criticalPath, hoursPerDay, workload, sumOf, applyChange, invertChange, changeWrites, changedIds, deleteChange, toBoard, toTableRows, taskFacets, StatusPill, CompleteToggle, AssigneeStack, PersonLabel, DueLabel, PriorityFlag, TagList, SubtaskCount, ProgressLine, TaskChip, GroupLabel, taskColumns, TONE_TEXT, HUE_EDGE, HUE_BG, TaskDragProvider, SortableGroup, useSortableTask, useDraggableTask, useDropTarget, DragHandle, DropLine, LIFTED, useReducedMotion, arrayMove, isDay, dayNumber, fromDayNumber, dayOf, minutesOf, withTime, todayDay, addDays, diffDays, weekdayOf, startOfWeek, endOfWeek, weekDays, startOfMonth, endOfMonth, addMonths, daysBetween, monthGrid, WEEKEND, isWeekend, isWorkingDay, workingDaysBetween, addWorkingDays, spanOf, spansOverlap, tasksInRange, tasksOnDay, shiftDates, spanPatch, dueBucket, DUE_BUCKETS, dayForBucket, formatDay, formatTime, formatDate, timeScale, rangeOfTasks, isNewId } from \"@/components/makersclaw/blocks/task-model\". Props and an example: components/makersclaw/blocks/task-model/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
92
92
  "meta": {
93
93
  "makersclaw": {
94
- "version": "0.7.0",
94
+ "version": "0.8.1",
95
95
  "useWhen": "You are building a view of work items — a list, calendar, gantt, workload, roadmap or a switcher between them — or driving Board / DataTable from tasks. Views import it; a surface rarely renders it alone. Not for records that are not work (use data-table or board directly)."
96
96
  }
97
97
  }
@@ -5,7 +5,7 @@
5
5
  "title": "Testimonials",
6
6
  "description": "A marketing section of customer quotes: name, role, company, face or logo, the quote, an optional star rating, a verified mark and a \"view on X\" source, and optional headline numbers (stats). Layouts: a grid of cards (plain, card or raised; hover can light one and dim the rest; a \"write a review\" tile), one large quote, a switcher of faces, and a carousel, optionally over a picture.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.7.0/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.8.1/r/core.json"
9
9
  ],
10
10
  "dependencies": [],
11
11
  "files": [
@@ -45,7 +45,7 @@
45
45
  "docs": "Installed to components/makersclaw/blocks/testimonials. Import: import { Testimonials } from \"@/components/makersclaw/blocks/testimonials\". Props and an example: components/makersclaw/blocks/testimonials/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
46
46
  "meta": {
47
47
  "makersclaw": {
48
- "version": "0.7.0",
48
+ "version": "0.8.1",
49
49
  "useWhen": "Social proof on a public page: a landing page, a pricing page, a product page, a case-study teaser. Not for reviews a signed-in user writes and manages (a record list or form), or an app's own activity feed."
50
50
  }
51
51
  }