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
package/README.md CHANGED
@@ -48,11 +48,23 @@ them: [makersclaw.com](https://makersclaw.com).
48
48
  ## Components come with the template; blocks come when a surface needs one
49
49
 
50
50
  - **Components** — the kit (`components/ui`: Button, Field, Select, Sheet,
51
- Tabs, Menu, Notice, Icon…) and the parts bound to the data layer
51
+ Tabs, Menu, Notice, Icon…, and the layouts AppLayout and
52
+ DocumentLayout) and the parts bound to the data layer
52
53
  (`components/parts`: RecordSwitcher, useFixture). `init` lays them into
53
54
  every app. `add <component>` only restores one.
55
+ - **Layouts** — `AppLayout` is the one owner of the window's height (a
56
+ header, navigation, content that scrolls or fills, an inspector, a
57
+ footer); the starter shell is one, and `npm run check` refuses
58
+ anything else in an app that sizes by the window (`min-h-dvh`,
59
+ `h-screen`, `100vh`, `h-[80vh]`…). `DocumentLayout` is a page that
60
+ flows, for print and export. Props: the app's README §3b.
54
61
  - **Blocks** — the bigger pieces a surface is assembled from: a board, a
55
- job panel, and more to come. No app has one until `add` puts it in
62
+ calendar, a Gantt, the automations page, the agent's dock, 97 free blocks
63
+ in all (`npx makersclaw list --type block` names them; the newest are
64
+ `automations-screen`, `margin-notes`, `schedule-ruler`, `pace-bar`,
65
+ `time-grid`, `time-strip`, `tier-map`, `agent-dock`, `sum-bar`,
66
+ `schedule-engine`, `schedule-gantt`, `top-bar`, `first-run` and `chat-pane`).
67
+ No app has one until `add` puts it in
56
68
  `components/blocks/<name>/`. `search` finds them by what they do. A
57
69
  block takes its rows as props and hands saves out as callbacks; the
58
70
  surface reads and writes. So no block calls the data door (`_claw`,
@@ -91,8 +103,9 @@ tables live) and `check/pins.json` (the hash of every fixed file). A third
91
103
  says which package versions it installs: `pnpm-lock.yaml`, cut by `init`,
92
104
  `add` and `update` from the lock this version ships, so every app on one
93
105
  version resolves every package the same way. `update` moves an app to
94
- this version's fixed files and blocks and never touches its own files —
95
- the shell, the surfaces, `components/*.jsx`. Within `0.x` a new minor is a
106
+ this version's fixed files and blocks, adds a block an installed block
107
+ newly requires (`agent-pane` needs `chat-pane` since 0.8.1), and never
108
+ touches its own files — the shell, the surfaces, `components/*.jsx`. Within `0.x` a new minor is a
96
109
  new contract: `update` refuses it until `--major`, because screens written
97
110
  against the old one may need rebuilding.
98
111
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makersclaw",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "description": "The Makersclaw app template, its kit and its blocks: init an app, add the blocks a surface needs, search the registry.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,52 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "activity-log",
4
+ "type": "registry:block",
5
+ "title": "ActivityLog",
6
+ "description": "Who did what, to what, when, newest first: one row per event on a vertical timeline, \"Anna Lee edited deals\" with the line's detail under it, a kind dot and the time. The agent is an author like a person, with its own mark: \"Agent, for anna@acme.com\", \"Agent, on a run\". It takes the app's activity lines as useActivity() returns them (lib/hooks.js; with a row, one record's timeline) and words them itself, or rows you shaped. leading=\"icon\" draws one subject's journey instead.",
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/agent-marks.json"
10
+ ],
11
+ "dependencies": [],
12
+ "files": [
13
+ {
14
+ "path": "registry/blocks/activity-log/index.js",
15
+ "type": "registry:component",
16
+ "target": "@components/makersclaw/blocks/activity-log/index.js",
17
+ "content": "// The ActivityLog block — `makersclaw add activity-log`. Fixed: compose it\n// through its props (README.md beside this file). ActivityFeed is the\n// CRM's name for the same block.\nexport { ActivityLog, ActivityFeed, activityItems, activityAuthor, activityTime } from \"./activity-log\";\n"
18
+ },
19
+ {
20
+ "path": "registry/blocks/activity-log/activity-log.jsx",
21
+ "type": "registry:component",
22
+ "target": "@components/makersclaw/blocks/activity-log/activity-log.jsx",
23
+ "content": "\"use client\";\n\nimport { Avatar, Badge, Button, Card, Empty, Icon, Item, ItemGroup, Skeleton, StatusDot, cx } from \"../../ui\";\nimport { AgentMark } from \"../agent-marks\";\n\n// ActivityLog — who did what, to what, when; newest first (the app kit,\n// D15; grown as the CRM's activity-feed, 0.7.0). One row per event: the\n// author's face on a vertical timeline line, \"<b>Actor</b> verb\n// <b>Object</b>\" with a muted detail under it, and a kind dot and the time\n// on the right. The agent is an author like a person, with its own mark:\n// \"Agent, for anna@acme.com\", \"Agent, on a run\".\n//\n// Two ways in. `items` are rows you shaped yourself (the caller formats\n// the time and picks the tone). `rows` are the app's activity lines as\n// useActivity() returns them (lib/hooks.js) — { id, at, action, surface,\n// row_ref, detail, by } — and the block words them: `by` user:<email> is\n// the person (named through `people`), agent:<email> is \"Agent, for\n// <them>\", agent:job is \"Agent, on a run\".\n//\n// leading=\"icon\" is one subject's journey instead: each row leads with its\n// kind's icon in a circle tinted by its tone, a title with the short date\n// beside it, one muted line under it, no actor and no trailing column; the\n// header can name the subject in a pill.\n\nconst TONES = [\"success\", \"info\", \"warning\", \"danger\", \"neutral\"];\nconst LOADING_ROWS = 4;\n\n// The circle behind a kind's icon: a wash of its tone, the glyph in it.\nconst DISC = {\n success: \"bg-success/15 text-success\",\n info: \"bg-info/15 text-info\",\n warning: \"bg-warning/15 text-warning\",\n danger: \"bg-destructive/15 text-destructive\",\n primary: \"bg-primary/15 text-primary\",\n neutral: \"bg-muted text-muted-foreground\",\n};\n\n// The icon and tone of a journey row: its own, else its kind's.\nfunction kindOf(item, kinds) {\n const k = (item.kind != null && kinds?.[item.kind]) || {};\n const tone = item.tone ?? k.tone;\n return { icon: item.icon ?? k.icon ?? \"circle\", tone: DISC[tone] ? tone : \"neutral\" };\n}\n\n/** The timeline segment behind the avatar column: from the row's middle\n * down on the first row, top to middle on the last, full height between.\n * left-7 is the avatar's centre (Item's px-3 + half of a 32px avatar). */\nfunction Line({ first, last, icon }) {\n if (first && last) return null;\n if (icon)\n // The journey's circles sit on the title line, not the row's middle:\n // their centre is 26px down (py-3.5 + half of a 24px circle), left-6.\n return (\n <span\n aria-hidden=\"true\"\n className={cx(\"absolute left-6 w-px -translate-x-1/2 bg-border\", first ? \"top-[26px]\" : \"top-0\", last ? \"h-[26px]\" : \"bottom-0\")}\n />\n );\n return (\n <span\n aria-hidden=\"true\"\n className={cx(\"absolute left-7 w-px -translate-x-1/2 bg-border\", first ? \"top-1/2\" : \"top-0\", last ? \"bottom-1/2\" : \"bottom-0\")}\n />\n );\n}\n\nfunction Disc({ icon, tone }) {\n return (\n // raw: an icon in a circle washed with a status tone; Item's own `icon`\n // square is always muted, and no kit part tints a glyph's backdrop.\n <span aria-hidden=\"true\" className={cx(\"relative flex size-6 shrink-0 items-center justify-center rounded-full\", DISC[tone])}>\n <Icon name={icon} size={13} />\n </span>\n );\n}\n\nfunction JourneyRow({ item, first, last, kinds, onItemClick }) {\n const { icon, tone } = kindOf(item, kinds);\n const onClick = item.onClick ?? (onItemClick && !item.href ? () => onItemClick(item) : undefined);\n return (\n // raw: a positioned wrapper so the timeline line runs behind the\n // circles across the whole row; no kit part draws a timeline.\n <div className=\"relative\">\n <Line first={first} last={last} icon />\n <Item\n className=\"py-3.5 rounded-none [&]:items-start\"\n media={<Disc icon={icon} tone={tone} />}\n title={\n <>\n {item.title ?? item.object}\n {item.time ? (\n <>\n {\" \"}\n <time dateTime={item.timestamp} title={item.timestamp || undefined} data-nums className=\"ml-1 text-xs font-normal text-muted-foreground\">\n {item.time}\n </time>\n </>\n ) : null}\n </>\n }\n description={item.detail || undefined}\n href={item.href}\n onClick={item.href ? undefined : onClick}\n />\n </div>\n );\n}\n\nfunction Sentence({ item, linkObject }) {\n return (\n <>\n <span>{item.actorName}</span> <span className=\"font-normal text-muted-foreground\">{item.verb}</span>{\" \"}\n {linkObject ? (\n // The kit's inline text link, in the sentence's own size and weight;\n // a row that is not a target of its own can still link its object.\n <Button variant=\"link\" size=\"inherit\" href={item.objectHref} className=\"relative z-10\">\n {item.object}\n </Button>\n ) : (\n <span>{item.object}</span>\n )}\n </>\n );\n}\n\nfunction Row({ item, first, last, onItemClick }) {\n const tone = TONES.includes(item.tone) ? item.tone : \"neutral\";\n const onClick = item.onClick ?? (onItemClick && !item.href && !item.objectHref ? () => onItemClick(item) : undefined);\n const linkObject = Boolean(item.objectHref) && !item.href && !onClick;\n return (\n // raw: a positioned wrapper so the timeline line can run behind the\n // Item's avatar across the whole row; no kit part draws a timeline.\n <div className=\"relative\">\n <Line first={first} last={last} />\n <Item\n size=\"default\"\n className=\"py-3.5 rounded-none hover:bg-muted/50\"\n media={\n item.agent ? (\n // raw: the agent's mark in the avatar's circle, so the timeline\n // line runs behind it like a face.\n <span className=\"relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted\">\n <AgentMark size=\"md\" />\n </span>\n ) : (\n <Avatar name={item.actorName} src={item.actorAvatar} size=\"sm\" />\n )\n }\n title={<Sentence item={item} linkObject={linkObject} />}\n description={item.detail || undefined}\n href={item.href}\n onClick={item.href ? undefined : onClick}\n meta={\n <span className=\"inline-flex items-center gap-2 whitespace-nowrap text-sm\">\n <StatusDot tone={tone} size=\"sm\" />\n <time dateTime={item.timestamp} title={item.timestamp || undefined}>\n {item.time}\n </time>\n </span>\n }\n />\n </div>\n );\n}\n\nfunction SkeletonRow({ first, last, icon }) {\n return (\n <div className=\"relative\">\n <Line first={first} last={last} icon={icon} />\n <Item\n className={cx(\"py-3.5 rounded-none\", icon && \"[&]:items-start\")}\n media={<Skeleton shape=\"circle\" className={icon ? \"size-6\" : \"size-8\"} />}\n title={<Skeleton className=\"w-48 max-w-full\" />}\n description={<Skeleton className=\"mt-1.5 w-32 max-w-full\" />}\n meta={icon ? undefined : <Skeleton className=\"w-16\" />}\n />\n </div>\n );\n}\n\nconst ISO = /^\\d{4}-\\d{2}-\\d{2}T/;\n\n/** \"just now\", \"5 min ago\", \"3 h ago\", \"yesterday\", \"12 Sep\". */\nexport function activityTime(at, now = new Date()) {\n const d = at instanceof Date ? at : typeof at === \"string\" && (ISO.test(at) || /^\\d{4}-\\d{2}-\\d{2}/.test(at)) ? new Date(at) : null;\n if (!d || Number.isNaN(d.getTime())) return at == null ? \"\" : String(at);\n const s = Math.round((now.getTime() - d.getTime()) / 1000);\n if (s < 60) return \"just now\";\n if (s < 3600) return `${Math.floor(s / 60)} min ago`;\n if (s < 86400 && d.toDateString() === now.toDateString()) return `${Math.floor(s / 3600)} h ago`;\n const y = new Date(now);\n y.setDate(y.getDate() - 1);\n if (d.toDateString() === y.toDateString()) return \"yesterday\";\n return d.toLocaleDateString(\"en-GB\", { day: \"numeric\", month: \"short\", ...(d.getFullYear() === now.getFullYear() ? {} : { year: \"numeric\" }) });\n}\n\n/** A line's tone from its action word (the door's: added, edited, …). */\nconst ACTION_TONE = { added: \"success\", created: \"success\", confirmed: \"success\", linked: \"info\", listed: \"info\", edited: \"info\", moved: \"info\", merged: \"warning\", removed: \"danger\", erased: \"danger\", unlinked: \"neutral\", unlisted: \"neutral\" };\n\n/** Who a `by` names, in words: { name, agent, email }. */\nexport function activityAuthor(by, people) {\n const raw = String(by ?? \"\");\n const named = (email) => (email && people && (people[email] ?? people[email.toLowerCase()])) || email;\n if (raw === \"agent:job\" || raw === \"agent:run\") return { name: \"Agent, on a run\", agent: true };\n if (raw.startsWith(\"agent:\")) {\n const email = raw.slice(6);\n return { name: email ? `Agent, for ${named(email)}` : \"Agent\", agent: true, email };\n }\n if (raw.startsWith(\"user:\")) {\n const who = raw.slice(5);\n if (!who || who === \"unknown\") return { name: \"Someone\", agent: false };\n return { name: named(who), agent: false, email: who.includes(\"@\") ? who : undefined };\n }\n return { name: raw || \"Someone\", agent: false };\n}\n\n/**\n * The app's activity lines (useActivity's `rows`) as items:\n *\n * rows [{ id, at, action, surface, row_ref, detail, data, by }]\n * people { \"anna@acme.com\": \"Anna Lee\" }: names for emails\n * formatTime (at) → words; default activityTime (\"5 min ago\")\n * describe (row) → part of an item, laid over what this makes\n * (an href, an object's name, a tone)\n */\nexport function activityItems(rows, { people, formatTime = activityTime, describe } = {}) {\n return (rows ?? []).filter(Boolean).map((row, i) => {\n const who = activityAuthor(row.by, people);\n const item = {\n id: row.id ?? `${row.at ?? \"\"}-${i}`,\n actorName: who.name,\n agent: who.agent,\n verb: row.action ?? \"changed\",\n object: row.surface || \"a record\",\n detail: row.detail || undefined,\n tone: ACTION_TONE[row.action] ?? \"neutral\",\n kind: row.action,\n // A journey row's title is the sentence; its detail line, the detail.\n title: [who.name, row.action ?? \"changed\", row.surface].filter(Boolean).join(\" \"),\n time: formatTime(row.at),\n timestamp: typeof row.at === \"string\" ? row.at : row.at instanceof Date ? row.at.toISOString() : undefined,\n };\n return describe ? { ...item, ...describe(row) } : item;\n });\n}\n\n/**\n * items [{ id, actorName, actorAvatar?, agent?, verb, object,\n * objectHref?, detail?, tone, time, timestamp?, href?,\n * onClick? }]; agent: true draws the agent's mark\n * rows instead of items: useActivity()'s rows, worded by\n * activityItems (with `people`, `formatTime`, `describe`)\n * title optional header, draws the feed inside a Card\n * subtitle a muted line under the title (drawn only with a title)\n * loading skeleton rows instead of items\n * onItemClick (item) → void; every row without its own href, onClick\n * or objectHref becomes a button calling it\n * emptyTitle default \"No activity yet\"\n * emptyBody a muted line under it\n * label the list's name for a screen reader; default title or \"Activity\"\n * leading avatar (default: the actor's face, the sentence, a dot and\n * the time on the right) · icon (a journey: the kind's icon\n * in a tinted circle, title + date, no rules between rows)\n * kinds { [kind]: { icon, tone } } — leading=\"icon\" looks up a\n * row's `kind` here; a row's own `icon`/`tone` win\n * subject a pill after the title naming whose history this is\n */\nexport function ActivityLog({\n items,\n rows,\n people,\n formatTime,\n describe,\n title,\n subtitle,\n loading = false,\n onItemClick,\n emptyTitle = \"No activity yet\",\n emptyBody,\n label,\n leading = \"avatar\",\n kinds,\n subject,\n className,\n}) {\n const journey = leading === \"icon\";\n const list = (items ?? (rows ? activityItems(rows, { people, formatTime, describe }) : [])).filter(Boolean);\n const named = label ?? (typeof title === \"string\" ? title : \"Activity\");\n const framed = Boolean(title);\n\n let body;\n if (loading) {\n body = (\n <ItemGroup variant={framed ? \"plain\" : \"outline\"} aria-label={`${named}, loading`}>\n {Array.from({ length: LOADING_ROWS }, (_, i) => (\n <SkeletonRow key={i} first={i === 0} last={i === LOADING_ROWS - 1} icon={journey} />\n ))}\n </ItemGroup>\n );\n } else if (list.length === 0) {\n body = <Empty icon=\"clock\" title={emptyTitle} body={emptyBody} className={framed ? \"m-4\" : undefined} />;\n } else {\n body = (\n <ItemGroup\n variant={framed ? \"plain\" : \"outline\"}\n aria-label={named}\n // A journey is one line of events, no rules between them.\n className={journey ? \"py-1 [&>li]:border-t-0\" : undefined}\n >\n {list.map((item, i) =>\n journey ? (\n <JourneyRow key={item.id ?? i} item={item} first={i === 0} last={i === list.length - 1} kinds={kinds} onItemClick={onItemClick} />\n ) : (\n <Row key={item.id ?? i} item={item} first={i === 0} last={i === list.length - 1} onItemClick={onItemClick} />\n ),\n )}\n </ItemGroup>\n );\n }\n\n if (!framed) return <div className={className}>{body}</div>;\n return (\n <Card\n title={\n subject ? (\n <span className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n <span>{title}</span>\n {typeof subject === \"string\" ? (\n <Badge variant=\"soft\" className=\"font-normal\">\n {subject}\n </Badge>\n ) : (\n subject\n )}\n </span>\n ) : (\n title\n )\n }\n description={subtitle} className={cx(\"overflow-hidden\", className)}>\n {/* Edge to edge under the header, as the rows' rules are. */}\n <div aria-busy={loading || undefined} className=\"-mx-4 -mb-4 border-t border-border\">\n {body}\n </div>\n </Card>\n );\n}\n\n/** The CRM's name for it (0.7.0), kept so a screen written against the\n * CRM's activity-feed moves without a rename. */\nexport const ActivityFeed = ActivityLog;\n"
24
+ },
25
+ {
26
+ "path": "registry/blocks/activity-log/README.md",
27
+ "type": "registry:file",
28
+ "target": "@components/makersclaw/blocks/activity-log/README.md",
29
+ "content": "# ActivityLog\n\nWho did what, to what, when. Newest first, one row per event on a\nvertical timeline: the author's face, \"**Anna Lee** edited **deals**\",\nthe line's detail under it in muted words, a kind dot and the time.\n\nThe agent is an author like a person, with its own mark (the diamond from\n`agent-marks`) where a face would be:\n\n- \"Agent, for Anna Lee\" — the agent wrote it on Anna's ask;\n- \"Agent, on a run\" — a scheduled job wrote it.\n\nWith a record, it is that record's story. Grown in the CRM (0.7.0) as\n`activity-feed`; the premium registry owns that name, so here it is\n`activity-log`, and `ActivityFeed` stays exported as an alias.\n\n```jsx\nimport { ActivityLog } from \"../components/blocks/activity-log\"; // a Makersclaw app (\"./blocks/activity-log\" from components/)\nimport { ActivityLog } from \"@/components/makersclaw/blocks/activity-log\"; // a shadcn project\n```\n\nA client component. It requires `agent-marks` (laid with it). The\nExample is at the end.\n\n## Which hook feeds it\n\n```js\nconst { rows, loading, unavailable } = useActivity({ row: deal.id }); // lib/hooks.js\n```\n\n`useActivity({ row, surface, since, limit, agent })` reads `GET\n_claw/data/activity`: the lines the data door wrote for every change it\ntook, `{ id, at, action, surface, row_ref, detail, data, by }`. `row`\nkeeps one record's lines; `agent: true` keeps only the agent's. `by` is\n`user:<email>`, `agent:<email>` (the agent, on that member's ask) or\n`agent:job` (a scheduled run). `action` is the door's word: `added`,\n`edited`, `moved`, `removed`, `confirmed`, `merged`, `linked`,\n`unlinked`, `listed`, `unlisted`.\n\n## Props\n\n- `rows` — `useActivity()`'s rows. The block words them (below).\n- `people` — `{ \"anna@acme.com\": \"Anna Lee\" }`: names for the emails in\n `by`. Without a name, the email shows.\n- `formatTime(at)` — words for a line's time. Default \"just now\", \"5 min\n ago\", \"3 h ago\", \"yesterday\", \"12 Sep\".\n- `describe(row)` — part of an item laid over what the block makes of a\n row: an `href` to the record, an `object` name, a `tone`.\n- `items` — instead of `rows`: items you shaped yourself, `[{ id,\n actorName, actorAvatar?, agent?, verb, object, objectHref?, detail?,\n tone, time, timestamp?, href?, onClick? }]`. `agent: true` draws the\n agent's mark. `tone` is `success` · `info` · `warning` · `danger` ·\n `neutral`.\n- `title` — a head; draws the log inside a `Card`. `subtitle` — a muted\n line under it.\n- `subject` — a pill after the title naming whose story this is.\n- `loading` — skeleton rows instead of items.\n- `onItemClick(item)` — every row without its own `href`, `onClick` or\n `objectHref` becomes a button calling it.\n- `emptyTitle` — default \"No activity yet\". `emptyBody` — a muted line\n under it.\n- `label` — the list's name for a screen reader. Default the title, or\n \"Activity\".\n- `leading` — `avatar` (default) · `icon`: one subject's journey, each\n row its kind's icon in a tinted circle, a title with the date, no\n author column.\n- `kinds` — `{ [kind]: { icon, tone } }` for `leading=\"icon\"`; a row's\n kind is its `action`.\n- `className` — layout around it. Never colour.\n\n`activityItems(rows, { people, formatTime, describe })`,\n`activityAuthor(by, people)` and `activityTime(at)` are exported for a\nscreen that words lines itself.\n\n## Who may do what\n\nAny member who can open the app reads every line. That is why a line\nnever holds a field's value: only the action, the surface, the record's\nid and one sentence of detail. The log has no controls of its own.\n\n## Never\n\n- Never put a field's value in a line's `detail` for this log to show.\n- Never draw the agent with a person's avatar, or a person with the\n agent's mark.\n- Never use it for one ask's changes with an Undo: that is\n `agent-changes`.\n\n## Example\n\nA record's story, beside the record.\n\n```jsx\n\"use client\";\nimport { useActivity } from \"../lib/hooks\";\nimport { ActivityLog } from \"../components/blocks/activity-log\";\n\nexport default function DealStory({ deal, people }) {\n const { rows, loading, unavailable } = useActivity({ row: deal.id });\n if (unavailable) return <p className=\"text-sm text-muted-foreground\">The story is not connected yet.</p>;\n return (\n <ActivityLog\n title=\"Story\"\n subject={deal.name}\n rows={rows}\n people={people}\n loading={loading}\n emptyBody=\"Changes to this deal show here, by people and by the agent.\"\n />\n );\n}\n```\n"
30
+ }
31
+ ],
32
+ "categories": [
33
+ "activity",
34
+ "timeline",
35
+ "history",
36
+ "audit",
37
+ "log",
38
+ "feed",
39
+ "events",
40
+ "who did what",
41
+ "record story",
42
+ "recent",
43
+ "changes"
44
+ ],
45
+ "docs": "Installed to components/makersclaw/blocks/activity-log. Import: import { ActivityLog, ActivityFeed, activityItems, activityAuthor, activityTime } from \"@/components/makersclaw/blocks/activity-log\". Props and an example: components/makersclaw/blocks/activity-log/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
46
+ "meta": {
47
+ "makersclaw": {
48
+ "version": "0.8.1",
49
+ "useWhen": "A record's story (what happened to this deal, and who did it), an app's recent changes on a home screen, a review of what the agent did this week next to what people did. Not for one job's own steps (job-panel), one ask's changes with an undo (agent-changes), or a sortable audit table (data-table)."
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "agent-changes",
4
+ "type": "registry:block",
5
+ "title": "AgentChanges",
6
+ "description": "The receipt of one ask: what the agent did in one line (\"Sorted 46 stickies into 6 groups\"), who asked and when, the changes listed (folded after five, \"Show 41 more\"), and \"Undo this ask\" — your async undo, the app's own declared action, answering { ok } — then the undone state, struck through, in words. The block draws; the app knows what an ask changed and takes it back.",
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/agent-marks.json"
10
+ ],
11
+ "dependencies": [],
12
+ "files": [
13
+ {
14
+ "path": "registry/blocks/agent-changes/index.js",
15
+ "type": "registry:component",
16
+ "target": "@components/makersclaw/blocks/agent-changes/index.js",
17
+ "content": "// The AgentChanges block — `makersclaw add agent-changes`. Fixed: compose\n// it through its props (README.md beside this file).\nexport { AgentChanges } from \"./agent-changes\";\n"
18
+ },
19
+ {
20
+ "path": "registry/blocks/agent-changes/agent-changes.jsx",
21
+ "type": "registry:component",
22
+ "target": "@components/makersclaw/blocks/agent-changes/agent-changes.jsx",
23
+ "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { Button, Icon, cx } from \"../../ui\";\nimport { AgentMark, Byline } from \"../agent-marks\";\n\n// AgentChanges — the receipt of one ask (the app kit, D15): what the\n// agent did in one line (\"Sorted 46 stickies into 6 groups\"), the changes\n// listed (folded after five), and \"Undo this ask\". The block draws; the\n// app's own declared undo action does the work, because only the app\n// knows what an ask drew (Whiteboard's \"violet trace\", Mind Maps, Gantt's\n// \"Undo draft\"). The list comes from useActivity({ agent: true, since })\n// or from what the ask reported. Props in, callbacks out.\n\nconst FOLD = 5;\n\n/**\n * summary what the ask did, one line (\"Sorted 46 stickies into 6 groups\")\n * changes [{ id?, label, detail? }]: each change, newest last;\n * folded after five\n * by who and when: Byline's props ({ by, ask, at }), or words\n * onUndo() async → { ok } | { ok: false, error }: the app's undo of\n * this ask; without it there is no Undo (the member may not)\n * undone true when the ask was undone already (from your data)\n * undoLabel default \"Undo this ask\"\n * undoneWords default \"Undone. Everything this ask changed is back as it was.\"\n * label the region's name for a reader (default the summary)\n */\nexport function AgentChanges({\n summary,\n changes = [],\n by,\n onUndo,\n undone: undoneProp = false,\n undoLabel = \"Undo this ask\",\n undoneWords = \"Undone. Everything this ask changed is back as it was.\",\n label,\n className,\n}) {\n const [open, setOpen] = useState(false);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState(null);\n const [undoneHere, setUndoneHere] = useState(false);\n const undone = undoneProp || undoneHere;\n const list = (changes ?? []).filter(Boolean);\n const shown = open ? list : list.slice(0, FOLD);\n const more = list.length - shown.length;\n\n async function undo() {\n if (!onUndo || busy) return;\n setBusy(true);\n setError(null);\n let r;\n try {\n r = await onUndo();\n } catch (e) {\n r = { ok: false, error: e?.message ?? String(e) };\n }\n setBusy(false);\n if (r && r.ok === false) setError(r.error || \"Couldn't undo it. Try again.\");\n else setUndoneHere(true);\n }\n\n return (\n <section\n aria-label={label ?? (typeof summary === \"string\" ? summary : \"What the agent changed\")}\n className={cx(\"@container grid grid-cols-1 min-w-0 content-start gap-2.5 rounded-lg border border-border bg-card p-3.5 text-sm text-card-foreground\", undone && \"bg-muted\", className)}\n >\n <div className=\"flex min-w-0 items-start gap-2\">\n <span className=\"mt-1 shrink-0\">\n <AgentMark label=\"The agent\" />\n </span>\n <div className=\"grid grid-cols-1 min-w-0 flex-1 gap-0.5\">\n <p className={cx(\"min-w-0 break-words font-semibold\", undone && \"text-muted-foreground line-through\")}>{summary}</p>\n {by ? typeof by === \"object\" && !Array.isArray(by) && !by.$$typeof ? <Byline mark={false} {...by} /> : <span className=\"text-xs text-muted-foreground\">{by}</span> : null}\n </div>\n </div>\n\n {list.length ? (\n <ul className={cx(\"m-0 grid grid-cols-1 list-none gap-1 p-0 pl-5\", undone && \"text-muted-foreground\")}>\n {shown.map((c, i) => (\n <li key={c.id ?? i} className=\"flex min-w-0 items-start gap-2\">\n <Icon name={undone ? \"undo\" : \"check\"} size={12} className={cx(\"mt-1 shrink-0\", undone ? \"text-muted-foreground\" : \"text-success\")} />\n <span className=\"min-w-0 break-words\">\n <span className={undone ? \"line-through\" : undefined}>{c.label}</span>\n {c.detail ? <span className=\"text-muted-foreground\"> · {c.detail}</span> : null}\n </span>\n </li>\n ))}\n </ul>\n ) : null}\n {list.length > FOLD ? (\n <Button variant=\"link\" size=\"inherit\" tone=\"muted\" className=\"justify-self-start pl-5 text-xs\" aria-expanded={open} onClick={() => setOpen((v) => !v)}>\n {open ? \"Show fewer\" : `Show ${more} more`}\n </Button>\n ) : null}\n\n {undone ? (\n <p role=\"status\" className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <Icon name=\"undo\" size={14} className=\"shrink-0\" />\n {undoneWords}\n </p>\n ) : onUndo ? (\n <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n <Button size=\"sm\" variant=\"secondary\" loading={busy} onClick={undo}>\n <Icon name=\"undo\" size={14} /> {undoLabel}\n </Button>\n {list.length ? <span className=\"text-xs text-muted-foreground\">{list.length === 1 ? \"takes it back\" : `takes back all ${list.length} changes`}</span> : null}\n </div>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"text-xs text-destructive\">\n {error}\n </p>\n ) : null}\n </section>\n );\n}\n"
24
+ },
25
+ {
26
+ "path": "registry/blocks/agent-changes/README.md",
27
+ "type": "registry:file",
28
+ "target": "@components/makersclaw/blocks/agent-changes/README.md",
29
+ "content": "# AgentChanges\n\nThe receipt of one ask. After the agent changes many things at once, the\nmember sees:\n\n- what it did, in one line: \"Sorted 46 stickies into 6 groups\";\n- who asked and when: \"By the agent, on Priya's ask · 11:20\";\n- each change, folded after five (\"Show 41 more\");\n- **Undo this ask**, which takes all of them back in one press.\n\nUndone, the receipt stays, struck through, and says so in words.\n\nThe block draws; **the app does the undo**. Only the app knows what an\nask drew (the whiteboard's stickies, the map's branches, the plan's\nbars), so Undo calls your own declared undo action.\n\n```jsx\nimport { AgentChanges } from \"../components/blocks/agent-changes\"; // a Makersclaw app (\"./blocks/agent-changes\" from components/)\nimport { AgentChanges } from \"@/components/makersclaw/blocks/agent-changes\"; // a shadcn project\n```\n\nA client component. It requires `agent-marks` (laid with it).\n\n## Which hook feeds it\n\nThe changes come from what the ask reported, or from the activity lines\nthe agent wrote since it started:\n\n```js\nconst { rows } = useActivity({ agent: true, since: ask.started_at }); // lib/hooks.js\nconst changes = rows.map((r) => ({ id: r.id, label: r.detail ?? `${r.action} ${r.surface}` }));\n```\n\nUndo is the app's own declared action (`runAction`, lib/actions): the\nsame write path the agent uses, with the same door rules.\n\n## Props\n\n- `summary` — what the ask did, one line, in the app's words.\n- `changes` — `[{ id?, label, detail? }]`, each change. Folded after five.\n- `by` — who and when: `Byline`'s props (`{ by, ask, at }`, e.g. `{ ask:\n \"Priya\", at: \"11:20\" }`), or your own words.\n- `onUndo()` — async, answers `{ ok: true }` or `{ ok: false, error }` (a\n throw counts as failed). The button spins while it runs; a failure says\n why under it. Without `onUndo` there is no Undo.\n- `undone` — `true` when your data says the ask was undone already.\n- `undoLabel` — default \"Undo this ask\".\n- `undoneWords` — default \"Undone. Everything this ask changed is back as\n it was.\"\n- `label` — the region's name for a reader. Default the summary.\n- `className` — layout around it. Never colour.\n\n## Who may do what\n\nGive `onUndo` to the member who asked, and to an owner or admin; your\ndeclared undo action refuses anyone else anyway. Everyone else sees the\nreceipt without the button.\n\n## Never\n\n- Never undo by deleting what looks new: undo exactly what this ask\n wrote, through your declared action.\n- Never hide the receipt after an undo; it stays, struck, so the member\n knows what happened.\n- Never use it for proposals the member has not kept yet: that is\n `suggestion`.\n\n## Example\n\nThe receipt under a whiteboard after the agent sorted it.\n\n```jsx\n\"use client\";\nimport { runAction } from \"../lib/actions\";\nimport { AgentChanges } from \"../components/blocks/agent-changes\";\n\nexport function SortReceipt({ ask, moves, reload }) {\n return (\n <AgentChanges\n summary={`Sorted ${moves.length} stickies into ${ask.groups} groups`}\n by={{ ask: ask.asked_by_name, at: ask.ended_at }}\n changes={moves.map((m) => ({ id: m.id, label: m.sticky, detail: `to ${m.group}` }))}\n undone={ask.undone}\n onUndo={async () => {\n const r = await runAction({ name: \"undo_ask\", args: { ask: ask.id } });\n if (r.ok) reload();\n return r;\n }}\n />\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"
30
+ }
31
+ ],
32
+ "categories": [
33
+ "undo",
34
+ "changes",
35
+ "receipt",
36
+ "ask",
37
+ "what changed",
38
+ "revert",
39
+ "trace",
40
+ "batch",
41
+ "summary",
42
+ "history"
43
+ ],
44
+ "docs": "Installed to components/makersclaw/blocks/agent-changes. Import: import { AgentChanges } from \"@/components/makersclaw/blocks/agent-changes\". Props and an example: components/makersclaw/blocks/agent-changes/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
45
+ "meta": {
46
+ "makersclaw": {
47
+ "version": "0.8.1",
48
+ "useWhen": "After the agent changes many things at once on a member's ask and the member should see them and take them all back in one press: a whiteboard sorted into groups, a mind map grown, a plan drafted onto a Gantt, a batch of records tidied. Not for proposals waiting to be kept (suggestion) or for the app's whole history (activity-log)."
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "agent-chat",
4
+ "type": "registry:block",
5
+ "title": "AgentChat",
6
+ "description": "The app's own chat with its agent, in the app's look: the member's words, the agent's answer as it is written, one line per step (\"Worked through 6 steps\"), Stop while it works, and what waits on the member settled in place — the agent's question is answered in the chat (its options, and the member's own words where it welcomes them), and its yes is the `approval` block's press frame, handed in as `yes`; a need the app cannot settle (connecting an account, spending money) says so and links to the desk. It draws what useAgentThread() returns (lib/hooks.js): the same conversation the desk's agent column shows, one session, two views. Optional row makes it a chat about one record. fill=false for a compact card in a column.",
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/needs-you.json"
10
+ ],
11
+ "dependencies": [],
12
+ "files": [
13
+ {
14
+ "path": "registry/blocks/agent-chat/index.js",
15
+ "type": "registry:component",
16
+ "target": "@components/makersclaw/blocks/agent-chat/index.js",
17
+ "content": "// The AgentChat block — `makersclaw add agent-chat`. Fixed: compose it\n// through its props (README.md beside this file).\nexport { AgentChat } from \"./agent-chat\";\n"
18
+ },
19
+ {
20
+ "path": "registry/blocks/agent-chat/agent-chat.jsx",
21
+ "type": "registry:component",
22
+ "target": "@components/makersclaw/blocks/agent-chat/agent-chat.jsx",
23
+ "content": "\"use client\";\n\nimport { Fragment, useEffect, useRef, useState } from \"react\";\nimport { Button, Icon, IconButton, Notice, Spinner, Textarea, cx } from \"../../ui\";\nimport { QuestionBox } from \"../needs-you\";\n\n// AgentChat — the app's own chat with its agent, in the app's look (0.8.1,\n// the workspace's docs/APP-AGENT-BLOCKS-PLAN.md phase 1). It draws the\n// object `useAgentThread()` returns (lib/hooks.js): the member's words,\n// the agent's answer as it is written, one line per step, and where the\n// thread stands. It is the SAME conversation the desk's agent column\n// shows — one session, two views — so an app that places it says so in\n// its package (`\"agent_in_app\": true` in the blueprint), and the desk then\n// keeps its column folded for the app.\n//\n// const chat = useAgentThread({ row: { kind: \"person\", id, name } });\n// <AgentChat chat={chat} title={`Ask about ${name}`} suggestions={[…]} />\n//\n// What waits on the member is settled in the chat, where it was asked\n// (0.8.1, D18/D19): the agent's QUESTION is answered in place (its options,\n// and the member's own words where it welcomes them: `chat.answer`), and\n// its YES is the `approval` block's press frame, handed in as `yes`. The\n// chat never draws an Approve of its own — the press is Makersclaw's, in\n// a frame app code cannot script. Without `yes`, or for a need the app\n// cannot settle (connecting an account, spending money, several questions\n// at once), the bar says so and opens the desk: \"Waiting for your yes on\n// the desk\".\n\nconst STATE_LINE = {\n queued: \"Queued — it starts when the one before it ends\",\n working: \"Working on it\",\n};\n\n/** What waits on the member, as the bar under the thread says it. */\nfunction needsTitle(kind, inApp) {\n if (kind === \"yes\" || kind === \"approval\") return inApp === \"press\" ? \"Waiting for your yes\" : \"Waiting for your yes on the desk\";\n if (kind === \"question\") return inApp === \"answer\" ? \"A question for you\" : \"Waiting for your answer on the desk\";\n if (kind === \"connect\") return \"Waiting for you to connect an account on the desk\";\n if (kind === \"limit\") return \"Paused for credits — see the desk\";\n return \"Needs you on the desk\";\n}\n\n// ---------------------------------------------------------------------------\n// The agent's text: plain words with the little markdown agents write —\n// paragraphs, lists, **bold**, `code`, [links](https://…). React nodes\n// only, never HTML.\n\nconst INLINE = /(\\*\\*[^*]+\\*\\*|`[^`]+`|\\[[^\\]]+\\]\\((?:https?:\\/\\/)[^)\\s]+\\))/g;\n\nfunction inline(text, key) {\n const out = [];\n let last = 0;\n let i = 0;\n for (const m of String(text).matchAll(INLINE)) {\n if (m.index > last) out.push(text.slice(last, m.index));\n const tok = m[0];\n const k = `${key}-${i++}`;\n if (tok.startsWith(\"**\")) out.push(<strong key={k}>{tok.slice(2, -2)}</strong>);\n else if (tok.startsWith(\"`\")) out.push(<code key={k} className=\"rounded bg-muted px-1 font-mono text-[0.92em]\">{tok.slice(1, -1)}</code>);\n else {\n const label = tok.slice(1, tok.indexOf(\"](\"));\n const href = tok.slice(tok.indexOf(\"](\") + 2, -1);\n out.push(\n <a key={k} href={href} target=\"_blank\" rel=\"noopener noreferrer\" className=\"break-all text-primary underline underline-offset-2\">\n {label}\n </a>,\n );\n }\n last = m.index + tok.length;\n }\n if (last < text.length) out.push(text.slice(last));\n return out;\n}\n\nconst LIST_ITEM = /^\\s*(?:[-*•]|\\d+[.)])\\s+/;\n\n/** Paragraphs and lists from the agent's text. */\nfunction Prose({ text, className }) {\n const blocks = String(text ?? \"\").replace(/\\r/g, \"\").split(/\\n{2,}/);\n return (\n <div className={cx(\"grid min-w-0 gap-2 break-words\", className)}>\n {blocks.map((block, b) => {\n const lines = block.split(\"\\n\").filter((l) => l.trim());\n if (!lines.length) return null;\n if (lines.every((l) => LIST_ITEM.test(l))) {\n const ordered = /^\\s*\\d/.test(lines[0]);\n const List = ordered ? \"ol\" : \"ul\";\n return (\n <List key={b} className={cx(\"grid gap-1 pl-5\", ordered ? \"list-decimal\" : \"list-disc\")}>\n {lines.map((l, j) => (\n <li key={j}>{inline(l.replace(LIST_ITEM, \"\"), `${b}-${j}`)}</li>\n ))}\n </List>\n );\n }\n return (\n <p key={b} className=\"whitespace-pre-wrap\">\n {lines.map((l, j) => (\n <Fragment key={j}>\n {j > 0 ? \"\\n\" : null}\n {/^#{1,6}\\s/.test(l) ? <strong>{inline(l.replace(/^#{1,6}\\s+/, \"\"), `${b}-${j}`)}</strong> : inline(l, `${b}-${j}`)}\n </Fragment>\n ))}\n </p>\n );\n })}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n\nfunction StepMark({ status }) {\n if (status === \"done\") return <Icon name=\"check\" size={14} className=\"shrink-0 text-success\" />;\n if (status === \"failed\") return <Icon name=\"warning\" size={14} className=\"shrink-0 text-destructive\" />;\n return <Spinner size=\"sm\" label=\"Working\" className=\"shrink-0 text-muted-foreground\" />;\n}\n\n/** A run of steps: the one running now while the turn works, else one\n * line that opens to the list. */\nfunction Steps({ steps, live }) {\n const [open, setOpen] = useState(false);\n const running = live ? steps.filter((s) => s.status === \"running\").at(-1) : null;\n const count = `${steps.length} ${steps.length === 1 ? \"step\" : \"steps\"}`;\n if (running) {\n return (\n <div className=\"flex min-w-0 items-center gap-2 text-xs text-muted-foreground\">\n <StepMark status=\"running\" />\n <span className=\"min-w-0 truncate\">{running.label}</span>\n {steps.length > 1 ? <span className=\"shrink-0\">· {count}</span> : null}\n </div>\n );\n }\n return (\n <div className=\"min-w-0 text-xs text-muted-foreground\">\n <button\n type=\"button\"\n className=\"flex min-w-0 items-center gap-1.5 rounded-sm hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n >\n <Icon name={open ? \"chevron-down\" : \"chevron-right\"} size={14} className=\"shrink-0\" />\n <span className=\"truncate\">Worked through {count}</span>\n </button>\n {open ? (\n <ul className=\"mt-1.5 grid gap-1 pl-5\">\n {steps.map((s, i) => (\n <li key={i} className=\"flex min-w-0 items-center gap-2\">\n <StepMark status={s.status} />\n <span className=\"min-w-0 truncate\">{s.label}</span>\n </li>\n ))}\n </ul>\n ) : null}\n </div>\n );\n}\n\nfunction MemberWords({ children }) {\n return (\n <div className=\"ml-auto max-w-[85%] min-w-0 whitespace-pre-wrap break-words rounded-[var(--radius)] bg-muted px-2.5 py-1.5\">\n {children}\n </div>\n );\n}\n\n/** One turn: the member's words, then the agent's text and steps in the\n * order they came, steps that follow each other folded into one line. */\nfunction Turn({ turn, last }) {\n const live = last && turn.status === \"working\";\n const groups = [];\n for (const part of turn.parts ?? []) {\n const prev = groups[groups.length - 1];\n if (part.type === \"step\") {\n if (prev?.type === \"steps\") prev.steps.push(part);\n else groups.push({ type: \"steps\", steps: [part] });\n } else if (part.text?.trim()) groups.push(part);\n }\n return (\n <div className=\"grid min-w-0 gap-2\">\n {turn.member ? <MemberWords>{turn.member}</MemberWords> : null}\n {groups.map((g, i) =>\n g.type === \"steps\" ? (\n <Steps key={i} steps={g.steps} live={live && i === groups.length - 1 && !turn.writing} />\n ) : (\n <Prose key={i} text={g.text} />\n ),\n )}\n {turn.writing ? (\n <Prose text={`${turn.writing}▍`} />\n ) : live && !groups.length ? (\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner size=\"sm\" label=\"Working\" /> Thinking…\n </div>\n ) : null}\n {turn.status === \"stopped\" ? <p className=\"text-xs text-muted-foreground\">Stopped.</p> : null}\n {turn.status === \"failed\" ? <p className=\"text-xs text-destructive\">It didn't finish. Ask again, or open it on the desk.</p> : null}\n </div>\n );\n}\n\n/**\n * chat what useAgentThread() returns (required)\n * title the head's words (\"Ask about Pinewood\"); default \"Ask the agent\"\n * suggestions asks that fit the moment, shown before the first ask\n * empty one line before the first ask\n * placeholder the box's words\n * yes a node drawn in the needs slot when the agent waits on a\n * yes the app can take (`chat.needs.in_app === \"press\"`):\n * the `approval` block, fed by useApproval(chat.request.id)\n * (D18). Without it that yes opens the desk\n * onClose a close in the head (a panel beside a record)\n * bare no head (inside a Sheet or a Card that has its own)\n * fill take the height of its container (default). false: a\n * compact chat whose thread scrolls inside a capped height,\n * for a card in a column\n * className layout around it. Never colour.\n */\nexport function AgentChat({\n chat,\n title = \"Ask the agent\",\n suggestions = [],\n empty,\n placeholder,\n yes,\n onClose,\n bare = false,\n fill = true,\n className,\n}) {\n const [text, setText] = useState(\"\");\n const listRef = useRef(null);\n const turns = chat?.turns ?? [];\n const pending = chat?.pending && !turns.some((t) => t.member === chat.pending) ? chat.pending : null;\n const lastTurn = turns[turns.length - 1];\n const writing = lastTurn?.writing ?? \"\";\n const needs = chat?.state === \"needs_you\" ? (chat.needs ?? { kind: \"other\", text: \"\" }) : null;\n const live = chat?.state === \"working\" || chat?.state === \"queued\" || Boolean(pending);\n const started = turns.length > 0 || Boolean(pending);\n const inMakersclaw = chat?.place === \"makersclaw\";\n\n // The newest words stay in view while the agent writes.\n useEffect(() => {\n const el = listRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n }, [turns.length, writing, pending, lastTurn?.parts?.length, chat?.state]);\n\n const send = (words) => {\n const t = String(words ?? text).trim();\n if (!t || !chat?.send) return;\n setText(\"\");\n chat.send(t);\n };\n const answerHere = needs?.in_app === \"answer\" && typeof chat?.answer === \"function\";\n const pressHere = needs?.in_app === \"press\" && yes != null && yes !== false;\n const blocked = Boolean(needs) || inMakersclaw;\n\n return (\n <div className={cx(\"flex min-w-0 flex-col bg-background text-sm\", fill && \"h-full min-h-0\", className)}>\n {!bare ? (\n <div className=\"flex h-10 shrink-0 items-center gap-2 border-b border-border pl-3.5 pr-2 font-semibold\">\n <Icon name=\"sparkles\" size={16} className=\"shrink-0 text-primary\" />\n <span className=\"min-w-0 flex-1 truncate\">{title}</span>\n {started && chat?.newChat ? <IconButton icon=\"plus\" size=\"sm\" label=\"New chat\" onClick={chat.newChat} /> : null}\n {onClose ? <IconButton icon=\"x\" size=\"sm\" label=\"Close\" onClick={onClose} /> : null}\n </div>\n ) : null}\n\n <div\n ref={listRef}\n role=\"log\"\n aria-live=\"polite\"\n aria-label={title}\n className={cx(\n \"grid min-w-0 content-start gap-3 overflow-y-auto overscroll-contain p-3.5\",\n fill ? \"min-h-0 flex-1\" : started ? \"max-h-96\" : \"\",\n )}\n >\n {inMakersclaw ? (\n <Notice\n tone=\"info\"\n title=\"This ask is in Makersclaw\"\n action={\n <Button size=\"sm\" variant=\"secondary\" onClick={() => chat.openOnDesk?.()}>\n Open <Icon name=\"external\" size={12} />\n </Button>\n }\n >\n {chat.request?.title ?? \"It is followed there.\"}\n </Notice>\n ) : (\n <>\n {turns.map((t, i) => (\n <Turn key={t.id ?? i} turn={t} last={i === turns.length - 1 && !pending} />\n ))}\n {pending ? (\n <div className=\"grid min-w-0 gap-2\">\n <MemberWords>{pending}</MemberWords>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner size=\"sm\" label=\"Starting\" /> Starting…\n </div>\n </div>\n ) : null}\n </>\n )}\n {!started && !inMakersclaw ? (\n <>\n {empty ? <p className=\"text-muted-foreground\">{empty}</p> : null}\n {chat?.loading ? (\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Spinner size=\"sm\" label=\"Loading\" /> Opening the chat…\n </div>\n ) : null}\n {suggestions.length ? (\n <div className=\"flex min-w-0 flex-wrap gap-1.5\">\n {suggestions.map((s) => (\n <button\n key={s}\n type=\"button\"\n onClick={() => send(s)}\n className=\"flex max-w-full min-w-0 items-start gap-1.5 rounded-[var(--radius)] border border-border px-2.5 py-1 text-left text-xs hover:bg-muted focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <Icon name=\"sparkles\" size={12} className=\"mt-0.5 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 break-words\">{s}</span>\n </button>\n ))}\n </div>\n ) : null}\n </>\n ) : null}\n </div>\n\n {needs && pressHere ? (\n <div className=\"max-h-[70%] shrink-0 overflow-y-auto border-t border-border p-2.5\">{yes}</div>\n ) : needs ? (\n <div className=\"shrink-0 border-t border-border p-2.5\">\n <div className=\"grid min-w-0 gap-2 rounded-[var(--radius)] border border-warning p-2.5\">\n <div className=\"flex min-w-0 items-start gap-2\">\n <Icon name=\"warning\" size={16} className=\"mt-px shrink-0 text-warning\" />\n <div className=\"grid min-w-0 gap-0.5\">\n <span className=\"font-medium\">{needsTitle(needs.kind, answerHere ? \"answer\" : needs.in_app)}</span>\n {needs.text ? <span className={cx(\"break-words text-muted-foreground\", !answerHere && \"line-clamp-3\")}>{needs.text}</span> : null}\n </div>\n </div>\n {answerHere ? (\n <QuestionBox options={needs.options ?? []} free={needs.free} onAnswer={(payload) => chat.answer(payload)} />\n ) : (\n <Button size=\"sm\" variant=\"primary\" className=\"justify-self-start\" onClick={() => chat.openOnDesk?.()}>\n Open on the desk <Icon name=\"external\" size={12} />\n </Button>\n )}\n </div>\n </div>\n ) : live && !inMakersclaw ? (\n <div className=\"flex shrink-0 items-center gap-2 border-t border-border px-3.5 py-1.5 text-xs text-muted-foreground\">\n <Spinner size=\"sm\" label=\"Working\" />\n <span className=\"min-w-0 flex-1 truncate\">{STATE_LINE[chat?.state] ?? STATE_LINE.working}</span>\n {chat?.request?.id && chat?.stop ? (\n <Button size=\"sm\" variant=\"quiet\" onClick={() => chat.stop()}>\n <Icon name=\"stop\" size={12} /> Stop\n </Button>\n ) : null}\n </div>\n ) : null}\n {chat?.error ? <p className=\"shrink-0 px-3.5 pt-2 text-xs text-destructive\">{chat.error}</p> : null}\n {chat?.unavailable ? (\n <p className=\"shrink-0 px-3.5 pt-2 text-xs text-muted-foreground\">\n This chat needs a newer Makersclaw.{\" \"}\n {chat.request ? (\n <Button variant=\"link\" size=\"inherit\" onClick={() => chat.openOnDesk?.()}>\n Open it on the desk\n </Button>\n ) : null}\n </p>\n ) : null}\n\n <form\n className=\"flex shrink-0 items-end gap-2 border-t border-border px-3 py-2.5\"\n onSubmit={(e) => {\n e.preventDefault();\n send();\n }}\n >\n <Textarea\n aria-label={title}\n autoGrow\n minRows={1}\n maxRows={6}\n placeholder={\n blocked\n ? needs\n ? answerHere\n ? \"Answer above first\"\n : pressHere\n ? \"Say yes above first\"\n : \"Answer on the desk first\"\n : \"This ask is in Makersclaw\"\n : (placeholder ?? \"Ask anything…\")\n }\n value={text}\n disabled={blocked}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey && !e.nativeEvent.isComposing) {\n e.preventDefault();\n send();\n }\n }}\n className=\"min-w-0 flex-1\"\n />\n <IconButton icon=\"arrow-up\" label=\"Send\" variant=\"primary\" size=\"sm\" type=\"submit\" disabled={blocked || !text.trim() || chat?.sending} />\n </form>\n </div>\n );\n}\n"
24
+ },
25
+ {
26
+ "path": "registry/blocks/agent-chat/README.md",
27
+ "type": "registry:file",
28
+ "target": "@components/makersclaw/blocks/agent-chat/README.md",
29
+ "content": "# AgentChat\n\nThe app's own chat with its agent, drawn in the app's look. The member\ntypes; the agent's answer appears as it is written, with one line per\nstep it takes (\"Searching the web\"), folded into \"Worked through 6 steps\"\nonce the turn ends. Stop is one press away while it works.\n\nIt is the same conversation the desk's agent column shows: one session,\ntwo views, never a copy. A member who opens the column on the desk reads\nthe same thread, and either place can continue it.\n\nWhat waits on the member is settled in the chat, where it was asked:\n\n- **The agent's question** is answered in place (0.8.1, D19): its options,\n one press each, and a box for the member's own words where the question\n welcomes them (`chat.answer`). The same checks as the desk's form.\n- **The agent's yes** is the `approval` block's press frame, handed in as\n `yes`. The chat never draws an Approve of its own: the press is\n Makersclaw's, in a frame the app's code cannot script. Without `yes` the\n chat says \"Waiting for your yes on the desk\" with the agent's words and\n \"Open on the desk\".\n- **Connecting an account**, and **money**: on the desk, always, and\n several questions at once.\n\n```jsx\nimport { AgentChat } from \"../components/blocks/agent-chat\"; // a Makersclaw app (\"./blocks/agent-chat\" from components/)\nimport { AgentChat } from \"@/components/makersclaw/blocks/agent-chat\"; // a shadcn project\n```\n\nA client component. It draws the object `useAgentThread()` returns\n(lib/hooks.js); asking stays with the hook. The Example is at the end.\n\n## Tell the desk\n\nAn app that places this block says so in its package: `\"agent_in_app\":\ntrue` in `store.json`'s `seeds.blueprint` (a built app: in its\nblueprint). The desk then keeps its agent column folded for the app, and\nan ask from the app's screens never opens the column by itself; the\ncolumn still opens from the window's Show agent control, on the same\nthread. Without the flag the desk opens its column on every ask, as it\ndid before, and the member sees two agent panes.\n\n## Props\n\n- `chat` — what `useAgentThread()` returns. Required.\n- `title` — the head's words, and the box's label. Default `\"Ask the\n agent\"`. About a record: `\"Ask about Pinewood\"`.\n- `suggestions` — asks that fit the moment, as chips before the first ask.\n A chip sends its words. Long ones wrap; they never run off the column.\n- `empty` — one line before the first ask. Say what the agent can do here,\n in the app's words. Never where the answer appears: it appears here.\n- `placeholder` — the box's words. Default `\"Ask anything…\"`.\n- `yes` — a node drawn in place of the bar when the agent waits on a yes\n the app can take (`chat.needs.in_app === \"press\"`): the `approval`\n block, fed by `useApproval(chat.request.id)`. Hook it only for that\n need: `useApproval(chat.needs?.in_app === \"press\" ? chat.request?.id : null)`.\n- `onClose` — a close in the head, for a panel beside a record.\n- `bare` — no head, inside a `Sheet` or a `Card` that has its own.\n- `fill` — default `true`: the chat takes its container's height (a\n panel, a sheet) and the thread scrolls inside it. `false`: a compact\n chat for a card in a column (an inspector, a home screen's side): it is\n as tall as its content, and once a thread starts it scrolls inside a\n capped height.\n- `className` — layout around it. Never colour.\n\n## useAgentThread (lib/hooks.js)\n\n```js\nconst chat = useAgentThread({ row, how, job, key });\n```\n\n- `row` — the record the chat is about, `{ kind, id, name }`. It rides\n with every ask as context, and the thread is kept for it: open the same\n record again and its chat is there.\n- `how` — instructions for the agent only.\n- `job` — a declared job's key, or `true`. Default none: a chat is a\n conversation, not a job.\n- `key` — where this browser keeps the thread (default the row's\n `kind:id`, else `\"app\"`); `null` keeps none.\n\nIt returns `sessionId`, `state` (`queued` · `working` · `needs_you` ·\n`done` · `stopped` · `failed`, or null before the first ask), `needs`\n(`{ kind, text, at, in_app, options?, free? }` while it waits on the\nmember: `in_app` is `\"answer\"`, `\"press\"` or null for the desk), `turns`, `pending`,\n`place` (`\"makersclaw\"` for an ask made in Makersclaw: the chat shows a\npointer, not the turns), `request`, `sending`, `loading`, `error`,\n`unavailable`, and `send(text)`, `stop()`, `answer({ optionId | text })`,\n`openOnDesk()`, `newChat()`, `reload()`.\n\nIt reads `GET _claw/threads/<session>` (lib/platform.js `thread`): the\nmember's own thread in this app, never a teammate's. It looks every\n1.5 s while the agent works, every 6 s while it waits on the member, and\nnot at all once the turn has ended or the page is hidden.\n\n## Outside Makersclaw\n\nAny object of the same shape works: `turns` (`[{ id, member, parts:\n[{ type: \"text\", text } | { type: \"step\", label, status }], writing,\nstatus }]`), `state`, `needs`, `pending`, and the five functions.\n\n## Example\n\nA chat about the person a screen has open, beside the record.\n\n```jsx\n\"use client\";\nimport { useAgentThread } from \"../lib/hooks\";\nimport { AgentChat } from \"../components/blocks/agent-chat\";\n\nexport default function PersonAsk({ person }) {\n const chat = useAgentThread({ row: { kind: \"person\", id: person.id, name: person.name } });\n return (\n <AgentChat\n chat={chat}\n title={`Ask about ${person.name}`}\n suggestions={[\"What did we last talk about?\", \"Draft a follow-up\"]}\n />\n );\n}\n```\n\nOn a home screen, the same chat as a card in the side column: `fill={false}` and `bare`\ninside a `Card` that has its own title.\n\nA chat that settles what waits on the member in place: the question\nanswered in the chat, the yes pressed in the approval card above it.\n\n```jsx\n\"use client\";\nimport { useAgentThread, useApproval } from \"../lib/hooks\";\nimport { AgentChat } from \"../components/blocks/agent-chat\";\nimport { Approval } from \"../components/blocks/approval\";\n\nexport default function Ask() {\n const chat = useAgentThread();\n // Only for the one ask's yes; useApproval(null) asks nothing.\n const approval = useApproval(chat.needs?.in_app === \"press\" ? chat.request?.id : null);\n return (\n <AgentChat\n chat={chat}\n yes={<Approval approval={approval} title=\"Waiting for your yes\" onOpenDesk={chat.openOnDesk} />}\n />\n );\n}\n```\n"
30
+ }
31
+ ],
32
+ "categories": [
33
+ "chat",
34
+ "ask",
35
+ "assistant",
36
+ "conversation",
37
+ "thread",
38
+ "messages",
39
+ "ai",
40
+ "copilot",
41
+ "stop",
42
+ "needs-you",
43
+ "inspector",
44
+ "record"
45
+ ],
46
+ "docs": "Installed to components/makersclaw/blocks/agent-chat. Import: import { AgentChat } from \"@/components/makersclaw/blocks/agent-chat\". Props and an example: components/makersclaw/blocks/agent-chat/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
47
+ "meta": {
48
+ "makersclaw": {
49
+ "version": "0.8.1",
50
+ "useWhen": "The app should hold its conversation with its agent: an Ask panel beside a record, an ask box on a home screen, a sheet behind an Ask button. Place it and set \"agent_in_app\": true in the package's blueprint, so the desk keeps its agent column folded for the app. For work the founder commissions from a verb and watches land, use job-panel."
51
+ }
52
+ }
53
+ }