@revisium/orchestrator 0.0.0 → 0.1.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -1
- package/control-plane/bootstrap.config.json +104 -2
- package/control-plane/default-playbook/catalog/pipelines.json +657 -0
- package/control-plane/default-playbook/catalog/roles.json +65 -0
- package/control-plane/default-playbook/package.json +5 -0
- package/control-plane/default-playbook/playbook.json +13 -0
- package/control-plane/default-playbook/prompts/analyst.md +29 -0
- package/control-plane/default-playbook/prompts/developer.md +26 -0
- package/control-plane/default-playbook/prompts/integrator.md +20 -0
- package/control-plane/default-playbook/prompts/orchestrator.md +23 -0
- package/control-plane/default-playbook/prompts/reviewer.md +28 -0
- package/control-plane/default-playbook/prompts/triager.md +51 -0
- package/control-plane/default-playbook/prompts/watcher.md +24 -0
- package/dist/api/graphql-api/filters/agent-observability-exception.filter.js +24 -0
- package/dist/api/graphql-api/filters/agent-observability-exception.filter.js.map +1 -0
- package/dist/api/graphql-api/filters/graphql-validation-exception.filter.js +36 -0
- package/dist/api/graphql-api/filters/graphql-validation-exception.filter.js.map +1 -0
- package/dist/api/graphql-api/graphql-api.module.js +77 -0
- package/dist/api/graphql-api/graphql-api.module.js.map +1 -0
- package/dist/api/graphql-api/graphql-ws/agent-observability-subscription-bridge.service.js +296 -0
- package/dist/api/graphql-api/graphql-ws/agent-observability-subscription-bridge.service.js.map +1 -0
- package/dist/api/graphql-api/graphql-ws/agent-observability-subscription-mappers.js +64 -0
- package/dist/api/graphql-api/graphql-ws/agent-observability-subscription-mappers.js.map +1 -0
- package/dist/api/graphql-api/graphql-ws/constants.js +11 -0
- package/dist/api/graphql-api/graphql-ws/constants.js.map +1 -0
- package/dist/api/graphql-api/graphql-ws/pubsub.module.js +32 -0
- package/dist/api/graphql-api/graphql-ws/pubsub.module.js.map +1 -0
- package/dist/api/graphql-api/graphql-ws/run-progress-subscription-poller.service.js +101 -0
- package/dist/api/graphql-api/graphql-ws/run-progress-subscription-poller.service.js.map +1 -0
- package/dist/api/graphql-api/graphql-ws/subscription-bridge.service.js +115 -0
- package/dist/api/graphql-api/graphql-ws/subscription-bridge.service.js.map +1 -0
- package/dist/api/graphql-api/graphql-ws/subscription-mappers.js +85 -0
- package/dist/api/graphql-api/graphql-ws/subscription-mappers.js.map +1 -0
- package/dist/api/graphql-api/graphql-ws/ws.js +22 -0
- package/dist/api/graphql-api/graphql-ws/ws.js.map +1 -0
- package/dist/api/graphql-api/inbox/inbox-subscription.resolver.js +56 -0
- package/dist/api/graphql-api/inbox/inbox-subscription.resolver.js.map +1 -0
- package/dist/api/graphql-api/inbox/inbox.resolver.js +125 -0
- package/dist/api/graphql-api/inbox/inbox.resolver.js.map +1 -0
- package/dist/api/graphql-api/inbox/inputs/answer-question.input.js +33 -0
- package/dist/api/graphql-api/inbox/inputs/answer-question.input.js.map +1 -0
- package/dist/api/graphql-api/inbox/inputs/gate-decision.input.js +27 -0
- package/dist/api/graphql-api/inbox/inputs/gate-decision.input.js.map +1 -0
- package/dist/api/graphql-api/inbox/inputs/list-inbox.input.js +28 -0
- package/dist/api/graphql-api/inbox/inputs/list-inbox.input.js.map +1 -0
- package/dist/api/graphql-api/inbox/inputs/resolve-inbox-item.input.js +38 -0
- package/dist/api/graphql-api/inbox/inputs/resolve-inbox-item.input.js.map +1 -0
- package/dist/api/graphql-api/inbox/model/gate-risk.model.js +53 -0
- package/dist/api/graphql-api/inbox/model/gate-risk.model.js.map +1 -0
- package/dist/api/graphql-api/inbox/model/inbox-connection.model.js +16 -0
- package/dist/api/graphql-api/inbox/model/inbox-connection.model.js.map +1 -0
- package/dist/api/graphql-api/inbox/model/inbox-item.model.js +88 -0
- package/dist/api/graphql-api/inbox/model/inbox-item.model.js.map +1 -0
- package/dist/api/graphql-api/inbox/model/inbox-resolution.model.js +48 -0
- package/dist/api/graphql-api/inbox/model/inbox-resolution.model.js.map +1 -0
- package/dist/api/graphql-api/method/inputs/list-method.input.js +15 -0
- package/dist/api/graphql-api/method/inputs/list-method.input.js.map +1 -0
- package/dist/api/graphql-api/method/method.resolver.js +90 -0
- package/dist/api/graphql-api/method/method.resolver.js.map +1 -0
- package/dist/api/graphql-api/method/model/alternative-role-group.model.js +32 -0
- package/dist/api/graphql-api/method/model/alternative-role-group.model.js.map +1 -0
- package/dist/api/graphql-api/method/model/pipeline-connection.model.js +16 -0
- package/dist/api/graphql-api/method/model/pipeline-connection.model.js.map +1 -0
- package/dist/api/graphql-api/method/model/pipeline.model.js +69 -0
- package/dist/api/graphql-api/method/model/pipeline.model.js.map +1 -0
- package/dist/api/graphql-api/method/model/playbook-connection.model.js +16 -0
- package/dist/api/graphql-api/method/model/playbook-connection.model.js.map +1 -0
- package/dist/api/graphql-api/method/model/playbook.model.js +47 -0
- package/dist/api/graphql-api/method/model/playbook.model.js.map +1 -0
- package/dist/api/graphql-api/method/model/role-connection.model.js +16 -0
- package/dist/api/graphql-api/method/model/role-connection.model.js.map +1 -0
- package/dist/api/graphql-api/method/model/role.model.js +98 -0
- package/dist/api/graphql-api/method/model/role.model.js.map +1 -0
- package/dist/api/graphql-api/pr/inputs/pr-readiness.input.js +52 -0
- package/dist/api/graphql-api/pr/inputs/pr-readiness.input.js.map +1 -0
- package/dist/api/graphql-api/pr/model/pr-readiness.model.js +403 -0
- package/dist/api/graphql-api/pr/model/pr-readiness.model.js.map +1 -0
- package/dist/api/graphql-api/pr/pr.resolver.js +76 -0
- package/dist/api/graphql-api/pr/pr.resolver.js.map +1 -0
- package/dist/api/graphql-api/registerGraphqlEnums.js +9 -0
- package/dist/api/graphql-api/registerGraphqlEnums.js.map +1 -0
- package/dist/api/graphql-api/runs/inputs/create-run.input.js +63 -0
- package/dist/api/graphql-api/runs/inputs/create-run.input.js.map +1 -0
- package/dist/api/graphql-api/runs/inputs/get-agent-log.input.js +48 -0
- package/dist/api/graphql-api/runs/inputs/get-agent-log.input.js.map +1 -0
- package/dist/api/graphql-api/runs/inputs/get-run-attempts.input.js +32 -0
- package/dist/api/graphql-api/runs/inputs/get-run-attempts.input.js.map +1 -0
- package/dist/api/graphql-api/runs/inputs/get-run-events.input.js +28 -0
- package/dist/api/graphql-api/runs/inputs/get-run-events.input.js.map +1 -0
- package/dist/api/graphql-api/runs/inputs/list-runs.input.js +23 -0
- package/dist/api/graphql-api/runs/inputs/list-runs.input.js.map +1 -0
- package/dist/api/graphql-api/runs/inputs/simulate-route.input.js +43 -0
- package/dist/api/graphql-api/runs/inputs/simulate-route.input.js.map +1 -0
- package/dist/api/graphql-api/runs/model/agent-activity.model.js +367 -0
- package/dist/api/graphql-api/runs/model/agent-activity.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/create-run-result.model.js +53 -0
- package/dist/api/graphql-api/runs/model/create-run-result.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/run-attempt.model.js +114 -0
- package/dist/api/graphql-api/runs/model/run-attempt.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/run-connection.model.js +16 -0
- package/dist/api/graphql-api/runs/model/run-connection.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/run-cost.model.js +67 -0
- package/dist/api/graphql-api/runs/model/run-cost.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/run-digest.model.js +41 -0
- package/dist/api/graphql-api/runs/model/run-digest.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/run-event-connection.model.js +16 -0
- package/dist/api/graphql-api/runs/model/run-event-connection.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/run-event.model.js +58 -0
- package/dist/api/graphql-api/runs/model/run-event.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/run-progress.model.js +33 -0
- package/dist/api/graphql-api/runs/model/run-progress.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/run-workflow.model.js +287 -0
- package/dist/api/graphql-api/runs/model/run-workflow.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/run.model.js +57 -0
- package/dist/api/graphql-api/runs/model/run.model.js.map +1 -0
- package/dist/api/graphql-api/runs/model/usage.model.js +32 -0
- package/dist/api/graphql-api/runs/model/usage.model.js.map +1 -0
- package/dist/api/graphql-api/runs/run-digest.resolver.js +40 -0
- package/dist/api/graphql-api/runs/run-digest.resolver.js.map +1 -0
- package/dist/api/graphql-api/runs/run-events.resolver.js +45 -0
- package/dist/api/graphql-api/runs/run-events.resolver.js.map +1 -0
- package/dist/api/graphql-api/runs/run-progress.resolver.js +53 -0
- package/dist/api/graphql-api/runs/run-progress.resolver.js.map +1 -0
- package/dist/api/graphql-api/runs/runs-subscription.resolver.js +124 -0
- package/dist/api/graphql-api/runs/runs-subscription.resolver.js.map +1 -0
- package/dist/api/graphql-api/runs/runs.resolver.js +165 -0
- package/dist/api/graphql-api/runs/runs.resolver.js.map +1 -0
- package/dist/api/graphql-api/share/graphql-param-types.js +6 -0
- package/dist/api/graphql-api/share/graphql-param-types.js.map +1 -0
- package/dist/api/graphql-api/share/inputs/connection.input.js +27 -0
- package/dist/api/graphql-api/share/inputs/connection.input.js.map +1 -0
- package/dist/api/graphql-api/share/inputs/run-subscription.input.js +22 -0
- package/dist/api/graphql-api/share/inputs/run-subscription.input.js.map +1 -0
- package/dist/api/graphql-api/share/model/paginated.model.js +75 -0
- package/dist/api/graphql-api/share/model/paginated.model.js.map +1 -0
- package/dist/api/graphql-api/system/model/daemon-status.model.js +47 -0
- package/dist/api/graphql-api/system/model/daemon-status.model.js.map +1 -0
- package/dist/api/graphql-api/system/model/doctor-result.model.js +33 -0
- package/dist/api/graphql-api/system/model/doctor-result.model.js.map +1 -0
- package/dist/api/graphql-api/system/model/project.model.js +37 -0
- package/dist/api/graphql-api/system/model/project.model.js.map +1 -0
- package/dist/api/graphql-api/system/model/repository-context.model.js +70 -0
- package/dist/api/graphql-api/system/model/repository-context.model.js.map +1 -0
- package/dist/api/graphql-api/system/model/repository-validation.model.js +62 -0
- package/dist/api/graphql-api/system/model/repository-validation.model.js.map +1 -0
- package/dist/api/graphql-api/system/model/system-status.model.js +29 -0
- package/dist/api/graphql-api/system/model/system-status.model.js.map +1 -0
- package/dist/api/graphql-api/system/system.resolver.js +83 -0
- package/dist/api/graphql-api/system/system.resolver.js.map +1 -0
- package/dist/cli/commands/doctor-report.js +70 -0
- package/dist/cli/commands/doctor-report.js.map +1 -0
- package/dist/cli/commands/lifecycle.js +463 -0
- package/dist/cli/commands/lifecycle.js.map +1 -0
- package/dist/cli/commands/mcp.js +53 -8
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/process-tree.js +87 -0
- package/dist/cli/commands/process-tree.js.map +1 -0
- package/dist/cli/commands/revisium-helpers.js +2 -2
- package/dist/cli/commands/rogue-reaper.js +63 -0
- package/dist/cli/commands/rogue-reaper.js.map +1 -0
- package/dist/cli/index.js +5 -29
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/program.js +7 -23
- package/dist/cli/program.js.map +1 -1
- package/dist/config.js +79 -1
- package/dist/config.js.map +1 -1
- package/dist/control-plane/bootstrap.js +101 -0
- package/dist/control-plane/bootstrap.js.map +1 -0
- package/dist/control-plane/change-notifications.js +35 -0
- package/dist/control-plane/change-notifications.js.map +1 -0
- package/dist/control-plane/client-transport.js +74 -41
- package/dist/control-plane/client-transport.js.map +1 -1
- package/dist/control-plane/data-access.js +13 -5
- package/dist/control-plane/data-access.js.map +1 -1
- package/dist/control-plane/definitions.js +1 -1
- package/dist/control-plane/definitions.js.map +1 -1
- package/dist/control-plane/inbox.js +5 -31
- package/dist/control-plane/inbox.js.map +1 -1
- package/dist/control-plane/index.js +1 -1
- package/dist/control-plane/index.js.map +1 -1
- package/dist/control-plane/json-fields.js +2 -0
- package/dist/control-plane/json-fields.js.map +1 -1
- package/dist/control-plane/resolve-cwd.js +76 -8
- package/dist/control-plane/resolve-cwd.js.map +1 -1
- package/dist/control-plane/schema-migration.js +82 -0
- package/dist/control-plane/schema-migration.js.map +1 -0
- package/dist/control-plane/seed-default-playbook.js +141 -0
- package/dist/control-plane/seed-default-playbook.js.map +1 -0
- package/dist/control-plane/steps.js +15 -349
- package/dist/control-plane/steps.js.map +1 -1
- package/dist/control-plane/tables.js +1 -0
- package/dist/control-plane/tables.js.map +1 -1
- package/dist/e2e/kit/agents.js +148 -0
- package/dist/e2e/kit/agents.js.map +1 -0
- package/dist/e2e/kit/assertions.js +163 -0
- package/dist/e2e/kit/assertions.js.map +1 -0
- package/dist/e2e/kit/crash.js +44 -0
- package/dist/e2e/kit/crash.js.map +1 -0
- package/dist/e2e/kit/drive.js +45 -0
- package/dist/e2e/kit/drive.js.map +1 -0
- package/dist/e2e/kit/env.js +16 -0
- package/dist/e2e/kit/env.js.map +1 -0
- package/dist/e2e/kit/fake-integrator.js +57 -0
- package/dist/e2e/kit/fake-integrator.js.map +1 -0
- package/dist/e2e/kit/gh-emulator.js +213 -0
- package/dist/e2e/kit/gh-emulator.js.map +1 -0
- package/dist/e2e/kit/git-target-repo.js +115 -0
- package/dist/e2e/kit/git-target-repo.js.map +1 -0
- package/dist/e2e/kit/harness.js +72 -0
- package/dist/e2e/kit/harness.js.map +1 -0
- package/dist/e2e/kit/index.js +14 -0
- package/dist/e2e/kit/index.js.map +1 -0
- package/dist/e2e/kit/mcp.js +32 -0
- package/dist/e2e/kit/mcp.js.map +1 -0
- package/dist/e2e/kit/scenarios.js +196 -0
- package/dist/e2e/kit/scenarios.js.map +1 -0
- package/dist/e2e/recovery-crash-child.js +29 -0
- package/dist/e2e/recovery-crash-child.js.map +1 -0
- package/dist/e2e/recovery-dd-crash-child.js +43 -0
- package/dist/e2e/recovery-dd-crash-child.js.map +1 -0
- package/dist/engine/dbos.module.js +2 -1
- package/dist/engine/dbos.module.js.map +1 -1
- package/dist/engine/dbos.service.js +89 -18
- package/dist/engine/dbos.service.js.map +1 -1
- package/dist/engine/ensure-postgres.js +18 -4
- package/dist/engine/ensure-postgres.js.map +1 -1
- package/dist/features/inbox/commands/handlers/inbox-command.handlers.js +80 -0
- package/dist/features/inbox/commands/handlers/inbox-command.handlers.js.map +1 -0
- package/dist/features/inbox/commands/impl/answer-question.command.js +7 -0
- package/dist/features/inbox/commands/impl/answer-question.command.js.map +1 -0
- package/dist/features/inbox/commands/impl/approve-gate.command.js +7 -0
- package/dist/features/inbox/commands/impl/approve-gate.command.js.map +1 -0
- package/dist/features/inbox/commands/impl/reject-gate.command.js +7 -0
- package/dist/features/inbox/commands/impl/reject-gate.command.js.map +1 -0
- package/dist/features/inbox/commands/impl/resolve-inbox-item.command.js +7 -0
- package/dist/features/inbox/commands/impl/resolve-inbox-item.command.js.map +1 -0
- package/dist/features/inbox/commands/index.js +8 -0
- package/dist/features/inbox/commands/index.js.map +1 -0
- package/dist/features/inbox/inbox-api.module.js +23 -0
- package/dist/features/inbox/inbox-api.module.js.map +1 -0
- package/dist/features/inbox/inbox-api.service.js +63 -0
- package/dist/features/inbox/inbox-api.service.js.map +1 -0
- package/dist/features/inbox/queries/handlers/inbox-query.handlers.js +111 -0
- package/dist/features/inbox/queries/handlers/inbox-query.handlers.js.map +1 -0
- package/dist/features/inbox/queries/impl/get-inbox-item.query.js +7 -0
- package/dist/features/inbox/queries/impl/get-inbox-item.query.js.map +1 -0
- package/dist/features/inbox/queries/impl/get-pending-decisions.query.js +7 -0
- package/dist/features/inbox/queries/impl/get-pending-decisions.query.js.map +1 -0
- package/dist/features/inbox/queries/impl/list-inbox.query.js +7 -0
- package/dist/features/inbox/queries/impl/list-inbox.query.js.map +1 -0
- package/dist/features/inbox/queries/impl/summarize-gate-risk.query.js +7 -0
- package/dist/features/inbox/queries/impl/summarize-gate-risk.query.js.map +1 -0
- package/dist/features/inbox/queries/index.js +8 -0
- package/dist/features/inbox/queries/index.js.map +1 -0
- package/dist/features/method/commands/index.js +2 -0
- package/dist/features/method/commands/index.js.map +1 -0
- package/dist/features/method/method-api.module.js +23 -0
- package/dist/features/method/method-api.module.js.map +1 -0
- package/dist/features/method/method-api.service.js +47 -0
- package/dist/features/method/method-api.service.js.map +1 -0
- package/dist/features/method/queries/handlers/method-query.handlers.js +115 -0
- package/dist/features/method/queries/handlers/method-query.handlers.js.map +1 -0
- package/dist/features/method/queries/impl/get-pipeline.query.js +7 -0
- package/dist/features/method/queries/impl/get-pipeline.query.js.map +1 -0
- package/dist/features/method/queries/impl/get-role.query.js +7 -0
- package/dist/features/method/queries/impl/get-role.query.js.map +1 -0
- package/dist/features/method/queries/impl/list-pipelines.query.js +7 -0
- package/dist/features/method/queries/impl/list-pipelines.query.js.map +1 -0
- package/dist/features/method/queries/impl/list-playbooks.query.js +7 -0
- package/dist/features/method/queries/impl/list-playbooks.query.js.map +1 -0
- package/dist/features/method/queries/impl/list-roles.query.js +7 -0
- package/dist/features/method/queries/impl/list-roles.query.js.map +1 -0
- package/dist/features/method/queries/index.js +9 -0
- package/dist/features/method/queries/index.js.map +1 -0
- package/dist/features/pr/commands/index.js +2 -0
- package/dist/features/pr/commands/index.js.map +1 -0
- package/dist/features/pr/pr-api.module.js +23 -0
- package/dist/features/pr/pr-api.module.js.map +1 -0
- package/dist/features/pr/pr-api.service.js +35 -0
- package/dist/features/pr/pr-api.service.js.map +1 -0
- package/dist/features/pr/queries/handlers/pr-query.handlers.js +48 -0
- package/dist/features/pr/queries/handlers/pr-query.handlers.js.map +1 -0
- package/dist/features/pr/queries/impl/get-pr-readiness.query.js +7 -0
- package/dist/features/pr/queries/impl/get-pr-readiness.query.js.map +1 -0
- package/dist/features/pr/queries/impl/list-pr-feedback.query.js +7 -0
- package/dist/features/pr/queries/impl/list-pr-feedback.query.js.map +1 -0
- package/dist/features/pr/queries/index.js +3 -0
- package/dist/features/pr/queries/index.js.map +1 -0
- package/dist/features/runs/commands/handlers/runs-command.handlers.js +32 -0
- package/dist/features/runs/commands/handlers/runs-command.handlers.js.map +1 -0
- package/dist/features/runs/commands/impl/create-run.command.js +7 -0
- package/dist/features/runs/commands/impl/create-run.command.js.map +1 -0
- package/dist/features/runs/commands/index.js +3 -0
- package/dist/features/runs/commands/index.js.map +1 -0
- package/dist/features/runs/queries/handlers/runs-query.handlers.js +359 -0
- package/dist/features/runs/queries/handlers/runs-query.handlers.js.map +1 -0
- package/dist/features/runs/queries/impl/get-agent-activity.query.js +7 -0
- package/dist/features/runs/queries/impl/get-agent-activity.query.js.map +1 -0
- package/dist/features/runs/queries/impl/get-agent-attempts.query.js +7 -0
- package/dist/features/runs/queries/impl/get-agent-attempts.query.js.map +1 -0
- package/dist/features/runs/queries/impl/get-agent-log.query.js +7 -0
- package/dist/features/runs/queries/impl/get-agent-log.query.js.map +1 -0
- package/dist/features/runs/queries/impl/get-run-attempts.query.js +7 -0
- package/dist/features/runs/queries/impl/get-run-attempts.query.js.map +1 -0
- package/dist/features/runs/queries/impl/get-run-digest.query.js +7 -0
- package/dist/features/runs/queries/impl/get-run-digest.query.js.map +1 -0
- package/dist/features/runs/queries/impl/get-run-events.query.js +7 -0
- package/dist/features/runs/queries/impl/get-run-events.query.js.map +1 -0
- package/dist/features/runs/queries/impl/get-run-progress.query.js +7 -0
- package/dist/features/runs/queries/impl/get-run-progress.query.js.map +1 -0
- package/dist/features/runs/queries/impl/get-run-workflow.query.js +7 -0
- package/dist/features/runs/queries/impl/get-run-workflow.query.js.map +1 -0
- package/dist/features/runs/queries/impl/get-run.query.js +7 -0
- package/dist/features/runs/queries/impl/get-run.query.js.map +1 -0
- package/dist/features/runs/queries/impl/list-runs.query.js +7 -0
- package/dist/features/runs/queries/impl/list-runs.query.js.map +1 -0
- package/dist/features/runs/queries/impl/simulate-route.query.js +7 -0
- package/dist/features/runs/queries/impl/simulate-route.query.js.map +1 -0
- package/dist/features/runs/queries/index.js +15 -0
- package/dist/features/runs/queries/index.js.map +1 -0
- package/dist/features/runs/runs-api.module.js +23 -0
- package/dist/features/runs/runs-api.module.js.map +1 -0
- package/dist/features/runs/runs-api.service.js +79 -0
- package/dist/features/runs/runs-api.service.js.map +1 -0
- package/dist/features/shared/connection.js +39 -0
- package/dist/features/shared/connection.js.map +1 -0
- package/dist/features/system/commands/index.js +2 -0
- package/dist/features/system/commands/index.js.map +1 -0
- package/dist/features/system/queries/handlers/system-query.handlers.js +96 -0
- package/dist/features/system/queries/handlers/system-query.handlers.js.map +1 -0
- package/dist/features/system/queries/impl/doctor.query.js +4 -0
- package/dist/features/system/queries/impl/doctor.query.js.map +1 -0
- package/dist/features/system/queries/impl/get-project.query.js +4 -0
- package/dist/features/system/queries/impl/get-project.query.js.map +1 -0
- package/dist/features/system/queries/impl/get-repository-context.query.js +7 -0
- package/dist/features/system/queries/impl/get-repository-context.query.js.map +1 -0
- package/dist/features/system/queries/impl/get-status.query.js +4 -0
- package/dist/features/system/queries/impl/get-status.query.js.map +1 -0
- package/dist/features/system/queries/impl/validate-repository.query.js +7 -0
- package/dist/features/system/queries/impl/validate-repository.query.js.map +1 -0
- package/dist/features/system/queries/index.js +9 -0
- package/dist/features/system/queries/index.js.map +1 -0
- package/dist/features/system/system-api.module.js +23 -0
- package/dist/features/system/system-api.module.js.map +1 -0
- package/dist/features/system/system-api.service.js +47 -0
- package/dist/features/system/system-api.service.js.map +1 -0
- package/dist/host/daemon.js +99 -0
- package/dist/host/daemon.js.map +1 -0
- package/dist/host/dbos-identity.js +42 -0
- package/dist/host/dbos-identity.js.map +1 -0
- package/dist/host/ensure-host.js +120 -0
- package/dist/host/ensure-host.js.map +1 -0
- package/dist/host/host-runtime.js +90 -0
- package/dist/host/host-runtime.js.map +1 -0
- package/dist/host/host.lifecycle.js +16 -3
- package/dist/host/host.lifecycle.js.map +1 -1
- package/dist/host/queue-ownership.js +70 -0
- package/dist/host/queue-ownership.js.map +1 -0
- package/dist/host/queue-poller-census.js +47 -0
- package/dist/host/queue-poller-census.js.map +1 -0
- package/dist/http/graphql-host.js +56 -0
- package/dist/http/graphql-host.js.map +1 -0
- package/dist/{mcp/mcp.module.js → http/graphql-host.module.js} +12 -10
- package/dist/http/graphql-host.module.js.map +1 -0
- package/dist/infrastructure/metrics/graphql/graphql-metrics.js +91 -0
- package/dist/infrastructure/metrics/graphql/graphql-metrics.js.map +1 -0
- package/dist/mcp/mcp-capabilities.js +9 -1
- package/dist/mcp/mcp-capabilities.js.map +1 -1
- package/dist/mcp/mcp-facade.service.js +68 -5
- package/dist/mcp/mcp-facade.service.js.map +1 -1
- package/dist/mcp/mcp-http.service.js +95 -0
- package/dist/mcp/mcp-http.service.js.map +1 -0
- package/dist/mcp/mcp-tools.js +93 -7
- package/dist/mcp/mcp-tools.js.map +1 -1
- package/dist/observability/agent-activity-reporter.js +185 -0
- package/dist/observability/agent-activity-reporter.js.map +1 -0
- package/dist/observability/agent-observability.service.js +1142 -0
- package/dist/observability/agent-observability.service.js.map +1 -0
- package/dist/observability/index.js +4 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/types.js +11 -0
- package/dist/observability/types.js.map +1 -0
- package/dist/pipeline/await-human.js +8 -4
- package/dist/pipeline/await-human.js.map +1 -1
- package/dist/pipeline/data-driven-task.workflow.js +667 -0
- package/dist/pipeline/data-driven-task.workflow.js.map +1 -0
- package/dist/pipeline/data-driven-template.js +57 -0
- package/dist/pipeline/data-driven-template.js.map +1 -0
- package/dist/pipeline/pipeline.module.js +2 -2
- package/dist/pipeline/pipeline.module.js.map +1 -1
- package/dist/pipeline/pipeline.service.js +412 -0
- package/dist/pipeline/pipeline.service.js.map +1 -0
- package/dist/pipeline/route-contract.js +82 -0
- package/dist/pipeline/route-contract.js.map +1 -0
- package/dist/pipeline-core/index.js +16 -0
- package/dist/pipeline-core/index.js.map +1 -0
- package/dist/pipeline-core/interpret.js +353 -0
- package/dist/pipeline-core/interpret.js.map +1 -0
- package/dist/pipeline-core/kit/assertions.js +61 -0
- package/dist/pipeline-core/kit/assertions.js.map +1 -0
- package/dist/pipeline-core/kit/builders.js +138 -0
- package/dist/pipeline-core/kit/builders.js.map +1 -0
- package/dist/pipeline-core/kit/drive.js +96 -0
- package/dist/pipeline-core/kit/drive.js.map +1 -0
- package/dist/pipeline-core/kit/fixtures.js +342 -0
- package/dist/pipeline-core/kit/fixtures.js.map +1 -0
- package/dist/pipeline-core/kit/index.js +13 -0
- package/dist/pipeline-core/kit/index.js.map +1 -0
- package/dist/pipeline-core/types.js +134 -0
- package/dist/pipeline-core/types.js.map +1 -0
- package/dist/pipeline-core/validate-capability.js +23 -0
- package/dist/pipeline-core/validate-capability.js.map +1 -0
- package/dist/pipeline-core/validate-conflicts.js +37 -0
- package/dist/pipeline-core/validate-conflicts.js.map +1 -0
- package/dist/pipeline-core/validate-dataflow.js +212 -0
- package/dist/pipeline-core/validate-dataflow.js.map +1 -0
- package/dist/pipeline-core/validate-diff.js +158 -0
- package/dist/pipeline-core/validate-diff.js.map +1 -0
- package/dist/pipeline-core/validate-edges.js +44 -0
- package/dist/pipeline-core/validate-edges.js.map +1 -0
- package/dist/pipeline-core/validate-graph.js +123 -0
- package/dist/pipeline-core/validate-graph.js.map +1 -0
- package/dist/pipeline-core/validate-loops.js +226 -0
- package/dist/pipeline-core/validate-loops.js.map +1 -0
- package/dist/pipeline-core/validate-parallel.js +132 -0
- package/dist/pipeline-core/validate-parallel.js.map +1 -0
- package/dist/pipeline-core/validate-sink.js +27 -0
- package/dist/pipeline-core/validate-sink.js.map +1 -0
- package/dist/pipeline-core/validate-topology.js +140 -0
- package/dist/pipeline-core/validate-topology.js.map +1 -0
- package/dist/pipeline-core/validate-verdict.js +72 -0
- package/dist/pipeline-core/validate-verdict.js.map +1 -0
- package/dist/pipeline-core/validate.js +119 -0
- package/dist/pipeline-core/validate.js.map +1 -0
- package/dist/playbook/catalog-loader.js +14 -1
- package/dist/playbook/catalog-loader.js.map +1 -1
- package/dist/playbook/import-mapper.js +14 -38
- package/dist/playbook/import-mapper.js.map +1 -1
- package/dist/playbook/manifest.js +1 -1
- package/dist/revisium/playbooks.service.js +107 -19
- package/dist/revisium/playbooks.service.js.map +1 -1
- package/dist/revisium/roles.service.js +1 -1
- package/dist/revisium/roles.service.js.map +1 -1
- package/dist/revisium/run.service.js +55 -8
- package/dist/revisium/run.service.js.map +1 -1
- package/dist/run/append-event.js +24 -1
- package/dist/run/append-event.js.map +1 -1
- package/dist/run/block-run.js +17 -0
- package/dist/run/block-run.js.map +1 -0
- package/dist/run/complete-run.js +18 -0
- package/dist/run/complete-run.js.map +1 -0
- package/dist/run/create-run.js +33 -36
- package/dist/run/create-run.js.map +1 -1
- package/dist/run/inspect-run.js +31 -30
- package/dist/run/inspect-run.js.map +1 -1
- package/dist/run/run-outputs.js +88 -0
- package/dist/run/run-outputs.js.map +1 -0
- package/dist/run/terminal-run-status.js +66 -7
- package/dist/run/terminal-run-status.js.map +1 -1
- package/dist/runners/claude-code.service.js +5 -0
- package/dist/runners/claude-code.service.js.map +1 -1
- package/dist/runners/codex.service.js +51 -0
- package/dist/runners/codex.service.js.map +1 -0
- package/dist/runners/integrator-branch-naming.js +39 -0
- package/dist/runners/integrator-branch-naming.js.map +1 -0
- package/dist/runners/integrator-git.js +84 -0
- package/dist/runners/integrator-git.js.map +1 -0
- package/dist/runners/integrator-remote.js +34 -0
- package/dist/runners/integrator-remote.js.map +1 -0
- package/dist/runners/integrator-types.js +9 -0
- package/dist/runners/integrator-types.js.map +1 -0
- package/dist/runners/integrator.js +327 -147
- package/dist/runners/integrator.js.map +1 -1
- package/dist/runners/runner.module.js +7 -3
- package/dist/runners/runner.module.js.map +1 -1
- package/dist/runners/worktree.service.js +63 -0
- package/dist/runners/worktree.service.js.map +1 -0
- package/dist/smoke/cli.js +47 -0
- package/dist/smoke/cli.js.map +1 -0
- package/dist/smoke/isolation.js +113 -0
- package/dist/smoke/isolation.js.map +1 -0
- package/dist/task-control-plane/run-watch.service.js +281 -0
- package/dist/task-control-plane/run-watch.service.js.map +1 -0
- package/dist/task-control-plane/task-control-plane-api.service.js +569 -23
- package/dist/task-control-plane/task-control-plane-api.service.js.map +1 -1
- package/dist/task-control-plane/task-control-plane.module.js +22 -3
- package/dist/task-control-plane/task-control-plane.module.js.map +1 -1
- package/dist/worker/artifact-store.js +116 -0
- package/dist/worker/artifact-store.js.map +1 -0
- package/dist/worker/build-context.js +169 -2
- package/dist/worker/build-context.js.map +1 -1
- package/dist/worker/claude-code-runner.js +159 -68
- package/dist/worker/claude-code-runner.js.map +1 -1
- package/dist/worker/codex-runner.js +474 -0
- package/dist/worker/codex-runner.js.map +1 -0
- package/dist/worker/git-worktree-manager.js +129 -65
- package/dist/worker/git-worktree-manager.js.map +1 -1
- package/dist/worker/process-executor.js +23 -2
- package/dist/worker/process-executor.js.map +1 -1
- package/dist/worker/result-envelope.js +115 -57
- package/dist/worker/result-envelope.js.map +1 -1
- package/dist/worker/runner-common.js +106 -0
- package/dist/worker/runner-common.js.map +1 -0
- package/dist/worker/runner-dispatch.js +4 -1
- package/dist/worker/runner-dispatch.js.map +1 -1
- package/dist/worker/runner.js +11 -1
- package/dist/worker/runner.js.map +1 -1
- package/dist/worker/stub-runner.js +7 -45
- package/dist/worker/stub-runner.js.map +1 -1
- package/package.json +32 -7
- package/dist/app.module.js +0 -28
- package/dist/app.module.js.map +0 -1
- package/dist/cli/commands/bootstrap.js +0 -39
- package/dist/cli/commands/bootstrap.js.map +0 -1
- package/dist/cli/commands/dev.js +0 -143
- package/dist/cli/commands/dev.js.map +0 -1
- package/dist/cli/commands/inbox.js +0 -288
- package/dist/cli/commands/inbox.js.map +0 -1
- package/dist/cli/commands/playbook.js +0 -74
- package/dist/cli/commands/playbook.js.map +0 -1
- package/dist/cli/commands/poll-workflow-state.js +0 -144
- package/dist/cli/commands/poll-workflow-state.js.map +0 -1
- package/dist/cli/commands/revisium-context.js +0 -23
- package/dist/cli/commands/revisium-context.js.map +0 -1
- package/dist/cli/commands/revisium.js +0 -89
- package/dist/cli/commands/revisium.js.map +0 -1
- package/dist/cli/commands/run.js +0 -426
- package/dist/cli/commands/run.js.map +0 -1
- package/dist/cli/commands/work.js +0 -149
- package/dist/cli/commands/work.js.map +0 -1
- package/dist/cli/live-guard.js +0 -49
- package/dist/cli/live-guard.js.map +0 -1
- package/dist/cli/needs-host.js +0 -78
- package/dist/cli/needs-host.js.map +0 -1
- package/dist/mcp/mcp-stdio.service.js +0 -48
- package/dist/mcp/mcp-stdio.service.js.map +0 -1
- package/dist/mcp/mcp.module.js.map +0 -1
- package/dist/pipeline/develop-task.workflow.js +0 -497
- package/dist/pipeline/develop-task.workflow.js.map +0 -1
- package/dist/worker/loop.js +0 -122
- package/dist/worker/loop.js.map +0 -1
- package/dist/worker/script-runner.js +0 -28
- package/dist/worker/script-runner.js.map +0 -1
- package/dist/worker/worker-id.js +0 -18
- package/dist/worker/worker-id.js.map +0 -1
- package/dist/worker/worktree-manager.js +0 -7
- package/dist/worker/worktree-manager.js.map +0 -1
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* data-driven-task.workflow.ts — the DBOS effect-adapter for a DATA-DRIVEN pipeline (plan 0015 §10).
|
|
3
|
+
*
|
|
4
|
+
* Runs the pure `pipeline-core` graph on REAL DBOS. As of slice 3 this is the SOLE pipeline engine:
|
|
5
|
+
* selection routes EVERY pipeline here (TaskControlPlaneApiService), executing the state-machine
|
|
6
|
+
* template pinned for the run; a pipeline without a valid template FAILS LOUD at selection. The old
|
|
7
|
+
* hardcoded `developTask` workflow + its role→phase classifiers were removed.
|
|
8
|
+
*
|
|
9
|
+
* INVARIANT: `src/pipeline/*` imports NO `@dbos-inc/dbos-sdk` (M1 — DBOS sealed). All DBOS interaction
|
|
10
|
+
* goes through the generic DbosService verbs (registerStep/registerWorkflow/awaitDecision) injected as
|
|
11
|
+
* deps. This file is registered via the engine seam in PipelineService.
|
|
12
|
+
*
|
|
13
|
+
* GENERIC ENGINE: zero role-ids / pipeline shapes here. `roleRef`/`scriptRef` are opaque capability
|
|
14
|
+
* handles resolved against the run's route bindings + the existing runner machinery (§1/§10).
|
|
15
|
+
*
|
|
16
|
+
* The loop (§10):
|
|
17
|
+
* { state, decision } = core.step(template, state, lastResult)
|
|
18
|
+
* → execute `decision` as a durable DBOS step (runner / human gate / integrator / fork)
|
|
19
|
+
* → validate result vs the node's `resultSchema` + redact at this boundary (reuse runStep/append)
|
|
20
|
+
* → record the result as the next `lastResult`
|
|
21
|
+
* → repeat until `decision.type === 'complete'` → finish the run.
|
|
22
|
+
*
|
|
23
|
+
* RECOVERY: DBOS replays the workflow body; `core.step` is deterministic and every effect is a durable
|
|
24
|
+
* memoized DBOS step, so a replay re-derives the identical Decision sequence and consumes the recorded
|
|
25
|
+
* step results — no live race, no duplicate effects (deterministic ids + ROW_CONFLICT no-op).
|
|
26
|
+
*
|
|
27
|
+
* C1 architecture: the body is an extracted DBOS-free builder (`makeDataDrivenTask`) registered via the
|
|
28
|
+
* engine seam, so tests exercise the SAME production logic directly with a plain step fn.
|
|
29
|
+
*/
|
|
30
|
+
import { step as coreStep, initialState, validateTemplate, InterpretError, } from '../pipeline-core/index.js';
|
|
31
|
+
import { runnerNeedsLivePreflight, runnerUsesRealIntegrator } from './route-contract.js';
|
|
32
|
+
import { redactEventPayload } from '../run/append-event.js';
|
|
33
|
+
import { redactSecrets } from '../control-plane/inbox.js';
|
|
34
|
+
export const RUN_PROGRESS_EVENT_KEY = 'run-progress';
|
|
35
|
+
const MAX_STEPS = 1_000; // a VALID template terminates; guards a data/loop authoring mistake at runtime.
|
|
36
|
+
/**
|
|
37
|
+
* Reserved engine error codes (matched only by a node's `catch`, §3/§6).
|
|
38
|
+
*
|
|
39
|
+
* A built-in script (the integrator) has TWO distinct failure modes the routing data discriminates:
|
|
40
|
+
* - `revo.ScriptBlocked` — the script needs a human (nothing-to-integrate, ambiguous PRs, a refused
|
|
41
|
+
* pinned identity, a non-JSON `pr view`). NOT a crash; a `catch` routes it to a `blocked` terminal,
|
|
42
|
+
* and the adapter surfaces the human-readable lesson on a `pipeline_blocked` event (parity with the
|
|
43
|
+
* old engine's `blockPipeline({ reason:'integrate' })`).
|
|
44
|
+
* - `revo.ScriptFailed` — the script THREW (a gh/push error). A `catch` routes it to a `failed`
|
|
45
|
+
* terminal (parity with the old engine's top-level catch → failRun).
|
|
46
|
+
*/
|
|
47
|
+
const REVO_SCRIPT_FAILED = 'revo.ScriptFailed';
|
|
48
|
+
const REVO_SCRIPT_BLOCKED = 'revo.ScriptBlocked';
|
|
49
|
+
const REVO_RESULT_INVALID = 'revo.ResultInvalid';
|
|
50
|
+
const REVO_INPUT_MISSING = 'revo.InputMissing';
|
|
51
|
+
/** Per-node execution stepKey: the bare nodeId on the first entry (stable ids for existing tests), an
|
|
52
|
+
* ordinal-suffixed key on loop re-entries so attempts/events/outputs are distinct per iteration (0016
|
|
53
|
+
* §4.1 — fixes the latent 0015 stepKey-reuse collision). */
|
|
54
|
+
function stepKeyFor(nodeId, ordinal) {
|
|
55
|
+
return ordinal <= 1 ? nodeId : `${nodeId}#${ordinal}`;
|
|
56
|
+
}
|
|
57
|
+
/** Next per-(run,node) execution ordinal (1-based). Deterministic on DBOS replay: the runBody loop
|
|
58
|
+
* re-runs identically (coreStep is pure, effects are memoized), so the accumulator is rebuilt 1:1. */
|
|
59
|
+
function nextOrdinal(byNode, nodeId) {
|
|
60
|
+
const n = (byNode.get(nodeId) ?? 0) + 1;
|
|
61
|
+
byNode.set(nodeId, n);
|
|
62
|
+
return n;
|
|
63
|
+
}
|
|
64
|
+
function isRecord(value) {
|
|
65
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
66
|
+
}
|
|
67
|
+
/** Extract the DOMAIN verdict from the only supported source: top-level AttemptResult.verdict. */
|
|
68
|
+
function domainVerdictOf(result) {
|
|
69
|
+
if (typeof result.verdict === 'string' && result.verdict.trim().length > 0) {
|
|
70
|
+
return result.verdict.trim().toLowerCase();
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
function resultVerdictProblem(template, node, result) {
|
|
75
|
+
if (node.kind !== 'agent')
|
|
76
|
+
return undefined;
|
|
77
|
+
const verdict = domainVerdictOf(result);
|
|
78
|
+
if (!verdict) {
|
|
79
|
+
return `${REVO_RESULT_INVALID}: node ${node.id} requires top-level result.verdict`;
|
|
80
|
+
}
|
|
81
|
+
if (!template.verdicts.domain.includes(verdict)) {
|
|
82
|
+
return `${REVO_RESULT_INVALID}: node ${node.id} emitted verdict "${verdict}" outside template verdicts.domain [${template.verdicts.domain.join(', ')}]`;
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Validate a recorded result against a node's `resultSchema` at the ADAPTER boundary (§10). MVP
|
|
88
|
+
* contract (resolves §14 Q3 — resultSchema is a DATA handle, validated structurally here): a declared
|
|
89
|
+
* `resultSchema` requires a non-empty object/string output. Token redaction already happens inside
|
|
90
|
+
* `runStep`/`appendEvent`; this guards a malformed effect result → `revo.ResultInvalid` (§6 precedence).
|
|
91
|
+
*/
|
|
92
|
+
function resultSatisfiesSchema(node, result) {
|
|
93
|
+
if (!('resultSchema' in node) || !node.resultSchema)
|
|
94
|
+
return true;
|
|
95
|
+
const output = result.output;
|
|
96
|
+
if (output === null || output === undefined)
|
|
97
|
+
return false;
|
|
98
|
+
if (typeof output === 'string')
|
|
99
|
+
return output.length > 0;
|
|
100
|
+
if (isRecord(output))
|
|
101
|
+
return true;
|
|
102
|
+
return Array.isArray(output);
|
|
103
|
+
}
|
|
104
|
+
function progressCursor(state, lastResult) {
|
|
105
|
+
return {
|
|
106
|
+
activeNodeIds: [...state.activeNodeIds],
|
|
107
|
+
scopedCounters: { ...state.scopedCounters },
|
|
108
|
+
status: state.status,
|
|
109
|
+
...(lastResult ? { lastResult } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Map an approve/reject human decision onto a DOMAIN verdict the template's gate `outcomes` can route.
|
|
114
|
+
* The core never sees approve/reject — it routes on a domain label (§8). Approve → the first declared
|
|
115
|
+
* outcome (the "proceed" label by template convention, e.g. `approved`); reject → fail-closed to a
|
|
116
|
+
* NON-first outcome if one exists (e.g. `changes_requested`), else undefined so the gate's `default`
|
|
117
|
+
* (typically a `blocked` terminal) fires. This keeps gate semantics 100% in the routing data (§6/§8).
|
|
118
|
+
*/
|
|
119
|
+
function gateVerdict(decision, outcomes) {
|
|
120
|
+
if (decision.decision === 'approve')
|
|
121
|
+
return outcomes[0];
|
|
122
|
+
// reject: prefer a declared "rework/changes" outcome; else let the default branch route (blocked).
|
|
123
|
+
return outcomes.length > 1 ? outcomes.at(-1) : undefined;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Stable gate topic from a node's reason. The topic is the DBOS recv channel AND part of the gate
|
|
127
|
+
* inbox id (`runId|topic`), so DISTINCT gates in one pipeline MUST map to DISTINCT topics — otherwise
|
|
128
|
+
* a second gate's `recv` collides with the first's already-consumed message and the run hangs (plan
|
|
129
|
+
* 0018: the `review-question` gate would otherwise reuse the `plan` topic of the plan gate).
|
|
130
|
+
* merge-review → 'merge'
|
|
131
|
+
* review-question→ 'question'
|
|
132
|
+
* (anything else)→ 'plan' (the plan-review gate)
|
|
133
|
+
*/
|
|
134
|
+
function gateTopicFor(reason) {
|
|
135
|
+
if (/merge/i.test(reason))
|
|
136
|
+
return 'merge';
|
|
137
|
+
if (/question/i.test(reason))
|
|
138
|
+
return 'question';
|
|
139
|
+
return 'plan';
|
|
140
|
+
}
|
|
141
|
+
// D3 — enrich the gate inbox row with the artifact under review + the reviewer verdict, inline, so an
|
|
142
|
+
// approver decides without digging the agent log. `pushInbox` has no size cap (unlike run-outputs'
|
|
143
|
+
// PAYLOAD_MAX), so the artifact is budgeted HERE: over-budget → a head preview + a payload_ref locator,
|
|
144
|
+
// never the full payload. The inbox id is keyed by runId|gateKey only, so a larger context does not
|
|
145
|
+
// change it → pushInbox stays idempotent on replay. The payload is also secret/token redacted at this
|
|
146
|
+
// build site (pushInbox only masks secret-NAMED keys, not token SHAPES in free-text) — see gateArtifactView.
|
|
147
|
+
export const GATE_ARTIFACT_MAX = 16_000;
|
|
148
|
+
export const GATE_PREVIEW_CHARS = 4_000;
|
|
149
|
+
/** Latest (or pinned-ordinal) output row for a gate ref, or undefined if the producer has not run. */
|
|
150
|
+
function resolveGateRow(ref, outputsByNode) {
|
|
151
|
+
if (!ref)
|
|
152
|
+
return undefined;
|
|
153
|
+
const produced = outputsByNode.get(ref.node) ?? [];
|
|
154
|
+
if (produced.length === 0)
|
|
155
|
+
return undefined;
|
|
156
|
+
if (typeof ref.iteration === 'number')
|
|
157
|
+
return produced.find((o) => o.ordinal === ref.iteration);
|
|
158
|
+
return produced[produced.length - 1]; // 'latest' (and 'all' → the most recent for an inline view)
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Inline artifact view with the 16KB budget. Secrets + token shapes are scrubbed BEFORE inlining or
|
|
162
|
+
* previewing — mirroring run-outputs.ts (the sibling persist boundary): pushInbox only masks
|
|
163
|
+
* secret-NAMED keys, so a token shape (`ghp_…`) in a free-text field (e.g. pollPr's prFeedback) would
|
|
164
|
+
* otherwise persist verbatim. Over-budget → a head preview (of the redacted serialization) + an
|
|
165
|
+
* `attempt:` locator (the full artifact is recoverable from that attempt's agent log).
|
|
166
|
+
*/
|
|
167
|
+
function gateArtifactView(row, as) {
|
|
168
|
+
const base = { nodeId: row.nodeId, name: as ?? row.name, schemaRef: row.schemaRef };
|
|
169
|
+
const safe = redactEventPayload(redactSecrets(row.payload) ?? null);
|
|
170
|
+
const serialized = JSON.stringify(safe ?? null);
|
|
171
|
+
// Budget on BYTES (not UTF-16 length) so a multi-byte payload can't slip past the cap.
|
|
172
|
+
if (Buffer.byteLength(serialized, 'utf8') <= GATE_ARTIFACT_MAX)
|
|
173
|
+
return { ...base, payload: safe };
|
|
174
|
+
return {
|
|
175
|
+
...base,
|
|
176
|
+
truncated: true,
|
|
177
|
+
preview: serialized.slice(0, GATE_PREVIEW_CHARS),
|
|
178
|
+
payloadRef: `attempt:${row.attemptId ?? ''}`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Build the enriched gate inbox summary from the workflow-local outputs (replay-safe — rebuilt
|
|
183
|
+
* identically, 0016 §6). `verdictFrom` resolves a node's verdict output; when it is NOT specified, the
|
|
184
|
+
* verdict defaults to the routing verdict that opened the gate (`lastVerdict`). Routing is unaffected —
|
|
185
|
+
* purely informational.
|
|
186
|
+
*/
|
|
187
|
+
export function buildGateSummary(decision, outputsByNode, lastVerdict) {
|
|
188
|
+
const summary = { nodeId: decision.nodeId, outcomes: decision.outcomes };
|
|
189
|
+
const artRow = resolveGateRow(decision.gatedArtifact, outputsByNode);
|
|
190
|
+
if (artRow)
|
|
191
|
+
summary.gatedArtifact = gateArtifactView(artRow, decision.gatedArtifact?.as);
|
|
192
|
+
const verdictRow = resolveGateRow(decision.verdictFrom, outputsByNode);
|
|
193
|
+
if (verdictRow)
|
|
194
|
+
summary.reviewerVerdict = gateArtifactView(verdictRow);
|
|
195
|
+
// Only fall back to the routing verdict when no verdictFrom was REQUESTED — a specified-but-unresolved
|
|
196
|
+
// verdictFrom must not silently present the routing verdict as if it came from that source.
|
|
197
|
+
else if (!decision.verdictFrom && lastVerdict)
|
|
198
|
+
summary.reviewerVerdict = { verdict: lastVerdict };
|
|
199
|
+
return summary;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* makeDataDrivenTask — DBOS-free factory for the dataDrivenTask async function (C1).
|
|
203
|
+
*
|
|
204
|
+
* Receives the (DBOS-wrapped in prod, plain in tests) `runStepFn` so the body is IDENTICAL across
|
|
205
|
+
* production and tests. Returns a plain async function with the workflow signature.
|
|
206
|
+
*/
|
|
207
|
+
export function makeDataDrivenTask(runStepFn, deps) {
|
|
208
|
+
const { appendEvent, appendRunOutput, awaitHuman, completeRun, failRun, blockRun, loadRunTaskContext, integrateFn, runStub, confirmMergeFn, runConfirmStub, pollPrFn, runPollStub, respondThreadsFn, runRespondStub, preflightFn, createWorktreeFn, releaseWorktreeFn } = deps;
|
|
209
|
+
/** Resolve a node's `consumes` from the workflow-local output accumulator — NOT live Revisium reads
|
|
210
|
+
* (0016 §6 / consensus M4: a live read on replay can see rows written past the replay point). */
|
|
211
|
+
function resolveConsumes(node, outputsByNode) {
|
|
212
|
+
const refs = 'consumes' in node ? (node.consumes ?? []) : [];
|
|
213
|
+
const inputs = {};
|
|
214
|
+
for (const ref of refs) {
|
|
215
|
+
const produced = outputsByNode.get(ref.node) ?? [];
|
|
216
|
+
const iteration = ref.iteration ?? 'latest';
|
|
217
|
+
let value;
|
|
218
|
+
let found;
|
|
219
|
+
if (iteration === 'all') {
|
|
220
|
+
value = produced.map((o) => o.payload);
|
|
221
|
+
found = produced.length > 0;
|
|
222
|
+
}
|
|
223
|
+
else if (iteration === 'latest') {
|
|
224
|
+
value = produced.length ? produced[produced.length - 1].payload : undefined;
|
|
225
|
+
found = produced.length > 0;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
const hit = produced.find((o) => o.ordinal === iteration);
|
|
229
|
+
value = hit?.payload;
|
|
230
|
+
found = hit !== undefined;
|
|
231
|
+
}
|
|
232
|
+
if (!found) {
|
|
233
|
+
if (ref.optional)
|
|
234
|
+
continue;
|
|
235
|
+
return { missing: `${ref.node} as ${ref.as}` };
|
|
236
|
+
}
|
|
237
|
+
inputs[ref.as] = value;
|
|
238
|
+
}
|
|
239
|
+
return { inputs };
|
|
240
|
+
}
|
|
241
|
+
/** Record a node's produced output to the workflow-local accumulator + Revisium (when `produces`). */
|
|
242
|
+
// (gate-summary helpers live at module scope below — they are pure over outputsByNode.)
|
|
243
|
+
async function recordOutput(runId, node, ordinal, output, outputsByNode) {
|
|
244
|
+
if (!('produces' in node) || !node.produces)
|
|
245
|
+
return;
|
|
246
|
+
const row = {
|
|
247
|
+
runId,
|
|
248
|
+
nodeId: node.id,
|
|
249
|
+
ordinal,
|
|
250
|
+
name: node.produces.name,
|
|
251
|
+
schemaRef: ('resultSchema' in node && node.resultSchema) || '',
|
|
252
|
+
payload: output,
|
|
253
|
+
attemptId: stepKeyFor(node.id, ordinal),
|
|
254
|
+
};
|
|
255
|
+
const list = outputsByNode.get(node.id) ?? [];
|
|
256
|
+
list.push(row);
|
|
257
|
+
outputsByNode.set(node.id, list);
|
|
258
|
+
await appendRunOutput(row);
|
|
259
|
+
}
|
|
260
|
+
return async function dataDrivenTaskImpl(runId, opts) {
|
|
261
|
+
try {
|
|
262
|
+
return await runBody(runId, opts);
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
// TERMINAL failure: mark the Revisium run-row `failed` (idempotent, event-first) before
|
|
266
|
+
// re-throwing so DBOS still records the workflow ERROR (progress truth) and the run-row stops
|
|
267
|
+
// lying. The run's terminal-failure surfacing contract (0008 #2).
|
|
268
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
269
|
+
try {
|
|
270
|
+
await failRun(runId, reason);
|
|
271
|
+
}
|
|
272
|
+
catch (failErr) {
|
|
273
|
+
console.error(`[data-driven] failRun(${runId}) itself failed: ${String(failErr)}`);
|
|
274
|
+
}
|
|
275
|
+
throw err;
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
async function runBody(runId, opts) {
|
|
279
|
+
const { route, template } = opts;
|
|
280
|
+
// Defense-in-depth: the pinned template is validated at the boundary (§9 — pipeline-core is the
|
|
281
|
+
// authoritative validator even though selection already validated it). A broken pin fails the run.
|
|
282
|
+
const diagnostics = validateTemplate(template).filter((d) => d.severity === 'error');
|
|
283
|
+
if (diagnostics.length > 0) {
|
|
284
|
+
throw new Error(`PINNED_TEMPLATE_INVALID: ${template.pipelineId} — ${diagnostics.map((d) => d.code).join(', ')}`);
|
|
285
|
+
}
|
|
286
|
+
const { taskId, title, base } = await loadRunTaskContext(runId);
|
|
287
|
+
// B5/B7 — live preflight: one memoized DBOS step, evaluated exactly once BEFORE the graph runs.
|
|
288
|
+
// Skipped entirely when every selected binding resolves to a stub/script runner (mirrors the old
|
|
289
|
+
// engine's gate). A `needsHuman` preflight blocks the run (clean/base invariant unmet) and surfaces
|
|
290
|
+
// the lesson — the run never enters the graph. This is an engine-level guard (infrastructure), not a
|
|
291
|
+
// template node: it is cross-cutting and identical for every pinned pipeline (zero role-ids/shapes).
|
|
292
|
+
const live = route.roleBindings.some((b) => runnerNeedsLivePreflight(b.resolvedRunnerId));
|
|
293
|
+
if (live) {
|
|
294
|
+
// Preflight runs against the BASE checkout (resolveTaskCwd), BEFORE the worktree exists — its
|
|
295
|
+
// fetch + clean/freshness checks protect the user's base repo. Ordering is load-bearing.
|
|
296
|
+
const pf = await preflightFn(taskId, base);
|
|
297
|
+
if ('needsHuman' in pf) {
|
|
298
|
+
return await blockWithLesson(runId, taskId, 'preflight', pf.lesson, 0);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Per-run worktree (plan 0017): create AFTER a passing preflight and BEFORE any live effect, so all
|
|
302
|
+
// repo-touching steps (developer/rework + integrator) resolve to the isolated worktree (keyed by
|
|
303
|
+
// runId) — never the shared base checkout. Skipped for non-live runs. The `finally` releases it at a
|
|
304
|
+
// SUCCEEDED terminal (the PR is merged via confirmMerge → branch is in base → worktree disposable) and
|
|
305
|
+
// on a throw (failure); it KEEPS the worktree on a `blocked` terminal (confirmMerge blocks when the PR
|
|
306
|
+
// isn't merged yet — the tree must survive for rework / a manual merge; reclaimed by cleanup_worktree
|
|
307
|
+
// + the host-start sweep). It does NOT run while parked at a gate (awaitHuman suspends the live
|
|
308
|
+
// workflow via `recv`, so runBody never returns there). Create is INSIDE the try so the release also
|
|
309
|
+
// cleans up a create that partially built the worktree before throwing (codex/CodeRabbit).
|
|
310
|
+
let result;
|
|
311
|
+
try {
|
|
312
|
+
if (live) {
|
|
313
|
+
await createWorktreeFn(runId, taskId, title, base);
|
|
314
|
+
}
|
|
315
|
+
result = await runGraph(runId, opts, taskId, title, base);
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
finally {
|
|
319
|
+
if (live && result?.status !== 'blocked') {
|
|
320
|
+
try {
|
|
321
|
+
await releaseWorktreeFn(runId, taskId);
|
|
322
|
+
}
|
|
323
|
+
catch (releaseErr) {
|
|
324
|
+
console.warn(`[data-driven] worktree release for ${runId} failed (orphan; pruned later): ${String(releaseErr)}`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/** The pipeline-core interpretation loop, extracted so the worktree `finally` in runBody wraps it. */
|
|
330
|
+
async function runGraph(runId, opts, taskId, title, base) {
|
|
331
|
+
const { route, template } = opts;
|
|
332
|
+
// Capability resolution map (GENERIC — no role-ids in the engine): roleRef/scriptRef → route binding.
|
|
333
|
+
// The route's bindings are authoritative for runner dispatch (and durable on recovery via the DBOS
|
|
334
|
+
// workflow input). A `role:<id>` handle resolves to the binding whose roleId matches `<id>`. A
|
|
335
|
+
// `script:<id>` handle likewise resolves by roleId; additionally the canonical `script:integrator`
|
|
336
|
+
// handle resolves to whichever binding's RESOLVED runner mechanically performs the merge (runner-
|
|
337
|
+
// wins, D7) so the integrator script dispatches real-vs-stub exactly like the hardcoded path.
|
|
338
|
+
const bindingByRef = new Map();
|
|
339
|
+
for (const binding of route.roleBindings) {
|
|
340
|
+
bindingByRef.set(`role:${binding.roleId}`, binding);
|
|
341
|
+
bindingByRef.set(`script:${binding.roleId}`, binding);
|
|
342
|
+
bindingByRef.set(binding.roleId, binding);
|
|
343
|
+
if (runnerUsesRealIntegrator(binding.resolvedRunnerId) && !bindingByRef.has('script:integrator')) {
|
|
344
|
+
bindingByRef.set('script:integrator', binding);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
const executionProfile = route.executionProfile;
|
|
348
|
+
let state = initialState(template);
|
|
349
|
+
let lastResult;
|
|
350
|
+
let lastVerdict = '';
|
|
351
|
+
let lastFailureReason = '';
|
|
352
|
+
let stepCount = 0;
|
|
353
|
+
// Workflow-local dataflow state (0016 §4.1/§6): per-node execution ordinals + produced outputs.
|
|
354
|
+
// Both are rebuilt deterministically on DBOS replay (the loop re-runs identically); the adapter
|
|
355
|
+
// hydrates consumers from `outputsByNode`, never from a live Revisium read.
|
|
356
|
+
const effectOrdinalByNode = new Map();
|
|
357
|
+
const outputsByNode = new Map();
|
|
358
|
+
for (let i = 0; i < MAX_STEPS; i++) {
|
|
359
|
+
const { state: nextState, decision } = coreStep(template, state, lastResult);
|
|
360
|
+
state = nextState;
|
|
361
|
+
await deps.setProgress?.(runId, progressCursor(state, lastResult));
|
|
362
|
+
if (decision.type === 'complete') {
|
|
363
|
+
return await finish(runId, decision.status, lastVerdict, stepCount, lastFailureReason);
|
|
364
|
+
}
|
|
365
|
+
const eff = await applyDecision(decision, {
|
|
366
|
+
runId, template, bindingByRef, executionProfile, taskId, title, base,
|
|
367
|
+
effectOrdinalByNode, outputsByNode,
|
|
368
|
+
// The verdict from the PRIOR effect (the reviewer/poller that routed into this node). At an
|
|
369
|
+
// awaitGate this is the routing verdict that opened the gate → D3's default reviewerVerdict.
|
|
370
|
+
lastVerdict,
|
|
371
|
+
});
|
|
372
|
+
lastResult = eff.lastResult;
|
|
373
|
+
if (eff.lastVerdict !== undefined)
|
|
374
|
+
lastVerdict = eff.lastVerdict;
|
|
375
|
+
lastFailureReason = eff.failureReason ?? '';
|
|
376
|
+
stepCount += eff.stepDelta;
|
|
377
|
+
}
|
|
378
|
+
throw new InterpretError(`data-driven ${template.pipelineId} did not terminate within ${MAX_STEPS} steps (template loop bug)`);
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Execute ONE non-terminal Decision as a durable effect and return the next `lastResult`/`lastVerdict`
|
|
382
|
+
* + the step-count delta. Extracted from the `runBody` loop so each is small + independently testable
|
|
383
|
+
* (the loop just threads the result; this is the per-kind dispatch).
|
|
384
|
+
*/
|
|
385
|
+
async function applyDecision(decision, ctx) {
|
|
386
|
+
const { runId, template, bindingByRef, taskId, title, base } = ctx;
|
|
387
|
+
switch (decision.type) {
|
|
388
|
+
case 'invokeRole': {
|
|
389
|
+
const node = resolveNode(template, decision.nodeId);
|
|
390
|
+
const ordinal = nextOrdinal(ctx.effectOrdinalByNode, node.id);
|
|
391
|
+
const stepKey = stepKeyFor(node.id, ordinal);
|
|
392
|
+
const resolved = resolveConsumes(node, ctx.outputsByNode);
|
|
393
|
+
if ('missing' in resolved) {
|
|
394
|
+
// A required upstream output is absent → fail-loud as a WIRING fault (0016 §6 / consensus M3):
|
|
395
|
+
// a dedicated step_failed names the missing (node, as), distinct from a domain `blocker`. The
|
|
396
|
+
// node's default onFailure='abort' then routes to a failed terminal (the run fails loud).
|
|
397
|
+
await appendEvent({
|
|
398
|
+
runId, taskId, stepId: '', stepKey, type: 'step_failed',
|
|
399
|
+
payload: { nodeId: node.id, error: `${REVO_INPUT_MISSING}: required input ${resolved.missing} was not produced` },
|
|
400
|
+
});
|
|
401
|
+
return { lastResult: { outcome: 'failed', errorCode: REVO_INPUT_MISSING }, lastVerdict: 'failed', stepDelta: 1 };
|
|
402
|
+
}
|
|
403
|
+
const result = await invokeRole(runId, decision, node, ctx, resolved.inputs, stepKey);
|
|
404
|
+
if (result.failed) {
|
|
405
|
+
await appendEvent({
|
|
406
|
+
runId, taskId, stepId: '', stepKey, type: 'step_failed',
|
|
407
|
+
payload: { nodeId: node.id, error: result.errorCode },
|
|
408
|
+
});
|
|
409
|
+
return { lastResult: { outcome: 'failed', errorCode: result.errorCode }, lastVerdict: 'failed', failureReason: result.reason, stepDelta: 1 };
|
|
410
|
+
}
|
|
411
|
+
await recordOutput(runId, node, ordinal, result.output, ctx.outputsByNode);
|
|
412
|
+
const verdict = result.verdict;
|
|
413
|
+
return {
|
|
414
|
+
lastResult: { outcome: 'succeeded', ...(verdict ? { verdict } : {}) },
|
|
415
|
+
...(verdict ? { lastVerdict: verdict } : {}),
|
|
416
|
+
stepDelta: 1,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
case 'invokeScript': {
|
|
420
|
+
const node = resolveNode(template, decision.nodeId);
|
|
421
|
+
const ordinal = nextOrdinal(ctx.effectOrdinalByNode, node.id);
|
|
422
|
+
// A script node may `consumes` upstream data (plan 0018: respondThreads ← triage). Hydrate it
|
|
423
|
+
// from the workflow-local accumulator (same seam as agents), fail-loud on a missing required input.
|
|
424
|
+
const resolved = resolveConsumes(node, ctx.outputsByNode);
|
|
425
|
+
if ('missing' in resolved) {
|
|
426
|
+
await appendEvent({
|
|
427
|
+
runId, taskId, stepId: '', stepKey: stepKeyFor(node.id, ordinal), type: 'step_failed',
|
|
428
|
+
payload: { nodeId: node.id, error: `${REVO_INPUT_MISSING}: required input ${resolved.missing} was not produced` },
|
|
429
|
+
});
|
|
430
|
+
return { lastResult: { outcome: 'failed', errorCode: REVO_INPUT_MISSING }, lastVerdict: 'failed', stepDelta: 1 };
|
|
431
|
+
}
|
|
432
|
+
const scriptResult = await invokeScript(runId, decision, { taskId, title, base }, bindingByRef, stepKeyFor(node.id, ordinal), resolved.inputs);
|
|
433
|
+
// A blocked script (needsHuman) routes via revo.ScriptBlocked → a `blocked` terminal; a thrown
|
|
434
|
+
// script routes via revo.ScriptFailed → a `failed` terminal (§6 catch). The lesson-bearing
|
|
435
|
+
// pipeline_blocked is emitted inside invokeScript for the block path (parity with the old engine).
|
|
436
|
+
if (scriptResult.outcome === 'blocked') {
|
|
437
|
+
return { lastResult: { outcome: 'failed', errorCode: REVO_SCRIPT_BLOCKED }, lastVerdict: 'blocked', stepDelta: 1 };
|
|
438
|
+
}
|
|
439
|
+
if (scriptResult.outcome === 'failed') {
|
|
440
|
+
return { lastResult: { outcome: 'failed', errorCode: REVO_SCRIPT_FAILED }, lastVerdict: 'failed', stepDelta: 1 };
|
|
441
|
+
}
|
|
442
|
+
await recordOutput(runId, node, ordinal, scriptResult.pointer, ctx.outputsByNode);
|
|
443
|
+
// A classifying script (pollPr, plan 0018) surfaces a DOMAIN verdict so the next `choice` can
|
|
444
|
+
// route on it (§8). Scripts with a single fixed `next` (integrator/confirmMerge) carry none.
|
|
445
|
+
const sv = scriptResult.verdict;
|
|
446
|
+
return { lastResult: { outcome: 'succeeded', ...(sv ? { verdict: sv } : {}) }, ...(sv ? { lastVerdict: sv } : {}), stepDelta: 1 };
|
|
447
|
+
}
|
|
448
|
+
case 'awaitGate': {
|
|
449
|
+
const topic = gateTopicFor(decision.reason);
|
|
450
|
+
// Per-entry gate key (nodeId#ordinal) so a re-entered gate (e.g. a question gate looped in the
|
|
451
|
+
// review phase) gets a DISTINCT inbox row instead of colliding on `runId|topic` (§3.2 audit).
|
|
452
|
+
const ordinal = nextOrdinal(ctx.effectOrdinalByNode, decision.nodeId);
|
|
453
|
+
const human = await awaitHuman(runId, topic, stepKeyFor(decision.nodeId, ordinal), `${decision.reason} approval`, buildGateSummary(decision, ctx.outputsByNode, ctx.lastVerdict));
|
|
454
|
+
const verdict = gateVerdict(human, decision.outcomes);
|
|
455
|
+
return { lastResult: verdict ? { verdict } : {}, ...(verdict ? { lastVerdict: verdict } : {}), stepDelta: 0 };
|
|
456
|
+
}
|
|
457
|
+
case 'fork': {
|
|
458
|
+
// Fork/join is supported by the core; the MVP feature-development pipeline has none. Record a
|
|
459
|
+
// deterministic barrier arrival per branch (verdict undefined) so an `all` join proceeds. A richer
|
|
460
|
+
// concurrent-branch executor (DBOS child workflows) is a later slice (§14 Q1).
|
|
461
|
+
await appendEvent({
|
|
462
|
+
runId,
|
|
463
|
+
taskId,
|
|
464
|
+
stepId: '',
|
|
465
|
+
stepKey: `fork:${decision.nodeId}`,
|
|
466
|
+
type: 'pipeline_fork',
|
|
467
|
+
payload: { nodeId: decision.nodeId, branches: decision.branches.map((b) => b.id), joinId: decision.joinId },
|
|
468
|
+
});
|
|
469
|
+
return {
|
|
470
|
+
lastResult: { joinArrivals: decision.branches.map((b, idx) => ({ branchId: b.id, seq: idx + 1 })) },
|
|
471
|
+
stepDelta: 0,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
case 'startTimer':
|
|
475
|
+
// `wait` nodes are rare (§1) and unused by the MVP templates; a durable timer executor is a later
|
|
476
|
+
// slice. Treat as an immediate (recorded) resume so a template using it still advances.
|
|
477
|
+
return { lastResult: {}, stepDelta: 0 };
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
// ── Effect executors ─────────────────────────────────────────────────────────
|
|
481
|
+
/** invokeRole → dispatch via the existing runStep DBOS step; validate result vs resultSchema. */
|
|
482
|
+
async function invokeRole(runId, decision, node, ctx, inputs, stepKey) {
|
|
483
|
+
const binding = ctx.bindingByRef.get(decision.roleRef);
|
|
484
|
+
if (!binding) {
|
|
485
|
+
// A VALID template's caps resolve at run start; an unresolved roleRef is a fatal config gap.
|
|
486
|
+
throw new Error(`CAPABILITY_UNRESOLVED: roleRef ${decision.roleRef} has no route binding`);
|
|
487
|
+
}
|
|
488
|
+
// stepKey is ordinal-aware (0016 §4.1): distinct per loop iteration, stable across replay. The
|
|
489
|
+
// hydrated `inputs` (consumed upstream outputs) ride in stepInput → the runner renders them as a
|
|
490
|
+
// `## Inputs (from previous steps)` prompt section (build-context).
|
|
491
|
+
const stepInput = Object.keys(inputs).length > 0 ? { nodeId: decision.nodeId, inputs } : { nodeId: decision.nodeId };
|
|
492
|
+
const result = await runStepFn(runId, binding.rowId, stepKey, stepInput, binding.resolvedRunnerId, ctx.executionProfile);
|
|
493
|
+
// runStep converts a runner-process crash into a blocking attempt (needsHuman + verdict BLOCKER);
|
|
494
|
+
// that is a domain failure of the node → route via §6 precedence as a result-invalid/failed effect.
|
|
495
|
+
if (result.needsHuman) {
|
|
496
|
+
return { failed: true, errorCode: REVO_RESULT_INVALID, reason: `${REVO_RESULT_INVALID}: node ${node.id} returned needsHuman instead of a valid result` };
|
|
497
|
+
}
|
|
498
|
+
if (!resultSatisfiesSchema(node, result)) {
|
|
499
|
+
return { failed: true, errorCode: REVO_RESULT_INVALID, reason: `${REVO_RESULT_INVALID}: node ${node.id} result did not satisfy resultSchema ${String('resultSchema' in node ? node.resultSchema : '')}` };
|
|
500
|
+
}
|
|
501
|
+
const verdictProblem = resultVerdictProblem(ctx.template, node, result);
|
|
502
|
+
if (verdictProblem) {
|
|
503
|
+
return { failed: true, errorCode: REVO_RESULT_INVALID, reason: verdictProblem };
|
|
504
|
+
}
|
|
505
|
+
return { failed: false, verdict: domainVerdictOf(result), output: result.output };
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* invokeScript → the built-in system SCRIPT library. The only built-in v1 script is the integrator
|
|
509
|
+
* (`script:integrator`); it dispatches to the real integrator (live) or the stub (script) exactly as
|
|
510
|
+
* the hardcoded path does — runner-wins via the resolved binding (D7).
|
|
511
|
+
*
|
|
512
|
+
* Two distinct outcomes the routing data discriminates (parity with the old engine):
|
|
513
|
+
* - `blocked`: the integrator needs a human (nothing to integrate, ambiguous PRs, refused identity,
|
|
514
|
+
* non-JSON pr view). We emit a `pipeline_blocked` event carrying the human-readable lesson (so the
|
|
515
|
+
* human sees WHY — the persist boundary redacts any token), then the node's `catch[revo.ScriptBlocked]`
|
|
516
|
+
* routes to a `blocked` terminal.
|
|
517
|
+
* - `failed`: the integrator THREW (a gh/push error). `catch[revo.ScriptFailed]` routes to a `failed`
|
|
518
|
+
* terminal; the run's top-level catch failRuns (the thrown reason is recorded, redacted).
|
|
519
|
+
*/
|
|
520
|
+
async function invokeScript(runId, decision, ctx, bindingByRef, stepKey, inputs) {
|
|
521
|
+
const isConfirmMerge = decision.scriptRef === 'script:confirmMerge';
|
|
522
|
+
const isPollPr = decision.scriptRef === 'script:pollPr';
|
|
523
|
+
const isRespondThreads = decision.scriptRef === 'script:respondThreads';
|
|
524
|
+
const binding = bindingByRef.get(decision.scriptRef) ?? bindingByRef.get('script:integrator');
|
|
525
|
+
// respondThreads consumes `triage` (plan 0018) — ride the hydrated input on the integrator input so
|
|
526
|
+
// the live script can reply/resolve the triaged threads without a live Revisium read.
|
|
527
|
+
const integratorInput = { runId, taskId: ctx.taskId, title: ctx.title, base: ctx.base, ...(inputs.triage !== undefined ? { triage: inputs.triage } : {}) };
|
|
528
|
+
// A script node whose resolved runner mechanically performs the merge uses the REAL script;
|
|
529
|
+
// otherwise the pure stub (zero git/gh). Absent a binding (template-only script), default to stub.
|
|
530
|
+
const useReal = !!binding && runnerUsesRealIntegrator(binding.resolvedRunnerId);
|
|
531
|
+
let result;
|
|
532
|
+
try {
|
|
533
|
+
if (isConfirmMerge) {
|
|
534
|
+
result = useReal ? await confirmMergeFn(integratorInput) : runConfirmStub(integratorInput);
|
|
535
|
+
}
|
|
536
|
+
else if (isPollPr) {
|
|
537
|
+
result = useReal ? await pollPrFn(integratorInput) : runPollStub(integratorInput);
|
|
538
|
+
}
|
|
539
|
+
else if (isRespondThreads) {
|
|
540
|
+
result = useReal ? await respondThreadsFn(integratorInput) : runRespondStub(integratorInput);
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
result = useReal ? await integrateFn(integratorInput) : runStub(integratorInput);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
catch (err) {
|
|
547
|
+
await appendEvent({
|
|
548
|
+
runId,
|
|
549
|
+
taskId: ctx.taskId,
|
|
550
|
+
stepId: '',
|
|
551
|
+
stepKey,
|
|
552
|
+
type: 'step_failed',
|
|
553
|
+
payload: { scriptRef: decision.scriptRef, error: err instanceof Error ? err.message : String(err) },
|
|
554
|
+
});
|
|
555
|
+
return { outcome: 'failed' };
|
|
556
|
+
}
|
|
557
|
+
if ('needsHuman' in result) {
|
|
558
|
+
// Surface the blocking reason as pipeline_blocked (the persist boundary redacts any token, D15) so
|
|
559
|
+
// the human sees WHY the script could not proceed — exactly as the old engine's blockPipeline.
|
|
560
|
+
const reason = isConfirmMerge ? 'confirm-merge' : isPollPr ? 'poll-pr' : isRespondThreads ? 'respond-threads' : 'integrate';
|
|
561
|
+
await appendEvent({
|
|
562
|
+
runId,
|
|
563
|
+
taskId: ctx.taskId,
|
|
564
|
+
stepId: '',
|
|
565
|
+
stepKey: 'pipeline',
|
|
566
|
+
type: 'pipeline_blocked',
|
|
567
|
+
payload: { reason, lesson: result.lesson, nodeId: decision.nodeId },
|
|
568
|
+
});
|
|
569
|
+
return { outcome: 'blocked' };
|
|
570
|
+
}
|
|
571
|
+
if (isConfirmMerge) {
|
|
572
|
+
const merged = result;
|
|
573
|
+
await appendEvent({
|
|
574
|
+
runId,
|
|
575
|
+
taskId: ctx.taskId,
|
|
576
|
+
stepId: '',
|
|
577
|
+
stepKey,
|
|
578
|
+
type: 'merge_confirmed',
|
|
579
|
+
payload: { prNumber: merged.prNumber, prUrl: merged.prUrl },
|
|
580
|
+
});
|
|
581
|
+
return { outcome: 'ok', pointer: { merged: true, prNumber: merged.prNumber, prUrl: merged.prUrl } };
|
|
582
|
+
}
|
|
583
|
+
if (isPollPr) {
|
|
584
|
+
// pollPr CLASSIFIES the feedback: its verdict (review_changes/ci_changes/clean) routes the prRouter
|
|
585
|
+
// choice (§8 — a script may emit a domain verdict the routing data acts on, same as an agent).
|
|
586
|
+
const feedback = result;
|
|
587
|
+
await appendEvent({
|
|
588
|
+
runId,
|
|
589
|
+
taskId: ctx.taskId,
|
|
590
|
+
stepId: '',
|
|
591
|
+
stepKey,
|
|
592
|
+
type: 'pr_polled',
|
|
593
|
+
payload: { prNumber: feedback.prNumber, verdict: feedback.verdict, ciFailures: feedback.ciFailures.length, reviewThreads: feedback.reviewThreads.length },
|
|
594
|
+
});
|
|
595
|
+
return { outcome: 'ok', pointer: feedback, verdict: feedback.verdict };
|
|
596
|
+
}
|
|
597
|
+
if (isRespondThreads) {
|
|
598
|
+
const responded = result;
|
|
599
|
+
await appendEvent({
|
|
600
|
+
runId,
|
|
601
|
+
taskId: ctx.taskId,
|
|
602
|
+
stepId: '',
|
|
603
|
+
stepKey,
|
|
604
|
+
type: 'threads_responded',
|
|
605
|
+
payload: { replied: responded.replied, resolved: responded.resolved },
|
|
606
|
+
});
|
|
607
|
+
return { outcome: 'ok', pointer: responded };
|
|
608
|
+
}
|
|
609
|
+
const integrated = result;
|
|
610
|
+
await appendEvent({
|
|
611
|
+
runId,
|
|
612
|
+
taskId: ctx.taskId,
|
|
613
|
+
stepId: '',
|
|
614
|
+
stepKey,
|
|
615
|
+
type: 'integrate_succeeded',
|
|
616
|
+
payload: { prUrl: integrated.prUrl, branch: integrated.branch, prNumber: integrated.prNumber },
|
|
617
|
+
});
|
|
618
|
+
return { outcome: 'ok', pointer: { prUrl: integrated.prUrl, branch: integrated.branch, prNumber: integrated.prNumber } };
|
|
619
|
+
}
|
|
620
|
+
/** Terminal: finish the run in Revisium per the core's terminal status. */
|
|
621
|
+
async function finish(runId, status, verdict, steps, failureReason = '') {
|
|
622
|
+
if (status === 'succeeded') {
|
|
623
|
+
await completeRun(runId, { actor: 'pipeline', source: 'data-driven-complete', verdict, iterations: steps });
|
|
624
|
+
}
|
|
625
|
+
else if (status === 'blocked') {
|
|
626
|
+
await appendEvent({
|
|
627
|
+
runId,
|
|
628
|
+
taskId: '',
|
|
629
|
+
stepId: '',
|
|
630
|
+
stepKey: 'pipeline',
|
|
631
|
+
type: 'pipeline_blocked',
|
|
632
|
+
payload: { reason: 'route-terminal', lastVerdict: verdict, steps },
|
|
633
|
+
});
|
|
634
|
+
await blockRun(runId, { actor: 'pipeline', source: 'data-driven-blocked', reason: 'route-terminal' });
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
await failRun(runId, failureReason || `data-driven pipeline reached a failed terminal (lastVerdict=${verdict})`);
|
|
638
|
+
}
|
|
639
|
+
return { runId, status, verdict, steps };
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Block the run early with a human-readable lesson (the engine-level preflight guard — there is no
|
|
643
|
+
* graph node for it). Emits a lesson-bearing `pipeline_blocked` (token-redacted at the persist
|
|
644
|
+
* boundary) + marks the Revisium run-row blocked, then returns a `blocked` result WITHOUT entering the
|
|
645
|
+
* graph. Mirrors the old engine's `blockPipeline({ reason })`.
|
|
646
|
+
*/
|
|
647
|
+
async function blockWithLesson(runId, taskId, reason, lesson, steps) {
|
|
648
|
+
await appendEvent({
|
|
649
|
+
runId,
|
|
650
|
+
taskId,
|
|
651
|
+
stepId: '',
|
|
652
|
+
stepKey: 'pipeline',
|
|
653
|
+
type: 'pipeline_blocked',
|
|
654
|
+
payload: { reason, lesson },
|
|
655
|
+
});
|
|
656
|
+
await blockRun(runId, { actor: 'pipeline', source: `data-driven-${reason}`, reason });
|
|
657
|
+
return { runId, status: 'blocked', verdict: 'blocked', steps };
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
/** Resolve a node id against the template (a VALID template never dangles — guarded defensively). */
|
|
661
|
+
function resolveNode(template, nodeId) {
|
|
662
|
+
const node = template.nodes[nodeId];
|
|
663
|
+
if (!node)
|
|
664
|
+
throw new InterpretError(`unknown node id "${nodeId}" (invalid template)`);
|
|
665
|
+
return node;
|
|
666
|
+
}
|
|
667
|
+
//# sourceMappingURL=data-driven-task.workflow.js.map
|