@agimon-ai/doompi-workflow 0.0.1-alpha.76 → 0.0.1-alpha.78
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/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/api-contracts.cjs +7 -0
- package/dist/api-contracts.d.cts +2 -0
- package/dist/api-contracts.d.mts +2 -0
- package/dist/api-contracts.mjs +2 -0
- package/dist/extensions/pi.cjs +63 -0
- package/dist/extensions/pi.cjs.map +1 -0
- package/dist/extensions/pi.d.cts +6 -0
- package/dist/extensions/pi.d.cts.map +1 -0
- package/dist/extensions/pi.d.mts +6 -0
- package/dist/extensions/pi.d.mts.map +1 -0
- package/dist/extensions/pi.mjs +58 -0
- package/dist/extensions/pi.mjs.map +1 -0
- package/dist/extensions/server.cjs +96 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.cts +5 -0
- package/dist/extensions/server.d.cts.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +91 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +3219 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/index.cjs +4 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +2 -0
- package/dist/src/constants/workflow.cjs +32 -0
- package/dist/src/constants/workflow.cjs.map +1 -0
- package/dist/src/constants/workflow.mjs +21 -0
- package/dist/src/constants/workflow.mjs.map +1 -0
- package/dist/src/extensions/(backend)/_lib/index.server.cjs +12 -0
- package/dist/src/extensions/(backend)/_lib/index.server.cjs.map +1 -0
- package/dist/src/extensions/(backend)/_lib/index.server.mjs +12 -0
- package/dist/src/extensions/(backend)/_lib/index.server.mjs.map +1 -0
- package/dist/src/extensions/(backend)/api/workflow/route.server.cjs +7 -0
- package/dist/src/extensions/(backend)/api/workflow/route.server.cjs.map +1 -0
- package/dist/src/extensions/(backend)/api/workflow/route.server.mjs +8 -0
- package/dist/src/extensions/(backend)/api/workflow/route.server.mjs.map +1 -0
- package/dist/src/extensions/(backend)/channel/workflow-catalog.server.cjs +7 -0
- package/dist/src/extensions/(backend)/channel/workflow-catalog.server.cjs.map +1 -0
- package/dist/src/extensions/(backend)/channel/workflow-catalog.server.mjs +8 -0
- package/dist/src/extensions/(backend)/channel/workflow-catalog.server.mjs.map +1 -0
- package/dist/src/extensions/(backend)/channel/workflows.server.cjs +7 -0
- package/dist/src/extensions/(backend)/channel/workflows.server.cjs.map +1 -0
- package/dist/src/extensions/(backend)/channel/workflows.server.mjs +8 -0
- package/dist/src/extensions/(backend)/channel/workflows.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/index.cli.cjs +100 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/index.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/index.cli.mjs +100 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/index.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/index.server.cjs +11 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/index.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/index.server.mjs +11 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/index.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/workflowSkillsResource.cjs +12 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/workflowSkillsResource.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/workflowSkillsResource.mjs +12 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/_lib/workflowSkillsResource.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/api/workflow/route.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/api/workflow/route.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/api/workflow/route.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/api/workflow/route.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/workflow-launch.cli.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/workflow-launch.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/workflow-launch.cli.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/workflow-launch.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/workflow-launch.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/workflow-launch.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/workflow-launch.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/command/workflow-launch.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/resources-discover.cli.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/resources-discover.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/resources-discover.cli.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/resources-discover.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-author-workflow.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-author-workflow.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-author-workflow.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-author-workflow.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-workflow.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-workflow.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-workflow.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/doompi-use-workflow.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/workflow-recovery.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/workflow-recovery.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/workflow-recovery.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/workflow-recovery.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/workflow-skills.cli.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/workflow-skills.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/workflow-skills.cli.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/resource/workflow-skills.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.cjs +15 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.mjs +16 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.cjs +17 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.mjs +18 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/root.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/shortcut/workflow-panel.cli.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/shortcut/workflow-panel.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/shortcut/workflow-panel.cli.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/shortcut/workflow-panel.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/shortcut/workflow-view-close.cli.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/shortcut/workflow-view-close.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/shortcut/workflow-view-close.cli.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/shortcut/workflow-view-close.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/launch-workflow.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/launch-workflow.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/launch-workflow.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/launch-workflow.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/list-workflows.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/list-workflows.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/list-workflows.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/list-workflows.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/workflow-run.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/workflow-run.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/workflow-run.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/workflow-run.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/workflow.cli.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/workflow.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/workflow.cli.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool/workflow.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.cli.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.cli.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.server.cjs +6 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.server.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.server.mjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.server.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowFinishedRenderer.cjs +50 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowFinishedRenderer.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowFinishedRenderer.mjs +47 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowFinishedRenderer.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowStepRenderer.cjs +36 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowStepRenderer.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowStepRenderer.mjs +35 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowStepRenderer.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/workflow-finished.cli.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/workflow-finished.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/workflow-finished.cli.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/workflow-finished.cli.mjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/workflow-step.cli.cjs +7 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/workflow-step.cli.cjs.map +1 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/workflow-step.cli.mjs +8 -0
- package/dist/src/extensions/workspaces/sessions/(frontend)/message/workflow-step.cli.mjs.map +1 -0
- package/dist/src/schemas/apiContracts.cjs +330 -0
- package/dist/src/schemas/apiContracts.cjs.map +1 -0
- package/dist/src/schemas/apiContracts.d.cts +53 -0
- package/dist/src/schemas/apiContracts.d.cts.map +1 -0
- package/dist/src/schemas/apiContracts.d.mts +53 -0
- package/dist/src/schemas/apiContracts.d.mts.map +1 -0
- package/dist/src/schemas/apiContracts.mjs +327 -0
- package/dist/src/schemas/apiContracts.mjs.map +1 -0
- package/dist/src/schemas/workflowPi.cjs +77 -0
- package/dist/src/schemas/workflowPi.cjs.map +1 -0
- package/dist/src/schemas/workflowPi.d.cts +1 -0
- package/dist/src/schemas/workflowPi.d.mts +1 -0
- package/dist/src/schemas/workflowPi.mjs +74 -0
- package/dist/src/schemas/workflowPi.mjs.map +1 -0
- package/dist/src/services/backgroundWork/index.cjs +61 -0
- package/dist/src/services/backgroundWork/index.cjs.map +1 -0
- package/dist/src/services/backgroundWork/index.mjs +61 -0
- package/dist/src/services/backgroundWork/index.mjs.map +1 -0
- package/dist/src/services/piToolBridge/index.cjs +205 -0
- package/dist/src/services/piToolBridge/index.cjs.map +1 -0
- package/dist/src/services/piToolBridge/index.mjs +195 -0
- package/dist/src/services/piToolBridge/index.mjs.map +1 -0
- package/dist/src/services/serverRuntime/index.cjs +387 -0
- package/dist/src/services/serverRuntime/index.cjs.map +1 -0
- package/dist/src/services/serverRuntime/index.mjs +387 -0
- package/dist/src/services/serverRuntime/index.mjs.map +1 -0
- package/dist/src/services/webWorkflowCatalog/index.cjs +53 -0
- package/dist/src/services/webWorkflowCatalog/index.cjs.map +1 -0
- package/dist/src/services/webWorkflowCatalog/index.mjs +52 -0
- package/dist/src/services/webWorkflowCatalog/index.mjs.map +1 -0
- package/dist/src/services/workflowCatalogChannel/index.cjs +74 -0
- package/dist/src/services/workflowCatalogChannel/index.cjs.map +1 -0
- package/dist/src/services/workflowCatalogChannel/index.mjs +74 -0
- package/dist/src/services/workflowCatalogChannel/index.mjs.map +1 -0
- package/dist/src/services/workflowCatalogDeps/index.cjs +25 -0
- package/dist/src/services/workflowCatalogDeps/index.cjs.map +1 -0
- package/dist/src/services/workflowCatalogDeps/index.mjs +25 -0
- package/dist/src/services/workflowCatalogDeps/index.mjs.map +1 -0
- package/dist/src/services/workflowExecution/index.cjs +205 -0
- package/dist/src/services/workflowExecution/index.cjs.map +1 -0
- package/dist/src/services/workflowExecution/index.d.cts +6 -0
- package/dist/src/services/workflowExecution/index.d.mts +6 -0
- package/dist/src/services/workflowExecution/index.mjs +200 -0
- package/dist/src/services/workflowExecution/index.mjs.map +1 -0
- package/dist/src/services/workflowFence/index.cjs +170 -0
- package/dist/src/services/workflowFence/index.cjs.map +1 -0
- package/dist/src/services/workflowFence/index.mjs +166 -0
- package/dist/src/services/workflowFence/index.mjs.map +1 -0
- package/dist/src/services/workflowHubApi/index.cjs +415 -0
- package/dist/src/services/workflowHubApi/index.cjs.map +1 -0
- package/dist/src/services/workflowHubApi/index.mjs +411 -0
- package/dist/src/services/workflowHubApi/index.mjs.map +1 -0
- package/dist/src/services/workflowLaunchCommand/index.cjs +121 -0
- package/dist/src/services/workflowLaunchCommand/index.cjs.map +1 -0
- package/dist/src/services/workflowLaunchCommand/index.d.cts +52 -0
- package/dist/src/services/workflowLaunchCommand/index.d.cts.map +1 -0
- package/dist/src/services/workflowLaunchCommand/index.d.mts +52 -0
- package/dist/src/services/workflowLaunchCommand/index.d.mts.map +1 -0
- package/dist/src/services/workflowLaunchCommand/index.mjs +118 -0
- package/dist/src/services/workflowLaunchCommand/index.mjs.map +1 -0
- package/dist/src/services/workflowLauncher/index.cjs +181 -0
- package/dist/src/services/workflowLauncher/index.cjs.map +1 -0
- package/dist/src/services/workflowLauncher/index.mjs +177 -0
- package/dist/src/services/workflowLauncher/index.mjs.map +1 -0
- package/dist/src/services/workflowNarration/index.cjs +19 -0
- package/dist/src/services/workflowNarration/index.cjs.map +1 -0
- package/dist/src/services/workflowNarration/index.mjs +19 -0
- package/dist/src/services/workflowNarration/index.mjs.map +1 -0
- package/dist/src/services/workflowResource/index.cjs +27 -0
- package/dist/src/services/workflowResource/index.cjs.map +1 -0
- package/dist/src/services/workflowResource/index.mjs +24 -0
- package/dist/src/services/workflowResource/index.mjs.map +1 -0
- package/dist/src/services/workflowRuns/index.cjs +333 -0
- package/dist/src/services/workflowRuns/index.cjs.map +1 -0
- package/dist/src/services/workflowRuns/index.mjs +319 -0
- package/dist/src/services/workflowRuns/index.mjs.map +1 -0
- package/dist/src/services/workflowTerminal/index.cjs +69 -0
- package/dist/src/services/workflowTerminal/index.cjs.map +1 -0
- package/dist/src/services/workflowTerminal/index.mjs +69 -0
- package/dist/src/services/workflowTerminal/index.mjs.map +1 -0
- package/dist/src/services/workflowTools/index.cjs +221 -0
- package/dist/src/services/workflowTools/index.cjs.map +1 -0
- package/dist/src/services/workflowTools/index.mjs +221 -0
- package/dist/src/services/workflowTools/index.mjs.map +1 -0
- package/dist/src/services/workflowWatcher/index.cjs +78 -0
- package/dist/src/services/workflowWatcher/index.cjs.map +1 -0
- package/dist/src/services/workflowWatcher/index.mjs +74 -0
- package/dist/src/services/workflowWatcher/index.mjs.map +1 -0
- package/dist/src/services/workflowsHubChannel/index.cjs +58 -0
- package/dist/src/services/workflowsHubChannel/index.cjs.map +1 -0
- package/dist/src/services/workflowsHubChannel/index.mjs +58 -0
- package/dist/src/services/workflowsHubChannel/index.mjs.map +1 -0
- package/dist/src/tui/leader.cjs +84 -0
- package/dist/src/tui/leader.cjs.map +1 -0
- package/dist/src/tui/leader.mjs +83 -0
- package/dist/src/tui/leader.mjs.map +1 -0
- package/dist/src/tui/workflow/doomOverlay.cjs +159 -0
- package/dist/src/tui/workflow/doomOverlay.cjs.map +1 -0
- package/dist/src/tui/workflow/doomOverlay.mjs +157 -0
- package/dist/src/tui/workflow/doomOverlay.mjs.map +1 -0
- package/dist/src/tui/workflow/overlayText.cjs +83 -0
- package/dist/src/tui/workflow/overlayText.cjs.map +1 -0
- package/dist/src/tui/workflow/overlayText.mjs +78 -0
- package/dist/src/tui/workflow/overlayText.mjs.map +1 -0
- package/dist/src/tui/workflow/rendering.cjs +22 -0
- package/dist/src/tui/workflow/rendering.cjs.map +1 -0
- package/dist/src/tui/workflow/rendering.mjs +20 -0
- package/dist/src/tui/workflow/rendering.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowCatalog.cjs +336 -0
- package/dist/src/tui/workflow/workflowCatalog.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowCatalog.mjs +333 -0
- package/dist/src/tui/workflow/workflowCatalog.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowFinishedMessage.cjs +50 -0
- package/dist/src/tui/workflow/workflowFinishedMessage.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowFinishedMessage.mjs +47 -0
- package/dist/src/tui/workflow/workflowFinishedMessage.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowInspector.cjs +276 -0
- package/dist/src/tui/workflow/workflowInspector.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowInspector.mjs +276 -0
- package/dist/src/tui/workflow/workflowInspector.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowOverlay.cjs +126 -0
- package/dist/src/tui/workflow/workflowOverlay.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowOverlay.mjs +125 -0
- package/dist/src/tui/workflow/workflowOverlay.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowPicker.cjs +138 -0
- package/dist/src/tui/workflow/workflowPicker.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowPicker.mjs +136 -0
- package/dist/src/tui/workflow/workflowPicker.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowProgressOverlay.cjs +197 -0
- package/dist/src/tui/workflow/workflowProgressOverlay.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowProgressOverlay.mjs +192 -0
- package/dist/src/tui/workflow/workflowProgressOverlay.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowPrompt.cjs +142 -0
- package/dist/src/tui/workflow/workflowPrompt.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowPrompt.mjs +139 -0
- package/dist/src/tui/workflow/workflowPrompt.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowRunPanel.cjs +95 -0
- package/dist/src/tui/workflow/workflowRunPanel.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowRunPanel.mjs +94 -0
- package/dist/src/tui/workflow/workflowRunPanel.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowStatusRow.cjs +20 -0
- package/dist/src/tui/workflow/workflowStatusRow.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowStatusRow.mjs +20 -0
- package/dist/src/tui/workflow/workflowStatusRow.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowStepMessage.cjs +32 -0
- package/dist/src/tui/workflow/workflowStepMessage.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowStepMessage.mjs +31 -0
- package/dist/src/tui/workflow/workflowStepMessage.mjs.map +1 -0
- package/dist/src/tui/workflow/workflowToolRender.cjs +491 -0
- package/dist/src/tui/workflow/workflowToolRender.cjs.map +1 -0
- package/dist/src/tui/workflow/workflowToolRender.mjs +490 -0
- package/dist/src/tui/workflow/workflowToolRender.mjs.map +1 -0
- package/dist/src/tui/workflowRuntime.cjs +1934 -0
- package/dist/src/tui/workflowRuntime.cjs.map +1 -0
- package/dist/src/tui/workflowRuntime.d.cts +33 -0
- package/dist/src/tui/workflowRuntime.d.cts.map +1 -0
- package/dist/src/tui/workflowRuntime.d.mts +33 -0
- package/dist/src/tui/workflowRuntime.d.mts.map +1 -0
- package/dist/src/tui/workflowRuntime.mjs +1930 -0
- package/dist/src/tui/workflowRuntime.mjs.map +1 -0
- package/dist/src/types/apiRoutes.cjs +82 -0
- package/dist/src/types/apiRoutes.cjs.map +1 -0
- package/dist/src/types/apiRoutes.mjs +80 -0
- package/dist/src/types/apiRoutes.mjs.map +1 -0
- package/dist/src/types/webWorkflowTerminal.cjs +23 -0
- package/dist/src/types/webWorkflowTerminal.cjs.map +1 -0
- package/dist/src/types/webWorkflowTerminal.mjs +22 -0
- package/dist/src/types/webWorkflowTerminal.mjs.map +1 -0
- package/dist/src/types/webWorkflows.cjs +8 -0
- package/dist/src/types/webWorkflows.cjs.map +1 -0
- package/dist/src/types/webWorkflows.mjs +7 -0
- package/dist/src/types/webWorkflows.mjs.map +1 -0
- package/package.json +8 -8
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/services/workflowLauncher/index.ts"],"sourcesContent":["import { resolve } from 'node:path';\n\nimport { type EmbeddedWorkflowFeature, type Workflow } from '@agimon-ai/workflow-mcp';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\nimport { type DispatchInput, workflowCatalogPageSchema, workflowDispatchInputsSchema } from '../../schemas/workflowPi';\nimport type {\n WorkflowCatalogDetail,\n WorkflowInputSummary,\n WorkflowJobSummary,\n} from '../../tui/workflow/workflowCatalog';\nimport { toolResultText } from '../piToolBridge';\nimport { type WorkflowLaunchExecutor, type WorkflowLaunchInput } from '../workflowExecution';\n\nconst CATALOG_PAGE_SIZE = 100;\nconst USER_PROMPT_TRIGGER = 'user_prompt';\nconst WORKFLOW_DISPATCH_TRIGGER = 'workflow_dispatch';\nconst BOOLEAN_INPUT_TYPE = 'boolean';\n\ntype WorkflowListTool = EmbeddedWorkflowFeature['listWorkflowsTool'];\ntype WorkflowListInput = Parameters<WorkflowListTool['execute']>[0];\n\nexport interface WorkflowCatalogEntry {\n description: string;\n name: string;\n path: string;\n relativePath: string;\n tags: string[];\n}\n\nexport interface WorkflowCatalogPage {\n directory: string;\n hasNextPage: boolean;\n page: number;\n pageSize: number;\n workflows: WorkflowCatalogEntry[];\n}\n\nexport interface WorkflowLauncherUi {\n editor(title: string, prefill?: string): Promise<string | undefined>;\n input(title: string, placeholder?: string): Promise<string | undefined>;\n notify(message: string, type?: 'info' | 'warning' | 'error'): void;\n select(title: string, options: string[]): Promise<string | undefined>;\n}\n\nexport interface WorkflowEntryLaunchOptions {\n compatibleRunners(workflow: Workflow): string[] | undefined;\n launch: WorkflowLaunchExecutor['execute'];\n parseWorkflow(workflowPath: string): Workflow;\n ui: WorkflowLauncherUi;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? { ...value } : {};\n}\n\nfunction workflowTriggerBlock(workflow: Workflow): Record<string, unknown> {\n return asRecord(workflow.on);\n}\n\nfunction dispatchInputs(workflow: Workflow): Record<string, DispatchInput> {\n const dispatch = workflowTriggerBlock(workflow)[WORKFLOW_DISPATCH_TRIGGER];\n if (dispatch === null || dispatch === undefined) return {};\n const parsed = workflowDispatchInputsSchema.safeParse(dispatch);\n if (!parsed.success) throw new Error(`Invalid workflow_dispatch input definitions: ${parsed.error.message}`);\n return parsed.data.inputs ?? {};\n}\n\nfunction launchResultError(result: CallToolResult): Error {\n return new Error(toolResultText(result) || 'Workflow launch failed.');\n}\n\nexport function parseWorkflowCatalogPage(result: CallToolResult): WorkflowCatalogPage {\n if (result.isError) throw launchResultError(result);\n let value: unknown;\n try {\n value = JSON.parse(toolResultText(result));\n } catch (cause) {\n throw new Error('Workflow catalog returned invalid JSON.', { cause });\n }\n const parsed = workflowCatalogPageSchema.safeParse(value);\n if (!parsed.success) throw new Error(`Workflow catalog response was invalid: ${parsed.error.message}`);\n return {\n directory: parsed.data.directory,\n hasNextPage: parsed.data.hasNextPage,\n page: parsed.data.page,\n pageSize: parsed.data.pageSize,\n workflows: parsed.data.workflows.map((entry) => ({\n description: entry.description,\n name: entry.name,\n path: resolve(parsed.data.directory, entry.path),\n relativePath: entry.path,\n tags: entry.tags,\n })),\n };\n}\n\nexport async function loadWorkflowCatalog(\n listWorkflowsTool: WorkflowListTool,\n directory: string,\n): Promise<WorkflowCatalogEntry[]> {\n const entries: WorkflowCatalogEntry[] = [];\n let page = 1;\n let hasNextPage = true;\n while (hasNextPage) {\n const input: WorkflowListInput = { directory, page, pageSize: CATALOG_PAGE_SIZE };\n const result = await listWorkflowsTool.execute(input);\n const catalogPage = parseWorkflowCatalogPage(result);\n entries.push(...catalogPage.workflows);\n hasNextPage = catalogPage.hasNextPage;\n page += 1;\n }\n return entries;\n}\n\nasync function requestPrompt(ui: WorkflowLauncherUi): Promise<string | undefined> {\n while (true) {\n const value = await ui.editor('Workflow prompt');\n if (value === undefined) return undefined;\n const prompt = value.trim();\n if (prompt) return prompt;\n ui.notify('A workflow prompt is required.', 'warning');\n }\n}\n\nasync function requestDispatchInput(\n ui: WorkflowLauncherUi,\n name: string,\n input: DispatchInput,\n): Promise<string | undefined> {\n const title = input.description ? `${name}: ${input.description}` : `Workflow input: ${name}`;\n if (input.options && input.options.length > 0) return ui.select(title, input.options);\n if (input.type === BOOLEAN_INPUT_TYPE) return ui.select(title, ['true', 'false']);\n\n while (true) {\n const value = await ui.input(title, input.default);\n if (value === undefined) return undefined;\n const normalized = value.trim() || input.default;\n if (normalized || !input.required) return normalized || undefined;\n ui.notify(`A value is required for workflow input ${name}.`, 'warning');\n }\n}\n\nexport async function collectWorkflowInputs(\n workflow: Workflow,\n ui: WorkflowLauncherUi,\n): Promise<{ inputs?: Record<string, string>; prompt?: string } | undefined> {\n const triggers = workflowTriggerBlock(workflow);\n const requiresPrompt = Object.hasOwn(triggers, USER_PROMPT_TRIGGER);\n const prompt = requiresPrompt ? await requestPrompt(ui) : undefined;\n if (requiresPrompt && prompt === undefined) return undefined;\n\n const definitions = dispatchInputs(workflow);\n const inputs: Record<string, string> = {};\n for (const [name, definition] of Object.entries(definitions)) {\n const value = await requestDispatchInput(ui, name, definition);\n if (value === undefined && definition.required) return undefined;\n if (value !== undefined) inputs[name] = value;\n }\n return {\n ...(prompt === undefined ? {} : { prompt }),\n ...(Object.keys(inputs).length === 0 ? {} : { inputs }),\n };\n}\n\n/**\n * Everything a launch needs once the workflow is chosen: the runner, the\n * prompt, and any `workflow_dispatch` inputs, each asked for through the\n * host's own dialogs. Selection is the caller's business - `SPC w l` launches\n * the row under its cursor, so this takes an entry rather than picking one.\n */\nfunction stepLabel(step: { name?: string; uses?: string; run?: unknown; id?: string }, index: number): string {\n if (step.name) return step.name;\n if (step.uses) return step.uses;\n if (step.id) return step.id;\n // A `run:` step without a name is identified by its position; printing the\n // command would put a shell line into a summary pane.\n return `step ${index + 1}`;\n}\n\nfunction catalogInputs(workflow: Workflow): WorkflowInputSummary[] {\n return Object.entries(dispatchInputs(workflow)).map(([name, definition]) => ({\n name,\n ...(definition.description ? { description: definition.description } : {}),\n ...(definition.required === undefined ? {} : { required: definition.required }),\n ...(definition.default === undefined ? {} : { default: definition.default }),\n ...(definition.options ? { options: definition.options } : {}),\n }));\n}\n\nfunction catalogJobs(workflow: Workflow): WorkflowJobSummary[] {\n return Object.entries(workflow.jobs ?? {}).map(([name, job]) => ({\n name,\n steps: (job.steps ?? []).map((step, index) => stepLabel(step, index)),\n }));\n}\n\n/**\n * The parsed shape `SPC w l`'s detail pane shows. A parse failure is returned\n * as `error` rather than thrown: one unparseable file in a repository must not\n * take the whole board down.\n */\nexport function summarizeWorkflowFile(\n workflowPath: string,\n options: Pick<WorkflowEntryLaunchOptions, 'compatibleRunners' | 'parseWorkflow'>,\n): WorkflowCatalogDetail {\n try {\n const workflow = options.parseWorkflow(workflowPath);\n const runners = options.compatibleRunners(workflow);\n return {\n triggers: Object.keys(workflowTriggerBlock(workflow)),\n inputs: catalogInputs(workflow),\n jobs: catalogJobs(workflow),\n ...(runners ? { runners } : {}),\n };\n } catch (cause) {\n return {\n triggers: [],\n inputs: [],\n jobs: [],\n error: cause instanceof Error ? cause.message : String(cause),\n };\n }\n}\n\nexport async function launchWorkflowEntry(\n options: WorkflowEntryLaunchOptions,\n selected: Pick<WorkflowCatalogEntry, 'path'>,\n ctx: ExtensionContext,\n): Promise<CallToolResult | undefined> {\n const workflow = options.parseWorkflow(selected.path);\n const runners = options.compatibleRunners(workflow);\n if (runners && runners.length === 0) throw new Error('No compatible runner is available for this workflow.');\n let runner: string | undefined;\n if (runners) {\n runner = await options.ui.select('Select a workflow runner', runners);\n if (runner === undefined) return undefined;\n }\n\n const triggerInputs = await collectWorkflowInputs(workflow, options.ui);\n if (triggerInputs === undefined) return undefined;\n const launchInput: WorkflowLaunchInput = {\n workflowPath: selected.path,\n ...(runner === undefined ? {} : { runner }),\n ...(typeof workflow.workspace === 'string' ? { workspace: workflow.workspace } : {}),\n ...triggerInputs,\n };\n return options.launch(launchInput, ctx);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/services/workflowNarration/index.ts
|
|
2
|
+
const RUNNING_STAGE = "running";
|
|
3
|
+
const COMPLETED_STAGE = "completed";
|
|
4
|
+
const ERROR_STAGE = "error";
|
|
5
|
+
/**
|
|
6
|
+
* Translate an observed workflow lifecycle transition into generic speech.
|
|
7
|
+
* Voice owns delivery and ignores requests while its minor mode is inactive.
|
|
8
|
+
*/
|
|
9
|
+
function narrateWorkflowTransition(requester, record, previousStage, startedDuringSession) {
|
|
10
|
+
const newlyLaunched = previousStage === void 0 && startedDuringSession;
|
|
11
|
+
if (newlyLaunched) requester.narrate(`Workflow launched: ${record.displayName}.`);
|
|
12
|
+
if (previousStage !== RUNNING_STAGE && !newlyLaunched) return;
|
|
13
|
+
if (record.stage === COMPLETED_STAGE) requester.narrate(`Workflow succeeded: ${record.displayName}.`);
|
|
14
|
+
if (record.stage === ERROR_STAGE) requester.narrate(`Workflow failed: ${record.displayName}.`);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
exports.narrateWorkflowTransition = narrateWorkflowTransition;
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../../../src/services/workflowNarration/index.ts"],"sourcesContent":["import type { WorkflowRunRecord, WorkflowStage } from '@agimon-ai/workflow-mcp';\n\n/** Package-local narration sink; the Pi adapter binds it to the injected Cordis service. */\nexport interface WorkflowNarrationSink {\n narrate(text: string): void;\n}\n\nconst RUNNING_STAGE: WorkflowStage = 'running';\nconst COMPLETED_STAGE: WorkflowStage = 'completed';\nconst ERROR_STAGE: WorkflowStage = 'error';\n\ntype NarratedWorkflow = Pick<WorkflowRunRecord, 'displayName' | 'stage'>;\n\n/**\n * Translate an observed workflow lifecycle transition into generic speech.\n * Voice owns delivery and ignores requests while its minor mode is inactive.\n */\nexport function narrateWorkflowTransition(\n requester: WorkflowNarrationSink,\n record: NarratedWorkflow,\n previousStage: WorkflowStage | undefined,\n startedDuringSession: boolean,\n): void {\n const newlyLaunched = previousStage === undefined && startedDuringSession;\n if (newlyLaunched) requester.narrate(`Workflow launched: ${record.displayName}.`);\n\n if (previousStage !== RUNNING_STAGE && !newlyLaunched) return;\n if (record.stage === COMPLETED_STAGE) requester.narrate(`Workflow succeeded: ${record.displayName}.`);\n if (record.stage === ERROR_STAGE) requester.narrate(`Workflow failed: ${record.displayName}.`);\n}\n"],"mappings":";AAOA,MAAM,gBAA+B;AACrC,MAAM,kBAAiC;AACvC,MAAM,cAA6B;;;;;AAQnC,SAAgB,0BACd,WACA,QACA,eACA,sBACM;CACN,MAAM,gBAAgB,kBAAkB,KAAA,KAAa;CACrD,IAAI,eAAe,UAAU,QAAQ,sBAAsB,OAAO,YAAY,EAAE;CAEhF,IAAI,kBAAkB,iBAAiB,CAAC,eAAe;CACvD,IAAI,OAAO,UAAU,iBAAiB,UAAU,QAAQ,uBAAuB,OAAO,YAAY,EAAE;CACpG,IAAI,OAAO,UAAU,aAAa,UAAU,QAAQ,oBAAoB,OAAO,YAAY,EAAE;AAC/F"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/services/workflowNarration/index.ts
|
|
2
|
+
const RUNNING_STAGE = "running";
|
|
3
|
+
const COMPLETED_STAGE = "completed";
|
|
4
|
+
const ERROR_STAGE = "error";
|
|
5
|
+
/**
|
|
6
|
+
* Translate an observed workflow lifecycle transition into generic speech.
|
|
7
|
+
* Voice owns delivery and ignores requests while its minor mode is inactive.
|
|
8
|
+
*/
|
|
9
|
+
function narrateWorkflowTransition(requester, record, previousStage, startedDuringSession) {
|
|
10
|
+
const newlyLaunched = previousStage === void 0 && startedDuringSession;
|
|
11
|
+
if (newlyLaunched) requester.narrate(`Workflow launched: ${record.displayName}.`);
|
|
12
|
+
if (previousStage !== RUNNING_STAGE && !newlyLaunched) return;
|
|
13
|
+
if (record.stage === COMPLETED_STAGE) requester.narrate(`Workflow succeeded: ${record.displayName}.`);
|
|
14
|
+
if (record.stage === ERROR_STAGE) requester.narrate(`Workflow failed: ${record.displayName}.`);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { narrateWorkflowTransition };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/services/workflowNarration/index.ts"],"sourcesContent":["import type { WorkflowRunRecord, WorkflowStage } from '@agimon-ai/workflow-mcp';\n\n/** Package-local narration sink; the Pi adapter binds it to the injected Cordis service. */\nexport interface WorkflowNarrationSink {\n narrate(text: string): void;\n}\n\nconst RUNNING_STAGE: WorkflowStage = 'running';\nconst COMPLETED_STAGE: WorkflowStage = 'completed';\nconst ERROR_STAGE: WorkflowStage = 'error';\n\ntype NarratedWorkflow = Pick<WorkflowRunRecord, 'displayName' | 'stage'>;\n\n/**\n * Translate an observed workflow lifecycle transition into generic speech.\n * Voice owns delivery and ignores requests while its minor mode is inactive.\n */\nexport function narrateWorkflowTransition(\n requester: WorkflowNarrationSink,\n record: NarratedWorkflow,\n previousStage: WorkflowStage | undefined,\n startedDuringSession: boolean,\n): void {\n const newlyLaunched = previousStage === undefined && startedDuringSession;\n if (newlyLaunched) requester.narrate(`Workflow launched: ${record.displayName}.`);\n\n if (previousStage !== RUNNING_STAGE && !newlyLaunched) return;\n if (record.stage === COMPLETED_STAGE) requester.narrate(`Workflow succeeded: ${record.displayName}.`);\n if (record.stage === ERROR_STAGE) requester.narrate(`Workflow failed: ${record.displayName}.`);\n}\n"],"mappings":";AAOA,MAAM,gBAA+B;AACrC,MAAM,kBAAiC;AACvC,MAAM,cAA6B;;;;;AAQnC,SAAgB,0BACd,WACA,QACA,eACA,sBACM;CACN,MAAM,gBAAgB,kBAAkB,KAAA,KAAa;CACrD,IAAI,eAAe,UAAU,QAAQ,sBAAsB,OAAO,YAAY,EAAE;CAEhF,IAAI,kBAAkB,iBAAiB,CAAC,eAAe;CACvD,IAAI,OAAO,UAAU,iBAAiB,UAAU,QAAQ,uBAAuB,OAAO,YAAY,EAAE;CACpG,IAAI,OAAO,UAAU,aAAa,UAAU,QAAQ,oBAAoB,OAAO,YAAY,EAAE;AAC/F"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const require_runtime = require("../../../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
let node_fs = require("node:fs");
|
|
3
|
+
let node_fs_promises = require("node:fs/promises");
|
|
4
|
+
let node_path = require("node:path");
|
|
5
|
+
node_path = require_runtime.__toESM(node_path, 1);
|
|
6
|
+
let node_url = require("node:url");
|
|
7
|
+
//#region src/services/workflowResource/index.ts
|
|
8
|
+
function packageRoot() {
|
|
9
|
+
let directory = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
10
|
+
while (!(0, node_fs.existsSync)(node_path.default.join(directory, "package.json"))) {
|
|
11
|
+
const parent = node_path.default.dirname(directory);
|
|
12
|
+
if (parent === directory) throw new Error("Workflow package resources are unavailable.");
|
|
13
|
+
directory = parent;
|
|
14
|
+
}
|
|
15
|
+
return directory;
|
|
16
|
+
}
|
|
17
|
+
function workflowSkillDirectory() {
|
|
18
|
+
return node_path.default.join(packageRoot(), "skills");
|
|
19
|
+
}
|
|
20
|
+
async function readWorkflowSkill(name) {
|
|
21
|
+
return (0, node_fs_promises.readFile)(node_path.default.join(packageRoot(), name === "workflow-recovery" ? "skills" : "src/prompts", name, "SKILL.md"), "utf8");
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
exports.readWorkflowSkill = readWorkflowSkill;
|
|
25
|
+
exports.workflowSkillDirectory = workflowSkillDirectory;
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["path","fileURLToPath","existsSync","readFile"],"sources":["../../../../src/services/workflowResource/index.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nfunction packageRoot(): string {\n let directory = path.dirname(fileURLToPath(import.meta.url));\n while (!existsSync(path.join(directory, 'package.json'))) {\n const parent = path.dirname(directory);\n if (parent === directory) throw new Error('Workflow package resources are unavailable.');\n directory = parent;\n }\n return directory;\n}\nexport function workflowSkillDirectory(): string {\n return path.join(packageRoot(), 'skills');\n}\nexport async function readWorkflowSkill(name: string): Promise<string> {\n return readFile(\n path.join(packageRoot(), name === 'workflow-recovery' ? 'skills' : 'src/prompts', name, 'SKILL.md'),\n 'utf8',\n );\n}\n"],"mappings":";;;;;;;AAIA,SAAS,cAAsB;CAC7B,IAAI,YAAYA,UAAAA,QAAK,SAAA,GAAQC,SAAAA,cAAAA,CAAAA,QAAAA,KAAAA,CAAAA,CAAAA,cAAAA,UAAAA,CAAAA,CAAAA,IAA6B,CAAC;CAC3D,OAAO,EAAA,GAACC,QAAAA,WAAAA,CAAWF,UAAAA,QAAK,KAAK,WAAW,cAAc,CAAC,GAAG;EACxD,MAAM,SAASA,UAAAA,QAAK,QAAQ,SAAS;EACrC,IAAI,WAAW,WAAW,MAAM,IAAI,MAAM,6CAA6C;EACvF,YAAY;CACd;CACA,OAAO;AACT;AACA,SAAgB,yBAAiC;CAC/C,OAAOA,UAAAA,QAAK,KAAK,YAAY,GAAG,QAAQ;AAC1C;AACA,eAAsB,kBAAkB,MAA+B;CACrE,QAAA,GAAOG,iBAAAA,SAAAA,CACLH,UAAAA,QAAK,KAAK,YAAY,GAAG,SAAS,sBAAsB,WAAW,eAAe,MAAM,UAAU,GAClG,MACF;AACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
//#region src/services/workflowResource/index.ts
|
|
6
|
+
function packageRoot() {
|
|
7
|
+
let directory = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
while (!existsSync(path.join(directory, "package.json"))) {
|
|
9
|
+
const parent = path.dirname(directory);
|
|
10
|
+
if (parent === directory) throw new Error("Workflow package resources are unavailable.");
|
|
11
|
+
directory = parent;
|
|
12
|
+
}
|
|
13
|
+
return directory;
|
|
14
|
+
}
|
|
15
|
+
function workflowSkillDirectory() {
|
|
16
|
+
return path.join(packageRoot(), "skills");
|
|
17
|
+
}
|
|
18
|
+
async function readWorkflowSkill(name) {
|
|
19
|
+
return readFile(path.join(packageRoot(), name === "workflow-recovery" ? "skills" : "src/prompts", name, "SKILL.md"), "utf8");
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { readWorkflowSkill, workflowSkillDirectory };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/services/workflowResource/index.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nfunction packageRoot(): string {\n let directory = path.dirname(fileURLToPath(import.meta.url));\n while (!existsSync(path.join(directory, 'package.json'))) {\n const parent = path.dirname(directory);\n if (parent === directory) throw new Error('Workflow package resources are unavailable.');\n directory = parent;\n }\n return directory;\n}\nexport function workflowSkillDirectory(): string {\n return path.join(packageRoot(), 'skills');\n}\nexport async function readWorkflowSkill(name: string): Promise<string> {\n return readFile(\n path.join(packageRoot(), name === 'workflow-recovery' ? 'skills' : 'src/prompts', name, 'SKILL.md'),\n 'utf8',\n );\n}\n"],"mappings":";;;;;AAIA,SAAS,cAAsB;CAC7B,IAAI,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;CAC3D,OAAO,CAAC,WAAW,KAAK,KAAK,WAAW,cAAc,CAAC,GAAG;EACxD,MAAM,SAAS,KAAK,QAAQ,SAAS;EACrC,IAAI,WAAW,WAAW,MAAM,IAAI,MAAM,6CAA6C;EACvF,YAAY;CACd;CACA,OAAO;AACT;AACA,SAAgB,yBAAiC;CAC/C,OAAO,KAAK,KAAK,YAAY,GAAG,QAAQ;AAC1C;AACA,eAAsB,kBAAkB,MAA+B;CACrE,OAAO,SACL,KAAK,KAAK,YAAY,GAAG,SAAS,sBAAsB,WAAW,eAAe,MAAM,UAAU,GAClG,MACF;AACF"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
let node_path = require("node:path");
|
|
2
|
+
//#region src/services/workflowRuns/index.ts
|
|
3
|
+
/**
|
|
4
|
+
* MIRRORS @agimon-ai/workflow-mcp's on-disk registry
|
|
5
|
+
* (src/services/WorkflowRegistryService.ts and WorkflowProgressService.ts in
|
|
6
|
+
* that package). The engine keeps one directory per run under
|
|
7
|
+
* `<home>/workspaces/<workspace>/<stage>/<runKey>/` holding a `run.json`
|
|
8
|
+
* record and an append-only `progress.ndjson` job/step log; the hub only ever
|
|
9
|
+
* reads them. The derivation is duplicated rather than imported because
|
|
10
|
+
* doompi-web must not depend on the engine at runtime; the unit suite pins
|
|
11
|
+
* this mirror against the package's published types.
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_WORKFLOW_HOME_DIR_NAME = ".workflow-mcp";
|
|
14
|
+
const WORKFLOW_HOME_ENV = "WORKFLOW_MCP_HOME";
|
|
15
|
+
const WORKSPACES_DIR_NAME = "workspaces";
|
|
16
|
+
const RUN_RECORD_FILE_NAME = "run.json";
|
|
17
|
+
const PROGRESS_FILE_NAME = "progress.ndjson";
|
|
18
|
+
const WORKFLOW_STAGES = [
|
|
19
|
+
"running",
|
|
20
|
+
"completed",
|
|
21
|
+
"error"
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* Errored runs stay a day, which is how long recovery has to act on them.
|
|
25
|
+
*
|
|
26
|
+
* Finished runs have no retention of their own: a session keeps every run it
|
|
27
|
+
* launched, grouped by outcome, for as long as the session lives. A run leaves
|
|
28
|
+
* the view when the engine prunes its registry directory, not on a timer here,
|
|
29
|
+
* because "what did this session run today" is a question asked long after the
|
|
30
|
+
* run settled.
|
|
31
|
+
*/
|
|
32
|
+
const WORKFLOW_ERROR_RETENTION_MS = 864e5;
|
|
33
|
+
/** The env key doompi-workflow stamps on runs it launches; ties a run to a Pi session. */
|
|
34
|
+
const PI_SESSION_ENV = "PI_SESSION_ID";
|
|
35
|
+
const PROGRESS_STATES = /* @__PURE__ */ new Set([
|
|
36
|
+
"running",
|
|
37
|
+
"completed",
|
|
38
|
+
"skipped",
|
|
39
|
+
"failed",
|
|
40
|
+
"pause_requested",
|
|
41
|
+
"paused",
|
|
42
|
+
"resumed"
|
|
43
|
+
]);
|
|
44
|
+
const OUTCOMES = /* @__PURE__ */ new Set([
|
|
45
|
+
"success",
|
|
46
|
+
"skipped",
|
|
47
|
+
"failed",
|
|
48
|
+
"interrupted"
|
|
49
|
+
]);
|
|
50
|
+
const EXECUTION_STATES = /* @__PURE__ */ new Set([
|
|
51
|
+
"running",
|
|
52
|
+
"pause_requested",
|
|
53
|
+
"paused",
|
|
54
|
+
"resume_requested"
|
|
55
|
+
]);
|
|
56
|
+
const STEP_TERMINAL_STATES = /* @__PURE__ */ new Set([
|
|
57
|
+
"completed",
|
|
58
|
+
"skipped",
|
|
59
|
+
"failed"
|
|
60
|
+
]);
|
|
61
|
+
/** The engine records its pre:/post: blocks under these reserved pseudo-job names. */
|
|
62
|
+
const PHASE_JOB_PRE = "pre";
|
|
63
|
+
const PHASE_JOB_POST = "post";
|
|
64
|
+
const ANSI_ESCAPE_PATTERN = /\u001b\[[0-9;]*[A-Za-z]/g;
|
|
65
|
+
/** Where workflow-mcp keeps its registry, mirroring the engine's own resolution. */
|
|
66
|
+
function resolveWorkflowHome(input) {
|
|
67
|
+
return (0, node_path.resolve)(input.envValue !== void 0 && input.envValue !== "" ? input.envValue : (0, node_path.resolve)(input.homeDir, DEFAULT_WORKFLOW_HOME_DIR_NAME));
|
|
68
|
+
}
|
|
69
|
+
function isRecord(value) {
|
|
70
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
71
|
+
}
|
|
72
|
+
function asOptionalString(value) {
|
|
73
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
74
|
+
}
|
|
75
|
+
function asOptionalNumber(value) {
|
|
76
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
77
|
+
}
|
|
78
|
+
function stripAnsi(text) {
|
|
79
|
+
return text.replace(ANSI_ESCAPE_PATTERN, "").trim();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Validates one run.json into the wire shape plus scoping facts.
|
|
83
|
+
*
|
|
84
|
+
* Returns undefined for anything unreadable or a foreign format. The record
|
|
85
|
+
* is trusted for its own stage: the registry rewrites it when a run moves
|
|
86
|
+
* between stage directories.
|
|
87
|
+
*/
|
|
88
|
+
function parseWorkflowRunRecord(raw) {
|
|
89
|
+
let parsed;
|
|
90
|
+
try {
|
|
91
|
+
parsed = JSON.parse(raw);
|
|
92
|
+
} catch {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (!isRecord(parsed)) return void 0;
|
|
96
|
+
const runKey = asOptionalString(parsed.runKey);
|
|
97
|
+
const workspace = asOptionalString(parsed.workspace);
|
|
98
|
+
const workflowPath = asOptionalString(parsed.workflowPath);
|
|
99
|
+
const startedAt = asOptionalString(parsed.startedAt);
|
|
100
|
+
const stage = asOptionalString(parsed.stage);
|
|
101
|
+
if (!runKey || !workspace || !workflowPath || !startedAt) return void 0;
|
|
102
|
+
if (stage === void 0 || !WORKFLOW_STAGES.includes(stage)) return void 0;
|
|
103
|
+
const outcome = asOptionalString(parsed.outcome);
|
|
104
|
+
const executionState = asOptionalString(parsed.executionState);
|
|
105
|
+
const rawError = asOptionalString(parsed.errorMessage);
|
|
106
|
+
const env = isRecord(parsed.env) ? parsed.env : void 0;
|
|
107
|
+
const view = {
|
|
108
|
+
runKey,
|
|
109
|
+
workspace,
|
|
110
|
+
displayName: asOptionalString(parsed.displayName) ?? runKey,
|
|
111
|
+
...asOptionalString(parsed.workflowName) === void 0 ? {} : { workflowName: asOptionalString(parsed.workflowName) },
|
|
112
|
+
workflowPath,
|
|
113
|
+
stage,
|
|
114
|
+
...outcome !== void 0 && OUTCOMES.has(outcome) ? { outcome } : {},
|
|
115
|
+
...executionState !== void 0 && EXECUTION_STATES.has(executionState) ? { executionState } : {},
|
|
116
|
+
...asOptionalString(parsed.prompt) === void 0 ? {} : { prompt: asOptionalString(parsed.prompt) },
|
|
117
|
+
startedAt,
|
|
118
|
+
...asOptionalString(parsed.finishedAt) === void 0 ? {} : { finishedAt: asOptionalString(parsed.finishedAt) },
|
|
119
|
+
...rawError === void 0 ? {} : { errorMessage: stripAnsi(rawError) },
|
|
120
|
+
...asOptionalString(parsed.failedJob) === void 0 ? {} : { failedJob: asOptionalString(parsed.failedJob) },
|
|
121
|
+
...parsed.stale === true ? { stale: true } : {},
|
|
122
|
+
...asOptionalString(parsed.staleReason) === void 0 ? {} : { staleReason: asOptionalString(parsed.staleReason) },
|
|
123
|
+
...asOptionalString(parsed.worktreeBranch) === void 0 ? {} : { worktreeBranch: asOptionalString(parsed.worktreeBranch) },
|
|
124
|
+
jobs: []
|
|
125
|
+
};
|
|
126
|
+
const piSessionId = env === void 0 ? void 0 : asOptionalString(env[PI_SESSION_ENV]);
|
|
127
|
+
return {
|
|
128
|
+
view,
|
|
129
|
+
...piSessionId === void 0 ? {} : { piSessionId }
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Parses the append-only progress log. Malformed lines are skipped rather
|
|
134
|
+
* than failing the file: a reader routinely catches a torn final line
|
|
135
|
+
* mid-append.
|
|
136
|
+
*/
|
|
137
|
+
function parseWorkflowProgress(raw) {
|
|
138
|
+
const events = [];
|
|
139
|
+
for (const line of raw.split("\n")) {
|
|
140
|
+
const trimmed = line.trim();
|
|
141
|
+
if (trimmed === "") continue;
|
|
142
|
+
let parsed;
|
|
143
|
+
try {
|
|
144
|
+
parsed = JSON.parse(trimmed);
|
|
145
|
+
} catch {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (!isRecord(parsed)) continue;
|
|
149
|
+
const type = parsed.type;
|
|
150
|
+
const status = asOptionalString(parsed.status);
|
|
151
|
+
const job = asOptionalString(parsed.job);
|
|
152
|
+
const at = asOptionalString(parsed.at);
|
|
153
|
+
if (type !== "job" && type !== "step" || !job || !at) continue;
|
|
154
|
+
if (status === void 0 || !PROGRESS_STATES.has(status)) continue;
|
|
155
|
+
const step = asOptionalString(parsed.step);
|
|
156
|
+
const index = asOptionalNumber(parsed.index);
|
|
157
|
+
const total = asOptionalNumber(parsed.total);
|
|
158
|
+
const reason = asOptionalString(parsed.reason);
|
|
159
|
+
events.push({
|
|
160
|
+
type,
|
|
161
|
+
status,
|
|
162
|
+
job,
|
|
163
|
+
...step === void 0 ? {} : { step },
|
|
164
|
+
...index === void 0 ? {} : { index },
|
|
165
|
+
...total === void 0 ? {} : { total },
|
|
166
|
+
...reason === void 0 ? {} : { reason },
|
|
167
|
+
at
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return events;
|
|
171
|
+
}
|
|
172
|
+
function jobPhase(name) {
|
|
173
|
+
if (name === PHASE_JOB_PRE) return PHASE_JOB_PRE;
|
|
174
|
+
if (name === PHASE_JOB_POST) return PHASE_JOB_POST;
|
|
175
|
+
return "job";
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Folds the event log into the current job tree; later events win, so a job
|
|
179
|
+
* that started and later failed reads as failed. Jobs and steps keep the
|
|
180
|
+
* order of their first appearance.
|
|
181
|
+
*/
|
|
182
|
+
function foldWorkflowProgress(events) {
|
|
183
|
+
const jobs = [];
|
|
184
|
+
const jobByName = /* @__PURE__ */ new Map();
|
|
185
|
+
for (const event of events) {
|
|
186
|
+
let job = jobByName.get(event.job);
|
|
187
|
+
if (job === void 0) {
|
|
188
|
+
job = {
|
|
189
|
+
name: event.job,
|
|
190
|
+
phase: jobPhase(event.job),
|
|
191
|
+
status: event.status,
|
|
192
|
+
steps: []
|
|
193
|
+
};
|
|
194
|
+
jobByName.set(event.job, job);
|
|
195
|
+
jobs.push(job);
|
|
196
|
+
}
|
|
197
|
+
if (event.type === "job") {
|
|
198
|
+
job.status = event.status;
|
|
199
|
+
if (event.reason !== void 0) job.reason = event.reason;
|
|
200
|
+
if (event.index !== void 0) job.index = event.index;
|
|
201
|
+
if (event.total !== void 0) job.total = event.total;
|
|
202
|
+
if (event.status === "running" && job.startedAt === void 0) job.startedAt = event.at;
|
|
203
|
+
if (STEP_TERMINAL_STATES.has(event.status)) job.endedAt = event.at;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (event.step === void 0) continue;
|
|
207
|
+
let step = job.steps.find((candidate) => candidate.name === event.step);
|
|
208
|
+
if (step === void 0) {
|
|
209
|
+
step = {
|
|
210
|
+
name: event.step,
|
|
211
|
+
status: event.status
|
|
212
|
+
};
|
|
213
|
+
job.steps.push(step);
|
|
214
|
+
}
|
|
215
|
+
step.status = event.status;
|
|
216
|
+
if (event.reason !== void 0) step.reason = event.reason;
|
|
217
|
+
if (event.status === "running" && step.startedAt === void 0) step.startedAt = event.at;
|
|
218
|
+
if (STEP_TERMINAL_STATES.has(event.status)) step.endedAt = event.at;
|
|
219
|
+
}
|
|
220
|
+
return jobs;
|
|
221
|
+
}
|
|
222
|
+
const ACTIVE_PROGRESS_STATES = /* @__PURE__ */ new Set([
|
|
223
|
+
"running",
|
|
224
|
+
"pause_requested",
|
|
225
|
+
"paused",
|
|
226
|
+
"resumed"
|
|
227
|
+
]);
|
|
228
|
+
/** The job and step a run is on right now, for the NOW breadcrumb. */
|
|
229
|
+
function workflowPosition(jobs) {
|
|
230
|
+
for (let jobIndex = jobs.length - 1; jobIndex >= 0; jobIndex -= 1) {
|
|
231
|
+
const job = jobs[jobIndex];
|
|
232
|
+
if (!ACTIVE_PROGRESS_STATES.has(job.status)) continue;
|
|
233
|
+
for (let stepIndex = job.steps.length - 1; stepIndex >= 0; stepIndex -= 1) {
|
|
234
|
+
const step = job.steps[stepIndex];
|
|
235
|
+
if (ACTIVE_PROGRESS_STATES.has(step.status)) return {
|
|
236
|
+
job: job.name,
|
|
237
|
+
step: step.name,
|
|
238
|
+
...job.index === void 0 ? {} : { index: job.index },
|
|
239
|
+
...job.total === void 0 ? {} : { total: job.total }
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
job: job.name,
|
|
244
|
+
...job.index === void 0 ? {} : { index: job.index },
|
|
245
|
+
...job.total === void 0 ? {} : { total: job.total }
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/** The finished view: record fields plus the folded job tree and position. */
|
|
250
|
+
function completeWorkflowRunView(view, jobs) {
|
|
251
|
+
const position = view.stage === "running" ? workflowPosition(jobs) : void 0;
|
|
252
|
+
return {
|
|
253
|
+
...view,
|
|
254
|
+
jobs,
|
|
255
|
+
...position === void 0 ? {} : { position }
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Whether a run belongs on a session's workflow tab: launched by that Pi
|
|
260
|
+
* session, which is the same env test doompi-workflow's isSessionRun applies.
|
|
261
|
+
*
|
|
262
|
+
* The registry is one directory under $HOME shared by every repository and
|
|
263
|
+
* every Pi session on the machine, so repository proximity is not ownership.
|
|
264
|
+
* Scoping on it as well let two sessions open in one repo read each other's
|
|
265
|
+
* history, and kept a dead session's runs on the board of every session that
|
|
266
|
+
* replaced it. Fails closed on an unstamped record, which is what a launch
|
|
267
|
+
* from the CLI rather than from a session leaves behind.
|
|
268
|
+
*/
|
|
269
|
+
function runBelongsToSession(run, sessionId) {
|
|
270
|
+
return run.piSessionId !== void 0 && run.piSessionId === sessionId;
|
|
271
|
+
}
|
|
272
|
+
function parseTime(value) {
|
|
273
|
+
if (value === void 0) return 0;
|
|
274
|
+
const time = Date.parse(value);
|
|
275
|
+
return Number.isFinite(time) ? time : 0;
|
|
276
|
+
}
|
|
277
|
+
const STAGE_ORDER = {
|
|
278
|
+
running: 0,
|
|
279
|
+
error: 1,
|
|
280
|
+
completed: 2
|
|
281
|
+
};
|
|
282
|
+
/**
|
|
283
|
+
* Whether a run still belongs in the view.
|
|
284
|
+
*
|
|
285
|
+
* Only errored runs age out here, and slowly: everything else a session
|
|
286
|
+
* started stays until the engine forgets the run itself.
|
|
287
|
+
*/
|
|
288
|
+
function withinRetention(run, now) {
|
|
289
|
+
if (run.stage !== "error") return true;
|
|
290
|
+
return now - (parseTime(run.finishedAt) || parseTime(run.startedAt)) < WORKFLOW_ERROR_RETENTION_MS;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* When a run last moved, which is what orders it within its group.
|
|
294
|
+
*
|
|
295
|
+
* A running run has only its start; a settled one is ordered by when it
|
|
296
|
+
* settled, because a list kept for the whole session is read as a history and
|
|
297
|
+
* two runs started together can finish an hour apart.
|
|
298
|
+
*/
|
|
299
|
+
function lastMovedAt(run) {
|
|
300
|
+
return run.stage === "running" ? parseTime(run.startedAt) : parseTime(run.finishedAt) || parseTime(run.startedAt);
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Running runs first, then errored (recovery acts on them), then finished;
|
|
304
|
+
* newest first within a group, and each group capped on its own.
|
|
305
|
+
*/
|
|
306
|
+
function presentWorkflowRuns(runs, now) {
|
|
307
|
+
const groups = /* @__PURE__ */ new Map();
|
|
308
|
+
for (const run of runs) {
|
|
309
|
+
if (!withinRetention(run, now)) continue;
|
|
310
|
+
const group = groups.get(run.stage);
|
|
311
|
+
if (group) group.push(run);
|
|
312
|
+
else groups.set(run.stage, [run]);
|
|
313
|
+
}
|
|
314
|
+
return [...groups.entries()].sort(([left], [right]) => STAGE_ORDER[left] - STAGE_ORDER[right]).flatMap(([, group]) => group.sort((left, right) => lastMovedAt(right) - lastMovedAt(left)).slice(0, 24));
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
exports.PI_SESSION_ENV = PI_SESSION_ENV;
|
|
318
|
+
exports.PROGRESS_FILE_NAME = PROGRESS_FILE_NAME;
|
|
319
|
+
exports.RUN_RECORD_FILE_NAME = RUN_RECORD_FILE_NAME;
|
|
320
|
+
exports.WORKFLOW_ERROR_RETENTION_MS = WORKFLOW_ERROR_RETENTION_MS;
|
|
321
|
+
exports.WORKFLOW_HOME_ENV = WORKFLOW_HOME_ENV;
|
|
322
|
+
exports.WORKFLOW_STAGES = WORKFLOW_STAGES;
|
|
323
|
+
exports.WORKSPACES_DIR_NAME = WORKSPACES_DIR_NAME;
|
|
324
|
+
exports.completeWorkflowRunView = completeWorkflowRunView;
|
|
325
|
+
exports.foldWorkflowProgress = foldWorkflowProgress;
|
|
326
|
+
exports.parseWorkflowProgress = parseWorkflowProgress;
|
|
327
|
+
exports.parseWorkflowRunRecord = parseWorkflowRunRecord;
|
|
328
|
+
exports.presentWorkflowRuns = presentWorkflowRuns;
|
|
329
|
+
exports.resolveWorkflowHome = resolveWorkflowHome;
|
|
330
|
+
exports.runBelongsToSession = runBelongsToSession;
|
|
331
|
+
exports.workflowPosition = workflowPosition;
|
|
332
|
+
|
|
333
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["resolve"],"sources":["../../../../src/services/workflowRuns/index.ts"],"sourcesContent":["import { resolve } from 'node:path';\n\nimport type {\n WorkflowJobPhase,\n WorkflowJobView,\n WorkflowOutcome,\n WorkflowPosition,\n WorkflowProgressState,\n WorkflowRunView,\n WorkflowStage,\n WorkflowStepView,\n} from '../../types/webWorkflows';\n\n/**\n * MIRRORS @agimon-ai/workflow-mcp's on-disk registry\n * (src/services/WorkflowRegistryService.ts and WorkflowProgressService.ts in\n * that package). The engine keeps one directory per run under\n * `<home>/workspaces/<workspace>/<stage>/<runKey>/` holding a `run.json`\n * record and an append-only `progress.ndjson` job/step log; the hub only ever\n * reads them. The derivation is duplicated rather than imported because\n * doompi-web must not depend on the engine at runtime; the unit suite pins\n * this mirror against the package's published types.\n */\nconst DEFAULT_WORKFLOW_HOME_DIR_NAME = '.workflow-mcp';\nexport const WORKFLOW_HOME_ENV = 'WORKFLOW_MCP_HOME';\nexport const WORKSPACES_DIR_NAME = 'workspaces';\nexport const RUN_RECORD_FILE_NAME = 'run.json';\nexport const PROGRESS_FILE_NAME = 'progress.ndjson';\nexport const WORKFLOW_STAGES: readonly WorkflowStage[] = ['running', 'completed', 'error'];\n\n/**\n * Errored runs stay a day, which is how long recovery has to act on them.\n *\n * Finished runs have no retention of their own: a session keeps every run it\n * launched, grouped by outcome, for as long as the session lives. A run leaves\n * the view when the engine prunes its registry directory, not on a timer here,\n * because \"what did this session run today\" is a question asked long after the\n * run settled.\n */\nexport const WORKFLOW_ERROR_RETENTION_MS = 24 * 60 * 60 * 1000;\n/**\n * Upper bound per outcome group rather than over the whole list.\n *\n * One cap across every run let a long stream of green runs push a failure out\n * of the list, which is the one thing that must never fall off the end.\n */\nexport const MAX_PRESENTED_WORKFLOW_RUNS_PER_GROUP = 24;\n\n/** The env key doompi-workflow stamps on runs it launches; ties a run to a Pi session. */\nexport const PI_SESSION_ENV = 'PI_SESSION_ID';\n\nconst PROGRESS_STATES: ReadonlySet<string> = new Set([\n 'running',\n 'completed',\n 'skipped',\n 'failed',\n 'pause_requested',\n 'paused',\n 'resumed',\n]);\nconst OUTCOMES: ReadonlySet<string> = new Set(['success', 'skipped', 'failed', 'interrupted']);\nconst EXECUTION_STATES: ReadonlySet<string> = new Set(['running', 'pause_requested', 'paused', 'resume_requested']);\nconst STEP_TERMINAL_STATES: ReadonlySet<WorkflowProgressState> = new Set(['completed', 'skipped', 'failed']);\n/** The engine records its pre:/post: blocks under these reserved pseudo-job names. */\nconst PHASE_JOB_PRE = 'pre';\nconst PHASE_JOB_POST = 'post';\n\n// oxlint-disable-next-line no-control-regex -- stripping terminal color codes from errorMessage is the point\nconst ANSI_ESCAPE_PATTERN = /\\u001b\\[[0-9;]*[A-Za-z]/g;\n\nexport interface WorkflowHomeInput {\n /** process.env.WORKFLOW_MCP_HOME, supplied by the caller. */\n envValue: string | undefined;\n /** os.homedir(), supplied by the caller. */\n homeDir: string;\n}\n\n/** Where workflow-mcp keeps its registry, mirroring the engine's own resolution. */\nexport function resolveWorkflowHome(input: WorkflowHomeInput): string {\n return resolve(\n input.envValue !== undefined && input.envValue !== ''\n ? input.envValue\n : resolve(input.homeDir, DEFAULT_WORKFLOW_HOME_DIR_NAME),\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction asOptionalString(value: unknown): string | undefined {\n return typeof value === 'string' && value !== '' ? value : undefined;\n}\n\nfunction asOptionalNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction stripAnsi(text: string): string {\n return text.replace(ANSI_ESCAPE_PATTERN, '').trim();\n}\n\n/**\n * One run record plus the facts the hub needs for session scoping but the\n * page never sees.\n */\nexport interface ParsedWorkflowRun {\n /** The wire view, before the progress log is folded in (jobs empty). */\n view: WorkflowRunView;\n /** env.PI_SESSION_ID from the record, when the launcher stamped one. */\n piSessionId?: string;\n}\n\n/**\n * Validates one run.json into the wire shape plus scoping facts.\n *\n * Returns undefined for anything unreadable or a foreign format. The record\n * is trusted for its own stage: the registry rewrites it when a run moves\n * between stage directories.\n */\nexport function parseWorkflowRunRecord(raw: string): ParsedWorkflowRun | undefined {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!isRecord(parsed)) return undefined;\n const runKey = asOptionalString(parsed.runKey);\n const workspace = asOptionalString(parsed.workspace);\n const workflowPath = asOptionalString(parsed.workflowPath);\n const startedAt = asOptionalString(parsed.startedAt);\n const stage = asOptionalString(parsed.stage);\n if (!runKey || !workspace || !workflowPath || !startedAt) return undefined;\n if (stage === undefined || !WORKFLOW_STAGES.includes(stage as WorkflowStage)) return undefined;\n\n const outcome = asOptionalString(parsed.outcome);\n const executionState = asOptionalString(parsed.executionState);\n const rawError = asOptionalString(parsed.errorMessage);\n const env = isRecord(parsed.env) ? parsed.env : undefined;\n const view: WorkflowRunView = {\n runKey,\n workspace,\n displayName: asOptionalString(parsed.displayName) ?? runKey,\n ...(asOptionalString(parsed.workflowName) === undefined\n ? {}\n : { workflowName: asOptionalString(parsed.workflowName) }),\n workflowPath,\n stage: stage as WorkflowStage,\n ...(outcome !== undefined && OUTCOMES.has(outcome) ? { outcome: outcome as WorkflowOutcome } : {}),\n ...(executionState !== undefined && EXECUTION_STATES.has(executionState)\n ? { executionState: executionState as WorkflowRunView['executionState'] }\n : {}),\n ...(asOptionalString(parsed.prompt) === undefined ? {} : { prompt: asOptionalString(parsed.prompt) }),\n startedAt,\n ...(asOptionalString(parsed.finishedAt) === undefined ? {} : { finishedAt: asOptionalString(parsed.finishedAt) }),\n ...(rawError === undefined ? {} : { errorMessage: stripAnsi(rawError) }),\n ...(asOptionalString(parsed.failedJob) === undefined ? {} : { failedJob: asOptionalString(parsed.failedJob) }),\n ...(parsed.stale === true ? { stale: true } : {}),\n ...(asOptionalString(parsed.staleReason) === undefined\n ? {}\n : { staleReason: asOptionalString(parsed.staleReason) }),\n ...(asOptionalString(parsed.worktreeBranch) === undefined\n ? {}\n : { worktreeBranch: asOptionalString(parsed.worktreeBranch) }),\n jobs: [],\n };\n const piSessionId = env === undefined ? undefined : asOptionalString(env[PI_SESSION_ENV]);\n return { view, ...(piSessionId === undefined ? {} : { piSessionId }) };\n}\n\ninterface WorkflowProgressEvent {\n type: 'job' | 'step';\n status: WorkflowProgressState;\n job: string;\n step?: string;\n index?: number;\n total?: number;\n reason?: string;\n at: string;\n}\n\n/**\n * Parses the append-only progress log. Malformed lines are skipped rather\n * than failing the file: a reader routinely catches a torn final line\n * mid-append.\n */\nexport function parseWorkflowProgress(raw: string): WorkflowProgressEvent[] {\n const events: WorkflowProgressEvent[] = [];\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed === '') continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n continue;\n }\n if (!isRecord(parsed)) continue;\n const type = parsed.type;\n const status = asOptionalString(parsed.status);\n const job = asOptionalString(parsed.job);\n const at = asOptionalString(parsed.at);\n if ((type !== 'job' && type !== 'step') || !job || !at) continue;\n if (status === undefined || !PROGRESS_STATES.has(status)) continue;\n const step = asOptionalString(parsed.step);\n const index = asOptionalNumber(parsed.index);\n const total = asOptionalNumber(parsed.total);\n const reason = asOptionalString(parsed.reason);\n events.push({\n type,\n status: status as WorkflowProgressState,\n job,\n ...(step === undefined ? {} : { step }),\n ...(index === undefined ? {} : { index }),\n ...(total === undefined ? {} : { total }),\n ...(reason === undefined ? {} : { reason }),\n at,\n });\n }\n return events;\n}\n\nfunction jobPhase(name: string): WorkflowJobPhase {\n if (name === PHASE_JOB_PRE) return PHASE_JOB_PRE;\n if (name === PHASE_JOB_POST) return PHASE_JOB_POST;\n return 'job';\n}\n\n/**\n * Folds the event log into the current job tree; later events win, so a job\n * that started and later failed reads as failed. Jobs and steps keep the\n * order of their first appearance.\n */\nexport function foldWorkflowProgress(events: readonly WorkflowProgressEvent[]): WorkflowJobView[] {\n const jobs: WorkflowJobView[] = [];\n const jobByName = new Map<string, WorkflowJobView>();\n for (const event of events) {\n let job = jobByName.get(event.job);\n if (job === undefined) {\n job = { name: event.job, phase: jobPhase(event.job), status: event.status, steps: [] };\n jobByName.set(event.job, job);\n jobs.push(job);\n }\n if (event.type === 'job') {\n job.status = event.status;\n if (event.reason !== undefined) job.reason = event.reason;\n if (event.index !== undefined) job.index = event.index;\n if (event.total !== undefined) job.total = event.total;\n if (event.status === 'running' && job.startedAt === undefined) job.startedAt = event.at;\n if (STEP_TERMINAL_STATES.has(event.status)) job.endedAt = event.at;\n continue;\n }\n if (event.step === undefined) continue;\n let step: WorkflowStepView | undefined = job.steps.find((candidate) => candidate.name === event.step);\n if (step === undefined) {\n step = { name: event.step, status: event.status };\n job.steps.push(step);\n }\n step.status = event.status;\n if (event.reason !== undefined) step.reason = event.reason;\n if (event.status === 'running' && step.startedAt === undefined) step.startedAt = event.at;\n if (STEP_TERMINAL_STATES.has(event.status)) step.endedAt = event.at;\n }\n return jobs;\n}\n\nconst ACTIVE_PROGRESS_STATES: ReadonlySet<WorkflowProgressState> = new Set([\n 'running',\n 'pause_requested',\n 'paused',\n 'resumed',\n]);\n\n/** The job and step a run is on right now, for the NOW breadcrumb. */\nexport function workflowPosition(jobs: readonly WorkflowJobView[]): WorkflowPosition | undefined {\n for (let jobIndex = jobs.length - 1; jobIndex >= 0; jobIndex -= 1) {\n const job = jobs[jobIndex]!;\n if (!ACTIVE_PROGRESS_STATES.has(job.status)) continue;\n for (let stepIndex = job.steps.length - 1; stepIndex >= 0; stepIndex -= 1) {\n const step = job.steps[stepIndex]!;\n if (ACTIVE_PROGRESS_STATES.has(step.status)) {\n return {\n job: job.name,\n step: step.name,\n ...(job.index === undefined ? {} : { index: job.index }),\n ...(job.total === undefined ? {} : { total: job.total }),\n };\n }\n }\n return {\n job: job.name,\n ...(job.index === undefined ? {} : { index: job.index }),\n ...(job.total === undefined ? {} : { total: job.total }),\n };\n }\n return undefined;\n}\n\n/** The finished view: record fields plus the folded job tree and position. */\nexport function completeWorkflowRunView(view: WorkflowRunView, jobs: WorkflowJobView[]): WorkflowRunView {\n const position = view.stage === 'running' ? workflowPosition(jobs) : undefined;\n return { ...view, jobs, ...(position === undefined ? {} : { position }) };\n}\n\n/**\n * Whether a run belongs on a session's workflow tab: launched by that Pi\n * session, which is the same env test doompi-workflow's isSessionRun applies.\n *\n * The registry is one directory under $HOME shared by every repository and\n * every Pi session on the machine, so repository proximity is not ownership.\n * Scoping on it as well let two sessions open in one repo read each other's\n * history, and kept a dead session's runs on the board of every session that\n * replaced it. Fails closed on an unstamped record, which is what a launch\n * from the CLI rather than from a session leaves behind.\n */\nexport function runBelongsToSession(run: ParsedWorkflowRun, sessionId: string): boolean {\n return run.piSessionId !== undefined && run.piSessionId === sessionId;\n}\n\nfunction parseTime(value: string | undefined): number {\n if (value === undefined) return 0;\n const time = Date.parse(value);\n return Number.isFinite(time) ? time : 0;\n}\n\nconst STAGE_ORDER: Readonly<Record<WorkflowStage, number>> = { running: 0, error: 1, completed: 2 };\n\n/**\n * Whether a run still belongs in the view.\n *\n * Only errored runs age out here, and slowly: everything else a session\n * started stays until the engine forgets the run itself.\n */\nfunction withinRetention(run: WorkflowRunView, now: number): boolean {\n if (run.stage !== 'error') return true;\n const settledAt = parseTime(run.finishedAt) || parseTime(run.startedAt);\n return now - settledAt < WORKFLOW_ERROR_RETENTION_MS;\n}\n\n/**\n * When a run last moved, which is what orders it within its group.\n *\n * A running run has only its start; a settled one is ordered by when it\n * settled, because a list kept for the whole session is read as a history and\n * two runs started together can finish an hour apart.\n */\nfunction lastMovedAt(run: WorkflowRunView): number {\n return run.stage === 'running' ? parseTime(run.startedAt) : parseTime(run.finishedAt) || parseTime(run.startedAt);\n}\n\n/**\n * Running runs first, then errored (recovery acts on them), then finished;\n * newest first within a group, and each group capped on its own.\n */\nexport function presentWorkflowRuns(runs: readonly WorkflowRunView[], now: number): WorkflowRunView[] {\n const groups = new Map<WorkflowStage, WorkflowRunView[]>();\n for (const run of runs) {\n if (!withinRetention(run, now)) continue;\n const group = groups.get(run.stage);\n if (group) group.push(run);\n else groups.set(run.stage, [run]);\n }\n return [...groups.entries()]\n .sort(([left], [right]) => STAGE_ORDER[left] - STAGE_ORDER[right])\n .flatMap(([, group]) =>\n group\n .sort((left, right) => lastMovedAt(right) - lastMovedAt(left))\n .slice(0, MAX_PRESENTED_WORKFLOW_RUNS_PER_GROUP),\n );\n}\n"],"mappings":"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"}
|