@hotmeshio/long-tail 0.1.6 → 0.1.7
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.
- package/README.md +44 -4
- package/build/api/auth.d.ts +5 -0
- package/build/api/auth.js +42 -0
- package/build/api/bot-accounts.d.ts +50 -0
- package/build/api/bot-accounts.js +215 -0
- package/build/api/controlplane.d.ts +20 -0
- package/build/api/controlplane.js +110 -0
- package/build/api/dba.d.ts +15 -0
- package/build/api/dba.js +68 -0
- package/build/api/escalations.d.ts +70 -0
- package/build/api/escalations.js +656 -0
- package/build/api/exports.d.ts +32 -0
- package/build/api/exports.js +146 -0
- package/build/api/index.d.ts +18 -0
- package/build/api/index.js +54 -0
- package/build/api/insight.d.ts +29 -0
- package/build/api/insight.js +90 -0
- package/build/api/maintenance.d.ts +7 -0
- package/build/api/maintenance.js +28 -0
- package/build/api/mcp-runs.d.ts +16 -0
- package/build/api/mcp-runs.js +62 -0
- package/build/api/mcp.d.ts +52 -0
- package/build/api/mcp.js +212 -0
- package/build/api/namespaces.d.ts +7 -0
- package/build/{routes/escalations/helpers.js → api/namespaces.js} +24 -12
- package/build/api/roles.d.ts +25 -0
- package/build/api/roles.js +159 -0
- package/build/api/settings.d.ts +2 -0
- package/build/api/settings.js +35 -0
- package/build/api/tasks.d.ts +27 -0
- package/build/api/tasks.js +96 -0
- package/build/api/users.d.ts +44 -0
- package/build/api/users.js +162 -0
- package/build/api/workflow-sets.d.ts +26 -0
- package/build/api/workflow-sets.js +119 -0
- package/build/api/workflows.d.ts +48 -0
- package/build/api/workflows.js +298 -0
- package/build/api/yaml-workflows.d.ts +87 -0
- package/build/api/yaml-workflows.js +556 -0
- package/build/index.d.ts +4 -0
- package/build/index.js +6 -1
- package/build/lib/db/schemas/004_workflow_sets.sql +29 -0
- package/build/lib/db/schemas/005_unique_graph_topic.sql +7 -0
- package/build/lib/db/schemas/011_system_workflow_configs.sql +7 -0
- package/build/lib/events/callback.d.ts +41 -0
- package/build/lib/events/callback.js +98 -0
- package/build/modules/config.js +1 -1
- package/build/routes/auth.js +37 -36
- package/build/routes/bot-accounts.js +34 -164
- package/build/routes/controlplane.js +20 -60
- package/build/routes/dba.js +18 -28
- package/build/routes/escalations/bulk.js +17 -192
- package/build/routes/escalations/list.js +29 -75
- package/build/routes/escalations/resolve.js +3 -193
- package/build/routes/escalations/single.js +13 -122
- package/build/routes/exports.js +44 -95
- package/build/routes/index.js +2 -0
- package/build/routes/insight.js +46 -88
- package/build/routes/maintenance.js +41 -17
- package/build/routes/mcp-runs.js +52 -60
- package/build/routes/mcp.js +49 -177
- package/build/routes/namespaces.js +9 -20
- package/build/routes/roles.js +23 -97
- package/build/routes/settings.js +37 -25
- package/build/routes/tasks.js +28 -64
- package/build/routes/users.js +24 -113
- package/build/routes/workflow-sets.d.ts +2 -0
- package/build/routes/workflow-sets.js +98 -0
- package/build/routes/workflows/config.js +23 -57
- package/build/routes/workflows/discovery.js +11 -85
- package/build/routes/workflows/invocation.js +16 -84
- package/build/routes/yaml-workflows/cron.js +12 -61
- package/build/routes/yaml-workflows/crud.js +30 -223
- package/build/routes/yaml-workflows/deployment.js +15 -115
- package/build/routes/yaml-workflows/versions.js +20 -58
- package/build/sdk/index.d.ts +327 -0
- package/build/sdk/index.js +298 -0
- package/build/services/controlplane/index.d.ts +1 -2
- package/build/services/controlplane/index.js +3 -3
- package/build/services/controlplane/sql.d.ts +2 -2
- package/build/services/controlplane/sql.js +4 -5
- package/build/services/controlplane/types.d.ts +1 -0
- package/build/services/export/index.js +6 -1
- package/build/services/hotmesh-utils.js +2 -4
- package/build/services/insight/index.d.ts +7 -0
- package/build/services/insight/index.js +30 -0
- package/build/services/mcp/client/tools.js +13 -1
- package/build/services/mcp-runs/sql.js +1 -1
- package/build/services/workflow-sets/db.d.ts +16 -0
- package/build/services/workflow-sets/db.js +78 -0
- package/build/services/workflow-sets/index.d.ts +1 -0
- package/build/services/workflow-sets/index.js +11 -0
- package/build/services/workflow-sets/sql.d.ts +6 -0
- package/build/services/workflow-sets/sql.js +24 -0
- package/build/services/yaml-workflow/db-utils.d.ts +1 -0
- package/build/services/yaml-workflow/db-utils.js +4 -0
- package/build/services/yaml-workflow/db.d.ts +5 -0
- package/build/services/yaml-workflow/db.js +17 -0
- package/build/services/yaml-workflow/pipeline/build/wiring.js +14 -1
- package/build/services/yaml-workflow/pipeline/prompts.d.ts +1 -1
- package/build/services/yaml-workflow/pipeline/prompts.js +1 -1
- package/build/services/yaml-workflow/sql.d.ts +2 -1
- package/build/services/yaml-workflow/sql.js +8 -3
- package/build/services/yaml-workflow/types.d.ts +3 -0
- package/build/services/yaml-workflow/workers/callbacks.js +7 -1
- package/build/services/yaml-workflow/workers/register.js +7 -0
- package/build/start/adapters.js +4 -0
- package/build/system/index.js +6 -0
- package/build/system/mcp-servers/knowledge.js +1 -1
- package/build/system/seed/server-definitions.js +2 -1
- package/build/system/workflows/mcp-workflow-builder/activities/index.d.ts +1 -1
- package/build/system/workflows/mcp-workflow-builder/activities/index.js +2 -1
- package/build/system/workflows/mcp-workflow-builder/activities/tool-loader.d.ts +6 -0
- package/build/system/workflows/mcp-workflow-builder/activities/tool-loader.js +26 -0
- package/build/system/workflows/mcp-workflow-builder/index.js +26 -2
- package/build/system/workflows/mcp-workflow-builder/prompts.js +104 -35
- package/build/system/workflows/mcp-workflow-planner/activities/analyze.d.ts +11 -0
- package/build/system/workflows/mcp-workflow-planner/activities/analyze.js +36 -0
- package/build/system/workflows/mcp-workflow-planner/activities/index.d.ts +3 -0
- package/build/system/workflows/mcp-workflow-planner/activities/index.js +12 -0
- package/build/system/workflows/mcp-workflow-planner/activities/persist.d.ts +19 -0
- package/build/system/workflows/mcp-workflow-planner/activities/persist.js +55 -0
- package/build/system/workflows/mcp-workflow-planner/activities/plan.d.ts +10 -0
- package/build/system/workflows/mcp-workflow-planner/activities/plan.js +43 -0
- package/build/system/workflows/mcp-workflow-planner/index.d.ts +7 -0
- package/build/system/workflows/mcp-workflow-planner/index.js +152 -0
- package/build/system/workflows/mcp-workflow-planner/prompts.d.ts +7 -0
- package/build/system/workflows/mcp-workflow-planner/prompts.js +77 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/sdk.d.ts +27 -0
- package/build/types/sdk.js +2 -0
- package/build/types/workflow-set.d.ts +44 -0
- package/build/types/workflow-set.js +5 -0
- package/dashboard/dist/assets/{AdminDashboard-BXkKGkb5.js → AdminDashboard-DRjkRSjJ.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-BXkKGkb5.js.map → AdminDashboard-DRjkRSjJ.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-DcH592mc.js → AvailableEscalationsPage-CnivX4Tz.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-DcH592mc.js.map → AvailableEscalationsPage-CnivX4Tz.js.map} +1 -1
- package/dashboard/dist/assets/BotPicker-DwwaBhTH.js +2 -0
- package/dashboard/dist/assets/{BotPicker-A6LtzyuO.js.map → BotPicker-DwwaBhTH.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-C7nL2_mv.js → CollapsibleSection-DQpaVA0M.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-C7nL2_mv.js.map → CollapsibleSection-DQpaVA0M.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-CWFwJrSl.js → ConfirmDeleteModal-B7JoDNvt.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-CWFwJrSl.js.map → ConfirmDeleteModal-B7JoDNvt.js.map} +1 -1
- package/dashboard/dist/assets/{CopyableId-DbZ5c3jh.js → CopyableId-AqoZayBG.js} +2 -2
- package/dashboard/dist/assets/{CopyableId-DbZ5c3jh.js.map → CopyableId-AqoZayBG.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-ClWkmLPu.js → CredentialsPage-qGw1kQzi.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-ClWkmLPu.js.map → CredentialsPage-qGw1kQzi.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-CtH2hReF.js → CustomDurationPicker-D1HUQcd0.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-CtH2hReF.js.map → CustomDurationPicker-D1HUQcd0.js.map} +1 -1
- package/dashboard/dist/assets/{DataTable-CM5ZcpPi.js → DataTable-DKvSKoVG.js} +2 -2
- package/dashboard/dist/assets/{DataTable-CM5ZcpPi.js.map → DataTable-DKvSKoVG.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-CwqavyeC.js → ElapsedCell-B0yrReGQ.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-CwqavyeC.js.map → ElapsedCell-B0yrReGQ.js.map} +1 -1
- package/dashboard/dist/assets/{EmptyState-BBn78pmm.js → EmptyState-X0fIzYID.js} +2 -2
- package/dashboard/dist/assets/{EmptyState-BBn78pmm.js.map → EmptyState-X0fIzYID.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-BcJ2E3X7.js → EscalationsOverview-BQAT9W7r.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-BcJ2E3X7.js.map → EscalationsOverview-BQAT9W7r.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-C1en_KZ0.js → EventTable-CX1KNLhZ.js} +2 -2
- package/dashboard/dist/assets/{EventTable-C1en_KZ0.js.map → EventTable-CX1KNLhZ.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-CZTlrLQT.js → FilterBar-DMTvuQy-.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-CZTlrLQT.js.map → FilterBar-DMTvuQy-.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-Cdbsapig.js → ListToolbar-DTOSxoEy.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-Cdbsapig.js.map → ListToolbar-DTOSxoEy.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-CSpEJxKa.js → McpOverview-BaKTIWrG.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-CSpEJxKa.js.map → McpOverview-BaKTIWrG.js.map} +1 -1
- package/dashboard/dist/assets/McpQueryDetailPage-CC08T5k8.js +5 -0
- package/dashboard/dist/assets/McpQueryDetailPage-CC08T5k8.js.map +1 -0
- package/dashboard/dist/assets/McpQueryPage-CVfF9dYg.js +2 -0
- package/dashboard/dist/assets/McpQueryPage-CVfF9dYg.js.map +1 -0
- package/dashboard/dist/assets/{McpRunDetailPage-9xdxgG4d.js → McpRunDetailPage-CKs1RWeV.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-9xdxgG4d.js.map → McpRunDetailPage-CKs1RWeV.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-wWLqHsd4.js → McpRunsPage-CcPD_tY1.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-wWLqHsd4.js.map → McpRunsPage-CcPD_tY1.js.map} +1 -1
- package/dashboard/dist/assets/{Modal-kB_P7ZOr.js → Modal-_2AbWxJT.js} +2 -2
- package/dashboard/dist/assets/{Modal-kB_P7ZOr.js.map → Modal-_2AbWxJT.js.map} +1 -1
- package/dashboard/dist/assets/OperatorDashboard-BGiRaRDr.js +2 -0
- package/dashboard/dist/assets/{OperatorDashboard-jc0vrgDI.js.map → OperatorDashboard-BGiRaRDr.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-NkOeBR05.js → PageHeader-DVr5Qyzm.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-NkOeBR05.js.map → PageHeader-DVr5Qyzm.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-ywNhrmFK.js → PageHeaderWithStats-D0KRASML.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-ywNhrmFK.js.map → PageHeaderWithStats-D0KRASML.js.map} +1 -1
- package/dashboard/dist/assets/{PriorityBadge-B2MQbSxy.js → PriorityBadge-Bx2559OU.js} +2 -2
- package/dashboard/dist/assets/{PriorityBadge-B2MQbSxy.js.map → PriorityBadge-Bx2559OU.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-B7z7IdqE.js → ProcessDetailPage-69I--sry.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-B7z7IdqE.js.map → ProcessDetailPage-69I--sry.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-C-uHadO6.js → ProcessesListPage-BDpUbua2.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-C-uHadO6.js.map → ProcessesListPage-BDpUbua2.js.map} +1 -1
- package/dashboard/dist/assets/{RolePill-C1dgC-fK.js → RolePill-CcAqEaSt.js} +2 -2
- package/dashboard/dist/assets/{RolePill-C1dgC-fK.js.map → RolePill-CcAqEaSt.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-BSxrD1vm.js → RolesPage-Cl23Hjet.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-BSxrD1vm.js.map → RolesPage-Cl23Hjet.js.map} +1 -1
- package/dashboard/dist/assets/{RowActions-lYaHGI-v.js → RowActions-B4mqIt3Z.js} +2 -2
- package/dashboard/dist/assets/{RowActions-lYaHGI-v.js.map → RowActions-B4mqIt3Z.js.map} +1 -1
- package/dashboard/dist/assets/{StatCard-v2TiITVr.js → StatCard-Cz_2OjAZ.js} +2 -2
- package/dashboard/dist/assets/{StatCard-v2TiITVr.js.map → StatCard-Cz_2OjAZ.js.map} +1 -1
- package/dashboard/dist/assets/{StatusBadge-DWlxevgG.js → StatusBadge-Wi2FJZsn.js} +2 -2
- package/dashboard/dist/assets/{StatusBadge-DWlxevgG.js.map → StatusBadge-Wi2FJZsn.js.map} +1 -1
- package/dashboard/dist/assets/{StepIndicator-CRM4ft28.js → StepIndicator-PW5NRDMb.js} +2 -2
- package/dashboard/dist/assets/{StepIndicator-CRM4ft28.js.map → StepIndicator-PW5NRDMb.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-CF0EToEU.js → StickyPagination-Bl2Uzz65.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-CF0EToEU.js.map → StickyPagination-Bl2Uzz65.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-CNlj7fgg.js → SwimlaneTimeline-CUPqMd0z.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-CNlj7fgg.js.map → SwimlaneTimeline-CUPqMd0z.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-CH8qMGhC.js → TagInput-BLtf86Ly.js} +2 -2
- package/dashboard/dist/assets/{TagInput-CH8qMGhC.js.map → TagInput-BLtf86Ly.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-CdWo-6mu.js → TaskDetailPage-BXJFX74D.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-CdWo-6mu.js.map → TaskDetailPage-BXJFX74D.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-BPj4ogVG.js → TaskQueuePill-CWYj3xKe.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-BPj4ogVG.js.map → TaskQueuePill-CWYj3xKe.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-CtRkMpKU.js → TasksListPage-C3cX94Mw.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-CtRkMpKU.js.map → TasksListPage-C3cX94Mw.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-Di1a3X5P.js → TimeAgo-B_5yDDHV.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-Di1a3X5P.js.map → TimeAgo-B_5yDDHV.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-CqrXql-S.js → TimestampCell-DRX724uU.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-CqrXql-S.js.map → TimestampCell-DRX724uU.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-BUFYCnRa.js → UserName-Ca8FA469.js} +2 -2
- package/dashboard/dist/assets/{UserName-BUFYCnRa.js.map → UserName-Ca8FA469.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-25iusMml.js → WorkflowExecutionPage-BBYWEV2P.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-25iusMml.js.map → WorkflowExecutionPage-BBYWEV2P.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowPill-BXifAuLi.js +2 -0
- package/dashboard/dist/assets/{WorkflowPill-DPKOcbf4.js.map → WorkflowPill-BXifAuLi.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-BgxslssH.js → WorkflowsDashboard-Drl3juz9.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-BgxslssH.js.map → WorkflowsDashboard-Drl3juz9.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-Doe5L-Re.js → WorkflowsOverview-03IRrDLg.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-Doe5L-Re.js.map → WorkflowsOverview-03IRrDLg.js.map} +1 -1
- package/dashboard/dist/assets/YamlWorkflowsPage-DC2cLxVi.js +2 -0
- package/dashboard/dist/assets/YamlWorkflowsPage-DC2cLxVi.js.map +1 -0
- package/dashboard/dist/assets/{bots-Bi2_O1Ts.js → bots-DZEXcgiJ.js} +2 -2
- package/dashboard/dist/assets/{bots-Bi2_O1Ts.js.map → bots-DZEXcgiJ.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-Ck1KlLkT.js → escalation-Cw48lNaF.js} +2 -2
- package/dashboard/dist/assets/{escalation-Ck1KlLkT.js.map → escalation-Cw48lNaF.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-ohDsj2eJ.js → escalation-columns-NINpo3qf.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-ohDsj2eJ.js.map → escalation-columns-NINpo3qf.js.map} +1 -1
- package/dashboard/dist/assets/helpers-Cuu3xKfr.js +2 -0
- package/dashboard/dist/assets/helpers-Cuu3xKfr.js.map +1 -0
- package/dashboard/dist/assets/{helpers-BoD2SgUY.js → helpers-fk_qr729.js} +2 -2
- package/dashboard/dist/assets/{helpers-BoD2SgUY.js.map → helpers-fk_qr729.js.map} +1 -1
- package/dashboard/dist/assets/index-B98ipWxE.js +2 -0
- package/dashboard/dist/assets/{index-D7zYZOnH.js.map → index-B98ipWxE.js.map} +1 -1
- package/dashboard/dist/assets/{index-BEtLIsML.js → index-BIG3KooI.js} +2 -2
- package/dashboard/dist/assets/{index-BEtLIsML.js.map → index-BIG3KooI.js.map} +1 -1
- package/dashboard/dist/assets/{index-DYyLF-Qb.js → index-BwN3KP_L.js} +5 -5
- package/dashboard/dist/assets/{index-DYyLF-Qb.js.map → index-BwN3KP_L.js.map} +1 -1
- package/dashboard/dist/assets/index-Bxe8h1x4.js +17 -0
- package/dashboard/dist/assets/{index-DOkHXmyf.js.map → index-Bxe8h1x4.js.map} +1 -1
- package/dashboard/dist/assets/{index-FuohTtaM.js → index-CNI7k7oB.js} +3 -3
- package/dashboard/dist/assets/{index-FuohTtaM.js.map → index-CNI7k7oB.js.map} +1 -1
- package/dashboard/dist/assets/{index-CZrJ09p-.js → index-CORHB0WC.js} +2 -2
- package/dashboard/dist/assets/{index-CZrJ09p-.js.map → index-CORHB0WC.js.map} +1 -1
- package/dashboard/dist/assets/{index-PyCTS05D.css → index-DcIKW-cZ.css} +1 -1
- package/dashboard/dist/assets/{index-D3NyVADW.js → index-Dj-z-x8M.js} +2 -2
- package/dashboard/dist/assets/index-Dj-z-x8M.js.map +1 -0
- package/dashboard/dist/assets/{index-Bn2xHDr8.js → index-DwRytW9O.js} +3 -3
- package/dashboard/dist/assets/{index-Bn2xHDr8.js.map → index-DwRytW9O.js.map} +1 -1
- package/dashboard/dist/assets/index-aRvL-dXp.js +2 -0
- package/dashboard/dist/assets/{index-Dk2Q51o0.js.map → index-aRvL-dXp.js.map} +1 -1
- package/dashboard/dist/assets/index-b03HlbnH.js +2 -0
- package/dashboard/dist/assets/{index-BpT-6WgJ.js.map → index-b03HlbnH.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-CJtYjA7A.js → mcp-BZoFryNc.js} +2 -2
- package/dashboard/dist/assets/{mcp-CJtYjA7A.js.map → mcp-BZoFryNc.js.map} +1 -1
- package/dashboard/dist/assets/mcp-query-wiw1kwm8.js +2 -0
- package/dashboard/dist/assets/mcp-query-wiw1kwm8.js.map +1 -0
- package/dashboard/dist/assets/{mcp-runs-DUWm9Z4V.js → mcp-runs-BaEKnf5v.js} +2 -2
- package/dashboard/dist/assets/{mcp-runs-DUWm9Z4V.js.map → mcp-runs-BaEKnf5v.js.map} +1 -1
- package/dashboard/dist/assets/{namespaces-BM5P2qmL.js → namespaces-BwnZI4_A.js} +2 -2
- package/dashboard/dist/assets/{namespaces-BM5P2qmL.js.map → namespaces-BwnZI4_A.js.map} +1 -1
- package/dashboard/dist/assets/{roles-lv0shpjJ.js → roles-Bgn1K8zU.js} +2 -2
- package/dashboard/dist/assets/{roles-lv0shpjJ.js.map → roles-Bgn1K8zU.js.map} +1 -1
- package/dashboard/dist/assets/{settings-Wlq92mRo.js → settings-CizYiutL.js} +2 -2
- package/dashboard/dist/assets/{settings-Wlq92mRo.js.map → settings-CizYiutL.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-BFGm4PuE.js → tasks-Bmte_hc4.js} +2 -2
- package/dashboard/dist/assets/{tasks-BFGm4PuE.js.map → tasks-Bmte_hc4.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-DIE6ue4x.js → useEventHooks-CUCxpiI2.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-DIE6ue4x.js.map → useEventHooks-CUCxpiI2.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-DCwSO73t.js → useYamlActivityEvents-Cum02Ej9.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-DCwSO73t.js.map → useYamlActivityEvents-Cum02Ej9.js.map} +1 -1
- package/dashboard/dist/assets/{users-tA5-K0wA.js → users-NSDgTt-z.js} +2 -2
- package/dashboard/dist/assets/{users-tA5-K0wA.js.map → users-NSDgTt-z.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-BiIug1SK.js → vendor-icons-D1DdudfH.js} +93 -73
- package/dashboard/dist/assets/vendor-icons-D1DdudfH.js.map +1 -0
- package/dashboard/dist/assets/{workflows-CfLc15Wr.js → workflows-k0XRdGXx.js} +2 -2
- package/dashboard/dist/assets/{workflows-CfLc15Wr.js.map → workflows-k0XRdGXx.js.map} +1 -1
- package/dashboard/dist/assets/yaml-workflows-DAre8I78.js +2 -0
- package/dashboard/dist/assets/yaml-workflows-DAre8I78.js.map +1 -0
- package/dashboard/dist/index.html +3 -3
- package/docs/epic-integration.md +224 -0
- package/docs/events.md +28 -0
- package/docs/sdk.md +177 -0
- package/docs/story.md +157 -0
- package/docs/workflow-builder.md +371 -0
- package/package.json +3 -2
- package/build/routes/escalations/helpers.d.ts +0 -5
- package/build/routes/resolve.d.ts +0 -9
- package/build/routes/resolve.js +0 -19
- package/build/routes/yaml-workflows/helpers.d.ts +0 -2
- package/build/routes/yaml-workflows/helpers.js +0 -8
- package/dashboard/dist/assets/BotPicker-A6LtzyuO.js +0 -2
- package/dashboard/dist/assets/McpQueryDetailPage-DhqEI180.js +0 -5
- package/dashboard/dist/assets/McpQueryDetailPage-DhqEI180.js.map +0 -1
- package/dashboard/dist/assets/McpQueryPage-CIiVMlqo.js +0 -2
- package/dashboard/dist/assets/McpQueryPage-CIiVMlqo.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-jc0vrgDI.js +0 -2
- package/dashboard/dist/assets/RunAsSelector-CJDnyp93.js +0 -2
- package/dashboard/dist/assets/RunAsSelector-CJDnyp93.js.map +0 -1
- package/dashboard/dist/assets/WorkflowPill-DPKOcbf4.js +0 -2
- package/dashboard/dist/assets/YamlWorkflowsPage-BliAckJ6.js +0 -2
- package/dashboard/dist/assets/YamlWorkflowsPage-BliAckJ6.js.map +0 -1
- package/dashboard/dist/assets/index-BpT-6WgJ.js +0 -2
- package/dashboard/dist/assets/index-D3NyVADW.js.map +0 -1
- package/dashboard/dist/assets/index-D7zYZOnH.js +0 -2
- package/dashboard/dist/assets/index-DOkHXmyf.js +0 -17
- package/dashboard/dist/assets/index-Dk2Q51o0.js +0 -2
- package/dashboard/dist/assets/mcp-query-jQJQrs_7.js +0 -2
- package/dashboard/dist/assets/mcp-query-jQJQrs_7.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-BiIug1SK.js.map +0 -1
- package/dashboard/dist/assets/yaml-workflows-D7JXNqbM.js +0 -2
- package/dashboard/dist/assets/yaml-workflows-D7JXNqbM.js.map +0 -1
- package/docs/img/01-login.png +0 -0
- package/docs/img/02-dashboard-home.png +0 -0
- package/docs/img/03-processes-list.png +0 -0
- package/docs/img/04-escalations-list.png +0 -0
- package/docs/img/05-mcp-servers.png +0 -0
- package/docs/img/06-mcp-pipelines.png +0 -0
- package/docs/img/07-workflows-list.png +0 -0
- package/docs/img/compilation/01-query-submit.png +0 -0
- package/docs/img/compilation/02-mcp-servers.png +0 -0
- package/docs/img/compilation/03-query-completed.png +0 -0
- package/docs/img/compilation/04-wizard-original.png +0 -0
- package/docs/img/compilation/05-wizard-timeline.png +0 -0
- package/docs/img/compilation/06-wizard-profile.png +0 -0
- package/docs/img/compilation/07-wizard-deploy.png +0 -0
- package/docs/img/compilation/08-wizard-test-modal.png +0 -0
- package/docs/img/compilation/09-wizard-test-compare.png +0 -0
- package/docs/img/compilation/10-wizard-verify.png +0 -0
|
@@ -45,7 +45,7 @@ app:
|
|
|
45
45
|
### trigger
|
|
46
46
|
Entry point. Receives user input. Always the first activity.
|
|
47
47
|
\`\`\`yaml
|
|
48
|
-
|
|
48
|
+
trigger_x8kf:
|
|
49
49
|
title: Trigger
|
|
50
50
|
type: trigger
|
|
51
51
|
output:
|
|
@@ -54,9 +54,9 @@ my_trigger:
|
|
|
54
54
|
\`\`\`
|
|
55
55
|
|
|
56
56
|
### worker
|
|
57
|
-
Executes an MCP tool. Receives data via input.maps, produces output.
|
|
57
|
+
Executes an MCP tool. Receives data via input.maps, produces output. Same suffix as the trigger.
|
|
58
58
|
\`\`\`yaml
|
|
59
|
-
|
|
59
|
+
capture_x8kf:
|
|
60
60
|
title: Capture Page
|
|
61
61
|
type: worker
|
|
62
62
|
topic: <same as subscribes>
|
|
@@ -64,10 +64,10 @@ my_worker:
|
|
|
64
64
|
schema:
|
|
65
65
|
type: object
|
|
66
66
|
maps:
|
|
67
|
-
url: '{
|
|
67
|
+
url: '{trigger_x8kf.output.data.url}'
|
|
68
68
|
screenshot_path:
|
|
69
69
|
'@pipe':
|
|
70
|
-
- ['{
|
|
70
|
+
- ['{trigger_x8kf.output.data.slug}', '.png']
|
|
71
71
|
- ['{@string.concat}']
|
|
72
72
|
workflowName: capture_page
|
|
73
73
|
output:
|
|
@@ -76,10 +76,14 @@ my_worker:
|
|
|
76
76
|
\`\`\`
|
|
77
77
|
|
|
78
78
|
### hook
|
|
79
|
-
Durable pause point
|
|
79
|
+
Durable pause point with three modes:
|
|
80
|
+
- **Web hook**: Pauses until an external signal arrives. Define \`hook: { type: object, properties: {...} }\` for the expected signal schema. Receives signal data via \`{$self.hook.data.*}\`. Requires a matching entry in the graph-level \`hooks:\` section.
|
|
81
|
+
- **Sleep**: Pauses for a duration. \`sleep: 5\` pauses 5 seconds. Supports @pipe expressions for dynamic delays.
|
|
82
|
+
- **Cycle pivot**: When \`cycle: true\`, becomes an iteration anchor that a cycle activity can loop back to.
|
|
83
|
+
- **Passthrough**: No hook/sleep config — acts as a data-mapping convergence point, executes immediately.
|
|
80
84
|
|
|
81
85
|
### cycle
|
|
82
|
-
Loop back to a hook ancestor
|
|
86
|
+
Loop back to a hook ancestor marked \`cycle: true\`. Each iteration runs in isolated state, but \`job.maps\` accumulates across iterations.
|
|
83
87
|
|
|
84
88
|
## Data Mapping Rules
|
|
85
89
|
|
|
@@ -88,14 +92,56 @@ Loop back to a hook ancestor for iteration patterns.
|
|
|
88
92
|
field_name: '{sourceActivity.output.data.fieldName}'
|
|
89
93
|
\`\`\`
|
|
90
94
|
|
|
91
|
-
### @pipe
|
|
92
|
-
|
|
95
|
+
### @pipe — Reverse Polish Notation (operands THEN operator)
|
|
96
|
+
|
|
97
|
+
@pipe uses **stack-machine / RPN evaluation**: each row is evaluated top-to-bottom. A row is either OPERANDS (data for the next function) or an OPERATOR (a function that consumes the row above it). The rule is simple and absolute:
|
|
98
|
+
|
|
99
|
+
> **ALL operands for a function must appear on the single row ABOVE the function row.**
|
|
100
|
+
|
|
101
|
+
A function row contains ONLY the function reference: \`['{@string.substring}']\`. It receives its arguments from the row immediately above it. The first element on the operands row is typically a dynamic reference that resolves at runtime; the remaining elements are literal values.
|
|
102
|
+
|
|
103
|
+
#### Simple pipe (no extra args):
|
|
93
104
|
\`\`\`yaml
|
|
94
105
|
field_name:
|
|
95
106
|
'@pipe':
|
|
96
|
-
- ['{source.output.data.value}', '-suffix']
|
|
97
|
-
- ['{@string.concat}']
|
|
98
|
-
- ['{@string.toLowerCase}']
|
|
107
|
+
- ['{source.output.data.value}', '-suffix'] # operands: value, suffix
|
|
108
|
+
- ['{@string.concat}'] # operator: concat(value, suffix) → "hello-suffix"
|
|
109
|
+
- ['{@string.toLowerCase}'] # operator: toLowerCase("hello-suffix")
|
|
110
|
+
\`\`\`
|
|
111
|
+
When a function takes only one argument (the result of the prior row), it needs no separate operands row — it just consumes what's above.
|
|
112
|
+
|
|
113
|
+
#### Multi-arg function (THIS IS THE PATTERN LLMs GET WRONG):
|
|
114
|
+
\`\`\`yaml
|
|
115
|
+
date_substring:
|
|
116
|
+
'@pipe':
|
|
117
|
+
- ['{@date.now}'] # operator: date.now() → 1713528000000
|
|
118
|
+
- ['{@date.toISOString}', 0, 10] # operands: [isoString, 0, 10] for substring
|
|
119
|
+
- ['{@string.substring}'] # operator: substring(isoString, 0, 10) → "2026-04-19"
|
|
120
|
+
\`\`\`
|
|
121
|
+
Row 2 is the OPERANDS row for substring. It contains THREE values:
|
|
122
|
+
1. \`{@date.toISOString}\` — resolves dynamically (converts epoch → "2026-04-19T12:00:00.000Z")
|
|
123
|
+
2. \`0\` — start index (literal)
|
|
124
|
+
3. \`10\` — end index (literal)
|
|
125
|
+
|
|
126
|
+
Row 3 is the OPERATOR row: \`substring\` consumes all three values from row 2.
|
|
127
|
+
|
|
128
|
+
**COMMON MISTAKE** (NEVER DO THIS):
|
|
129
|
+
\`\`\`yaml
|
|
130
|
+
# WRONG — puts args on the operator row instead of the operands row above it
|
|
131
|
+
- ['{@date.toISOString}']
|
|
132
|
+
- ['{@string.substring}', 0, 10] # ← BROKEN: 0, 10 must be on the row ABOVE
|
|
133
|
+
\`\`\`
|
|
134
|
+
\`\`\`yaml
|
|
135
|
+
# ALSO WRONG — splits operands across two rows
|
|
136
|
+
- ['{@date.toISOString}']
|
|
137
|
+
- [0, 10] # ← BROKEN: operands separated from the dynamic value
|
|
138
|
+
- ['{@string.substring}']
|
|
139
|
+
\`\`\`
|
|
140
|
+
The ONLY correct form: all operands together on ONE row, operator alone on the NEXT row.
|
|
141
|
+
|
|
142
|
+
**PREFERRED for dates**: Use \`{@date.yyyymmdd}\` which returns "YYYY-MM-DD" directly — no pipe needed:
|
|
143
|
+
\`\`\`yaml
|
|
144
|
+
today: '{@date.yyyymmdd}'
|
|
99
145
|
\`\`\`
|
|
100
146
|
|
|
101
147
|
### Nested @pipe (fan-out/fan-in):
|
|
@@ -104,7 +150,7 @@ Sub-pipes must be ROW-LEVEL entries in the parent pipe array — each is a separ
|
|
|
104
150
|
dated_key:
|
|
105
151
|
'@pipe':
|
|
106
152
|
- '@pipe':
|
|
107
|
-
- ['{
|
|
153
|
+
- ['{trigger_x8kf.output.data.slug}', '-']
|
|
108
154
|
- ['{@string.concat}']
|
|
109
155
|
- '@pipe':
|
|
110
156
|
- ['{@date.now}']
|
|
@@ -112,7 +158,7 @@ dated_key:
|
|
|
112
158
|
- ['{@string.substring}']
|
|
113
159
|
- ['{@string.concat}']
|
|
114
160
|
\`\`\`
|
|
115
|
-
This produces \`my-slug-2026-04-19\`.
|
|
161
|
+
This produces \`my-slug-2026-04-19\`. Sub-pipe 1: \`slug + "-"\`. Sub-pipe 2: today as YYYY-MM-DD (RPN: operands then operator). Final row: concat all sub-pipe results.
|
|
116
162
|
|
|
117
163
|
CRITICAL RULES for nested @pipe:
|
|
118
164
|
1. Never put a nested \`@pipe\` object INSIDE an array row. Each sub-pipe must be its own row in the parent.
|
|
@@ -122,7 +168,7 @@ CRITICAL RULES for nested @pipe:
|
|
|
122
168
|
path:
|
|
123
169
|
'@pipe':
|
|
124
170
|
- '@pipe':
|
|
125
|
-
- ['{
|
|
171
|
+
- ['{trigger_x8kf.output.data.domain}', '/', '{trigger_x8kf.output.data.key}', '/']
|
|
126
172
|
- ['{@string.concat}']
|
|
127
173
|
- '@pipe':
|
|
128
174
|
- ['{@date.now}']
|
|
@@ -137,14 +183,16 @@ This resolves: sub-pipe1 → "research/google/", sub-pipe2 → "2026-04-19", sub
|
|
|
137
183
|
IMPORTANT: A bare array like \`['.png']\` as a row after sub-pipes will CRASH — HotMesh interprets it as a function call. Always wrap static values in \`'@pipe': - [value]\`.
|
|
138
184
|
|
|
139
185
|
### Available @pipe operators (every JS method is exposed):
|
|
140
|
-
- **@string**: charAt, concat, includes, indexOf, replace, slice, split, startsWith, substring, toLowerCase, toUpperCase, trim
|
|
141
|
-
- **@date**: now, toISOString, toDateString, getFullYear, getMonth, getDate, getHours, getMinutes, getSeconds, fromISOString, parse (full JS Date API)
|
|
142
|
-
- **@math**: add, subtract, multiply, divide
|
|
143
|
-
- **@number**: gte, lte,
|
|
144
|
-
- **@array**: get, length
|
|
145
|
-
- **@object**: get, keys, values
|
|
146
|
-
- **@conditional**: ternary, less_than,
|
|
186
|
+
- **@string**: charAt, concat, endsWith, includes, indexOf, lastIndexOf, padEnd, padStart, repeat, replace, search, slice, split, startsWith, substring, toLowerCase, toUpperCase, trim, trimEnd, trimStart
|
|
187
|
+
- **@date**: now, toISOString, toDateString, yyyymmdd (returns "YYYY-MM-DD" directly — preferred for date strings), getFullYear, getMonth, getDate, getDay, getHours, getMinutes, getSeconds, getTime, fromISOString, parse, UTC, toLocaleDateString, setFullYear, setMonth, setDate (full JS Date API)
|
|
188
|
+
- **@math**: add, subtract, multiply, divide, abs, ceil, floor, round, trunc, pow, sqrt, max, min, random
|
|
189
|
+
- **@number**: gt, gte, lt, lte, isFinite, isInteger, isEven, isOdd, isNaN, parseFloat, parseInt, toFixed, toExponential, toPrecision
|
|
190
|
+
- **@array**: get, length, concat, indexOf, join, lastIndexOf, pop, push, reverse, shift, slice, sort, splice, unshift
|
|
191
|
+
- **@object**: get, set, create, keys, values, entries, fromEntries, assign, hasOwnProperty, freeze
|
|
192
|
+
- **@conditional**: ternary, equality, strict_equality, inequality, strict_inequality, greater_than, less_than, greater_than_or_equal, less_than_or_equal, nullish
|
|
147
193
|
- **@json**: parse, stringify
|
|
194
|
+
- **@logical**: and, or
|
|
195
|
+
- **@bitwise**: and, or, xor, leftShift, rightShift
|
|
148
196
|
|
|
149
197
|
### Three mapping directions per activity:
|
|
150
198
|
- **input.maps**: Wire data INTO this activity from trigger or upstream activities
|
|
@@ -155,22 +203,41 @@ IMPORTANT: A bare array like \`['.png']\` as a row after sub-pipes will CRASH
|
|
|
155
203
|
|
|
156
204
|
1. **Trigger first**: Every workflow starts with a trigger activity
|
|
157
205
|
2. **Worker per tool**: Each MCP tool call is a worker activity
|
|
158
|
-
3. **
|
|
159
|
-
4. **
|
|
160
|
-
5. **
|
|
161
|
-
6. **
|
|
162
|
-
7. **
|
|
163
|
-
8. **
|
|
164
|
-
|
|
165
|
-
|
|
206
|
+
3. **Collision-proof activity IDs**: Multiple workflows share the same app namespace. Activity IDs MUST be globally unique within the app. Use a descriptive name with a shared 4-char random suffix appended to every activity in the flow: \`trigger_x8kf\`, \`capture_x8kf\`, \`analyze_x8kf\`, \`store_x8kf\`. The suffix is the same for all activities in one workflow but unique across workflows. NEVER use bare names like \`trigger\`, \`capture\`, \`analyze\` — they WILL collide with other workflows in the same app.
|
|
207
|
+
4. **workflowName**: Every worker MUST have \`workflowName: '<tool_name>'\` in its input.maps — this routes to the correct MCP tool handler
|
|
208
|
+
5. **_scope threading**: Every worker MUST have \`_scope: '{trigger_x8kf.output.data._scope}'\` (using YOUR trigger's ID) for IAM context
|
|
209
|
+
6. **Wire outputs forward**: Use \`{prevActivity.output.data.fieldName}\` to pass data between steps
|
|
210
|
+
7. **Use @pipe for transforms**: When a value needs runtime computation (date stamp, string concat, slugify), use @pipe — never hardcode computed values
|
|
211
|
+
8. **Simple fields stay simple**: If a field just passes a trigger value through (domain, key, url), use a plain reference like \`'{trigger_x8kf.output.data.domain}'\` — NEVER wrap it in @pipe. Only use @pipe when actual transformation is needed.
|
|
212
|
+
9. **File extensions**: Screenshot paths MUST include .png extension. Use @pipe concat if deriving from a slug
|
|
213
|
+
10. **job.maps on last activity**: The final activity should have job.maps to promote output fields to the workflow result
|
|
214
|
+
11. **Linear transitions**: Chain activities with transitions unless branching or iteration is needed
|
|
215
|
+
12. **Conditional transitions**: For branching, use multi-target transitions with conditions:
|
|
216
|
+
\`\`\`yaml
|
|
217
|
+
transitions:
|
|
218
|
+
check_x8kf:
|
|
219
|
+
- to: handle_error_x8kf
|
|
220
|
+
conditions:
|
|
221
|
+
code: 500
|
|
222
|
+
- to: proceed_x8kf
|
|
223
|
+
\`\`\`
|
|
224
|
+
Conditions can match on \`code\` (HTTP status) or \`match\` (field comparisons). The first matching condition wins; the last entry (no conditions) is the default.
|
|
225
|
+
13. **Trigger stats for idempotency**: Use \`stats.id\` and \`stats.key\` on the trigger when the workflow needs custom job IDs or indexed lookups:
|
|
226
|
+
\`\`\`yaml
|
|
227
|
+
trigger_x8kf:
|
|
228
|
+
type: trigger
|
|
229
|
+
stats:
|
|
230
|
+
id: '{$self.input.data.workflowId}'
|
|
231
|
+
key: '{$self.input.data.entityId}'
|
|
232
|
+
\`\`\`
|
|
166
233
|
|
|
167
234
|
## Activity Manifest
|
|
168
235
|
|
|
169
|
-
Along with the YAML, produce an activity_manifest array describing each activity:
|
|
236
|
+
Along with the YAML, produce an activity_manifest array describing each activity. Note how all activity IDs share the same random suffix (\`_x8kf\`) for collision-proofing while remaining human-readable:
|
|
170
237
|
\`\`\`json
|
|
171
238
|
[
|
|
172
239
|
{
|
|
173
|
-
"activity_id": "
|
|
240
|
+
"activity_id": "trigger_x8kf",
|
|
174
241
|
"title": "Trigger",
|
|
175
242
|
"type": "trigger",
|
|
176
243
|
"tool_source": "trigger",
|
|
@@ -179,7 +246,7 @@ Along with the YAML, produce an activity_manifest array describing each activity
|
|
|
179
246
|
"output_fields": ["url", "slug"]
|
|
180
247
|
},
|
|
181
248
|
{
|
|
182
|
-
"activity_id": "
|
|
249
|
+
"activity_id": "capture_x8kf",
|
|
183
250
|
"title": "Capture Page",
|
|
184
251
|
"type": "worker",
|
|
185
252
|
"tool_source": "mcp",
|
|
@@ -188,7 +255,7 @@ Along with the YAML, produce an activity_manifest array describing each activity
|
|
|
188
255
|
"mcp_server_id": "long-tail-playwright-cli",
|
|
189
256
|
"mcp_tool_name": "capture_page",
|
|
190
257
|
"tool_arguments": {},
|
|
191
|
-
"input_mappings": { "url": "{
|
|
258
|
+
"input_mappings": { "url": "{trigger_x8kf.output.data.url}" },
|
|
192
259
|
"output_fields": ["page_id", "path", "url", "title"]
|
|
193
260
|
}
|
|
194
261
|
]
|
|
@@ -222,9 +289,11 @@ When the user provides answers to your questions, build the workflow immediately
|
|
|
222
289
|
|
|
223
290
|
## Output Format
|
|
224
291
|
|
|
292
|
+
CRITICAL: The "name" field MUST match the "subscribes" topic in the YAML exactly. Use lowercase with dots as separators (e.g. "screenshot.analyze.store", "capture.page", "daily.report"). Dashes and underscores are also allowed but dots are preferred. The name and subscribes topic MUST be identical.
|
|
293
|
+
|
|
225
294
|
Return a JSON object (no markdown fences):
|
|
226
295
|
{
|
|
227
|
-
"name": "
|
|
296
|
+
"name": "screenshot.analyze.store",
|
|
228
297
|
"description": "What this workflow does",
|
|
229
298
|
"yaml": "<the complete YAML string>",
|
|
230
299
|
"input_schema": { <JSON Schema for trigger inputs> },
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyze a specification to determine whether it requires plan mode.
|
|
3
|
+
* Returns structural signals extracted from the input.
|
|
4
|
+
*/
|
|
5
|
+
export interface SpecAnalysis {
|
|
6
|
+
requires_plan: boolean;
|
|
7
|
+
signal_count: number;
|
|
8
|
+
char_count: number;
|
|
9
|
+
signals_found: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare function analyzeSpecification(specification: string): Promise<SpecAnalysis>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Analyze a specification to determine whether it requires plan mode.
|
|
4
|
+
* Returns structural signals extracted from the input.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.analyzeSpecification = analyzeSpecification;
|
|
8
|
+
const PLAN_SIGNALS = [
|
|
9
|
+
/\bworkflow[s]?\b/gi,
|
|
10
|
+
/\bstep\s+\d/gi,
|
|
11
|
+
/\bphase\s+\d/gi,
|
|
12
|
+
/\bfirst\b.*\bthen\b/gi,
|
|
13
|
+
/\bcompos/gi,
|
|
14
|
+
/\borchestrat/gi,
|
|
15
|
+
/\bpipeline/gi,
|
|
16
|
+
/\bsub-?process/gi,
|
|
17
|
+
/\bplan\b/gi,
|
|
18
|
+
];
|
|
19
|
+
const MIN_PLAN_LENGTH = 500;
|
|
20
|
+
async function analyzeSpecification(specification) {
|
|
21
|
+
const charCount = specification.length;
|
|
22
|
+
const signalsFound = [];
|
|
23
|
+
for (const pattern of PLAN_SIGNALS) {
|
|
24
|
+
const matches = specification.match(pattern);
|
|
25
|
+
if (matches?.length) {
|
|
26
|
+
signalsFound.push(matches[0]);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const requiresPlan = charCount >= MIN_PLAN_LENGTH && signalsFound.length >= 2;
|
|
30
|
+
return {
|
|
31
|
+
requires_plan: requiresPlan,
|
|
32
|
+
signal_count: signalsFound.length,
|
|
33
|
+
char_count: charCount,
|
|
34
|
+
signals_found: signalsFound,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deploySetNamespaces = exports.updateSetStatus = exports.persistBuiltWorkflow = exports.persistPlan = exports.generatePlan = exports.analyzeSpecification = void 0;
|
|
4
|
+
var analyze_1 = require("./analyze");
|
|
5
|
+
Object.defineProperty(exports, "analyzeSpecification", { enumerable: true, get: function () { return analyze_1.analyzeSpecification; } });
|
|
6
|
+
var plan_1 = require("./plan");
|
|
7
|
+
Object.defineProperty(exports, "generatePlan", { enumerable: true, get: function () { return plan_1.generatePlan; } });
|
|
8
|
+
var persist_1 = require("./persist");
|
|
9
|
+
Object.defineProperty(exports, "persistPlan", { enumerable: true, get: function () { return persist_1.persistPlan; } });
|
|
10
|
+
Object.defineProperty(exports, "persistBuiltWorkflow", { enumerable: true, get: function () { return persist_1.persistBuiltWorkflow; } });
|
|
11
|
+
Object.defineProperty(exports, "updateSetStatus", { enumerable: true, get: function () { return persist_1.updateSetStatus; } });
|
|
12
|
+
Object.defineProperty(exports, "deploySetNamespaces", { enumerable: true, get: function () { return persist_1.deploySetNamespaces; } });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence activities for the workflow planner.
|
|
3
|
+
* These are side-effect functions that update the database.
|
|
4
|
+
*/
|
|
5
|
+
import type { PlanItem, LTWorkflowSetStatus } from '../../../../types/workflow-set';
|
|
6
|
+
export declare function persistPlan(setId: string, planItems: PlanItem[]): Promise<void>;
|
|
7
|
+
export interface BuiltWorkflowData {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
yaml_content: string;
|
|
11
|
+
input_schema: Record<string, unknown>;
|
|
12
|
+
output_schema: Record<string, unknown>;
|
|
13
|
+
activity_manifest: unknown[];
|
|
14
|
+
tags: string[];
|
|
15
|
+
graph_topic: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function persistBuiltWorkflow(setId: string, planItem: PlanItem, builderOutput: BuiltWorkflowData): Promise<string>;
|
|
18
|
+
export declare function updateSetStatus(setId: string, status: LTWorkflowSetStatus): Promise<void>;
|
|
19
|
+
export declare function deploySetNamespaces(namespaces: string[]): Promise<void>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Persistence activities for the workflow planner.
|
|
4
|
+
* These are side-effect functions that update the database.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.persistPlan = persistPlan;
|
|
8
|
+
exports.persistBuiltWorkflow = persistBuiltWorkflow;
|
|
9
|
+
exports.updateSetStatus = updateSetStatus;
|
|
10
|
+
exports.deploySetNamespaces = deploySetNamespaces;
|
|
11
|
+
const workflow_sets_1 = require("../../../../services/workflow-sets");
|
|
12
|
+
const db_1 = require("../../../../services/yaml-workflow/db");
|
|
13
|
+
const deployer_1 = require("../../../../services/yaml-workflow/deployer");
|
|
14
|
+
const workers_1 = require("../../../../services/yaml-workflow/workers");
|
|
15
|
+
async function persistPlan(setId, planItems) {
|
|
16
|
+
const namespaces = [...new Set(planItems.map(w => w.namespace))];
|
|
17
|
+
await (0, workflow_sets_1.updateWorkflowSetPlan)(setId, planItems, namespaces);
|
|
18
|
+
}
|
|
19
|
+
async function persistBuiltWorkflow(setId, planItem, builderOutput) {
|
|
20
|
+
const input = {
|
|
21
|
+
name: builderOutput.name,
|
|
22
|
+
description: builderOutput.description,
|
|
23
|
+
app_id: planItem.namespace,
|
|
24
|
+
yaml_content: builderOutput.yaml_content,
|
|
25
|
+
graph_topic: builderOutput.graph_topic || builderOutput.name,
|
|
26
|
+
input_schema: builderOutput.input_schema,
|
|
27
|
+
output_schema: builderOutput.output_schema,
|
|
28
|
+
activity_manifest: builderOutput.activity_manifest,
|
|
29
|
+
tags: builderOutput.tags || [],
|
|
30
|
+
source_workflow_type: 'mcpWorkflowPlanner',
|
|
31
|
+
set_id: setId,
|
|
32
|
+
set_role: planItem.role,
|
|
33
|
+
set_build_order: planItem.build_order,
|
|
34
|
+
};
|
|
35
|
+
const record = await (0, db_1.createYamlWorkflow)(input);
|
|
36
|
+
return record.id;
|
|
37
|
+
}
|
|
38
|
+
async function updateSetStatus(setId, status) {
|
|
39
|
+
await (0, workflow_sets_1.updateWorkflowSetStatus)(setId, status);
|
|
40
|
+
}
|
|
41
|
+
async function deploySetNamespaces(namespaces) {
|
|
42
|
+
for (const namespace of namespaces) {
|
|
43
|
+
await (0, deployer_1.deployAppId)(namespace, '1');
|
|
44
|
+
// Register workers and activate all workflows in this namespace
|
|
45
|
+
const siblings = await (0, db_1.listYamlWorkflowsByAppId)(namespace);
|
|
46
|
+
for (const sibling of siblings) {
|
|
47
|
+
await (0, db_1.updateYamlWorkflowVersion)(sibling.id, '1');
|
|
48
|
+
await (0, workers_1.registerWorkersForWorkflow)(sibling);
|
|
49
|
+
if (sibling.status === 'draft' || sibling.status === 'deployed') {
|
|
50
|
+
await (0, db_1.updateYamlWorkflowStatus)(sibling.id, 'active');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
await (0, db_1.markAppIdContentDeployed)(namespace);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a decomposition plan from a specification using an LLM.
|
|
3
|
+
*/
|
|
4
|
+
import type { PlanItem } from '../../../../types/workflow-set';
|
|
5
|
+
export interface PlanResult {
|
|
6
|
+
plan_name: string;
|
|
7
|
+
plan_description: string;
|
|
8
|
+
workflows: PlanItem[];
|
|
9
|
+
}
|
|
10
|
+
export declare function generatePlan(specification: string): Promise<PlanResult>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Generate a decomposition plan from a specification using an LLM.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generatePlan = generatePlan;
|
|
7
|
+
const llm_1 = require("../../../../services/llm");
|
|
8
|
+
const defaults_1 = require("../../../../modules/defaults");
|
|
9
|
+
const prompts_1 = require("../prompts");
|
|
10
|
+
async function generatePlan(specification) {
|
|
11
|
+
const response = await (0, llm_1.callLLM)({
|
|
12
|
+
model: defaults_1.LLM_MODEL_PRIMARY,
|
|
13
|
+
max_tokens: 4096,
|
|
14
|
+
temperature: 0,
|
|
15
|
+
messages: [
|
|
16
|
+
{ role: 'system', content: prompts_1.PLANNER_SYSTEM_PROMPT },
|
|
17
|
+
{ role: 'user', content: specification },
|
|
18
|
+
],
|
|
19
|
+
});
|
|
20
|
+
const raw = response.content || '{}';
|
|
21
|
+
const cleaned = raw.replace(/^```(?:json)?\s*/m, '').replace(/\s*```$/m, '').trim();
|
|
22
|
+
const parsed = JSON.parse(cleaned);
|
|
23
|
+
if (!Array.isArray(parsed.workflows) || parsed.workflows.length === 0) {
|
|
24
|
+
throw new Error('Planner produced empty workflow list');
|
|
25
|
+
}
|
|
26
|
+
// Sort by build_order (leaf-first)
|
|
27
|
+
parsed.workflows.sort((a, b) => a.build_order - b.build_order);
|
|
28
|
+
// Extract unique namespaces
|
|
29
|
+
const namespaces = [...new Set(parsed.workflows.map(w => w.namespace))];
|
|
30
|
+
return {
|
|
31
|
+
plan_name: parsed.plan_name || 'unnamed-plan',
|
|
32
|
+
plan_description: parsed.plan_description || '',
|
|
33
|
+
workflows: parsed.workflows.map(w => ({
|
|
34
|
+
name: w.name,
|
|
35
|
+
description: w.description,
|
|
36
|
+
namespace: w.namespace,
|
|
37
|
+
role: w.role || 'leaf',
|
|
38
|
+
dependencies: w.dependencies || [],
|
|
39
|
+
build_order: w.build_order ?? 0,
|
|
40
|
+
io_contract: w.io_contract || { input_schema: {}, output_schema: {} },
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LTEnvelope, LTReturn } from '../../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Plan mode workflow — decomposes a specification into N workflows,
|
|
4
|
+
* builds them leaf-first by delegating to mcpWorkflowBuilder,
|
|
5
|
+
* and deploys the resulting set.
|
|
6
|
+
*/
|
|
7
|
+
export declare function mcpWorkflowPlanner(envelope: LTEnvelope): Promise<LTReturn>;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.mcpWorkflowPlanner = mcpWorkflowPlanner;
|
|
37
|
+
const hotmesh_1 = require("@hotmeshio/hotmesh");
|
|
38
|
+
const orchestrator_1 = require("../../../services/orchestrator");
|
|
39
|
+
const activities = __importStar(require("./activities"));
|
|
40
|
+
const { generatePlan, persistPlan, persistBuiltWorkflow, updateSetStatus, deploySetNamespaces, } = hotmesh_1.Durable.workflow.proxyActivities({
|
|
41
|
+
activities,
|
|
42
|
+
retry: {
|
|
43
|
+
maximumAttempts: 3,
|
|
44
|
+
backoffCoefficient: 2,
|
|
45
|
+
maximumInterval: '10 seconds',
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* Plan mode workflow — decomposes a specification into N workflows,
|
|
50
|
+
* builds them leaf-first by delegating to mcpWorkflowBuilder,
|
|
51
|
+
* and deploys the resulting set.
|
|
52
|
+
*/
|
|
53
|
+
async function mcpWorkflowPlanner(envelope) {
|
|
54
|
+
const { specification, setId } = envelope.data;
|
|
55
|
+
// 1. Generate plan from specification
|
|
56
|
+
const planResult = await generatePlan(specification);
|
|
57
|
+
// 2. Persist the plan to the workflow set
|
|
58
|
+
await persistPlan(setId, planResult.workflows);
|
|
59
|
+
// 3. Build each workflow in dependency order (leaf-first)
|
|
60
|
+
await updateSetStatus(setId, 'building');
|
|
61
|
+
const builtWorkflows = [];
|
|
62
|
+
for (const planItem of planResult.workflows) {
|
|
63
|
+
// Build context for the builder: sibling schemas for composition wiring
|
|
64
|
+
const siblingSchemas = builtWorkflows.map(w => ({
|
|
65
|
+
name: w.name,
|
|
66
|
+
input_schema: w.input_schema,
|
|
67
|
+
output_schema: w.output_schema,
|
|
68
|
+
graph_topic: w.graph_topic,
|
|
69
|
+
}));
|
|
70
|
+
// Delegate to the existing builder workflow
|
|
71
|
+
const builderResult = await (0, orchestrator_1.executeLT)({
|
|
72
|
+
workflowName: 'mcpWorkflowBuilder',
|
|
73
|
+
args: [{
|
|
74
|
+
data: {
|
|
75
|
+
prompt: buildPromptForPlanItem(planItem, siblingSchemas),
|
|
76
|
+
tags: [],
|
|
77
|
+
composition_context: {
|
|
78
|
+
sibling_schemas: siblingSchemas,
|
|
79
|
+
dependencies: planItem.dependencies,
|
|
80
|
+
namespace: planItem.namespace,
|
|
81
|
+
requires_await: planItem.dependencies.some(dep => planResult.workflows.find(w => w.name === dep)?.namespace === planItem.namespace),
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
metadata: envelope.metadata,
|
|
85
|
+
lt: envelope.lt,
|
|
86
|
+
}],
|
|
87
|
+
taskQueue: 'long-tail-system',
|
|
88
|
+
});
|
|
89
|
+
const builderData = builderResult.data;
|
|
90
|
+
// Persist the built workflow with set membership
|
|
91
|
+
const yamlId = await persistBuiltWorkflow(setId, planItem, {
|
|
92
|
+
name: builderData.name || planItem.name,
|
|
93
|
+
description: builderData.description || planItem.description,
|
|
94
|
+
yaml_content: builderData.yaml,
|
|
95
|
+
input_schema: builderData.input_schema || {},
|
|
96
|
+
output_schema: planItem.io_contract.output_schema || {},
|
|
97
|
+
activity_manifest: builderData.activity_manifest || [],
|
|
98
|
+
tags: builderData.tags || [],
|
|
99
|
+
graph_topic: builderData.name || planItem.name,
|
|
100
|
+
});
|
|
101
|
+
builtWorkflows.push({
|
|
102
|
+
name: planItem.name,
|
|
103
|
+
id: yamlId,
|
|
104
|
+
input_schema: builderData.input_schema || {},
|
|
105
|
+
output_schema: planItem.io_contract.output_schema || {},
|
|
106
|
+
graph_topic: builderData.name || planItem.name,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// 4. Deploy all namespaces
|
|
110
|
+
await updateSetStatus(setId, 'deploying');
|
|
111
|
+
const namespaces = [...new Set(planResult.workflows.map(w => w.namespace))];
|
|
112
|
+
await deploySetNamespaces(namespaces);
|
|
113
|
+
// 5. Mark complete
|
|
114
|
+
await updateSetStatus(setId, 'completed');
|
|
115
|
+
return {
|
|
116
|
+
type: 'return',
|
|
117
|
+
data: {
|
|
118
|
+
title: planResult.plan_name,
|
|
119
|
+
summary: `Built ${builtWorkflows.length} workflows across ${namespaces.length} namespace(s)`,
|
|
120
|
+
set_id: setId,
|
|
121
|
+
workflows: builtWorkflows,
|
|
122
|
+
namespaces,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Build a detailed prompt for the builder from a plan item.
|
|
128
|
+
* Includes the workflow description, I/O contract, and dependency context.
|
|
129
|
+
*/
|
|
130
|
+
function buildPromptForPlanItem(planItem, siblingSchemas) {
|
|
131
|
+
const parts = [planItem.description];
|
|
132
|
+
// Add I/O contract
|
|
133
|
+
if (planItem.io_contract.input_schema?.properties) {
|
|
134
|
+
parts.push(`\nInputs: ${JSON.stringify(planItem.io_contract.input_schema, null, 2)}`);
|
|
135
|
+
}
|
|
136
|
+
if (planItem.io_contract.output_schema?.properties) {
|
|
137
|
+
parts.push(`\nOutputs: ${JSON.stringify(planItem.io_contract.output_schema, null, 2)}`);
|
|
138
|
+
}
|
|
139
|
+
// Add dependency context
|
|
140
|
+
if (planItem.dependencies.length > 0) {
|
|
141
|
+
const depSchemas = siblingSchemas.filter(s => planItem.dependencies.includes(s.name));
|
|
142
|
+
if (depSchemas.length > 0) {
|
|
143
|
+
parts.push('\nThis workflow depends on the following sibling workflows:');
|
|
144
|
+
for (const dep of depSchemas) {
|
|
145
|
+
parts.push(`- ${dep.name} (topic: ${dep.graph_topic})`);
|
|
146
|
+
parts.push(` Input: ${JSON.stringify(dep.input_schema)}`);
|
|
147
|
+
parts.push(` Output: ${JSON.stringify(dep.output_schema)}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return parts.join('\n');
|
|
152
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Externalized prompts for the workflow planner.
|
|
3
|
+
*
|
|
4
|
+
* The planner prompt teaches the LLM how to decompose a specification
|
|
5
|
+
* into a set of related workflows with dependency ordering.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PLANNER_SYSTEM_PROMPT = "You are a workflow planner. Given a specification (PRD, TDD, or natural language description of a multi-step process), you decompose it into a set of standalone workflows that together implement the complete system.\n\n## Your Task\n\nAnalyze the specification and produce a structured plan: an array of workflow items, each with a name, description, namespace, role, dependencies, and input/output contract.\n\n## Workflow Roles\n\n- **leaf**: A standalone workflow that calls MCP tools directly. No dependencies on other custom workflows in the plan.\n- **composition**: A workflow that orchestrates other workflows in the plan. It calls them using HotMesh await activities (same namespace) or MCP tool calls (different namespace).\n- **router**: A workflow that routes to different workflows based on input conditions.\n\n## Namespace Rules\n\nWorkflows in the **same namespace** are deployed together as one HotMesh application. They can invoke each other using await activities (synchronous composition within the same execution engine).\n\nWorkflows in **different namespaces** are independent. They invoke each other as MCP tools (discovered by tag, invoked through the tool protocol).\n\n**Same namespace when:** tightly coupled, shared data context, always deployed together, phases of the same process.\n**Different namespace when:** independently reusable, different versioning cycles, different teams/domains.\n\n## Build Order\n\nLeaf workflows are built first (build_order = 0). Composition workflows that depend on leaves come next (build_order = 1). Workflows that compose those compositions come after (build_order = 2). The tree builds from leaves up.\n\n## Input/Output Contracts\n\nEach workflow has a typed input and output contract (JSON Schema). Composition workflows wire their inputs to child workflow inputs, and child outputs back to their own outputs. These contracts are how the builder knows what to wire.\n\n## Output Format\n\nReturn a JSON object (no markdown fences):\n{\n \"plan_name\": \"kebab-case-plan-name\",\n \"plan_description\": \"What this set of workflows accomplishes\",\n \"workflows\": [\n {\n \"name\": \"kebab-case-workflow-name\",\n \"description\": \"What this workflow does \u2014 specific enough to build from\",\n \"namespace\": \"the-app-namespace\",\n \"role\": \"leaf\" | \"composition\" | \"router\",\n \"dependencies\": [\"name-of-workflow-this-depends-on\"],\n \"build_order\": 0,\n \"io_contract\": {\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": { ... },\n \"required\": [...]\n },\n \"output_schema\": {\n \"type\": \"object\",\n \"properties\": { ... }\n }\n }\n }\n ]\n}\n\n## Rules\n\n1. Every workflow must be independently testable with sample inputs\n2. Leaf workflows should be fine-grained: one responsibility per workflow\n3. Composition workflows encode sequencing, branching, and escalation gates\n4. Do not create a workflow for something a single MCP tool call can handle \u2014 use a leaf workflow only when there are multiple steps or conditional logic\n5. Keep the number of workflows minimal \u2014 prefer fewer, well-scoped workflows over many trivial ones\n6. Names must be globally unique within the plan\n7. Dependencies reference other workflow names in the plan (not external tools)\n8. If the specification mentions human review, approval, or escalation, the relevant workflow should include a signal/hook step (describe this in the workflow description)";
|