makersclaw 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (401) hide show
  1. package/README.md +9 -3
  2. package/package.json +1 -1
  3. package/r/activity-log.json +52 -0
  4. package/r/agent-changes.json +51 -0
  5. package/r/agent-chat.json +53 -0
  6. package/r/agent-column.json +85 -0
  7. package/r/agent-dock.json +57 -0
  8. package/r/agent-kit.json +49 -0
  9. package/r/agent-marks.json +49 -0
  10. package/r/agent-pane.json +93 -0
  11. package/r/ai-action.json +56 -0
  12. package/r/annotate.json +3 -3
  13. package/r/approval-request.json +2 -2
  14. package/r/approval.json +54 -0
  15. package/r/ask-bar.json +50 -0
  16. package/r/audio-player.json +2 -2
  17. package/r/auth-form.json +2 -2
  18. package/r/automation-editor.json +66 -0
  19. package/r/automation-list.json +57 -0
  20. package/r/automation-model.json +118 -0
  21. package/r/automations-screen.json +71 -0
  22. package/r/board.json +2 -2
  23. package/r/calendar-view.json +3 -3
  24. package/r/cart.json +2 -2
  25. package/r/chart.json +2 -2
  26. package/r/chat-pane.json +84 -0
  27. package/r/chat.json +2 -2
  28. package/r/code-editor.json +2 -2
  29. package/r/comment-box.json +3 -3
  30. package/r/connect-card.json +51 -0
  31. package/r/contact-section.json +2 -2
  32. package/r/core.json +13 -7
  33. package/r/cost.json +51 -0
  34. package/r/csv-import.json +3 -3
  35. package/r/data-picker.json +60 -0
  36. package/r/data-table.json +2 -2
  37. package/r/diagram.json +2 -2
  38. package/r/doc-editor.json +2 -2
  39. package/r/doc-page.json +3 -3
  40. package/r/email-render.json +2 -2
  41. package/r/faq.json +2 -2
  42. package/r/file-upload.json +2 -2
  43. package/r/first-run.json +63 -0
  44. package/r/fix-note.json +57 -0
  45. package/r/flow-canvas.json +2 -2
  46. package/r/flow-editor.json +79 -0
  47. package/r/footer.json +2 -2
  48. package/r/gantt.json +3 -3
  49. package/r/job-panel.json +2 -2
  50. package/r/json-editor.json +3 -3
  51. package/r/library-shelf.json +56 -0
  52. package/r/map.json +2 -2
  53. package/r/margin-notes.json +67 -0
  54. package/r/menubar.json +2 -2
  55. package/r/mind-map.json +3 -3
  56. package/r/navigation-menu.json +2 -2
  57. package/r/needs-you.json +55 -0
  58. package/r/order-detail.json +2 -2
  59. package/r/org-chart.json +3 -3
  60. package/r/pace-bar.json +69 -0
  61. package/r/page-builder.json +2 -2
  62. package/r/payment-methods.json +2 -2
  63. package/r/pdf-document.json +2 -2
  64. package/r/pdf-viewer.json +2 -2
  65. package/r/product-detail.json +2 -2
  66. package/r/product-grid.json +3 -3
  67. package/r/record-form.json +2 -2
  68. package/r/record-grid.json +52 -0
  69. package/r/record-notes.json +4 -4
  70. package/r/registry.json +4086 -1512
  71. package/r/run-history.json +52 -0
  72. package/r/run-view.json +80 -0
  73. package/r/schedule-card.json +54 -0
  74. package/r/schedule-engine.json +79 -0
  75. package/r/schedule-gantt.json +83 -0
  76. package/r/schedule-ruler.json +64 -0
  77. package/r/search-dialog.json +2 -2
  78. package/r/settings-list.json +2 -2
  79. package/r/setup-checklist.json +2 -2
  80. package/r/share-dialog.json +2 -2
  81. package/r/sidebar.json +2 -2
  82. package/r/signature-pad.json +2 -2
  83. package/r/sketch-canvas.json +2 -2
  84. package/r/source-receipt.json +52 -0
  85. package/r/spreadsheet.json +3 -3
  86. package/r/stat-cards.json +3 -3
  87. package/r/step-picker.json +53 -0
  88. package/r/step-settings.json +72 -0
  89. package/r/suggestion.json +58 -0
  90. package/r/sum-bar.json +64 -0
  91. package/r/task-list.json +3 -3
  92. package/r/task-model.json +2 -2
  93. package/r/testimonials.json +2 -2
  94. package/r/tier-map.json +67 -0
  95. package/r/time-grid.json +73 -0
  96. package/r/time-strip.json +64 -0
  97. package/r/top-bar.json +66 -0
  98. package/r/transaction-list.json +2 -2
  99. package/r/trigger-picker.json +61 -0
  100. package/r/whiteboard.json +3 -3
  101. package/r/workflow-view.json +55 -0
  102. package/registry/blocks/activity-log/README.md +112 -0
  103. package/registry/blocks/activity-log/activity-log.jsx +351 -0
  104. package/registry/blocks/activity-log/block.json +33 -0
  105. package/registry/blocks/activity-log/demo.jsx +48 -0
  106. package/registry/blocks/activity-log/index.js +4 -0
  107. package/registry/blocks/agent-changes/README.md +94 -0
  108. package/registry/blocks/agent-changes/agent-changes.jsx +118 -0
  109. package/registry/blocks/agent-changes/block.json +28 -0
  110. package/registry/blocks/agent-changes/demo.jsx +39 -0
  111. package/registry/blocks/agent-changes/index.js +3 -0
  112. package/registry/blocks/agent-chat/README.md +145 -0
  113. package/registry/blocks/agent-chat/agent-chat.jsx +415 -0
  114. package/registry/blocks/agent-chat/block.json +30 -0
  115. package/registry/blocks/agent-chat/demo.jsx +165 -0
  116. package/registry/blocks/agent-chat/index.js +3 -0
  117. package/registry/blocks/agent-column/README.md +197 -0
  118. package/registry/blocks/agent-column/agent-column.jsx +492 -0
  119. package/registry/blocks/agent-column/block.json +67 -0
  120. package/registry/blocks/agent-column/column-picker.jsx +163 -0
  121. package/registry/blocks/agent-column/demo.jsx +50 -0
  122. package/registry/blocks/agent-column/index.js +7 -0
  123. package/registry/blocks/agent-column/model.js +164 -0
  124. package/registry/blocks/agent-column/receipt.jsx +483 -0
  125. package/registry/blocks/agent-column/spreadsheet-type.jsx +24 -0
  126. package/registry/blocks/agent-dock/README.md +210 -0
  127. package/registry/blocks/agent-dock/agent-dock.jsx +356 -0
  128. package/registry/blocks/agent-dock/block.json +47 -0
  129. package/registry/blocks/agent-dock/demo.jsx +153 -0
  130. package/registry/blocks/agent-dock/dock-model.js +118 -0
  131. package/registry/blocks/agent-dock/index.js +5 -0
  132. package/registry/blocks/agent-kit/README.md +73 -0
  133. package/registry/blocks/agent-kit/agent-kit.jsx +86 -0
  134. package/registry/blocks/agent-kit/block.json +10 -0
  135. package/registry/blocks/agent-kit/demo.jsx +35 -0
  136. package/registry/blocks/agent-kit/index.js +3 -0
  137. package/registry/blocks/agent-marks/README.md +80 -0
  138. package/registry/blocks/agent-marks/agent-marks.jsx +133 -0
  139. package/registry/blocks/agent-marks/block.json +27 -0
  140. package/registry/blocks/agent-marks/demo.jsx +49 -0
  141. package/registry/blocks/agent-marks/index.js +3 -0
  142. package/registry/blocks/agent-pane/README.md +225 -0
  143. package/registry/blocks/agent-pane/agent-pane.jsx +244 -0
  144. package/registry/blocks/agent-pane/block.json +41 -0
  145. package/registry/blocks/agent-pane/composer.jsx +6 -0
  146. package/registry/blocks/agent-pane/demo.jsx +233 -0
  147. package/registry/blocks/agent-pane/dock-context.js +10 -0
  148. package/registry/blocks/agent-pane/index.js +4 -0
  149. package/registry/blocks/agent-pane/prose.jsx +84 -0
  150. package/registry/blocks/agent-pane/questions.jsx +134 -0
  151. package/registry/blocks/agent-pane/transcript.jsx +268 -0
  152. package/registry/blocks/agent-pane/work.jsx +368 -0
  153. package/registry/blocks/ai-action/README.md +94 -0
  154. package/registry/blocks/ai-action/ai-action.jsx +188 -0
  155. package/registry/blocks/ai-action/block.json +34 -0
  156. package/registry/blocks/ai-action/demo.jsx +93 -0
  157. package/registry/blocks/ai-action/index.js +3 -0
  158. package/registry/blocks/approval/README.md +145 -0
  159. package/registry/blocks/approval/approval.jsx +163 -0
  160. package/registry/blocks/approval/block.json +31 -0
  161. package/registry/blocks/approval/demo.jsx +121 -0
  162. package/registry/blocks/approval/index.js +3 -0
  163. package/registry/blocks/ask-bar/README.md +105 -0
  164. package/registry/blocks/ask-bar/ask-bar.jsx +166 -0
  165. package/registry/blocks/ask-bar/block.json +26 -0
  166. package/registry/blocks/ask-bar/demo.jsx +78 -0
  167. package/registry/blocks/ask-bar/index.js +3 -0
  168. package/registry/blocks/automation-editor/README.md +291 -0
  169. package/registry/blocks/automation-editor/automation-editor.jsx +656 -0
  170. package/registry/blocks/automation-editor/block.json +39 -0
  171. package/registry/blocks/automation-editor/demo.jsx +284 -0
  172. package/registry/blocks/automation-editor/index.js +4 -0
  173. package/registry/blocks/automation-editor/run-inputs.jsx +82 -0
  174. package/registry/blocks/automation-list/README.md +129 -0
  175. package/registry/blocks/automation-list/automation-list.jsx +476 -0
  176. package/registry/blocks/automation-list/block.json +35 -0
  177. package/registry/blocks/automation-list/demo.jsx +67 -0
  178. package/registry/blocks/automation-list/index.js +3 -0
  179. package/registry/blocks/automation-model/README.md +109 -0
  180. package/registry/blocks/automation-model/block.json +135 -0
  181. package/registry/blocks/automation-model/catalog.js +256 -0
  182. package/registry/blocks/automation-model/check.js +161 -0
  183. package/registry/blocks/automation-model/demo.jsx +42 -0
  184. package/registry/blocks/automation-model/edit.js +262 -0
  185. package/registry/blocks/automation-model/fixes.js +287 -0
  186. package/registry/blocks/automation-model/glyph.jsx +13 -0
  187. package/registry/blocks/automation-model/graph.js +410 -0
  188. package/registry/blocks/automation-model/index.js +33 -0
  189. package/registry/blocks/automation-model/overlay.js +175 -0
  190. package/registry/blocks/automation-model/parts.jsx +94 -0
  191. package/registry/blocks/automation-model/schedule.js +53 -0
  192. package/registry/blocks/automation-model/templates.js +128 -0
  193. package/registry/blocks/automation-model/values.js +29 -0
  194. package/registry/blocks/automation-model/words.js +439 -0
  195. package/registry/blocks/automations-screen/README.md +207 -0
  196. package/registry/blocks/automations-screen/automations-screen.jsx +452 -0
  197. package/registry/blocks/automations-screen/block.json +47 -0
  198. package/registry/blocks/automations-screen/demo.jsx +364 -0
  199. package/registry/blocks/automations-screen/index.js +4 -0
  200. package/registry/blocks/automations-screen/screen-model.js +129 -0
  201. package/registry/blocks/chat-pane/README.md +143 -0
  202. package/registry/blocks/chat-pane/block.json +48 -0
  203. package/registry/blocks/chat-pane/chat-attach.js +166 -0
  204. package/registry/blocks/chat-pane/chat-composer.jsx +195 -0
  205. package/registry/blocks/chat-pane/chat-context.js +17 -0
  206. package/registry/blocks/chat-pane/chat-model.js +43 -0
  207. package/registry/blocks/chat-pane/chat-pane.jsx +398 -0
  208. package/registry/blocks/chat-pane/chats-list.jsx +52 -0
  209. package/registry/blocks/chat-pane/demo.jsx +103 -0
  210. package/registry/blocks/chat-pane/index.js +9 -0
  211. package/registry/blocks/connect-card/README.md +99 -0
  212. package/registry/blocks/connect-card/block.json +10 -0
  213. package/registry/blocks/connect-card/connect-card.jsx +103 -0
  214. package/registry/blocks/connect-card/demo.jsx +49 -0
  215. package/registry/blocks/connect-card/index.js +3 -0
  216. package/registry/blocks/cost/README.md +115 -0
  217. package/registry/blocks/cost/block.json +10 -0
  218. package/registry/blocks/cost/cost.jsx +176 -0
  219. package/registry/blocks/cost/demo.jsx +66 -0
  220. package/registry/blocks/cost/index.js +3 -0
  221. package/registry/blocks/data-picker/README.md +81 -0
  222. package/registry/blocks/data-picker/block.json +38 -0
  223. package/registry/blocks/data-picker/data-picker.jsx +210 -0
  224. package/registry/blocks/data-picker/demo.jsx +34 -0
  225. package/registry/blocks/data-picker/fields.js +89 -0
  226. package/registry/blocks/data-picker/index.js +4 -0
  227. package/registry/blocks/data-table/demo.jsx +1 -1
  228. package/registry/blocks/first-run/README.md +118 -0
  229. package/registry/blocks/first-run/block.json +11 -0
  230. package/registry/blocks/first-run/demo.jsx +88 -0
  231. package/registry/blocks/first-run/first-run-model.js +51 -0
  232. package/registry/blocks/first-run/first-run.jsx +156 -0
  233. package/registry/blocks/first-run/index.js +5 -0
  234. package/registry/blocks/first-run/probe-rules.js +26 -0
  235. package/registry/blocks/fix-note/README.md +79 -0
  236. package/registry/blocks/fix-note/block.json +35 -0
  237. package/registry/blocks/fix-note/demo.jsx +30 -0
  238. package/registry/blocks/fix-note/fix-note.jsx +235 -0
  239. package/registry/blocks/fix-note/index.js +3 -0
  240. package/registry/blocks/flow-editor/README.md +108 -0
  241. package/registry/blocks/flow-editor/block.json +44 -0
  242. package/registry/blocks/flow-editor/demo.jsx +115 -0
  243. package/registry/blocks/flow-editor/flow-canvas.jsx +568 -0
  244. package/registry/blocks/flow-editor/flow-editor.jsx +154 -0
  245. package/registry/blocks/flow-editor/index.js +6 -0
  246. package/registry/blocks/flow-editor/minimap.jsx +78 -0
  247. package/registry/blocks/flow-editor/outline.jsx +134 -0
  248. package/registry/blocks/library-shelf/README.md +117 -0
  249. package/registry/blocks/library-shelf/block.json +28 -0
  250. package/registry/blocks/library-shelf/demo.jsx +68 -0
  251. package/registry/blocks/library-shelf/index.js +3 -0
  252. package/registry/blocks/library-shelf/library-shelf.jsx +211 -0
  253. package/registry/blocks/library-shelf/probe-rules.js +15 -0
  254. package/registry/blocks/margin-notes/README.md +222 -0
  255. package/registry/blocks/margin-notes/block.json +10 -0
  256. package/registry/blocks/margin-notes/demo.jsx +144 -0
  257. package/registry/blocks/margin-notes/index.js +20 -0
  258. package/registry/blocks/margin-notes/margin-model.js +224 -0
  259. package/registry/blocks/margin-notes/margin-notes.jsx +465 -0
  260. package/registry/blocks/needs-you/README.md +177 -0
  261. package/registry/blocks/needs-you/block.json +34 -0
  262. package/registry/blocks/needs-you/demo.jsx +143 -0
  263. package/registry/blocks/needs-you/index.js +3 -0
  264. package/registry/blocks/needs-you/needs-you.jsx +441 -0
  265. package/registry/blocks/pace-bar/README.md +230 -0
  266. package/registry/blocks/pace-bar/block.json +10 -0
  267. package/registry/blocks/pace-bar/demo.jsx +255 -0
  268. package/registry/blocks/pace-bar/index.js +22 -0
  269. package/registry/blocks/pace-bar/pace-bar.jsx +461 -0
  270. package/registry/blocks/pace-bar/pace-model.js +288 -0
  271. package/registry/blocks/record-grid/README.md +100 -0
  272. package/registry/blocks/record-grid/block.json +28 -0
  273. package/registry/blocks/record-grid/demo.jsx +43 -0
  274. package/registry/blocks/record-grid/index.js +3 -0
  275. package/registry/blocks/record-grid/record-grid.jsx +251 -0
  276. package/registry/blocks/run-history/README.md +138 -0
  277. package/registry/blocks/run-history/block.json +10 -0
  278. package/registry/blocks/run-history/demo.jsx +74 -0
  279. package/registry/blocks/run-history/index.js +3 -0
  280. package/registry/blocks/run-history/run-history.jsx +218 -0
  281. package/registry/blocks/run-view/README.md +174 -0
  282. package/registry/blocks/run-view/block.json +50 -0
  283. package/registry/blocks/run-view/demo.jsx +286 -0
  284. package/registry/blocks/run-view/index.js +5 -0
  285. package/registry/blocks/run-view/run-controls.jsx +266 -0
  286. package/registry/blocks/run-view/run-view.jsx +236 -0
  287. package/registry/blocks/run-view/runs-list.jsx +99 -0
  288. package/registry/blocks/schedule-card/README.md +121 -0
  289. package/registry/blocks/schedule-card/block.json +10 -0
  290. package/registry/blocks/schedule-card/demo.jsx +82 -0
  291. package/registry/blocks/schedule-card/index.js +3 -0
  292. package/registry/blocks/schedule-card/schedule-card.jsx +136 -0
  293. package/registry/blocks/schedule-engine/README.md +137 -0
  294. package/registry/blocks/schedule-engine/block.json +10 -0
  295. package/registry/blocks/schedule-engine/demo.jsx +82 -0
  296. package/registry/blocks/schedule-engine/engine.js +769 -0
  297. package/registry/blocks/schedule-engine/index.js +9 -0
  298. package/registry/blocks/schedule-engine/ops.js +71 -0
  299. package/registry/blocks/schedule-engine/place.js +294 -0
  300. package/registry/blocks/schedule-engine/tree.js +79 -0
  301. package/registry/blocks/schedule-engine/waits.js +80 -0
  302. package/registry/blocks/schedule-gantt/README.md +159 -0
  303. package/registry/blocks/schedule-gantt/block.json +10 -0
  304. package/registry/blocks/schedule-gantt/demo.jsx +223 -0
  305. package/registry/blocks/schedule-gantt/gantt-model.js +219 -0
  306. package/registry/blocks/schedule-gantt/geometry.js +176 -0
  307. package/registry/blocks/schedule-gantt/index.js +26 -0
  308. package/registry/blocks/schedule-gantt/schedule-gantt.jsx +882 -0
  309. package/registry/blocks/schedule-gantt/sheet.jsx +372 -0
  310. package/registry/blocks/schedule-gantt/track.jsx +190 -0
  311. package/registry/blocks/schedule-ruler/README.md +148 -0
  312. package/registry/blocks/schedule-ruler/block.json +10 -0
  313. package/registry/blocks/schedule-ruler/demo.jsx +181 -0
  314. package/registry/blocks/schedule-ruler/index.js +21 -0
  315. package/registry/blocks/schedule-ruler/ruler-model.js +239 -0
  316. package/registry/blocks/schedule-ruler/schedule-ruler.jsx +548 -0
  317. package/registry/blocks/source-receipt/README.md +97 -0
  318. package/registry/blocks/source-receipt/block.json +30 -0
  319. package/registry/blocks/source-receipt/demo.jsx +71 -0
  320. package/registry/blocks/source-receipt/index.js +3 -0
  321. package/registry/blocks/source-receipt/source-receipt.jsx +107 -0
  322. package/registry/blocks/spreadsheet/spreadsheet.jsx +15 -1
  323. package/registry/blocks/step-picker/README.md +78 -0
  324. package/registry/blocks/step-picker/block.json +31 -0
  325. package/registry/blocks/step-picker/demo.jsx +23 -0
  326. package/registry/blocks/step-picker/index.js +3 -0
  327. package/registry/blocks/step-picker/step-picker.jsx +144 -0
  328. package/registry/blocks/step-settings/README.md +100 -0
  329. package/registry/blocks/step-settings/block.json +44 -0
  330. package/registry/blocks/step-settings/demo.jsx +93 -0
  331. package/registry/blocks/step-settings/fields.jsx +58 -0
  332. package/registry/blocks/step-settings/flow-settings.jsx +115 -0
  333. package/registry/blocks/step-settings/index.js +5 -0
  334. package/registry/blocks/step-settings/step-settings.jsx +290 -0
  335. package/registry/blocks/suggestion/README.md +171 -0
  336. package/registry/blocks/suggestion/block.json +40 -0
  337. package/registry/blocks/suggestion/demo.jsx +91 -0
  338. package/registry/blocks/suggestion/index.js +3 -0
  339. package/registry/blocks/suggestion/suggestion.jsx +436 -0
  340. package/registry/blocks/sum-bar/README.md +122 -0
  341. package/registry/blocks/sum-bar/block.json +10 -0
  342. package/registry/blocks/sum-bar/demo.jsx +110 -0
  343. package/registry/blocks/sum-bar/index.js +5 -0
  344. package/registry/blocks/sum-bar/sum-bar.jsx +209 -0
  345. package/registry/blocks/sum-bar/sum-model.js +126 -0
  346. package/registry/blocks/tier-map/README.md +217 -0
  347. package/registry/blocks/tier-map/block.json +10 -0
  348. package/registry/blocks/tier-map/demo.jsx +222 -0
  349. package/registry/blocks/tier-map/index.js +24 -0
  350. package/registry/blocks/tier-map/tier-map.jsx +574 -0
  351. package/registry/blocks/tier-map/tier-model.js +318 -0
  352. package/registry/blocks/time-grid/README.md +305 -0
  353. package/registry/blocks/time-grid/block.json +10 -0
  354. package/registry/blocks/time-grid/demo.jsx +279 -0
  355. package/registry/blocks/time-grid/grid-model.js +322 -0
  356. package/registry/blocks/time-grid/index.js +25 -0
  357. package/registry/blocks/time-grid/time-grid.jsx +1325 -0
  358. package/registry/blocks/time-strip/README.md +141 -0
  359. package/registry/blocks/time-strip/block.json +10 -0
  360. package/registry/blocks/time-strip/demo.jsx +129 -0
  361. package/registry/blocks/time-strip/index.js +19 -0
  362. package/registry/blocks/time-strip/strip-model.js +178 -0
  363. package/registry/blocks/time-strip/time-strip.jsx +260 -0
  364. package/registry/blocks/top-bar/README.md +149 -0
  365. package/registry/blocks/top-bar/block.json +35 -0
  366. package/registry/blocks/top-bar/demo.jsx +78 -0
  367. package/registry/blocks/top-bar/index.js +5 -0
  368. package/registry/blocks/top-bar/probe-rules.js +74 -0
  369. package/registry/blocks/top-bar/top-bar-model.js +152 -0
  370. package/registry/blocks/top-bar/top-bar.jsx +244 -0
  371. package/registry/blocks/trigger-picker/README.md +98 -0
  372. package/registry/blocks/trigger-picker/block.json +38 -0
  373. package/registry/blocks/trigger-picker/demo.jsx +59 -0
  374. package/registry/blocks/trigger-picker/index.js +3 -0
  375. package/registry/blocks/trigger-picker/trigger-picker.jsx +374 -0
  376. package/registry/blocks/workflow-view/README.md +123 -0
  377. package/registry/blocks/workflow-view/block.json +10 -0
  378. package/registry/blocks/workflow-view/demo.jsx +90 -0
  379. package/registry/blocks/workflow-view/index.js +3 -0
  380. package/registry/blocks/workflow-view/workflow-view.jsx +203 -0
  381. package/src/install.mjs +77 -16
  382. package/src/registry.mjs +3 -0
  383. package/templates/next/browser/lib/data.js +6 -1
  384. package/templates/next/files/README.md +627 -24
  385. package/templates/next/files/check/automation-format.ts +2103 -0
  386. package/templates/next/files/check/automation-package.ts +142 -0
  387. package/templates/next/files/check/run.mjs +968 -9
  388. package/templates/next/files/components/ui/field.jsx +17 -4
  389. package/templates/next/files/components/ui/icon.jsx +13 -0
  390. package/templates/next/files/components/ui/index.js +2 -1
  391. package/templates/next/files/components/ui/layout.jsx +77 -2
  392. package/templates/next/files/components/ui/notice.jsx +70 -0
  393. package/templates/next/files/components/ui/page.jsx +124 -0
  394. package/templates/next/files/components/ui/stat.jsx +22 -7
  395. package/templates/next/files/components/ui/toast.jsx +6 -3
  396. package/templates/next/files/lib/automations.js +660 -0
  397. package/templates/next/files/lib/claw.js +241 -5
  398. package/templates/next/files/lib/door.js +92 -0
  399. package/templates/next/files/lib/hooks.js +1627 -8
  400. package/templates/next/files/lib/platform.js +529 -21
  401. package/templates/next/template.json +13 -3
@@ -0,0 +1,368 @@
1
+ "use client";
2
+
3
+ import { Fragment, useEffect, useRef, useState } from "react";
4
+ import { Button, Icon, Spinner, cx } from "../../ui";
5
+
6
+ // The agent's work, as the desk's sidebar draws it (D27): the steps
7
+ // between two things the agent said are ONE line, "Worked through 26
8
+ // steps", or the step under way with a spinner; it opens to one line per
9
+ // step — a mono tag, what happened in words, a status word — and a step
10
+ // opens to its facts, the command or statement worth reading, what came
11
+ // back and why it failed. Reads fold ("Read 6 files"), retries a later
12
+ // call fixed fold ("Fixed 2 issues on the way"), the same line again is
13
+ // one line with a count, helpers started side by side are a card.
14
+ //
15
+ // What the lines SAY and which lines there are is decided by the platform
16
+ // (the rules the sidebar runs); this file only draws them, from the data
17
+ // useAgentPane() hands over. A step's detail is asked for when it opens
18
+ // (`load`), never carried with the line.
19
+
20
+ const plural = (n, one, many) => (n === 1 ? `1 ${one}` : `${n} ${many}`);
21
+
22
+ const STATUS_WORD = { failed: "didn’t work", interrupted: "stopped", denied: "not allowed" };
23
+
24
+ /** Seconds since `running` went true; 0 while it is not. */
25
+ function useElapsed(running) {
26
+ const start = useRef(null);
27
+ const [seconds, setSeconds] = useState(0);
28
+ useEffect(() => {
29
+ if (!running) return undefined;
30
+ start.current ??= Date.now();
31
+ const id = setInterval(() => setSeconds(Math.round((Date.now() - start.current) / 1000)), 1000);
32
+ return () => clearInterval(id);
33
+ }, [running]);
34
+ return running ? seconds : 0;
35
+ }
36
+
37
+ function Tag({ children }) {
38
+ return (
39
+ <span className="shrink-0 rounded-sm bg-muted px-1.5 py-0.5 font-mono text-[10px] font-medium uppercase tracking-wide text-muted-foreground">
40
+ {children}
41
+ </span>
42
+ );
43
+ }
44
+
45
+ function Chevron({ open }) {
46
+ return <Icon name={open ? "chevron-down" : "chevron-right"} size={12} className="shrink-0 text-muted-foreground" />;
47
+ }
48
+
49
+ /** The row's button: tag, words, a word for how it ended, a chevron. */
50
+ function Line({ tag, children, status, open, onToggle, running, elapsed, word, kind }) {
51
+ return (
52
+ <button
53
+ type="button"
54
+ aria-expanded={open}
55
+ data-status={status}
56
+ onClick={onToggle}
57
+ className={cx(
58
+ "flex w-full min-w-0 items-center gap-2 rounded-md px-1.5 py-1 text-left text-xs hover:bg-muted focus-visible:outline-2 focus-visible:outline-ring",
59
+ status === "failed" || status === "denied" ? "text-destructive" : "text-muted-foreground",
60
+ kind === "fixed" && "text-success",
61
+ )}
62
+ >
63
+ <Tag>{tag}</Tag>
64
+ <span className="min-w-0 flex-1 truncate">{children}</span>
65
+ {running && elapsed >= 3 ? <span className="shrink-0 tabular-nums">{elapsed}s</span> : null}
66
+ {running ? <Spinner size="sm" label="Working" className="shrink-0" /> : null}
67
+ {word ? <span className="shrink-0">{word}</span> : null}
68
+ <Chevron open={open} />
69
+ </button>
70
+ );
71
+ }
72
+
73
+ /* ---- one step, opened ------------------------------------------------ */
74
+
75
+ function Pre({ children }) {
76
+ return (
77
+ <pre className="max-h-48 overflow-auto rounded-md bg-muted p-2 font-mono text-[11px] leading-relaxed whitespace-pre-wrap break-words text-foreground">
78
+ {children}
79
+ </pre>
80
+ );
81
+ }
82
+
83
+ /** What a step opens to: asked for once, when it opens. */
84
+ function Detail({ id, load, reason, status }) {
85
+ const [got, setGot] = useState(load ? { state: "loading" } : { state: "none" });
86
+ useEffect(() => {
87
+ if (!load) return undefined;
88
+ let alive = true;
89
+ Promise.resolve(load(id)).then(
90
+ (r) => {
91
+ if (alive) setGot(r?.ok && r.data?.call ? { state: "ok", call: r.data.call } : { state: "error" });
92
+ },
93
+ () => {
94
+ if (alive) setGot({ state: "error" });
95
+ },
96
+ );
97
+ return () => {
98
+ alive = false;
99
+ };
100
+ }, [id, load]);
101
+
102
+ const call = got.call;
103
+ const facts = call?.facts ?? [];
104
+ const empty = got.state === "ok" && !facts.length && !call.code && !call.result && !call.said && !reason;
105
+ return (
106
+ <div className="grid min-w-0 gap-2 rounded-md border border-border bg-card px-2.5 py-2 text-xs">
107
+ {status === "failed" && reason ? <p className="text-destructive">{reason}</p> : null}
108
+ {got.state === "loading" ? (
109
+ <p className="flex items-center gap-2 text-muted-foreground">
110
+ <Spinner size="sm" label="Loading" /> Opening this step…
111
+ </p>
112
+ ) : null}
113
+ {got.state === "error" ? <p className="text-muted-foreground">This step can’t be opened just now.</p> : null}
114
+ {got.state === "ok" && call.said ? (
115
+ <div className="grid gap-1">
116
+ <span className="text-[11px] text-muted-foreground">What it said</span>
117
+ <Pre>{call.said}</Pre>
118
+ </div>
119
+ ) : null}
120
+ {facts.length ? (
121
+ <dl className="grid min-w-0 grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1">
122
+ {facts.map((f, i) => (
123
+ <Fragment key={`${f.label}-${i}`}>
124
+ <dt className="text-muted-foreground">{f.label}</dt>
125
+ <dd className="min-w-0 break-words">{f.value}</dd>
126
+ </Fragment>
127
+ ))}
128
+ </dl>
129
+ ) : null}
130
+ {got.state === "ok" && call.code ? (
131
+ <div className="grid gap-1">
132
+ <span className="text-[11px] text-muted-foreground">{call.code.label}</span>
133
+ <Pre>{call.code.text}</Pre>
134
+ </div>
135
+ ) : null}
136
+ {got.state === "ok" && call.result ? (
137
+ <div className="grid gap-1">
138
+ <span className="text-[11px] text-muted-foreground">What came back</span>
139
+ <Pre>{call.result}</Pre>
140
+ </div>
141
+ ) : null}
142
+ {empty ? <p className="text-muted-foreground">{status === "running" ? "Still working on this." : "Nothing more to show."}</p> : null}
143
+ </div>
144
+ );
145
+ }
146
+
147
+ /* ---- the rows --------------------------------------------------------- */
148
+
149
+ function CallRow({ call, live, load, onOpenRequest }) {
150
+ const [open, setOpen] = useState(false);
151
+ const running = call.status === "running" && live;
152
+ const elapsed = useElapsed(running);
153
+ return (
154
+ <div data-call={call.id} className="grid min-w-0 gap-1">
155
+ <Line
156
+ tag={call.tag}
157
+ status={call.status}
158
+ open={open}
159
+ onToggle={() => setOpen((o) => !o)}
160
+ running={running}
161
+ elapsed={elapsed}
162
+ word={call.saysFailure ? null : (STATUS_WORD[call.status] ?? null)}
163
+ >
164
+ {call.line}
165
+ </Line>
166
+ {call.status === "failed" && call.reason && !open ? <p className="pl-1.5 text-[11px] text-destructive">{call.reason}</p> : null}
167
+ {call.openRequest && onOpenRequest ? (
168
+ <div className="pl-1.5">
169
+ <Button size="sm" variant="secondary" onClick={() => onOpenRequest(call.openRequest)}>
170
+ Open in Makersclaw <Icon name="external" size={12} />
171
+ </Button>
172
+ </div>
173
+ ) : null}
174
+ {open ? <Detail id={call.id} load={load} reason={call.reason} status={call.status} /> : null}
175
+ </div>
176
+ );
177
+ }
178
+
179
+ function Sub({ children }) {
180
+ return <div className="ml-3 grid min-w-0 gap-0.5 border-l border-border pl-2">{children}</div>;
181
+ }
182
+
183
+ function ReadsRow({ row, live, load }) {
184
+ const [open, setOpen] = useState(false);
185
+ return (
186
+ <div data-reads={row.calls.length} className="grid min-w-0 gap-0.5">
187
+ <Line tag={row.tag} status={row.status} open={open} onToggle={() => setOpen((o) => !o)} running={row.status === "running" && live}>
188
+ {row.label}
189
+ </Line>
190
+ {open ? (
191
+ <Sub>
192
+ {row.calls.map((c) => (
193
+ <CallRow key={c.id} call={c} live={live} load={load} />
194
+ ))}
195
+ </Sub>
196
+ ) : null}
197
+ </div>
198
+ );
199
+ }
200
+
201
+ function RepeatRow({ row, live, load }) {
202
+ const [open, setOpen] = useState(false);
203
+ return (
204
+ <div data-repeat={row.count} className="grid min-w-0 gap-0.5">
205
+ <Line
206
+ tag={row.tag}
207
+ status={row.status}
208
+ open={open}
209
+ onToggle={() => setOpen((o) => !o)}
210
+ running={row.status === "running" && live}
211
+ word={row.saysFailure ? null : (STATUS_WORD[row.status] ?? null)}
212
+ >
213
+ {row.line} · {row.count} times
214
+ </Line>
215
+ {row.status === "failed" && row.reason && !open ? <p className="pl-1.5 text-[11px] text-destructive">{row.reason}</p> : null}
216
+ {open ? (
217
+ <Sub>
218
+ {row.calls.map((c) => (
219
+ <CallRow key={c.id} call={c} live={live} load={load} />
220
+ ))}
221
+ </Sub>
222
+ ) : null}
223
+ </div>
224
+ );
225
+ }
226
+
227
+ function FixedRow({ row }) {
228
+ const [open, setOpen] = useState(false);
229
+ const n = row.fixes.length;
230
+ return (
231
+ <div data-fixed={n} className="grid min-w-0 gap-0.5">
232
+ <Line tag="FIXED" kind="fixed" open={open} onToggle={() => setOpen((o) => !o)}>
233
+ {n === 1 ? "Fixed 1 issue on the way" : `Fixed ${n} issues on the way`}
234
+ </Line>
235
+ {open ? (
236
+ <ol className="ml-3 grid min-w-0 gap-1.5 border-l border-border pl-2 text-xs text-muted-foreground">
237
+ {row.fixes.map((f) => (
238
+ <li key={f.id} className="grid min-w-0 gap-0.5">
239
+ <span className="break-words">
240
+ {f.what}: <span className="text-destructive">{f.reason}</span>
241
+ </span>
242
+ <span className="break-words">→ {f.then}</span>
243
+ </li>
244
+ ))}
245
+ </ol>
246
+ ) : null}
247
+ </div>
248
+ );
249
+ }
250
+
251
+ const HELPER_WORD = { running: "Working", waiting: "Waiting for you", done: "Done", failed: "Didn’t finish", denied: "Not allowed", interrupted: "Stopped" };
252
+
253
+ function HelperMark({ status }) {
254
+ if (status === "done") return <Icon name="circle-check" size={14} className="shrink-0 text-success" />;
255
+ if (status === "running") return <Spinner size="sm" label="Working" className="shrink-0 text-muted-foreground" />;
256
+ if (status === "failed" || status === "denied") return <Icon name="circle-x" size={14} className="shrink-0 text-destructive" />;
257
+ return <Icon name="circle" size={14} className="shrink-0 text-muted-foreground" />;
258
+ }
259
+
260
+ /** Helpers started side by side: a card, one row each; a row opens to its step. */
261
+ function HelpersCard({ row, load }) {
262
+ const [open, setOpen] = useState(null);
263
+ return (
264
+ <div role="group" aria-label={`${row.calls.length} helpers`} data-helpers={row.calls.length} className="grid min-w-0 divide-y divide-border overflow-hidden rounded-lg border border-border bg-card">
265
+ {row.calls.map((c) => (
266
+ <div key={c.id} className="grid min-w-0">
267
+ <button
268
+ type="button"
269
+ aria-expanded={open === c.id}
270
+ data-state={c.status}
271
+ onClick={() => setOpen((o) => (o === c.id ? null : c.id))}
272
+ className="flex min-w-0 items-center gap-2 px-2.5 py-1.5 text-left text-xs hover:bg-muted focus-visible:outline-2 focus-visible:outline-ring"
273
+ >
274
+ <HelperMark status={c.status} />
275
+ <span className="min-w-0 flex-1 truncate">{c.line}</span>
276
+ <span className="shrink-0 text-muted-foreground">{HELPER_WORD[c.status] ?? ""}</span>
277
+ </button>
278
+ {open === c.id ? (
279
+ <div className="px-2 pb-2">
280
+ <Detail id={c.id} load={load} reason={null} status={c.status} />
281
+ </div>
282
+ ) : null}
283
+ </div>
284
+ ))}
285
+ </div>
286
+ );
287
+ }
288
+
289
+ /** The model's own reasoning is not carried: the line says it thought. */
290
+ function ThoughtRow({ row }) {
291
+ return (
292
+ <div className="flex min-w-0 items-center gap-2 px-1.5 py-1 text-xs text-muted-foreground">
293
+ <Tag>THINK</Tag>
294
+ <span className="min-w-0 flex-1 truncate">{row.streaming ? "Thinking it through…" : "Thought it through"}</span>
295
+ {row.streaming ? <Spinner size="sm" label="Thinking" className="shrink-0" /> : null}
296
+ </div>
297
+ );
298
+ }
299
+
300
+ function Row({ row, live, load, onOpenRequest }) {
301
+ switch (row.kind) {
302
+ case "call":
303
+ return <CallRow call={row} live={live} load={load} onOpenRequest={onOpenRequest} />;
304
+ case "reads":
305
+ return <ReadsRow row={row} live={live} load={load} />;
306
+ case "repeat":
307
+ return <RepeatRow row={row} live={live} load={load} />;
308
+ case "fixed":
309
+ return <FixedRow row={row} />;
310
+ case "helpers":
311
+ return <HelpersCard row={row} load={load} />;
312
+ case "thought":
313
+ return <ThoughtRow row={row} />;
314
+ default:
315
+ return null;
316
+ }
317
+ }
318
+
319
+ /** A run of lines as one line, closed until opened; while a step runs the
320
+ * line is that step with a spinner and the count so far. A failure
321
+ * nothing fixed is counted on it, so a closed fold never hides it. */
322
+ function Fold({ run, live, load, onOpenRequest }) {
323
+ const [open, setOpen] = useState(false);
324
+ const sum = run.summary;
325
+ const running = sum.running && live;
326
+ const stopped = !running && (sum.stopped || sum.running);
327
+ const label = running ? (sum.latest ?? "Working") : stopped ? `Stopped after ${plural(sum.steps, "step", "steps")}` : `Worked through ${plural(sum.steps, "step", "steps")}`;
328
+ return (
329
+ <div className="grid min-w-0 gap-1" data-open={open || undefined}>
330
+ <button
331
+ type="button"
332
+ aria-expanded={open}
333
+ data-status={running ? "running" : stopped ? "interrupted" : "done"}
334
+ onClick={() => setOpen((o) => !o)}
335
+ className="flex w-full min-w-0 items-center gap-2 rounded-md border border-border px-2.5 py-1.5 text-left text-xs text-muted-foreground hover:bg-muted focus-visible:outline-2 focus-visible:outline-ring"
336
+ >
337
+ {running ? <Spinner size="sm" label="Working" className="shrink-0" /> : null}
338
+ <span className="min-w-0 flex-1 truncate">{label}</span>
339
+ {running ? <span className="shrink-0">{plural(sum.steps, "step", "steps")}</span> : null}
340
+ {sum.failed > 0 ? <span className="shrink-0 text-destructive">{sum.failed} didn’t work</span> : null}
341
+ <Chevron open={open} />
342
+ </button>
343
+ {open ? (
344
+ <div className="grid min-w-0 gap-0.5 pl-1">
345
+ {run.rows.map((row) => (
346
+ <Row key={row.id} row={row} live={live} load={load} onOpenRequest={onOpenRequest} />
347
+ ))}
348
+ </div>
349
+ ) : null}
350
+ </div>
351
+ );
352
+ }
353
+
354
+ /** The work between two things the agent said: folded into one line, with
355
+ * a helpers card and a lone line standing as they are. */
356
+ export function WorkBlock({ runs, live, load, onOpenRequest }) {
357
+ return (
358
+ <div className="grid min-w-0 gap-1.5">
359
+ {runs.map((run) =>
360
+ run.kind === "fold" ? (
361
+ <Fold key={run.id} run={run} live={live} load={load} onOpenRequest={onOpenRequest} />
362
+ ) : (
363
+ <Row key={run.row.id} row={run.row} live={live} load={load} onOpenRequest={onOpenRequest} />
364
+ ),
365
+ )}
366
+ </div>
367
+ );
368
+ }
@@ -0,0 +1,94 @@
1
+ # AiAction
2
+
3
+ One model call on what the screen already holds: **Summarize**,
4
+ **Shorter**, **Explain this score**, **Why did it move**.
5
+
6
+ - The price is on the button **before** the press, drawn by the `cost`
7
+ block's `CostTag`: "Shorter · about 1 cr" (the most it can use is in
8
+ its tooltip).
9
+ - While it runs, the button spins and the line says "One call to the
10
+ model…".
11
+ - The answer appears in place, with **Use**, **Copy** and **Again**.
12
+ - When the platform refuses, its own words show ("The app's weekly
13
+ allowance is used up."), with Try again.
14
+ - On a claw without the door, a quiet "Shorter is not connected yet".
15
+
16
+ One call is not the agent. It has no tools and no conversation, so it
17
+ wears the dashed one-call mark (`CallMark` from `agent-marks`), never the
18
+ agent's diamond.
19
+
20
+ ```jsx
21
+ import { AiAction } from "../components/blocks/ai-action"; // a Makersclaw app ("./blocks/ai-action" from components/)
22
+ import { AiAction } from "@/components/makersclaw/blocks/ai-action"; // a shadcn project
23
+ ```
24
+
25
+ A client component. It requires `agent-marks` (laid with it).
26
+
27
+ ## Which hook feeds it
28
+
29
+ ```js
30
+ const shorter = useLlmAction({ input: draft, system: "Make it shorter. Keep every fact." }); // lib/hooks.js
31
+ // → { estimate: { credits, credits_max } | null, estimating, run(), result, loading, error, unavailable, reset() }
32
+ ```
33
+
34
+ `useLlmAction` prices the call once per distinct input (`POST _claw/llm`
35
+ with `estimate: true`: checked, never sent to a model, never charged),
36
+ and `run()` makes it. `result` is the answer: `{ text }`, or `{ data }`
37
+ with a `schema`.
38
+
39
+ ## Props
40
+
41
+ - `label` — the verb, in the app's words ("Shorter", "Explain this
42
+ score").
43
+ - `action` — what `useLlmAction()` returns. Required.
44
+ - `icon` — a kit `Icon` name for the button. Default the one-call mark.
45
+ - `render(result)` — draws the answer your way: a schema's `data` as a
46
+ list, a score's reasons. Default the text as written (a `data` without
47
+ `render` shows as plain JSON).
48
+ - `onUse(result)` — puts the answer to work: replace the draft, fill the
49
+ field. Without it there is no Use. After a Use the button says "Used".
50
+ - `useLabel` — default "Use" ("Replace the draft").
51
+ - `title` — the answer's head. Default the label.
52
+ - `className` — layout around it. Never colour.
53
+
54
+ `priceWords({ credits, credits_max })` is exported for a screen reader
55
+ and for callers: "1 cr", "1–3 cr".
56
+
57
+ ## Who may do what
58
+
59
+ Any member who can open the app. The door holds the caps: the workspace's
60
+ wallet, the member's monthly cap, the app's weekly allowance, 30 calls a
61
+ minute. A refusal is shown in its own words; never retry it in a loop.
62
+
63
+ ## Never
64
+
65
+ - **Never press without the price.** The button says it before the
66
+ press; while it is being priced the button waits.
67
+ - Never write the answer into a record by itself: Use is the member's
68
+ press, and `onUse` does the write.
69
+ - Never use it for work that needs tools (reading records, searching the
70
+ web, sending): that is an ask to the agent.
71
+ - Never draw the agent's diamond on it.
72
+
73
+ ## Example
74
+
75
+ A draft with Shorter beside it.
76
+
77
+ ```jsx
78
+ "use client";
79
+ import { useState } from "react";
80
+ import { Textarea } from "../components/ui";
81
+ import { useLlmAction } from "../lib/hooks";
82
+ import { AiAction } from "../components/blocks/ai-action";
83
+
84
+ export default function Draft({ initial }) {
85
+ const [draft, setDraft] = useState(initial);
86
+ const shorter = useLlmAction({ input: draft, system: "Make it shorter. Keep every fact and the writer's voice." });
87
+ return (
88
+ <div className="grid gap-3">
89
+ <Textarea value={draft} onChange={(e) => setDraft(e.target.value)} autoGrow />
90
+ <AiAction label="Shorter" action={shorter} useLabel="Replace the draft" onUse={(r) => setDraft(r.text)} />
91
+ </div>
92
+ );
93
+ }
94
+ ```
@@ -0,0 +1,188 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef, useState } from "react";
4
+ import { Button, Icon, IconButton, Spinner, cx } from "../../ui";
5
+ import { CallMark } from "../agent-marks";
6
+ import { CostTag, creditsWords } from "../cost";
7
+
8
+ // AiAction — one model call on what the screen holds (the app kit, D15):
9
+ // Summarize, Shorter, Explain this score, Why did it move. Its price is on
10
+ // the button before the press ("Shorter · 1 cr"), the answer appears in
11
+ // place with Use, Copy and Again, a refusal says its words, and a claw
12
+ // without the door is a quiet "not connected yet".
13
+ //
14
+ // const shorter = useLlmAction({ input: draft, system: "Make it shorter. Keep the facts." });
15
+ // <AiAction label="Shorter" action={shorter} onUse={(r) => setDraft(r.text)} />
16
+ //
17
+ // It draws what useLlmAction() returns (lib/hooks.js). One call is the
18
+ // dashed CallMark, never the agent's diamond: no tools, no conversation.
19
+
20
+ /** The price as words, for a screen reader and for callers: "1 cr", "1–3 cr".
21
+ * What shows on the button is the cost block's CostTag. */
22
+ export function priceWords(estimate) {
23
+ if (!estimate) return null;
24
+ const low = creditsWords(Number(estimate.credits));
25
+ if (low == null) return null;
26
+ const high = creditsWords(Number(estimate.credits_max));
27
+ return high && high !== low && Number(estimate.credits_max) > Number(estimate.credits) ? `${low}–${high} cr` : `${low} cr`;
28
+ }
29
+
30
+ /** The answer's words, when it has words: a string, { text }, or { ok, text }. */
31
+ function textOf(result) {
32
+ if (result == null) return null;
33
+ if (typeof result === "string") return result;
34
+ if (typeof result.text === "string") return result.text;
35
+ return null;
36
+ }
37
+
38
+ /** Its data, when it came back shaped (a schema): { data } or an object. */
39
+ function dataOf(result) {
40
+ if (result == null || typeof result === "string") return undefined;
41
+ if ("data" in result) return result.data;
42
+ return typeof result.text === "string" ? undefined : result;
43
+ }
44
+
45
+ /**
46
+ * label the verb ("Shorter", "Explain this score")
47
+ * icon a kit Icon name for the button; default the call's mark
48
+ * action what useLlmAction() returns: { estimate, estimating,
49
+ * run(), result, loading, error, unavailable, reset() }
50
+ * render(result) draws the answer your way (a schema's data); default
51
+ * the text as written
52
+ * onUse(result) puts the answer to work (replace the draft); without
53
+ * it there is no Use
54
+ * useLabel default "Use"
55
+ * title the answer's head (default the label)
56
+ * className layout around it. Never colour.
57
+ */
58
+ export function AiAction({ label, icon, action, render, onUse, useLabel = "Use", title, className }) {
59
+ const [copied, setCopied] = useState(false);
60
+ const [used, setUsed] = useState(false);
61
+ const timer = useRef(null);
62
+ useEffect(() => () => clearTimeout(timer.current), []);
63
+
64
+ const a = action ?? {};
65
+ const price = priceWords(a.estimate);
66
+ const result = a.result;
67
+ const text = textOf(result);
68
+ const data = dataOf(result);
69
+ const has = result != null && (text != null ? text.trim() !== "" : data !== undefined);
70
+ const busy = Boolean(a.loading);
71
+
72
+ if (a.unavailable) {
73
+ return (
74
+ <p className={cx("inline-flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground", className)}>
75
+ <CallMark />
76
+ <span className="min-w-0 break-words">{label} is not connected yet.</span>
77
+ </p>
78
+ );
79
+ }
80
+
81
+ const press = () => {
82
+ if (busy || !a.run) return;
83
+ setUsed(false);
84
+ a.run();
85
+ };
86
+
87
+ async function copy() {
88
+ if (text == null) return;
89
+ try {
90
+ await navigator.clipboard.writeText(text);
91
+ setCopied(true);
92
+ clearTimeout(timer.current);
93
+ timer.current = setTimeout(() => setCopied(false), 1600);
94
+ } catch {
95
+ setCopied(false);
96
+ }
97
+ }
98
+
99
+ return (
100
+ <div className={cx("@container grid grid-cols-1 min-w-0 gap-2 text-sm", className)}>
101
+ <Button
102
+ size="sm"
103
+ variant="secondary"
104
+ className="max-w-full justify-self-start"
105
+ loading={busy}
106
+ disabled={busy || a.estimating || !a.run}
107
+ onClick={press}
108
+ aria-label={price ? `${label}, ${price === "1 cr" ? "1 credit" : price.replace(" cr", " credits")}` : undefined}
109
+ >
110
+ {icon ? <Icon name={icon} size={14} /> : <CallMark />}
111
+ <span className="min-w-0 truncate">{label}</span>
112
+ {price || a.estimating ? (
113
+ <>
114
+ <span aria-hidden="true">·</span>
115
+ <CostTag credits={Number(a.estimate?.credits)} max={Number(a.estimate?.credits_max)} loading={!price} icon={false} />
116
+ </>
117
+ ) : null}
118
+ </Button>
119
+
120
+ {busy ? (
121
+ <p role="status" className="flex items-center gap-2 text-xs text-muted-foreground">
122
+ <Spinner size="sm" label="Asking" /> One call to the model…
123
+ </p>
124
+ ) : null}
125
+
126
+ {a.error && !busy ? (
127
+ <div role="alert" className="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 text-xs text-destructive">
128
+ <Icon name="warning" size={14} className="shrink-0" />
129
+ <span className="min-w-0 break-words">{a.error}</span>
130
+ {a.run ? (
131
+ <Button variant="link" size="inherit" onClick={press}>
132
+ Try again
133
+ </Button>
134
+ ) : null}
135
+ </div>
136
+ ) : null}
137
+
138
+ {has && !busy ? (
139
+ <section aria-label={`${title ?? label}: the answer`} className="grid grid-cols-1 min-w-0 gap-2 rounded-[var(--radius)] border border-dashed border-border bg-card p-3 text-card-foreground">
140
+ <div className="flex min-w-0 items-center gap-2 text-xs text-muted-foreground">
141
+ <CallMark>{title ?? label}</CallMark>
142
+ <span className="shrink-0">· 1 call</span>
143
+ {a.reset ? <IconButton icon="x" size="sm" label="Put it away" className="ml-auto -my-1" onClick={a.reset} /> : null}
144
+ </div>
145
+ <div className="min-w-0 break-words">
146
+ {render ? render(result) : text != null ? <p className="whitespace-pre-wrap">{text}</p> : <pre className="overflow-x-auto whitespace-pre-wrap text-xs">{JSON.stringify(data, null, 2)}</pre>}
147
+ </div>
148
+ <div className="flex min-w-0 flex-wrap items-center gap-1.5">
149
+ {onUse ? (
150
+ used ? (
151
+ <span className="inline-flex items-center gap-1 text-xs font-medium text-success">
152
+ <Icon name="check" size={14} /> Used
153
+ </span>
154
+ ) : (
155
+ <Button
156
+ size="sm"
157
+ variant="primary"
158
+ onClick={() => {
159
+ onUse(result);
160
+ setUsed(true);
161
+ }}
162
+ >
163
+ {useLabel}
164
+ </Button>
165
+ )
166
+ ) : null}
167
+ {text != null ? (
168
+ <Button size="sm" variant="quiet" onClick={copy}>
169
+ <Icon name={copied ? "check" : "copy"} size={14} /> {copied ? "Copied" : "Copy"}
170
+ </Button>
171
+ ) : null}
172
+ {a.run ? (
173
+ <Button size="sm" variant="quiet" onClick={press}>
174
+ <Icon name="refresh" size={14} /> Again
175
+ {price ? (
176
+ <>
177
+ <span aria-hidden="true">·</span>
178
+ <CostTag credits={Number(a.estimate?.credits)} max={Number(a.estimate?.credits_max)} icon={false} />
179
+ </>
180
+ ) : null}
181
+ </Button>
182
+ ) : null}
183
+ </div>
184
+ </section>
185
+ ) : null}
186
+ </div>
187
+ );
188
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "ai-action",
3
+ "title": "AiAction",
4
+ "description": "One model call on what the screen holds — Summarize, Shorter, Explain this score, Why did it move — with its price on the button before the press (\"Shorter · 1 cr\"), a running state, the answer in place (its text, or your render of a schema's data) with Use, Copy and Again, the refusal's own words when it fails, and a quiet \"not connected yet\" on a claw without the door. It draws what useLlmAction() returns (lib/hooks.js) and wears the dashed one-call mark, never the agent's diamond.",
5
+ "useWhen": "A screen wants a quick model answer about something it already shows, with no conversation and no tools: shorten a draft, summarize a thread, explain a score, say why a number moved, suggest a subject line. For work that reads, searches or writes records, ask the agent (ask-bar, agent-chat).",
6
+ "tags": [
7
+ "ai",
8
+ "llm",
9
+ "model",
10
+ "summarize",
11
+ "shorter",
12
+ "rewrite",
13
+ "explain",
14
+ "why",
15
+ "draft",
16
+ "one call",
17
+ "price",
18
+ "credits",
19
+ "generate",
20
+ "magic button"
21
+ ],
22
+ "exports": [
23
+ "AiAction",
24
+ "priceWords"
25
+ ],
26
+ "files": [
27
+ "index.js",
28
+ "ai-action.jsx"
29
+ ],
30
+ "requires": [
31
+ "agent-marks",
32
+ "cost"
33
+ ]
34
+ }