@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/workflowExecution/index.ts"],"sourcesContent":["import { resolveRootSessionId } from '@agimon-ai/doompi-core/child-process';\nimport type { DoomToolRestriction } from '@agimon-ai/doompi-core/tool-surface';\nimport { type EmbeddedWorkflowFeature, type WorkflowRunRecord } from '@agimon-ai/workflow-mcp';\nimport type { AgentToolResult, AgentToolUpdateCallback, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { z } from 'zod';\n\nimport { type WorkflowRunInput } from '../../schemas/workflowPi';\nimport {\n launchedRunSummary,\n launchHandoffSummary,\n PI_SESSION_ENV,\n resolveMaxConcurrent,\n toolResultText,\n withOptions,\n} from '../piToolBridge';\n\nconst AGIFLOW_JOB_ID_ENV = 'AGIFLOW_JOB_ID';\nconst AGIFLOW_JOB_KIND_ENV = 'AGIFLOW_JOB_KIND';\nconst AGIFLOW_PROJECT_ID_ENV = 'AGIFLOW_PROJECT_ID';\n\nimport { WORKFLOW_PI_TOOL_NAMES, LAUNCH_WORKFLOW_TOOL_NAME } from '../../constants/workflow';\n\n/**\n * What workflow mode does to the tool surface: nothing but hide its own tools.\n *\n * The tools are registered for the whole session because Pi has no other way to\n * add one later, so the mode is expressed as a restriction rather than as a\n * registration.\n */\nexport function workflowToolRestriction(enabled: boolean): DoomToolRestriction {\n const hidden = new Set<string>(WORKFLOW_PI_TOOL_NAMES);\n return (incoming) => (enabled ? incoming : incoming.filter((name) => !hidden.has(name)));\n}\n\nexport type WorkflowRunSelector = Pick<WorkflowRunInput, 'runKey' | 'workspace'>;\n\nexport type WorkflowLaunchInput = z.infer<ReturnType<EmbeddedWorkflowFeature['runTool']['getInputSchema']>>;\n\n/**\n * Where a launch was answered from, which decides what the caller is told.\n *\n * Tagged rather than inferred from an absent field: the failure carries an\n * `unknown`, and `unknown` includes `undefined`, so only a tag can tell a\n * rejection apart from a result.\n */\ntype LaunchOutcome = { kind: 'value'; result: CallToolResult } | { kind: 'error'; error: unknown };\ntype LaunchAck =\n | { kind: 'settled'; outcome: LaunchOutcome }\n | { kind: 'record'; record: WorkflowRunRecord }\n | { kind: 'handoff' };\n\n/** How often the registry is asked whether the launch has produced a run. */\nconst LAUNCH_ACK_POLL_MS = 500;\n/**\n * How long to wait for that before answering without a run key.\n *\n * Long enough to cover a launcher that is merely slow, short enough that a\n * caller is never left holding a turn open for a launcher that will not answer.\n */\nconst LAUNCH_ACK_TIMEOUT_MS = 15_000;\n\nexport interface LaunchedRunQuery {\n sessionId: string | undefined;\n /** Epoch milliseconds the launch began, so an earlier run cannot match. */\n since: number;\n workflowPath: string;\n}\n\nexport interface WorkflowLaunchExecutorDependencies {\n readonly environment: Readonly<Record<string, string | undefined>>;\n activeRunCount?: () => Promise<number>;\n onLaunch?: (ctx: ExtensionContext) => Promise<void> | void;\n observeSession?: (sessionId: string | undefined) => void;\n rejectRunner?: (workflowPath: string, runner: string) => string | undefined;\n runTool: EmbeddedWorkflowFeature['runTool'];\n trackPendingRun: <T>(run: Promise<T>) => Promise<T>;\n /**\n * The run this launch registered, or undefined while none has appeared.\n *\n * Its presence is what lets a launch answer on the registry instead of on the\n * launcher process exiting. Left out, the launch waits for the process, which\n * is the behaviour every caller had before.\n */\n findLaunchedRun?: (query: LaunchedRunQuery) => Promise<WorkflowRunRecord | undefined>;\n /** Report a launch that fails after this call already answered \"started\". */\n onLateFailure?: (error: unknown, ctx: ExtensionContext) => void;\n launchAckPollMs?: number;\n launchAckTimeoutMs?: number;\n}\n\nexport interface WorkflowLaunchExecutor {\n execute(\n input: WorkflowLaunchInput,\n ctx: ExtensionContext,\n onUpdate?: AgentToolUpdateCallback<{ tool: string }>,\n ): Promise<CallToolResult>;\n}\n\nexport interface WorkflowPiToolDependencies {\n readonly environment: Readonly<Record<string, string | undefined>>;\n launchExecutor?: WorkflowLaunchExecutor;\n onLaunch?: (ctx: ExtensionContext) => Promise<void> | void;\n activeRunCount?: () => Promise<number>;\n followRun?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n tailRun?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n openRun?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n rejectRunner?: (workflowPath: string, runner: string) => string | undefined;\n requireSessionRun?: (input: WorkflowRunSelector, sessionId: string | undefined) => Promise<WorkflowRunRecord>;\n /**\n * Resolve a failed recovery target globally.\n *\n * Recovery is the one ownership-transferring action: a replacement Pi\n * session must be able to adopt a terminal run whose launching session is\n * gone. Every non-recovery action remains session-scoped.\n */\n requireRecoverableRun?: (input: WorkflowRunSelector) => Promise<WorkflowRunRecord>;\n readRecoveryEvidence?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n /**\n * Hand a recovery to a terminal launcher, returning what to tell the caller.\n *\n * Undefined means this recovery cannot be delegated, and the in-process\n * replay below is used instead.\n */\n delegateRecovery?: (\n input: { runKey: string; workspace?: string; runner?: string },\n ctx: ExtensionContext,\n ) => Promise<string | undefined>;\n observeSession?: (sessionId: string | undefined) => void;\n trackPendingRun?: <T>(run: Promise<T>) => Promise<T>;\n feature?: EmbeddedWorkflowFeature;\n recoverTool?: {\n execute(input: {\n dryRun?: boolean;\n job?: string;\n runKey: string;\n runner?: string;\n workspace?: string;\n }): Promise<CallToolResult>;\n };\n controlTool?: ReturnType<EmbeddedWorkflowFeature['createControlTool']>;\n runTool?: EmbeddedWorkflowFeature['runTool'];\n listWorkflowsTool?: EmbeddedWorkflowFeature['listWorkflowsTool'];\n}\n\nexport function reportProgress(\n onUpdate: AgentToolUpdateCallback<{ tool: string }> | undefined,\n tool: string,\n message: string,\n): void {\n onUpdate?.({ content: [{ type: 'text', text: message }], details: { tool } });\n}\n\nexport function appendGuidance(\n result: AgentToolResult<{ tool: string }>,\n guidance: string,\n): AgentToolResult<{ tool: string }> {\n return { ...result, content: [...result.content, { type: 'text', text: guidance }] };\n}\n\nfunction statusAction(runKey: string): string {\n return `workflow_run {\"action\":\"status\",\"runKey\":${JSON.stringify(runKey)}}`;\n}\n\nexport function actionGuidance(action: WorkflowRunInput['action'], runKey: string): string[] {\n const status = statusAction(runKey);\n if (action === 'stop') return [`Next: call ${status} to confirm the run reached a terminal stage.`];\n if (action === 'recover') {\n return [\n `Report the recovery failure and do not retry it blindly: call ${status} first.`,\n 'Ask the user before launching fresh work when the recorded recovery is no longer valid.',\n ];\n }\n return [`Next: call ${status} to verify the recorded execution state.`];\n}\n\nexport const launchFailureOptions = [\n 'Report the failure to the user with the error above. A launch failure is usually a bad workflow path, a missing launcher, or a workflow whose own pre-conditions refused.',\n 'list_workflows: confirm the workflow path exists and its description matches the work, if the path may be wrong.',\n 'workflow_run with action status: check whether an earlier attempt is already running before launching again.',\n];\n\n/**\n * An Error, whatever the launch rejected with.\n *\n * A rejection reaches here as `unknown` because it crossed a promise boundary,\n * and rethrowing that as-is hands Pi's tool layer something it cannot read a\n * message or a stack off. The original is kept as the cause rather than\n * flattened into a string.\n */\nfunction asError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value), { cause: value });\n}\n\n/** Resolves to undefined, so a race against it reads as \"nothing settled yet\". */\nfunction sleep(ms: number): Promise<undefined> {\n return new Promise((settle) => {\n const timer = setTimeout(() => settle(undefined), ms);\n timer.unref?.();\n });\n}\n\n/**\n * Wait for whichever answer arrives first: the launch settling, the run\n * appearing in the registry, or the budget running out.\n *\n * A launch that delegates to a terminal launcher settles when that launcher's\n * whole process chain closes, which on a loaded machine has been measured\n * minutes after the run itself was registered and working. The registry is the\n * earlier and more truthful signal: a run recorded there is a run that started.\n */\nasync function awaitLaunchAck(\n settled: Promise<LaunchOutcome>,\n dependencies: WorkflowLaunchExecutorDependencies,\n query: LaunchedRunQuery,\n): Promise<LaunchAck> {\n const findLaunchedRun = dependencies.findLaunchedRun;\n if (!findLaunchedRun) return { kind: 'settled', outcome: await settled };\n\n const pollMs = dependencies.launchAckPollMs ?? LAUNCH_ACK_POLL_MS;\n const deadline = Date.now() + (dependencies.launchAckTimeoutMs ?? LAUNCH_ACK_TIMEOUT_MS);\n for (;;) {\n const outcome = await Promise.race([settled, sleep(pollMs)]);\n if (outcome) return { kind: 'settled', outcome };\n // A registry read that throws must not fail the launch: the run may be\n // perfectly healthy, and the settled promise is still the fallback.\n const record = await findLaunchedRun(query).catch(() => undefined);\n if (record) return { kind: 'record', record };\n if (Date.now() >= deadline) return { kind: 'handoff' };\n }\n}\n\n/**\n * Carry a failure that lands after the caller was told the run started.\n *\n * Answering early trades the launcher's exit code for timeliness. Dropping that\n * code entirely is not part of the trade: a launch that fails a minute later\n * would otherwise leave a user waiting on a run that never existed.\n */\nfunction reportLateFailure(\n settled: Promise<LaunchOutcome>,\n dependencies: WorkflowLaunchExecutorDependencies,\n ctx: ExtensionContext,\n): void {\n void settled.then((outcome) => {\n if (outcome.kind === 'error') {\n dependencies.onLateFailure?.(asError(outcome.error), ctx);\n return;\n }\n if (outcome.result.isError) {\n dependencies.onLateFailure?.(new Error(toolResultText(outcome.result) || 'Workflow launch failed.'), ctx);\n }\n });\n}\n\nexport function createWorkflowLaunchExecutor(dependencies: WorkflowLaunchExecutorDependencies): WorkflowLaunchExecutor {\n return {\n async execute(input, ctx, onUpdate) {\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), dependencies.environment);\n dependencies.observeSession?.(sessionId);\n const agiflowJobKind = input.env?.[AGIFLOW_JOB_KIND_ENV]?.trim();\n const agiflowJobId = input.env?.[AGIFLOW_JOB_ID_ENV]?.trim();\n const explicitProjectId = input.env?.[AGIFLOW_PROJECT_ID_ENV]?.trim();\n if (Boolean(agiflowJobKind) !== Boolean(agiflowJobId)) {\n throw new Error('Agiflow workflow launches require AGIFLOW_JOB_KIND and AGIFLOW_JOB_ID together.');\n }\n if (agiflowJobKind && agiflowJobKind !== 'task' && agiflowJobKind !== 'work-unit') {\n throw new Error('Agiflow workflow launches require AGIFLOW_JOB_KIND to be task or work-unit.');\n }\n if (agiflowJobKind && !explicitProjectId) {\n throw new Error('Agiflow workflow launches require AGIFLOW_PROJECT_ID with the job identity.');\n }\n if (agiflowJobKind && !input.prompt?.trim()) {\n throw new Error(\n 'Agiflow workflow launches require a non-empty prompt so user_prompt runs do not wait for terminal input.',\n );\n }\n reportProgress(onUpdate, LAUNCH_WORKFLOW_TOOL_NAME, 'Checking workflow capacity...');\n const maxConcurrent = resolveMaxConcurrent(dependencies.environment);\n const active = (await dependencies.activeRunCount?.()) ?? 0;\n if (active >= maxConcurrent) {\n throw new Error(\n withOptions(`This session is at capacity: ${active}/${maxConcurrent} workflows running.`, [\n 'Wait for a running workflow to finish, then launch again. The extension reports each one as it ends.',\n 'workflow_run with action status: show what is running, so the user can judge whether something is stuck.',\n 'workflow_run with action stop: free a slot by stopping a run the user no longer wants.',\n ]),\n );\n }\n\n if (input.runner) {\n const rejection = dependencies.rejectRunner?.(input.workflowPath, input.runner);\n if (rejection) throw new Error(rejection);\n }\n reportProgress(onUpdate, LAUNCH_WORKFLOW_TOOL_NAME, `Launching workflow ${input.workflowPath}...`);\n const workflowEnv = { ...input.env };\n const dispatcherContextFile = dependencies.environment.AGIFLOW_DISPATCH_CONTEXT_FILE;\n const dispatcherProjectId = dependencies.environment[AGIFLOW_PROJECT_ID_ENV]?.trim();\n if (\n dispatcherContextFile &&\n agiflowJobKind &&\n dispatcherProjectId &&\n explicitProjectId &&\n dispatcherProjectId !== explicitProjectId\n ) {\n throw new Error(\n `Agiflow workflow project identity conflicts with the dispatcher context (${explicitProjectId} versus ${dispatcherProjectId}).`,\n );\n }\n if (dispatcherContextFile) {\n for (const key of [\n 'AGIFLOW_ORGANIZATION_ID',\n 'AGIFLOW_PROJECT_ID',\n 'AGIFLOW_DEVICE_ID',\n 'BACKEND_AGIFLOW_API_ENDPOINT',\n 'AGIFLOW_DISPATCH_SECRET_FILE',\n ] as const) {\n const hostValue = dependencies.environment[key];\n if (hostValue) workflowEnv[key] = hostValue;\n }\n }\n const since = Date.now();\n const launch = dependencies.trackPendingRun(\n dependencies.runTool.execute({\n ...input,\n env: { ...workflowEnv, [PI_SESSION_ENV]: sessionId },\n }),\n );\n // Folded into a value before anything races it. A promise this function\n // may stop awaiting must never be able to reject unobserved, which in\n // Node ends the whole process, Pi's TUI included.\n const settled: Promise<LaunchOutcome> = launch.then(\n (value): LaunchOutcome => ({ kind: 'value', result: value }),\n (error: unknown): LaunchOutcome => ({ kind: 'error', error }),\n );\n\n const ack = await awaitLaunchAck(settled, dependencies, {\n sessionId,\n since,\n workflowPath: input.workflowPath,\n });\n\n if (ack.kind === 'settled') {\n const outcome = ack.outcome;\n if (outcome.kind === 'error') throw asError(outcome.error);\n const result = outcome.result;\n if (result.isError)\n throw new Error(withOptions(toolResultText(result) || 'Workflow launch failed.', launchFailureOptions));\n await dependencies.onLaunch?.(ctx);\n return result;\n }\n\n reportLateFailure(settled, dependencies, ctx);\n await dependencies.onLaunch?.(ctx);\n return {\n content: [\n {\n type: 'text',\n text: ack.kind === 'record' ? launchedRunSummary(ack.record) : launchHandoffSummary(input.workflowPath),\n },\n ],\n };\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
let node_async_hooks = require("node:async_hooks");
|
|
2
|
+
let _agimon_ai_doompi_core_child_process = require("@agimon-ai/doompi-core/child-process");
|
|
3
|
+
//#region src/services/workflowFence/index.ts
|
|
4
|
+
const DISPATCHER_AGENT_NAME = "agiflow-dispatcher";
|
|
5
|
+
const SESSION_START_EVENT = "session_start";
|
|
6
|
+
const INACTIVE_RUNTIME_MESSAGE = "The workflow runtime is no longer active.";
|
|
7
|
+
const CLEANUP_SCOPE = Symbol("doom-workflow-cleanup");
|
|
8
|
+
const DISPATCHER_TOOL_NAMES = /* @__PURE__ */ new Set(["list_workflows", "launch_workflow"]);
|
|
9
|
+
const ROOT_SCOPED_TOOL_NAMES = /* @__PURE__ */ new Set(["launch_workflow"]);
|
|
10
|
+
const WORKFLOW_RUN_TOOL_NAME = "workflow_run";
|
|
11
|
+
function boundValue(target, property) {
|
|
12
|
+
const value = Reflect.get(target, property, target);
|
|
13
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
14
|
+
}
|
|
15
|
+
function withParentSession(ctx, parentSessionId) {
|
|
16
|
+
const sessionManager = new Proxy(ctx.sessionManager, { get(target, property) {
|
|
17
|
+
if (property === "getSessionId") return () => parentSessionId;
|
|
18
|
+
return boundValue(target, property);
|
|
19
|
+
} });
|
|
20
|
+
return new Proxy(ctx, { get(target, property) {
|
|
21
|
+
if (property === "sessionManager") return sessionManager;
|
|
22
|
+
return boundValue(target, property);
|
|
23
|
+
} });
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A dispatcher child launches workflows for its root session and never runs one
|
|
27
|
+
* itself, so `workflow_run` stays off its surface even if something registers it.
|
|
28
|
+
*/
|
|
29
|
+
function dispatcherToolRestriction() {
|
|
30
|
+
return (incoming) => incoming.filter((name) => name !== WORKFLOW_RUN_TOOL_NAME);
|
|
31
|
+
}
|
|
32
|
+
/** Restrict a dispatcher child to discovery and root-owned launch. */
|
|
33
|
+
function dispatcherTools(tools, parentSessionId, environment) {
|
|
34
|
+
const rootSessionId = parentSessionId ? (0, _agimon_ai_doompi_core_child_process.resolveRootSessionId)(parentSessionId, environment) : void 0;
|
|
35
|
+
return tools.filter((tool) => DISPATCHER_TOOL_NAMES.has(tool.name)).map((tool) => {
|
|
36
|
+
if (!rootSessionId || !ROOT_SCOPED_TOOL_NAMES.has(tool.name)) return tool;
|
|
37
|
+
return {
|
|
38
|
+
...tool,
|
|
39
|
+
execute: (toolCallId, params, signal, onUpdate, ctx) => tool.execute(toolCallId, params, signal, onUpdate, withParentSession(ctx, rootSessionId))
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function resolveDispatcherParentSession(environment) {
|
|
44
|
+
return (0, _agimon_ai_doompi_core_child_process.readChildProcessContext)(environment)?.parentSessionId ?? (environment[_agimon_ai_doompi_core_child_process.SUBAGENT_PARENT_SESSION_ENV]?.trim() || void 0);
|
|
45
|
+
}
|
|
46
|
+
function isWorkflowDispatcherProcess(environment) {
|
|
47
|
+
if ((0, _agimon_ai_doompi_core_child_process.readChildProcessContext)(environment)?.mode === DISPATCHER_AGENT_NAME) return true;
|
|
48
|
+
return environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME && Boolean(environment[_agimon_ai_doompi_core_child_process.SUBAGENT_PARENT_SESSION_ENV]?.trim());
|
|
49
|
+
}
|
|
50
|
+
/** Fence every callback retained by Pi after this package root is replaced. */
|
|
51
|
+
function createWorkflowFence(host, signal) {
|
|
52
|
+
const scope = new node_async_hooks.AsyncLocalStorage();
|
|
53
|
+
let active = true;
|
|
54
|
+
let disposing = false;
|
|
55
|
+
let generation = 0;
|
|
56
|
+
let lastSessionStartEvent;
|
|
57
|
+
let lastSessionStartContext;
|
|
58
|
+
const isCurrentInvocation = () => {
|
|
59
|
+
const currentScope = scope.getStore();
|
|
60
|
+
if (!active || signal?.aborted && currentScope !== CLEANUP_SCOPE) return false;
|
|
61
|
+
return currentScope === void 0 || currentScope === CLEANUP_SCOPE || currentScope === generation;
|
|
62
|
+
};
|
|
63
|
+
const ownsContext = (contextGeneration) => {
|
|
64
|
+
const currentScope = scope.getStore();
|
|
65
|
+
if (!active || signal?.aborted && currentScope !== CLEANUP_SCOPE) return false;
|
|
66
|
+
return currentScope === CLEANUP_SCOPE || contextGeneration === generation && (currentScope === void 0 || currentScope === contextGeneration);
|
|
67
|
+
};
|
|
68
|
+
const guardContext = (context, contextGeneration) => {
|
|
69
|
+
const guardedUi = new Proxy(context.ui, { get(target, property) {
|
|
70
|
+
const value = Reflect.get(target, property, target);
|
|
71
|
+
if (typeof value !== "function") return value;
|
|
72
|
+
return (...args) => {
|
|
73
|
+
if (ownsContext(contextGeneration)) return Reflect.apply(value, target, args);
|
|
74
|
+
if (property === "confirm") return Promise.resolve(false);
|
|
75
|
+
if (property === "custom" || property === "editor" || property === "input" || property === "select") return Promise.resolve(void 0);
|
|
76
|
+
};
|
|
77
|
+
} });
|
|
78
|
+
return new Proxy(context, { get(target, property) {
|
|
79
|
+
if (property === "ui") return guardedUi;
|
|
80
|
+
return boundValue(target, property);
|
|
81
|
+
} });
|
|
82
|
+
};
|
|
83
|
+
const tool = (definition) => {
|
|
84
|
+
return {
|
|
85
|
+
...definition,
|
|
86
|
+
execute: async (toolCallId, params, signal, onUpdate, context) => {
|
|
87
|
+
const executionGeneration = generation;
|
|
88
|
+
if (!active || disposing || signal?.aborted) throw new Error(INACTIVE_RUNTIME_MESSAGE);
|
|
89
|
+
const guardedContext = guardContext(context, executionGeneration);
|
|
90
|
+
const guardedUpdate = onUpdate ? (update) => {
|
|
91
|
+
if (active && executionGeneration === generation && !signal?.aborted) onUpdate(update);
|
|
92
|
+
} : void 0;
|
|
93
|
+
const result = await scope.run(executionGeneration, () => definition.execute(toolCallId, params, signal, guardedUpdate, guardedContext));
|
|
94
|
+
if (!active || disposing || executionGeneration !== generation) throw new Error(INACTIVE_RUNTIME_MESSAGE);
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
const command = (name, options) => {
|
|
100
|
+
return [name, {
|
|
101
|
+
...options,
|
|
102
|
+
handler: async (args, context) => {
|
|
103
|
+
const executionGeneration = generation;
|
|
104
|
+
if (!active || disposing) return;
|
|
105
|
+
await scope.run(executionGeneration, () => options.handler(args, guardContext(context, executionGeneration)));
|
|
106
|
+
}
|
|
107
|
+
}];
|
|
108
|
+
};
|
|
109
|
+
const shortcut = (key, options) => {
|
|
110
|
+
return [key, {
|
|
111
|
+
...options,
|
|
112
|
+
handler: (context) => {
|
|
113
|
+
const executionGeneration = generation;
|
|
114
|
+
if (!active || disposing) return;
|
|
115
|
+
return scope.run(executionGeneration, () => options.handler(guardContext(context, executionGeneration)));
|
|
116
|
+
}
|
|
117
|
+
}];
|
|
118
|
+
};
|
|
119
|
+
const events = (handlers) => Object.fromEntries(Object.entries(handlers).map(([eventName, handler]) => [eventName, (event, context) => {
|
|
120
|
+
if (!active || disposing) return void 0;
|
|
121
|
+
if (eventName === SESSION_START_EVENT && (event !== lastSessionStartEvent || context !== lastSessionStartContext)) {
|
|
122
|
+
generation += 1;
|
|
123
|
+
lastSessionStartEvent = event;
|
|
124
|
+
lastSessionStartContext = context;
|
|
125
|
+
}
|
|
126
|
+
const eventGeneration = generation;
|
|
127
|
+
return scope.run(eventGeneration, () => handler(event, guardContext(context, eventGeneration)));
|
|
128
|
+
}]));
|
|
129
|
+
return {
|
|
130
|
+
pi: new Proxy(host, { get(target, property) {
|
|
131
|
+
if (property === "sendMessage") return (...args) => {
|
|
132
|
+
if (isCurrentInvocation()) target.sendMessage(...args);
|
|
133
|
+
};
|
|
134
|
+
if (property === "sendUserMessage") return (...args) => {
|
|
135
|
+
if (isCurrentInvocation()) target.sendUserMessage(...args);
|
|
136
|
+
};
|
|
137
|
+
if (property === "exec") return (...args) => isCurrentInvocation() ? target.exec(...args) : Promise.resolve({
|
|
138
|
+
code: 1,
|
|
139
|
+
killed: false,
|
|
140
|
+
stderr: INACTIVE_RUNTIME_MESSAGE,
|
|
141
|
+
stdout: ""
|
|
142
|
+
});
|
|
143
|
+
return boundValue(target, property);
|
|
144
|
+
} }),
|
|
145
|
+
tool,
|
|
146
|
+
command,
|
|
147
|
+
shortcut,
|
|
148
|
+
events,
|
|
149
|
+
beginDisposal() {
|
|
150
|
+
if (disposing || !active) return;
|
|
151
|
+
disposing = true;
|
|
152
|
+
generation += 1;
|
|
153
|
+
},
|
|
154
|
+
finishDisposal() {
|
|
155
|
+
active = false;
|
|
156
|
+
disposing = false;
|
|
157
|
+
generation += 1;
|
|
158
|
+
},
|
|
159
|
+
isCurrentInvocation,
|
|
160
|
+
runCleanup: (operation) => scope.run(CLEANUP_SCOPE, operation)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
//#endregion
|
|
164
|
+
exports.createWorkflowFence = createWorkflowFence;
|
|
165
|
+
exports.dispatcherToolRestriction = dispatcherToolRestriction;
|
|
166
|
+
exports.dispatcherTools = dispatcherTools;
|
|
167
|
+
exports.isWorkflowDispatcherProcess = isWorkflowDispatcherProcess;
|
|
168
|
+
exports.resolveDispatcherParentSession = resolveDispatcherParentSession;
|
|
169
|
+
|
|
170
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["resolveRootSessionId","readChildProcessContext","SUBAGENT_PARENT_SESSION_ENV","AsyncLocalStorage"],"sources":["../../../../src/services/workflowFence/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\n\nimport {\n readChildProcessContext,\n resolveRootSessionId,\n SUBAGENT_PARENT_SESSION_ENV,\n} from '@agimon-ai/doompi-core/child-process';\nimport type { PiEventHandlers } from '@agimon-ai/doompi-core/pi-extension';\nimport type { DoomToolRestriction } from '@agimon-ai/doompi-core/tool-surface';\nimport type { ExtensionAPI, ExtensionContext, ToolDefinition } from '@earendil-works/pi-coding-agent';\n\nconst DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst SESSION_START_EVENT = 'session_start';\nconst INACTIVE_RUNTIME_MESSAGE = 'The workflow runtime is no longer active.';\nconst CLEANUP_SCOPE = Symbol('doom-workflow-cleanup');\n\nconst DISPATCHER_TOOL_NAMES = new Set(['list_workflows', 'launch_workflow']);\nconst ROOT_SCOPED_TOOL_NAMES = new Set(['launch_workflow']);\nconst WORKFLOW_RUN_TOOL_NAME = 'workflow_run';\n\ntype ToolSchema = Parameters<ExtensionAPI['registerTool']>[0]['parameters'];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\ntype RuntimeScope = number | typeof CLEANUP_SCOPE;\ntype LifecycleHandler = (event: unknown, context: ExtensionContext) => unknown;\n\nexport interface WorkflowFence {\n tool<TSchema extends ToolSchema, TDetails>(\n tool: ToolDefinition<TSchema, TDetails>,\n ): ToolDefinition<TSchema, TDetails>;\n command(name: string, options: CommandOptions): readonly [string, CommandOptions];\n shortcut(\n shortcut: Parameters<ExtensionAPI['registerShortcut']>[0],\n options: ShortcutOptions,\n ): readonly [Parameters<ExtensionAPI['registerShortcut']>[0], ShortcutOptions];\n events(handlers: PiEventHandlers): PiEventHandlers;\n readonly pi: ExtensionAPI;\n readonly beginDisposal: () => void;\n readonly finishDisposal: () => void;\n readonly isCurrentInvocation: () => boolean;\n readonly runCleanup: <T>(operation: () => T) => T;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction withParentSession(ctx: ExtensionContext, parentSessionId: string): ExtensionContext {\n const sessionManager = new Proxy(ctx.sessionManager, {\n get(target, property) {\n if (property === 'getSessionId') return () => parentSessionId;\n return boundValue(target, property);\n },\n });\n return new Proxy(ctx, {\n get(target, property) {\n if (property === 'sessionManager') return sessionManager;\n return boundValue(target, property);\n },\n });\n}\n\n/**\n * A dispatcher child launches workflows for its root session and never runs one\n * itself, so `workflow_run` stays off its surface even if something registers it.\n */\nexport function dispatcherToolRestriction(): DoomToolRestriction {\n return (incoming) => incoming.filter((name) => name !== WORKFLOW_RUN_TOOL_NAME);\n}\n\n/** Restrict a dispatcher child to discovery and root-owned launch. */\nexport function dispatcherTools<TSchema extends ToolSchema, TDetails>(\n tools: readonly ToolDefinition<TSchema, TDetails>[],\n parentSessionId: string | undefined,\n environment: Readonly<Record<string, string | undefined>>,\n): ToolDefinition<TSchema, TDetails>[] {\n const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : undefined;\n return tools\n .filter((tool) => DISPATCHER_TOOL_NAMES.has(tool.name))\n .map((tool) => {\n if (!rootSessionId || !ROOT_SCOPED_TOOL_NAMES.has(tool.name)) return tool;\n return {\n ...tool,\n execute: (toolCallId, params, signal, onUpdate, ctx) =>\n tool.execute(toolCallId, params, signal, onUpdate, withParentSession(ctx, rootSessionId)),\n };\n });\n}\n\nexport function resolveDispatcherParentSession(\n environment: Readonly<Record<string, string | undefined>>,\n): string | undefined {\n const childContext = readChildProcessContext(environment);\n return childContext?.parentSessionId ?? (environment[SUBAGENT_PARENT_SESSION_ENV]?.trim() || undefined);\n}\n\nexport function isWorkflowDispatcherProcess(environment: Readonly<Record<string, string | undefined>>): boolean {\n const childContext = readChildProcessContext(environment);\n if (childContext?.mode === DISPATCHER_AGENT_NAME) return true;\n return (\n environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME &&\n Boolean(environment[SUBAGENT_PARENT_SESSION_ENV]?.trim())\n );\n}\n\n/** Fence every callback retained by Pi after this package root is replaced. */\nexport function createWorkflowFence(host: ExtensionAPI, signal?: AbortSignal): WorkflowFence {\n const scope = new AsyncLocalStorage<RuntimeScope>();\n let active = true;\n let disposing = false;\n let generation = 0;\n let lastSessionStartEvent: unknown;\n let lastSessionStartContext: ExtensionContext | undefined;\n\n const isCurrentInvocation = (): boolean => {\n const currentScope = scope.getStore();\n if (!active || (signal?.aborted && currentScope !== CLEANUP_SCOPE)) return false;\n return currentScope === undefined || currentScope === CLEANUP_SCOPE || currentScope === generation;\n };\n const ownsContext = (contextGeneration: number): boolean => {\n const currentScope = scope.getStore();\n if (!active || (signal?.aborted && currentScope !== CLEANUP_SCOPE)) return false;\n return (\n currentScope === CLEANUP_SCOPE ||\n (contextGeneration === generation && (currentScope === undefined || currentScope === contextGeneration))\n );\n };\n\n const guardContext = <TContext extends ExtensionContext>(context: TContext, contextGeneration: number): TContext => {\n const guardedUi = new Proxy(context.ui, {\n get(target, property) {\n const value = Reflect.get(target, property, target);\n if (typeof value !== 'function') return value;\n return (...args: unknown[]): unknown => {\n if (ownsContext(contextGeneration)) return Reflect.apply(value, target, args);\n if (property === 'confirm') return Promise.resolve(false);\n if (property === 'custom' || property === 'editor' || property === 'input' || property === 'select') {\n return Promise.resolve(undefined);\n }\n return undefined;\n };\n },\n });\n return new Proxy(context, {\n get(target, property) {\n if (property === 'ui') return guardedUi;\n return boundValue(target, property);\n },\n }) as TContext;\n };\n\n const tool = <TSchema extends ToolSchema, TDetails>(\n definition: ToolDefinition<TSchema, TDetails>,\n ): ToolDefinition<TSchema, TDetails> => {\n return {\n ...definition,\n execute: async (toolCallId, params, signal, onUpdate, context) => {\n const executionGeneration = generation;\n if (!active || disposing || signal?.aborted) throw new Error(INACTIVE_RUNTIME_MESSAGE);\n const guardedContext = guardContext(context, executionGeneration);\n const guardedUpdate = onUpdate\n ? (update: Parameters<NonNullable<typeof onUpdate>>[0]): void => {\n if (active && executionGeneration === generation && !signal?.aborted) onUpdate(update);\n }\n : undefined;\n const result = await scope.run(executionGeneration, () =>\n definition.execute(toolCallId, params, signal, guardedUpdate, guardedContext),\n );\n if (!active || disposing || executionGeneration !== generation) throw new Error(INACTIVE_RUNTIME_MESSAGE);\n return result;\n },\n };\n };\n\n const command: WorkflowFence['command'] = (name, options) => {\n return [\n name,\n {\n ...options,\n handler: async (args, context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n await scope.run(executionGeneration, () => options.handler(args, guardContext(context, executionGeneration)));\n },\n },\n ];\n };\n\n const shortcut: WorkflowFence['shortcut'] = (key, options) => {\n return [\n key,\n {\n ...options,\n handler: (context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n return scope.run(executionGeneration, () => options.handler(guardContext(context, executionGeneration)));\n },\n },\n ];\n };\n\n const events = (handlers: PiEventHandlers): PiEventHandlers =>\n Object.fromEntries(\n Object.entries(handlers).map(([eventName, handler]) => [\n eventName,\n (event: unknown, context: ExtensionContext) => {\n if (!active || disposing) return undefined;\n if (\n eventName === SESSION_START_EVENT &&\n (event !== lastSessionStartEvent || context !== lastSessionStartContext)\n ) {\n generation += 1;\n lastSessionStartEvent = event;\n lastSessionStartContext = context;\n }\n const eventGeneration = generation;\n return scope.run(eventGeneration, () =>\n (handler as LifecycleHandler)(event, guardContext(context, eventGeneration)),\n );\n },\n ]),\n ) as PiEventHandlers;\n\n const guardedPi = new Proxy(host, {\n get(target, property) {\n if (property === 'sendMessage') {\n return (...args: Parameters<ExtensionAPI['sendMessage']>): void => {\n if (isCurrentInvocation()) target.sendMessage(...args);\n };\n }\n if (property === 'sendUserMessage') {\n return (...args: Parameters<ExtensionAPI['sendUserMessage']>): void => {\n if (isCurrentInvocation()) target.sendUserMessage(...args);\n };\n }\n if (property === 'exec') {\n return (...args: Parameters<ExtensionAPI['exec']>): ReturnType<ExtensionAPI['exec']> =>\n isCurrentInvocation()\n ? target.exec(...args)\n : Promise.resolve({ code: 1, killed: false, stderr: INACTIVE_RUNTIME_MESSAGE, stdout: '' });\n }\n return boundValue(target, property);\n },\n });\n\n return {\n pi: guardedPi,\n tool,\n command,\n shortcut,\n events,\n beginDisposal() {\n if (disposing || !active) return;\n disposing = true;\n generation += 1;\n },\n finishDisposal() {\n active = false;\n disposing = false;\n generation += 1;\n },\n isCurrentInvocation,\n runCleanup: (operation) => scope.run(CLEANUP_SCOPE, operation),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { SUBAGENT_PARENT_SESSION_ENV, readChildProcessContext, resolveRootSessionId } from "@agimon-ai/doompi-core/child-process";
|
|
3
|
+
//#region src/services/workflowFence/index.ts
|
|
4
|
+
const DISPATCHER_AGENT_NAME = "agiflow-dispatcher";
|
|
5
|
+
const SESSION_START_EVENT = "session_start";
|
|
6
|
+
const INACTIVE_RUNTIME_MESSAGE = "The workflow runtime is no longer active.";
|
|
7
|
+
const CLEANUP_SCOPE = Symbol("doom-workflow-cleanup");
|
|
8
|
+
const DISPATCHER_TOOL_NAMES = /* @__PURE__ */ new Set(["list_workflows", "launch_workflow"]);
|
|
9
|
+
const ROOT_SCOPED_TOOL_NAMES = /* @__PURE__ */ new Set(["launch_workflow"]);
|
|
10
|
+
const WORKFLOW_RUN_TOOL_NAME = "workflow_run";
|
|
11
|
+
function boundValue(target, property) {
|
|
12
|
+
const value = Reflect.get(target, property, target);
|
|
13
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
14
|
+
}
|
|
15
|
+
function withParentSession(ctx, parentSessionId) {
|
|
16
|
+
const sessionManager = new Proxy(ctx.sessionManager, { get(target, property) {
|
|
17
|
+
if (property === "getSessionId") return () => parentSessionId;
|
|
18
|
+
return boundValue(target, property);
|
|
19
|
+
} });
|
|
20
|
+
return new Proxy(ctx, { get(target, property) {
|
|
21
|
+
if (property === "sessionManager") return sessionManager;
|
|
22
|
+
return boundValue(target, property);
|
|
23
|
+
} });
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A dispatcher child launches workflows for its root session and never runs one
|
|
27
|
+
* itself, so `workflow_run` stays off its surface even if something registers it.
|
|
28
|
+
*/
|
|
29
|
+
function dispatcherToolRestriction() {
|
|
30
|
+
return (incoming) => incoming.filter((name) => name !== WORKFLOW_RUN_TOOL_NAME);
|
|
31
|
+
}
|
|
32
|
+
/** Restrict a dispatcher child to discovery and root-owned launch. */
|
|
33
|
+
function dispatcherTools(tools, parentSessionId, environment) {
|
|
34
|
+
const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : void 0;
|
|
35
|
+
return tools.filter((tool) => DISPATCHER_TOOL_NAMES.has(tool.name)).map((tool) => {
|
|
36
|
+
if (!rootSessionId || !ROOT_SCOPED_TOOL_NAMES.has(tool.name)) return tool;
|
|
37
|
+
return {
|
|
38
|
+
...tool,
|
|
39
|
+
execute: (toolCallId, params, signal, onUpdate, ctx) => tool.execute(toolCallId, params, signal, onUpdate, withParentSession(ctx, rootSessionId))
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function resolveDispatcherParentSession(environment) {
|
|
44
|
+
return readChildProcessContext(environment)?.parentSessionId ?? (environment[SUBAGENT_PARENT_SESSION_ENV]?.trim() || void 0);
|
|
45
|
+
}
|
|
46
|
+
function isWorkflowDispatcherProcess(environment) {
|
|
47
|
+
if (readChildProcessContext(environment)?.mode === DISPATCHER_AGENT_NAME) return true;
|
|
48
|
+
return environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME && Boolean(environment[SUBAGENT_PARENT_SESSION_ENV]?.trim());
|
|
49
|
+
}
|
|
50
|
+
/** Fence every callback retained by Pi after this package root is replaced. */
|
|
51
|
+
function createWorkflowFence(host, signal) {
|
|
52
|
+
const scope = new AsyncLocalStorage();
|
|
53
|
+
let active = true;
|
|
54
|
+
let disposing = false;
|
|
55
|
+
let generation = 0;
|
|
56
|
+
let lastSessionStartEvent;
|
|
57
|
+
let lastSessionStartContext;
|
|
58
|
+
const isCurrentInvocation = () => {
|
|
59
|
+
const currentScope = scope.getStore();
|
|
60
|
+
if (!active || signal?.aborted && currentScope !== CLEANUP_SCOPE) return false;
|
|
61
|
+
return currentScope === void 0 || currentScope === CLEANUP_SCOPE || currentScope === generation;
|
|
62
|
+
};
|
|
63
|
+
const ownsContext = (contextGeneration) => {
|
|
64
|
+
const currentScope = scope.getStore();
|
|
65
|
+
if (!active || signal?.aborted && currentScope !== CLEANUP_SCOPE) return false;
|
|
66
|
+
return currentScope === CLEANUP_SCOPE || contextGeneration === generation && (currentScope === void 0 || currentScope === contextGeneration);
|
|
67
|
+
};
|
|
68
|
+
const guardContext = (context, contextGeneration) => {
|
|
69
|
+
const guardedUi = new Proxy(context.ui, { get(target, property) {
|
|
70
|
+
const value = Reflect.get(target, property, target);
|
|
71
|
+
if (typeof value !== "function") return value;
|
|
72
|
+
return (...args) => {
|
|
73
|
+
if (ownsContext(contextGeneration)) return Reflect.apply(value, target, args);
|
|
74
|
+
if (property === "confirm") return Promise.resolve(false);
|
|
75
|
+
if (property === "custom" || property === "editor" || property === "input" || property === "select") return Promise.resolve(void 0);
|
|
76
|
+
};
|
|
77
|
+
} });
|
|
78
|
+
return new Proxy(context, { get(target, property) {
|
|
79
|
+
if (property === "ui") return guardedUi;
|
|
80
|
+
return boundValue(target, property);
|
|
81
|
+
} });
|
|
82
|
+
};
|
|
83
|
+
const tool = (definition) => {
|
|
84
|
+
return {
|
|
85
|
+
...definition,
|
|
86
|
+
execute: async (toolCallId, params, signal, onUpdate, context) => {
|
|
87
|
+
const executionGeneration = generation;
|
|
88
|
+
if (!active || disposing || signal?.aborted) throw new Error(INACTIVE_RUNTIME_MESSAGE);
|
|
89
|
+
const guardedContext = guardContext(context, executionGeneration);
|
|
90
|
+
const guardedUpdate = onUpdate ? (update) => {
|
|
91
|
+
if (active && executionGeneration === generation && !signal?.aborted) onUpdate(update);
|
|
92
|
+
} : void 0;
|
|
93
|
+
const result = await scope.run(executionGeneration, () => definition.execute(toolCallId, params, signal, guardedUpdate, guardedContext));
|
|
94
|
+
if (!active || disposing || executionGeneration !== generation) throw new Error(INACTIVE_RUNTIME_MESSAGE);
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
const command = (name, options) => {
|
|
100
|
+
return [name, {
|
|
101
|
+
...options,
|
|
102
|
+
handler: async (args, context) => {
|
|
103
|
+
const executionGeneration = generation;
|
|
104
|
+
if (!active || disposing) return;
|
|
105
|
+
await scope.run(executionGeneration, () => options.handler(args, guardContext(context, executionGeneration)));
|
|
106
|
+
}
|
|
107
|
+
}];
|
|
108
|
+
};
|
|
109
|
+
const shortcut = (key, options) => {
|
|
110
|
+
return [key, {
|
|
111
|
+
...options,
|
|
112
|
+
handler: (context) => {
|
|
113
|
+
const executionGeneration = generation;
|
|
114
|
+
if (!active || disposing) return;
|
|
115
|
+
return scope.run(executionGeneration, () => options.handler(guardContext(context, executionGeneration)));
|
|
116
|
+
}
|
|
117
|
+
}];
|
|
118
|
+
};
|
|
119
|
+
const events = (handlers) => Object.fromEntries(Object.entries(handlers).map(([eventName, handler]) => [eventName, (event, context) => {
|
|
120
|
+
if (!active || disposing) return void 0;
|
|
121
|
+
if (eventName === SESSION_START_EVENT && (event !== lastSessionStartEvent || context !== lastSessionStartContext)) {
|
|
122
|
+
generation += 1;
|
|
123
|
+
lastSessionStartEvent = event;
|
|
124
|
+
lastSessionStartContext = context;
|
|
125
|
+
}
|
|
126
|
+
const eventGeneration = generation;
|
|
127
|
+
return scope.run(eventGeneration, () => handler(event, guardContext(context, eventGeneration)));
|
|
128
|
+
}]));
|
|
129
|
+
return {
|
|
130
|
+
pi: new Proxy(host, { get(target, property) {
|
|
131
|
+
if (property === "sendMessage") return (...args) => {
|
|
132
|
+
if (isCurrentInvocation()) target.sendMessage(...args);
|
|
133
|
+
};
|
|
134
|
+
if (property === "sendUserMessage") return (...args) => {
|
|
135
|
+
if (isCurrentInvocation()) target.sendUserMessage(...args);
|
|
136
|
+
};
|
|
137
|
+
if (property === "exec") return (...args) => isCurrentInvocation() ? target.exec(...args) : Promise.resolve({
|
|
138
|
+
code: 1,
|
|
139
|
+
killed: false,
|
|
140
|
+
stderr: INACTIVE_RUNTIME_MESSAGE,
|
|
141
|
+
stdout: ""
|
|
142
|
+
});
|
|
143
|
+
return boundValue(target, property);
|
|
144
|
+
} }),
|
|
145
|
+
tool,
|
|
146
|
+
command,
|
|
147
|
+
shortcut,
|
|
148
|
+
events,
|
|
149
|
+
beginDisposal() {
|
|
150
|
+
if (disposing || !active) return;
|
|
151
|
+
disposing = true;
|
|
152
|
+
generation += 1;
|
|
153
|
+
},
|
|
154
|
+
finishDisposal() {
|
|
155
|
+
active = false;
|
|
156
|
+
disposing = false;
|
|
157
|
+
generation += 1;
|
|
158
|
+
},
|
|
159
|
+
isCurrentInvocation,
|
|
160
|
+
runCleanup: (operation) => scope.run(CLEANUP_SCOPE, operation)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
//#endregion
|
|
164
|
+
export { createWorkflowFence, dispatcherToolRestriction, dispatcherTools, isWorkflowDispatcherProcess, resolveDispatcherParentSession };
|
|
165
|
+
|
|
166
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/services/workflowFence/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\n\nimport {\n readChildProcessContext,\n resolveRootSessionId,\n SUBAGENT_PARENT_SESSION_ENV,\n} from '@agimon-ai/doompi-core/child-process';\nimport type { PiEventHandlers } from '@agimon-ai/doompi-core/pi-extension';\nimport type { DoomToolRestriction } from '@agimon-ai/doompi-core/tool-surface';\nimport type { ExtensionAPI, ExtensionContext, ToolDefinition } from '@earendil-works/pi-coding-agent';\n\nconst DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst SESSION_START_EVENT = 'session_start';\nconst INACTIVE_RUNTIME_MESSAGE = 'The workflow runtime is no longer active.';\nconst CLEANUP_SCOPE = Symbol('doom-workflow-cleanup');\n\nconst DISPATCHER_TOOL_NAMES = new Set(['list_workflows', 'launch_workflow']);\nconst ROOT_SCOPED_TOOL_NAMES = new Set(['launch_workflow']);\nconst WORKFLOW_RUN_TOOL_NAME = 'workflow_run';\n\ntype ToolSchema = Parameters<ExtensionAPI['registerTool']>[0]['parameters'];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\ntype RuntimeScope = number | typeof CLEANUP_SCOPE;\ntype LifecycleHandler = (event: unknown, context: ExtensionContext) => unknown;\n\nexport interface WorkflowFence {\n tool<TSchema extends ToolSchema, TDetails>(\n tool: ToolDefinition<TSchema, TDetails>,\n ): ToolDefinition<TSchema, TDetails>;\n command(name: string, options: CommandOptions): readonly [string, CommandOptions];\n shortcut(\n shortcut: Parameters<ExtensionAPI['registerShortcut']>[0],\n options: ShortcutOptions,\n ): readonly [Parameters<ExtensionAPI['registerShortcut']>[0], ShortcutOptions];\n events(handlers: PiEventHandlers): PiEventHandlers;\n readonly pi: ExtensionAPI;\n readonly beginDisposal: () => void;\n readonly finishDisposal: () => void;\n readonly isCurrentInvocation: () => boolean;\n readonly runCleanup: <T>(operation: () => T) => T;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction withParentSession(ctx: ExtensionContext, parentSessionId: string): ExtensionContext {\n const sessionManager = new Proxy(ctx.sessionManager, {\n get(target, property) {\n if (property === 'getSessionId') return () => parentSessionId;\n return boundValue(target, property);\n },\n });\n return new Proxy(ctx, {\n get(target, property) {\n if (property === 'sessionManager') return sessionManager;\n return boundValue(target, property);\n },\n });\n}\n\n/**\n * A dispatcher child launches workflows for its root session and never runs one\n * itself, so `workflow_run` stays off its surface even if something registers it.\n */\nexport function dispatcherToolRestriction(): DoomToolRestriction {\n return (incoming) => incoming.filter((name) => name !== WORKFLOW_RUN_TOOL_NAME);\n}\n\n/** Restrict a dispatcher child to discovery and root-owned launch. */\nexport function dispatcherTools<TSchema extends ToolSchema, TDetails>(\n tools: readonly ToolDefinition<TSchema, TDetails>[],\n parentSessionId: string | undefined,\n environment: Readonly<Record<string, string | undefined>>,\n): ToolDefinition<TSchema, TDetails>[] {\n const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : undefined;\n return tools\n .filter((tool) => DISPATCHER_TOOL_NAMES.has(tool.name))\n .map((tool) => {\n if (!rootSessionId || !ROOT_SCOPED_TOOL_NAMES.has(tool.name)) return tool;\n return {\n ...tool,\n execute: (toolCallId, params, signal, onUpdate, ctx) =>\n tool.execute(toolCallId, params, signal, onUpdate, withParentSession(ctx, rootSessionId)),\n };\n });\n}\n\nexport function resolveDispatcherParentSession(\n environment: Readonly<Record<string, string | undefined>>,\n): string | undefined {\n const childContext = readChildProcessContext(environment);\n return childContext?.parentSessionId ?? (environment[SUBAGENT_PARENT_SESSION_ENV]?.trim() || undefined);\n}\n\nexport function isWorkflowDispatcherProcess(environment: Readonly<Record<string, string | undefined>>): boolean {\n const childContext = readChildProcessContext(environment);\n if (childContext?.mode === DISPATCHER_AGENT_NAME) return true;\n return (\n environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME &&\n Boolean(environment[SUBAGENT_PARENT_SESSION_ENV]?.trim())\n );\n}\n\n/** Fence every callback retained by Pi after this package root is replaced. */\nexport function createWorkflowFence(host: ExtensionAPI, signal?: AbortSignal): WorkflowFence {\n const scope = new AsyncLocalStorage<RuntimeScope>();\n let active = true;\n let disposing = false;\n let generation = 0;\n let lastSessionStartEvent: unknown;\n let lastSessionStartContext: ExtensionContext | undefined;\n\n const isCurrentInvocation = (): boolean => {\n const currentScope = scope.getStore();\n if (!active || (signal?.aborted && currentScope !== CLEANUP_SCOPE)) return false;\n return currentScope === undefined || currentScope === CLEANUP_SCOPE || currentScope === generation;\n };\n const ownsContext = (contextGeneration: number): boolean => {\n const currentScope = scope.getStore();\n if (!active || (signal?.aborted && currentScope !== CLEANUP_SCOPE)) return false;\n return (\n currentScope === CLEANUP_SCOPE ||\n (contextGeneration === generation && (currentScope === undefined || currentScope === contextGeneration))\n );\n };\n\n const guardContext = <TContext extends ExtensionContext>(context: TContext, contextGeneration: number): TContext => {\n const guardedUi = new Proxy(context.ui, {\n get(target, property) {\n const value = Reflect.get(target, property, target);\n if (typeof value !== 'function') return value;\n return (...args: unknown[]): unknown => {\n if (ownsContext(contextGeneration)) return Reflect.apply(value, target, args);\n if (property === 'confirm') return Promise.resolve(false);\n if (property === 'custom' || property === 'editor' || property === 'input' || property === 'select') {\n return Promise.resolve(undefined);\n }\n return undefined;\n };\n },\n });\n return new Proxy(context, {\n get(target, property) {\n if (property === 'ui') return guardedUi;\n return boundValue(target, property);\n },\n }) as TContext;\n };\n\n const tool = <TSchema extends ToolSchema, TDetails>(\n definition: ToolDefinition<TSchema, TDetails>,\n ): ToolDefinition<TSchema, TDetails> => {\n return {\n ...definition,\n execute: async (toolCallId, params, signal, onUpdate, context) => {\n const executionGeneration = generation;\n if (!active || disposing || signal?.aborted) throw new Error(INACTIVE_RUNTIME_MESSAGE);\n const guardedContext = guardContext(context, executionGeneration);\n const guardedUpdate = onUpdate\n ? (update: Parameters<NonNullable<typeof onUpdate>>[0]): void => {\n if (active && executionGeneration === generation && !signal?.aborted) onUpdate(update);\n }\n : undefined;\n const result = await scope.run(executionGeneration, () =>\n definition.execute(toolCallId, params, signal, guardedUpdate, guardedContext),\n );\n if (!active || disposing || executionGeneration !== generation) throw new Error(INACTIVE_RUNTIME_MESSAGE);\n return result;\n },\n };\n };\n\n const command: WorkflowFence['command'] = (name, options) => {\n return [\n name,\n {\n ...options,\n handler: async (args, context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n await scope.run(executionGeneration, () => options.handler(args, guardContext(context, executionGeneration)));\n },\n },\n ];\n };\n\n const shortcut: WorkflowFence['shortcut'] = (key, options) => {\n return [\n key,\n {\n ...options,\n handler: (context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n return scope.run(executionGeneration, () => options.handler(guardContext(context, executionGeneration)));\n },\n },\n ];\n };\n\n const events = (handlers: PiEventHandlers): PiEventHandlers =>\n Object.fromEntries(\n Object.entries(handlers).map(([eventName, handler]) => [\n eventName,\n (event: unknown, context: ExtensionContext) => {\n if (!active || disposing) return undefined;\n if (\n eventName === SESSION_START_EVENT &&\n (event !== lastSessionStartEvent || context !== lastSessionStartContext)\n ) {\n generation += 1;\n lastSessionStartEvent = event;\n lastSessionStartContext = context;\n }\n const eventGeneration = generation;\n return scope.run(eventGeneration, () =>\n (handler as LifecycleHandler)(event, guardContext(context, eventGeneration)),\n );\n },\n ]),\n ) as PiEventHandlers;\n\n const guardedPi = new Proxy(host, {\n get(target, property) {\n if (property === 'sendMessage') {\n return (...args: Parameters<ExtensionAPI['sendMessage']>): void => {\n if (isCurrentInvocation()) target.sendMessage(...args);\n };\n }\n if (property === 'sendUserMessage') {\n return (...args: Parameters<ExtensionAPI['sendUserMessage']>): void => {\n if (isCurrentInvocation()) target.sendUserMessage(...args);\n };\n }\n if (property === 'exec') {\n return (...args: Parameters<ExtensionAPI['exec']>): ReturnType<ExtensionAPI['exec']> =>\n isCurrentInvocation()\n ? target.exec(...args)\n : Promise.resolve({ code: 1, killed: false, stderr: INACTIVE_RUNTIME_MESSAGE, stdout: '' });\n }\n return boundValue(target, property);\n },\n });\n\n return {\n pi: guardedPi,\n tool,\n command,\n shortcut,\n events,\n beginDisposal() {\n if (disposing || !active) return;\n disposing = true;\n generation += 1;\n },\n finishDisposal() {\n active = false;\n disposing = false;\n generation += 1;\n },\n isCurrentInvocation,\n runCleanup: (operation) => scope.run(CLEANUP_SCOPE, operation),\n };\n}\n"],"mappings":"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"}
|