@dxos/plugin-routine 0.0.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 (403) hide show
  1. package/LICENSE +105 -0
  2. package/PLUGIN.mdl +475 -0
  3. package/README.md +15 -0
  4. package/dist/lib/neutral/RoutineArticle-UNTMV4CC.mjs +95 -0
  5. package/dist/lib/neutral/RoutineArticle-UNTMV4CC.mjs.map +7 -0
  6. package/dist/lib/neutral/RoutineCompanion-ZZ6WMY7I.mjs +249 -0
  7. package/dist/lib/neutral/RoutineCompanion-ZZ6WMY7I.mjs.map +7 -0
  8. package/dist/lib/neutral/RoutinePlugin.mjs +10 -0
  9. package/dist/lib/neutral/RoutinePlugin.mjs.map +7 -0
  10. package/dist/lib/neutral/RoutinePlugin.node.mjs +1133 -0
  11. package/dist/lib/neutral/RoutinePlugin.node.mjs.map +7 -0
  12. package/dist/lib/neutral/RoutinePlugin.workerd.mjs +36 -0
  13. package/dist/lib/neutral/RoutinePlugin.workerd.mjs.map +7 -0
  14. package/dist/lib/neutral/RoutineSettings-ZJOM4F3S.mjs +48 -0
  15. package/dist/lib/neutral/RoutineSettings-ZJOM4F3S.mjs.map +7 -0
  16. package/dist/lib/neutral/RoutineTraceCompanion-5U6R7LJE.mjs +236 -0
  17. package/dist/lib/neutral/RoutineTraceCompanion-5U6R7LJE.mjs.map +7 -0
  18. package/dist/lib/neutral/SkillArticle-WWDNKW2Z.mjs +27 -0
  19. package/dist/lib/neutral/SkillArticle-WWDNKW2Z.mjs.map +7 -0
  20. package/dist/lib/neutral/app-graph-builder-FALWLZTI.mjs +90 -0
  21. package/dist/lib/neutral/app-graph-builder-FALWLZTI.mjs.map +7 -0
  22. package/dist/lib/neutral/capabilities/index.mjs +25 -0
  23. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  24. package/dist/lib/neutral/capabilities/node.mjs +19 -0
  25. package/dist/lib/neutral/capabilities/node.mjs.map +7 -0
  26. package/dist/lib/neutral/chunk-674LDIUJ.mjs +9 -0
  27. package/dist/lib/neutral/chunk-674LDIUJ.mjs.map +7 -0
  28. package/dist/lib/neutral/chunk-CNYAPXUW.mjs +65 -0
  29. package/dist/lib/neutral/chunk-CNYAPXUW.mjs.map +7 -0
  30. package/dist/lib/neutral/chunk-HLO4LYXT.mjs +44 -0
  31. package/dist/lib/neutral/chunk-HLO4LYXT.mjs.map +7 -0
  32. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  33. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +7 -0
  34. package/dist/lib/neutral/chunk-ODQDVFMZ.mjs +8 -0
  35. package/dist/lib/neutral/chunk-ODQDVFMZ.mjs.map +7 -0
  36. package/dist/lib/neutral/chunk-R7J2MU2M.mjs +263 -0
  37. package/dist/lib/neutral/chunk-R7J2MU2M.mjs.map +7 -0
  38. package/dist/lib/neutral/chunk-WLNL77C7.mjs +14 -0
  39. package/dist/lib/neutral/chunk-WLNL77C7.mjs.map +7 -0
  40. package/dist/lib/neutral/components/index.mjs +1921 -0
  41. package/dist/lib/neutral/components/index.mjs.map +7 -0
  42. package/dist/lib/neutral/containers/index.mjs +17 -0
  43. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  44. package/dist/lib/neutral/create-object-V23KVDMJ.mjs +25 -0
  45. package/dist/lib/neutral/create-object-V23KVDMJ.mjs.map +7 -0
  46. package/dist/lib/neutral/create-routine-I67BYJA2.mjs +38 -0
  47. package/dist/lib/neutral/create-routine-I67BYJA2.mjs.map +7 -0
  48. package/dist/lib/neutral/create-trigger-from-template-U3KNS77V.mjs +70 -0
  49. package/dist/lib/neutral/create-trigger-from-template-U3KNS77V.mjs.map +7 -0
  50. package/dist/lib/neutral/hooks/index.mjs +47 -0
  51. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  52. package/dist/lib/neutral/index.mjs +27 -0
  53. package/dist/lib/neutral/index.mjs.map +7 -0
  54. package/dist/lib/neutral/layer-specs-ADQCTTRT.mjs +135 -0
  55. package/dist/lib/neutral/layer-specs-ADQCTTRT.mjs.map +7 -0
  56. package/dist/lib/neutral/meta.json +1 -0
  57. package/dist/lib/neutral/meta.mjs +8 -0
  58. package/dist/lib/neutral/meta.mjs.map +7 -0
  59. package/dist/lib/neutral/navigation-resolver-KQIWUH6F.mjs +18 -0
  60. package/dist/lib/neutral/navigation-resolver-KQIWUH6F.mjs.map +7 -0
  61. package/dist/lib/neutral/operation-handler-QKLJSDCQ.mjs +13 -0
  62. package/dist/lib/neutral/operation-handler-QKLJSDCQ.mjs.map +7 -0
  63. package/dist/lib/neutral/operations/index.mjs +8 -0
  64. package/dist/lib/neutral/operations/index.mjs.map +7 -0
  65. package/dist/lib/neutral/plugin.mjs +16 -0
  66. package/dist/lib/neutral/plugin.mjs.map +7 -0
  67. package/dist/lib/neutral/react-surface-GMO7I7YE.mjs +67 -0
  68. package/dist/lib/neutral/react-surface-GMO7I7YE.mjs.map +7 -0
  69. package/dist/lib/neutral/registry-sync-PHBU6CH2.mjs +86 -0
  70. package/dist/lib/neutral/registry-sync-PHBU6CH2.mjs.map +7 -0
  71. package/dist/lib/neutral/run-routine-HJWXIWLJ.mjs +37 -0
  72. package/dist/lib/neutral/run-routine-HJWXIWLJ.mjs.map +7 -0
  73. package/dist/lib/neutral/templates-IIUCEBAX.mjs +49 -0
  74. package/dist/lib/neutral/templates-IIUCEBAX.mjs.map +7 -0
  75. package/dist/lib/neutral/testing.mjs +8 -0
  76. package/dist/lib/neutral/testing.mjs.map +7 -0
  77. package/dist/lib/neutral/translations.mjs +115 -0
  78. package/dist/lib/neutral/translations.mjs.map +7 -0
  79. package/dist/lib/neutral/trigger-runtime-controller-7FOTH2NP.mjs +77 -0
  80. package/dist/lib/neutral/trigger-runtime-controller-7FOTH2NP.mjs.map +7 -0
  81. package/dist/lib/neutral/types/index.mjs +17 -0
  82. package/dist/lib/neutral/types/index.mjs.map +7 -0
  83. package/dist/types/dx.config.d.ts +28 -0
  84. package/dist/types/dx.config.d.ts.map +1 -0
  85. package/dist/types/src/RoutinePlugin.d.ts +4 -0
  86. package/dist/types/src/RoutinePlugin.d.ts.map +1 -0
  87. package/dist/types/src/RoutinePlugin.node.d.ts +4 -0
  88. package/dist/types/src/RoutinePlugin.node.d.ts.map +1 -0
  89. package/dist/types/src/RoutinePlugin.test.d.ts +2 -0
  90. package/dist/types/src/RoutinePlugin.test.d.ts.map +1 -0
  91. package/dist/types/src/RoutinePlugin.workerd.d.ts +4 -0
  92. package/dist/types/src/RoutinePlugin.workerd.d.ts.map +1 -0
  93. package/dist/types/src/capabilities/app-graph-builder.d.ts +5 -0
  94. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  95. package/dist/types/src/capabilities/create-object.d.ts +5 -0
  96. package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
  97. package/dist/types/src/capabilities/create-object.test.d.ts +2 -0
  98. package/dist/types/src/capabilities/create-object.test.d.ts.map +1 -0
  99. package/dist/types/src/capabilities/index.d.ts +12 -0
  100. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  101. package/dist/types/src/capabilities/layer-specs.d.ts +5 -0
  102. package/dist/types/src/capabilities/layer-specs.d.ts.map +1 -0
  103. package/dist/types/src/capabilities/navigation-resolver.d.ts +5 -0
  104. package/dist/types/src/capabilities/navigation-resolver.d.ts.map +1 -0
  105. package/dist/types/src/capabilities/node.d.ts +9 -0
  106. package/dist/types/src/capabilities/node.d.ts.map +1 -0
  107. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  108. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  109. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  110. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  111. package/dist/types/src/capabilities/registry-sync.d.ts +21 -0
  112. package/dist/types/src/capabilities/registry-sync.d.ts.map +1 -0
  113. package/dist/types/src/capabilities/templates.d.ts +5 -0
  114. package/dist/types/src/capabilities/templates.d.ts.map +1 -0
  115. package/dist/types/src/capabilities/trigger-runtime-controller.d.ts +5 -0
  116. package/dist/types/src/capabilities/trigger-runtime-controller.d.ts.map +1 -0
  117. package/dist/types/src/capabilities/trigger-runtime-controller.test.d.ts +2 -0
  118. package/dist/types/src/capabilities/trigger-runtime-controller.test.d.ts.map +1 -0
  119. package/dist/types/src/commands/index.d.ts +2 -0
  120. package/dist/types/src/commands/index.d.ts.map +1 -0
  121. package/dist/types/src/commands/trigger/create/index.d.ts +25 -0
  122. package/dist/types/src/commands/trigger/create/index.d.ts.map +1 -0
  123. package/dist/types/src/commands/trigger/create/queue.d.ts +13 -0
  124. package/dist/types/src/commands/trigger/create/queue.d.ts.map +1 -0
  125. package/dist/types/src/commands/trigger/create/subscription.d.ts +15 -0
  126. package/dist/types/src/commands/trigger/create/subscription.d.ts.map +1 -0
  127. package/dist/types/src/commands/trigger/create/timer.d.ts +13 -0
  128. package/dist/types/src/commands/trigger/create/timer.d.ts.map +1 -0
  129. package/dist/types/src/commands/trigger/index.d.ts +57 -0
  130. package/dist/types/src/commands/trigger/index.d.ts.map +1 -0
  131. package/dist/types/src/commands/trigger/list.d.ts +7 -0
  132. package/dist/types/src/commands/trigger/list.d.ts.map +1 -0
  133. package/dist/types/src/commands/trigger/options.d.ts +10 -0
  134. package/dist/types/src/commands/trigger/options.d.ts.map +1 -0
  135. package/dist/types/src/commands/trigger/remove.d.ts +8 -0
  136. package/dist/types/src/commands/trigger/remove.d.ts.map +1 -0
  137. package/dist/types/src/commands/trigger/update/index.d.ts +28 -0
  138. package/dist/types/src/commands/trigger/update/index.d.ts.map +1 -0
  139. package/dist/types/src/commands/trigger/update/queue.d.ts +13 -0
  140. package/dist/types/src/commands/trigger/update/queue.d.ts.map +1 -0
  141. package/dist/types/src/commands/trigger/update/subscription.d.ts +15 -0
  142. package/dist/types/src/commands/trigger/update/subscription.d.ts.map +1 -0
  143. package/dist/types/src/commands/trigger/update/timer.d.ts +13 -0
  144. package/dist/types/src/commands/trigger/update/timer.d.ts.map +1 -0
  145. package/dist/types/src/commands/trigger/util.d.ts +46 -0
  146. package/dist/types/src/commands/trigger/util.d.ts.map +1 -0
  147. package/dist/types/src/components/CreateRoutinePanel/CreateRoutinePanel.d.ts +14 -0
  148. package/dist/types/src/components/CreateRoutinePanel/CreateRoutinePanel.d.ts.map +1 -0
  149. package/dist/types/src/components/CreateRoutinePanel/index.d.ts +2 -0
  150. package/dist/types/src/components/CreateRoutinePanel/index.d.ts.map +1 -0
  151. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.d.ts +16 -0
  152. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.d.ts.map +1 -0
  153. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.stories.d.ts +17 -0
  154. package/dist/types/src/components/InstructionsEditor/InstructionsEditor.stories.d.ts.map +1 -0
  155. package/dist/types/src/components/InstructionsEditor/index.d.ts +2 -0
  156. package/dist/types/src/components/InstructionsEditor/index.d.ts.map +1 -0
  157. package/dist/types/src/components/MasterDetail/MasterDetail.d.ts +51 -0
  158. package/dist/types/src/components/MasterDetail/MasterDetail.d.ts.map +1 -0
  159. package/dist/types/src/components/MasterDetail/MasterDetail.stories.d.ts +16 -0
  160. package/dist/types/src/components/MasterDetail/MasterDetail.stories.d.ts.map +1 -0
  161. package/dist/types/src/components/MasterDetail/index.d.ts +2 -0
  162. package/dist/types/src/components/MasterDetail/index.d.ts.map +1 -0
  163. package/dist/types/src/components/RoutineForm/RoutineForm.d.ts +25 -0
  164. package/dist/types/src/components/RoutineForm/RoutineForm.d.ts.map +1 -0
  165. package/dist/types/src/components/RoutineForm/index.d.ts +2 -0
  166. package/dist/types/src/components/RoutineForm/index.d.ts.map +1 -0
  167. package/dist/types/src/components/Schedule/Schedule.d.ts +80 -0
  168. package/dist/types/src/components/Schedule/Schedule.d.ts.map +1 -0
  169. package/dist/types/src/components/Schedule/Schedule.stories.d.ts +23 -0
  170. package/dist/types/src/components/Schedule/Schedule.stories.d.ts.map +1 -0
  171. package/dist/types/src/components/Schedule/cron.d.ts +44 -0
  172. package/dist/types/src/components/Schedule/cron.d.ts.map +1 -0
  173. package/dist/types/src/components/Schedule/cron.test.d.ts +2 -0
  174. package/dist/types/src/components/Schedule/cron.test.d.ts.map +1 -0
  175. package/dist/types/src/components/Schedule/index.d.ts +4 -0
  176. package/dist/types/src/components/Schedule/index.d.ts.map +1 -0
  177. package/dist/types/src/components/Schedule/types.d.ts +66 -0
  178. package/dist/types/src/components/Schedule/types.d.ts.map +1 -0
  179. package/dist/types/src/components/TemplateEditor/TemplateEditor.d.ts +13 -0
  180. package/dist/types/src/components/TemplateEditor/TemplateEditor.d.ts.map +1 -0
  181. package/dist/types/src/components/TemplateEditor/TemplateEditor.stories.d.ts +19 -0
  182. package/dist/types/src/components/TemplateEditor/TemplateEditor.stories.d.ts.map +1 -0
  183. package/dist/types/src/components/TemplateEditor/TemplateForm.d.ts +21 -0
  184. package/dist/types/src/components/TemplateEditor/TemplateForm.d.ts.map +1 -0
  185. package/dist/types/src/components/TemplateEditor/TemplateForm.stories.d.ts +16 -0
  186. package/dist/types/src/components/TemplateEditor/TemplateForm.stories.d.ts.map +1 -0
  187. package/dist/types/src/components/TemplateEditor/extensions/handlebars-extension.d.ts +12 -0
  188. package/dist/types/src/components/TemplateEditor/extensions/handlebars-extension.d.ts.map +1 -0
  189. package/dist/types/src/components/TemplateEditor/extensions/index.d.ts +3 -0
  190. package/dist/types/src/components/TemplateEditor/extensions/index.d.ts.map +1 -0
  191. package/dist/types/src/components/TemplateEditor/extensions/xml-extension.d.ts +8 -0
  192. package/dist/types/src/components/TemplateEditor/extensions/xml-extension.d.ts.map +1 -0
  193. package/dist/types/src/components/TemplateEditor/index.d.ts +2 -0
  194. package/dist/types/src/components/TemplateEditor/index.d.ts.map +1 -0
  195. package/dist/types/src/components/TemplateEditor/types.d.ts +18 -0
  196. package/dist/types/src/components/TemplateEditor/types.d.ts.map +1 -0
  197. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts +24 -0
  198. package/dist/types/src/components/TriggerEditor/TriggerEditor.d.ts.map +1 -0
  199. package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts +25 -0
  200. package/dist/types/src/components/TriggerEditor/TriggerEditor.stories.d.ts.map +1 -0
  201. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.d.ts +15 -0
  202. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.d.ts.map +1 -0
  203. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.stories.d.ts +15 -0
  204. package/dist/types/src/components/TriggerEditor/TriggerKindSelector.stories.d.ts.map +1 -0
  205. package/dist/types/src/components/TriggerEditor/index.d.ts +2 -0
  206. package/dist/types/src/components/TriggerEditor/index.d.ts.map +1 -0
  207. package/dist/types/src/components/index.d.ts +8 -0
  208. package/dist/types/src/components/index.d.ts.map +1 -0
  209. package/dist/types/src/containers/RoutineArticle/RoutineArticle.d.ts +14 -0
  210. package/dist/types/src/containers/RoutineArticle/RoutineArticle.d.ts.map +1 -0
  211. package/dist/types/src/containers/RoutineArticle/RoutineArticle.stories.d.ts +20 -0
  212. package/dist/types/src/containers/RoutineArticle/RoutineArticle.stories.d.ts.map +1 -0
  213. package/dist/types/src/containers/RoutineArticle/index.d.ts +2 -0
  214. package/dist/types/src/containers/RoutineArticle/index.d.ts.map +1 -0
  215. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.d.ts +17 -0
  216. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.d.ts.map +1 -0
  217. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.stories.d.ts +15 -0
  218. package/dist/types/src/containers/RoutineCompanion/RoutineCompanion.stories.d.ts.map +1 -0
  219. package/dist/types/src/containers/RoutineCompanion/index.d.ts +3 -0
  220. package/dist/types/src/containers/RoutineCompanion/index.d.ts.map +1 -0
  221. package/dist/types/src/containers/RoutineSettings/RoutineSettings.d.ts +10 -0
  222. package/dist/types/src/containers/RoutineSettings/RoutineSettings.d.ts.map +1 -0
  223. package/dist/types/src/containers/RoutineSettings/index.d.ts +2 -0
  224. package/dist/types/src/containers/RoutineSettings/index.d.ts.map +1 -0
  225. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.d.ts +9 -0
  226. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.d.ts.map +1 -0
  227. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.stories.d.ts +15 -0
  228. package/dist/types/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.stories.d.ts.map +1 -0
  229. package/dist/types/src/containers/RoutineTraceCompanion/index.d.ts +2 -0
  230. package/dist/types/src/containers/RoutineTraceCompanion/index.d.ts.map +1 -0
  231. package/dist/types/src/containers/RoutineTraceCompanion/runs.d.ts +34 -0
  232. package/dist/types/src/containers/RoutineTraceCompanion/runs.d.ts.map +1 -0
  233. package/dist/types/src/containers/RoutineTraceCompanion/runs.test.d.ts +2 -0
  234. package/dist/types/src/containers/RoutineTraceCompanion/runs.test.d.ts.map +1 -0
  235. package/dist/types/src/containers/RoutineTraceCompanion/useRoutineRuns.d.ts +11 -0
  236. package/dist/types/src/containers/RoutineTraceCompanion/useRoutineRuns.d.ts.map +1 -0
  237. package/dist/types/src/containers/SkillArticle/SkillArticle.d.ts +6 -0
  238. package/dist/types/src/containers/SkillArticle/SkillArticle.d.ts.map +1 -0
  239. package/dist/types/src/containers/SkillArticle/index.d.ts +2 -0
  240. package/dist/types/src/containers/SkillArticle/index.d.ts.map +1 -0
  241. package/dist/types/src/containers/index.d.ts +7 -0
  242. package/dist/types/src/containers/index.d.ts.map +1 -0
  243. package/dist/types/src/hooks/index.d.ts +2 -0
  244. package/dist/types/src/hooks/index.d.ts.map +1 -0
  245. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts +12 -0
  246. package/dist/types/src/hooks/useTriggerRuntimeControls.d.ts.map +1 -0
  247. package/dist/types/src/index.d.ts +4 -0
  248. package/dist/types/src/index.d.ts.map +1 -0
  249. package/dist/types/src/meta.d.ts +33 -0
  250. package/dist/types/src/meta.d.ts.map +1 -0
  251. package/dist/types/src/operations/create-routine.d.ts +5 -0
  252. package/dist/types/src/operations/create-routine.d.ts.map +1 -0
  253. package/dist/types/src/operations/create-trigger-from-template.d.ts +5 -0
  254. package/dist/types/src/operations/create-trigger-from-template.d.ts.map +1 -0
  255. package/dist/types/src/operations/index.d.ts +3 -0
  256. package/dist/types/src/operations/index.d.ts.map +1 -0
  257. package/dist/types/src/operations/run-routine.d.ts +5 -0
  258. package/dist/types/src/operations/run-routine.d.ts.map +1 -0
  259. package/dist/types/src/paths.d.ts +5 -0
  260. package/dist/types/src/paths.d.ts.map +1 -0
  261. package/dist/types/src/plugin.d.ts +4 -0
  262. package/dist/types/src/plugin.d.ts.map +1 -0
  263. package/dist/types/src/templates/index.d.ts +11 -0
  264. package/dist/types/src/templates/index.d.ts.map +1 -0
  265. package/dist/types/src/testing/index.d.ts +2 -0
  266. package/dist/types/src/testing/index.d.ts.map +1 -0
  267. package/dist/types/src/testing/test-functions.d.ts +328 -0
  268. package/dist/types/src/testing/test-functions.d.ts.map +1 -0
  269. package/dist/types/src/testing.d.ts +2 -0
  270. package/dist/types/src/testing.d.ts.map +1 -0
  271. package/dist/types/src/translations.d.ts +3 -0
  272. package/dist/types/src/translations.d.ts.map +1 -0
  273. package/dist/types/src/types/Routine.d.ts +55 -0
  274. package/dist/types/src/types/Routine.d.ts.map +1 -0
  275. package/dist/types/src/types/Routine.test.d.ts +2 -0
  276. package/dist/types/src/types/Routine.test.d.ts.map +1 -0
  277. package/dist/types/src/types/RoutineCapabilities.d.ts +44 -0
  278. package/dist/types/src/types/RoutineCapabilities.d.ts.map +1 -0
  279. package/dist/types/src/types/RoutineOperation.d.ts +45 -0
  280. package/dist/types/src/types/RoutineOperation.d.ts.map +1 -0
  281. package/dist/types/src/types/index.d.ts +5 -0
  282. package/dist/types/src/types/index.d.ts.map +1 -0
  283. package/dist/types/src/types/schema.d.ts +33 -0
  284. package/dist/types/src/types/schema.d.ts.map +1 -0
  285. package/dist/types/src/util/index.d.ts +3 -0
  286. package/dist/types/src/util/index.d.ts.map +1 -0
  287. package/dist/types/src/util/routines-for-object.d.ts +22 -0
  288. package/dist/types/src/util/routines-for-object.d.ts.map +1 -0
  289. package/dist/types/src/util/routines-for-object.test.d.ts +2 -0
  290. package/dist/types/src/util/routines-for-object.test.d.ts.map +1 -0
  291. package/dist/types/src/util/run-instructions.d.ts +5 -0
  292. package/dist/types/src/util/run-instructions.d.ts.map +1 -0
  293. package/dist/types/src/util/run-instructions.test.d.ts +2 -0
  294. package/dist/types/src/util/run-instructions.test.d.ts.map +1 -0
  295. package/dist/types/tsconfig.tsbuildinfo +1 -0
  296. package/dx.config.ts +33 -0
  297. package/package.json +196 -0
  298. package/src/RoutinePlugin.node.ts +48 -0
  299. package/src/RoutinePlugin.test.ts +27 -0
  300. package/src/RoutinePlugin.tsx +58 -0
  301. package/src/RoutinePlugin.workerd.ts +24 -0
  302. package/src/capabilities/app-graph-builder.ts +80 -0
  303. package/src/capabilities/create-object.test.ts +18 -0
  304. package/src/capabilities/create-object.ts +26 -0
  305. package/src/capabilities/index.ts +22 -0
  306. package/src/capabilities/layer-specs.ts +190 -0
  307. package/src/capabilities/navigation-resolver.ts +21 -0
  308. package/src/capabilities/node.ts +19 -0
  309. package/src/capabilities/operation-handler.ts +16 -0
  310. package/src/capabilities/react-surface.tsx +66 -0
  311. package/src/capabilities/registry-sync.ts +114 -0
  312. package/src/capabilities/templates.ts +17 -0
  313. package/src/capabilities/trigger-runtime-controller.test.ts +107 -0
  314. package/src/capabilities/trigger-runtime-controller.ts +126 -0
  315. package/src/commands/index.ts +5 -0
  316. package/src/commands/trigger/create/index.ts +14 -0
  317. package/src/commands/trigger/create/queue.ts +87 -0
  318. package/src/commands/trigger/create/subscription.ts +126 -0
  319. package/src/commands/trigger/create/timer.ts +90 -0
  320. package/src/commands/trigger/index.ts +16 -0
  321. package/src/commands/trigger/list.ts +69 -0
  322. package/src/commands/trigger/options.ts +47 -0
  323. package/src/commands/trigger/remove.ts +45 -0
  324. package/src/commands/trigger/update/index.ts +14 -0
  325. package/src/commands/trigger/update/queue.ts +191 -0
  326. package/src/commands/trigger/update/subscription.ts +278 -0
  327. package/src/commands/trigger/update/timer.ts +194 -0
  328. package/src/commands/trigger/util.ts +412 -0
  329. package/src/components/CreateRoutinePanel/CreateRoutinePanel.tsx +68 -0
  330. package/src/components/CreateRoutinePanel/index.ts +5 -0
  331. package/src/components/InstructionsEditor/InstructionsEditor.stories.tsx +69 -0
  332. package/src/components/InstructionsEditor/InstructionsEditor.tsx +107 -0
  333. package/src/components/InstructionsEditor/index.ts +5 -0
  334. package/src/components/MasterDetail/MasterDetail.stories.tsx +100 -0
  335. package/src/components/MasterDetail/MasterDetail.tsx +175 -0
  336. package/src/components/MasterDetail/index.ts +5 -0
  337. package/src/components/RoutineForm/RoutineForm.tsx +293 -0
  338. package/src/components/RoutineForm/index.ts +5 -0
  339. package/src/components/Schedule/Schedule.stories.tsx +73 -0
  340. package/src/components/Schedule/Schedule.tsx +527 -0
  341. package/src/components/Schedule/cron.test.ts +230 -0
  342. package/src/components/Schedule/cron.ts +337 -0
  343. package/src/components/Schedule/index.ts +8 -0
  344. package/src/components/Schedule/types.ts +124 -0
  345. package/src/components/TemplateEditor/TemplateEditor.stories.tsx +93 -0
  346. package/src/components/TemplateEditor/TemplateEditor.tsx +77 -0
  347. package/src/components/TemplateEditor/TemplateForm.stories.tsx +76 -0
  348. package/src/components/TemplateEditor/TemplateForm.tsx +204 -0
  349. package/src/components/TemplateEditor/extensions/handlebars-extension.ts +274 -0
  350. package/src/components/TemplateEditor/extensions/index.ts +6 -0
  351. package/src/components/TemplateEditor/extensions/xml-extension.ts +64 -0
  352. package/src/components/TemplateEditor/index.ts +5 -0
  353. package/src/components/TemplateEditor/types.tsx +28 -0
  354. package/src/components/TriggerEditor/TriggerEditor.stories.tsx +122 -0
  355. package/src/components/TriggerEditor/TriggerEditor.tsx +365 -0
  356. package/src/components/TriggerEditor/TriggerKindSelector.stories.tsx +42 -0
  357. package/src/components/TriggerEditor/TriggerKindSelector.tsx +87 -0
  358. package/src/components/TriggerEditor/index.ts +5 -0
  359. package/src/components/index.ts +11 -0
  360. package/src/containers/RoutineArticle/RoutineArticle.stories.tsx +146 -0
  361. package/src/containers/RoutineArticle/RoutineArticle.tsx +109 -0
  362. package/src/containers/RoutineArticle/index.ts +5 -0
  363. package/src/containers/RoutineCompanion/RoutineCompanion.stories.tsx +82 -0
  364. package/src/containers/RoutineCompanion/RoutineCompanion.tsx +342 -0
  365. package/src/containers/RoutineCompanion/index.ts +6 -0
  366. package/src/containers/RoutineSettings/RoutineSettings.tsx +65 -0
  367. package/src/containers/RoutineSettings/index.ts +5 -0
  368. package/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.stories.tsx +133 -0
  369. package/src/containers/RoutineTraceCompanion/RoutineTraceCompanion.tsx +125 -0
  370. package/src/containers/RoutineTraceCompanion/index.ts +5 -0
  371. package/src/containers/RoutineTraceCompanion/runs.test.ts +140 -0
  372. package/src/containers/RoutineTraceCompanion/runs.ts +135 -0
  373. package/src/containers/RoutineTraceCompanion/useRoutineRuns.ts +50 -0
  374. package/src/containers/SkillArticle/SkillArticle.tsx +29 -0
  375. package/src/containers/SkillArticle/index.ts +5 -0
  376. package/src/containers/index.ts +11 -0
  377. package/src/hooks/index.ts +6 -0
  378. package/src/hooks/useTriggerRuntimeControls.ts +70 -0
  379. package/src/index.ts +7 -0
  380. package/src/meta.ts +9 -0
  381. package/src/operations/create-routine.ts +39 -0
  382. package/src/operations/create-trigger-from-template.ts +68 -0
  383. package/src/operations/index.ts +11 -0
  384. package/src/operations/run-routine.ts +45 -0
  385. package/src/paths.ts +18 -0
  386. package/src/plugin.ts +11 -0
  387. package/src/templates/index.ts +48 -0
  388. package/src/testing/index.ts +5 -0
  389. package/src/testing/test-functions.ts +76 -0
  390. package/src/testing.ts +7 -0
  391. package/src/translations.ts +125 -0
  392. package/src/types/Routine.test.ts +51 -0
  393. package/src/types/Routine.ts +144 -0
  394. package/src/types/RoutineCapabilities.ts +51 -0
  395. package/src/types/RoutineOperation.ts +104 -0
  396. package/src/types/index.ts +9 -0
  397. package/src/types/schema.ts +31 -0
  398. package/src/util/index.ts +6 -0
  399. package/src/util/routines-for-object.test.ts +109 -0
  400. package/src/util/routines-for-object.ts +89 -0
  401. package/src/util/run-instructions.test.ts +23 -0
  402. package/src/util/run-instructions.ts +12 -0
  403. package/src/vite-env.d.ts +10 -0
@@ -0,0 +1,109 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { Atom, RegistryContext } from '@effect-atom/atom-react';
6
+ import React, { useCallback, useContext, useMemo } from 'react';
7
+
8
+ import { useOperationInvoker } from '@dxos/app-framework/ui';
9
+ import { type AppSurface } from '@dxos/app-toolkit/ui';
10
+ import { Obj, Ref } from '@dxos/echo';
11
+ import { useObject } from '@dxos/react-client/echo';
12
+ import { Panel } from '@dxos/react-ui';
13
+ import { Menu, MenuBuilder, useMenuBuilder } from '@dxos/react-ui-menu';
14
+
15
+ import { RoutineForm } from '#components';
16
+ import { meta } from '#meta';
17
+ import { Routine, RoutineOperation } from '#types';
18
+
19
+ export type RoutineArticleProps = AppSurface.ObjectArticleProps<Routine.Routine>;
20
+
21
+ /**
22
+ * Article surface for a {@link Routine}. The form edits the live routine in place; each trigger's on/off state
23
+ * is toggled inline in the trigger editor. The toolbar exposes Run.
24
+ *
25
+ * TODO(wittjosiah): Disable editing while the routine is running (you shouldn't mutate running code). This was
26
+ * previously wired as "read-only when enabled" via a routine-level toggle, but that is not how we want to
27
+ * achieve it — reintroduce a run-state-based lock instead.
28
+ */
29
+ export const RoutineArticle = ({ role, attendableId, subject }: RoutineArticleProps) => {
30
+ const { invokePromise } = useOperationInvoker();
31
+ const registry = useContext(RegistryContext);
32
+ // Subscribe so the run affordance tracks the routine's action (`spec`).
33
+ const [routine] = useObject(subject);
34
+ const db = Obj.getDatabase(subject);
35
+
36
+ const runningAtom = useMemo(() => Atom.make(false), []);
37
+
38
+ // Require both a spec and at least one trigger: manual runs are attributed to the first trigger
39
+ // so they appear in history, and without a trigger the run would be invisible there.
40
+ const canRun = useMemo(() => Boolean(routine.spec) && routine.triggers.length > 0, [routine.spec, routine.triggers]);
41
+
42
+ const handleRun = useCallback(() => {
43
+ if (!invokePromise || !db) {
44
+ return;
45
+ }
46
+ // Thread the routine's first trigger as trace attribution so the run appears in history.
47
+ // Manual runs bypass the trigger dispatcher (which normally stamps meta.trigger), so we
48
+ // do it here — history filters on trigger entity id, and without this the run is invisible.
49
+ const triggerRef = routine.triggers[0];
50
+ registry.set(runningAtom, true);
51
+ void invokePromise(
52
+ RoutineOperation.RunRoutine,
53
+ { routine: Ref.make(subject) },
54
+ {
55
+ spaceId: db.spaceId,
56
+ notify: { error: ['run-error.message', { ns: meta.profile.key }] },
57
+ ...(triggerRef ? { tracing: { trigger: triggerRef } } : {}),
58
+ },
59
+ ).finally(() => registry.set(runningAtom, false));
60
+ }, [invokePromise, db, subject, routine, registry, runningAtom]);
61
+
62
+ const menuActions = useArticleMenuActions({ canRun, runningAtom, handleRun });
63
+
64
+ if (!db) {
65
+ return null;
66
+ }
67
+
68
+ return (
69
+ <Menu.Root {...menuActions} attendableId={attendableId}>
70
+ <Panel.Root role={role}>
71
+ <Panel.Toolbar>
72
+ <Menu.Toolbar className='dx-document' />
73
+ </Panel.Toolbar>
74
+ <Panel.Content>
75
+ <RoutineForm db={db} routine={subject} />
76
+ </Panel.Content>
77
+ </Panel.Root>
78
+ </Menu.Root>
79
+ );
80
+ };
81
+
82
+ //
83
+ // Hooks
84
+ //
85
+
86
+ type ArticleMenuActionsOptions = {
87
+ canRun: boolean;
88
+ runningAtom: Atom.Writable<boolean>;
89
+ handleRun: () => void;
90
+ };
91
+
92
+ const useArticleMenuActions = ({ canRun, runningAtom, handleRun }: ArticleMenuActionsOptions) =>
93
+ useMenuBuilder(
94
+ (get) =>
95
+ MenuBuilder.make()
96
+ .action(
97
+ 'run',
98
+ {
99
+ label: ['run.label', { ns: meta.profile.key }],
100
+ icon: 'ph--play--regular',
101
+ disabled: get(runningAtom) || !canRun,
102
+ disposition: 'toolbar',
103
+ testId: 'routine.toolbar.run',
104
+ },
105
+ () => handleRun(),
106
+ )
107
+ .build(),
108
+ [canRun, handleRun, runningAtom],
109
+ );
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export { type RoutineArticleProps, RoutineArticle as default } from './RoutineArticle';
@@ -0,0 +1,82 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import * as Effect from 'effect/Effect';
7
+ import React from 'react';
8
+
9
+ import { withPluginManager } from '@dxos/app-framework/testing';
10
+ import { Instructions, Skill } from '@dxos/compute';
11
+ import { Filter, Ref } from '@dxos/echo';
12
+ import { ClientPlugin } from '@dxos/plugin-client/testing';
13
+ import { RoutinePlugin } from '@dxos/plugin-routine/testing';
14
+ import { corePlugins } from '@dxos/plugin-testing';
15
+ import { type Space, useQuery, useSpaces } from '@dxos/react-client/echo';
16
+ import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
17
+ import { Text } from '@dxos/schema';
18
+
19
+ import { translations } from '#translations';
20
+ import { Routine } from '#types';
21
+
22
+ import { RoutineCompanion } from './RoutineCompanion';
23
+
24
+ const types = [Routine.Routine, Instructions.Instructions, Skill.Skill, Text.Text];
25
+
26
+ /** Seed a companion-subject object plus one automation connected via instructions.objects. */
27
+ const seed = (space: Space) => {
28
+ const subject = space.db.add(Text.make({ content: 'Meeting notes' }));
29
+
30
+ space.db.add(
31
+ Routine.make({
32
+ name: 'Summarize Notes',
33
+ instructions: Instructions.make({ name: 'Summarize notes', objects: [Ref.make(subject)] }),
34
+ }),
35
+ );
36
+ };
37
+
38
+ const withCompanion = () =>
39
+ withPluginManager({
40
+ plugins: [
41
+ ...corePlugins(),
42
+ ClientPlugin({
43
+ types,
44
+ onClientInitialized: ({ client }) =>
45
+ Effect.gen(function* () {
46
+ yield* Effect.promise(() => client.halo.createIdentity());
47
+ const space = yield* Effect.promise(() => client.spaces.create());
48
+ yield* Effect.promise(() => space.waitUntilReady());
49
+ seed(space);
50
+ }),
51
+ }),
52
+ RoutinePlugin(),
53
+ ],
54
+ });
55
+
56
+ const DefaultStory = () => {
57
+ const spaces = useSpaces();
58
+ const space = spaces[spaces.length - 1];
59
+ const [subject] = useQuery(space?.db, Filter.type(Text.Text));
60
+ if (!subject || !space?.db) {
61
+ return <Loading />;
62
+ }
63
+ return <RoutineCompanion attendableId={subject.id} subject={subject} />;
64
+ };
65
+
66
+ const meta = {
67
+ title: 'plugins/plugin-routine/containers/RoutineCompanion',
68
+ render: DefaultStory,
69
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
70
+ parameters: {
71
+ layout: 'fullscreen',
72
+ translations,
73
+ },
74
+ } satisfies Meta<typeof DefaultStory>;
75
+
76
+ export default meta;
77
+
78
+ type Story = StoryObj<typeof meta>;
79
+
80
+ export const Default: Story = {
81
+ decorators: [withCompanion()],
82
+ };
@@ -0,0 +1,342 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { Atom } from '@effect-atom/atom-react';
6
+ import * as Effect from 'effect/Effect';
7
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
8
+
9
+ import { useCapabilities, useOperationInvoker } from '@dxos/app-framework/ui';
10
+ import { type AppSurface } from '@dxos/app-toolkit/ui';
11
+ import { Database, Filter, Obj, Type } from '@dxos/echo';
12
+ import { EffectEx } from '@dxos/effect';
13
+ import { SpaceOperation } from '@dxos/plugin-space';
14
+ import { useQuery } from '@dxos/react-client/echo';
15
+ import { Panel, ScrollArea, useTranslation } from '@dxos/react-ui';
16
+ import { type ActionGraphProps, Menu, MenuBuilder, useMenuBuilder } from '@dxos/react-ui-menu';
17
+
18
+ import { MasterDetail, type MasterDetailAdornment, type MasterDetailIcon, RoutineForm } from '#components';
19
+ import { meta } from '#meta';
20
+ import { Routine, RoutineCapabilities } from '#types';
21
+
22
+ import { connectedRoutinesQuery } from '../../util';
23
+
24
+ /** Association state of a row relative to the companion's object. */
25
+ type Status = 'associated' | 'detached';
26
+
27
+ export type RoutineCompanionProps = AppSurface.ObjectArticleProps<Obj.Unknown>;
28
+
29
+ /**
30
+ * Per-object companion: a master-detail list of automations connected to the object, via
31
+ * {@link connectedRoutinesQuery} (covers both trigger-input and instructions-context paths).
32
+ *
33
+ * The list is session-stable: a routine seen connected stays listed even after it loses its association
34
+ * (flagged with a 'detached' adornment) so it doesn't vanish mid-edit. The toolbar create menu offers a
35
+ * template picker (contributed via {@link RoutineCapabilities.Template}, filtered by `appliesTo`); each
36
+ * template's `scaffold` returns a fully-wired in-memory routine graph, shown editable in {@link RoutineForm}
37
+ * and committed on Save with a single `Database.add` (which cascades the owned children). Existing routines
38
+ * are edited in place.
39
+ */
40
+ export const RoutineCompanion = ({ subject: object, attendableId }: RoutineCompanionProps) => {
41
+ // A non-persisted subject has no database; `db` may be undefined. Every hook below tolerates that, and the
42
+ // render is guarded after the last hook (see below) so hook order is identical across renders either way.
43
+ const db = Obj.getDatabase(object);
44
+
45
+ const { t } = useTranslation(meta.profile.key);
46
+ const { invokePromise } = useOperationInvoker();
47
+ const { items, statusFor } = useConnectedRoutines(db, object);
48
+
49
+ const [selectedId, setSelectedId] = useState<string | undefined>();
50
+ const [draft, setDraft] = useState<Routine.Routine | undefined>();
51
+ // After saving a draft, hold the persisted routine directly so the detail panel renders immediately
52
+ // before the reactive queries catch up to include the newly-connected routine.
53
+ const [savedRoutine, setSavedRoutine] = useState<Routine.Routine | undefined>();
54
+ const selected = useMemo(
55
+ () => items.find((routine) => routine.id === selectedId) ?? savedRoutine,
56
+ [items, selectedId, savedRoutine],
57
+ );
58
+
59
+ const handleSelect = useCallback(
60
+ (id: string | undefined) => {
61
+ // Ignore selection changes while a draft is active — the edit (or create) must be saved or cancelled first.
62
+ if (draft) {
63
+ return;
64
+ }
65
+ setSavedRoutine(undefined);
66
+ setSelectedId(id);
67
+ },
68
+ [draft],
69
+ );
70
+
71
+ const handleCreateFromTemplate = useCallback(
72
+ async (template: RoutineCapabilities.Template) => {
73
+ if (!db) {
74
+ return;
75
+ }
76
+
77
+ // The scaffold returns a fully-wired in-memory routine draft graph (its owned trigger/instructions
78
+ // bound and parented); nothing is persisted until Save.
79
+ const scaffolded = await EffectEx.runPromise(
80
+ template.scaffold({ subject: object }).pipe(Effect.provideService(Database.Service, Database.makeService(db))),
81
+ );
82
+
83
+ setSavedRoutine(undefined);
84
+ setSelectedId(undefined);
85
+ setDraft(scaffolded);
86
+ },
87
+ [db, object],
88
+ );
89
+
90
+ // Templates filtered to those applicable to this companion's subject.
91
+ const allTemplates = useCapabilities(RoutineCapabilities.Template);
92
+ const templates = useMemo(
93
+ () => allTemplates.filter((template) => template.appliesTo?.(object) ?? true),
94
+ [allTemplates, object],
95
+ );
96
+
97
+ // Toolbar create menu: a `+` dropdown of applicable templates, pushed to the trailing edge by a growing gap
98
+ // separator (disabled while a draft is in progress so it can't be silently replaced).
99
+ const menuActions = useCompanionMenuActions({ t, templates, draft, handleCreateFromTemplate });
100
+
101
+ const handleCancel = useCallback(() => {
102
+ // Draft was never persisted, nothing to clean up.
103
+ setDraft(undefined);
104
+ }, []);
105
+
106
+ const handleSave = useCallback(async () => {
107
+ if (!draft || !db) {
108
+ return;
109
+ }
110
+
111
+ // The draft is a fully-wired graph (see `Routine.make`); a single add cascades the owned trigger and
112
+ // instructions, and the subject carried in the instructions' `objects` is the structural connection the
113
+ // query finds.
114
+ const persistedRoutine = db.add(draft);
115
+ await db.flush();
116
+ setSelectedId(persistedRoutine.id);
117
+ // Provide the persisted routine directly so the detail panel renders before the reactive queries
118
+ // catch up to include the newly-connected routine.
119
+ setSavedRoutine(persistedRoutine);
120
+ setDraft(undefined);
121
+ }, [draft, db]);
122
+
123
+ const handleDelete = useCallback(
124
+ (routine: Routine.Routine) => {
125
+ if (!db) {
126
+ return;
127
+ }
128
+
129
+ setSavedRoutine((current) => (current?.id === routine.id ? undefined : current));
130
+ setSelectedId((current) => (current === routine.id ? undefined : current));
131
+ // Route through the space operation so the deletion is undoable (toast + RestoreObjects), rather than
132
+ // mutating the database directly.
133
+ void invokePromise?.(SpaceOperation.RemoveObjects, { objects: [routine] }, { spaceId: db.spaceId });
134
+ },
135
+ [invokePromise, db],
136
+ );
137
+
138
+ // Per-row overflow menu: delete. (A routine's on/off state is toggled per-trigger inline in the form,
139
+ // not from the list.)
140
+ const getMenu = useGetMenu({ t, handleDelete });
141
+
142
+ // Row icon, reactive per row: an enabled routine takes its type's hue (amber); disabled uses the default
143
+ // icon colour. Subscribes (via `get`) only to this routine's triggers' `enabled` flags.
144
+ const getIcon = useCallback((get: Atom.Context, routine: Routine.Routine): MasterDetailIcon => {
145
+ const { icon, hue } = Obj.getIcon(routine) ?? { icon: 'ph--lightning--regular', hue: undefined };
146
+ const { enabled } = get(routineEnabled(routine));
147
+ return { icon, hue: enabled ? hue : undefined };
148
+ }, []);
149
+
150
+ // Row label, reactive per row via the object's label atom, so a rename updates the row live.
151
+ const getLabel = useCallback(
152
+ (get: Atom.Context, routine: Routine.Routine): string =>
153
+ get(Obj.labelAtom(routine)) || t('object-name.placeholder', { ns: Type.getTypename(Routine.Routine) }) || '',
154
+ [t],
155
+ );
156
+
157
+ // Trailing adornment: a warning badge on a row whose routine has left the connected set (it stays in the
158
+ // session-stable list — see {@link useConnectedRoutines} — rather than disappearing while still selected/edited).
159
+ const getAdornment = useCallback(
160
+ (_get: Atom.Context, routine: Routine.Routine): MasterDetailAdornment | undefined =>
161
+ statusFor(routine.id) === 'detached'
162
+ ? { icon: 'ph--warning--regular', label: t('routine-detached.message') }
163
+ : undefined,
164
+ [statusFor, t],
165
+ );
166
+
167
+ // Render guard placed after every hook so hook order stays stable: a non-persisted subject (no database)
168
+ // has nothing to list.
169
+ if (!db) {
170
+ return null;
171
+ }
172
+
173
+ // One form for both flows. A selected (persisted) routine is edited in place. The create-from-template draft
174
+ // is the only Save/Cancel flow: an in-memory routine shown editable, discarded on Cancel and persisted by a
175
+ // single `Database.add` on Save. The `key` (the routine id) remounts the uncontrolled form when the shown
176
+ // routine changes; the draft carries a fresh id, so no edits leak between rows.
177
+ const shown = draft ?? selected;
178
+ const detail = shown ? (
179
+ <RoutineForm
180
+ key={shown.id}
181
+ db={db}
182
+ routine={shown}
183
+ onSave={draft ? () => void handleSave() : undefined}
184
+ onCancel={draft ? handleCancel : undefined}
185
+ />
186
+ ) : null;
187
+
188
+ return (
189
+ <Menu.Root {...menuActions} attendableId={attendableId}>
190
+ <Panel.Root>
191
+ <Panel.Toolbar>
192
+ <Menu.Toolbar className='dx-document' />
193
+ </Panel.Toolbar>
194
+ <Panel.Content asChild className='pt-trim-md'>
195
+ <ScrollArea.Root>
196
+ <ScrollArea.Viewport>
197
+ <MasterDetail<Routine.Routine>
198
+ classNames='dx-document'
199
+ items={items}
200
+ selectedId={selectedId}
201
+ detail={detail}
202
+ onSelect={handleSelect}
203
+ getMenu={getMenu}
204
+ getIcon={getIcon}
205
+ getLabel={getLabel}
206
+ getAdornment={getAdornment}
207
+ emptyLabel={t('no-routines.message')}
208
+ />
209
+ </ScrollArea.Viewport>
210
+ </ScrollArea.Root>
211
+ </Panel.Content>
212
+ </Panel.Root>
213
+ </Menu.Root>
214
+ );
215
+ };
216
+
217
+ //
218
+ // Hooks
219
+ //
220
+
221
+ /**
222
+ * The companion's automation list, session-stable and frozen against disconnection: routines connected to the
223
+ * object via {@link connectedRoutinesQuery} (trigger-input and instructions-context paths unified) are
224
+ * accumulated append-only so rows never reorder, and a routine that leaves the connected set stays in the list
225
+ * (flagged `detached` via {@link statusFor}) rather than vanishing mid-edit — only a hard-deleted routine drops
226
+ * out. Detached rows are resolved from the space's full routine set since the connected query no longer returns
227
+ * them. A freshly-saved routine appears once the query reflects it.
228
+ */
229
+ const useConnectedRoutines = (
230
+ db: Database.Database | undefined,
231
+ object: Obj.Unknown,
232
+ ): { items: Routine.Routine[]; statusFor: (id: string) => Status } => {
233
+ const connected = useQuery(db, connectedRoutinesQuery(object));
234
+ const connectedIds = useMemo(() => new Set(connected.map((routine) => routine.id)), [connected]);
235
+
236
+ // All routines in the space — used to resolve rows that have left the connected set (still exist, just detached).
237
+ const all = useQuery(db, Filter.type(Routine.Routine));
238
+ const byId = useMemo(() => new Map(all.map((routine) => [routine.id, routine])), [all]);
239
+
240
+ // Session-stable, append-only: a routine seen connected this session is remembered so its row never reorders
241
+ // or disappears on disconnect. Scoped to the current subject — reset if this instance is reused for another
242
+ // object so the previous subject's rows don't leak in.
243
+ const seenOrder = useRef<string[]>([]);
244
+ const seenForObject = useRef(object.id);
245
+ if (seenForObject.current !== object.id) {
246
+ seenForObject.current = object.id;
247
+ seenOrder.current = [];
248
+ }
249
+ for (const id of connectedIds) {
250
+ if (!seenOrder.current.includes(id)) {
251
+ seenOrder.current.push(id);
252
+ }
253
+ }
254
+
255
+ // Resolve to live objects in stable order, dropping only ids whose routine was hard-deleted.
256
+ const items = useMemo(
257
+ () => seenOrder.current.flatMap((id) => (byId.has(id) ? [byId.get(id)!] : [])),
258
+ [byId, connectedIds],
259
+ );
260
+
261
+ const statusFor = useCallback(
262
+ (id: string): Status => (connectedIds.has(id) ? 'associated' : 'detached'),
263
+ [connectedIds],
264
+ );
265
+
266
+ return { items, statusFor };
267
+ };
268
+
269
+ /**
270
+ * Reactive family for a routine's on/off state — subscribes (via `get`) to its triggers' `enabled` flags so the
271
+ * row icon re-derives when a flag flips. Keyed by the routine instance.
272
+ */
273
+ const routineEnabled = Atom.family(
274
+ (routine: Routine.Routine): Atom.Atom<{ hasTriggers: boolean; enabled: boolean }> =>
275
+ Atom.make((get) => {
276
+ const triggers = get(Obj.atomProperty(routine, 'triggers'));
277
+ const hasTriggers = triggers.length > 0;
278
+ return {
279
+ hasTriggers,
280
+ enabled: hasTriggers && triggers.every((ref) => get(Obj.atomProperty(ref, 'enabled')) === true),
281
+ };
282
+ }),
283
+ );
284
+
285
+ type GetMenuOptions = {
286
+ t: ReturnType<typeof useTranslation>['t'];
287
+ handleDelete: (routine: Routine.Routine) => void;
288
+ };
289
+
290
+ const useGetMenu = ({ t, handleDelete }: GetMenuOptions) =>
291
+ useCallback(
292
+ (_get: Atom.Context, routine: Routine.Routine): ActionGraphProps =>
293
+ MenuBuilder.make()
294
+ .action(
295
+ 'delete',
296
+ {
297
+ label: t('delete.label'),
298
+ icon: 'ph--trash--regular',
299
+ testId: 'routine.companion.delete',
300
+ },
301
+ () => handleDelete(routine),
302
+ )
303
+ .build(),
304
+ [t, handleDelete],
305
+ );
306
+
307
+ type CompanionMenuActionsOptions = {
308
+ t: ReturnType<typeof useTranslation>['t'];
309
+ templates: RoutineCapabilities.Template[];
310
+ draft: Routine.Routine | undefined;
311
+ handleCreateFromTemplate: (template: RoutineCapabilities.Template) => Promise<void>;
312
+ };
313
+
314
+ const useCompanionMenuActions = ({ t, templates, draft, handleCreateFromTemplate }: CompanionMenuActionsOptions) =>
315
+ useMenuBuilder(
316
+ () =>
317
+ MenuBuilder.make()
318
+ .separator('gap')
319
+ .group(
320
+ 'create',
321
+ {
322
+ variant: 'dropdownMenu',
323
+ label: t('add-routine.label'),
324
+ icon: 'ph--plus--regular',
325
+ iconOnly: true,
326
+ caretDown: false,
327
+ disabled: draft != null || templates.length === 0,
328
+ testId: 'routine.companion.create',
329
+ },
330
+ (group) => {
331
+ for (const template of templates) {
332
+ group.action(
333
+ template.id,
334
+ { label: template.label, icon: template.icon ?? 'ph--lightning--regular' },
335
+ () => void handleCreateFromTemplate(template),
336
+ );
337
+ }
338
+ },
339
+ )
340
+ .build(),
341
+ [t, templates, draft, handleCreateFromTemplate],
342
+ );
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export { RoutineCompanion as default } from './RoutineCompanion';
6
+ export * from './RoutineCompanion';
@@ -0,0 +1,65 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { AppSurface } from '@dxos/app-toolkit/ui';
8
+ import { type ComputeEnvironment } from '@dxos/client-protocol';
9
+ import { useObject } from '@dxos/echo-react';
10
+ import { DropdownMenu, IconButton, useTranslation } from '@dxos/react-ui';
11
+ import { Form } from '@dxos/react-ui-form';
12
+
13
+ import { meta } from '#meta';
14
+
15
+ export type RoutineSettingsProps = AppSurface.SpaceArticleProps;
16
+
17
+ /**
18
+ * Space-level routine settings. Individual routines are now first-class objects (configured in their
19
+ * article + per-object companion), so this page is focused on runtime management — where the space's
20
+ * routines execute.
21
+ */
22
+ export const RoutineSettings = ({ space }: RoutineSettingsProps) => {
23
+ const { t } = useTranslation(meta.profile.key);
24
+ const [properties, changeProperties] = useObject(space.properties);
25
+ const selected = properties.computeEnvironment ?? 'local';
26
+
27
+ const handleUpdate = (option: ComputeEnvironment) => {
28
+ changeProperties((draft) => {
29
+ draft.computeEnvironment = option;
30
+ });
31
+ };
32
+
33
+ return (
34
+ <Form.Root variant='settings'>
35
+ <Form.Viewport scroll>
36
+ <Form.Content>
37
+ <Form.Section title={t('routine-verbose.label')} description={t('routine.description')}>
38
+ <Form.Row label={t('runtime.label')} description={t('runtime.description')}>
39
+ <DropdownMenu.Root>
40
+ <DropdownMenu.Trigger asChild>
41
+ <IconButton iconEnd icon='ph--caret-down--regular' size={4} label={t(`runtime.${selected}.label`)} />
42
+ </DropdownMenu.Trigger>
43
+ <DropdownMenu.Portal>
44
+ <DropdownMenu.Content side='bottom'>
45
+ <DropdownMenu.Viewport>
46
+ <DropdownMenu.Item onClick={() => handleUpdate('disabled')}>
47
+ {t('runtime.disabled.label')}
48
+ </DropdownMenu.Item>
49
+ <DropdownMenu.Item onClick={() => handleUpdate('local')}>
50
+ {t('runtime.local.label')}
51
+ </DropdownMenu.Item>
52
+ <DropdownMenu.Item onClick={() => handleUpdate('edge')}>
53
+ {t('runtime.edge.label')}
54
+ </DropdownMenu.Item>
55
+ </DropdownMenu.Viewport>
56
+ </DropdownMenu.Content>
57
+ </DropdownMenu.Portal>
58
+ </DropdownMenu.Root>
59
+ </Form.Row>
60
+ </Form.Section>
61
+ </Form.Content>
62
+ </Form.Viewport>
63
+ </Form.Root>
64
+ );
65
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export { RoutineSettings as default } from './RoutineSettings';