@provos/ironcurtain 0.9.1 → 0.11.0
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 +69 -10
- package/dist/auth/oauth-provider.js +1 -4
- package/dist/auth/oauth-provider.js.map +1 -1
- package/dist/cli.js +40 -2
- package/dist/cli.js.map +1 -1
- package/dist/config/config-command.js +174 -10
- package/dist/config/config-command.js.map +1 -1
- package/dist/config/first-start.js +61 -0
- package/dist/config/first-start.js.map +1 -1
- package/dist/config/generated/compiled-policy.json +528 -161
- package/dist/config/generated/test-scenarios.json +4810 -170
- package/dist/config/generated/tool-annotations.json +34 -47
- package/dist/config/index.d.ts +58 -0
- package/dist/config/index.js +97 -15
- package/dist/config/index.js.map +1 -1
- package/dist/config/mcp-servers.json +2 -2
- package/dist/config/model-provider.d.ts +8 -2
- package/dist/config/model-provider.js +52 -9
- package/dist/config/model-provider.js.map +1 -1
- package/dist/config/paths.d.ts +181 -0
- package/dist/config/paths.js +326 -23
- package/dist/config/paths.js.map +1 -1
- package/dist/config/types.d.ts +7 -1
- package/dist/config/user-config.d.ts +61 -4
- package/dist/config/user-config.js +108 -21
- package/dist/config/user-config.js.map +1 -1
- package/dist/config/validate-policy-dir.d.ts +10 -0
- package/dist/config/validate-policy-dir.js +59 -0
- package/dist/config/validate-policy-dir.js.map +1 -0
- package/dist/cron/compile-task-policy.js +1 -0
- package/dist/cron/compile-task-policy.js.map +1 -1
- package/dist/cron/job-commands.js +22 -2
- package/dist/cron/job-commands.js.map +1 -1
- package/dist/cron/types.d.ts +16 -2
- package/dist/cron/types.js +1 -3
- package/dist/cron/types.js.map +1 -1
- package/dist/daemon/daemon-command.js +16 -2
- package/dist/daemon/daemon-command.js.map +1 -1
- package/dist/daemon/ironcurtain-daemon.d.ts +44 -1
- package/dist/daemon/ironcurtain-daemon.js +210 -8
- package/dist/daemon/ironcurtain-daemon.js.map +1 -1
- package/dist/docker/adapters/claude-code.d.ts +2 -1
- package/dist/docker/adapters/claude-code.js +320 -131
- package/dist/docker/adapters/claude-code.js.map +1 -1
- package/dist/docker/adapters/goose.d.ts +12 -11
- package/dist/docker/adapters/goose.js +80 -27
- package/dist/docker/adapters/goose.js.map +1 -1
- package/dist/docker/agent-adapter.d.ts +178 -4
- package/dist/docker/agent-adapter.js +14 -0
- package/dist/docker/agent-adapter.js.map +1 -1
- package/dist/docker/agent-registry.js +3 -2
- package/dist/docker/agent-registry.js.map +1 -1
- package/dist/docker/code-mode-proxy.d.ts +27 -0
- package/dist/docker/code-mode-proxy.js +3 -0
- package/dist/docker/code-mode-proxy.js.map +1 -1
- package/dist/docker/container-lifecycle.d.ts +15 -0
- package/dist/docker/container-lifecycle.js +32 -0
- package/dist/docker/container-lifecycle.js.map +1 -0
- package/dist/docker/docker-agent-session.d.ts +113 -62
- package/dist/docker/docker-agent-session.js +241 -300
- package/dist/docker/docker-agent-session.js.map +1 -1
- package/dist/docker/docker-infrastructure.d.ts +256 -21
- package/dist/docker/docker-infrastructure.js +585 -30
- package/dist/docker/docker-infrastructure.js.map +1 -1
- package/dist/docker/docker-manager.d.ts +36 -1
- package/dist/docker/docker-manager.js +168 -26
- package/dist/docker/docker-manager.js.map +1 -1
- package/dist/docker/docker-progress-sink.d.ts +43 -0
- package/dist/docker/docker-progress-sink.js +299 -0
- package/dist/docker/docker-progress-sink.js.map +1 -0
- package/dist/docker/mitm-proxy.d.ts +90 -1
- package/dist/docker/mitm-proxy.js +720 -40
- package/dist/docker/mitm-proxy.js.map +1 -1
- package/dist/docker/oauth-credentials.d.ts +46 -3
- package/dist/docker/oauth-credentials.js +56 -14
- package/dist/docker/oauth-credentials.js.map +1 -1
- package/dist/docker/oauth-token-manager.js +2 -2
- package/dist/docker/oauth-token-manager.js.map +1 -1
- package/dist/docker/orientation.d.ts +1 -1
- package/dist/docker/provider-config.d.ts +81 -2
- package/dist/docker/provider-config.js +222 -28
- package/dist/docker/provider-config.js.map +1 -1
- package/dist/docker/proxy-tools.d.ts +0 -2
- package/dist/docker/proxy-tools.js +2 -7
- package/dist/docker/proxy-tools.js.map +1 -1
- package/dist/docker/pty-session.d.ts +49 -1
- package/dist/docker/pty-session.js +212 -90
- package/dist/docker/pty-session.js.map +1 -1
- package/dist/docker/pty-types.d.ts +0 -2
- package/dist/docker/pty-types.js +0 -2
- package/dist/docker/pty-types.js.map +1 -1
- package/dist/docker/resource-limits.d.ts +125 -0
- package/dist/docker/resource-limits.js +200 -0
- package/dist/docker/resource-limits.js.map +1 -0
- package/dist/docker/spawn-with-idle-timeout.d.ts +39 -0
- package/dist/docker/spawn-with-idle-timeout.js +152 -0
- package/dist/docker/spawn-with-idle-timeout.js.map +1 -0
- package/dist/docker/sse-extractor.d.ts +51 -0
- package/dist/docker/sse-extractor.js +303 -0
- package/dist/docker/sse-extractor.js.map +1 -0
- package/dist/docker/token-stream-bus.d.ts +83 -0
- package/dist/docker/token-stream-bus.js +98 -0
- package/dist/docker/token-stream-bus.js.map +1 -0
- package/dist/docker/token-stream-types.d.ts +71 -0
- package/dist/docker/token-stream-types.js +8 -0
- package/dist/docker/token-stream-types.js.map +1 -0
- package/dist/docker/types.d.ts +61 -6
- package/dist/doctor/checks.d.ts +138 -0
- package/dist/doctor/checks.js +511 -0
- package/dist/doctor/checks.js.map +1 -0
- package/dist/doctor/doctor-command.d.ts +29 -0
- package/dist/doctor/doctor-command.js +160 -0
- package/dist/doctor/doctor-command.js.map +1 -0
- package/dist/doctor/mcp-liveness.d.ts +28 -0
- package/dist/doctor/mcp-liveness.js +84 -0
- package/dist/doctor/mcp-liveness.js.map +1 -0
- package/dist/doctor/oauth-checks.d.ts +23 -0
- package/dist/doctor/oauth-checks.js +157 -0
- package/dist/doctor/oauth-checks.js.map +1 -0
- package/dist/doctor/output.d.ts +26 -0
- package/dist/doctor/output.js +82 -0
- package/dist/doctor/output.js.map +1 -0
- package/dist/escalation/listener-command.js +0 -3
- package/dist/escalation/listener-command.js.map +1 -1
- package/dist/event-bus/typed-event-bus.d.ts +26 -0
- package/dist/event-bus/typed-event-bus.js +35 -0
- package/dist/event-bus/typed-event-bus.js.map +1 -0
- package/dist/index.js +32 -9
- package/dist/index.js.map +1 -1
- package/dist/logger.js +31 -2
- package/dist/logger.js.map +1 -1
- package/dist/memory/auto-save.d.ts +18 -4
- package/dist/memory/auto-save.js +46 -6
- package/dist/memory/auto-save.js.map +1 -1
- package/dist/memory/memory-policy.d.ts +41 -0
- package/dist/memory/memory-policy.js +36 -0
- package/dist/memory/memory-policy.js.map +1 -0
- package/dist/mux/mux-app.d.ts +2 -0
- package/dist/mux/mux-app.js +30 -34
- package/dist/mux/mux-app.js.map +1 -1
- package/dist/mux/mux-command.d.ts +10 -1
- package/dist/mux/mux-command.js +62 -35
- package/dist/mux/mux-command.js.map +1 -1
- package/dist/mux/mux-renderer.js +22 -17
- package/dist/mux/mux-renderer.js.map +1 -1
- package/dist/mux/pty-bridge.d.ts +2 -0
- package/dist/mux/pty-bridge.js +3 -0
- package/dist/mux/pty-bridge.js.map +1 -1
- package/dist/mux/session-scanner.d.ts +7 -0
- package/dist/mux/session-scanner.js +21 -2
- package/dist/mux/session-scanner.js.map +1 -1
- package/dist/mux/types.d.ts +0 -4
- package/dist/mux/types.js.map +1 -1
- package/dist/{pipeline → observability}/llm-logger.d.ts +9 -3
- package/dist/{pipeline → observability}/llm-logger.js +16 -4
- package/dist/observability/llm-logger.js.map +1 -0
- package/dist/observe/observe-command.d.ts +12 -0
- package/dist/observe/observe-command.js +298 -0
- package/dist/observe/observe-command.js.map +1 -0
- package/dist/observe/observe-renderer.d.ts +24 -0
- package/dist/observe/observe-renderer.js +87 -0
- package/dist/observe/observe-renderer.js.map +1 -0
- package/dist/observe/observe-tui-rain.d.ts +42 -0
- package/dist/observe/observe-tui-rain.js +531 -0
- package/dist/observe/observe-tui-rain.js.map +1 -0
- package/dist/observe/observe-tui-text-panel.d.ts +46 -0
- package/dist/observe/observe-tui-text-panel.js +525 -0
- package/dist/observe/observe-tui-text-panel.js.map +1 -0
- package/dist/observe/observe-tui-types.d.ts +270 -0
- package/dist/observe/observe-tui-types.js +200 -0
- package/dist/observe/observe-tui-types.js.map +1 -0
- package/dist/observe/observe-tui-word-scorer.d.ts +143 -0
- package/dist/observe/observe-tui-word-scorer.js +572 -0
- package/dist/observe/observe-tui-word-scorer.js.map +1 -0
- package/dist/observe/observe-tui.d.ts +59 -0
- package/dist/observe/observe-tui.js +592 -0
- package/dist/observe/observe-tui.js.map +1 -0
- package/dist/persona/compile-persona-policy.js +1 -0
- package/dist/persona/compile-persona-policy.js.map +1 -1
- package/dist/persona/memory-gate.d.ts +19 -0
- package/dist/persona/memory-gate.js +33 -0
- package/dist/persona/memory-gate.js.map +1 -0
- package/dist/persona/persona-command.js +41 -6
- package/dist/persona/persona-command.js.map +1 -1
- package/dist/persona/resolve.d.ts +22 -0
- package/dist/persona/resolve.js +45 -2
- package/dist/persona/resolve.js.map +1 -1
- package/dist/persona/types.d.ts +16 -0
- package/dist/pipeline/annotate.d.ts +7 -1
- package/dist/pipeline/annotate.js +92 -2
- package/dist/pipeline/annotate.js.map +1 -1
- package/dist/pipeline/compile.js +2 -0
- package/dist/pipeline/compile.js.map +1 -1
- package/dist/pipeline/constitution-compiler.d.ts +25 -14
- package/dist/pipeline/constitution-compiler.js +107 -38
- package/dist/pipeline/constitution-compiler.js.map +1 -1
- package/dist/pipeline/dynamic-list-types.d.ts +3 -6
- package/dist/pipeline/dynamic-list-types.js +3 -16
- package/dist/pipeline/dynamic-list-types.js.map +1 -1
- package/dist/pipeline/parallel-progress.d.ts +59 -0
- package/dist/pipeline/parallel-progress.js +263 -0
- package/dist/pipeline/parallel-progress.js.map +1 -0
- package/dist/pipeline/pipeline-runner.d.ts +49 -8
- package/dist/pipeline/pipeline-runner.js +419 -231
- package/dist/pipeline/pipeline-runner.js.map +1 -1
- package/dist/pipeline/pipeline-shared.d.ts +59 -1
- package/dist/pipeline/pipeline-shared.js +127 -12
- package/dist/pipeline/pipeline-shared.js.map +1 -1
- package/dist/pipeline/policy-verifier.js +16 -3
- package/dist/pipeline/policy-verifier.js.map +1 -1
- package/dist/pipeline/proxy-mcp-connections.js +17 -2
- package/dist/pipeline/proxy-mcp-connections.js.map +1 -1
- package/dist/pipeline/scenario-generator.d.ts +4 -8
- package/dist/pipeline/scenario-generator.js +13 -46
- package/dist/pipeline/scenario-generator.js.map +1 -1
- package/dist/pipeline/server-prefilter.d.ts +31 -0
- package/dist/pipeline/server-prefilter.js +115 -0
- package/dist/pipeline/server-prefilter.js.map +1 -0
- package/dist/pipeline/types.d.ts +5 -0
- package/dist/sandbox/index.d.ts +14 -0
- package/dist/sandbox/index.js +335 -116
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/ironcurtain-protocol.d.ts +52 -0
- package/dist/sandbox/ironcurtain-protocol.js +185 -0
- package/dist/sandbox/ironcurtain-protocol.js.map +1 -0
- package/dist/session/agent-session.d.ts +6 -0
- package/dist/session/agent-session.js +16 -5
- package/dist/session/agent-session.js.map +1 -1
- package/dist/session/cli-transport.js +0 -6
- package/dist/session/cli-transport.js.map +1 -1
- package/dist/session/index.d.ts +35 -14
- package/dist/session/index.js +324 -130
- package/dist/session/index.js.map +1 -1
- package/dist/session/preflight.d.ts +50 -13
- package/dist/session/preflight.js +252 -80
- package/dist/session/preflight.js.map +1 -1
- package/dist/session/prompts.d.ts +2 -5
- package/dist/session/prompts.js.map +1 -1
- package/dist/session/session-manager.d.ts +61 -6
- package/dist/session/session-manager.js +72 -10
- package/dist/session/session-manager.js.map +1 -1
- package/dist/session/session-metadata.d.ts +21 -5
- package/dist/session/session-metadata.js +34 -12
- package/dist/session/session-metadata.js.map +1 -1
- package/dist/session/types.d.ts +311 -5
- package/dist/session/types.js +57 -1
- package/dist/session/types.js.map +1 -1
- package/dist/signal/setup-signal.js +13 -21
- package/dist/signal/setup-signal.js.map +1 -1
- package/dist/signal/signal-bot-daemon.d.ts +16 -1
- package/dist/signal/signal-bot-daemon.js +39 -27
- package/dist/signal/signal-bot-daemon.js.map +1 -1
- package/dist/signal/signal-container.js +7 -1
- package/dist/signal/signal-container.js.map +1 -1
- package/dist/skills/discovery.d.ts +77 -0
- package/dist/skills/discovery.js +206 -0
- package/dist/skills/discovery.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.js +3 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/staging.d.ts +28 -0
- package/dist/skills/staging.js +68 -0
- package/dist/skills/staging.js.map +1 -0
- package/dist/skills/types.d.ts +46 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/trusted-process/approval-whitelist.d.ts +0 -2
- package/dist/trusted-process/approval-whitelist.js +17 -17
- package/dist/trusted-process/approval-whitelist.js.map +1 -1
- package/dist/trusted-process/async-mutex.d.ts +32 -0
- package/dist/trusted-process/async-mutex.js +50 -0
- package/dist/trusted-process/async-mutex.js.map +1 -0
- package/dist/trusted-process/audit-log.d.ts +38 -1
- package/dist/trusted-process/audit-log.js +82 -13
- package/dist/trusted-process/audit-log.js.map +1 -1
- package/dist/trusted-process/call-circuit-breaker.js +2 -1
- package/dist/trusted-process/call-circuit-breaker.js.map +1 -1
- package/dist/trusted-process/control-server.d.ts +101 -0
- package/dist/trusted-process/control-server.js +282 -0
- package/dist/trusted-process/control-server.js.map +1 -0
- package/dist/trusted-process/domain-utils.d.ts +6 -6
- package/dist/trusted-process/domain-utils.js +7 -23
- package/dist/trusted-process/domain-utils.js.map +1 -1
- package/dist/trusted-process/error-prefixes.d.ts +16 -0
- package/dist/trusted-process/error-prefixes.js +17 -0
- package/dist/trusted-process/error-prefixes.js.map +1 -0
- package/dist/trusted-process/index.d.ts +40 -23
- package/dist/trusted-process/index.js +131 -225
- package/dist/trusted-process/index.js.map +1 -1
- package/dist/trusted-process/list-matcher.d.ts +17 -0
- package/dist/trusted-process/list-matcher.js +31 -0
- package/dist/trusted-process/list-matcher.js.map +1 -0
- package/dist/trusted-process/mcp-client-manager.d.ts +35 -6
- package/dist/trusted-process/mcp-client-manager.js +40 -45
- package/dist/trusted-process/mcp-client-manager.js.map +1 -1
- package/dist/trusted-process/mcp-proxy-server.d.ts +31 -120
- package/dist/trusted-process/mcp-proxy-server.js +166 -657
- package/dist/trusted-process/mcp-proxy-server.js.map +1 -1
- package/dist/trusted-process/policy-engine.d.ts +16 -4
- package/dist/trusted-process/policy-engine.js +90 -45
- package/dist/trusted-process/policy-engine.js.map +1 -1
- package/dist/trusted-process/policy-roots.d.ts +6 -0
- package/dist/trusted-process/policy-roots.js +20 -0
- package/dist/trusted-process/policy-roots.js.map +1 -1
- package/dist/trusted-process/sandbox-integration.d.ts +12 -0
- package/dist/trusted-process/sandbox-integration.js +26 -0
- package/dist/trusted-process/sandbox-integration.js.map +1 -1
- package/dist/trusted-process/tool-call-coordinator.d.ts +269 -0
- package/dist/trusted-process/tool-call-coordinator.js +508 -0
- package/dist/trusted-process/tool-call-coordinator.js.map +1 -0
- package/dist/trusted-process/tool-call-pipeline.d.ts +205 -0
- package/dist/trusted-process/tool-call-pipeline.js +798 -0
- package/dist/trusted-process/tool-call-pipeline.js.map +1 -0
- package/dist/trusted-process/tool-description-hints.d.ts +1 -1
- package/dist/types/argument-roles.d.ts +1 -1
- package/dist/types/argument-roles.js +14 -1
- package/dist/types/argument-roles.js.map +1 -1
- package/dist/types/audit.d.ts +9 -0
- package/dist/{session → types}/errors.d.ts +8 -2
- package/dist/{session → types}/errors.js +8 -2
- package/dist/types/errors.js.map +1 -0
- package/dist/types/reserved-servers.d.ts +11 -0
- package/dist/types/reserved-servers.js +12 -0
- package/dist/types/reserved-servers.js.map +1 -0
- package/dist/types/server-listing.d.ts +14 -0
- package/dist/types/server-listing.js +2 -0
- package/dist/types/server-listing.js.map +1 -0
- package/dist/types/slug.d.ts +2 -0
- package/dist/types/slug.js +2 -0
- package/dist/types/slug.js.map +1 -1
- package/dist/types/url-normalize.d.ts +16 -0
- package/dist/types/url-normalize.js +33 -0
- package/dist/types/url-normalize.js.map +1 -0
- package/dist/utils/error-message.d.ts +8 -0
- package/dist/utils/error-message.js +11 -0
- package/dist/utils/error-message.js.map +1 -0
- package/dist/utils/exec-error.d.ts +19 -0
- package/dist/utils/exec-error.js +16 -0
- package/dist/utils/exec-error.js.map +1 -0
- package/dist/utils/is-plain-object.d.ts +7 -0
- package/dist/utils/is-plain-object.js +12 -0
- package/dist/utils/is-plain-object.js.map +1 -0
- package/dist/utils/preflight-checks.d.ts +16 -0
- package/dist/utils/preflight-checks.js +178 -0
- package/dist/utils/preflight-checks.js.map +1 -0
- package/dist/web-ui/__tests__/json-rpc-dispatch.test.d.ts +7 -0
- package/dist/web-ui/__tests__/json-rpc-dispatch.test.js +725 -0
- package/dist/web-ui/__tests__/json-rpc-dispatch.test.js.map +1 -0
- package/dist/web-ui/dispatch/escalation-dispatch.d.ts +7 -0
- package/dist/web-ui/dispatch/escalation-dispatch.js +52 -0
- package/dist/web-ui/dispatch/escalation-dispatch.js.map +1 -0
- package/dist/web-ui/dispatch/job-dispatch.d.ts +8 -0
- package/dist/web-ui/dispatch/job-dispatch.js +83 -0
- package/dist/web-ui/dispatch/job-dispatch.js.map +1 -0
- package/dist/web-ui/dispatch/persona-dispatch.d.ts +6 -0
- package/dist/web-ui/dispatch/persona-dispatch.js +116 -0
- package/dist/web-ui/dispatch/persona-dispatch.js.map +1 -0
- package/dist/web-ui/dispatch/session-dispatch.d.ts +9 -0
- package/dist/web-ui/dispatch/session-dispatch.js +201 -0
- package/dist/web-ui/dispatch/session-dispatch.js.map +1 -0
- package/dist/web-ui/dispatch/token-stream-dispatch.d.ts +15 -0
- package/dist/web-ui/dispatch/token-stream-dispatch.js +55 -0
- package/dist/web-ui/dispatch/token-stream-dispatch.js.map +1 -0
- package/dist/web-ui/dispatch/types.d.ts +31 -0
- package/dist/web-ui/dispatch/types.js +68 -0
- package/dist/web-ui/dispatch/types.js.map +1 -0
- package/dist/web-ui/dispatch/workflow-dispatch.d.ts +103 -0
- package/dist/web-ui/dispatch/workflow-dispatch.js +925 -0
- package/dist/web-ui/dispatch/workflow-dispatch.js.map +1 -0
- package/dist/web-ui/json-rpc-dispatch.d.ts +12 -0
- package/dist/web-ui/json-rpc-dispatch.js +34 -0
- package/dist/web-ui/json-rpc-dispatch.js.map +1 -0
- package/dist/web-ui/state-graph.d.ts +13 -0
- package/dist/web-ui/state-graph.js +82 -0
- package/dist/web-ui/state-graph.js.map +1 -0
- package/dist/web-ui/token-stream-bridge.d.ts +76 -0
- package/dist/web-ui/token-stream-bridge.js +265 -0
- package/dist/web-ui/token-stream-bridge.js.map +1 -0
- package/dist/web-ui/web-event-bus.d.ts +152 -0
- package/dist/web-ui/web-event-bus.js +19 -0
- package/dist/web-ui/web-event-bus.js.map +1 -0
- package/dist/web-ui/web-session-transport.d.ts +31 -0
- package/dist/web-ui/web-session-transport.js +109 -0
- package/dist/web-ui/web-session-transport.js.map +1 -0
- package/dist/web-ui/web-ui-server.d.ts +76 -0
- package/dist/web-ui/web-ui-server.js +461 -0
- package/dist/web-ui/web-ui-server.js.map +1 -0
- package/dist/web-ui/web-ui-types.d.ts +290 -0
- package/dist/web-ui/web-ui-types.js +32 -0
- package/dist/web-ui/web-ui-types.js.map +1 -0
- package/dist/web-ui/ws-utils.d.ts +5 -0
- package/dist/web-ui/ws-utils.js +12 -0
- package/dist/web-ui/ws-utils.js.map +1 -0
- package/dist/web-ui-static/assets/index-BFO5z1js.js +76 -0
- package/dist/web-ui-static/assets/index-CCUwrkIL.css +1 -0
- package/dist/web-ui-static/assets/orbitron-latin-700-normal-4jsRXGGJ.woff2 +0 -0
- package/dist/web-ui-static/assets/orbitron-latin-700-normal-DmYOh-W9.woff +0 -0
- package/dist/web-ui-static/index.html +14 -0
- package/dist/workflow/artifacts.d.ts +59 -0
- package/dist/workflow/artifacts.js +188 -0
- package/dist/workflow/artifacts.js.map +1 -0
- package/dist/workflow/checkpoint-selection.d.ts +34 -0
- package/dist/workflow/checkpoint-selection.js +48 -0
- package/dist/workflow/checkpoint-selection.js.map +1 -0
- package/dist/workflow/checkpoint.d.ts +35 -0
- package/dist/workflow/checkpoint.js +84 -0
- package/dist/workflow/checkpoint.js.map +1 -0
- package/dist/workflow/cli-support.d.ts +92 -0
- package/dist/workflow/cli-support.js +423 -0
- package/dist/workflow/cli-support.js.map +1 -0
- package/dist/workflow/definition-loader.d.ts +32 -0
- package/dist/workflow/definition-loader.js +56 -0
- package/dist/workflow/definition-loader.js.map +1 -0
- package/dist/workflow/discovery.d.ts +78 -0
- package/dist/workflow/discovery.js +203 -0
- package/dist/workflow/discovery.js.map +1 -0
- package/dist/workflow/errors.d.ts +66 -0
- package/dist/workflow/errors.js +49 -0
- package/dist/workflow/errors.js.map +1 -0
- package/dist/workflow/guards.d.ts +8 -0
- package/dist/workflow/guards.js +38 -0
- package/dist/workflow/guards.js.map +1 -0
- package/dist/workflow/lint-integration.d.ts +64 -0
- package/dist/workflow/lint-integration.js +56 -0
- package/dist/workflow/lint-integration.js.map +1 -0
- package/dist/workflow/lint.d.ts +66 -0
- package/dist/workflow/lint.js +410 -0
- package/dist/workflow/lint.js.map +1 -0
- package/dist/workflow/machine-builder.d.ts +90 -0
- package/dist/workflow/machine-builder.js +485 -0
- package/dist/workflow/machine-builder.js.map +1 -0
- package/dist/workflow/message-log.d.ts +85 -0
- package/dist/workflow/message-log.js +40 -0
- package/dist/workflow/message-log.js.map +1 -0
- package/dist/workflow/orchestrator.d.ts +450 -0
- package/dist/workflow/orchestrator.js +1941 -0
- package/dist/workflow/orchestrator.js.map +1 -0
- package/dist/workflow/prompt-builder.d.ts +39 -0
- package/dist/workflow/prompt-builder.js +242 -0
- package/dist/workflow/prompt-builder.js.map +1 -0
- package/dist/workflow/run-state-command.d.ts +9 -0
- package/dist/workflow/run-state-command.js +414 -0
- package/dist/workflow/run-state-command.js.map +1 -0
- package/dist/workflow/run-state-debug-capture.d.ts +40 -0
- package/dist/workflow/run-state-debug-capture.js +101 -0
- package/dist/workflow/run-state-debug-capture.js.map +1 -0
- package/dist/workflow/status-parser.d.ts +68 -0
- package/dist/workflow/status-parser.js +259 -0
- package/dist/workflow/status-parser.js.map +1 -0
- package/dist/workflow/types.d.ts +498 -0
- package/dist/workflow/types.js +83 -0
- package/dist/workflow/types.js.map +1 -0
- package/dist/workflow/validate.d.ts +58 -0
- package/dist/workflow/validate.js +499 -0
- package/dist/workflow/validate.js.map +1 -0
- package/dist/workflow/workflow-command.d.ts +26 -0
- package/dist/workflow/workflow-command.js +648 -0
- package/dist/workflow/workflow-command.js.map +1 -0
- package/dist/workflow/workflow-discovery.d.ts +25 -0
- package/dist/workflow/workflow-discovery.js +100 -0
- package/dist/workflow/workflow-discovery.js.map +1 -0
- package/dist/workflow/workflow-manager.d.ts +122 -0
- package/dist/workflow/workflow-manager.js +308 -0
- package/dist/workflow/workflow-manager.js.map +1 -0
- package/dist/workflow/workflows/design-and-code/workflow.yaml +169 -0
- package/dist/workflow/workflows/test-email-summary/skills/email-formatting/SKILL.md +55 -0
- package/dist/workflow/workflows/test-email-summary/skills/gmail-query-syntax/SKILL.md +63 -0
- package/dist/workflow/workflows/test-email-summary/skills/json-schema-emails/SKILL.md +41 -0
- package/dist/workflow/workflows/test-email-summary/skills/json-schema-emails/schema.json +34 -0
- package/dist/workflow/workflows/test-email-summary/skills/summary-style-guide/SKILL.md +51 -0
- package/dist/workflow/workflows/test-email-summary/workflow.yaml +89 -0
- package/dist/workflow/workflows/vuln-discovery/skills/harness-design-fuzzing/SKILL.md +201 -0
- package/dist/workflow/workflows/vuln-discovery/skills/memory-safety-c-cpp/SKILL.md +166 -0
- package/dist/workflow/workflows/vuln-discovery/skills/vulnerability-triage/SKILL.md +185 -0
- package/dist/workflow/workflows/vuln-discovery/workflow.yaml +920 -0
- package/dist/workflow/worktree.d.ts +43 -0
- package/dist/workflow/worktree.js +106 -0
- package/dist/workflow/worktree.js.map +1 -0
- package/docker/Dockerfile.base +12 -1
- package/docker/Dockerfile.base.arm64 +17 -1
- package/docker/entrypoint-claude-code.sh +46 -0
- package/docker/entrypoint-goose.sh +25 -0
- package/package.json +22 -8
- package/packages/web-ui/README.md +113 -0
- package/packages/web-ui/docs/workflow-state-machine.png +0 -0
- package/src/config/generated/compiled-policy.json +528 -161
- package/src/config/generated/test-scenarios.json +4810 -170
- package/src/config/generated/tool-annotations.json +34 -47
- package/src/config/mcp-servers.json +2 -2
- package/src/workflow/workflows/design-and-code/workflow.yaml +169 -0
- package/src/workflow/workflows/test-email-summary/skills/email-formatting/SKILL.md +55 -0
- package/src/workflow/workflows/test-email-summary/skills/gmail-query-syntax/SKILL.md +63 -0
- package/src/workflow/workflows/test-email-summary/skills/json-schema-emails/SKILL.md +41 -0
- package/src/workflow/workflows/test-email-summary/skills/json-schema-emails/schema.json +34 -0
- package/src/workflow/workflows/test-email-summary/skills/summary-style-guide/SKILL.md +51 -0
- package/src/workflow/workflows/test-email-summary/workflow.yaml +89 -0
- package/src/workflow/workflows/vuln-discovery/skills/harness-design-fuzzing/SKILL.md +201 -0
- package/src/workflow/workflows/vuln-discovery/skills/memory-safety-c-cpp/SKILL.md +166 -0
- package/src/workflow/workflows/vuln-discovery/skills/vulnerability-triage/SKILL.md +185 -0
- package/src/workflow/workflows/vuln-discovery/workflow.yaml +920 -0
- package/dist/pipeline/llm-logger.js.map +0 -1
- package/dist/session/errors.js.map +0 -1
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entry point for `ironcurtain workflow`.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* start <definition> "task" [--model <model>] [--workspace <path>]
|
|
6
|
+
* resume <baseDir> [--state <stateName>] [--model <model>]
|
|
7
|
+
* inspect <baseDir> [--all]
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, mkdirSync, readdirSync, statSync } from 'node:fs';
|
|
10
|
+
import { resolve } from 'node:path';
|
|
11
|
+
import { parseArgs } from 'node:util';
|
|
12
|
+
import { createInterface } from 'node:readline/promises';
|
|
13
|
+
import { getIronCurtainHome } from '../config/paths.js';
|
|
14
|
+
import { loadConfig } from '../config/index.js';
|
|
15
|
+
import { formatHelp } from '../cli-help.js';
|
|
16
|
+
import { FileCheckpointStore } from './checkpoint.js';
|
|
17
|
+
import { discoverWorkflows, resolveWorkflowPath, parseDefinitionFile } from './discovery.js';
|
|
18
|
+
import { discoverWorkflowRuns } from './workflow-discovery.js';
|
|
19
|
+
import { WorkflowManager } from './workflow-manager.js';
|
|
20
|
+
import { TypedEventBus } from '../event-bus/typed-event-bus.js';
|
|
21
|
+
import { countBySeverity, lintWorkflow } from './lint.js';
|
|
22
|
+
import { defaultLintContext, runPreflight } from './lint-integration.js';
|
|
23
|
+
import { loadDefinition } from './definition-loader.js';
|
|
24
|
+
import { MessageLog } from './message-log.js';
|
|
25
|
+
import { WorkflowOrchestrator } from './orchestrator.js';
|
|
26
|
+
import { createWorkflowSessionFactory, createConsoleTab, createGateHandler, printLifecycleEvent, printSummary, printResumeInfo, selectResumableWorkflow, synthesizeCheckpoint, runEventLoop, writeStdout, writeStderr, RED, BLUE, BOLD, DIM, MAGENTA, CYAN, YELLOW, RESET, } from './cli-support.js';
|
|
27
|
+
import { runRunState } from './run-state-command.js';
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Help specs
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
const workflowSpec = {
|
|
32
|
+
name: 'ironcurtain workflow',
|
|
33
|
+
description: 'Run multi-agent workflows',
|
|
34
|
+
usage: [
|
|
35
|
+
'ironcurtain workflow list',
|
|
36
|
+
'ironcurtain workflow start <name-or-path> "task" [--model <model>] [--workspace <path>] [--no-lint] [--strict-lint]',
|
|
37
|
+
'ironcurtain workflow resume <baseDir> [--state <stateName>] [--model <model>] [--no-lint] [--strict-lint]',
|
|
38
|
+
'ironcurtain workflow inspect <baseDir> [--all]',
|
|
39
|
+
'ironcurtain workflow lint <name-or-path> [--strict]',
|
|
40
|
+
'ironcurtain workflow run-state <name-or-path> <state> --artifacts <dir> [options]',
|
|
41
|
+
],
|
|
42
|
+
subcommands: [
|
|
43
|
+
{ name: 'list', description: 'List available workflow definitions' },
|
|
44
|
+
{ name: 'start', description: 'Start a workflow by name or definition file path' },
|
|
45
|
+
{ name: 'resume', description: 'Resume a checkpointed workflow' },
|
|
46
|
+
{ name: 'inspect', description: 'Show workflow status, artifacts, and recent messages' },
|
|
47
|
+
{ name: 'lint', description: 'Run semantic checks on a workflow definition' },
|
|
48
|
+
{ name: 'run-state', description: 'Run a single agent state once against pre-staged artifacts' },
|
|
49
|
+
],
|
|
50
|
+
options: [
|
|
51
|
+
{ flag: 'model', description: 'Override the agent model (start, resume)', placeholder: '<model-id>' },
|
|
52
|
+
{
|
|
53
|
+
flag: 'workspace',
|
|
54
|
+
description: 'Use an existing directory as workspace (start only)',
|
|
55
|
+
placeholder: '<path>',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
flag: 'state',
|
|
59
|
+
description: 'Synthesize checkpoint at this state (resume only)',
|
|
60
|
+
placeholder: '<name>',
|
|
61
|
+
},
|
|
62
|
+
{ flag: 'all', description: 'Show full message log (inspect only)' },
|
|
63
|
+
{ flag: 'no-lint', description: 'Skip pre-flight linting (start, resume)' },
|
|
64
|
+
{ flag: 'strict-lint', description: 'Treat lint warnings as errors (start, resume)' },
|
|
65
|
+
{ flag: 'strict', description: 'Treat lint warnings as errors (lint only)' },
|
|
66
|
+
{ flag: 'help', short: 'h', description: 'Show this help message' },
|
|
67
|
+
],
|
|
68
|
+
examples: [
|
|
69
|
+
'ironcurtain workflow list',
|
|
70
|
+
'ironcurtain workflow start design-and-code "Build a REST API"',
|
|
71
|
+
'ironcurtain workflow start ./my-workflow.yaml "Build a REST API"',
|
|
72
|
+
'ironcurtain workflow start design-and-code "task" --model anthropic:claude-haiku-4-5',
|
|
73
|
+
'ironcurtain workflow resume /tmp/workflow-abc123',
|
|
74
|
+
'ironcurtain workflow resume /tmp/workflow-abc123 --state review',
|
|
75
|
+
'ironcurtain workflow resume /tmp/workflow-abc123 --model anthropic:claude-sonnet-4-6',
|
|
76
|
+
'ironcurtain workflow inspect /tmp/workflow-abc123',
|
|
77
|
+
'ironcurtain workflow inspect /tmp/workflow-abc123 --all',
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Lint helpers
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
function formatDiagnostic(d) {
|
|
84
|
+
const sevColor = d.severity === 'error' ? RED : CYAN;
|
|
85
|
+
const location = d.stateId ? ` (state: ${d.stateId})` : '';
|
|
86
|
+
const lines = [`${DIM}[${d.code}]${RESET} ${sevColor}${d.severity}${RESET} ${d.message}${location}`];
|
|
87
|
+
if (d.hint)
|
|
88
|
+
lines.push(` ${DIM}hint: ${d.hint}${RESET}`);
|
|
89
|
+
return lines;
|
|
90
|
+
}
|
|
91
|
+
function printDiagnostics(diagnostics) {
|
|
92
|
+
for (const d of diagnostics) {
|
|
93
|
+
for (const line of formatDiagnostic(d))
|
|
94
|
+
writeStderr(line);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Loads + validates a workflow definition from a path via the shared
|
|
99
|
+
* {@link loadDefinition} helper. Prints CLI-formatted errors and exits on
|
|
100
|
+
* any failure (parse or validate). Validation errors take precedence over
|
|
101
|
+
* lint diagnostics.
|
|
102
|
+
*/
|
|
103
|
+
function loadAndValidateDefinition(path) {
|
|
104
|
+
const result = loadDefinition(path);
|
|
105
|
+
if (result.ok)
|
|
106
|
+
return result.definition;
|
|
107
|
+
if (result.kind === 'validate' && result.issues) {
|
|
108
|
+
writeStderr(`${RED}Workflow validation failed:${RESET}`);
|
|
109
|
+
for (const issue of result.issues)
|
|
110
|
+
writeStderr(` ${RED}- ${issue}${RESET}`);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
writeStderr(`${RED}Failed to load workflow: ${result.message}${RESET}`);
|
|
114
|
+
}
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Loads + lints a workflow definition file via the shared
|
|
119
|
+
* {@link runPreflight} helper. CLI-specific reporting: prints diagnostics
|
|
120
|
+
* to stderr and exits on any failure (load or lint). On success with
|
|
121
|
+
* warnings-only output, prints a short continue notice.
|
|
122
|
+
*
|
|
123
|
+
* Returns the loaded definition on success so callers can continue using it
|
|
124
|
+
* without re-parsing (start/resume have already routed through the same
|
|
125
|
+
* file before calling this).
|
|
126
|
+
*/
|
|
127
|
+
export function runCliPreflightLint(definitionPath, mode) {
|
|
128
|
+
const result = runPreflight(definitionPath, mode);
|
|
129
|
+
if (result.ok) {
|
|
130
|
+
if (result.diagnostics.length > 0) {
|
|
131
|
+
printDiagnostics(result.diagnostics);
|
|
132
|
+
writeStderr(`${DIM}Lint: 0 errors, ${result.warnings} warning(s) — continuing.${RESET}`);
|
|
133
|
+
}
|
|
134
|
+
return result.definition;
|
|
135
|
+
}
|
|
136
|
+
if (result.kind === 'load') {
|
|
137
|
+
// Reuse `loadAndValidateDefinition`'s nicer per-issue formatting on
|
|
138
|
+
// validate failures by re-running it (cheap; reads the same file once
|
|
139
|
+
// more) — it owns the structured-issues bullet rendering. For parse
|
|
140
|
+
// failures it falls through and prints "Failed to load workflow:".
|
|
141
|
+
loadAndValidateDefinition(definitionPath);
|
|
142
|
+
// Unreachable: `loadAndValidateDefinition` always exits on failure.
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
// Lint failure (load succeeded). Match the previous output verbatim.
|
|
146
|
+
printDiagnostics(result.diagnostics);
|
|
147
|
+
writeStderr(`${RED}Lint failed: ${result.errors} error(s), ${result.warnings} warning(s).${RESET}`);
|
|
148
|
+
writeStderr(`${DIM}Rerun with --no-lint to bypass (not recommended).${RESET}`);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
function resolveLintMode(noLint, strictLint) {
|
|
152
|
+
if (noLint === true)
|
|
153
|
+
return 'off';
|
|
154
|
+
if (strictLint === true)
|
|
155
|
+
return 'strict';
|
|
156
|
+
return 'warn';
|
|
157
|
+
}
|
|
158
|
+
export function parseArgsStrict(opts) {
|
|
159
|
+
try {
|
|
160
|
+
return parseArgs({ ...opts, strict: true });
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
164
|
+
writeStderr(`${RED}${message}${RESET}`);
|
|
165
|
+
writeStderr(`${DIM}Run with --help to see available options.${RESET}`);
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// Subcommand implementations
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
async function runStart(args) {
|
|
173
|
+
const { values, positionals } = parseArgsStrict({
|
|
174
|
+
args,
|
|
175
|
+
options: {
|
|
176
|
+
model: { type: 'string' },
|
|
177
|
+
workspace: { type: 'string' },
|
|
178
|
+
'no-lint': { type: 'boolean' },
|
|
179
|
+
'strict-lint': { type: 'boolean' },
|
|
180
|
+
help: { type: 'boolean', short: 'h' },
|
|
181
|
+
},
|
|
182
|
+
allowPositionals: true,
|
|
183
|
+
});
|
|
184
|
+
if (values.help) {
|
|
185
|
+
process.stderr.write(formatHelp(workflowSpec) + '\n');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const definitionRef = positionals[0];
|
|
189
|
+
const taskDescription = positionals[1];
|
|
190
|
+
if (!definitionRef || !taskDescription) {
|
|
191
|
+
writeStderr(`${RED}Usage: ironcurtain workflow start <name-or-path> "task" [--model <model>]${RESET}`);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
const resolvedDef = resolveWorkflowPath(definitionRef);
|
|
195
|
+
if (!resolvedDef) {
|
|
196
|
+
writeStderr(`${RED}Workflow not found: ${definitionRef}${RESET}`);
|
|
197
|
+
writeStderr(`${DIM}Looked in bundled and user workflow directories.${RESET}`);
|
|
198
|
+
writeStderr(`${DIM}Run 'ironcurtain workflow list' to see available workflows.${RESET}`);
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
// Pre-flight: validate + lint before any orchestrator side effects.
|
|
202
|
+
const lintMode = resolveLintMode(values['no-lint'], values['strict-lint']);
|
|
203
|
+
runCliPreflightLint(resolvedDef, lintMode);
|
|
204
|
+
let workspacePath;
|
|
205
|
+
if (values.workspace) {
|
|
206
|
+
const resolvedWs = resolve(values.workspace);
|
|
207
|
+
if (!existsSync(resolvedWs) || !statSync(resolvedWs).isDirectory()) {
|
|
208
|
+
writeStderr(`${RED}Workspace path is not a directory: ${resolvedWs}${RESET}`);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
workspacePath = resolvedWs;
|
|
212
|
+
}
|
|
213
|
+
const modelOverride = values.model;
|
|
214
|
+
const baseDir = resolve(getIronCurtainHome(), 'workflow-runs');
|
|
215
|
+
mkdirSync(baseDir, { recursive: true });
|
|
216
|
+
const checkpointStore = new FileCheckpointStore(baseDir);
|
|
217
|
+
const gateHandler = createGateHandler();
|
|
218
|
+
const sessionFactory = createWorkflowSessionFactory(modelOverride);
|
|
219
|
+
const config = loadConfig();
|
|
220
|
+
const deps = {
|
|
221
|
+
createSession: sessionFactory,
|
|
222
|
+
createWorkflowTab: (label) => createConsoleTab(label),
|
|
223
|
+
raiseGate: gateHandler.raiseGate,
|
|
224
|
+
dismissGate: gateHandler.dismissGate,
|
|
225
|
+
baseDir,
|
|
226
|
+
checkpointStore,
|
|
227
|
+
userConfig: config.userConfig,
|
|
228
|
+
};
|
|
229
|
+
const orchestrator = new WorkflowOrchestrator(deps);
|
|
230
|
+
orchestrator.onEvent(printLifecycleEvent);
|
|
231
|
+
const controller = new AbortController();
|
|
232
|
+
process.on('SIGINT', () => {
|
|
233
|
+
writeStderr(`\n[workflow] Caught SIGINT, shutting down...`);
|
|
234
|
+
controller.abort();
|
|
235
|
+
});
|
|
236
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
237
|
+
try {
|
|
238
|
+
writeStdout(`${BOLD}${MAGENTA}Starting workflow${RESET}`);
|
|
239
|
+
writeStdout(`${DIM}Task: ${taskDescription}${RESET}`);
|
|
240
|
+
writeStdout(`${DIM}Base dir: ${baseDir}${RESET}`);
|
|
241
|
+
writeStdout('');
|
|
242
|
+
const workflowId = await orchestrator.start(resolvedDef, taskDescription, workspacePath);
|
|
243
|
+
const wsPath = workspacePath ?? resolve(baseDir, workflowId, 'workspace');
|
|
244
|
+
const artifactDir = resolve(wsPath, '.workflow');
|
|
245
|
+
await runEventLoop(orchestrator, workflowId, rl, controller.signal);
|
|
246
|
+
printSummary(orchestrator, workflowId, artifactDir);
|
|
247
|
+
const exitCode = computeExitCode(orchestrator, workflowId, controller.signal);
|
|
248
|
+
process.exit(exitCode);
|
|
249
|
+
}
|
|
250
|
+
finally {
|
|
251
|
+
rl.close();
|
|
252
|
+
await orchestrator.shutdownAll().catch(() => { });
|
|
253
|
+
writeStdout(`${DIM}Artifacts preserved at: ${baseDir}${RESET}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async function runResume(args) {
|
|
257
|
+
const { values, positionals } = parseArgsStrict({
|
|
258
|
+
args,
|
|
259
|
+
options: {
|
|
260
|
+
state: { type: 'string' },
|
|
261
|
+
model: { type: 'string' },
|
|
262
|
+
'no-lint': { type: 'boolean' },
|
|
263
|
+
'strict-lint': { type: 'boolean' },
|
|
264
|
+
help: { type: 'boolean', short: 'h' },
|
|
265
|
+
},
|
|
266
|
+
allowPositionals: true,
|
|
267
|
+
});
|
|
268
|
+
if (values.help) {
|
|
269
|
+
process.stderr.write(formatHelp(workflowSpec) + '\n');
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const baseDirArg = positionals[0];
|
|
273
|
+
if (!baseDirArg) {
|
|
274
|
+
writeStderr(`${RED}Usage: ironcurtain workflow resume <baseDir> [--state <stateName>]${RESET}`);
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
const baseDir = resolve(baseDirArg);
|
|
278
|
+
if (!existsSync(baseDir)) {
|
|
279
|
+
writeStderr(`${RED}Base directory does not exist: ${baseDir}${RESET}`);
|
|
280
|
+
process.exit(1);
|
|
281
|
+
}
|
|
282
|
+
const modelOverride = values.model;
|
|
283
|
+
const overrideState = values.state;
|
|
284
|
+
const checkpointStore = new FileCheckpointStore(baseDir);
|
|
285
|
+
const gateHandler = createGateHandler();
|
|
286
|
+
const sessionFactory = createWorkflowSessionFactory(modelOverride);
|
|
287
|
+
let selected;
|
|
288
|
+
const hasCheckpoints = discoverWorkflowRuns(baseDir).some((r) => r.hasCheckpoint);
|
|
289
|
+
if (overrideState && !hasCheckpoints) {
|
|
290
|
+
// Find a definition path from the workflow directory
|
|
291
|
+
const definitionPath = findDefinitionPath(baseDir);
|
|
292
|
+
selected = synthesizeCheckpoint(baseDir, overrideState, definitionPath, checkpointStore);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
selected = selectResumableWorkflow(checkpointStore, baseDir);
|
|
296
|
+
}
|
|
297
|
+
// Pre-flight lint before orchestrator.resume(). The checkpoint carries
|
|
298
|
+
// a definitionPath we can re-validate + lint.
|
|
299
|
+
const defPath = selected.checkpoint.definitionPath;
|
|
300
|
+
if (defPath && existsSync(defPath)) {
|
|
301
|
+
const lintMode = resolveLintMode(values['no-lint'], values['strict-lint']);
|
|
302
|
+
runCliPreflightLint(defPath, lintMode);
|
|
303
|
+
}
|
|
304
|
+
printResumeInfo(baseDir, selected.workflowId, selected.checkpoint);
|
|
305
|
+
const config = loadConfig();
|
|
306
|
+
const deps = {
|
|
307
|
+
createSession: sessionFactory,
|
|
308
|
+
createWorkflowTab: (label) => createConsoleTab(label),
|
|
309
|
+
raiseGate: gateHandler.raiseGate,
|
|
310
|
+
dismissGate: gateHandler.dismissGate,
|
|
311
|
+
baseDir,
|
|
312
|
+
checkpointStore,
|
|
313
|
+
userConfig: config.userConfig,
|
|
314
|
+
};
|
|
315
|
+
const orchestrator = new WorkflowOrchestrator(deps);
|
|
316
|
+
orchestrator.onEvent(printLifecycleEvent);
|
|
317
|
+
const controller = new AbortController();
|
|
318
|
+
process.on('SIGINT', () => {
|
|
319
|
+
writeStderr(`\n[workflow] Caught SIGINT, shutting down...`);
|
|
320
|
+
controller.abort();
|
|
321
|
+
});
|
|
322
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
323
|
+
try {
|
|
324
|
+
writeStdout(`${BOLD}${MAGENTA}Resuming...${RESET}`);
|
|
325
|
+
writeStdout('');
|
|
326
|
+
await orchestrator.resume(selected.workflowId);
|
|
327
|
+
const wsPath = resolve(baseDir, selected.workflowId, 'workspace');
|
|
328
|
+
const artifactDir = resolve(wsPath, '.workflow');
|
|
329
|
+
await runEventLoop(orchestrator, selected.workflowId, rl, controller.signal);
|
|
330
|
+
printSummary(orchestrator, selected.workflowId, artifactDir);
|
|
331
|
+
const exitCode = computeExitCode(orchestrator, selected.workflowId, controller.signal);
|
|
332
|
+
process.exit(exitCode);
|
|
333
|
+
}
|
|
334
|
+
finally {
|
|
335
|
+
rl.close();
|
|
336
|
+
await orchestrator.shutdownAll().catch(() => { });
|
|
337
|
+
writeStdout(`${DIM}Artifacts preserved at: ${baseDir}${RESET}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function runInspect(args) {
|
|
341
|
+
const { values, positionals } = parseArgsStrict({
|
|
342
|
+
args,
|
|
343
|
+
options: {
|
|
344
|
+
all: { type: 'boolean' },
|
|
345
|
+
help: { type: 'boolean', short: 'h' },
|
|
346
|
+
},
|
|
347
|
+
allowPositionals: true,
|
|
348
|
+
});
|
|
349
|
+
if (values.help) {
|
|
350
|
+
process.stderr.write(formatHelp(workflowSpec) + '\n');
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const baseDirArg = positionals[0];
|
|
354
|
+
if (!baseDirArg) {
|
|
355
|
+
writeStderr(`${RED}Usage: ironcurtain workflow inspect <baseDir> [--all]${RESET}`);
|
|
356
|
+
process.exit(1);
|
|
357
|
+
}
|
|
358
|
+
const baseDir = resolve(baseDirArg);
|
|
359
|
+
if (!existsSync(baseDir)) {
|
|
360
|
+
writeStderr(`${RED}Base directory does not exist: ${baseDir}${RESET}`);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
const showAll = values.all === true;
|
|
364
|
+
const runs = discoverWorkflowRuns(baseDir);
|
|
365
|
+
if (runs.length === 0) {
|
|
366
|
+
writeStdout(`${DIM}No workflows found in ${baseDir}${RESET}`);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
// WorkflowManager owns the canonical "load a past run" logic. We point it at
|
|
370
|
+
// the user-supplied baseDir via `baseDirOverride` so the same loader works
|
|
371
|
+
// for both the daemon's home directory and arbitrary `inspect` targets.
|
|
372
|
+
// The CLI never starts workflows through this manager, so the event bus is
|
|
373
|
+
// a no-op sink and the orchestrator created lazily inside the manager is
|
|
374
|
+
// never used to spawn sessions.
|
|
375
|
+
const manager = new WorkflowManager({
|
|
376
|
+
eventBus: new TypedEventBus(),
|
|
377
|
+
baseDirOverride: baseDir,
|
|
378
|
+
});
|
|
379
|
+
for (const run of runs) {
|
|
380
|
+
const workflowId = run.workflowId;
|
|
381
|
+
const workflowDir = run.directoryPath;
|
|
382
|
+
const result = manager.loadPastRun(workflowId);
|
|
383
|
+
let checkpoint;
|
|
384
|
+
let loadedDef;
|
|
385
|
+
if ('error' in result) {
|
|
386
|
+
if (result.error === 'corrupted') {
|
|
387
|
+
// Behavior change: a malformed checkpoint or definition used to either
|
|
388
|
+
// throw (checkpoint) or be silently ignored (definition). We now print
|
|
389
|
+
// a clear error line and continue with the next workflow.
|
|
390
|
+
writeStdout(`${BOLD}${CYAN}Workflow: ${workflowId}${RESET}`);
|
|
391
|
+
writeStdout(` ${RED}Failed to load: ${result.message ?? 'unknown error'}${RESET}`);
|
|
392
|
+
writeStdout('');
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
// not_found: no checkpoint on disk. Preserve current behavior -- render
|
|
396
|
+
// the directory with `checkpoint = undefined` and silently parse the
|
|
397
|
+
// definition (without strict schema validation) for state descriptions.
|
|
398
|
+
checkpoint = undefined;
|
|
399
|
+
loadedDef = tryParseDefinitionForStateDescriptions(workflowDir);
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
checkpoint = result.checkpoint;
|
|
403
|
+
loadedDef = result.definition;
|
|
404
|
+
}
|
|
405
|
+
writeStdout(`${BOLD}${CYAN}Workflow: ${workflowId}${RESET}`);
|
|
406
|
+
const stateDescriptions = loadedDef
|
|
407
|
+
? new Map(Object.entries(loadedDef.states)
|
|
408
|
+
.filter(([, s]) => s.description)
|
|
409
|
+
.map(([id, s]) => [id, s.description]))
|
|
410
|
+
: undefined;
|
|
411
|
+
const defPath = resolve(workflowDir, 'definition.json');
|
|
412
|
+
if (checkpoint) {
|
|
413
|
+
const stateStr = String(checkpoint.machineState);
|
|
414
|
+
const desc = stateDescriptions?.get(stateStr);
|
|
415
|
+
const stateLabel = desc
|
|
416
|
+
? `${BOLD}${stateStr}${RESET} ${DIM}\u2014 "${desc}"${RESET}`
|
|
417
|
+
: `${BOLD}${stateStr}${RESET}`;
|
|
418
|
+
writeStdout(` State: ${stateLabel}`);
|
|
419
|
+
writeStdout(` Timestamp: ${checkpoint.timestamp}`);
|
|
420
|
+
if (checkpoint.context.lastError) {
|
|
421
|
+
writeStdout(` Error: ${RED}${checkpoint.context.lastError}${RESET}`);
|
|
422
|
+
}
|
|
423
|
+
writeStdout(` Task: ${checkpoint.context.taskDescription.slice(0, 100)}`);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
writeStdout(` ${DIM}No checkpoint${RESET}`);
|
|
427
|
+
}
|
|
428
|
+
// Artifact directories
|
|
429
|
+
const wsPath = resolve(workflowDir, 'workspace', '.workflow');
|
|
430
|
+
if (existsSync(wsPath)) {
|
|
431
|
+
const artifactNames = readdirSync(wsPath).filter((e) => statSync(resolve(wsPath, e)).isDirectory());
|
|
432
|
+
writeStdout(` Artifacts: ${artifactNames.join(', ') || '(none)'}`);
|
|
433
|
+
}
|
|
434
|
+
if (existsSync(defPath)) {
|
|
435
|
+
writeStdout(` Definition: ${defPath}`);
|
|
436
|
+
}
|
|
437
|
+
// Informational lint of the checkpointed definition. Read-only — never
|
|
438
|
+
// affects exit code. Intentionally does NOT pass `workflowFilePath`:
|
|
439
|
+
// inspect operates on a past-run's `definition.json` whose sibling
|
|
440
|
+
// tree is the run directory, not the source workflow package, so
|
|
441
|
+
// WF010 (skill-reference) would emit false positives by looking for
|
|
442
|
+
// SKILL.md in a directory that never carried skills sidecars.
|
|
443
|
+
if (loadedDef) {
|
|
444
|
+
const diagnostics = lintWorkflow(loadedDef, defaultLintContext);
|
|
445
|
+
if (diagnostics.length > 0) {
|
|
446
|
+
const { errors, warnings } = countBySeverity(diagnostics);
|
|
447
|
+
writeStdout(` ${BOLD}Lint:${RESET} ${errors} error(s), ${warnings} warning(s)`);
|
|
448
|
+
for (const d of diagnostics) {
|
|
449
|
+
for (const line of formatDiagnostic(d))
|
|
450
|
+
writeStdout(` ${line}`);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
// Message log
|
|
455
|
+
const logPath = resolve(workflowDir, 'messages.jsonl');
|
|
456
|
+
const messageLog = new MessageLog(logPath);
|
|
457
|
+
const entries = messageLog.readAll();
|
|
458
|
+
if (entries.length > 0) {
|
|
459
|
+
const displayEntries = showAll ? entries : entries.slice(-20);
|
|
460
|
+
const label = showAll
|
|
461
|
+
? `All ${entries.length} messages`
|
|
462
|
+
: `Last ${displayEntries.length} of ${entries.length} messages`;
|
|
463
|
+
writeStdout(` ${BOLD}${label}:${RESET}`);
|
|
464
|
+
for (const entry of displayEntries) {
|
|
465
|
+
const ts = entry.ts.slice(11, 19); // HH:MM:SS
|
|
466
|
+
const prefix = ` ${DIM}${ts}${RESET}`;
|
|
467
|
+
switch (entry.type) {
|
|
468
|
+
case 'agent_sent':
|
|
469
|
+
writeStdout(`${prefix} ${CYAN}[sent/${entry.role}]${RESET} ${truncate(entry.message, 120)}`);
|
|
470
|
+
break;
|
|
471
|
+
case 'agent_received':
|
|
472
|
+
writeStdout(`${prefix} ${CYAN}[recv/${entry.role}]${RESET} verdict=${entry.verdict ?? '-'} ${truncate(entry.message, 80)}`);
|
|
473
|
+
break;
|
|
474
|
+
case 'agent_retry':
|
|
475
|
+
writeStdout(`${prefix} ${MAGENTA}[retry/${entry.role}]${RESET} ${entry.reason}`);
|
|
476
|
+
break;
|
|
477
|
+
case 'gate_raised':
|
|
478
|
+
writeStdout(`${prefix} ${BOLD}[gate]${RESET} events: ${entry.acceptedEvents.join(', ')}`);
|
|
479
|
+
break;
|
|
480
|
+
case 'gate_resolved':
|
|
481
|
+
writeStdout(`${prefix} ${BOLD}[gate resolved]${RESET} ${entry.event}`);
|
|
482
|
+
break;
|
|
483
|
+
case 'error':
|
|
484
|
+
writeStdout(`${prefix} ${RED}[error]${RESET} ${entry.error}`);
|
|
485
|
+
break;
|
|
486
|
+
case 'quota_exhausted':
|
|
487
|
+
writeStdout(`${prefix} ${YELLOW}[quota/${entry.role}]${RESET} resets=${entry.resetAt ?? 'unknown'} — ${truncate(entry.rawMessage, 80)}`);
|
|
488
|
+
break;
|
|
489
|
+
case 'transient_failure':
|
|
490
|
+
writeStdout(`${prefix} ${YELLOW}[transient/${entry.role}]${RESET} kind=${entry.kind} — ${truncate(entry.rawMessage, 80)}`);
|
|
491
|
+
break;
|
|
492
|
+
case 'state_transition': {
|
|
493
|
+
const toDesc = stateDescriptions?.get(entry.event);
|
|
494
|
+
const toLabel = toDesc ? `${entry.event} ${DIM}\u2014 "${toDesc}"${RESET}` : entry.event;
|
|
495
|
+
writeStdout(`${prefix} ${BLUE}[transition]${RESET} ${entry.from} -> ${toLabel}`);
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
writeStdout(` ${DIM}No message log${RESET}`);
|
|
503
|
+
}
|
|
504
|
+
writeStdout('');
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Best-effort definition load used in the `not_found` branch of `loadPastRun`.
|
|
509
|
+
* Mirrors the pre-refactor behavior: parse-only (no schema validation), errors
|
|
510
|
+
* swallowed. The returned definition is used solely to populate state
|
|
511
|
+
* descriptions in the rendered message log.
|
|
512
|
+
*/
|
|
513
|
+
function tryParseDefinitionForStateDescriptions(workflowDir) {
|
|
514
|
+
const defPath = resolve(workflowDir, 'definition.json');
|
|
515
|
+
if (!existsSync(defPath))
|
|
516
|
+
return undefined;
|
|
517
|
+
try {
|
|
518
|
+
return parseDefinitionFile(defPath);
|
|
519
|
+
}
|
|
520
|
+
catch {
|
|
521
|
+
// Non-fatal -- definition may be from an older schema.
|
|
522
|
+
return undefined;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// ---------------------------------------------------------------------------
|
|
526
|
+
// Helpers
|
|
527
|
+
// ---------------------------------------------------------------------------
|
|
528
|
+
function computeExitCode(orchestrator, workflowId, signal) {
|
|
529
|
+
if (signal.aborted)
|
|
530
|
+
return 130;
|
|
531
|
+
const status = orchestrator.getStatus(workflowId);
|
|
532
|
+
if (status?.phase === 'completed')
|
|
533
|
+
return 0;
|
|
534
|
+
return 1;
|
|
535
|
+
}
|
|
536
|
+
/** Finds the first definition.json path under a base directory's workflow runs. */
|
|
537
|
+
function findDefinitionPath(baseDir) {
|
|
538
|
+
const run = discoverWorkflowRuns(baseDir).find((r) => r.hasDefinition);
|
|
539
|
+
if (run)
|
|
540
|
+
return resolve(run.directoryPath, 'definition.json');
|
|
541
|
+
writeStderr(`${RED}No definition.json found in ${baseDir}${RESET}`);
|
|
542
|
+
process.exit(1);
|
|
543
|
+
}
|
|
544
|
+
function truncate(text, maxLen) {
|
|
545
|
+
const oneLine = text.replace(/\n/g, ' ').trim();
|
|
546
|
+
if (oneLine.length <= maxLen)
|
|
547
|
+
return oneLine;
|
|
548
|
+
return oneLine.slice(0, maxLen - 3) + '...';
|
|
549
|
+
}
|
|
550
|
+
// ---------------------------------------------------------------------------
|
|
551
|
+
// Lint subcommand
|
|
552
|
+
// ---------------------------------------------------------------------------
|
|
553
|
+
function runLintCommand(args) {
|
|
554
|
+
const { values, positionals } = parseArgsStrict({
|
|
555
|
+
args,
|
|
556
|
+
options: {
|
|
557
|
+
strict: { type: 'boolean' },
|
|
558
|
+
help: { type: 'boolean', short: 'h' },
|
|
559
|
+
},
|
|
560
|
+
allowPositionals: true,
|
|
561
|
+
});
|
|
562
|
+
if (values.help) {
|
|
563
|
+
process.stderr.write(formatHelp(workflowSpec) + '\n');
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
const definitionRef = positionals[0];
|
|
567
|
+
if (!definitionRef) {
|
|
568
|
+
writeStderr(`${RED}Usage: ironcurtain workflow lint <name-or-path> [--strict]${RESET}`);
|
|
569
|
+
process.exit(1);
|
|
570
|
+
}
|
|
571
|
+
const resolved = resolveWorkflowPath(definitionRef);
|
|
572
|
+
if (!resolved) {
|
|
573
|
+
writeStderr(`${RED}Workflow not found: ${definitionRef}${RESET}`);
|
|
574
|
+
writeStderr(`${DIM}Looked in bundled and user workflow directories.${RESET}`);
|
|
575
|
+
process.exit(1);
|
|
576
|
+
}
|
|
577
|
+
// Structural validation first — a malformed definition cannot be linted.
|
|
578
|
+
const definition = loadAndValidateDefinition(resolved);
|
|
579
|
+
const ctx = { ...defaultLintContext, workflowFilePath: resolved };
|
|
580
|
+
const diagnostics = lintWorkflow(definition, ctx);
|
|
581
|
+
if (diagnostics.length === 0) {
|
|
582
|
+
writeStderr(`${DIM}No lint diagnostics for ${resolved}.${RESET}`);
|
|
583
|
+
process.exit(0);
|
|
584
|
+
}
|
|
585
|
+
printDiagnostics(diagnostics);
|
|
586
|
+
const { errors, warnings } = countBySeverity(diagnostics);
|
|
587
|
+
writeStderr(`${DIM}Summary: ${errors} error(s), ${warnings} warning(s).${RESET}`);
|
|
588
|
+
if (errors > 0)
|
|
589
|
+
process.exit(1);
|
|
590
|
+
if (values.strict === true && warnings > 0)
|
|
591
|
+
process.exit(2);
|
|
592
|
+
process.exit(0);
|
|
593
|
+
}
|
|
594
|
+
// ---------------------------------------------------------------------------
|
|
595
|
+
// List subcommand
|
|
596
|
+
// ---------------------------------------------------------------------------
|
|
597
|
+
function runList() {
|
|
598
|
+
const workflows = discoverWorkflows();
|
|
599
|
+
if (workflows.length === 0) {
|
|
600
|
+
writeStdout(`${DIM}No workflow definitions found.${RESET}`);
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
const nameWidth = Math.max(4, ...workflows.map((w) => w.name.length));
|
|
604
|
+
const sourceWidth = Math.max(6, ...workflows.map((w) => w.source.length));
|
|
605
|
+
const header = `${'NAME'.padEnd(nameWidth)} ${'SOURCE'.padEnd(sourceWidth)} DESCRIPTION`;
|
|
606
|
+
writeStdout(`${BOLD}${header}${RESET}`);
|
|
607
|
+
for (const wf of workflows) {
|
|
608
|
+
const line = `${wf.name.padEnd(nameWidth)} ${wf.source.padEnd(sourceWidth)} ${wf.description}`;
|
|
609
|
+
writeStdout(line);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
// ---------------------------------------------------------------------------
|
|
613
|
+
// Main entry point
|
|
614
|
+
// ---------------------------------------------------------------------------
|
|
615
|
+
export async function main(args) {
|
|
616
|
+
const subcommand = args[0];
|
|
617
|
+
const subArgs = args.slice(1);
|
|
618
|
+
// Top-level help
|
|
619
|
+
if (!subcommand || subcommand === '--help' || subcommand === '-h') {
|
|
620
|
+
process.stderr.write(formatHelp(workflowSpec) + '\n');
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
switch (subcommand) {
|
|
624
|
+
case 'list':
|
|
625
|
+
runList();
|
|
626
|
+
break;
|
|
627
|
+
case 'start':
|
|
628
|
+
await runStart(subArgs);
|
|
629
|
+
break;
|
|
630
|
+
case 'resume':
|
|
631
|
+
await runResume(subArgs);
|
|
632
|
+
break;
|
|
633
|
+
case 'inspect':
|
|
634
|
+
runInspect(subArgs);
|
|
635
|
+
break;
|
|
636
|
+
case 'lint':
|
|
637
|
+
runLintCommand(subArgs);
|
|
638
|
+
break;
|
|
639
|
+
case 'run-state':
|
|
640
|
+
await runRunState(subArgs);
|
|
641
|
+
break;
|
|
642
|
+
default:
|
|
643
|
+
writeStderr(`${RED}Unknown workflow subcommand: ${subcommand}${RESET}`);
|
|
644
|
+
process.stderr.write(formatHelp(workflowSpec) + '\n');
|
|
645
|
+
process.exit(1);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
//# sourceMappingURL=workflow-command.js.map
|