@joewinke/jatui 0.36.3 → 0.38.0

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 (271) hide show
  1. package/dist/artifact-blocks/AttachmentChip.svelte +66 -0
  2. package/dist/artifact-blocks/AttachmentChip.svelte.d.ts +7 -0
  3. package/dist/artifact-blocks/BlockComments.svelte +309 -0
  4. package/dist/artifact-blocks/BlockComments.svelte.d.ts +33 -0
  5. package/dist/artifact-blocks/BlockRenderer.svelte +674 -0
  6. package/dist/artifact-blocks/BlockRenderer.svelte.d.ts +55 -0
  7. package/dist/artifact-blocks/BlockVerdict.svelte +151 -0
  8. package/dist/artifact-blocks/BlockVerdict.svelte.d.ts +13 -0
  9. package/dist/artifact-blocks/BlocksArtifactView.svelte +1616 -0
  10. package/dist/artifact-blocks/BlocksArtifactView.svelte.d.ts +113 -0
  11. package/dist/artifact-blocks/CONTRACT.md +225 -0
  12. package/dist/artifact-blocks/CommentPill.svelte +49 -0
  13. package/dist/artifact-blocks/CommentPill.svelte.d.ts +16 -0
  14. package/dist/artifact-blocks/FoldedRounds.svelte +95 -0
  15. package/dist/artifact-blocks/FoldedRounds.svelte.d.ts +9 -0
  16. package/dist/artifact-blocks/Glyph.svelte +54 -0
  17. package/dist/artifact-blocks/Glyph.svelte.d.ts +10 -0
  18. package/dist/artifact-blocks/HistoryScrubber.svelte +500 -0
  19. package/dist/artifact-blocks/HistoryScrubber.svelte.d.ts +15 -0
  20. package/dist/artifact-blocks/Markdown.svelte +186 -0
  21. package/dist/artifact-blocks/Markdown.svelte.d.ts +30 -0
  22. package/dist/artifact-blocks/NoteComposer.svelte +31 -0
  23. package/dist/artifact-blocks/NoteComposer.svelte.d.ts +8 -0
  24. package/dist/artifact-blocks/PlainComposer.svelte +200 -0
  25. package/dist/artifact-blocks/PlainComposer.svelte.d.ts +15 -0
  26. package/dist/artifact-blocks/SectionTools.svelte +102 -0
  27. package/dist/artifact-blocks/SectionTools.svelte.d.ts +19 -0
  28. package/dist/artifact-blocks/adapter.d.ts +13 -0
  29. package/dist/artifact-blocks/adapter.js +31 -0
  30. package/dist/artifact-blocks/autoSend.d.ts +49 -0
  31. package/dist/artifact-blocks/autoSend.js +103 -0
  32. package/dist/artifact-blocks/blocks/actions/ActionsBlock.svelte +557 -0
  33. package/dist/artifact-blocks/blocks/actions/ActionsBlock.svelte.d.ts +48 -0
  34. package/dist/artifact-blocks/blocks/actions/block.d.ts +8 -0
  35. package/dist/artifact-blocks/blocks/actions/block.js +74 -0
  36. package/dist/artifact-blocks/blocks/actions/requests.d.ts +62 -0
  37. package/dist/artifact-blocks/blocks/actions/requests.js +26 -0
  38. package/dist/artifact-blocks/blocks/actions/schema.d.ts +168 -0
  39. package/dist/artifact-blocks/blocks/actions/schema.js +253 -0
  40. package/dist/artifact-blocks/blocks/callout/CalloutBlock.svelte +779 -0
  41. package/dist/artifact-blocks/blocks/callout/CalloutBlock.svelte.d.ts +40 -0
  42. package/dist/artifact-blocks/blocks/callout/block.d.ts +7 -0
  43. package/dist/artifact-blocks/blocks/callout/block.js +39 -0
  44. package/dist/artifact-blocks/blocks/callout/schema.d.ts +72 -0
  45. package/dist/artifact-blocks/blocks/callout/schema.js +115 -0
  46. package/dist/artifact-blocks/blocks/chart/ChartBlock.svelte +875 -0
  47. package/dist/artifact-blocks/blocks/chart/ChartBlock.svelte.d.ts +59 -0
  48. package/dist/artifact-blocks/blocks/chart/block.d.ts +9 -0
  49. package/dist/artifact-blocks/blocks/chart/block.js +70 -0
  50. package/dist/artifact-blocks/blocks/chart/schema.d.ts +171 -0
  51. package/dist/artifact-blocks/blocks/chart/schema.js +498 -0
  52. package/dist/artifact-blocks/blocks/chart/thumb.d.ts +2 -0
  53. package/dist/artifact-blocks/blocks/chart/thumb.js +201 -0
  54. package/dist/artifact-blocks/blocks/checklist/ChecklistBlock.svelte +1048 -0
  55. package/dist/artifact-blocks/blocks/checklist/ChecklistBlock.svelte.d.ts +16 -0
  56. package/dist/artifact-blocks/blocks/checklist/Icon.svelte +105 -0
  57. package/dist/artifact-blocks/blocks/checklist/Icon.svelte.d.ts +17 -0
  58. package/dist/artifact-blocks/blocks/checklist/block.d.ts +10 -0
  59. package/dist/artifact-blocks/blocks/checklist/block.js +63 -0
  60. package/dist/artifact-blocks/blocks/checklist/itemReview.d.ts +16 -0
  61. package/dist/artifact-blocks/blocks/checklist/itemReview.js +63 -0
  62. package/dist/artifact-blocks/blocks/checklist/labels.d.ts +62 -0
  63. package/dist/artifact-blocks/blocks/checklist/labels.js +96 -0
  64. package/dist/artifact-blocks/blocks/checklist/retest.d.ts +43 -0
  65. package/dist/artifact-blocks/blocks/checklist/retest.js +68 -0
  66. package/dist/artifact-blocks/blocks/checklist/schema.d.ts +84 -0
  67. package/dist/artifact-blocks/blocks/checklist/schema.js +91 -0
  68. package/dist/artifact-blocks/blocks/code/CodeBlock.svelte +128 -0
  69. package/dist/artifact-blocks/blocks/code/CodeBlock.svelte.d.ts +12 -0
  70. package/dist/artifact-blocks/blocks/code/block.d.ts +8 -0
  71. package/dist/artifact-blocks/blocks/code/block.js +31 -0
  72. package/dist/artifact-blocks/blocks/code/highlight.d.ts +34 -0
  73. package/dist/artifact-blocks/blocks/code/highlight.js +280 -0
  74. package/dist/artifact-blocks/blocks/code/schema.d.ts +32 -0
  75. package/dist/artifact-blocks/blocks/code/schema.js +39 -0
  76. package/dist/artifact-blocks/blocks/collage/CollageBlock.svelte +290 -0
  77. package/dist/artifact-blocks/blocks/collage/CollageBlock.svelte.d.ts +29 -0
  78. package/dist/artifact-blocks/blocks/collage/block.d.ts +9 -0
  79. package/dist/artifact-blocks/blocks/collage/block.js +29 -0
  80. package/dist/artifact-blocks/blocks/collage/schema.d.ts +52 -0
  81. package/dist/artifact-blocks/blocks/collage/schema.js +86 -0
  82. package/dist/artifact-blocks/blocks/compare/CompareBlock.svelte +484 -0
  83. package/dist/artifact-blocks/blocks/compare/CompareBlock.svelte.d.ts +25 -0
  84. package/dist/artifact-blocks/blocks/compare/block.d.ts +9 -0
  85. package/dist/artifact-blocks/blocks/compare/block.js +32 -0
  86. package/dist/artifact-blocks/blocks/compare/schema.d.ts +74 -0
  87. package/dist/artifact-blocks/blocks/compare/schema.js +148 -0
  88. package/dist/artifact-blocks/blocks/diagram/DiagramBlock.svelte +392 -0
  89. package/dist/artifact-blocks/blocks/diagram/DiagramBlock.svelte.d.ts +30 -0
  90. package/dist/artifact-blocks/blocks/diagram/block.d.ts +9 -0
  91. package/dist/artifact-blocks/blocks/diagram/block.js +50 -0
  92. package/dist/artifact-blocks/blocks/diagram/constants.d.ts +48 -0
  93. package/dist/artifact-blocks/blocks/diagram/constants.js +53 -0
  94. package/dist/artifact-blocks/blocks/diagram/schema.d.ts +161 -0
  95. package/dist/artifact-blocks/blocks/diagram/schema.js +621 -0
  96. package/dist/artifact-blocks/blocks/diagram/thumb.d.ts +2 -0
  97. package/dist/artifact-blocks/blocks/diagram/thumb.js +157 -0
  98. package/dist/artifact-blocks/blocks/diagram/types.d.ts +74 -0
  99. package/dist/artifact-blocks/blocks/diagram/types.js +1 -0
  100. package/dist/artifact-blocks/blocks/diff/DiffBlock.svelte +81 -0
  101. package/dist/artifact-blocks/blocks/diff/DiffBlock.svelte.d.ts +10 -0
  102. package/dist/artifact-blocks/blocks/diff/block.d.ts +7 -0
  103. package/dist/artifact-blocks/blocks/diff/block.js +36 -0
  104. package/dist/artifact-blocks/blocks/diff/schema.d.ts +18 -0
  105. package/dist/artifact-blocks/blocks/diff/schema.js +35 -0
  106. package/dist/artifact-blocks/blocks/diff-review/DiffReviewBlock.svelte +1055 -0
  107. package/dist/artifact-blocks/blocks/diff-review/DiffReviewBlock.svelte.d.ts +5 -0
  108. package/dist/artifact-blocks/blocks/diff-review/block.d.ts +15 -0
  109. package/dist/artifact-blocks/blocks/diff-review/block.js +64 -0
  110. package/dist/artifact-blocks/blocks/diff-review/decisions.d.ts +57 -0
  111. package/dist/artifact-blocks/blocks/diff-review/decisions.js +80 -0
  112. package/dist/artifact-blocks/blocks/diff-review/schema.d.ts +13 -0
  113. package/dist/artifact-blocks/blocks/diff-review/schema.js +84 -0
  114. package/dist/artifact-blocks/blocks/diff-review/types.d.ts +35 -0
  115. package/dist/artifact-blocks/blocks/diff-review/types.js +1 -0
  116. package/dist/artifact-blocks/blocks/explainer/ExplainerBlock.svelte +145 -0
  117. package/dist/artifact-blocks/blocks/explainer/ExplainerBlock.svelte.d.ts +5 -0
  118. package/dist/artifact-blocks/blocks/explainer/block.d.ts +8 -0
  119. package/dist/artifact-blocks/blocks/explainer/block.js +21 -0
  120. package/dist/artifact-blocks/blocks/explainer/schema.d.ts +26 -0
  121. package/dist/artifact-blocks/blocks/explainer/schema.js +69 -0
  122. package/dist/artifact-blocks/blocks/group-content.d.ts +10 -0
  123. package/dist/artifact-blocks/blocks/group-content.js +16 -0
  124. package/dist/artifact-blocks/blocks/group-data.d.ts +10 -0
  125. package/dist/artifact-blocks/blocks/group-data.js +7 -0
  126. package/dist/artifact-blocks/blocks/group-review.d.ts +10 -0
  127. package/dist/artifact-blocks/blocks/group-review.js +12 -0
  128. package/dist/artifact-blocks/blocks/group-visual.d.ts +17 -0
  129. package/dist/artifact-blocks/blocks/group-visual.js +14 -0
  130. package/dist/artifact-blocks/blocks/map/MapBlock.svelte +413 -0
  131. package/dist/artifact-blocks/blocks/map/MapBlock.svelte.d.ts +53 -0
  132. package/dist/artifact-blocks/blocks/map/block.d.ts +9 -0
  133. package/dist/artifact-blocks/blocks/map/block.js +62 -0
  134. package/dist/artifact-blocks/blocks/map/schema.d.ts +123 -0
  135. package/dist/artifact-blocks/blocks/map/schema.js +113 -0
  136. package/dist/artifact-blocks/blocks/map/thumb.d.ts +2 -0
  137. package/dist/artifact-blocks/blocks/map/thumb.js +69 -0
  138. package/dist/artifact-blocks/blocks/markdown/MarkdownBlock.svelte +33 -0
  139. package/dist/artifact-blocks/blocks/markdown/MarkdownBlock.svelte.d.ts +15 -0
  140. package/dist/artifact-blocks/blocks/markdown/block.d.ts +7 -0
  141. package/dist/artifact-blocks/blocks/markdown/block.js +28 -0
  142. package/dist/artifact-blocks/blocks/markdown/render.d.ts +17 -0
  143. package/dist/artifact-blocks/blocks/markdown/render.js +115 -0
  144. package/dist/artifact-blocks/blocks/markdown/schema.d.ts +10 -0
  145. package/dist/artifact-blocks/blocks/markdown/schema.js +23 -0
  146. package/dist/artifact-blocks/blocks/media-picker/MediaPickerBlock.svelte +2112 -0
  147. package/dist/artifact-blocks/blocks/media-picker/MediaPickerBlock.svelte.d.ts +5 -0
  148. package/dist/artifact-blocks/blocks/media-picker/block.d.ts +24 -0
  149. package/dist/artifact-blocks/blocks/media-picker/block.js +137 -0
  150. package/dist/artifact-blocks/blocks/media-picker/choices.d.ts +28 -0
  151. package/dist/artifact-blocks/blocks/media-picker/choices.js +35 -0
  152. package/dist/artifact-blocks/blocks/media-picker/decisions.d.ts +51 -0
  153. package/dist/artifact-blocks/blocks/media-picker/decisions.js +75 -0
  154. package/dist/artifact-blocks/blocks/media-picker/schema.d.ts +7 -0
  155. package/dist/artifact-blocks/blocks/media-picker/schema.js +199 -0
  156. package/dist/artifact-blocks/blocks/media-picker/types.d.ts +92 -0
  157. package/dist/artifact-blocks/blocks/media-picker/types.js +1 -0
  158. package/dist/artifact-blocks/blocks/media-picker/versions.d.ts +51 -0
  159. package/dist/artifact-blocks/blocks/media-picker/versions.js +118 -0
  160. package/dist/artifact-blocks/blocks/mockup/MockupBlock.svelte +213 -0
  161. package/dist/artifact-blocks/blocks/mockup/MockupBlock.svelte.d.ts +5 -0
  162. package/dist/artifact-blocks/blocks/mockup/block.d.ts +26 -0
  163. package/dist/artifact-blocks/blocks/mockup/block.js +52 -0
  164. package/dist/artifact-blocks/blocks/mockup/doc.d.ts +24 -0
  165. package/dist/artifact-blocks/blocks/mockup/doc.js +44 -0
  166. package/dist/artifact-blocks/blocks/mockup/sandbox.d.ts +21 -0
  167. package/dist/artifact-blocks/blocks/mockup/sandbox.js +27 -0
  168. package/dist/artifact-blocks/blocks/mockup/schema.d.ts +7 -0
  169. package/dist/artifact-blocks/blocks/mockup/schema.js +90 -0
  170. package/dist/artifact-blocks/blocks/mockup/types.d.ts +36 -0
  171. package/dist/artifact-blocks/blocks/mockup/types.js +17 -0
  172. package/dist/artifact-blocks/blocks/program/ProgramBlock.svelte +359 -0
  173. package/dist/artifact-blocks/blocks/program/ProgramBlock.svelte.d.ts +32 -0
  174. package/dist/artifact-blocks/blocks/program/block.d.ts +35 -0
  175. package/dist/artifact-blocks/blocks/program/block.js +68 -0
  176. package/dist/artifact-blocks/blocks/program/schema.d.ts +132 -0
  177. package/dist/artifact-blocks/blocks/program/schema.js +268 -0
  178. package/dist/artifact-blocks/blocks/stats/StatsBlock.svelte +315 -0
  179. package/dist/artifact-blocks/blocks/stats/StatsBlock.svelte.d.ts +24 -0
  180. package/dist/artifact-blocks/blocks/stats/block.d.ts +7 -0
  181. package/dist/artifact-blocks/blocks/stats/block.js +49 -0
  182. package/dist/artifact-blocks/blocks/stats/schema.d.ts +82 -0
  183. package/dist/artifact-blocks/blocks/stats/schema.js +43 -0
  184. package/dist/artifact-blocks/blocks/stats/thumb.d.ts +2 -0
  185. package/dist/artifact-blocks/blocks/stats/thumb.js +102 -0
  186. package/dist/artifact-blocks/blocks/table/TableBlock.svelte +490 -0
  187. package/dist/artifact-blocks/blocks/table/TableBlock.svelte.d.ts +28 -0
  188. package/dist/artifact-blocks/blocks/table/block.d.ts +9 -0
  189. package/dist/artifact-blocks/blocks/table/block.js +100 -0
  190. package/dist/artifact-blocks/blocks/table/schema.d.ts +143 -0
  191. package/dist/artifact-blocks/blocks/table/schema.js +278 -0
  192. package/dist/artifact-blocks/blocks/timeline/TimelineBlock.svelte +347 -0
  193. package/dist/artifact-blocks/blocks/timeline/TimelineBlock.svelte.d.ts +42 -0
  194. package/dist/artifact-blocks/blocks/timeline/block.d.ts +9 -0
  195. package/dist/artifact-blocks/blocks/timeline/block.js +96 -0
  196. package/dist/artifact-blocks/blocks/timeline/constants.d.ts +26 -0
  197. package/dist/artifact-blocks/blocks/timeline/constants.js +27 -0
  198. package/dist/artifact-blocks/blocks/timeline/schema.d.ts +102 -0
  199. package/dist/artifact-blocks/blocks/timeline/schema.js +405 -0
  200. package/dist/artifact-blocks/blocks/timeline/thumb.d.ts +2 -0
  201. package/dist/artifact-blocks/blocks/timeline/thumb.js +117 -0
  202. package/dist/artifact-blocks/blocks/timeline/types.d.ts +66 -0
  203. package/dist/artifact-blocks/blocks/timeline/types.js +1 -0
  204. package/dist/artifact-blocks/blocks/transcript/TranscriptBlock.svelte +169 -0
  205. package/dist/artifact-blocks/blocks/transcript/TranscriptBlock.svelte.d.ts +26 -0
  206. package/dist/artifact-blocks/blocks/transcript/block.d.ts +9 -0
  207. package/dist/artifact-blocks/blocks/transcript/block.js +86 -0
  208. package/dist/artifact-blocks/blocks/transcript/schema.d.ts +114 -0
  209. package/dist/artifact-blocks/blocks/transcript/schema.js +126 -0
  210. package/dist/artifact-blocks/builtins.d.ts +40 -0
  211. package/dist/artifact-blocks/builtins.js +22 -0
  212. package/dist/artifact-blocks/contractBlocks.d.ts +92 -0
  213. package/dist/artifact-blocks/contractBlocks.js +279 -0
  214. package/dist/artifact-blocks/history.d.ts +140 -0
  215. package/dist/artifact-blocks/history.js +363 -0
  216. package/dist/artifact-blocks/index.d.ts +40 -0
  217. package/dist/artifact-blocks/index.js +46 -0
  218. package/dist/artifact-blocks/listen/context.d.ts +30 -0
  219. package/dist/artifact-blocks/listen/context.js +30 -0
  220. package/dist/artifact-blocks/liveData.d.ts +78 -0
  221. package/dist/artifact-blocks/liveData.js +137 -0
  222. package/dist/artifact-blocks/liveDataPoller.d.ts +41 -0
  223. package/dist/artifact-blocks/liveDataPoller.js +140 -0
  224. package/dist/artifact-blocks/openNav.d.ts +46 -0
  225. package/dist/artifact-blocks/openNav.js +106 -0
  226. package/dist/artifact-blocks/pageReviewKeys.d.ts +17 -0
  227. package/dist/artifact-blocks/pageReviewKeys.js +115 -0
  228. package/dist/artifact-blocks/params.d.ts +98 -0
  229. package/dist/artifact-blocks/params.js +159 -0
  230. package/dist/artifact-blocks/registry.d.ts +27 -0
  231. package/dist/artifact-blocks/registry.js +83 -0
  232. package/dist/artifact-blocks/review/BlockIcon.svelte +99 -0
  233. package/dist/artifact-blocks/review/BlockIcon.svelte.d.ts +17 -0
  234. package/dist/artifact-blocks/review/BulkRejectForm.svelte +94 -0
  235. package/dist/artifact-blocks/review/BulkRejectForm.svelte.d.ts +11 -0
  236. package/dist/artifact-blocks/review/BulkUndoBar.svelte +40 -0
  237. package/dist/artifact-blocks/review/BulkUndoBar.svelte.d.ts +9 -0
  238. package/dist/artifact-blocks/review/ItemNote.svelte +193 -0
  239. package/dist/artifact-blocks/review/ItemNote.svelte.d.ts +33 -0
  240. package/dist/artifact-blocks/review/NoteToggle.svelte +52 -0
  241. package/dist/artifact-blocks/review/NoteToggle.svelte.d.ts +12 -0
  242. package/dist/artifact-blocks/review/TeamChip.svelte +71 -0
  243. package/dist/artifact-blocks/review/TeamChip.svelte.d.ts +8 -0
  244. package/dist/artifact-blocks/review/attachments.d.ts +10 -0
  245. package/dist/artifact-blocks/review/attachments.js +37 -0
  246. package/dist/artifact-blocks/review/bulk.d.ts +52 -0
  247. package/dist/artifact-blocks/review/bulk.js +61 -0
  248. package/dist/artifact-blocks/review/itemReview.d.ts +33 -0
  249. package/dist/artifact-blocks/review/itemReview.js +112 -0
  250. package/dist/artifact-blocks/review/roundLines.d.ts +14 -0
  251. package/dist/artifact-blocks/review/roundLines.js +20 -0
  252. package/dist/artifact-blocks/review/rounds.d.ts +86 -0
  253. package/dist/artifact-blocks/review/rounds.js +302 -0
  254. package/dist/artifact-blocks/review/saver.d.ts +23 -0
  255. package/dist/artifact-blocks/review/saver.js +48 -0
  256. package/dist/artifact-blocks/review/team.d.ts +31 -0
  257. package/dist/artifact-blocks/review/team.js +42 -0
  258. package/dist/artifact-blocks/review/visualOrder.d.ts +29 -0
  259. package/dist/artifact-blocks/review/visualOrder.js +66 -0
  260. package/dist/artifact-blocks/review.d.ts +180 -0
  261. package/dist/artifact-blocks/review.js +716 -0
  262. package/dist/artifact-blocks/thumb-kit.d.ts +80 -0
  263. package/dist/artifact-blocks/thumb-kit.js +149 -0
  264. package/dist/artifact-blocks/types.d.ts +513 -0
  265. package/dist/artifact-blocks/types.js +1 -0
  266. package/dist/components/Button.svelte +8 -0
  267. package/dist/components/TextInput.svelte +39 -6
  268. package/dist/components/TextInput.svelte.d.ts +15 -7
  269. package/dist/components/basic/Checkbox.svelte +52 -14
  270. package/dist/components/basic/Checkbox.svelte.d.ts +11 -1
  271. package/package.json +11 -2
@@ -0,0 +1,557 @@
1
+ <script lang="ts">
2
+ /**
3
+ * actions block — buttons and small forms that send a REQUEST to the
4
+ * owning agent (mos-p9auh, living artifacts phase 4).
5
+ *
6
+ * A press goes to the HOST's actions service (`ctx.services.actions`,
7
+ * requests.ts ActionsService — MOS: POST /api/v1/artifacts/[id]/actions,
8
+ * one artifact_events row of kind 'action'). The agent sees it, acts and
9
+ * acks; this block polls the request list while anything is open and
10
+ * walks the button through Queued → Running → Done ✓ / Failed with the
11
+ * agent's note. The renderer never runs the action itself.
12
+ *
13
+ * Live only where the viewer can act (ctx.saveState present, not
14
+ * readonly) AND the host wired the service. Elsewhere — a share link,
15
+ * print, previews, a host with no actions leg — the actions render as a
16
+ * quiet list with no controls and a line saying why.
17
+ *
18
+ * Link actions (`href`, PARAMS-SPEC §2) are plain `<a>`s: they navigate,
19
+ * fire no event and need no service or role, so they work everywhere.
20
+ */
21
+ import BlockIcon from "../../review/BlockIcon.svelte"
22
+ import { onDestroy, onMount } from "svelte"
23
+ import type { BlockProps } from "../../types.js"
24
+ import {
25
+ intentOf,
26
+ isLinkAction,
27
+ isOffOrigin,
28
+ isTerminal,
29
+ validateActionRequest,
30
+ type ActionDef,
31
+ type ActionsParams,
32
+ type AckStatus,
33
+ } from "./schema.js"
34
+ import {
35
+ actionsServiceOf,
36
+ latestByAction,
37
+ type ActionRequestView,
38
+ } from "./requests.js"
39
+ import SectionTools from "../../SectionTools.svelte"
40
+
41
+ let { params, ctx }: BlockProps<ActionsParams> = $props()
42
+
43
+ /** Poll cadence while a request is open (queued/running). */
44
+ const POLL_MS = 4000
45
+
46
+ const service = $derived(actionsServiceOf(ctx?.services))
47
+ /** The viewer could act here, but the host wired no actions service. */
48
+ const unwired = $derived(
49
+ Boolean(ctx?.saveState) && !ctx?.readonly && service === null,
50
+ )
51
+ const live = $derived(
52
+ Boolean(ctx?.saveState) && !ctx?.readonly && service !== null,
53
+ )
54
+ const origin = typeof location !== "undefined" ? location.origin : undefined
55
+ const requestActions = $derived(
56
+ (params?.actions ?? []).filter((a) => !isLinkAction(a)),
57
+ )
58
+ const actions = $derived(params?.actions ?? [])
59
+
60
+ let requests = $state<ActionRequestView[]>([])
61
+ let allowed = $state<Record<string, boolean> | null>(null)
62
+ let loadError = $state<string | null>(null)
63
+ /** actionId → in-flight POST */
64
+ let sending = $state<Record<string, boolean>>({})
65
+ /** actionId → last send/validation error */
66
+ let sendError = $state<Record<string, string>>({})
67
+ /** actionId → the danger confirm panel is open */
68
+ let confirming = $state<Record<string, boolean>>({})
69
+ /** actionId → typed reason (danger) */
70
+ let reasons = $state<Record<string, string>>({})
71
+ /** actionId → fieldId → raw form value */
72
+ let values = $state<Record<string, Record<string, string>>>({})
73
+
74
+ // Seed form values from field defaults once per action id.
75
+ $effect.pre(() => {
76
+ for (const a of requestActions) {
77
+ if (values[a.id]) continue
78
+ const seeded: Record<string, string> = {}
79
+ for (const f of a.fields) {
80
+ if (f.default !== undefined) seeded[f.id] = String(f.default)
81
+ else if (f.type === "select" && f.required)
82
+ seeded[f.id] = f.options[0]?.value ?? ""
83
+ else seeded[f.id] = ""
84
+ }
85
+ values[a.id] = seeded
86
+ }
87
+ })
88
+
89
+ const latest = $derived(latestByAction(requests))
90
+ const anyOpen = $derived(requests.some((r) => !isTerminal(r.status)))
91
+
92
+ let timer: ReturnType<typeof setTimeout> | null = null
93
+ let destroyed = false
94
+
95
+ async function refresh() {
96
+ if (!live || !service || !ctx?.artifactId) return
97
+ try {
98
+ const out = await service.load({
99
+ artifactId: ctx.artifactId,
100
+ blockId: ctx.blockId,
101
+ })
102
+ requests = out.requests
103
+ allowed = out.allowed
104
+ loadError = null
105
+ } catch (e) {
106
+ loadError =
107
+ e instanceof Error ? e.message : "Could not load request status"
108
+ }
109
+ }
110
+
111
+ function schedule() {
112
+ if (timer) clearTimeout(timer)
113
+ timer = null
114
+ if (destroyed || !live || !anyOpen) return
115
+ timer = setTimeout(async () => {
116
+ if (typeof document !== "undefined" && document.hidden) {
117
+ schedule()
118
+ return
119
+ }
120
+ await refresh()
121
+ schedule()
122
+ }, POLL_MS)
123
+ }
124
+
125
+ onMount(() => {
126
+ if (!live) return
127
+ void refresh().then(schedule)
128
+ })
129
+ onDestroy(() => {
130
+ destroyed = true
131
+ if (timer) clearTimeout(timer)
132
+ })
133
+
134
+ function mayAct(a: ActionDef): boolean {
135
+ if (!live) return false
136
+ // Until the first read answers, assume yes; the server re-checks anyway.
137
+ return allowed === null ? true : allowed[a.id] === true
138
+ }
139
+
140
+ async function send(a: ActionDef) {
141
+ if (!ctx?.artifactId || !service || sending[a.id]) return
142
+ const check = validateActionRequest(
143
+ a,
144
+ values[a.id] ?? {},
145
+ reasons[a.id] ?? "",
146
+ )
147
+ if (!check.ok) {
148
+ sendError[a.id] = check.error
149
+ return
150
+ }
151
+ sending[a.id] = true
152
+ sendError[a.id] = ""
153
+ try {
154
+ const req = await service.send({
155
+ artifactId: ctx.artifactId,
156
+ blockId: ctx.blockId,
157
+ actionId: a.id,
158
+ inputs: check.inputs,
159
+ reason: check.reason,
160
+ })
161
+ requests = [...requests.filter((r) => r.id !== req.id), req]
162
+ confirming[a.id] = false
163
+ reasons[a.id] = ""
164
+ schedule()
165
+ } catch (e) {
166
+ // Already open: show the existing request instead of a second one.
167
+ // Duck-typed (any error carrying `request`), so a host need not import
168
+ // ActionRequestError to say so.
169
+ const existing = (e as { request?: ActionRequestView | null } | null)
170
+ ?.request
171
+ if (existing && typeof existing === "object" && existing.id) {
172
+ requests = [...requests.filter((r) => r.id !== existing.id), existing]
173
+ schedule()
174
+ }
175
+ sendError[a.id] = e instanceof Error ? e.message : "Request failed"
176
+ } finally {
177
+ sending[a.id] = false
178
+ }
179
+ }
180
+
181
+ /** The danger confirm needs the reason first; the button opens it. */
182
+ function primaryClick(a: ActionDef) {
183
+ if (a.variant === "danger" && !confirming[a.id]) {
184
+ const check = validateActionRequest(a, values[a.id] ?? {}, null, {
185
+ fieldsOnly: true,
186
+ })
187
+ if (!check.ok) {
188
+ sendError[a.id] = check.error
189
+ return
190
+ }
191
+ sendError[a.id] = ""
192
+ confirming[a.id] = true
193
+ return
194
+ }
195
+ void send(a)
196
+ }
197
+
198
+ const STATUS: Record<
199
+ AckStatus,
200
+ { label: string; cls: string; icon: "clock" | "spin" | "check" | "x" }
201
+ > = {
202
+ queued: {
203
+ label: "Queued",
204
+ cls: "border-base-content/20 bg-base-200 text-base-content/80",
205
+ icon: "clock",
206
+ },
207
+ running: {
208
+ label: "Running",
209
+ cls: "border-info/40 bg-info/10 text-base-content",
210
+ icon: "spin",
211
+ },
212
+ done: {
213
+ label: "Done",
214
+ cls: "border-success/40 bg-success/10 text-base-content",
215
+ icon: "check",
216
+ },
217
+ failed: {
218
+ label: "Failed",
219
+ cls: "border-error/40 bg-error/10 text-base-content",
220
+ icon: "x",
221
+ },
222
+ }
223
+
224
+ const whenFmt = new Intl.DateTimeFormat("en-US", {
225
+ month: "short",
226
+ day: "numeric",
227
+ hour: "numeric",
228
+ minute: "2-digit",
229
+ })
230
+ function when(iso: string | null | undefined): string {
231
+ if (!iso) return ""
232
+ const d = new Date(iso)
233
+ return Number.isFinite(d.getTime()) ? whenFmt.format(d) : ""
234
+ }
235
+
236
+ function buttonClass(a: ActionDef): string {
237
+ if (a.variant === "danger") return "btn btn-sm btn-error"
238
+ if (a.variant === "primary") return "btn btn-sm btn-primary"
239
+ return "btn btn-sm btn-outline"
240
+ }
241
+
242
+ const inputCls =
243
+ "input input-sm w-full rounded-field border-base-content/20 bg-base-100"
244
+ </script>
245
+
246
+ <section
247
+ class="rounded-box border border-base-content/10 bg-base-100 p-4 sm:p-5"
248
+ data-block="actions"
249
+ aria-label={params?.title ?? "Actions"}
250
+ >
251
+ {#if params?.title}
252
+ <div class="flex items-center gap-2">
253
+ <h3 class="min-w-0 text-base font-semibold text-base-content">
254
+ {params.title}
255
+ </h3>
256
+ <SectionTools {ctx} inline />
257
+ </div>
258
+ {/if}
259
+ {#if params?.description}
260
+ <p class="mt-1 text-sm whitespace-pre-line text-base-content/70">
261
+ {params.description}
262
+ </p>
263
+ {/if}
264
+
265
+ {#if !live && requestActions.length > 0}
266
+ <p class="mt-2 text-xs text-base-content/60" data-testid="actions-readonly">
267
+ {unwired
268
+ ? "Requests can't be sent from this view."
269
+ : "Requests can be sent by signed-in workspace members."}
270
+ </p>
271
+ {:else if loadError}
272
+ <p class="mt-2 text-xs text-error" role="status">{loadError}</p>
273
+ {/if}
274
+
275
+ <ul class="mt-3 flex flex-col gap-3">
276
+ {#each actions as a (a.id)}
277
+ {#if isLinkAction(a)}
278
+ {@const external = isOffOrigin(a.href, origin)}
279
+ <li
280
+ class="rounded-field border border-base-content/10 p-3"
281
+ data-action={a.id}
282
+ data-link-action
283
+ >
284
+ <div class="flex flex-wrap items-center justify-between gap-2">
285
+ <div class="min-w-0 flex-1">
286
+ <p class="text-sm font-medium text-base-content">{a.label}</p>
287
+ {#if a.description}
288
+ <p class="mt-0.5 text-xs text-base-content/70">
289
+ {a.description}
290
+ </p>
291
+ {/if}
292
+ </div>
293
+ <a
294
+ class={buttonClass(a)}
295
+ href={a.href}
296
+ target={external ? "_blank" : undefined}
297
+ rel={external ? "noopener noreferrer" : undefined}
298
+ >
299
+ {a.label}
300
+ {#if external}
301
+ <BlockIcon name="external-link" size={14} />
302
+ <span class="sr-only"> (opens in a new tab)</span>
303
+ {/if}
304
+ </a>
305
+ </div>
306
+ </li>
307
+ {:else}
308
+ {@const req = latest.get(a.id)}
309
+ {@const open = req ? !isTerminal(req.status) : false}
310
+ {@const permitted = mayAct(a)}
311
+ {@const st = req ? STATUS[req.status] : null}
312
+ <li
313
+ class="rounded-field border border-base-content/10 p-3"
314
+ data-action={a.id}
315
+ data-status={req?.status ?? "idle"}
316
+ >
317
+ <form
318
+ class="flex flex-col gap-2"
319
+ onsubmit={(e) => {
320
+ e.preventDefault()
321
+ primaryClick(a)
322
+ }}
323
+ >
324
+ <div class="flex flex-wrap items-start justify-between gap-2">
325
+ <div class="min-w-0 flex-1">
326
+ <p class="text-sm font-medium text-base-content">{a.label}</p>
327
+ {#if a.description}
328
+ <p class="mt-0.5 text-xs text-base-content/70">
329
+ {a.description}
330
+ </p>
331
+ {/if}
332
+ <p class="mt-0.5 font-mono text-2xs text-base-content/50">
333
+ {intentOf(a)}
334
+ </p>
335
+ </div>
336
+ {#if st && req}
337
+ <span
338
+ class="inline-flex shrink-0 items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium {st.cls}"
339
+ data-testid="action-status"
340
+ >
341
+ {#if st.icon === "clock"}
342
+ <BlockIcon name="clock" size={12} aria-hidden="true" />
343
+ {:else if st.icon === "spin"}
344
+ <BlockIcon name="loader-circle"
345
+ size={12}
346
+ class="motion-safe:animate-spin"
347
+ aria-hidden="true"
348
+ />
349
+ {:else if st.icon === "check"}
350
+ <BlockIcon name="check" size={12} class="text-success" aria-hidden="true" />
351
+ {:else}
352
+ <BlockIcon name="circle-alert"
353
+ size={12}
354
+ class="text-error"
355
+ aria-hidden="true"
356
+ />
357
+ {/if}
358
+ {st.label}{req.status === "done" ? " ✓" : ""}
359
+ </span>
360
+ {/if}
361
+ </div>
362
+
363
+ {#if a.fields.length > 0}
364
+ <div class="grid gap-2 sm:grid-cols-2">
365
+ {#each a.fields as f (f.id)}
366
+ {@const fid = `act-${ctx?.blockId}-${a.id}-${f.id}`}
367
+ <label
368
+ class="flex min-w-0 flex-col gap-1 text-xs text-base-content/75 {f.type ===
369
+ 'text' && f.multiline
370
+ ? 'sm:col-span-2'
371
+ : ''}"
372
+ for={fid}
373
+ >
374
+ <span
375
+ >{f.label}{#if f.required}<span
376
+ class="text-error"
377
+ aria-hidden="true">{" *"}</span
378
+ >{/if}</span
379
+ >
380
+ {#if !values[a.id]}
381
+ <!-- seeded on the next tick -->
382
+ {:else if f.type === "select"}
383
+ <div
384
+ class="select select-sm w-full rounded-field border-base-content/20"
385
+ >
386
+ <select
387
+ id={fid}
388
+ bind:value={values[a.id][f.id]}
389
+ disabled={!permitted || open}
390
+ required={f.required}
391
+ >
392
+ {#if !f.required}<option value="">—</option>{/if}
393
+ {#each f.options as o (o.value)}
394
+ <option value={o.value}>{o.label}</option>
395
+ {/each}
396
+ </select>
397
+ </div>
398
+ {:else if f.type === "number"}
399
+ <input
400
+ id={fid}
401
+ type="number"
402
+ class={inputCls}
403
+ bind:value={values[a.id][f.id]}
404
+ min={f.min}
405
+ max={f.max}
406
+ step={f.step ?? "any"}
407
+ disabled={!permitted || open}
408
+ required={f.required}
409
+ />
410
+ {:else if f.multiline}
411
+ <textarea
412
+ id={fid}
413
+ class="textarea textarea-sm w-full rounded-field border-base-content/20"
414
+ rows="2"
415
+ bind:value={values[a.id][f.id]}
416
+ maxlength={f.maxLength}
417
+ placeholder={f.placeholder}
418
+ disabled={!permitted || open}
419
+ required={f.required}
420
+ ></textarea>
421
+ {:else}
422
+ <input
423
+ id={fid}
424
+ type="text"
425
+ class={inputCls}
426
+ bind:value={values[a.id][f.id]}
427
+ maxlength={f.maxLength}
428
+ placeholder={f.placeholder}
429
+ disabled={!permitted || open}
430
+ required={f.required}
431
+ />
432
+ {/if}
433
+ </label>
434
+ {/each}
435
+ </div>
436
+ {/if}
437
+
438
+ {#if confirming[a.id]}
439
+ <div
440
+ class="flex flex-col gap-2 rounded-field border border-error/40 bg-error/10 p-3"
441
+ data-testid="action-confirm"
442
+ >
443
+ <p class="flex items-start gap-2 text-sm text-base-content">
444
+ <BlockIcon name="triangle-alert"
445
+ size={16}
446
+ class="mt-0.5 shrink-0 text-error"
447
+ aria-hidden="true"
448
+ />
449
+ <span
450
+ >{a.confirm ??
451
+ `This asks the agent to “${a.label}”. Say why before it is sent.`}</span
452
+ >
453
+ </p>
454
+ <label
455
+ class="flex flex-col gap-1 text-xs text-base-content/75"
456
+ for={`act-${ctx?.blockId}-${a.id}-reason`}
457
+ >
458
+ Reason (required)
459
+ <textarea
460
+ id={`act-${ctx?.blockId}-${a.id}-reason`}
461
+ class="textarea textarea-sm w-full rounded-field border-base-content/20"
462
+ rows="2"
463
+ maxlength="500"
464
+ bind:value={reasons[a.id]}
465
+ ></textarea>
466
+ </label>
467
+ <div class="flex flex-wrap gap-2">
468
+ <button
469
+ type="button"
470
+ class="btn btn-sm btn-error"
471
+ disabled={sending[a.id]}
472
+ onclick={() => void send(a)}
473
+ >
474
+ {#if sending[a.id]}<BlockIcon name="loader-circle"
475
+ size={14}
476
+ class="motion-safe:animate-spin"
477
+ aria-hidden="true"
478
+ />{/if}
479
+ Send request
480
+ </button>
481
+ <button
482
+ type="button"
483
+ class="btn btn-sm btn-ghost"
484
+ onclick={() => {
485
+ confirming[a.id] = false
486
+ sendError[a.id] = ""
487
+ }}>Cancel</button
488
+ >
489
+ </div>
490
+ </div>
491
+ {:else if live}
492
+ <div class="flex flex-wrap items-center gap-2">
493
+ <button
494
+ type="submit"
495
+ class={buttonClass(a)}
496
+ disabled={!permitted || open || sending[a.id]}
497
+ aria-describedby={req
498
+ ? `act-${ctx?.blockId}-${a.id}-st`
499
+ : undefined}
500
+ >
501
+ {#if sending[a.id]}
502
+ <BlockIcon name="loader-circle"
503
+ size={14}
504
+ class="motion-safe:animate-spin"
505
+ aria-hidden="true"
506
+ />
507
+ {:else}
508
+ <BlockIcon name="send" size={14} aria-hidden="true" />
509
+ {/if}
510
+ {req && isTerminal(req.status) ? `${a.label} again` : a.label}
511
+ </button>
512
+ {#if !permitted}
513
+ <span class="text-xs text-base-content/60"
514
+ >Your role can't send this request.</span
515
+ >
516
+ {:else if open}
517
+ <span class="text-xs text-base-content/60"
518
+ >Waiting on the agent…</span
519
+ >
520
+ {/if}
521
+ </div>
522
+ {/if}
523
+
524
+ {#if sendError[a.id]}
525
+ <p class="text-xs text-error" role="alert">{sendError[a.id]}</p>
526
+ {/if}
527
+
528
+ {#if req}
529
+ <div
530
+ id={`act-${ctx?.blockId}-${a.id}-st`}
531
+ class="text-xs text-base-content/70"
532
+ role="status"
533
+ aria-live="polite"
534
+ >
535
+ {#if req.note}
536
+ <p
537
+ class="whitespace-pre-line text-base-content"
538
+ data-testid="action-note"
539
+ >
540
+ {req.note}
541
+ </p>
542
+ {/if}
543
+ <p class="mt-0.5 text-base-content/60">
544
+ {req.mine ? "You" : (req.viewerLabel ?? "Someone")} asked · {when(
545
+ req.createdAt,
546
+ )}{#if req.ackedBy}{" · "}{req.ackedBy}{req.ackedAt
547
+ ? ` · ${when(req.ackedAt)}`
548
+ : ""}{/if}
549
+ </p>
550
+ </div>
551
+ {/if}
552
+ </form>
553
+ </li>
554
+ {/if}
555
+ {/each}
556
+ </ul>
557
+ </section>
@@ -0,0 +1,48 @@
1
+ import type { BlockProps } from "../../types.js";
2
+ declare const ActionsBlock: import("svelte").Component<BlockProps<{
3
+ actions: {
4
+ id: string;
5
+ label: string;
6
+ variant: "primary" | "default" | "danger";
7
+ fields: ({
8
+ id: string;
9
+ type: "number";
10
+ label: string;
11
+ required: boolean;
12
+ min?: number | undefined;
13
+ max?: number | undefined;
14
+ step?: number | undefined;
15
+ default?: number | undefined;
16
+ } | {
17
+ id: string;
18
+ type: "select";
19
+ label: string;
20
+ required: boolean;
21
+ options: {
22
+ value: string;
23
+ label: string;
24
+ }[];
25
+ default?: string | undefined;
26
+ } | {
27
+ id: string;
28
+ type: "text";
29
+ label: string;
30
+ required: boolean;
31
+ multiline: boolean;
32
+ maxLength: number;
33
+ placeholder?: string | undefined;
34
+ default?: string | undefined;
35
+ })[];
36
+ description?: string | undefined;
37
+ intent?: string | undefined;
38
+ confirm?: string | undefined;
39
+ roles?: ("owner" | "admin" | "member" | "viewer" | "office" | "provider")[] | undefined;
40
+ owner?: string | undefined;
41
+ href?: string | undefined;
42
+ }[];
43
+ title?: string | undefined;
44
+ description?: string | undefined;
45
+ owner?: string | undefined;
46
+ }>, {}, "">;
47
+ type ActionsBlock = ReturnType<typeof ActionsBlock>;
48
+ export default ActionsBlock;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * actions block — buttons and small forms that send a REQUEST back to the
3
+ * owning agent (mos-p9auh, living artifacts phase 4).
4
+ */
5
+ import type { ArtifactBlockDef } from "../../types.js";
6
+ import { type ActionsParams } from "./schema.js";
7
+ declare const def: ArtifactBlockDef<ActionsParams>;
8
+ export default def;
@@ -0,0 +1,74 @@
1
+ import ActionsBlock from "./ActionsBlock.svelte";
2
+ import { actionsSchema } from "./schema.js";
3
+ const EXAMPLE = {
4
+ title: "Soak controls",
5
+ description: "Ask the soak agent to re-run a scenario, apply loops, or pause.",
6
+ actions: [
7
+ {
8
+ id: "rerun-scenario",
9
+ label: "Re-run scenario",
10
+ description: "Queues one more soak pass of the chosen scenario.",
11
+ intent: "rerun-scenario",
12
+ variant: "primary",
13
+ fields: [
14
+ {
15
+ id: "scenario",
16
+ type: "select",
17
+ label: "Scenario",
18
+ required: true,
19
+ multiline: false,
20
+ options: [
21
+ { value: "ruby_office_switch", label: "Ruby office switch" },
22
+ { value: "after_hours", label: "After hours" },
23
+ ],
24
+ default: "ruby_office_switch",
25
+ },
26
+ {
27
+ id: "calls",
28
+ type: "number",
29
+ label: "Calls",
30
+ required: false,
31
+ min: 1,
32
+ max: 50,
33
+ default: 10,
34
+ },
35
+ ],
36
+ },
37
+ {
38
+ id: "apply-v3-loops",
39
+ label: "Approve & apply v3 loops",
40
+ intent: "apply-loops:v3",
41
+ variant: "default",
42
+ fields: [],
43
+ },
44
+ {
45
+ id: "open-uat",
46
+ label: "Open the UAT build",
47
+ description: "A link, not a request: opens the build to test.",
48
+ href: "https://uat.example.com/soak",
49
+ variant: "default",
50
+ fields: [],
51
+ },
52
+ {
53
+ id: "pause-soak",
54
+ label: "Pause soak",
55
+ description: "Stops new calls; in-flight calls finish.",
56
+ intent: "pause-soak",
57
+ variant: "danger",
58
+ confirm: "Pausing stops the overnight soak until someone resumes it.",
59
+ roles: ["admin", "owner"],
60
+ fields: [],
61
+ },
62
+ ],
63
+ };
64
+ const def = {
65
+ type: "actions",
66
+ title: "Actions (buttons that ask the agent)",
67
+ description: "Two-way page controls: buttons and small forms whose press sends a REQUEST back to the owning agent — 'Re-run scenario ruby_office_switch', 'Approve & apply v3 loops', 'Pause soak'. MOS never runs anything: a press records one event (kind 'action': viewer, intent, inputs, reason) that you receive through `mos-artifact watch --slug s --kind action` or `mos-artifact drain --owner <you>`; act on it, then answer with `mos-artifact ack --event <id> --status running|done|failed --note '…'` and the button walks Queued → Running → Done ✓ / Failed with your note (open pages poll every 4s). A finished request is final; pressing again is a new request, and while one is open the button is held so a double-click cannot queue twice. Params: title?, description?, owner? (the agent that hears these; falls back to the block owner, then the publisher), actions[1-12] of { id (stable, lowercase a-z0-9_-), label (≤80), description?, intent? (the machine string you switch on; defaults to id), variant default|primary|danger, confirm? (danger copy), roles? (exact team roles allowed — viewer|member|office|provider|admin|owner; default every member-rank role), owner? (per-action routing), fields[0-8] }. Fields: { id, type:'text', label, placeholder?, required?, multiline?, maxLength? (≤2000) } | { id, type:'number', label, min?, max?, step?, required?, default? } | { id, type:'select', label, options[1-30] {value,label}, required?, default? }. The server re-validates every input against these declarations and drops undeclared ones. variant 'danger' requires a confirm step AND a typed reason (sent to you as payload.reason). LINKS (PARAMS-SPEC §2): give an action `href` (http(s):// or root-relative) and it is a plain link button — it opens the url (off-origin in a new tab), sends no request, ignores intent/fields/confirm/roles/owner and needs no team role, so it works on a read-only share link too; use it for 'Open the UAT build', 'Open the task'. Requests go through the host's actions service (jatui HostAdapter.services.actions); a host without one shows the request list without controls and says requests can't be sent from that view. Rate-limited per viewer. Signed-out / public-link viewers see the list without controls. Tip: one action per thing the agent can actually do, and always ack — an unacked request sits at Queued.",
68
+ schema: actionsSchema,
69
+ component: ActionsBlock,
70
+ // mos-8fvt9: the section's Listen + comment sit on the heading row.
71
+ hostsTools: (p) => Boolean(p.title),
72
+ example: EXAMPLE,
73
+ };
74
+ export default def;