botmux 2.47.0 → 2.47.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +10 -5
- package/README.md +10 -5
- package/dist/adapters/adopt-route.d.ts +63 -0
- package/dist/adapters/adopt-route.d.ts.map +1 -0
- package/dist/adapters/adopt-route.js +195 -0
- package/dist/adapters/adopt-route.js.map +1 -0
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +11 -0
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +11 -0
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +17 -1
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +36 -9
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/adapters/cli/coco.d.ts.map +1 -1
- package/dist/adapters/cli/coco.js +26 -1
- package/dist/adapters/cli/coco.js.map +1 -1
- package/dist/adapters/cli/codex-app.d.ts +4 -0
- package/dist/adapters/cli/codex-app.d.ts.map +1 -0
- package/dist/adapters/cli/codex-app.js +72 -0
- package/dist/adapters/cli/codex-app.js.map +1 -0
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +6 -1
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/cursor.d.ts.map +1 -1
- package/dist/adapters/cli/cursor.js +58 -12
- package/dist/adapters/cli/cursor.js.map +1 -1
- package/dist/adapters/cli/gemini.d.ts.map +1 -1
- package/dist/adapters/cli/gemini.js +5 -1
- package/dist/adapters/cli/gemini.js.map +1 -1
- package/dist/adapters/cli/hermes.d.ts +4 -0
- package/dist/adapters/cli/hermes.d.ts.map +1 -0
- package/dist/adapters/cli/hermes.js +40 -0
- package/dist/adapters/cli/hermes.js.map +1 -0
- package/dist/adapters/cli/mira.d.ts +4 -0
- package/dist/adapters/cli/mira.d.ts.map +1 -0
- package/dist/adapters/cli/mira.js +67 -0
- package/dist/adapters/cli/mira.js.map +1 -0
- package/dist/adapters/cli/mtr.d.ts +5 -0
- package/dist/adapters/cli/mtr.d.ts.map +1 -0
- package/dist/adapters/cli/mtr.js +62 -0
- package/dist/adapters/cli/mtr.js.map +1 -0
- package/dist/adapters/cli/opencode.d.ts.map +1 -1
- package/dist/adapters/cli/opencode.js +19 -1
- package/dist/adapters/cli/opencode.js.map +1 -1
- package/dist/adapters/cli/registry.d.ts +5 -1
- package/dist/adapters/cli/registry.d.ts.map +1 -1
- package/dist/adapters/cli/registry.js +22 -2
- package/dist/adapters/cli/registry.js.map +1 -1
- package/dist/adapters/cli/shared-hints.d.ts +1 -1
- package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
- package/dist/adapters/cli/shared-hints.js +2 -1
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +35 -2
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/adapters/hook-command.d.ts +18 -0
- package/dist/adapters/hook-command.d.ts.map +1 -0
- package/dist/adapters/hook-command.js +38 -0
- package/dist/adapters/hook-command.js.map +1 -0
- package/dist/adapters/hook-installer.d.ts +14 -0
- package/dist/adapters/hook-installer.d.ts.map +1 -0
- package/dist/adapters/hook-installer.js +192 -0
- package/dist/adapters/hook-installer.js.map +1 -0
- package/dist/bot-registry.d.ts +59 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +67 -0
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/bots-list-output.d.ts +8 -0
- package/dist/cli/bots-list-output.d.ts.map +1 -1
- package/dist/cli/bots-list-output.js +9 -0
- package/dist/cli/bots-list-output.js.map +1 -1
- package/dist/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +603 -106
- package/dist/cli.js.map +1 -1
- package/dist/codex-app-runner.d.ts +3 -0
- package/dist/codex-app-runner.d.ts.map +1 -0
- package/dist/codex-app-runner.js +512 -0
- package/dist/codex-app-runner.js.map +1 -0
- package/dist/config.d.ts +11 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +17 -4
- package/dist/config.js.map +1 -1
- package/dist/core/ask-api.d.ts +47 -0
- package/dist/core/ask-api.d.ts.map +1 -0
- package/dist/core/ask-api.js +139 -0
- package/dist/core/ask-api.js.map +1 -0
- package/dist/core/ask-args.d.ts +53 -0
- package/dist/core/ask-args.d.ts.map +1 -0
- package/dist/core/ask-args.js +122 -0
- package/dist/core/ask-args.js.map +1 -0
- package/dist/core/ask-broker.d.ts +98 -0
- package/dist/core/ask-broker.d.ts.map +1 -0
- package/dist/core/ask-broker.js +329 -0
- package/dist/core/ask-broker.js.map +1 -0
- package/dist/core/ask-hook/claude-code.d.ts +50 -0
- package/dist/core/ask-hook/claude-code.d.ts.map +1 -0
- package/dist/core/ask-hook/claude-code.js +145 -0
- package/dist/core/ask-hook/claude-code.js.map +1 -0
- package/dist/core/ask-hook/codex.d.ts +43 -0
- package/dist/core/ask-hook/codex.d.ts.map +1 -0
- package/dist/core/ask-hook/codex.js +69 -0
- package/dist/core/ask-hook/codex.js.map +1 -0
- package/dist/core/ask-hook/opencode.d.ts +41 -0
- package/dist/core/ask-hook/opencode.d.ts.map +1 -0
- package/dist/core/ask-hook/opencode.js +108 -0
- package/dist/core/ask-hook/opencode.js.map +1 -0
- package/dist/core/ask-hook/registry.d.ts +3 -0
- package/dist/core/ask-hook/registry.d.ts.map +1 -0
- package/dist/core/ask-hook/registry.js +12 -0
- package/dist/core/ask-hook/registry.js.map +1 -0
- package/dist/core/ask-hook/types.d.ts +26 -0
- package/dist/core/ask-hook/types.d.ts.map +1 -0
- package/dist/core/ask-hook/types.js +2 -0
- package/dist/core/ask-hook/types.js.map +1 -0
- package/dist/core/ask-types.d.ts +146 -0
- package/dist/core/ask-types.d.ts.map +1 -0
- package/dist/core/ask-types.js +18 -0
- package/dist/core/ask-types.js.map +1 -0
- package/dist/core/command-handler.d.ts +20 -0
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +774 -311
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts +2 -0
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +222 -2
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/role-resolver.d.ts +17 -1
- package/dist/core/role-resolver.d.ts.map +1 -1
- package/dist/core/role-resolver.js +64 -10
- package/dist/core/role-resolver.js.map +1 -1
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +19 -5
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/session-manager.d.ts +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +37 -20
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/trigger-session.d.ts +9 -0
- package/dist/core/trigger-session.d.ts.map +1 -0
- package/dist/core/trigger-session.js +158 -0
- package/dist/core/trigger-session.js.map +1 -0
- package/dist/core/types.d.ts +5 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +141 -0
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +543 -24
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +213 -58
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts +6 -1
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +9 -1
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/connector-api.d.ts +3 -0
- package/dist/dashboard/connector-api.d.ts.map +1 -0
- package/dist/dashboard/connector-api.js +351 -0
- package/dist/dashboard/connector-api.js.map +1 -0
- package/dist/dashboard/federated-group-core.d.ts +54 -0
- package/dist/dashboard/federated-group-core.d.ts.map +1 -0
- package/dist/dashboard/federated-group-core.js +165 -0
- package/dist/dashboard/federated-group-core.js.map +1 -0
- package/dist/dashboard/federation-api.d.ts +42 -0
- package/dist/dashboard/federation-api.d.ts.map +1 -0
- package/dist/dashboard/federation-api.js +408 -0
- package/dist/dashboard/federation-api.js.map +1 -0
- package/dist/dashboard/federation-spoke-api.d.ts +76 -0
- package/dist/dashboard/federation-spoke-api.d.ts.map +1 -0
- package/dist/dashboard/federation-spoke-api.js +618 -0
- package/dist/dashboard/federation-spoke-api.js.map +1 -0
- package/dist/dashboard/team-group.d.ts +18 -0
- package/dist/dashboard/team-group.d.ts.map +1 -0
- package/dist/dashboard/team-group.js +7 -0
- package/dist/dashboard/team-group.js.map +1 -0
- package/dist/dashboard/trigger-api.d.ts +13 -0
- package/dist/dashboard/trigger-api.d.ts.map +1 -0
- package/dist/dashboard/trigger-api.js +77 -0
- package/dist/dashboard/trigger-api.js.map +1 -0
- package/dist/dashboard/web/app.js +8 -0
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +205 -21
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/connectors.d.ts +2 -0
- package/dist/dashboard/web/connectors.d.ts.map +1 -0
- package/dist/dashboard/web/connectors.js +187 -0
- package/dist/dashboard/web/connectors.js.map +1 -0
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +43 -5
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +4 -0
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/team-federation.d.ts +3 -0
- package/dist/dashboard/web/team-federation.d.ts.map +1 -0
- package/dist/dashboard/web/team-federation.js +487 -0
- package/dist/dashboard/web/team-federation.js.map +1 -0
- package/dist/dashboard/web/workflows.js +3 -3
- package/dist/dashboard/web/workflows.js.map +1 -1
- package/dist/dashboard/webhook-routes.d.ts +19 -0
- package/dist/dashboard/webhook-routes.d.ts.map +1 -0
- package/dist/dashboard/webhook-routes.js +321 -0
- package/dist/dashboard/webhook-routes.js.map +1 -0
- package/dist/dashboard/workflow-api.d.ts +8 -1
- package/dist/dashboard/workflow-api.d.ts.map +1 -1
- package/dist/dashboard/workflow-api.js +19 -4
- package/dist/dashboard/workflow-api.js.map +1 -1
- package/dist/dashboard-web/app.js +539 -375
- package/dist/dashboard-web/index.html +3 -1
- package/dist/dashboard-web/style.css +22 -0
- package/dist/dashboard.js +199 -2
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +104 -11
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +104 -11
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/ask-card.d.ts +55 -0
- package/dist/im/lark/ask-card.d.ts.map +1 -0
- package/dist/im/lark/ask-card.js +328 -0
- package/dist/im/lark/ask-card.js.map +1 -0
- package/dist/im/lark/card-builder.d.ts +108 -3
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +480 -50
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +241 -18
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +83 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +286 -70
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +29 -4
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/grant-command.d.ts +2 -1
- package/dist/im/lark/grant-command.d.ts.map +1 -1
- package/dist/im/lark/grant-command.js +3 -2
- package/dist/im/lark/grant-command.js.map +1 -1
- package/dist/im/lark/identity-cache.d.ts.map +1 -1
- package/dist/im/lark/identity-cache.js +3 -3
- package/dist/im/lark/identity-cache.js.map +1 -1
- package/dist/im/lark/md-card.d.ts +20 -2
- package/dist/im/lark/md-card.d.ts.map +1 -1
- package/dist/im/lark/md-card.js +49 -17
- package/dist/im/lark/md-card.js.map +1 -1
- package/dist/im/lark/message-parser.d.ts.map +1 -1
- package/dist/im/lark/message-parser.js +87 -31
- package/dist/im/lark/message-parser.js.map +1 -1
- package/dist/im/lark/workflow-card-handler.d.ts +2 -2
- package/dist/im/lark/workflow-card-handler.d.ts.map +1 -1
- package/dist/im/lark/workflow-card-handler.js +12 -1
- package/dist/im/lark/workflow-card-handler.js.map +1 -1
- package/dist/im/lark/workflow-progress-card.d.ts.map +1 -1
- package/dist/im/lark/workflow-progress-card.js +53 -0
- package/dist/im/lark/workflow-progress-card.js.map +1 -1
- package/dist/mira-output.d.ts +3 -0
- package/dist/mira-output.d.ts.map +1 -0
- package/dist/mira-output.js +136 -0
- package/dist/mira-output.js.map +1 -0
- package/dist/mira-runner.d.ts +3 -0
- package/dist/mira-runner.d.ts.map +1 -0
- package/dist/mira-runner.js +534 -0
- package/dist/mira-runner.js.map +1 -0
- package/dist/services/bot-owner-store.d.ts +28 -0
- package/dist/services/bot-owner-store.d.ts.map +1 -0
- package/dist/services/bot-owner-store.js +82 -0
- package/dist/services/bot-owner-store.js.map +1 -0
- package/dist/services/bot-profile-store.d.ts +16 -0
- package/dist/services/bot-profile-store.d.ts.map +1 -0
- package/dist/services/bot-profile-store.js +98 -0
- package/dist/services/bot-profile-store.js.map +1 -0
- package/dist/services/brand-store.d.ts +15 -0
- package/dist/services/brand-store.d.ts.map +1 -0
- package/dist/services/brand-store.js +47 -0
- package/dist/services/brand-store.js.map +1 -0
- package/dist/services/card-prefs-store.d.ts +20 -0
- package/dist/services/card-prefs-store.d.ts.map +1 -0
- package/dist/services/card-prefs-store.js +82 -0
- package/dist/services/card-prefs-store.js.map +1 -0
- package/dist/services/codex-bridge-queue.d.ts +1 -0
- package/dist/services/codex-bridge-queue.d.ts.map +1 -1
- package/dist/services/codex-bridge-queue.js +23 -0
- package/dist/services/codex-bridge-queue.js.map +1 -1
- package/dist/services/codex-transcript.d.ts +1 -0
- package/dist/services/codex-transcript.d.ts.map +1 -1
- package/dist/services/codex-transcript.js.map +1 -1
- package/dist/services/connector-store.d.ts +58 -0
- package/dist/services/connector-store.d.ts.map +1 -0
- package/dist/services/connector-store.js +79 -0
- package/dist/services/connector-store.js.map +1 -0
- package/dist/services/deployment-identity.d.ts +22 -0
- package/dist/services/deployment-identity.d.ts.map +1 -0
- package/dist/services/deployment-identity.js +67 -0
- package/dist/services/deployment-identity.js.map +1 -0
- package/dist/services/federation-membership-store.d.ts +23 -0
- package/dist/services/federation-membership-store.d.ts.map +1 -0
- package/dist/services/federation-membership-store.js +66 -0
- package/dist/services/federation-membership-store.js.map +1 -0
- package/dist/services/federation-roster.d.ts +54 -0
- package/dist/services/federation-roster.d.ts.map +1 -0
- package/dist/services/federation-roster.js +51 -0
- package/dist/services/federation-roster.js.map +1 -0
- package/dist/services/federation-store.d.ts +76 -0
- package/dist/services/federation-store.d.ts.map +1 -0
- package/dist/services/federation-store.js +133 -0
- package/dist/services/federation-store.js.map +1 -0
- package/dist/services/grant-store.d.ts +12 -2
- package/dist/services/grant-store.d.ts.map +1 -1
- package/dist/services/grant-store.js +51 -4
- package/dist/services/grant-store.js.map +1 -1
- package/dist/services/group-creator.d.ts +10 -0
- package/dist/services/group-creator.d.ts.map +1 -1
- package/dist/services/group-creator.js +26 -1
- package/dist/services/group-creator.js.map +1 -1
- package/dist/services/groups-store.d.ts +30 -0
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +85 -12
- package/dist/services/groups-store.js.map +1 -1
- package/dist/services/hermes-transcript.d.ts +7 -0
- package/dist/services/hermes-transcript.d.ts.map +1 -0
- package/dist/services/hermes-transcript.js +117 -0
- package/dist/services/hermes-transcript.js.map +1 -0
- package/dist/services/invite-store.d.ts +28 -0
- package/dist/services/invite-store.d.ts.map +1 -0
- package/dist/services/invite-store.js +85 -0
- package/dist/services/invite-store.js.map +1 -0
- package/dist/services/pairing-store.d.ts +47 -0
- package/dist/services/pairing-store.d.ts.map +1 -0
- package/dist/services/pairing-store.js +132 -0
- package/dist/services/pairing-store.js.map +1 -0
- package/dist/services/project-scanner.d.ts +10 -0
- package/dist/services/project-scanner.d.ts.map +1 -1
- package/dist/services/project-scanner.js +11 -0
- package/dist/services/project-scanner.js.map +1 -1
- package/dist/services/relay-picker.d.ts +22 -0
- package/dist/services/relay-picker.d.ts.map +1 -0
- package/dist/services/relay-picker.js +62 -0
- package/dist/services/relay-picker.js.map +1 -0
- package/dist/services/send-policy.d.ts +55 -0
- package/dist/services/send-policy.d.ts.map +1 -0
- package/dist/services/send-policy.js +47 -0
- package/dist/services/send-policy.js.map +1 -0
- package/dist/services/session-store.js +1 -1
- package/dist/services/session-store.js.map +1 -1
- package/dist/services/team-roster.d.ts +38 -0
- package/dist/services/team-roster.d.ts.map +1 -0
- package/dist/services/team-roster.js +82 -0
- package/dist/services/team-roster.js.map +1 -0
- package/dist/services/team-store.d.ts +54 -0
- package/dist/services/team-store.d.ts.map +1 -0
- package/dist/services/team-store.js +156 -0
- package/dist/services/team-store.js.map +1 -0
- package/dist/services/trigger-log-store.d.ts +46 -0
- package/dist/services/trigger-log-store.d.ts.map +1 -0
- package/dist/services/trigger-log-store.js +132 -0
- package/dist/services/trigger-log-store.js.map +1 -0
- package/dist/services/trigger-types.d.ts +57 -0
- package/dist/services/trigger-types.d.ts.map +1 -0
- package/dist/services/trigger-types.js +28 -0
- package/dist/services/trigger-types.js.map +1 -0
- package/dist/services/webhook-key.d.ts +16 -0
- package/dist/services/webhook-key.d.ts.map +1 -0
- package/dist/services/webhook-key.js +123 -0
- package/dist/services/webhook-key.js.map +1 -0
- package/dist/services/webhook-lifecycle-extractors.d.ts +15 -0
- package/dist/services/webhook-lifecycle-extractors.d.ts.map +1 -0
- package/dist/services/webhook-lifecycle-extractors.js +59 -0
- package/dist/services/webhook-lifecycle-extractors.js.map +1 -0
- package/dist/services/webhook-lifecycle-store.d.ts +45 -0
- package/dist/services/webhook-lifecycle-store.d.ts.map +1 -0
- package/dist/services/webhook-lifecycle-store.js +159 -0
- package/dist/services/webhook-lifecycle-store.js.map +1 -0
- package/dist/setup/bot-config-editor.d.ts +8 -1
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +20 -2
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/ensure-tmux.d.ts +0 -22
- package/dist/setup/ensure-tmux.d.ts.map +1 -1
- package/dist/setup/ensure-tmux.js +25 -1
- package/dist/setup/ensure-tmux.js.map +1 -1
- package/dist/setup/verify-permissions.d.ts.map +1 -1
- package/dist/setup/verify-permissions.js +15 -1
- package/dist/setup/verify-permissions.js.map +1 -1
- package/dist/skills/definitions.d.ts +2 -0
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +178 -12
- package/dist/skills/definitions.js.map +1 -1
- package/dist/skills/installer.d.ts +34 -0
- package/dist/skills/installer.d.ts.map +1 -1
- package/dist/skills/installer.js +119 -2
- package/dist/skills/installer.js.map +1 -1
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/bot-routing.d.ts +50 -0
- package/dist/utils/bot-routing.d.ts.map +1 -1
- package/dist/utils/bot-routing.js +83 -0
- package/dist/utils/bot-routing.js.map +1 -1
- package/dist/utils/daemon-discovery.d.ts +11 -0
- package/dist/utils/daemon-discovery.d.ts.map +1 -0
- package/dist/utils/daemon-discovery.js +59 -0
- package/dist/utils/daemon-discovery.js.map +1 -0
- package/dist/utils/user-token.d.ts.map +1 -1
- package/dist/utils/user-token.js +0 -2
- package/dist/utils/user-token.js.map +1 -1
- package/dist/worker.js +198 -27
- package/dist/worker.js.map +1 -1
- package/dist/workflows/attempt-resume.d.ts.map +1 -1
- package/dist/workflows/attempt-resume.js +2 -2
- package/dist/workflows/attempt-resume.js.map +1 -1
- package/dist/workflows/definition.d.ts +412 -9
- package/dist/workflows/definition.d.ts.map +1 -1
- package/dist/workflows/definition.js +238 -3
- package/dist/workflows/definition.js.map +1 -1
- package/dist/workflows/events/payloads.d.ts +114 -11
- package/dist/workflows/events/payloads.d.ts.map +1 -1
- package/dist/workflows/events/payloads.js +46 -0
- package/dist/workflows/events/payloads.js.map +1 -1
- package/dist/workflows/events/replay.d.ts +21 -0
- package/dist/workflows/events/replay.d.ts.map +1 -1
- package/dist/workflows/events/replay.js +103 -0
- package/dist/workflows/events/replay.js.map +1 -1
- package/dist/workflows/events/schema.d.ts +1301 -606
- package/dist/workflows/events/schema.d.ts.map +1 -1
- package/dist/workflows/events/schema.js +37 -1
- package/dist/workflows/events/schema.js.map +1 -1
- package/dist/workflows/events/types.d.ts +5 -1
- package/dist/workflows/events/types.d.ts.map +1 -1
- package/dist/workflows/loader.d.ts +14 -0
- package/dist/workflows/loader.d.ts.map +1 -1
- package/dist/workflows/loader.js +27 -0
- package/dist/workflows/loader.js.map +1 -1
- package/dist/workflows/loop.js +58 -0
- package/dist/workflows/loop.js.map +1 -1
- package/dist/workflows/ops-projection.d.ts +58 -0
- package/dist/workflows/ops-projection.d.ts.map +1 -1
- package/dist/workflows/ops-projection.js +74 -0
- package/dist/workflows/ops-projection.js.map +1 -1
- package/dist/workflows/orchestrator.d.ts +65 -1
- package/dist/workflows/orchestrator.d.ts.map +1 -1
- package/dist/workflows/orchestrator.js +486 -74
- package/dist/workflows/orchestrator.js.map +1 -1
- package/dist/workflows/output-binding.d.ts +8 -1
- package/dist/workflows/output-binding.d.ts.map +1 -1
- package/dist/workflows/output-binding.js +75 -11
- package/dist/workflows/output-binding.js.map +1 -1
- package/dist/workflows/runtime.d.ts +1 -1
- package/dist/workflows/runtime.d.ts.map +1 -1
- package/dist/workflows/runtime.js +39 -4
- package/dist/workflows/runtime.js.map +1 -1
- package/dist/workflows/trigger-from-envelope.d.ts +13 -0
- package/dist/workflows/trigger-from-envelope.d.ts.map +1 -0
- package/dist/workflows/trigger-from-envelope.js +67 -0
- package/dist/workflows/trigger-from-envelope.js.map +1 -0
- package/dist/workflows/wait.d.ts +23 -2
- package/dist/workflows/wait.d.ts.map +1 -1
- package/dist/workflows/wait.js +39 -17
- package/dist/workflows/wait.js.map +1 -1
- package/package.json +1 -1
- package/dist/services/feishu-task-client.d.ts +0 -28
- package/dist/services/feishu-task-client.d.ts.map +0 -1
- package/dist/services/feishu-task-client.js +0 -123
- package/dist/services/feishu-task-client.js.map +0 -1
- package/dist/services/task-store.d.ts +0 -37
- package/dist/services/task-store.d.ts.map +0 -1
- package/dist/services/task-store.js +0 -115
- package/dist/services/task-store.js.map +0 -1
|
@@ -21,6 +21,16 @@
|
|
|
21
21
|
*
|
|
22
22
|
* One node may own at most one gate (before-gate) and one work
|
|
23
23
|
* activity in v0. After-gates and re-runs are deferred.
|
|
24
|
+
*
|
|
25
|
+
* v0.2 loop body activities are scoped by a `loop::<loopId>.<N>` segment:
|
|
26
|
+
*
|
|
27
|
+
* loop work activity: `<runId>::loop::<loopId>.<N>::work::<bodyNodeId>`
|
|
28
|
+
* loop gate activity: `<runId>::loop::<loopId>.<N>::gate::<bodyNodeId>`
|
|
29
|
+
*
|
|
30
|
+
* `<N>` is the 1-indexed iteration; `<loopId>` is the loop block's
|
|
31
|
+
* nodeId. All segments stay within `SEGMENT_RE` (allows
|
|
32
|
+
* `[A-Za-z0-9._:-]`), so existing `isValidPathSegment` / attempt-
|
|
33
|
+
* sidecar path guards continue to apply without modification.
|
|
24
34
|
* ────────────────────────────────────────────────────────────────────
|
|
25
35
|
*/
|
|
26
36
|
import { topologicalOrder, } from './definition.js';
|
|
@@ -31,6 +41,58 @@ export function gateActivityId(runId, nodeId) {
|
|
|
31
41
|
export function workActivityId(runId, nodeId) {
|
|
32
42
|
return `${runId}::work::${nodeId}`;
|
|
33
43
|
}
|
|
44
|
+
// ─── Loop iteration activity IDs (v0.2) ───────────────────────────────────
|
|
45
|
+
//
|
|
46
|
+
// See /tmp/wf-loop-v02.md §4.2 and the top-of-file ASCII spec.
|
|
47
|
+
//
|
|
48
|
+
// Iteration `N` is 1-indexed. We refuse to encode `N < 1` so callers
|
|
49
|
+
// never accidentally emit `loop::foo.0` ids (the iteration counter is a
|
|
50
|
+
// real loop-state position, not a placeholder).
|
|
51
|
+
export function loopWorkActivityId(runId, loopId, iteration, bodyNodeId) {
|
|
52
|
+
if (!Number.isInteger(iteration) || iteration < 1) {
|
|
53
|
+
throw new Error(`loopWorkActivityId: iteration must be a positive integer (got ${iteration})`);
|
|
54
|
+
}
|
|
55
|
+
return `${runId}::loop::${loopId}.${iteration}::work::${bodyNodeId}`;
|
|
56
|
+
}
|
|
57
|
+
export function loopGateActivityId(runId, loopId, iteration, bodyNodeId) {
|
|
58
|
+
if (!Number.isInteger(iteration) || iteration < 1) {
|
|
59
|
+
throw new Error(`loopGateActivityId: iteration must be a positive integer (got ${iteration})`);
|
|
60
|
+
}
|
|
61
|
+
return `${runId}::loop::${loopId}.${iteration}::gate::${bodyNodeId}`;
|
|
62
|
+
}
|
|
63
|
+
const PLAIN_RE = /^([^:]+(?:::?[^:]+)*?)::(work|gate)::([A-Za-z0-9_.-]+)$/;
|
|
64
|
+
const LOOP_RE = /^(.+)::loop::([A-Za-z0-9_.-]+)\.(\d+)::(work|gate)::([A-Za-z0-9_.-]+)$/;
|
|
65
|
+
export function parseActivityId(s) {
|
|
66
|
+
// Loop form first — the `::loop::` segment is unambiguous and would
|
|
67
|
+
// also accidentally satisfy a greedy plain match if we tried plain
|
|
68
|
+
// first (`runId` would absorb `::loop::<id>.<N>::work`).
|
|
69
|
+
const loopMatch = LOOP_RE.exec(s);
|
|
70
|
+
if (loopMatch) {
|
|
71
|
+
const [, runId, loopId, iterStr, activityKind, nodeId] = loopMatch;
|
|
72
|
+
const iteration = Number(iterStr);
|
|
73
|
+
if (!Number.isFinite(iteration) || iteration < 1)
|
|
74
|
+
return undefined;
|
|
75
|
+
return {
|
|
76
|
+
kind: 'loop',
|
|
77
|
+
runId,
|
|
78
|
+
loopId,
|
|
79
|
+
iteration,
|
|
80
|
+
activityKind: activityKind,
|
|
81
|
+
nodeId,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const plainMatch = PLAIN_RE.exec(s);
|
|
85
|
+
if (plainMatch) {
|
|
86
|
+
const [, runId, activityKind, nodeId] = plainMatch;
|
|
87
|
+
return {
|
|
88
|
+
kind: 'plain',
|
|
89
|
+
runId,
|
|
90
|
+
activityKind: activityKind,
|
|
91
|
+
nodeId,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
34
96
|
// ─── Decision function ───────────────────────────────────────────────────
|
|
35
97
|
/**
|
|
36
98
|
* Pure decision function. Read-only — never throws on graph cycles
|
|
@@ -64,110 +126,309 @@ export function decideNextActions(snapshot, def) {
|
|
|
64
126
|
const actions = [];
|
|
65
127
|
const runId = snapshot.run.runId;
|
|
66
128
|
const order = topologicalOrder(def);
|
|
129
|
+
// v0.2: compute loop body membership once so the top-level scheduler
|
|
130
|
+
// skips body nodes (they're dispatched by the loop branch only).
|
|
131
|
+
const bodyOwner = buildBodyOwnerMap(def);
|
|
67
132
|
let failedNodeId;
|
|
68
133
|
let pendingCount = 0;
|
|
134
|
+
// ─── Loop lifecycle + body dispatch pass (v0.2) ──────────────────────
|
|
135
|
+
//
|
|
136
|
+
// For each loop block in topo order, this pass owns:
|
|
137
|
+
// 1. emitting `startLoop` when the loop's `depends` first go green
|
|
138
|
+
// 2. emitting `startLoopIteration` to open each iteration
|
|
139
|
+
// 3. dispatching body activities under loop-iteration activityIds
|
|
140
|
+
// 4. emitting `finishLoopIteration` once the terminator decision
|
|
141
|
+
// attempt settles (approve or reject)
|
|
142
|
+
// 5. emitting `finishLoop` once iteration loop closes (approved /
|
|
143
|
+
// max-iterations-exceeded / non-terminator body failure / decision
|
|
144
|
+
// humanGate timeout)
|
|
145
|
+
//
|
|
146
|
+
// Per codex round 3: lifecycle actions are returned as the SOLE action
|
|
147
|
+
// of the tick so event ordering — `loopStarted` → `loopIterationStarted`
|
|
148
|
+
// → body attempts — is deterministic and never interleaves with body
|
|
149
|
+
// dispatches. Body dispatches batch up only when no lifecycle action
|
|
150
|
+
// fires this tick.
|
|
69
151
|
for (const nodeId of order) {
|
|
70
152
|
const node = def.nodes[nodeId];
|
|
71
|
-
|
|
72
|
-
// Already settled at the node level — nothing for us to advance.
|
|
73
|
-
if (nstatus === 'succeeded' || nstatus === 'skipped' || nstatus === 'cancelled') {
|
|
153
|
+
if (node.type !== 'loop')
|
|
74
154
|
continue;
|
|
155
|
+
const loopId = nodeId;
|
|
156
|
+
const loopState = snapshot.loops.get(loopId);
|
|
157
|
+
const depsOk = (node.depends ?? []).every((dep) => snapshot.nodes.get(dep)?.status === 'succeeded');
|
|
158
|
+
// (1) Loop not yet entered.
|
|
159
|
+
if (!loopState) {
|
|
160
|
+
if (!depsOk) {
|
|
161
|
+
pendingCount++;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
return [{ kind: 'startLoop', loopId, maxIterations: node.maxIterations }];
|
|
75
165
|
}
|
|
76
|
-
|
|
77
|
-
|
|
166
|
+
// Loop already finalized — nothing else to do.
|
|
167
|
+
if (loopState.status !== 'running')
|
|
78
168
|
continue;
|
|
169
|
+
// (2) Loop started but no iteration opened yet.
|
|
170
|
+
if (loopState.iteration === 0) {
|
|
171
|
+
return [
|
|
172
|
+
{ kind: 'startLoopIteration', loopId, iteration: 1, prevResolution: 'initial' },
|
|
173
|
+
];
|
|
79
174
|
}
|
|
80
|
-
//
|
|
81
|
-
const
|
|
82
|
-
|
|
175
|
+
// Active iteration in progress.
|
|
176
|
+
const currentIter = loopState.iteration;
|
|
177
|
+
const iterState = loopState.iterations[currentIter - 1];
|
|
178
|
+
if (!iterState) {
|
|
83
179
|
pendingCount++;
|
|
84
|
-
continue;
|
|
180
|
+
continue; // anomalous — shouldn't happen, skip safely
|
|
85
181
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
182
|
+
// (4) Current iteration already has a settled resolution:
|
|
183
|
+
if (iterState.status === 'approved') {
|
|
184
|
+
const outputRef = computeLoopOutputRef(snapshot, runId, node, loopId, currentIter);
|
|
185
|
+
return [
|
|
186
|
+
{
|
|
187
|
+
kind: 'finishLoop',
|
|
188
|
+
loopId,
|
|
189
|
+
finalIteration: currentIter,
|
|
190
|
+
resolution: 'approved',
|
|
191
|
+
outputRef,
|
|
192
|
+
},
|
|
193
|
+
];
|
|
194
|
+
}
|
|
195
|
+
if (iterState.status === 'rejected') {
|
|
196
|
+
if (currentIter < loopState.maxIterations) {
|
|
197
|
+
return [
|
|
198
|
+
{
|
|
199
|
+
kind: 'startLoopIteration',
|
|
200
|
+
loopId,
|
|
201
|
+
iteration: currentIter + 1,
|
|
202
|
+
prevResolution: 'rejected',
|
|
203
|
+
},
|
|
204
|
+
];
|
|
100
205
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
kind: '
|
|
104
|
-
|
|
105
|
-
|
|
206
|
+
return [
|
|
207
|
+
{
|
|
208
|
+
kind: 'finishLoop',
|
|
209
|
+
loopId,
|
|
210
|
+
finalIteration: currentIter,
|
|
211
|
+
resolution: 'max-iterations-exceeded',
|
|
212
|
+
errorCode: 'LoopMaxIterationsExceeded',
|
|
106
213
|
errorClass: 'userFault',
|
|
107
|
-
}
|
|
214
|
+
},
|
|
215
|
+
];
|
|
216
|
+
}
|
|
217
|
+
if (iterState.status === 'failed' || iterState.status === 'cancelled') {
|
|
218
|
+
// Non-terminator failure already finalized this iteration; close
|
|
219
|
+
// the loop block with `body-failed` resolution (codex Step 3
|
|
220
|
+
// review Medium). `cancelled` is reserved for user-initiated
|
|
221
|
+
// cancel; `body-failed` distinguishes "this loop died because a
|
|
222
|
+
// body node failed" from "user clicked cancel".
|
|
223
|
+
return [
|
|
224
|
+
{
|
|
225
|
+
kind: 'finishLoop',
|
|
226
|
+
loopId,
|
|
227
|
+
finalIteration: currentIter,
|
|
228
|
+
resolution: 'body-failed',
|
|
229
|
+
errorCode: 'LoopBodyFailed',
|
|
230
|
+
errorClass: 'fatal',
|
|
231
|
+
},
|
|
232
|
+
];
|
|
233
|
+
}
|
|
234
|
+
// (3) Iteration is `running` — dispatch body / terminator.
|
|
235
|
+
//
|
|
236
|
+
// Step through body nodes in topo order *within* this iteration.
|
|
237
|
+
// Use a small per-iteration helper map: bodyId → succeeded? so we
|
|
238
|
+
// can resolve intra-body deps without touching the v0.1 node-level
|
|
239
|
+
// status (which never advances for body nodes in v0.2).
|
|
240
|
+
const bodySet = new Set(node.body);
|
|
241
|
+
const bodyDone = new Map();
|
|
242
|
+
let bodyFailureFinish;
|
|
243
|
+
const iterDispatch = [];
|
|
244
|
+
for (const bodyId of orderForBody(order, bodySet)) {
|
|
245
|
+
const bodyNode = def.nodes[bodyId];
|
|
246
|
+
// Intra-body dep check: all body-side deps must have a succeeded
|
|
247
|
+
// activity in *this* iteration; loop-external deps were guaranteed
|
|
248
|
+
// already by the loop block's own `depends` gate.
|
|
249
|
+
const intraDepsOk = (bodyNode.depends ?? [])
|
|
250
|
+
.filter((d) => bodySet.has(d))
|
|
251
|
+
.every((d) => bodyDone.get(d) === true);
|
|
252
|
+
if (!intraDepsOk) {
|
|
253
|
+
pendingCount++;
|
|
108
254
|
continue;
|
|
109
255
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
256
|
+
const isTerminator = bodyId === node.terminate.node;
|
|
257
|
+
const bodyGateActId = loopGateActivityId(runId, loopId, currentIter, bodyId);
|
|
258
|
+
const bodyWorkActId = loopWorkActivityId(runId, loopId, currentIter, bodyId);
|
|
259
|
+
const advance = decideNodeAdvancement(snapshot, bodyNode, bodyId, bodyGateActId, bodyWorkActId);
|
|
260
|
+
if (advance.isSucceeded) {
|
|
261
|
+
bodyDone.set(bodyId, true);
|
|
262
|
+
if (isTerminator) {
|
|
263
|
+
// Terminator settled — read its wait resolution out of the
|
|
264
|
+
// activity attempt, then return `finishLoopIteration` as the
|
|
265
|
+
// sole action this tick so the iteration advances cleanly.
|
|
266
|
+
const decisionAct = snapshot.activities.get(bodyGateActId);
|
|
267
|
+
const lastAt = decisionAct?.attempts[decisionAct.attempts.length - 1];
|
|
268
|
+
const wait = lastAt?.wait?.resolution;
|
|
269
|
+
if (wait &&
|
|
270
|
+
wait.kind === 'resolved' &&
|
|
271
|
+
(wait.resolution === 'approved' || wait.resolution === 'rejected')) {
|
|
272
|
+
return [
|
|
273
|
+
{
|
|
274
|
+
kind: 'finishLoopIteration',
|
|
275
|
+
loopId,
|
|
276
|
+
iteration: currentIter,
|
|
277
|
+
resolution: wait.resolution,
|
|
278
|
+
decisionActivityId: bodyGateActId,
|
|
279
|
+
waitResolvedEventId: wait.eventId,
|
|
280
|
+
by: wait.by,
|
|
281
|
+
comment: wait.comment,
|
|
282
|
+
},
|
|
283
|
+
];
|
|
284
|
+
}
|
|
285
|
+
if (wait && wait.kind === 'deadlineExceeded') {
|
|
286
|
+
return [
|
|
287
|
+
{
|
|
288
|
+
kind: 'finishLoopIteration',
|
|
289
|
+
loopId,
|
|
290
|
+
iteration: currentIter,
|
|
291
|
+
resolution: 'rejected',
|
|
292
|
+
decisionActivityId: bodyGateActId,
|
|
293
|
+
waitResolvedEventId: wait.eventId,
|
|
294
|
+
by: 'system',
|
|
295
|
+
timedOut: true,
|
|
296
|
+
},
|
|
297
|
+
];
|
|
298
|
+
}
|
|
299
|
+
// Decision attempt succeeded but no resolution found — defer.
|
|
300
|
+
pendingCount++;
|
|
301
|
+
}
|
|
113
302
|
continue;
|
|
114
303
|
}
|
|
115
|
-
|
|
304
|
+
if (advance.isFailed) {
|
|
305
|
+
if (isTerminator) {
|
|
306
|
+
// Terminator humanGate timed out / failed → finish the loop
|
|
307
|
+
// with `timeout` + WaitDeadlineExceeded (codex Step 3 review
|
|
308
|
+
// Medium — schema invariant requires this errorCode pairing).
|
|
309
|
+
bodyFailureFinish = {
|
|
310
|
+
kind: 'finishLoop',
|
|
311
|
+
loopId,
|
|
312
|
+
finalIteration: currentIter,
|
|
313
|
+
resolution: 'timeout',
|
|
314
|
+
errorCode: 'WaitDeadlineExceeded',
|
|
315
|
+
errorClass: 'userFault',
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
// Non-terminator body node failed (subagent crash / hostExecutor
|
|
320
|
+
// error / non-terminator humanGate.reject = fail-run per
|
|
321
|
+
// /tmp/wf-loop-v02.md §10.8) → close as `body-failed`.
|
|
322
|
+
bodyFailureFinish = {
|
|
323
|
+
kind: 'finishLoop',
|
|
324
|
+
loopId,
|
|
325
|
+
finalIteration: currentIter,
|
|
326
|
+
resolution: 'body-failed',
|
|
327
|
+
errorCode: 'LoopBodyFailed',
|
|
328
|
+
errorClass: 'fatal',
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
break; // stop iterating body; we'll close the loop instead
|
|
332
|
+
}
|
|
333
|
+
// Not yet succeeded / failed — accumulate dispatch actions.
|
|
334
|
+
iterDispatch.push(...advance.actions);
|
|
335
|
+
pendingCount += advance.actions.length === 0 ? 1 : 0;
|
|
116
336
|
}
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
337
|
+
if (bodyFailureFinish) {
|
|
338
|
+
return [bodyFailureFinish];
|
|
339
|
+
}
|
|
340
|
+
// Body dispatches accumulate into the outer `actions` array; the
|
|
341
|
+
// legacy plain-node pass below will also push into it, so a single
|
|
342
|
+
// tick can dispatch multiple body nodes + plain nodes together.
|
|
343
|
+
// Lifecycle actions never reach this branch (they early-return
|
|
344
|
+
// above).
|
|
345
|
+
for (const a of iterDispatch)
|
|
346
|
+
actions.push(a);
|
|
347
|
+
}
|
|
348
|
+
// ─── Loop terminal propagation ────────────────────────────────────────
|
|
349
|
+
//
|
|
350
|
+
// After the loop branch may have emitted `finishLoop`, the next tick
|
|
351
|
+
// sees `loopState.status` settled but the legacy node-level state
|
|
352
|
+
// machine doesn't know about it. Propagate failed / cancelled loop
|
|
353
|
+
// blocks into `failedNodeId` so the actions.length===0 sweep below
|
|
354
|
+
// can emit `completeRunFailed`. Succeeded loop blocks expose their
|
|
355
|
+
// projected output via `outputs[workActivityId(runId, loopId)]` and
|
|
356
|
+
// are handled naturally by the sink sweep.
|
|
357
|
+
for (const [loopId, loopState] of snapshot.loops) {
|
|
358
|
+
if (loopState.status === 'failed' || loopState.status === 'cancelled') {
|
|
359
|
+
failedNodeId = failedNodeId ?? loopId;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
// ─── Plain (non-loop, non-body) node pass ────────────────────────────
|
|
363
|
+
//
|
|
364
|
+
// Same logic as v0.1: dispatch gate → dispatch work → settle node.
|
|
365
|
+
// Skips loop blocks (already handled) + decision nodes (only valid in
|
|
366
|
+
// loop body) + body nodes (dispatched only by the loop branch above).
|
|
367
|
+
for (const nodeId of order) {
|
|
368
|
+
const node = def.nodes[nodeId];
|
|
369
|
+
if (node.type === 'loop')
|
|
370
|
+
continue;
|
|
371
|
+
if (node.type === 'decision')
|
|
372
|
+
continue; // validateLoopBlocks guarantees in-body
|
|
373
|
+
if (bodyOwner.has(nodeId))
|
|
374
|
+
continue; // dispatched by loop branch
|
|
375
|
+
const nstatus = snapshot.nodes.get(nodeId)?.status ?? 'idle';
|
|
376
|
+
if (nstatus === 'succeeded' || nstatus === 'skipped' || nstatus === 'cancelled') {
|
|
125
377
|
continue;
|
|
126
378
|
}
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
379
|
+
if (nstatus === 'failed') {
|
|
380
|
+
failedNodeId = failedNodeId ?? nodeId;
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
// Dependencies gate dispatch. Loop blocks are treated as "succeeded"
|
|
384
|
+
// for the purpose of downstream deps when their snapshot status is
|
|
385
|
+
// 'succeeded'. This is how `${review-loop.output.x}` and direct
|
|
386
|
+
// body-node refs become resolvable for downstream plain nodes.
|
|
387
|
+
const depsOk = (node.depends ?? []).every((dep) => {
|
|
388
|
+
const depNode = def.nodes[dep];
|
|
389
|
+
if (depNode?.type === 'loop') {
|
|
390
|
+
return snapshot.loops.get(dep)?.status === 'succeeded';
|
|
139
391
|
}
|
|
392
|
+
return snapshot.nodes.get(dep)?.status === 'succeeded';
|
|
393
|
+
});
|
|
394
|
+
if (!depsOk) {
|
|
395
|
+
pendingCount++;
|
|
140
396
|
continue;
|
|
141
397
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
actions.push({
|
|
149
|
-
kind: 'completeNodeFailed',
|
|
150
|
-
nodeId,
|
|
151
|
-
lastActivityId: workActId,
|
|
152
|
-
errorClass,
|
|
153
|
-
});
|
|
398
|
+
const gateActId = gateActivityId(runId, nodeId);
|
|
399
|
+
const workActId = workActivityId(runId, nodeId);
|
|
400
|
+
const advance = decideNodeAdvancement(snapshot, node, nodeId, gateActId, workActId);
|
|
401
|
+
if (advance.isSucceeded) {
|
|
402
|
+
for (const a of advance.actions)
|
|
403
|
+
actions.push(a);
|
|
154
404
|
continue;
|
|
155
405
|
}
|
|
156
|
-
|
|
157
|
-
|
|
406
|
+
if (advance.isFailed) {
|
|
407
|
+
for (const a of advance.actions)
|
|
408
|
+
actions.push(a);
|
|
409
|
+
// completeNodeFailed action records nodeId in actions; the
|
|
410
|
+
// downstream sweep uses node.status='failed' from the next
|
|
411
|
+
// replay to fail the run.
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
for (const a of advance.actions)
|
|
415
|
+
actions.push(a);
|
|
416
|
+
if (advance.actions.length === 0)
|
|
417
|
+
pendingCount++;
|
|
158
418
|
}
|
|
159
419
|
if (actions.length === 0) {
|
|
160
420
|
if (failedNodeId) {
|
|
161
|
-
// Fail-fast: a node terminal-failed. Any pending downstream nodes
|
|
162
|
-
// are stuck on the failed dep and will never advance; in-flight
|
|
163
|
-
// peer nodes are caller's problem to cancel-fanout if they want.
|
|
164
421
|
actions.push({ kind: 'completeRunFailed', failedNodeId });
|
|
165
422
|
}
|
|
166
423
|
else if (pendingCount === 0) {
|
|
167
424
|
const sinks = findSinks(def);
|
|
168
425
|
if (sinks.length === 1) {
|
|
169
426
|
const sinkId = sinks[0];
|
|
170
|
-
const
|
|
427
|
+
const sinkNode = def.nodes[sinkId];
|
|
428
|
+
const sinkActId = workActivityId(runId, sinkId);
|
|
429
|
+
const sinkOutput = sinkNode?.type === 'loop'
|
|
430
|
+
? snapshot.outputs.get(sinkActId) // loopFinished projection (codex Step 2)
|
|
431
|
+
: snapshot.outputs.get(sinkActId);
|
|
171
432
|
if (sinkOutput) {
|
|
172
433
|
actions.push({
|
|
173
434
|
kind: 'completeRunSucceeded',
|
|
@@ -176,22 +437,173 @@ export function decideNextActions(snapshot, def) {
|
|
|
176
437
|
});
|
|
177
438
|
}
|
|
178
439
|
}
|
|
179
|
-
// Multi-sink: caller composes the run output (out of v0 scope).
|
|
180
440
|
}
|
|
181
441
|
}
|
|
182
442
|
return actions;
|
|
183
443
|
}
|
|
444
|
+
/**
|
|
445
|
+
* Per-node advancement decision used by both the top-level scheduler
|
|
446
|
+
* (plain nodes) and the v0.2 loop branch (body / decision nodes). The
|
|
447
|
+
* caller supplies the gate and work activityIds so the same logic
|
|
448
|
+
* applies to plain `runId::work::node` ids and loop iteration
|
|
449
|
+
* `runId::loop::loopId.N::work::node` ids without leaking the
|
|
450
|
+
* activityId convention into this helper.
|
|
451
|
+
*
|
|
452
|
+
* Returns the actions the caller should emit plus a small status
|
|
453
|
+
* triplet — exactly one of `isSucceeded` / `isFailed` is true when
|
|
454
|
+
* the node has reached its terminal; otherwise the call is "pending"
|
|
455
|
+
* (in-flight) and the returned actions are dispatch instructions for
|
|
456
|
+
* gate/work that haven't yet been emitted.
|
|
457
|
+
*/
|
|
458
|
+
function decideNodeAdvancement(snapshot, node, nodeId, gateActId, workActId) {
|
|
459
|
+
const actions = [];
|
|
460
|
+
// Decision node: gate-only. Both reject and approve resolve to
|
|
461
|
+
// `activitySucceeded` per wait.ts decision-mode (see N2 in
|
|
462
|
+
// /tmp/wf-loop-v02.md §4.3); only humanGate timeout produces a
|
|
463
|
+
// failed activity.
|
|
464
|
+
if (node.type === 'decision') {
|
|
465
|
+
const gateAct = snapshot.activities.get(gateActId);
|
|
466
|
+
if (!gateAct) {
|
|
467
|
+
actions.push({
|
|
468
|
+
kind: 'dispatchGate',
|
|
469
|
+
nodeId,
|
|
470
|
+
activityId: gateActId,
|
|
471
|
+
humanGate: node.humanGate,
|
|
472
|
+
});
|
|
473
|
+
return { actions, isSucceeded: false, isFailed: false };
|
|
474
|
+
}
|
|
475
|
+
if (gateAct.status === 'succeeded') {
|
|
476
|
+
return { actions, isSucceeded: true, isFailed: false };
|
|
477
|
+
}
|
|
478
|
+
if (gateAct.status === 'failed' || gateAct.status === 'timedOut') {
|
|
479
|
+
return { actions, isSucceeded: false, isFailed: true };
|
|
480
|
+
}
|
|
481
|
+
return { actions, isSucceeded: false, isFailed: false };
|
|
482
|
+
}
|
|
483
|
+
// Loop blocks are not handled by this helper.
|
|
484
|
+
if (node.type === 'loop') {
|
|
485
|
+
return { actions, isSucceeded: false, isFailed: false };
|
|
486
|
+
}
|
|
487
|
+
const gateAct = snapshot.activities.get(gateActId);
|
|
488
|
+
const workAct = snapshot.activities.get(workActId);
|
|
489
|
+
if (node.humanGate) {
|
|
490
|
+
if (!gateAct) {
|
|
491
|
+
actions.push({
|
|
492
|
+
kind: 'dispatchGate',
|
|
493
|
+
nodeId,
|
|
494
|
+
activityId: gateActId,
|
|
495
|
+
humanGate: node.humanGate,
|
|
496
|
+
});
|
|
497
|
+
return { actions, isSucceeded: false, isFailed: false };
|
|
498
|
+
}
|
|
499
|
+
if (gateAct.status === 'failed' || gateAct.status === 'timedOut') {
|
|
500
|
+
actions.push({
|
|
501
|
+
kind: 'completeNodeFailed',
|
|
502
|
+
nodeId,
|
|
503
|
+
lastActivityId: gateActId,
|
|
504
|
+
errorClass: 'userFault',
|
|
505
|
+
});
|
|
506
|
+
return { actions, isSucceeded: false, isFailed: true };
|
|
507
|
+
}
|
|
508
|
+
if (gateAct.status !== 'succeeded') {
|
|
509
|
+
// gate in-flight — caller treats this as pending
|
|
510
|
+
return { actions, isSucceeded: false, isFailed: false };
|
|
511
|
+
}
|
|
512
|
+
// gate cleared → fall through to work
|
|
513
|
+
}
|
|
514
|
+
if (!workAct) {
|
|
515
|
+
actions.push({
|
|
516
|
+
kind: 'dispatchWork',
|
|
517
|
+
nodeId,
|
|
518
|
+
activityId: workActId,
|
|
519
|
+
node,
|
|
520
|
+
});
|
|
521
|
+
return { actions, isSucceeded: false, isFailed: false };
|
|
522
|
+
}
|
|
523
|
+
if (workAct.status === 'succeeded') {
|
|
524
|
+
const output = snapshot.outputs.get(workActId);
|
|
525
|
+
if (output) {
|
|
526
|
+
actions.push({
|
|
527
|
+
kind: 'completeNodeSucceeded',
|
|
528
|
+
nodeId,
|
|
529
|
+
lastActivityId: workActId,
|
|
530
|
+
outputRef: output,
|
|
531
|
+
});
|
|
532
|
+
return { actions, isSucceeded: true, isFailed: false };
|
|
533
|
+
}
|
|
534
|
+
return { actions, isSucceeded: false, isFailed: false };
|
|
535
|
+
}
|
|
536
|
+
if (workAct.status === 'failed' || workAct.status === 'timedOut') {
|
|
537
|
+
const errorClass = workAct.status === 'timedOut' ? 'retryable' : deriveErrorClass(workAct);
|
|
538
|
+
actions.push({
|
|
539
|
+
kind: 'completeNodeFailed',
|
|
540
|
+
nodeId,
|
|
541
|
+
lastActivityId: workActId,
|
|
542
|
+
errorClass,
|
|
543
|
+
});
|
|
544
|
+
return { actions, isSucceeded: false, isFailed: true };
|
|
545
|
+
}
|
|
546
|
+
// running / waiting / acquired / effectAttempting — pending.
|
|
547
|
+
return { actions, isSucceeded: false, isFailed: false };
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Build `bodyNodeId → owningLoopId` map for fast carve-out lookups.
|
|
551
|
+
* Mirrors `validateLoopBlocks`'s body collection but built every tick
|
|
552
|
+
* because the orchestrator is a pure function and doesn't carry state.
|
|
553
|
+
*/
|
|
554
|
+
function buildBodyOwnerMap(def) {
|
|
555
|
+
const owner = new Map();
|
|
556
|
+
for (const [id, node] of Object.entries(def.nodes)) {
|
|
557
|
+
if (node.type !== 'loop')
|
|
558
|
+
continue;
|
|
559
|
+
for (const bodyId of node.body)
|
|
560
|
+
owner.set(bodyId, id);
|
|
561
|
+
}
|
|
562
|
+
return owner;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Filter a workflow-level topological order down to body nodes only,
|
|
566
|
+
* preserving the global order. Used to dispatch body nodes inside an
|
|
567
|
+
* active loop iteration in deterministic order.
|
|
568
|
+
*/
|
|
569
|
+
function orderForBody(allOrder, bodySet) {
|
|
570
|
+
return allOrder.filter((id) => bodySet.has(id));
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Resolve `loop.output.from` to the OutputRef of the body node's
|
|
574
|
+
* latest successful iteration so `finishLoop` can carry it forward.
|
|
575
|
+
* Returns `undefined` if the loop did not declare `output.from`, or if
|
|
576
|
+
* the body node hasn't produced a succeeded output in `iteration` yet
|
|
577
|
+
* (which shouldn't happen if the terminator already approved — but
|
|
578
|
+
* defensive against partial replay state).
|
|
579
|
+
*/
|
|
580
|
+
function computeLoopOutputRef(snapshot, runId, loopNode, loopId, iteration) {
|
|
581
|
+
const from = loopNode.output?.from;
|
|
582
|
+
if (!from)
|
|
583
|
+
return undefined;
|
|
584
|
+
const bodyWorkActId = loopWorkActivityId(runId, loopId, iteration, from);
|
|
585
|
+
return snapshot.outputs.get(bodyWorkActId);
|
|
586
|
+
}
|
|
184
587
|
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
185
588
|
function deriveErrorClass(activity) {
|
|
186
589
|
const last = activity.attempts[activity.attempts.length - 1];
|
|
187
590
|
return last?.error?.errorClass ?? 'fatal';
|
|
188
591
|
}
|
|
189
592
|
function findSinks(def) {
|
|
593
|
+
const bodyOwner = buildBodyOwnerMap(def);
|
|
594
|
+
// Only consider top-level (non-body) nodes when computing sinks. Body
|
|
595
|
+
// nodes are dispatched by their owning loop block; the outside view of
|
|
596
|
+
// a loop is "the loop block itself produces output" so body nodes must
|
|
597
|
+
// never count as workflow-level sinks even if no peer depends on them
|
|
598
|
+
// directly. (`reviewDecision` is the canonical example — nothing
|
|
599
|
+
// outside the loop depends on it, but it's structurally internal.)
|
|
190
600
|
const referenced = new Set();
|
|
191
|
-
for (const node of Object.
|
|
601
|
+
for (const [id, node] of Object.entries(def.nodes)) {
|
|
602
|
+
if (bodyOwner.has(id))
|
|
603
|
+
continue;
|
|
192
604
|
for (const dep of node.depends ?? [])
|
|
193
605
|
referenced.add(dep);
|
|
194
606
|
}
|
|
195
|
-
return Object.keys(def.nodes).filter((id) => !referenced.has(id));
|
|
607
|
+
return Object.keys(def.nodes).filter((id) => !bodyOwner.has(id) && !referenced.has(id));
|
|
196
608
|
}
|
|
197
609
|
//# sourceMappingURL=orchestrator.js.map
|